PHP7.1升级至7.4后Dompdf生成空白PDF问题排查
故障原因
新版Dompdf对HTML语法规范、资源加载的校验比旧版本严格,代码中存在的几个问题会直接导致DOM解析中断、渲染输出空白,且不会在PHP日志中抛出显性错误:
- HTML语法存在硬错误:一是h1标签写法错误,
<h1 Report</h1>缺少标签闭合的尖括号,无法被正常识别;二是循环内拼接的<span class="volunteers">标签全程未写</span>闭合,导致DOM结构完全错乱;三是头部标签使用错误,将包裹样式、元信息的<head>标签错写为正文语义的<header>标签,样式引用位置不符合DOM解析规则。 - 资源加载触发静默失败:代码中引用了外部在线字体、相对路径的本地CSS文件,新版Dompdf默认关闭远程资源、非绝对路径本地文件的加载权限,遇到无法读取的资源时会直接终止渲染流程,不会抛出报错。
- 输出缓冲区污染:如果代码运行过程中存在提前输出(包括BOM头、未被关闭的echo输出、PHP级别的Notice/Warning、文件开头的多余空格),会破坏PDF的文件头结构,导致下载后的文件无法正常解析内容。
- 附带逻辑bug:
$count = $results->fetchColumn();写在$rows = $results->fetchAll();之后,PDO结果集指针在fetchAll执行完成后已经指向末尾,无法正确读取总条数值,不过该问题不会导致空白页。
修复方案
按以下步骤逐一调整即可:
- 修正所有HTML语法错误
- 将头部的
<header>改为标准<head>标签,拼接完样式引用后补全</head>闭合,再写<body>标签 - 把错误的
<h1 Report</h1>修正为<h1>Report</h1> - 循环内每条span标签的拼接末尾补上
</span>闭合标签
- 将头部的
- 调整Dompdf配置解决资源加载问题
初始化Options时开启对应权限,本地CSS文件改用服务器绝对路径引用,非必要直接删除外部在线字体引用,避免加载超时:$options = new Options(); $options->set('defaultFont', 'Courier'); $options->set('isRemoteEnabled', true); $options->set('isHtml5ParserEnabled', true); // 本地CSS引用替换为绝对路径,示例: // $html .= '<link href="'.$_SERVER['DOCUMENT_ROOT'].'/css/pdf.css" rel="stylesheet" type="text/css">'; - 清理输出缓冲区避免文件头污染
在调用stream()方法输出PDF前,清空所有提前输出的缓冲区内容:$dompdf->render(); while (ob_get_level()) { ob_end_clean(); } $dompdf->stream("mvyc-all-active-members-report.pdf"); - 修正计数逻辑
直接用PHP原生count($rows)统计查询结果总条数,替换原有的fetchColumn写法,避免结果集指针导致的计数错误。
修正后的HTML拼接参考代码
$html = '<html><head>'; $html .= '<meta charset="UTF-8">'; // 不需要外部字体可直接删除对应引用行 $html .= '<link href="'.$_SERVER['DOCUMENT_ROOT'].'/css/pdf.css" rel="stylesheet" type="text/css">'; $html .= '</head><body>'; $html .= '<h1>Report</h1>'; $count = count($rows); $html .= '<h2>'.$count.' Members</h2>'; $html .= '<p>Report dated: '.date("F j, Y, g:i a").'</p>'; $html .= '<hr>'; foreach ($rows as $r2 ) { $html .= '<span class="volunteers"><strong>'.$r2["lastname"].', '.$r2["firstname"]. '</strong>: '.$r2["address"]. ', '.$r2["phone"]. ', '.$r2["email"].'.</span><br>'; } $html .='<h3>--------------------End of Report--------------------</h3>'; $html .='</body></html>';
内容的提问来源于stack exchange,提问作者Norman Bird
相关产品推荐
相关产品推荐

