質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%

Q&A

解決済

3回答

2799閲覧

PHPでzipファイルのダウンロードがうまくできません(文字化けがブラウザ上で表示される)

退会済みユーザー

退会済みユーザー

総合スコア0

0グッド

0クリップ

投稿2021/12/27 02:06

編集2022/01/25 21:41

前提・実現したいこと

ダウンロードボタンを押すとzipファイルを作成してダウンロード出来るようにしたいです。

下記のコードだとzipファイル作成までは出来たのですが、その後にダウンロードが始まることはなくブラウザ上にzipの中身が文字化けして表示されるだけで何も動作しません。作成できたzipファイルを直接ダウンロードして解凍してみたのですが問題なく解凍できました。なのでダウンロード周りのコードが間違っているのかもしれません。

該当のソースコード

php

1<?php 2$test_file = __DIR__ . '/../../../uploads/txt/test.txt'; 3 4if (isset($_POST['downloadbutton'])) { 5 $zip = new ZipArchive(); 6 $zipFileName = get_the_ID() . '.zip'; 7 $zipTmpDir = __DIR__ . '/../../../uploads/zip/'; 8 $result = $zip->open($zipTmpDir.$zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE); 9 10 if ($result === true) { 11 set_time_limit(0); 12 $zip->addFile($test_file, 'test.txt'); 13 $zip->close(); 14 15 header('Content-type: application/zip'); 16 header('X-Content-Type-Options: nosniff'); 17 header('Content-Length: '.filesize($zipTmpDir.$zipFileName)); 18 header('Content-Disposition: attachment; filename="'.$zipFileName.'"'); 19 header('Connection: close'); 20 while (ob_get_level()) { ob_end_clean(); } 21 readfile($zipTmpDir.$zipFileName); 22 } 23 unlink($zipTmpDir.$zipFileName); 24 exit; 25} 26?> 27 28<form id="testdl" method="post"> 29 <button id="button" type="submit" name="downloadbutton"><p>Download</p></button> 30</form>

php.iniに下記を追加することで文字化けがブラウザに表示されなくなり、ダウンロード出来るようになりました。ただこの方法が正しいのか、もしくはただエラーがあるのに無理やりダウンロード出来るようにしているのか分かりません。

php.ini

1output_buffering = on

参考にしたサイト: PHP:Warning: Cannot modify header information - headers already sent by ...の解決策

