PHP生成PDF主流方案是tcpdf和dompdf:tcpdf纯PHP实现、适合精确控制但中文换行和图片支持弱;dompdf基于HTML渲染但CSS支持有限,需手动降级样式、字体路径必须绝对且显式加载。

PHP 生成 PDF 的主流方案只有两个:tcpdf 和 dompdf
别被“MPDF”“wkhtmltopdf”这些名字绕晕——实际项目里,tcpdf 是纯 PHP 实现、无外部依赖,适合生成结构简单但需精确控制(比如发票、条码)的 PDF;dompdf 把 HTML 渲染成 PDF,写法接近前端开发,但对 CSS 支持有限,float、flex、@media print 基本不认。mpdf 虽然功能强,但体积大、PHP 8.1+ 兼容性有坑,新项目除非明确需要中文分页或复杂页眉页脚,否则先别碰。
用 dompdf 生成带样式的 PDF,HTML 必须手写“退化版”
你写的现代 HTML/CSS,在 dompdf 里大概率会错位、漏字、甚至空白。它不解析 JS,不执行 @import,连 background-image 都只支持绝对路径本地文件(https:// 地址直接忽略)。所以得手动降级:
-
<div class="grid">→ 改成嵌套<table>或固定宽高的<div style="display: inline-block; width: 200px;"> - 字体必须用
@font-face显式加载且路径为服务器绝对路径,例如/var/www/fonts/simhei.ttf,不能是 URL 或相对路径 - 中文内容务必在
<body>加style="font-family: simhei;",否则默认字体不支持中文,显示成方块 - 生成前先用
file_get_contents()拿到完整 HTML 字符串再传给Dompdf,别传 URL——它不会自动 fetch 远程页面
tcpdf 写文字和表格容易,但图片缩放和中文换行是硬伤
tcpdf 的 writeHTML() 方法看着像能渲染 HTML,其实只是个简易 parser,遇到 <img src="data:image/png;base64,..."> 会直接崩溃;而 Image() 方法又要求图片路径必须是服务端真实可读路径,不能是 HTTP URL。更麻烦的是中文自动换行:它默认按字符截断,不是按词,长段落容易把“中华人民共和国”切成“中华人民共/和国”。解决办法只有两个:
- 用
writeHTMLCell()替代writeHTML(),并显式设置$w(宽度)和$h(高度)参数,让内部换行逻辑生效 - 中文段落提前用
str_split($text, $max_len)手动切行,再逐行Cell()输出 - 图片统一转成本地临时文件,用
Image('/tmp/chart_123.png', $x, $y, $w, $h)调用,别图省事走 base64
生成失败时最常卡在内存、超时和字体路径这三处
报错 Fatal error: Allowed memory size of ... exhausted 不一定是代码问题,很可能是 PDF 内容含高清图或大表格,dompdf 渲染时吃光内存;tcpdf 则常见 Maximum execution time exceeded,尤其启用了 setHeaderCallback() 又在里面做了数据库查询。还有个隐蔽坑:tcpdf 的 addTTFfont() 如果路径写错,不会报错,只会静默回退到默认字体,导致中文全变方块,查日志都看不到线索。
立即学习“PHP免费学习笔记(深入)”;
- 生成前加
ini_set('memory_limit', '512M');和set_time_limit(120);,别依赖 php.ini 全局值 - 所有字体路径用
realpath(__DIR__ . '/fonts/simhei.ttf')确保是绝对路径,打印出来确认存在 - PDF 文件最终输出前,先用
ob_end_clean();清掉前面可能的 echo、warning 输出,否则生成的 PDF 打不开,Adobe 提示“损坏”
PDF 生成这件事,没有银弹。选哪个库不重要,重要的是接受它本质是个“像素级手工活”:样式要退化、图片要预处理、中文字要切行、错误不报明——每一步都在和渲染引擎的边界博弈。











