PDFは相変わらずつらい
ブラウザの印刷機能にPDF変換が実装されて久しい、西暦2016年。
今もまだ色々なしがらみに押し負けたPHPerたちの不毛な戦いは続いています。
もう年の瀬ですが来年もPDFと戦っていくための情報をお届けします。
wkhtmltopdfとphpwkhtmltopdfで幸せになろう
wkhtmltopdf
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がダウンロードされます。
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();
拡張して便利に
バイナリの位置とエンコード形式を初期設定。
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);
}
}
(new Pdf($html))->send();
使用上の注意点
https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524
wkhtmltopdfはテーブルを使用すると、2ページ目以降にも自動でヘッダを付与してくれるのですが、
それがズレたり次の列と被ったりしてデザインが大きく崩れます。
こちらのスタイルを付与すると解決できます。
tr {
page-break-inside: avoid;
}
まとめ
以前書いたこちらの記事から一年が経ち、色々な変更が見受けれての改訂版でした。
PHPでPDFを作成する時はwkhtmltopdf + snappyで戦え
v 0.12.3からwkhtmltopdfのインストール方法が変更され、アーカイブを解凍して配置するだけとなっていたり、
IPAフォントが以前のURLではダウンロード出来なくなっていたり、
SnappyがフォローしてくれていなかったHTTPヘッダの出力までラッピングしたphpwkhtmltopdfの存在を知ったり。
たった一年で色々起こるものです。
今後もPHPでPDFを操作する方法は定期的に調査して行こうと思います。
なにか気付いた点がありましたら、編集リクエストもお待ちしております。