Yii2-PHPSpreadSheet-标头已发送

时间:2019-07-05 01:10:36

标签: php yii2 phpspreadsheet

我在模态上有一个按钮,单击后我想根据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...

似乎没有什么可以解决我当前的问题。

我已经转了一段时间(不缺少尝试,进行研究……),并认为我会得到一些专家的建议和学习。我是新手,所以如果您能解释一下,以便我学习,将不胜感激。

更新1

我决定简化代码以查看问题所在,因此生成了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");
}

更新2 /解决方法

做了更多谷歌搜索,发现了我尝试过的帖子。通过添加die();在我行动的最后,错误消失了!有人可以解释。我以为这虽然是可行的,但这并不是一个正确的解决方案。

更新3 /解决方案

这最终是处理此问题的正确方法

替换下面的代码

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;

非常感谢您抽出宝贵的时间来帮助我。感谢您的时间和精力!

1 个答案:

答案 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');