前言
因为工作需要,需要使用PHP生成PDF,开始接触dompdf这个类库,dompdf可以把HTML文件生成PDF。
无奈使用的过程中遇到很多坑,细数dompdf的一些坑,中文乱码,中文换行,页面设置问题,生成文档,无奈还是使用,只能硬着头皮去找解决方案,网上许多方法只讲了一部分,没有发现一个好完整的解决方案,大多是随意复制粘贴,或者答非所问。
最后自己东拼西凑,终于整理出完整的解决方案,今天就记录下这些坑的解决方案,以免以后又踩坑,不废话直接进入正题。
使用环境
0、版本不同,可能会导致解决方案行不通,故记录使用环境。
1、Apache/2.4.33 (Win64) PHP/5.6.35
2、ThinkPHP5.0.21
3、dompdf v0.8.2
安装dompdf
1、使用命令行进入到项目根目录
cd C:\wamp64\www\tp5
2、使用composer安装dompdf
composer require dompdf/dompdf
3、检查是否安装成功,在C:\wamp64\www\tp5\vendor看是否有dompdf文件夹。
使用dompdf
0、因为dompdf有许多中文的坑,刚开始最好不要使用中文测试,免得心情糟糕。
1、引入Dompdf
use Dompdf\Dompdf;
2、获得HTML内容、相对于项目入口的目录
$html = file_get_contents('templates/1.html');
3、加载html
$dompdf->loadHtml($html);
4、设置页面属性 A4的纸张,
$dompdf->setPaper('A4', 'portrait');
5、渲染PDF
$dompdf->render();
6、在浏览器中下载,这行代码会自动在浏览器中下载
$dompdf->stream();
中文乱码问题
0、重点来了,相信这个问题不解决,大家也不会再考虑使用这个类库,一堆乱码看着简直心情糟糕透了。
1、下载类库语言安装脚本
https://github.com/dompdf/utils.git
2、将里面的load_font.php文件拷贝到项目根目录,和verdor同级
目录:C:\wamp64\www\tp5
3、下载一个宋体字体 simsun.ttf,也放到项目根目录,这时load_font.php和simsun.ttf应该在同一级目录
目录:C:\wamp64\www\tp5
4、开始安装字体,使用命令行进入当前目录,并安装字体
cd C:\wamp64\www\tp5
php load_font.php simsun.ttf simsun
命令说明 php load_font.php 调用这个文件,并传入字体路径,字体名字
注意这一步,最后的simsun最好不要添加引号,看有一些例子写了引号,导致后面声明字体使用不上。
5、安装结果图,显示这些东西基本就完成字体安装。
6、去类库字体目录检查是否安装成功
C:\wamp64\www\tp5\vendor\dompdf\dompdf\lib\fonts
找到是否有simsun.ttf和simsun.ufm2个文件
7、一般来说到上一步就安装成功,不放心可以进行终极检查
进入到这个目录:C:\wamp64\www\tp5\vendor\dompdf\dompdf\lib\fonts
找到这个文件:dompdf_font_family_cache.php
看下是否有以下这段,没有就添加上,有就最好。
'simsun' => array(
'normal' => $fontDir . '/simsun',
'bold' => $fontDir . '/simsun',
'italic' => $fontDir . '/simsun',
'bold_italic' => $fontDir . '/simsun',
)
8、在HTML中使用我们安装的字体,你可以在这个HTML任何地方写这个字体样式,不过为了全文显示正常最好还是在这写。
<body style="font-family:simsun">中文字体</body>
这样我们就可以愉快的使用中文字体了。
中文换行问题
0、当我开心解决了中文乱码问题之后,又发现了换行问题,中文不会换行,在网上找到寻找到了解决方案不过有点出入,版本不一样的问题。
1、寻找到Text.php文件
我的目录:C:\wamp64\www\tp5\vendor\dompdf\dompdf\src\FrameReflower\Text.php
2、找到相关代码
// split the text into words
$words = preg_split('/([\s-]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$wc = count($words);
3、替换以上代码,或者注释掉以上代码,添加我们的代码。
preg_match_all("/./u", $text, $array);
$words = array(0);
$wc = count($words);
4、小提示,可能因为版本的变迁,文件、代码位置不一样,大家最好使用目录全文搜索那一段代码,而不是直接去找那个文件。
页面设置问题
0、不知道什么原因,网上大多的例子都是横向设置,我还纠结半天什么鬼,内容在一个页面显示不了分了好几页,只能说英文不好容易踩坑。
1、设置页面
//网上你可能看到很多这样的例子,我要竖着的看啊,坑。
$dompdf->setPaper('A4', 'landscape');
//找了类库说明,发现还有一个参数,这下终于可以正常显示了。
$dompdf->setPaper('A4', 'portrait');
2、为了更好将HTML转换成PDF,建议将HTML宽高设置成和A4大小接近,避免不必要的麻烦。个人还是要根据实际pdf显示情况来调节。
body {
margin: 0;
width: 820px;
height: 1160px;
}
PDF生成问题
0、又解决了一个问题,这下真的万事大吉了嘛,nono,dompdf目前还是存在样式问题,没有得到很好的解决,所以这点需要的注意。
1、对元素浮动支持不是很友好。float
2、目前不支持css3的属性,所以不要奢望做出很复杂的样式。
自定义注入变量方法
0、为什么要注入变量,直接使用TP5里的注入方法不就可以了?我们是直接读取模板文件,而不通过页面渲染出来,所以我自己写个方法,用来向HTML中注入一些变量。有很多方法可以实现,有兴趣大家慢慢探索。
1、批量生成pdf如果需要头尾模板分离的话,可以使用HTML拼接的方式。
$html = file_get_contents('public/letters/templates/html/header.html');
$html .= file_get_contents($path);
$html .= file_get_contents('public/letters/templates/html/footer.html');
2、HTML模板按照以下方式写要替换的变量,代表要替换的变量。
{test}
3、变量注入方法,将模板和所有的变量传入这个方法,返回一个新的模板。
/**
* 轻量级变量注入方法、可以自行完善
*/
public function inject($html,$common)
{
//匹配模式
$pattern = '/\{([\w]+)\}/';
//捕获所有的模板变量
preg_match_all($pattern,$html,$matches);
//变量替换
for($i=0;$i<count($matches[1]);$i++){
if(isset($common[$matches[1][$i]])){
$html = preg_replace('/\{'.$matches[1][$i].'\}/',$common[$matches[1][$i]],$html);
}
}
return $html;
}
4、完整例子代码:
//模板路径
$path = 'public/templates/1.html';
//文件生成路径
$filePath='public/pdf/test.pdf';
//声明一个DomPDF对象
$dompdf = new Dompdf();
//HTML组合
$html = file_get_contents('public/templates/html/header.html');
//中间需要替换的部分
$html .= file_get_contents($path);
$html .= file_get_contents('public/templates/html/footer.html');
//注入的变量
$data['test'] = 'test';
//HTML注入变量
$html = $this->inject($html,$data);
//加载HTML内容
$dompdf->loadHtml($html);
//设置PDF纸张、方向 portrait、landscape
$dompdf->setPaper('A4', 'portrait');
// 渲染pdf
$dompdf->render();
//生成一个pdf文件
file_put_contents($filePath,$dompdf->output());
结语
以上是我最近折腾dompdf的完整经历,从一个问题到一个问题,还好最终都一一解决了。
很多问题也不能只靠网上百度,也要学会自己思考,阅读源代码结合自己一些编程经验找到解决方案。
这也是本人第一篇比较长分享文章了,希望能帮助同样使用这个类库的人。