
こんにちは、cakephp3を用いて帳票出力システムを作りたいです。
帳票出力ボタンを押すと、AjaxでPHPのコントローラーに要求し、サーバからデータ処理を行い、その内容をPhpSpreadsheetを使ってExcelファイルに出力し、クライアントのダウンロードフォルダーにファイルをダウンロードさせたいです。
問題は、ファイルがクライアントのダウンロードフォルダーには落とせないとのことです。
phpspreadsheetのrecipesを読むと、$writer->save('php://output')でクライアントにダウンロードさせられると書いてましたが、以下のソースを実行すると、エラーや警告もなく動くけどファイルが生成されません。ブラウザーのデバッグツールでも問題なく、ajax値も成功が戻ってきました。
ファイル名が日本語になっているため、Header情報には文字化けしていたので、英語のファイル名に変えてみても同じでした。
(PS:もし、ファイル名を文字化けせずにHeaderに設定できる方法もあれば教えて頂きたいです。)
$writer->save($outputFilename); のように、ファイル名を設定すると、プロジェクト経路のbinフォルダーに正しくファイルが生成されます。(この場合もHeaderのファイル名は文字化けしますが、ダウンロードされたファイル名は正しく表示されます。)
何が問題なのか、全く分からず…三日間この問題にハマって全然進めない状況です。
何かヒントや解決策があれば教えてください。よろしくお願いします。
php
1<?php 2// Excel出力するためのプラグイン 3use PhpOffice\PhpSpreadsheet\Writer\Xls; 4use PhpOffice\PhpSpreadsheet\Spreadsheet; 5require_once(ROOT .DS. "vendor" . DS . "autoload.php"); 6 7public function sectionsheet(){ 8 …省略 9 if ($this->request->is('ajax')) 10 { 11 //ファイル名を日本語にすると、Headerで文字化けする。 12 $outputFilename = "2018年度帳票.xls"; 13 //テスト用のシートを作る 14 $spreadsheet = new Spreadsheet(); 15 $spreadsheet->setActiveSheetIndex(0) 16 ->setCellValue('A1', '日本語'); 17 $spreadsheet->getActiveSheet()->setTitle('Simple'); 18 $spreadsheet->setActiveSheetIndex(0); 19 //ダウンロードするためのヘッダー設定 20 header('Content-Type: application/vnd.ms-excel'); 21 header('Content-Disposition: attachment;filename="'.$outputFilename.'"'); 22 header('Cache-Control: max-age=0'); 23 //Excelファイルを出力する。 24 $writer = new Xls($spreadsheet); 25 //問題はこの部分、$writer->save($outputFilename); は正常動作します。(プロジェクトのbinフォルダーにファイル生成される。) 26 $writer->save('php://output'); 27 28 exit; 29 30 } 31}
追加:色々調べた結果、CakephpのCallbackStreamを利用する、との方法もあり、以下のように書いてみましたが、同じ結果でした。
PHP
1//public function sectionsheet()の中 2$stream = new \Cake\Http\CallbackStream(function(){ 3 $spreadsheet = new Spreadsheet(); 4 $spreadsheet->setActiveSheetIndex(0) 5 ->setCellValue('A1', '日本語'); 6 $spreadsheet->getActiveSheet()->setTitle('Simple'); 7 $spreadsheet->setActiveSheetIdex(0); 8 9 header('Content-Type: application/vnd.ms-excel'); 10 header('Content-Disposition: attachment;filename="2018年度帳票.xls"'); 11 header('Cache-Control: max-age=0'); 12 13 $writer = new Xls($spreadsheet); 14 $writer->save('php://output'); 15 exit; 16 17}); 18 19return $this->response->withFile($stream, ['download' => true, 'name' => "2018年度帳票.xls"]);
参考:AJAXはこんな風に書きました。ブラウザーのデバッグツールで確認すると、$writer->save('php://output');で動かすと、dataに文字化けした値がリターンされますが、多分出力されたファイルが化けて表示されていると思われます。
AJAX
1$.ajax({ 2 url:urlPath, 3 type:'POST', 4 data:formData, 5 cache:false 6}) 7.done(function(data,status) 8{ 9 if(status) 10 { 11 alert('成功?'); 12 } 13 location.reload(); 14}) 15.fail(function(data){ 16 alert('失敗'); 17 location.reload( 18});
追加:リスポンスされた時のHeader情報は以下のようになっています。(ファイル名は、日本語になっています)
また追加:以下のように、出力部だけ別の関数にし、ブラウザーのURLに /sheets/sectionsheetouput と入力すると、クライアントに落ちることまで確認しました。
PHP
1public function sectionsheetoutput() 2 { 3 $this->autoRender = false; 4 $this->viewBuilder()->setLayout(false); 5 6 // Excel出力するためのファイル名とフォルダー名を設定する。 7 date_default_timezone_set('Asia/Tokyo'); 8 $outputDate = date('Ymd_His'); 9 $outputFilename = $outputDate . "_test.xlsx"; 10 11 $spreadsheet = new Spreadsheet(); 12 13 $spreadsheet->setActiveSheetIndex(0) 14 ->setCellValue('A1', '日本語_japanese'); 15 16 $spreadsheet->getActiveSheet()->setTitle('Simple'); 17 $spreadsheet->setActiveSheetIndex(0); 18 19 // header('Content-Type: application/vnd.ms-excel'); 20 header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); 21 header('Content-Disposition: attachment;filename="'.$outputFilename.'"'); 22 header('Cache-Control: max-age=0'); 23 $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); 24 $writer->save('php://output'); 25 exit; 26 }
追加に追加:$writer->save('php://output'); にすると、やはりヘッダーについてエラーがでました。
ERROR
12018-12-18 17:43:32 Warning: Warning (512): Unable to emit headers. Headers sent in file=D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php line=404 in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\cakephp\cakephp\src\Http\ResponseEmitter.php, line 48] 2Request URL: /sheets/sectionsheet 3Referer URL: http://localhost:8765/sheets/sectionsheet 4Trace: 5Cake\Error\BaseErrorHandler::handleError() - CORE\src\Error\BaseErrorHandler.php, line 153 6Cake\Http\ResponseEmitter::emit() - CORE\src\Http\ResponseEmitter.php, line 48 7Cake\Http\Server::emit() - CORE\src\Http\Server.php, line 106 8[main] - ROOT\webroot\index.php, line 40 9 10 11 122018-12-18 17:43:32 Warning: Warning (2): Cannot modify header information - headers already sent by (output started at D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php:404) in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\cakephp\cakephp\src\Http\ResponseEmitter.php, line 148] 13Request URL: /sheets/sectionsheet 14Referer URL: http://localhost:8765/sheets/sectionsheet 15Trace: 16Cake\Error\BaseErrorHandler::handleError() - CORE\src\Error\BaseErrorHandler.php, line 153 17header - [internal], line ?? 18Cake\Http\ResponseEmitter::emitStatusLine() - CORE\src\Http\ResponseEmitter.php, line 148 19Cake\Http\ResponseEmitter::emit() - CORE\src\Http\ResponseEmitter.php, line 54 20Cake\Http\Server::emit() - CORE\src\Http\Server.php, line 106 21[main] - ROOT\webroot\index.php, line 40 22 23 24 252018-12-18 17:43:32 Warning: Warning (2): Cannot modify header information - headers already sent by (output started at D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php:404) in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\cakephp\cakephp\src\Http\ResponseEmitter.php, line 181] 26Request URL: /sheets/sectionsheet 27Referer URL: http://localhost:8765/sheets/sectionsheet 28Trace: 29Cake\Error\BaseErrorHandler::handleError() - CORE\src\Error\BaseErrorHandler.php, line 153 30header - [internal], line ?? 31Cake\Http\ResponseEmitter::emitHeaders() - CORE\src\Http\ResponseEmitter.php, line 181 32Cake\Http\ResponseEmitter::emit() - CORE\src\Http\ResponseEmitter.php, line 55 33Cake\Http\Server::emit() - CORE\src\Http\Server.php, line 106 34[main] - ROOT\webroot\index.php, line 40 35 36 37 382018-12-18 17:43:32 Warning: Warning (2): Cannot modify header information - headers already sent by (output started at D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\phpoffice\phpspreadsheet\src\PhpSpreadsheet\Writer\Xlsx.php:404) in [D:\Bitnami\wampstack-7.1.7-0\apache2\htdocs\djks\trunk\vendor\cakephp\cakephp\src\Http\ResponseEmitter.php, line 181] 39Request URL: /sheets/sectionsheet 40Referer URL: http://localhost:8765/sheets/sectionsheet 41Trace: 42Cake\Error\BaseErrorHandler::handleError() - CORE\src\Error\BaseErrorHandler.php, line 153 43header - [internal], line ?? 44Cake\Http\ResponseEmitter::emitHeaders() - CORE\src\Http\ResponseEmitter.php, line 181 45Cake\Http\ResponseEmitter::emit() - CORE\src\Http\ResponseEmitter.php, line 55 46Cake\Http\Server::emit() - CORE\src\Http\Server.php, line 106 47[main] - ROOT\webroot\index.php, line 40
