mpdf 在 Yii2 中需手动集成官方包,类加载失败主因是路径配置错误或 classMap 干扰;中文乱码须启用 autoScriptToLang/autoLangToFont 并正确配置 fontDir 与 fontData;CSS 必须内联或分次写入,Output 模式需注意缓冲与权限。

mpdf 在 Yii 中不是框架原生组件,必须手动集成;直接 `use mPDF` 或 `new Pdf()` 报错,大概率是类未加载或配置路径错误。
Yii2 中 mPDF 类找不到?先确认安装方式和自动加载
别急着写代码,先看类能不能被自动加载。官方推荐用 mpdf/mpdf 官方包(非 yii2-mpdf 封装),因为后者已多年未维护,且对中文支持弱、Pdf::MODE_CORE 等常量容易冲突。
正确安装命令:
composer require mpdf/mpdf "^8.2"
安装后检查 vendor/autoload.php 是否已自动注册 mPDF 命名空间 —— 通常没问题;但如果你在 common/bootstrap.php 或 config/bootstrap.php 里手动加过 Yii::$classMap 映射(比如 'mPDF' => '@vendor/mpdf/mpdf/src/...),反而会干扰 Composer 自动加载,必须删掉。
验证是否可用:
$mpdf = new \Mpdf\Mpdf(); // 注意完整命名空间,不是 mPDF 或 MPDF
如果报 Class 'Mpdf\Mpdf' not found,说明:
– composer install 没成功(检查 vendor/mpdf/mpdf/src/Mpdf.php 是否存在)
– PHP 版本低于 7.4(mpdf 8.2+ 要求 ≥7.4)
– autoloader 被覆盖(如某些自定义 bootstrap 强制重置了 classMap)
mPDF 中文乱码的根因和最简修复
不是字体没选对,而是默认不启用 CJK 支持。即使传 'zh-CN' 参数,mPDF 8.x 也只当语言标识用,不自动加载中文字体。
必须显式启用 AdobeCJK 并指定字体路径:
$mpdf = new \Mpdf\Mpdf(['autoScriptToLang' => true, 'autoLangToFont' => true]);- 确保
ttf字体文件放在可读路径(如@app/fonts/simhei.ttf),并在初始化时传入: $mpdf = new \Mpdf\Mpdf([ 'fontDir' => [Yii::getAlias('@app/fonts')], 'fontData' => [ 'simhei' => [ 'R' => 'simhei.ttf' ], ], 'default_font' => 'simhei', ])- HTML 中避免用
<font face="...">,改用style="font-family: simhei"或 CSS 类
常见坑:
– fontDir 必须是绝对文件系统路径,@app/fonts 要用 Yii::getAlias() 解析
– simhei.ttf 文件权限为 644,Web 进程可读
– 不要混用 useAdobeCJK = true(这是 mPDF 7.x 的写法,8.x 已废弃)
renderPartial 渲染 PDF 页面时样式丢失?问题不在 CSS 引入方式
很多人把 CSS 放在 <link href="@web/css/print.css">,结果 PDF 里样式全失效 —— 因为 @web 是 URL 路径,mPDF 在服务端运行,根本不会发起 HTTP 请求去下载 CSS。
可行方案只有两个:
- 把 CSS 内联:用
<style>{file_get_contents(Yii::getAlias('@app/web/css/print.css'))}</style>嵌入 HTML 头部 - 用
WriteHTML($css, \Mpdf\HTMLParserMode::HEADER_CSS)分两次写入(先 CSS,再 HTML 内容)
注意:
– renderPartial 返回的是纯 HTML 字符串,不含 layout,所以 <head> 需要你手动补全
– 如果视图里用了 AssetBundle,它默认不会输出 CSS 到字符串中,得关掉:Yii::$app->assetManager->publishAssets = false;(临时禁用)或改用 AssetBundle::register() + 手动 getCssFiles()
导出到浏览器 vs 保存到服务器,Output() 参数不能只改路径
$mpdf->Output('report.pdf', 'D') 是下载,$mpdf->Output('/path/to/report.pdf', 'F') 是保存 —— 看似简单,但实际容易卡住:
-
'F'模式下,目标目录必须存在且 Web 进程有写权限(如/runtime/pdf/,别用/web/) -
'D'模式前必须清空输出缓冲:ob_end_clean();,否则 PDF 流前面混入空格或 warning 就打不开 - 不要在控制器里 return $pdf->render() 后再调
Output()——render()内部已经调了一次Output(),重复调会报 headers already sent
最稳做法:绕过封装,直接用原生 mPDF 实例操作,控制权更明确。封装层(如 kartik-v/yii2-mpdf)在复杂页眉页脚或分页场景下反而限制多、调试难。



















