整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

PHP转换HTML为PDF文档的方法和常见问题

司的某项业务需要与用户线上签订协议,即用户在线手写一个签名,后台将公司公章信息和用户的签名以及合同信息生成一份PDF文件,供用户查看和下载。



比对了一些插件,我们最终决定使用dompdf这个插件,插件的github在这里:https://github.com/dompdf/dompdf。

1. 使用方法

  • 安装可以使用composer或者直接下载源代码,使用require或者include引入。
  • 具体的使用方式,可以参考以下示例代码。
// 引入命名空间
use Dompdf\Dompdf;
// 初始化dompdf对象
$dompdf = new Dompdf();
// 加载html文档内容
$dompdf->loadHtml('hello world');
// 设置纸张类型和方向
$dompdf->setPaper('A4', 'landscape');
// 渲染HTML为PDF
$dompdf->render();
// 流输出
$dompdf->stream();

2. 常见问题和解决办法

2.1 中文乱码的问题

插件对于字体和编码问题是这样形容的:

PDF documents internally support the following fonts: Helvetica, Times-Roman, Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI encoding. In order for a PDF to display characters that are not available in Windows ANSI, you must supply an external font. Dompdf will embed any referenced font in the PDF so long as it has been pre-loaded or is accessible to dompdf and reference in CSS @font-face rules. See the font overview for more information on how to use fonts.The DejaVu TrueType fonts have been pre-installed to give dompdf decent Unicode character coverage by default. To use the DejaVu fonts reference the font in your stylesheet, e.g. body { font-family: DejaVu Sans; } (for DejaVu Sans). The following DejaVu 2.34 fonts are available: DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono.

尝试了一下,默认带的字体是无法渲染中文的,使用CSS的@font-face引入会报错(也可能是我打开方式不对)。这样就只好自己引入一个字体了。

插件给了一个安装语言文件的工具,地址再这里:https://github.com/dompdf/utils。

使用步骤:

  • 下载或者复制load_font.php文件,放到dompdf文件夹内,与src和test文件夹同级
  • 修改load_font.php文件中引入的autoload.php为项目实际的位置
  • 在命令行中执行php load_font.php simkai /path/to/simkai.ttf

这样,我们就可以在html文档的css中使用font-family属性来指定字体了。

html {
 font-family: simkai;
}

2.2 图片无法展示

插件应该是无法直接显示网络图片,所以需要将图片转换为BASE64格式才能显示。

将HTML文档中的所有图片转换为BASE64的方式:

function imgToBase64($html) {
 $html = preg_replace_callback('/<img(?:.*?)src="(.*?)"(?:.*?)\/?>/', function($matches) {
 $imageInfo = getimagesize($matches[1]);
 $base64 = "" . chunk_split(base64_encode(file_get_contents($matches[1])));
 $base64_image = 'data:' . $imageInfo['mime'] . ';base64,' . $base64;
 return str_replace($matches[1], $base64_image, $matches[0]);
 }, $html);
 return $html;
}

这样转换其实性能影响挺大的,感觉性能不太好可以加一下缓存。

ompdf是一个可以将HTML生成PD并保留样式效果的PHP第三方扩展。

下面就一步步讲解如何使用:

一、通过composer安装

composer require dompdf/dompdf


安装过程

二 、编写测试代码

(1)引用autoload.php

include 'vendor/autoload.php'; 

(2)实例化Dompdf

$dompdf=new \Dompdf\Dompdf();

(3)加载HTML

$dompdf->loadHtml($html); //$html 为HTML字符串

(4)设置纸张和方向

$dompdf->setPaper('A4', 'landscape'); //纸张大小和纸张方向

(5)生成PDF并下载

 $dompdf->render();
$dompdf->stream('数据字典.pdf');

三、导出PDF测试,发现中文乱码了


导出PDF发现中文乱码了

四、解决中文乱了问题

(1)下载支持中文的字体包放到根目录下(和vendor目录同级),这里演示使用的是阿里巴巴的普惠字体(字体格式是ttf的,小编原先下载使用的字体格式是otf格式的无效)

(2)下载dompdf字体安装工具解压到根目录(和vendor目录同级)

下载地址:https://github.com/dompdf/utils

(3)在命令行(CMD定位到根目录)下执行命令

php load_font.php "puhui" Alibaba-PuHuiTi-Light.ttf

执行成功后在路径(vendor\dompdf\dompdf\lib\fonts)下就会出现刚才的字体

(4)在样式文件中指定使用刚才安装的字体

body{font-family:puhui;}

(5)再次导出PDF测试成功


乱码问题解决

段时间做打印合同时,要生成pdf文件,所以就看了一下,有很多种生成方式,我这里用的是TCPDF,想用可以自行下载一下 下面举例说明很简单

if($_REQUEST['act']=='pdf'){

//1引入文件

require( './TCPDF/tcpdf.php');

//2获取到页面内容

$html=file_get_contents("http://localhost/demo.html");

//3实例化类

$pdf = new TCPDF(PDF_PAGE_ORIENTATIN, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

//4设置自带的字体

$pdf->SetFont('stsongstdlight', '', 12);

// 5.添加个页面

$pdf->AddPage();

// 6.将HTML生成PDF

$pdf->writeHTML($html);

// 7.输出(默认直接在浏览器显示)

$pdf->Output();

//生成的pdf可能会有样式问题,自行调节一下即可。

}

//上面只是简单的介绍一下如何使用,如果有特殊需求在自行了解,仅供入门参考。

在网上找到一个很好用的函数,顺便分享给大家,合同中需要转大写中文,下面函数即可。

//自动转换数字金额为 大写中文金额

function toChineseNumber($money){

$money = round($money,2);

$cnynums = array("零","壹","贰","叁","肆","伍","陆","柒","捌","玖");

$cnyunits = array("圆","角","分");

$cnygrees = array("拾","佰","仟","万","拾","佰","仟","亿");

list($int,$dec) = explode(".",$money,2);

$dec = array_filter(array($dec[1],$dec[0]));

$ret = array_merge($dec,array(implode("",cnyMapUnit(str_split($int),$cnygrees)),""));

$ret = implode("",array_reverse(cnyMapUnit($ret,$cnyunits)));

return str_replace(array_keys($cnynums),$cnynums,$ret);

}

function cnyMapUnit($list,$units) {

$ul=count($units);

$xs=array();

foreach (array_reverse($list) as $x) {

$l=count($xs);

if ($x!="0" || !($l%4))

$n=($x=='0'?'':$x).($units[($l-1)%$ul]);

else $n=is_numeric($xs[0][0])?$x:'';

array_unshift($xs,$n);

}

return $xs;

}

作者:吾林爱分享