乐趣区

PHP ——-wkhtmltopdf的使用方法

一. 问题描述
需要用 php 把 html 生成 pdf,找了了个 php 扩展,HTML2PDF,只能生成一些简单的 HTML 代码,复杂的 HTML+css 无法生成。网上找到了强大的 wkhtmltopdf。
二.wkhtmltopdf 介绍
工具全名叫 “wkhtmltopdf” ; 是一个使用 Qt WebKit 引擎做渲染的,能够把 html 文档转换成 pdf 文档 或 图片 (image) 的命令行工具。(强调一下:是“命令行工具”)支持多个平台,可在 win,linux,os x 等系统下运行。
三.wkhtmltopdf 安装(linux 环境)
安装步骤很简单,我在这里就不赘述了,具体可以参照(https://blog.csdn.net/assasin…://blog.csdn.net/qq_26562641/article/details/72875344), 里面写的都很详细
问题 1:测试后发现,生成的 pdf 文件对中文并不支持(外国人写的软件,这个没办法)?

答案:自行下载中文字体,安装在 linux 的字体库,具体方法可以参照(https://yq.aliyun.com/ziliao/269854)进行操作,其中字体可以在此网站下载(http://www.font5.com.cn/font_download.php?id=150&part=1237886897)

*** 下面是重点戏!!!!!!!***

三.php 操作 wkhtmltopdf
方法:1. 一个是 exec 执行

2. 扩展包操作 (建议采用,本文介绍的就是这个方法,由于我们是采用 php 语言开发,所以我在 composer 中选用了

mikehaertl/phpwkhtmltopdf 包 )

四.mikehaertl/phpwkhtmltopdf 包的具体使用
1. 包的安装(composer 很方便)
2. 具体使用可以参照该包的使用说明
3. 使用中出现的问题:
q. 在本地环境测试可以正常的下载,但是在 linux 环境下却不行?
a.php.ini 的禁用函数 proc_open() 要去除,如果不行(将禁用函数去除)

q.php.ini 中的禁用函数去除后,还是不行,槽糕的是,把服务器搞的无法访问(解决办法:清除浏览器缓存)?
a. 说的这个问题,我们来科普一下 proc_open()—php 内置函数

proc_open(): 执行一个命令,并且打开用来输入 / 输出的文件指针。

wkhtmltopdf 使用该命令,来进行 pdf 文件的生成 & 写入工作(生成 & 写入基于管道命令),所以在输入 & 输出有一方出现问题,就会导致,该管道无法关闭,从而出现管道阻塞,从而导致宕机。见代码(取自:vendor/mikehaertl/php-shellcommand/Command.php 文件总的 execute 方法片段):

$process = proc_open($command, $descriptors, $pipes, $this->procCwd, $this->procEnv, $this->procOptions);
if (is_resource($process)) {
if ($this->_stdIn!==null) {
if (is_resource($this->_stdIn) &&
in_array(get_resource_type($this->_stdIn), array(‘file’, ‘stream’), true)) {
stream_copy_to_stream($this->_stdIn, $pipes[0]);
} else {
fwrite($pipes[0], $this->_stdIn);
}
fclose($pipes[0]);
}
$this->_stdOut = stream_get_contents($pipes[1]);
$this->_stdErr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);

$this->_exitCode = proc_close($process);

if ($this->_exitCode!==0) {
$this->_error = $this->_stdErr ? $this->_stdErr : “Failed without error message: $command”;
return false;
}
} else {
$this->_error = “Could not run command $command”;
return false;
}

代码中的 $descriptors,规定了包含了要传送至进程的管道的描述信息。第一个元素为描述符类型,第二个元素是针对该描述符的选项。有效的类型有:pipe(第二个元素可以是:r 向进程传送该管道的读取端,w 向进程传送该管道的写入端),以及 file(第二个元素为文件名)。
表达一个真实文件描述符的流资源类型(例如:已打开的文件,一个 socket 端口,STDIN)。
而我在实际调试中却发现,我在本地调试时,该参数写入端为 w, 而 linux 中写入端为 r, 这个是宕机的罪魁祸首。进行代码分析:
$descriptors = array(
1 => array(‘pipe’,’w’),
2 => array(‘pipe’, $this->getIsWindows() ? ‘a’ : ‘w’),

);
public function getIsWindows()
{
return strncasecmp(PHP_OS, ‘WIN’, 3)===0;
}

将 2 => array(‘pipe’, $this->getIsWindows() ? ‘a’ : ‘w’),=》修改为 2 => array(‘pipe’, ‘a’), 问题解决。

退出移动版