1. 为什么选择dompdf生成中文PDF?
在ThinkPHP5项目中生成PDF文档时,开发者通常会面临多种技术选型。dompdf作为PHP生态中最成熟的HTML转PDF工具之一,其核心优势在于可以直接将HTML+CSS渲染为PDF文件,这比传统的FPDF等库更符合现代开发习惯。
我曾在电商订单系统中深度使用过dompdf,发现它特别适合以下场景:
- 需要保留HTML原有样式(如Bootstrap样式表)
- 已有现成的HTML模板需要复用
- 要求快速实现而不想从头编写PDF布局
但dompdf对中文的支持确实存在一些坑点。默认情况下生成的PDF会出现:
- 中文显示为空白方块
- 中文换行位置异常
- 部分CSS样式不生效
这些问题的根源在于dompdf的字体处理机制。它默认只内置了英文的Helvetica字体,要支持中文需要额外配置中文字体。下面我将分享在ThinkPHP5中解决这些问题的完整方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 安装dompdf
在ThinkPHP5项目中,推荐使用Composer安装dompdf最新稳定版:
bash复制composer require dompdf/dompdf
安装完成后,在控制器中引入dompdf:
php复制use Dompdf\Dompdf;
2.2 字体目录配置
dompdf默认会查找系统字体,但在Linux服务器上可能权限不足。更可靠的做法是手动指定字体目录。在ThinkPHP5的配置文件中(如config/pdf.php)添加:
php复制return [
'font_dir' => env('root_path') . 'public/static/fonts/',
'font_cache' => env('root_path') . 'public/static/fonts/',
'temp_dir' => env('runtime_path') . 'pdf/'
];
提示:确保fonts目录有写入权限(chmod -R 755 public/static/fonts)
3. 中文支持的核心解决方案
3.1 添加中文字体文件
将SimSun.ttf(宋体)或微软雅黑等中文字体文件放入配置的fonts目录。建议使用以下字体组合:
- SimSun.ttf(常规)
- SimHei.ttf(加粗)
- KaiTi.ttf(斜体)
在HTML的style标签中定义字体族:
html复制<style>
@font-face {
font-family: 'SimSun';
src: url('/static/fonts/SimSun.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
body {
font-family: 'SimSun', sans-serif;
}
</style>
3.2 编码设置
确保HTML文档声明了UTF-8编码:
html复制<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
在实例化dompdf时也需要指定编码:
php复制$dompdf = new Dompdf();
$dompdf->set_option('defaultFont', 'SimSun');
$dompdf->set_option('isHtml5ParserEnabled', true);
$dompdf->set_option('isRemoteEnabled', true); // 允许加载远程资源
4. 实战:生成带中文的PDF
4.1 基础示例代码
在ThinkPHP5控制器中创建生成方法:
php复制public function generatePdf()
{
// 准备HTML内容
$html = <<<HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>
@font-face {
font-family: 'SimSun';
src: url('/static/fonts/SimSun.ttf') format('truetype');
}
body { font-family: 'SimSun'; }
</style>
</head>
<body>
<h1>中文标题测试</h1>
<p>这是一段包含中文的PDF内容测试。dompdf可以正确渲染这些文字。</p>
</body>
</html>
HTML;
$dompdf = new Dompdf();
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
// 直接输出到浏览器
$dompdf->stream("document.pdf", ["Attachment" => false]);
// 或者保存到服务器
// $output = $dompdf->output();
// file_put_contents("public/pdf/output.pdf", $output);
}
4.2 复杂布局处理
当需要处理复杂中文排版时,有几个关键技巧:
-
表格边框问题:
使用CSS的border-collapse属性:css复制table { border-collapse: collapse; width: 100%; } td, th { border: 1px solid #000; padding: 8px; } -
中文换行控制:
css复制p { word-wrap: break-word; word-break: break-all; } -
页眉页脚实现:
通过PHP计算分页,在每页插入固定元素:php复制$canvas = $dompdf->getCanvas(); $font = $dompdf->getFontMetrics()->getFont("SimSun"); $canvas->page_script(function($pageNumber, $pageCount, $canvas, $fontMetrics) use ($font) { $canvas->text(30, 800, "第 {$pageNumber} 页/共 {$pageCount} 页", $font, 10); });
5. 常见问题排查指南
5.1 中文仍显示为方框
排查步骤:
- 确认字体文件路径正确且可读
- 检查HTML meta标签是否设置了UTF-8
- 查看服务器错误日志是否有字体加载失败记录
- 尝试在本地环境测试排除服务器配置问题
5.2 样式不生效问题
常见原因:
- 使用了dompdf不支持的CSS属性(如flex布局)
- 样式表路径错误
- 未启用远程资源加载
解决方案:
php复制$dompdf->set_option('isRemoteEnabled', true); // 允许加载外部CSS
$dompdf->set_option('isPhpEnabled', true); // 允许内联PHP
5.3 性能优化建议
当处理大量中文PDF时:
- 启用缓存:
php复制$dompdf->set_option('fontCache', 'path/to/cache'); - 预加载常用字体
- 对大文档分批次处理
6. 高级应用场景
6.1 与ThinkPHP5视图结合
利用TP5的视图引擎生成HTML:
php复制$html = $this->fetch('pdf_template', [
'title' => '中文PDF报告',
'content' => $data
]);
$dompdf->loadHtml($html);
模板文件(pdf_template.html):
html复制{include file="public:font_style"}
<div class="container">
<h1>{$title}</h1>
<div class="content">
{$content|raw}
</div>
</div>
6.2 生成中文合同文档
关键要点:
- 使用固定布局避免内容错位
- 添加数字签名位置
- 设置不可编辑属性:
php复制$dompdf->set_option('isPhpEnabled', true);
$dompdf->set_option('isJavascriptEnabled', false);
6.3 批量生成技巧
结合队列处理大批量生成:
php复制// 在命令行任务中
$pdf = new PdfGenerator();
foreach($documents as $doc){
$pdf->addJob($doc);
}
Queue::push($pdf);
7. 替代方案对比
当dompdf无法满足需求时,可以考虑:
-
TCPDF:
- 优点:原生中文支持好
- 缺点:需要手动布局
-
wkhtmltopdf:
- 优点:渲染精度高
- 缺点:需要服务器安装二进制文件
-
MPDF:
- 优点:中文支持完善
- 缺点:性能较差
实测对比表格:
| 工具 | 中文支持 | 性能 | 易用性 | 布局灵活性 |
|---|---|---|---|---|
| dompdf | ★★★☆ | ★★★☆ | ★★★★ | ★★★★ |
| TCPDF | ★★★★☆ | ★★★★ | ★★☆ | ★★★ |
| wkhtmltopdf | ★★★★☆ | ★★☆ | ★★★ | ★★★★★ |
| MPDF | ★★★★★ | ★★☆ | ★★★☆ | ★★★★ |
在实际项目中,我通常会根据以下标准选择:
- 简单中文文档:dompdf+字体配置
- 复杂中文报表:TCPDF
- 高保真打印:wkhtmltopdf
8. 实际项目中的经验总结
经过多个项目的实践,我总结了以下黄金法则:
-
字体预处理:
将字体文件转为dompdf优化过的格式:bash复制
php vendor/dompdf/dompdf/load_font.php SimSun /path/to/SimSun.ttf -
内存管理:
处理大文档时调整内存限制:php复制ini_set('memory_limit', '256M'); $dompdf->set_option('enable_php', true); -
错误处理:
封装自定义异常捕获:php复制try { $dompdf->render(); } catch (\Exception $e) { Log::error('PDF生成失败: '.$e->getMessage()); throw new PdfGenerationException($e->getMessage()); } -
性能监控:
添加生成耗时日志:php复制$start = microtime(true); $dompdf->render(); Log::info('PDF生成耗时: '.(microtime(true)-$start).'s');
对于高频使用的系统,建议:
- 建立字体缓存池
- 实现PDF生成队列
- 开发PDF预览中间件
这些经验都是从实际项目踩坑中总结而来,特别是处理政府公文这类对中文排版要求严格的场景时,上述方案经过了百万级文档生成的验证。
