質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

解決済

2回答

4722閲覧

CakePHP3で数万件のデータを出力

ssk

総合スコア332

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

0クリップ

投稿2017/06/04 06:37

編集2017/06/04 08:01

###前提・実現したいこと
数万件を一度に出力しようとすると、メモリ不足になります。
解消するために、5,000件ずつ処理する方法を選択しました。
しかし、2回目のループ(5,001〜)エラーになってしまいます。

headers already sent byで調べてみましたが、解決できず、、
助言いただけましたら、幸いです。

###発生している問題・エラーメッセージ

Cannot modify header information - headers already sent by

###該当のソースコード

PHP

1// 5000件ずつデータを取得するようにする 2 $limit = 5000; 3 $params = ['limit' => $limit, 'offset' => 0]; 4 5 while ($dataArr = $this->Hoges->find('all', $params)->hydrate(false)->toArray()) { 6 7 while(list($key,$val) = each($dataArr)){ 8 9 $data = [ 10 $val['id'], 11 ]; 12 13 fputcsv($fp, $data); 14 15 } 16 17 $params['offset'] += $limit; 18 19 }

###補足情報(言語/FW/ツール等のバージョンなど)
前回の質問
https://teratail.com/questions/78718

参考URL
http://beyondjapan.com/blog/2017/04/cakephp-findall-memoryleak-2

###追記
エラー全文

<pre class="cake-error"><a href="javascript:void(0);" onclick="document.getElementById('cakeErr5933b732a69a8-trace').style.display = (document.getElementById('cakeErr5933b732a69a8-trace').style.display == 'none' ? '' : 'none');"><b>Warning</b> (512)</a>: Unable to emit headers. Headers sent in file=/src/Controller/HogesController.php line=163 [<b>CORE/src/Http/ResponseEmitter.php</b>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shi_ue

2017/06/04 07:25

質問内容に、「2回目のループ(5,001〜)エラーになってしまいます」とありますが、提示されているコードでは、ループしていません。エラーが発生しているコードを記述してください。
ssk

2017/06/04 07:33

エラー全文を追記致しました。
ssk

2017/06/04 07:33

該当コードはfputcsv($fp, $data);です。
ssk

2017/06/04 07:35

ループしていない、、、list($key,$val) = each($dataArr)の書き方に誤りがありますか?
shi_ue

2017/06/04 07:36

いえ、5001件目からのデータはfindしてませんよ?
ssk

2017/06/04 07:43

参考URLを元に5,000件ずつ取得するコードを書きましたが、そのコードが間違っているということでしょうか?
shi_ue

2017/06/04 07:47 編集

わたしの目が節穴でなければ、質問文に載っているコードでは5000件を出力するだけです。参考URLに載っているコードだと、ちゃんと5000件ごとに取得しています。
ssk

2017/06/04 08:06

whileのループ構成を変更したところ、5万件をメモリ256Mで出力することができました!
guest

回答2

0

自己解決

shi_ue様の助言から、whileの書き方を変更しました。
メモリ256Mで5万件のデータ出力ができるようになりました。

PHP

1while ($dataArr = $this->Hoges->find('all', $params)->hydrate(false)->toArray()) { 2 3 while(list($key,$val) = each($dataArr)){ 4 5 $data = [ 6 $val['id'], 7 ]; 8 9 fputcsv($fp, $data); 10 11 } 12 13 $params['offset'] += $limit; 14 15 }

投稿2017/06/04 08:11

ssk

総合スコア332

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ssk

2017/06/10 15:05

Kosuke_Shibuya様、shi_ue様 低評価4件がついてしまいました。 低評価がお二方でしたら、コード上に問題または回答上に失礼がありましたでしょうか?この場を借りてお詫び申し上げます。。
guest

0

header関数より前で、エラーメッセージが出力されるから、header でエラーになっているだけですきっと。

投稿2017/06/04 06:39

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ssk

2017/06/04 06:46

ありがとうございます。 そもそも今のプログラムが間違っているということでしょうか?
退会済みユーザー

退会済みユーザー

2017/06/04 06:49

正しく動かないということは、間違っているということですよね。あっているとはお世辞も言えないと思いますが・・ そもそも、メモリエラーがあるということなのでから、それを解決することが必須で、そのエラーのためにheader でエラーになっています。だからメモリの問題を解決すればheader でエラーは起きません。
ssk

2017/06/04 06:55

そのエラーを解決するために、数万件のデータを5,000件ずつ処理しようとしました。 メモリ問題を解決するための考え方はどうでしょう、、ちなみに今のメモリの上限は256MBです。
退会済みユーザー

退会済みユーザー

2017/06/04 06:56

試しに、もっと減らした時はどうなりますか? 例えば、10件とか。
ssk

2017/06/04 07:00 編集

2万件前後は出力可能です。
ssk

2017/06/04 07:24

256M→812Mに変更したところ、5万件を出力できるようになりました。 812Mは個人的にかなり大きいと感じますが、実務では普通でしょうか? ※本番環境はXサーバーです。
退会済みユーザー

退会済みユーザー

2017/06/04 07:32

場合による
ssk

2017/06/04 07:34

今回のように大量データを扱う場合は、、、OKという認識で合っていますか?
退会済みユーザー

退会済みユーザー

2017/06/04 07:37

場合によるとしか言えません。 そもそもメモリの上限を上げられない環境だってあるし、csv 出力自体が必要のない機能かもしれません。csvより、他の手段の方がいい場合だってあります。
退会済みユーザー

退会済みユーザー

2017/06/04 07:39

csv出力機能をつけると、お客さんがexcel で開いてしまってデータを壊すことが多いので、実装しないことが多いです。
ssk

2017/06/04 07:47

りがとうございます。 今回はCSVの出力が必須でして。大量データを出力するには 1.メモリを上げる 2.メモリを抑えた出力 で対応せざるを得ないため、10万件以上のデータを考えると2の方が良いという結論に至りました。
退会済みユーザー

退会済みユーザー

2017/06/04 07:52 編集

メモリ使用を抑えるといっても、配列に格納している時点でNGですよね。 Generator でも使って出力したらいいんじゃないですか? この時点で、質問内容がずれています。
ssk

2017/06/04 08:09

Generatorを利用する方法は知らなかったので Kosuke_Shibuya様が以前に質問されたいた内容 https://teratail.com/questions/20518 を参考にGeneratorを勉強します。 今回は5,000件ずつ出力することで5万件のデータ出力ができましたので、自己解決にいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問