我在模态上有一个按钮,单击后我想根据xls模板文件生成Excel工作簿,然后提示用户下载/打开。
该按钮使用javascript打开一个新的空白窗口
click事件只是发生
var tsUrl = baseUrl + 'index.php?r=office/gen-t-s-xls&proj='+projNo+'&leg='+legNo+'&driver='+driverId;
var win = window.open(tsUrl, '_blank');
并调用以下控制器操作
public function actionGenTSXls($proj, $leg, $driver){
// https://phpspreadsheet.readthedocs.io/en/develop/topics/recipes/
if(!is_numeric($proj) || !is_numeric($leg) || !is_numeric($driver)){
echo 'Invalid entry.';
die();
}
//Get the Project Model
$model = Projects::find()
->where(['=', 'ProjNo', $proj])
->one();
if (!$model) {
echo "There was a problem with the submitted request. (1)";
die();
}
//Get the Project Leg Model
$modelLeg = ProjectsLegs::find()
->where(['=', 'ProjId', $model->ProjId])
->andWhere(['=', 'LegNo', $leg])
->andWhere(['=', 'DriverId', $driver])
->one();
if (!$modelLeg) {
echo "There was a problem with the submitted request. (2)";
die();
}
$timestamp = date('Ymd\THis'); // Date/Time stamp
$filename = 'TripSheet_'.$model->ProjNo.'_'.$modelLeg->LegId.'_'.$timestamp.'.xls';
if(YII_ENV_DEV){
$filepath = Yii::$app->basePath.'\web\files\excel\\';
}else{
$filepath = \Yii::getAlias('@webroot').'/files/excel/';
}
$file = $filepath . $filename;
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');
$sFile = Yii::$app->basePath.DIRECTORY_SEPARATOR.'templates'.DIRECTORY_SEPARATOR.'TS_Tmplt.xlsx';
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load( $sFile );
$spreadsheet->getProperties()
->setCreator("TS")
->setLastModifiedBy(User::findOne(Yii::$app->user->getId())->Dispatcher)
->setTitle("TS ".$model->ProjNo.'_'.$modelLeg->LegId)
->setSubject("TS ".$model->ProjNo.'_'.$modelLeg->LegId)
->setDescription("TS ".$model->ProjNo.'_'.$modelLeg->LegId);
//working on something with the spreadsheet/worksheet
$sheet = $spreadsheet->getSheetByName('Sheet1');
//Date
$sheet->setCellValue('K3', date("n/j/Y"));
$sheet->getStyle('K3')
->getNumberFormat()
->setFormatCode('m/d/yy');
//Order
if(!is_null($model->ProjNo)){$sheet->setCellValue('K4', $model->ProjNo);}
//Carrier Order
if(!is_null($model->CompTripNo)){
$sheet->setCellValue('K5', $model->CompTripNo);
$sheet->getStyle('K5')->getAlignment()->setShrinkToFit(true);
}
//Dispatcher
if(!is_null($model->DispatcherId)){$sheet->setCellValue('J11', User::findOne($modelLeg->DispatcherId)->Dispatcher);}
//Company Name
if(!is_null($model->ClientId)){
$sheet->setCellValue('E4', Clients::findOne($model->ClientId)->Company);
$sheet->getStyle('E4')->getAlignment()->setShrinkToFit(true);
}
//Start Date
if(!is_null($modelLeg->StartDt)){
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $modelLeg->StartDt);
$cellVal = $date->format("n/j/Y g:i A");
$sheet->setCellValue('E8', $cellVal);
}
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xls');
$writer->save('php://output');
}
现在,从一般意义上讲,它可以工作。它创建了xls,提示用户打开/下载。但这会在我的yii日志中生成错误。
[错误] [yii \ web \ HeadersAlreadySentException]异常 “ yii \ web \ HeadersAlreadySentException”,带有消息“ Headers has been” 已发送
我研究了无数类似的线程,并尝试了涉及
的各种排列ob_start();
if (ob_get_length()) ob_end_clean();
if (ob_get_contents()) ob_end_clean();
//etc...
似乎没有什么可以解决我当前的问题。
我已经转了一段时间(不缺少尝试,进行研究……),并认为我会得到一些专家的建议和学习。我是新手,所以如果您能解释一下,以便我学习,将不胜感激。
我决定简化代码以查看问题所在,因此生成了xls文件,因此可以暂时删除该代码,即使如此,仅用7行代码,我也会遇到相同的错误!
public function actionDownload(){
$filename = "TS.xls";
$file = "C:\Users\Dev\Downloads\TS.xls";
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load( $file );
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter( $spreadsheet, 'Xls');
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
$writer->save("php://output");
}
做了更多谷歌搜索,发现了我尝试过的帖子。通过添加die();在我行动的最后,错误消失了!有人可以解释。我以为这虽然是可行的,但这并不是一个正确的解决方案。
这最终是处理此问题的正确方法
替换下面的代码
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
$writer->save("php://output");
使用
$response = Yii::$app->getResponse();
$headers = $response->getHeaders();
$headers->set('Content-Type', 'application/vnd.ms-excel');
$headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"');
$headers->set('Cache-Control: max-age=0');
ob_start();
$writer->save("php://output");
$content = ob_get_contents();
ob_clean();
return $content;
非常感谢您抽出宝贵的时间来帮助我。感谢您的时间和精力!
答案 0 :(得分:0)
在您的第一个header
通话之前添加:
ob_end_clean(); // clear out anything that may have already been output
您的代码应类似于:
$file = $filepath . $filename;
ob_end_clean(); // clear out anything that may have already been output
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="'.$filename.'"');
header('Cache-Control: max-age=0');