教你如何使用 PHP 优雅的生成 PDF 和 Image

导读:本人初次写博客,有不足之处,请多多指教 。

起因

因为项目中有需求,要动态的生成一些图片,图片的格式要求也比较严格就像是这样的

file

表格中的数据如 单价 数量都是动态的数据, 刚开始准备用 GD库 来操作,后来想想不太现实所以去找了找有没有比较成熟的 php 类库。有不少的类库,可以实现直接生成 PDF 而没有可以直接生成 Image 的扩展包。

后来发现了一个 开源的软件 wkhtmltox 该软件支持读取本地和网络端的网页,直接在本地生成 pdfimagewkhtmltox官方地址

  • 该软件有 Window 版本和 Linux 版本(具体支持详情可以查看其官网)
  • 下载之后需要将可执行文件的路径添加到环境变量中

具体的使用大概是这样的

    $ D:/wktopdf/wkhtmltopdf/bin/wkhtmltoimage --format "jpg" "./1-夏天/夏天.html" "./1-夏天/夏天.jpg"
    $ wkhtmltopdf --format "pdf"  "./1-夏天/夏天.html" "./1-夏天/夏天.pdf"

支持中文路径和中文文件名, 但是用户可不会这种操作,所以需要一些封装(将执行流程抽象化),有一个哥们已经为我们做了,所以不需要我们去造轮子了


PHP实现方式一

KnpLabs/snappy一个基于 wkhtmltoxphp 扩展包 扩展包GitHup地址

使用方式

$ composer require knplabs/knp-snappy
<?php
require __DIR__ . '/vendor/autoload.php';

use Knp\Snappy\Image;

$snappy = new Image('D:/wktopdf/wkhtmltopdf/bin/wkhtmltoimage');                           // 如果你是window环境, 需要将该路径添加到环境变量中
$snappy = new Image(__DIR__ . '/vendor/h4cc/wkhtmltoimage-amd64/bin/wkhtmltoimage-amd64'); // 如果你是linux环境

$str = <<<'EOD'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
    @font-face {
        font-family: myFirstFont;
        src: url('C:/Users/Administrator/Desktop/snopy/Microsoft Yahei.ttf');
    }

    body {
        font-family: myFirstFont;
    }

</style>
<body>

</body>
</html>
EOD;

$path = __DIR__ .'/我的/';

if (!is_dir($path)) {
    mkdir($path, 0755, true);
}

// 实际生产环境中为了不报错,需要进行异常处理
try {
    // 第一个参数是需要转换的 html
    // 第二个参数是文件保存路径
    $result = $snappy->generateFromHtml($str, $path . '夏天.jpg');
} catch( Exception $e) {
    var_dump($e->getMessage());
}

你也可以从 compoer 中安装需要的 wkhtmltox 依赖,
file

由于 wkhtmltox 是基于 QtWebKit rendering engine, 所以理论上是可以,生成比较复杂的 PDF ,只要你的 Css 写的够好。同时也支持网络协议,可以从网页中生成 PDFImage
如果要引入一些外部的 css 字体 图片 请使用 绝对路径, 生成的 PDF 的大小格式或者分页的使用方式请移步 GitHub地址

重点该扩展包会使用 proc_open 函数 去执行生成的 shell 脚本,所以对生产环境的安全有一定的威胁,最后被砍掉了。


安全的实现方式

由于安全原因,自己做的东西被砍了以后,也尝试了别的方式去实现这个功能,但是都不太如意,因为需要生成的 Image 比较复杂,要么是 css 支持的不是很好,要么就是字体和图片无法引入的错乱。最后想到了在服务端 window的批处理文件 .bat 文件来实现。后来也实现了,可是使用的复杂程度就上去了。
最后在 php 的官方文档中发现了这个

file

查看了一下也是基于 wkhtmltox 的一个 php 的扩展包,于是就动手去实现了一下。

依赖项

  • wkhtmltox 软件 liunx 版本(目前个人只是编译了linux的扩展,如果有兴趣的可以尝试去编译 window版本的)

具体步骤(linux环境)

  1. 首先需要到官网去下载软件 软件下载地址
  2. 扩展需要编译的源码 源码下载地址
  3. 请注意 wkhtmltox 区分操作系统是32位还是64位的
  4. 个人服务器环境是centos7, 使用的 wkhtmltox 的版本是 0.124 0.124版软件包下载地址

开始编译需要的php扩展

git clone https://github.com/krakjoe/wkhtmltox
cd wkhtmltox
phpize
// 这里因为每个人安装环境不一样 /path/to/wkhtmltox/installation 请将这个地址替为wkhtmltox真实的安装路径
 /// PATH 替换为真实的php配置路径
./configure --with-wkhtmltox=/path/to/wkhtmltox/installation --with-php-config = PATH
make
make install
  1. 修改配置文件 ,将生成的 wkhtmltox.so 添加到 php.ini 的配置中,重启php
  2. 安装成功效果

file

  1. 然后就可以 开始愉快的使用这个强大的工具了

HELLO PDF

