thinkphp 6 实现 pdf 接口需用 tcpdf 生成二进制流,设置正确响应头(contenttype、content-disposition),注册中文字体(如 stsongstdlight),过滤非法字符与 xss,避免大表查询和敏感信息泄露。

ThinkPHP 6 实现接口返回 PDF 文件,核心是“后端生成 PDF 内容 + 响应头设置正确 + 接口可被前端直接访问或下载”。它不依赖框架内置功能,而是通过第三方库(如 TCPDF)生成二进制流,并用 response() 统一输出。关键不在“多复杂”,而在“路径清晰、编码不乱、中文能显、响应可控”。
选对库:优先用 TCPDF,别碰 fpdf 或 dompdf
TCPDF 是目前 TP6 生态中兼容性最好、中文支持最稳的 PDF 生成库。它原生支持 UTF-8、内置中文字体(如 stsongstdlight)、可精确控制页眉页脚、支持 HTML 渲染和矢量图形,且无外部依赖(不像 dompdf 需要额外安装字体或扩展)。
- 执行
composer require tecnickcom/tcpdf安装 - 不要用
fpdf:不支持 Unicode,中文直接乱码或报错 - 慎用
dompdf:在 TP6 中常因 autoload 或 CSS 解析失败导致空白 PDF 或内存溢出
写一个 PDF 接口:控制器里生成并输出
在 app/controller 下新建控制器(如 PdfController.php),方法内完成三件事:初始化 TCPDF、写入内容、设置响应头并输出。
- 必须调用
setLanguageArray()或加载中文语言包(可选但推荐) - 务必用
setFont('stsongstdlight', '', 12)或addTTFfont()注册自定义中文字体(否则中文显示为方块) - 使用
writeHTMLCell()渲染含样式的 HTML 内容,比MultiCell()更灵活 - 最后用
Output('report.pdf', 'D')表示强制下载;若想浏览器内预览,改用'I'
让接口真正可用:响应头 + 路由 + 字符集
光生成 PDF 不够,前端访问时得能正常下载或打开。常见问题:点开空白、提示“无法加载PDF”、中文变问号——基本都是响应头或编码没设对。
- TP6 中避免直接
echo $pdf->Output(),改用response($pdf->Output('doc.pdf', 'S'))->contentType('application/pdf')->header(...) - 手动设置关键 header:
Content-Disposition: inline; filename="doc.pdf"(预览)或attachment(下载) - 确保路由注册为 HTTP 类型(
Route::get('export/pdf', 'PdfController@export')),不能是 console 或 event 路由 - 如果 PDF 含数据库数据,建议在生成前做
iconv('UTF-8', 'UTF-8//IGNORE', $text)过滤非法字节,防 TCPDF 报错中断
性能与安全小提醒
PDF 生成是 CPU 密集型操作,尤其带图表或大量 HTML 时。上线前注意两点:
- 不要在 PDF 接口中查大表或不做分页——先查好数据,再传给 TCPDF 渲染
- 敏感字段(如用户手机号、身份证号)需脱敏后再填入 PDF,避免缓存或日志泄露
- 若接口被高频调用,可加简单限流:
cache()->remember('pdf_lock:'.$ip, 60, function() { ... }) - 禁止将用户传入的 HTML 直接
writeHTML()—— 需过滤 XSS,至少用htmlspecialchars()处理变量内容











