読者です 読者をやめる 読者になる 読者になる

It's raining cats and dogs.

無駄なことなんてないはず

file_get_contentsとreadfile

PHPでファイルをDLさせる際のPHPコード例
を読んだ。ちょうど今仕事でこれをやっていたので、超タイムリーと思って読んでたんだけど、ちょっと疑問に思ったこと。このサイトではファイルの出力で以下のようなコードを使っている。

<?php
header('Content-Type: application/octet-stream'); # コンテンツファイル
header('Content-Disposition: filename=dl.zip');  # ダウンロードするファイル名
header('Content-Length: '.filesize('dl.zip'));   # ファイルサイズを指定することでプログレスバーが表示される。
echo file_get_contents("dl.zip");  # 実際のダウンロード
?>

で、疑問に思ったのは

echo file_get_contents("dl.zip");  # 実際のダウンロード

ここ。
他のサイト(どこかは忘れた)では

readfile("dl.zip");  # 実際のダウンロード

となっているのを見かけていたので、こっちのやり方でやっていたのだけど、はて?どっちのやり方が良いのだろう?と。
マニュアルを読んでもイマイチよくわからないので、ググってみると、この辺の方が見つかりました。
このサイトによると。

  • file_get_contents

変数に一旦保存する

  • readfile

読み込むと同時に標準出力する。
とのこと。
ということは、でかいファイルをダウンロードしたいときは一旦変数に保存するfile_get_contentsはmemory_limitに引っかかってエラーになるかもしれないってことね。なるべくreadfileを使うことにしよう。
でもobなんちゃらでバッファリングしてたら結局メモリ上に残っちゃうから、バッファをクリアするob_end_flushPHPの実行時間の制限を設定するset_time_limitは忘れないようにしないとな。
この辺はあんまし関係なかった。むしろファイル出力する前にob_end_flushしちゃだめ。フラッシュすることで、headerを出力する前にブラウザにレスポンスを送出しちゃってるよって怒られる。

[追記]
でかいファイルは

$handle = fopen($pdfPath,”rb”);
while (!feof($handle)) {
  $buffer = fread($handle, $chunksize);
  echo $buffer;
  ob_flush();
  flush();
}
$status = fclose($handle);

id:kuliさんに教えてもらいました。
ソースも
http://jp.php.net/manual/ja/function.ob-flush.php#54126
とのこと。
つか、PHPマニュアルって重要そうなことが、コメント欄にさらっと書いてあることが多いよね☆