PHP(CakePHP)で検索した結果をCSVダウンロードをしたいのですが、件数が多い場合メモリ不足になってしまいます。
メモリ不足と判断した理由ですが、
- CakePHPのエラー画面でメモリ不足と表示される
- 数千件のデータなら問題ないが、数万件だと落ちる
- PHP.iniのmemory_limitを増やすと処理できるようになる
という点から判断しました。
エラーメッセージによると以下のコードのstr_replace()の部分でメモリが足りなくなっているようです。
memory_limitを増やすという対処法は難しいので、メモリ消費を減らす、適宜解放を行うなどの方法で実現したいと考えていますが、うまくコードが書けません。アドバイス等ありましたらお願い致します。
PHP
1public function export($results){ 2 $fp = fopen('php://temp', 'r+b'); 3 4 // 検索結果を書き込む 5 foreach ($results as $data) { 6 fputcsv($fp, $data); 7 } 8 9 rewind($fp); 10 $tmp = str_replace(PHP_EOL, "\r\n", stream_get_contents($fp)); 11 12 header("Content-Type: application/octet-stream"); 13 header("Content-Disposition: attachment; filename=".$this->filename); 14 echo mb_convert_encoding($tmp, 'SJIS-win', 'UTF-8'); 15 16 exit; 17}
解決できましたので、実装を追記しておきます。
修正したメソッド
PHP
1public function export($results){ 2 // フィルタを登録 3 stream_filter_register("eolFilter", "eol_filter"); 4 stream_filter_register("encodeFilter", "encode_filter"); 5 6 $fp = fopen('php://output', 'w'); 7 8 // フィルタを開いたストリームに付加する 9 stream_filter_append($fp, "eolFilter"); 10 stream_filter_append($fp, "encodeFilter"); 11 12 // ダウンロードさせる 13 header("Content-Type: application/octet-stream"); 14 header("Content-Disposition: attachment; filename=".$this->filename); 15 16 // 検索結果を書き込む 17 foreach ($results as $data) { 18 fputcsv($fp, $data); 19 } 20 21 fclose($fp); 22}
作成したフィルタクラス
PHP
1// 改行コードをPHP_EOLからCR+LFに置換するフィルタ 2class eol_filter extends php_user_filter { 3 function filter($in, $out, &$consumed, $closing) { 4 while ($bucket = stream_bucket_make_writeable($in)) { 5 $bucket->data = str_replace(PHP_EOL, "\r\n", $bucket->data); 6 $consumed += $bucket->datalen; 7 stream_bucket_append($out, $bucket); 8 } 9 return PSFS_PASS_ON; 10 } 11} 12 13// 文字コードをUTF-8からShift-JISに置換するフィルタ 14class encode_filter extends php_user_filter { 15 function filter($in, $out, &$consumed, $closing) { 16 while ($bucket = stream_bucket_make_writeable($in)) { 17 $bucket->data = mb_convert_encoding($bucket->data, 'SJIS-win', 'UTF-8'); 18 $consumed += $bucket->datalen; 19 stream_bucket_append($out, $bucket); 20 } 21 return PSFS_PASS_ON; 22 } 23}
参考ページ

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/12/04 04:54