【PHP】大量データをfputcsvで瞬時にCSVファイル出力する方法

2019-09-23

phpでcsvを作成する場合、fputcsv関数を使用するだろう。しかし数十万行・20MB以上のデータをcsvファイルとして書き込みする場合、それなりに時間がかかってしまう。

今回通常のレスポンスタイム内(3秒以内)でPHPのfputcsvでファイルを書き出す必要があり、多少情報が少なくて調べたことをまとめる。

時間のかかるfputcsv

ネットで調べると以下のやり方がずらりと出てくる。ほとんどこればっかり書かれている。

$list = [
    ["hoge", "fuga"],
    //省略
]

$fp = fopen('export.csv', 'w');

foreach ($list as $fields) {
    fputcsv($fp, $fields);
}

fclose($fp);

30万行以上のデータを上記のfputcsvでファイル書き出ししようとしたら30秒程度かかったのだ。そりゃ一行ずつflieにputしていくからそのくらいかかるのだろう。

ググった時、この処理ばっかり出てくるんだが、PHPユーザーはまさかこのまま使用するのだろうか。

streamでファイル書き込み

上記の方法は一行ずつ書き込んでいるから遅いわけだ。つまり一発でcsvファイルにフラッシュできれば書き込みの処理は圧倒的に早くなる。

$stream = fopen('php://temp', 'w');
foreach ($csv as $line) {
    fputcsv($stream, $line);
}
rewind($stream); // ポインタを戻す
$content = stream_get_contents($stream);
fclose($stream);
file_put_contents('export.csv', $content);

php://tempというストリームに確保していき、stream_get_contentsで書き込む内容を1度にputする。なんとこれだけで3秒以内を実現できた。

streamの書き込みはずば抜けて早いみたい。csvファイルをレスポンスする時なんかこのstream(php://output)でやることが多い。