use wkhtmltox\PDF\Converter as PDFConverter;
use wkhtmltox\PDF\Object as PDFObject;

$converter = new PDFConverter([
    "out" => "test.pdf"
]);

$converter->add(new PDFObject(
    file_get_contents("http://www.baidu.com")));

$converter->convert();

HELLO IMAGE

use wkhtmltox\Image\Converter as ImageConverter;
// 这里第一个参数可以传入 ` html ` 的字符串
$converter = new ImageConverter(null, [
    "fmt" => "png",
    "in" => "http://www.baidu.com",
    "out" => "test.png"
]);

$converter = new ImageConverter($str, [
    "fmt" => "jpg",
    "out" => "test.jpg"
]);
$converter->convert();

这个安全的实现方式,不会使用到一些会威胁到服务器安全的函数

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由 Summer 于 5年前 加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 31

@Summer 大神你好,可以申精吗

5年前 评论
66

性能如何,刚做完一个需要PDF的需求,用的phpoffice

5年前 评论

@66 因为是基于第三方的来源软件,速度很快。

5年前 评论
hainuo

@66 phpoffice 性能太差劲了吧 我之前用的是这个 tcpdf 还凑合吧

5年前 评论

@hainuo php官方推荐的这个使用起来,比较简单,是以php扩展形式使用的,性能和安全性上都比较高

5年前 评论
bestcyt

兄弟,错别字~GitHub地址

5年前 评论

@bestcyt 很强大兄弟^_^, 已改谢谢提醒。

5年前 评论

@CareyWang 前端很好用的截图包,不知道为什么停止更新了。发个教程?

5年前 评论
hainuo

@xihanshui 恩 看了 这个必须要安装第三方软件效率上肯定比 tcpdf要好,看了下还支持 win 抽空试一下

5年前 评论

@xihanshui 输php-config的时候就报这个错误 然后我就分开来写 好像成功了 然后make的时候就报另一个错误

5年前 评论

@pigsney 试试这样,先清除一下失败的编译信息,然后这样

./configure --with-wkhtmltox=/path/to/wkhtmltox/installation

这个里面路径是你的系统中 wkhtmltox 软件的主目录

5年前 评论

@xihanshui
试试这样,先清除一下失败的编译信息,然后这样
./configure --with-wkhtmltox=/path/to/wkhtmltox/installation
这个里面路径是你的系统中 wkhtmltox 软件的主目录

5年前 评论

file
已经安装成功

file
2个wkhtmltox目录下都没有installation,--with-wkhtmltox 没设置,但是可以编译成功

file

file
php -m 显示成功 phpinfo 里却找不到,怎么解决。。。。

5年前 评论
道法自然 3年前

@feijin_zzz 有没有将扩展名添加到php.ini 文件中,重启php 试试。

5年前 评论

尝试了很多,最后还是决定用 itext7。
!!! --- 语言只是工具,不要被工具限制住了。

5年前 评论

我想请教一下,使用php 扩展 wkhtmltox.so 来将html 代码转换成图片,能将方法写在控制器当中,然后通过浏览器访问,来触发wkhtmltox.so 将html 代码转换成图片。
我在我自己的本地服务器上面尝试过,发现通过在服务器上面运行脚本的方式: php convert_html_to_image.php 可以快速生成图片,但是通过 http://www.xxx.com/convert_html_to_image.p... 不能生成图片,并且,尝试通过url 访问的方式去生成图片的时候,apache 的cpu 占用十分高,容易导致服务器宕机。

5年前 评论

@joylee109 我使用的也是Apache 没有出现你说的问题 ,可以私聊下

5年前 评论

太赞了,正好需要

5年前 评论

太赞了,office文档->pdf->svg有什么好的方法吗

5年前 评论

wkhtmltoimage 这个生成图片可是二维码图片不显示 是怎么回事呢

5年前 评论
houmuxu

@xihanshui 您好,按您的代码,安全的实现方式 pdf可以生成,但是报错说找不到图片,我只编译了php扩展,在官网下载了wkhtmltox_0.12.5-1.bionic_amd64.deb这个,这个是要安装的吗

file

4年前 评论
duplicate symbol '_wkhtmltox_pdf_object_ce' in:
    .libs/wkhtmltox.o
    src/.libs/pdf.o
duplicate symbol '_wkhtmltox_pdf_ce' in:
    .libs/wkhtmltox.o
    src/.libs/pdf.o
duplicate symbol '_wkhtmltox_image_ce' in:
    .libs/wkhtmltox.o
    src/.libs/image.o
ld: 3 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [wkhtmltox.la] Error 1

make安装之后,报这个错误,请问怎么解决

3年前 评论

jquery导出JSON、XML、PNG、CSV、TXT,SQL,MS-Word,Ms-Excel Ms-Powerpoint、PDF插件www.yujianni.top/news/comp_artinfo...

3年前 评论

ImageConverter convert调用之后直接502,少数据测试都报这个,有人遇到吗

2年前 评论

我一直在使用bookjs-eazy, 对于高品质PDF 生成效果很好。兼容wkhtmltopdf,支持目录书签页码、页眉页脚、预览。

7个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!