1. 为什么选择FPDF在ThinkPHP5中生成中文PDF?
在Web开发中,PDF生成是个常见需求,特别是在需要打印报表、合同或导出文档的场景。FPDF作为PHP领域轻量级的PDF生成库,相比TCPDF或mPDF等更复杂的解决方案,具有以下独特优势:
- 无依赖:纯PHP实现,不依赖外部扩展或服务
- 内存友好:处理大文档时资源占用可控
- 接口简洁:基础API不到20个,学习曲线平缓
- 灵活性强:可通过扩展实现复杂功能
但原生FPDF对中文支持存在明显缺陷。我在实际项目中遇到过这些问题:
- 直接输出中文显示为空白
- 换行计算不准确导致文字重叠
- 无法使用系统字体外的中文字体
- 特殊符号(如《》℃)渲染异常
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与核心配置
2.1 基础环境搭建
首先确保ThinkPHP5项目已正确初始化。通过Composer安装FPDF:
bash复制composer require setasign/fpdf
创建基础控制器PdfController.php:
php复制namespace app\controller;
use think\Controller;
use FPDF;
class PdfController extends Controller {
public function generate() {
// PDF生成逻辑将在这里实现
}
}
2.2 中文字体解决方案
原生FPDF需要通过AddFont()方法手动添加字体。推荐使用以下两种方案:
方案一:使用开源字体文件
- 下载思源黑体(Source Han Sans)或阿里巴巴普惠体
- 将.ttf文件放入
public/fonts/目录 - 使用以下命令生成字体度量文件:
php复制require_once('tfpdf/tfpdf.php');
$pdf = new tFPDF();
$pdf->AddFont('SourceHanSansCN', '', 'SourceHanSansCN-Regular.ttf', true);
方案二:使用TFPDF扩展
TFPDF是FPDF的改进版,内置中文支持:
bash复制composer require tecnickcom/tfpdf
示例配置:
php复制require_once('tfpdf/tfpdf.php');
$pdf = new tFPDF();
$pdf->AddPage();
$pdf->SetFont('SimSun','',14); // 直接使用系统字体
提示:商业项目建议购买正版字体授权,微软雅黑等字体有版权风险
3. 完整中文PDF生成实现
3.1 基础文本输出
以下是支持中文的完整示例:
php复制public function generate() {
require_once('tfpdf/tfpdf.php');
$pdf = new tFPDF();
$pdf->AddPage();
// 添加字体(假设已放置字体文件)
$pdf->AddFont('SimSun', '', 'simsun.ttf', true);
$pdf->SetFont('SimSun', '', 14);
// 输出中文
$pdf->Cell(0, 10, '这是一个中文PDF测试文档', 0, 1);
$pdf->MultiCell(0, 10, '这是自动换行的中文文本。当内容超过页面宽度时,FPDF会自动处理换行问题。', 0);
// 输出到浏览器
$pdf->Output('D', '中文文档.pdf');
}
3.2 表格生成技巧
中文表格需要特别注意列宽计算:
php复制// 设置表格数据
$header = ['序号', '产品名称', '单价'];
$data = [
[1, '中文产品A', '¥100'],
[2, '测试商品B', '¥200']
];
// 计算列宽(中文字符按2个英文字符计算)
$colWidths = [15, 60, 30];
// 绘制表头
foreach($header as $i=>$col) {
$pdf->Cell($colWidths[$i], 7, $col, 1);
}
$pdf->Ln();
// 填充数据
foreach($data as $row) {
foreach($row as $i=>$col) {
$pdf->Cell($colWidths[$i], 6, $col, 1);
}
$pdf->Ln();
}
3.3 页眉页脚处理
php复制class PDF extends tFPDF {
function Header() {
$this->SetFont('SimSun','B',15);
$this->Cell(0,10,'公司机密文档',0,0,'C');
$this->Ln(20);
}
function Footer() {
$this->SetY(-15);
$this->SetFont('SimSun','I',8);
$this->Cell(0,10,'第 '.$this->PageNo().' 页',0,0,'C');
}
}
4. 实战问题排查与优化
4.1 常见中文乱码问题
问题现象:文字显示为方框或空白
- 检查点1:确认字体路径正确且可读
- 检查点2:确保PHP文件本身保存为UTF-8无BOM格式
- 检查点3:输出前确认字符串编码:
php复制// 转换编码(如从数据库获取的数据)
$text = iconv('UTF-8', 'CP936//IGNORE', $originalText);
4.2 性能优化建议
-
字体子集化:对于只使用少量汉字的情况,可以用
pyftsubset工具精简字体文件bash复制pyftsubset source.ttf --text="需要保留的文字" --output-file=small.ttf -
缓存生成结果:
php复制$cacheFile = 'cache/'.md5($content).'.pdf'; if(!file_exists($cacheFile)) { $pdf->Output('F', $cacheFile); } readfile($cacheFile); -
批量处理优化:使用
SetAutoPageBreak(false)禁用自动分页,最后统一处理
4.3 高级功能实现
中文水印:
php复制$pdf->SetFont('SimSun','',50);
$pdf->SetTextColor(220,220,220);
$pdf->RotatedText(50,150,'机密文件',45);
中文条形码:
php复制$pdf->SetFont('SimSun','',10);
$pdf->Cell(0,10,'产品编号:',0,1);
$pdf->Write1DBarcode('中文123', 'C128', '', '', '', 20);
我在实际项目中发现,当需要生成包含大量中文表格的PDF时,推荐采用分页预计算策略:先统计所有行的高度,再决定分页位置,避免表格跨页断裂。这比依赖自动分页能获得更好的视觉效果。
