mPDF生成的PDF仅浏览器可打开 Adobe Acrobat报格式损坏错误
问题核心原因
浏览器内置PDF解析器容错性极强,哪怕PDF文件流里混了少量多余字符也能正常渲染;但Adobe Acrobat对PDF格式校验非常严格,只要文件头、文件结构有一点污染就会报损坏/不支持错误。你当前的代码有两个核心问题:
- 自定义响应头逻辑冗余且错误,使用了非标准的
application/force-download类型,还重复声明了多次Content-Type - 没有清除输出缓冲区、没有终止后续代码执行,大概率存在PHP BOM头、调试输出、报错信息、多余空格等内容混进PDF文件流的情况,你手动写的时区计算逻辑和文件损坏问题没有关联。
可直接落地的修复方案
- 替换原有自定义header逻辑,不要自己手动写一堆下载头,优先用mPDF内置的输出方法,内置方法已经处理了所有标准头逻辑,不容易出错:
// 初始化mPDF、写入HTML内容的逻辑保持不变 $mpdf = new \Mpdf\Mpdf(); $mpdf->WriteHTML($yourHtmlContent); // 下载前先清空所有已存在的输出缓冲区,防止之前的输出污染PDF流 while (ob_get_level()) { ob_end_clean(); } // 直接调用mPDF的Output方法,第二个参数传'D'就是触发下载,不需要自己写header $mpdf->Output($name.'.pdf', 'D'); // 必须加exit终止后续执行,避免后面的代码输出多余内容 exit;
- 如果确实需要自定义响应头,删掉所有非标准配置,使用标准PDF头即可,参考如下:
case 'D': if (headers_sent()) { $this->Error('已有内容输出到浏览器,无法发送PDF文件'); } // 清空缓冲区 while (ob_get_level()) { ob_end_clean(); } // 标准响应头,不要用force-download、octet-stream这类非PDF的类型 header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="'.$name.'.pdf"'); header('Pragma: public'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); // 如果你是读取已经生成好的临时PDF文件输出,加上Content-Length头 // header('Content-Length: ' . filesize($yourTempPdfFilePath));
- 排查隐形输出污染
- 检查项目所有PHP文件,确保
<?php起始标签前没有任何空格、HTML内容、BOM头;删掉所有PHP文件末尾的?>闭合标签,避免标签后带多余空格输出。 - 输出PDF前不要执行echo、print_r、var_dump等任何输出操作,临时关闭PHP错误显示防止报错信息混进流:
error_reporting(0); ini_set('display_errors', 0); - 不要在mPDF输出逻辑后写任何其他执行代码,必须用exit终止。
- 检查项目所有PHP文件,确保
快速排查技巧:把下载下来的PDF文件用纯文本编辑器打开,如果文件开头不是
%PDF-标识,就说明前面混了多余内容,把开头到%PDF-之间的内容删掉再保存,就能被Adobe正常识别,顺着这个线索找是哪里输出了多余内容即可。
- 针对mPDF 6.x和PHP7.1+的兼容问题,不需要修改响应头里的时间逻辑,只需要在代码最开头设置正确的默认时区即可:
date_default_timezone_set('Asia/Shanghai');
内容的提问来源于stack exchange,提问作者relo80
相关产品推荐
相关产品推荐

