35803
お世話になります。

現在CakePHP3.4でダウンロードの処理を下記のようなコードで作成したのですが  
エラーが発生し、画面上に出力内容が表示されるという問題が発生しています。  
ヘッダーエラーを発生させずに処理をさせる方法とかはないでしょうか？  
※php.iniのbuffering_outputは4096になっており、ダウンロードするファイルサイズが  
このサイズを超過するとエラーが発生するのは分かりました。  
（onにすると大容量ファイルになった場合メモリを食いつぶしてメモリエラーになったため、NGでした。）

[xxxController.php]

```

    public function download()
    {
        $this->autoRender = false;
        $this->response->type('csv');
        $this->response->download('test.txt');
    
        $fp = fopen('php://output','w');
        stream_filter_append($fp, 'convert.iconv.UTF-8/CP932', STREAM_FILTER_WRITE);
    
        $user_list=array('value1','value2','value3','value4','value5','value6');
    
        for($i=0;$i<1000;$i++){
            $outStr = implode("\t", $user_list)."\r\n";
            fwrite($fp,$outStr);
        }
    
        fclose($fp);
    }
    
```

[エラー内容]  
Warning (512): Unable to emit headers. Headers sent in
file=/var/www/html/xxx/src/Controller/xxxController.php line=56
[CORE/src/Http/ResponseEmitter.php, line 48]  
Warning (2): Cannot modify header information - headers already sent by
(output started at /var/www/html/xxx/src/Controller/xxxController.php:56)
[CORE/src/Http/ResponseEmitter.php, line 148]  
Warning (2): Cannot modify header information - headers already sent by
(output started at /var/www/html/xxx/src/Controller/xxxController.php:56)
[CORE/src/Http/ResponseEmitter.php, line 178]  
Warning (2): Cannot modify header information - headers already sent by
(output started at /var/www/html/xxx/src/Controller/xxxController.php:56)
[CORE/src/Http/ResponseEmitter.php, line 178]

[追記]  
実際に行いたいこととしましては、dbなどから取得した情報をサーバ上に  
ファイルとして出力せずに、ユーザーのブラウザに対して出力（ダウンロードさせる）  
という処理になります。  
そのため、サーバに置いてあるファイルをダウンロードするのではなく  
ファイルを作成しつつエラー無くダウンロードさせる。という部分が知りたいです。  
（現状、そのつもりで処理を書いていますがヘッダーエラーが発生してしまう。）
CC BY-SA 3.0
2017-06-20T06:39:47.623
35742
2017-06-22T04:47:29.993
2017-06-21T09:16:12.947
12325
12325
question
php cakephp
CakePHP3.4でファイルを作成しつつダウンロードを行うとヘッダーエラーが発生する
動的にレスポンスを返したい場合は、 `Cake\Http\Response::withBody()` と
`\Cake\Http\CallbackStream` を使用します。

リクエストとレスポンスオブジェクト ボディーの設定 | CakePHP Cookbook  
<https://book.cakephp.org/3.0/ja/controllers/request-response.html#id18>

CallbackStream に、処理したい内容をクロージャーで記述します。

```

    public function download()
    {
        $this->autoRender = false;
    
        $stream = new \Cake\Http\CallbackStream(function () {
            $fp = fopen('php://output', 'w');
    
            stream_filter_append($fp, 'convert.iconv.UTF-8/CP932//TRANSLIT', STREAM_FILTER_WRITE);
    
            $user_list = ['value1', 'value2', 'value3', 'value4', 'value5', 'value6'];
    
            for ($i = 0; $i < 1000; $i++) {
                $outStr = implode("\t", $user_list) . "\r\n";
                fwrite($fp, $outStr);
            }
        });
    
        return $this->response
                ->withType('csv')
                ->withDownload('test.txt')
                ->withBody($stream);
    }
    
```
CC BY-SA 3.0
2017-06-22T04:47:29.993
35803
2017-06-22T04:47:29.993
2668
35742
answer