何故作ったのか
業務中にDBのSELECT結果を加工しcsvで出力する処理があったが、
出力されるファイルサイズが大きく、加工処理も複雑なものであった。
この処理でメモリ多く食ってしまうのではないかと思い簡単な対策として作成した。
ソース
$filename = '好きなファイル名を入れてください.csv';
//tmpファイル作成
$csvFile = tmpfile();
$metaData = stream_get_meta_data($csv);
//tmpファイルのパスを取得する
$csvpath = $metaData['uri'];
/*
tmpファイルに大量に書き込む処理
*/
//この例ではcsvなのでファイルによってContent-Typeを変える事
header("Content-Type: text/csv");
//-- ウェブブラウザが独自にMIMEタイプを判断する処理を抑止する
header("X-Content-Type-Options: nosniff");
//tmpファイルのサイズを渡す
header("Content-Length: " . filesize($csvpath));
//ファイル名を指定する
header("Content-Disposition: attachment; filename={$filename}");
//readfile()の前に出力バッファリングを無効化する
while (ob_get_level()) { ob_end_clean(); }
//tmpファイルのパスを取得し、出力する
readfile($csvpath);
//tmpファイルを破棄する
fclose($csvFile);
解説
ダウンロード処理に関しては以下の方が詳しいとのでこちらを参照されたし
【PHP】正しいダウンロード処理の書き方
https://qiita.com/fallout/items/3682e529d189693109eb
tmpファイル作成
//tmpファイル作成
$csvFile = tmpfile();
$metaData = stream_get_meta_data($csv);
//tmpファイルのパスを取得する
$csvpath = $metaData['uri'];
//~~中略~~~
fclose($csvFile);
tmpfile()
は書き込み可なユニークなファイルを作成し、そのハンドルを戻り値として返す関数である
ただファイルの名前や、保存先までは返してくれない為、stream_get_meta_data
で取得している。
PHP4ではuriが戻り値の配列に入っていないようだが、未だにPHP4を使っていると事はないだろう
未だに5.6.4を使っている筆者の現場も大差ないが
Content-Type
//この例ではcsvなのでファイルによってContent-Typeを変える事
header("Content-Type: text/csv");
//jsonの場合
header("Content-Type: application/json");
この箇所はダウンロードさせるファイルによって違うので以下を確認するといい
公式MIMEタイプ一覧
上では数が多く探すのが大変であれば、MDNの以下のページが分かりやすい
よくある MIME タイプ