WebDesign Dackel

PHPでファイルをダウンロードさせる時のエラーの対処

PHPでファイルをダウンロードさせる時のエラーの対処

Hatena0
Google+0
Pocket0
Feedly0

PHPでファイルのダウンロードをさせようとしよう!っていう記事はGoogleで検索をすると沢山出てきます。
ただ、記事で見つけたソースをそのまま使ってダウンロードが出来ないよ!となることがあったので、そんな時試してみる対処法をまとめておきます。

ファイルが正常にダウンロードされない

原因として考えられるのは、ファイルの容量が大きくてPHPがファイルを読み込んだ時点でメモリが足りなくなって0KBになってしまうことです。
readfile()を使っていてエラーが起きた、というのが多いかと思います。
対応するためのコードは以下。

$handle = fopen($path, "rb");
while(!feof($handle))
{
    print fread($handle, 4096);
    ob_flush();
    flush();
}
fclose();

上記のコードを、readfile($path)と置き換えます。ob_flush()flush()はどちらも実行する必要があります。
ちなみ僕は、ob_flush()を書かないでいて、ファイルが0KBになる事がありました。。

ダウンロードは出来るけどファイルが開けない

ファイルをダウンロードする時に、mb_output_handler()という関数が自動的に呼び出されることがあるようです。そのことでダウンロードしたファイルが壊れることがあります。
動画が開けない、画像が開けない、など。
対応するためのコードは以下。

mb_output_handler("pass");

これで、mb_output_handler()が自動的に呼ばれるのを防ぐことができるようです。

SSL環境、IE8以下でダウンロードが出来ない

IE8以下で、キャッシュを参照することができなくなってダウンロードに失敗することがあるみたいです。
対応するコードは以下。

header("Cache-Control: public");
header("Pragma: public");

headerは必ず、ブラウザに何かしらの出力を行う前に実行します。echoprintしてから実行するとエラーになります。

まとめ

上記のポイントを押さた最終的なコードを載せておきます。

$filename = "dl.zip";
$path = "data/".$filename;

mb_http_output("pass");
header("Cache-Control: public");
header("Pragma: public");
header("Content-Type:application/octet-stream");
header("Content-Disposition: attachment; filename={$filename}");
header("Content-Length: ".filesize($path));
$handle = fopen($path, "rb");

while(!feof($handle))
{
    print fread($handle, 4096);
    ob_flush();
    flush();
}
fclose();

実際使う際は、$filename$pathなどは外部のパラメータから取得することになると思います。

とりあえず、これまで経験したエラーの原因と解決策をまとめてみました。
他にもこんなのがあったよ、などありましたらコメントいただけたら幸いです。