yii框架本身不直接处理pdf解析,中文乱码主因是字体未嵌入、编码未映射或内容流未unicode解码,需从pdf源验证、解析库配置(如smalot/pdfparser注册中文字体映射)、生成端统一字体嵌入(如mpdf设fontdir/fontdata并禁用子集)三方面协同解决。

Yii框架本身不直接处理PDF解析,中文乱码问题通常出现在使用第三方PDF解析库(如 smalot/pdfparser、setasign/fpdi 或 tcpdf)时,核心原因是字体嵌入缺失、编码未正确映射或PDF内容流未按Unicode解码。解决需从PDF源、解析库配置、字体支持三方面协同处理。
确认PDF是否真正包含可提取的中文文本
很多“中文PDF”实际是扫描图像(OCR未做),解析器只能返回空或乱码。可用命令行工具快速验证:
-
Linux/macOS:
pdftotext -layout your.pdf - | head -n 20,若输出为方块、问号或空白,说明文本不可选,需先OCR - Windows:用Adobe Acrobat打开 → “文件→属性→字体”,查看是否列出中文字体(如“SimSun”、“NotoSansCJKsc”);若显示“Embedded Subset”且名称含“GBK”“UCS2”等,大概率可提取
- 在Yii中临时用
file_get_contents()读取PDF二进制头,检查是否含%PDF-1.(正常)或纯JPG/PNG魔数(实为图片)
使用 smalot/pdfparser 提取中文时的字体适配
该库默认不加载中文字体,遇到 CID 字符集(常见于中文PDF)会返回或空。需手动注入字体映射:
- 安装扩展:
composer require smalot/pdfparser - 在解析前注册常用中文字体路径(如系统自带或项目内嵌):
$parser = new \Smalot\PdfParser\Parser();<br> $parser->setFontDir(Yii::getAlias('@app/fonts/')); // 放入 simsun.ttc、NotoSansCJKsc-Regular.otf 等 - 关键:覆盖默认字体解析逻辑,在
Parser实例化后调用:$parser->setFontMap([<br> 'Adobe-GB1' => 'NotoSansCJKsc-Regular.otf',<br> 'GB-EUC-H' => 'simsun.ttc',<br> 'UniGB-UTF16-H' => 'NotoSansCJKsc-Regular.otf'<br> ]) - 提取时强制启用Unicode解码:
$document = $parser->parseFile('xxx.pdf');<br> $text = $document->getText(true); // 第二个参数 true 启用 UTF-8 转换
生成PDF时避免后续解析乱码(反向预防)
若PDF由Yii应用生成(如用 mpdf 或 tcpdf),必须从源头确保字体嵌入与编码统一:
- 使用
mpdf(推荐):$mpdf = new \Mpdf\Mpdf([<br> 'mode' => 'utf-8',<br> 'format' => 'A4',<br> 'fontDir' => [Yii::getAlias('@app/fonts/')],<br> 'fontdata' => [<br> 'simhei' => ['R' => 'simhei.ttf'],<br> 'noto' => ['R' => 'NotoSansCJKsc-Regular.otf']<br> ],<br> 'default_font' => 'noto'<br> ])<br> $mpdf->WriteHTML('<span style="font-family: noto;">你好,世界</span>'); - 禁用子集嵌入(否则解析器无法识别字体名):
'useSubstitutions' => false, 'autoScriptToLang' => false - 导出前调用
$mpdf->Output('xxx.pdf', 'F'),再用pdffonts xxx.pdf验证字体是否显示为“yes”和“embedded”
备用方案:调用系统级OCR处理扫描PDF
对纯图像PDF,PHP层集成Tesseract OCR是最可靠方式:
- 安装
tesseract-ocr和中文语言包:sudo apt install tesseract-ocr tesseract-ocr-chi-sim(Ubuntu) - 用
spatie/pdf-to-text库自动调用:composer require spatie/pdf-to-text<br> $text = (new \Spatie\PdfToText\Pdf())->setPdf('scan.pdf')->text();
它内部会将PDF转为PNG,再执行tesseract xx.png stdout -l chi_sim - 注意:需在Yii配置中允许shell执行,生产环境建议异步处理并加超时限制











