Help us understand the problem. What is going on with this article?

PHPでPDFを作成するときはphpwkhtmltopdfで戦え [2016年度版]

More than 3 years have passed since last update.

PDFは相変わらずつらい

ブラウザの印刷機能にPDF変換が実装されて久しい、西暦2016年。
今もまだ色々なしがらみに押し負けたPHPerたちの不毛な戦いは続いています。
もう年の瀬ですが来年もPDFと戦っていくための情報をお届けします。

wkhtmltopdfとphpwkhtmltopdfで幸せになろう

wkhtmltopdf

http://wkhtmltopdf.org/

HTMLをWebkitで解釈してPDFに変換するGoogle謹製のツールです。
HTML5 も CSS3 も難なく解釈します。
2016年12月の時点での最新バージョンは0.12.4です。

mikehaertl/phpwkhtmltopdf

https://packagist.org/packages/mikehaertl/phpwkhtmltopdf

wkhtmltopdfをPHPで扱うためのラッパークラスです。
packagistで配布されています。

導入方法

wkhtmltopdfは64bit版Linux用バイナリを利用します。
導入環境は、CentOS 6.5 (64bit版) の想定です。
他の環境の場合は、本家サイトから適切なバージョンを入手しましょう。
また既にcomposerを導入しているプロジェクトを前提として話を進めます。

wkhtmltopdfのインストール

まずはwkhtmltopdfのインストールから進めていきます。
今回利用するバージョンは0.12.4です。

$ cd /usr/local/bin
$ wget http://download.gna.org/wkhtmltopdf/0.12/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
$ xz -dv wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
$ tar -xf wkhtmltox-0.12.4_linux-generic-amd64.tar

上記の操作を終えると、wkhtmltox ディレクトリが解凍されています。
実行ファイルのフルパスは /usr/local/bin/wkhtmltox/bin/wkhtmltopdf となります。
バージョンチェックのコマンドを実行してwkhtmltopdfの動確を行いましょう。

$ /usr/local/bin/wkhtmltox/bin/wkhtmltopdf --version
wkhtmltopdf 0.12.4 (with patched qt)

※ たいてい以下のパッケージが足りずに怒られるので、追加でインストールしてください

$ yum install -y libXrender libXext

日本語フォントのインストール

wkhtmltopdfには日本語フォントが入っていないので、日本語を通すとその部分だけが真っ白になります。
必ず日本語フォントを別途インストールしましょう。

今回はIPAフォントのお世話になることにします。
http://ipafont.ipa.go.jp/ipaexfont/download.html

$ wget http://dl.ipafont.ipa.go.jp/IPAexfont/IPAexfont00301.zip
$ unzip IPAexfont00301.zip
$ mv IPAexfont00301 /usr/share/fonts

mikehaertl/phpwkhtmltopdfのインストール

composerでインストールします。
導入したいプロジェクトで以下のコマンドを実行してください。

$ composer require mikehaertl/phpwkhtmltopdf

PDFの出力サンプル

mikehaertl\wkhtmlto\Pdfをインスタンス化して addPage() にHTMLを投げ込むと、ページが追加されます。
HTMLファイルの場所をフルパスで渡すこともできます。

send() を叩けばブラウザにPDFが表示されます。
またsend('xxx.pdf') のように第一引数を指定すると、定義したファイル名でPDFがダウンロードされます。

pdf.php
require './vendor/autoload.php';

$html = <<<EOF
<!DOCTYPE html>
<html>
    <style>
    body {
        padding: 7px;
        background-color: black;
    }
    .red {
        color: red;
        font-size: 50px;
    }
    .opacity {
        opacity: 0.3;
    }
    </style>

    <body>
        <div class="red">
            <p>PDF化してください!</p>
            <p class="opacity">何でもしますから!</p>
        </div>
    </body>
</html>
EOF;

use mikehaertl\wkhtmlto\Pdf;


$pdf = new Pdf([

     // バイナリの位置とエンコード形式
    'binary'   => '/usr/local/bin/wkhtmltox/bin/wkhtmltopdf',
    'encoding' => 'utf-8',

    // 以下の指定があるとPDFをページ端まで利用できる
    'margin-top'    => 0,
    'margin-right'  => 0,
    'margin-bottom' => 0,
    'margin-left'   => 0,
    'no-outline',

]);

// ページを追加
$pdf->addPage($html);

// ブラウザにPDFを表示
$pdf->send();

pdf.php.png

拡張して便利に

バイナリの位置とエンコード形式を初期設定。

pdf.php
use mikehaertl\wkhtmlto\Pdf as BasePdf;

class Pdf extends BasePdf
{
    const DEFAULT_OPTIONS = [
        'binary'   => '/usr/local/bin/wkhtmltox/bin/wkhtmltopdf',
        'encoding' => 'utf-8',
    ];

    public function __construct($options = null)
    {
        $this->setOptions(self::DEFAULT_OPTIONS);
        parent::__construct($options);
    }
}
example.php
(new Pdf($html))->send();

使用上の注意点

https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524

wkhtmltopdfはテーブルを使用すると、2ページ目以降にも自動でヘッダを付与してくれるのですが、
それがズレたり次の列と被ったりしてデザインが大きく崩れます。
こちらのスタイルを付与すると解決できます。

style.css
tr {
    page-break-inside: avoid;
}

まとめ

以前書いたこちらの記事から一年が経ち、色々な変更が見受けれての改訂版でした。
PHPでPDFを作成する時はwkhtmltopdf + snappyで戦え

v 0.12.3からwkhtmltopdfのインストール方法が変更され、アーカイブを解凍して配置するだけとなっていたり、
IPAフォントが以前のURLではダウンロード出来なくなっていたり、
SnappyがフォローしてくれていなかったHTTPヘッダの出力までラッピングしたphpwkhtmltopdfの存在を知ったり。
たった一年で色々起こるものです。

今後もPHPでPDFを操作する方法は定期的に調査して行こうと思います。
なにか気付いた点がありましたら、編集リクエストもお待ちしております。

morisuke
Vue.js / Laravelが得意。ご連絡はメールかTwitterでどうぞ。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした