直接 composer require setasign/fpdi 会失败,因为 FPDI 仅是页面导入器,需搭配 TCPDF、FPDF 或 mPDF 等底层 PDF 库才能工作;单独安装会触发“No PDF parser available”异常。

为什么直接 composer require setasign/fpdi 会失败
因为 setasign/fpdi 本身不包含 PDF 解析/写入能力,它只是个“页面导入器”,必须搭配一个底层 PDF 处理库(如 setasign/tcpdf、setasign/fpdf 或 setasign/mpdf)才能工作。单独安装 fpdi 后调用 addPageFromTemplate() 或 useTemplate() 时,会立刻抛出 FpdiException: No PDF parser available。
常见错误现象:
– 调用 $pdf->setSourceFile() 返回 null 或抛异常
– getTemplateSize() 报错 “No parser found”
– Composer 安装后无任何可运行示例,文档里写的类找不到
- 必须同时安装 FPDI + 兼容的底层库,推荐组合:
composer require setasign/fpdi setasign/fpdf - 若项目已用
mpdf/mpdf,则改用composer require setasign/fpdi setasign/mpdf(注意版本兼容性,fpdi ^2.6支持mpdf ^8.1) - 不要装
tcpdf:它与 FPDI 的集成已过时且维护停滞,fpdi-tcpdf包早已废弃
如何用 FPDI + FPDF 追加一页到现有 PDF
核心思路是:用 Fpdi 读取原 PDF 的某页作为模板,再用 Fpdf 创建新文档,把模板页“导入”进去,最后在新文档上追加内容(文字、图像等)并保存。
典型使用场景:在合同末尾插入签名页、在报表 PDF 后附加二维码页、给发票 PDF 加盖电子章
立即学习“PHP免费学习笔记(深入)”;
-
Fpdi继承自Fpdf,所以可以直接复用Fpdf的绘图方法(Cell()、Image()、SetFont()) - 导入第 1 页(索引从 1 开始):
$pageId = $pdf->importPage(1);返回的是内部模板 ID,不是页码 - 用
$pdf->useTemplate($pageId)将该页绘制到当前页;之后才能调用AddPage()新增空白页 - 追加页必须在
useTemplate()之后调用AddPage(),否则新页不会被写入输出流
$pdf = new \setasign\Fpdi\Fpdi();
$pdf->AddFont('helvetica', '', 'helvetic.php');
$pdf->setSourceFile('original.pdf');
$tplId = $pdf->importPage(1);
$pdf->AddPage();
$pdf->useTemplate($tplId);
<p>// 追加内容到第 1 页(覆盖原页)
$pdf->SetFont('helvetica', 'B', 14);
$pdf->SetXY(50, 50);
$pdf->Cell(0, 10, 'Modified on ' . date('Y-m-d'), 0, 1, 'C');</p><p>// 再新增一页作追加页
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'This is an appended page.', 0, 1, 'L');</p><p>$pdf->Output('modified.pdf', 'F');
修改指定页内容时为何文字总被裁剪或偏移
FPDI 导入模板页后,坐标系原点默认在左下角(PDF 标准),而 Fpdf 默认原点在左上角——但 Fpdi 已自动做了翻转适配,所以你调用 SetXY(50, 50) 时,Y=50 指的是距顶部 50 单位,不是底部。问题通常出在没获取模板尺寸就硬写坐标。
性能影响:反复调用 importPage() 不会重复解析 PDF,FPDI 缓存了源文件解析结果;但每次 useTemplate() 都会重绘整个模板页,大文件下内存占用明显上升
- 务必先用
$size = $pdf->getTemplateSize($tplId)获取宽高,再做相对定位(如右下角加水印:SetXY($size['width'] - 60, $size['height'] - 20)) - 如果原 PDF 页面尺寸不统一(比如第 1 页 A4、第 2 页 Letter),需对每页单独
importPage()并检查getTemplateSize() - 中文乱码?别用默认
helvetica字体,要注册支持 UTF-8 的字体(如dejavusans),并确保useTemplate()前已AddFont()
生成的 PDF 打不开或显示空白页
最常被忽略的是输出时机和缓冲区干扰。FPDI/FPDF 的 Output() 必须在脚本结束前调用,且不能有任何前置输出(包括空格、BOM、echo、warning)。
容易踩的坑:
– 在 Output() 前有 var_dump() 或未捕获的 Notice
– 使用了输出缓冲(ob_start())但没清理干净
– Apache 的 mod_deflate 或 Nginx 的 gzip 压缩干扰了二进制 PDF 流
- 调试时先用
$pdf->Output('test.pdf', 'F')保存到磁盘,再用命令行file test.pdf确认是否真为 PDF 文件 - 若浏览器打开为空白,查看响应头:必须含
Content-Type: application/pdf和Content-Length,且无Transfer-Encoding: chunked干扰 - 线上环境禁用所有错误报告:
error_reporting(0); ini_set('display_errors', '0');,否则 PHP 错误信息会混入 PDF 二进制流导致损坏
FPDI 的“模板页”本质是 PDF XObject,不是可编辑的 DOM;所谓“修改页面”,其实是把原页当背景图重新绘制一遍,再叠加上层内容——这个底层逻辑决定了它无法真正编辑文本对象或矢量路径,只能覆盖式操作。



















