PHPでPDFを作成する時はwkhtmltopdf + snappyで戦え

  • 198
    Like
  • 0
    Comment

!!最新情報は以下の記事を参照して下さい!!

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

HTMLをPDFに変換するアプローチのつらみ

・インラインのCSSしか受け付けない
・そもそもCSS2.0系のプロパティしか受け付けない
・セレクタで要素が絞り込めない

mPDF、主に君のことだ。

wkhtmltopdfとsnappyで幸せになろう

wkhtmltopdf

http://wkhtmltopdf.org/
Webkit html to pdf の略。
名前からも分かるようにHTMLをWebkitで解釈してPDFに変換するGoogle謹製のツールです。
もちろん、HTML5 も CSS3.0 も難なく解釈します
最高感ある。

knplabs/knp-snappy

https://packagist.org/packages/knplabs/knp-snappy
wkhtmltopdfをPHPで扱うためのラッパークラスです。
packagistで配布されています。

導入方法

CentOS 6.5 (64bit版) を想定しています。
他の環境の場合は必要なバージョンが異なるので、本家サイトから適切なwkhtmltopdfパッケージを入手しましょう。

wkhtmltopdfのインストール

まずはwkhtmltopdfのインストールから進めていきます。
rpm -ivh 実行時にエラーが発生した場合は、エラーを見ながらyumで足りないパッケージを入れましょう。

$ cd /usr/local/src
$ wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2.1/wkhtmltox-0.12.2.1_linux-centos6-amd64.rpm
$ rpm -ivh wkhtmltox-0.12.2.1_linux-centos6-amd64.rpm

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

wkhtmltopdfには日本語フォントが入っていないので、日本語を通すとその部分だけが真っ白になります。
なので必ず日本語フォントを別途インストールしましょう。
今回はIPAフォントのお世話になることにします。
http://ipafont.ipa.go.jp/ipaexfont/download.html

$ wget http://ipafont.ipa.go.jp/ipaexfont/ipaexm00201.php
$ unzip ipaexm00201.php
$ mv ipaexm00201/ /usr/share/fonts

snappyの導入

composerで持ってきます。
導入したいPHPのプロジェクトで以下のコマンドを実行してください。
composer require knplabs/knp-snappy

PDFの出力サンプル

HTMLを用意してSnappyのgetOutputFromHtmlメソッドに投げるだけです。
Smartyなどのテンプレートエンジンと組み合わせると、サクサクと帳票のたぐいを組んでいけると思います。

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

$html = <<<EOF
<style>
.red {
    color:red;
    background-color: black;
    font-size:30px;
}
.opacity {
    opacity: 0.3;
}
</style>

<div class="red">
    <p>祝ってやる</p>
    <p>祝ってやる</p>
    <p>祝ってやる</p>
    <p>祝ってやる</p>
    <p class="opacity">祝ってやる</p>
    <p>祝ってやる</p>
    <p>祝ってやる</p>
    <p>祝ってやる</p>
    <p class="opacity">祝ってやる</p>
    <p>祝ってやる</p>
    <p>祝ってやる</p>
</div>
EOF;

// wkhtmltopdfの位置をコンストラクタに渡す
$pdf = new Knp\Snappy\Pdf('/usr/local/bin/wkhtmltopdf');

// encoding = utf-8をセット
$pdf->setOption('encoding', 'utf-8');

// PDFをブラウザに出力
header("Content-Type: application/pdf");
echo $pdf->getOutputFromHtml($html);

test.php.png

CSS3のプロパティであるopacityも正しく解釈されていることが分かると思います。

拡張してもうちょい便利に

pdf.php
class Pdf extends \Knp\Snappy\Pdf
{
    // 初期値にwkhtmltopdfの位置を登録、エンコード設定をUTF-8に変更
    public function __construct($binary = '/usr/local/bin/wkhtmltopdf', array $options = [], array $env = null)
    {
        parent::__construct($binary, $options, $env);
        $this->setOption('encoding', 'utf-8');
    }

    // headerの出力も自動で行う
    public function output($html)
    {
        header("Content-Type: application/pdf");
        return $this->getOutputFromHtml($html);
    }
}
example
echo (new Pdf)->output($html);

使用上の注意点

https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524
wkhtmltopdfはテーブルを使用すると、2ページ目以降にも自動でヘッダを付与してくれるのですが、それが凄い勢いでズレたり次の列と被ったりします。
こちらのスタイルを付与すると解決できます。

tr {
    page-break-inside: avoid;
}

まとめ

割とどんな書き方しても解釈してくれるんでもうPDFなんて怖くありません。
PDF出力機能のチケットを切られて他の人へたらい回しにするのはもうやめましょう。
もうやめましょう(念押し)