FuelPHP(or PHP)で巨大ファイルのダウンロードさせる
2013年04月18日 17時47分
※ 2013年5月1日 追記: この記事に乗っている内容で問題&勘違いがあったので続きを追加しました。こちらをお勧めします。
続・FuelPHPで巨大ファイルのダウンロードさせる
結構サイズの大きいファイルをダウンロードさせたい時に
何も考えずにFile::read($path)を実行したらメモリー不足エラーが出てしまいました。
Error – Allowed memory size of 10485760 bytes exhausted (tried to allocate 34990081 bytes)
File::read()の中を読んでみると第2引数の$as_stringがfalseの場合、
readfile関数でブラウザ出力していました。
これだとファイルサイズ分だけメモリを消費してしまうのでphp.iniか.htaccessでmemory_limitを必要な分だけ増やすか、ファイルを少し読み込んではレスポンスに出力するストリーミング的な処理をする必要があります。
勿論、今回の対処は後者です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
+ ob_start(); $response = Response::forge(); $response->set_header('Content-Type', 'application/octet-stream'); $response->set_header('Content-Disposition', 'attachment; filename="download_file.zip"'); $response->send(true); - File::read($download_file_path); + if ($fp = fopen($download_file_path, 'rb')) { + while(!feof($fp) and (connection_status() == 0)) { + echo fread($fp, 1024 * 4); // 4mb + ob_flush(); + } + ob_end_flush(); + fclose($fp); + } exit; |
FuelPHPというよりは素のphpでの対応になってしまいましたがこれで巨大ファイルのダウンロードも一定のメモリ使用量で対応が可能になります。
connection_statusはクライアントとの接続がなくなったら余計な処理はせずにループを終了するための処理です。