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

xihanshui發表於2018-06-21

導讀:本人初次寫部落格,有不足之處,請多多指教 。

因為專案中有需求,要動態的生成一些圖片,圖片的格式要求也比較嚴格就像是這樣的

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"

支援中文路徑和中文檔名, 但是使用者可不會這種操作,所以需要一些封裝(將執行流程抽象化),有一個哥們已經為我們做了,所以不需要我們去造輪子了


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();

這個安全的實現方式,不會使用到一些會威脅到伺服器安全的函式

相關文章