試したことと結果

  • いくつかのサイトを参考にしたのでいらないものを足してしまったか、もしくは引いてしまったのかと思いダウンロード周りのコードを何度も修正したのですが別のエラー(Cannot modify header information - headers already sent)が表示され結局解決できませんでした。

  • while (ob_get_level()) { ob_end_clean(); } を ob_end_clean(); に変更しました。文字化けが表示されるようになりました→  PK 8b�Stest.txtPK? 8b�S��test.txtPK6&

  • 上記のコードを別のphpファイルに移しfunctionにして元のファイルからincludeで呼んだんですが同じ文字化けが表示されました。

  • mb_output_handler("pass"); と mb_http_output("pass"); をコメントアウトしてみましたが同じ文字化けが表示されました。

  • header('Content-Type: application/zip; name="' . $zipFileName . '"'); をコメントアウトしてheader('Content-type: application/zip'); を追加してみましたが同じ文字化けが表示されました。

  • サーバーのファイルパーミッションを確認したんですがダウンロード出来ない原因は見つかりませんでした。

  • 私と同じようにzipの中身が文字化けしてブラウザに表示されてダウンロード出来ない方の解決済みの投稿を見つけたんですが(https://teratail.com/questions/279532)その方はCakePHPを使用されているみたいで、その解決策のコードを追加してもエラーが出るだけでした。

追加したコード→ Configure::write('debug', 0);

  • unlink($zipTmpDir.$zipFileName); をコメントアウトし作成されたzipファイルを削除せず、そのzipファイルをhtmlコード <a href="test.zip" download>download test</a> でダウンロードしてみたんですが、それは問題なくダウンロードも解凍もできました。

  • header('X-Content-Type-Options: nosniff'); を追加しました。

  • php.ini に output_buffering = on を追加しました。

  • ob_end_clean(); を再び while (ob_get_level()) { ob_end_clean(); } に戻したらダウンロードも解凍もできました。ただiphoneのchromeからだとダウンロードはできても解凍ができません。

補足情報(FW/ツールのバージョンなど)

phpのバージョン: 7.4.25

phpのzipのバージョン
Zip enabled
Zip version 1.15.6
Libzip headers version 1.3.2
Libzip library version 1.3.2

使用しているサーバー: Conoha Wing

使用しているEditer: Visual Studio Code

Wordpressでサイトを作っています

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AsukaKobayashi

2022/01/07 05:32

1/7時点で質問に記載のコードを、 WordPress環境ではない、さくらサーバーにて動かしてみたところ問題なく動作しました。 ($test_file $zipFileName $zipTmpDir の3か所は適宜変更してテストしています) > 作成できたzipファイルを直接ダウンロードして解凍してみた とのことですが、 `unlink($zipTmpDir.$zipFileName);` の行を消した状態で Download ボタンをクリックし、その後 https://example.com/uploads/zip/hoge.zip というような形で、「作成できたzipファイル」のURLに直接アクセスしたときは 文字化けは発生せず、ファイルのダウンロードができるということでしょうか?
退会済みユーザー

退会済みユーザー

2022/01/07 05:54

AsukaKobayashiさん テストしていただき有難うございます! 同じコードで問題なく動作したということはコード以外のサーバーか何かの設定のところで問題があるのかもしれませんね...。 「直接ダウンロード」というのは unlink($zipTmpDir.$zipFileName); の部分を一度コメントアウトしてその後にダウンロードボタンをクリックし、Conoha Wingが用意してあるファイルマネージャーで直接上記のコードで指定したサーバー上のフォルダを開き、zipファイルをそのファイルマネージャーからダウンロードしました。 一応その後にphpコードで作成されたzipファイルをHTMLコードだけで <a href="test.zip" download>download test</a> と記述してダウンロードしてみたんですが、それは問題なくダウンロードも解凍もできました。
guest

回答3

0

ベストアンサー

追加で質問をしてややこしくなってしまったので、一番の最初の質問の"文字化けが表示されてダウンロード出来ない"のところまでで一度解決にしたいと思います。解決策は下記になります。ご回答をしてくださった皆様本当にありがとうございました!!

コード

php

1<?php 2$test_file = __DIR__ . '/../../../uploads/txt/test.txt'; 3 4if (isset($_POST['downloadbutton'])) { 5 $zip = new ZipArchive(); 6 $zipFileName = get_the_ID() . '.zip'; 7 $zipTmpDir = __DIR__ . '/../../../uploads/zip/'; 8 $result = $zip->open($zipTmpDir.$zipFileName, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE); 9 10 if ($result === true) { 11 set_time_limit(0); 12 $zip->addFile($test_file, 'test.txt'); 13 $zip->close(); 14 15 header('Content-type: application/zip'); 16 header('X-Content-Type-Options: nosniff'); 17 header('Content-Length: '.filesize($zipTmpDir.$zipFileName)); 18 header('Content-Disposition: attachment; filename="'.$zipFileName.'"'); 19 header('Connection: close'); 20 while (ob_get_level()) { ob_end_clean(); } 21 readfile($zipTmpDir.$zipFileName); 22 } 23 unlink($zipTmpDir.$zipFileName); 24 exit; 25} 26?> 27 28<form id="testdl" method="post"> 29 <button id="button" type="submit" name="downloadbutton"><p>Download</p></button> 30</form>

解決策

php.iniに下記を追加することで文字化けがブラウザに表示されなくなり、ダウンロード出来るようになりました。ただこの方法が正しいのか、もしくはただエラーがあるのに無理やりダウンロード出来るようにしているのか分かりません。

php.ini

1output_buffering = on

参考にしたサイト: PHP:Warning: Cannot modify header information - headers already sent by ...の解決策

投稿2022/01/25 21:48

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

質問に記載のコードを
WordPress環境ではない、さくらサーバーにて動かしてみたところ問題なく動作してしまったため
(ファイルのパスやWordPress固有の部分は変更/Win10 Google Chromeにて確認)
下記が有効かわかりませんが、対応のアイディアをいくつか回答させてください。

ダウンロード用のコードを修正してみる案

PHP

1header('Content-type: application/zip');

の下に

PHP

1//-- ウェブブラウザが独自にMIMEタイプを判断する処理を抑止する 2header('X-Content-Type-Options: nosniff');

を追加してみるのはいかがでしょうか?

参考:【PHP】正しいダウンロード処理の書き方

WordPressのデバッグモードの切り替えしてみる案

私と同じようにzipの中身が文字化けしてブラウザに表示されてダウンロード出来ない方の解決済みの投稿を見つけたんですが(https://teratail.com/questions/279532)その方はCakePHPを使用されているみたいで、その解決策のコードを追加してもエラーが出るだけでした。

こちらは「デバッグモードをOFFにする」という解決方法とのことなので、
WordPressのデバッグモードをONまたはOFFに切り替えてみるのはいかがでしょうか?

wp-config.php に記載の
define('WP_DEBUG', false); または efine('WP_DEBUG', true);
trueからfalseまたは、falseからtrueに変更することで変化が起きるかご確認いただくとよいかもしれません。

参考:WordPressのデバッグモード

投稿2022/01/07 06:18

AsukaKobayashi

総合スコア296

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/01/07 21:10

ご回答ありがとうございます。 両方試させていただきましたが同じ文字化けの画面が表示されました。 wordpressにデバッグモードの機能があることを知りませんでした!上記のコードとは違うところでundefined variableを見つけることができました。ありがとうございます!
guest

0

ここをこのように変えてどうなるか試してみてください。何も表示されていないのはphp.iniでエラー制御をオフにしているため、なにか重大なエラーが見えていないだけの可能性が高いです。

PHP

1 while (ob_get_level()) { ob_end_clean(); }

php

1ob_end_clean();

投稿2021/12/27 02:30

FKM

総合スコア3647

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/12/27 05:44

ご回答ありがとうございます! ob_end_clean(); に変更してみました。 ダウンロードボタンを押した後に下記のような文字化けが表示されるようになりました。 PK 8b�Stest.txtPK? 8b�S��test.txtPK6&
FKM

2021/12/27 05:49

ブラウザに表示されているのでしょうか?
退会済みユーザー

退会済みユーザー

2021/12/27 05:53

はいchromeのブラウザに表示せれています。
FKM

2021/12/27 05:58

それが表示されているということは、どこかでその値をechoやvar_dumpなどをしている可能性があります。その部分をコメントアウトしましょう。 header命令前にそれをやると、エラーが起きますので。
退会済みユーザー

退会済みユーザー

2021/12/27 07:39

header命令前に文字化け部分が表示するようなechoやvar_dumpは見つけられなかったです。 上記のコードの上にはワードプレスの記事を表示するコードを一緒に同じファイルに書いていたのですが、それらが何か影響してるのかと思い上記のzipファイルの作成からダウンロードまでのコードを別のphpファイルに移してfunctionにして元のファイルから呼ぶようにしてみたのですが結果は同じで全く同じ文字化けが表示されまいた。
FKM

2021/12/27 07:49

mb_output_handler("pass"); mb_http_output("pass"); ここも変な気がします。ここは対象エンコードを表記するものなので。
phper.k

2021/12/27 07:53

header('Content-type: application/zip'); を追加すればいけそう
退会済みユーザー

退会済みユーザー

2021/12/28 07:50

返信遅れてすみません! FKMさん その二つのコードをコメントアウトしてみたんですが結果は同じで文字化けが表示されました。 phper.kさん header('Content-Type: application/zip; name="' . $zipFileName . '"'); の部分をコメントアウトして header('Content-type: application/zip'); を追加してみたのですが変わりはなく文字化けが表示されました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問