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

# 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版) の想定です。
他の環境の場合は、[本家サイト](http://wkhtmltopdf.org/downloads.html)から適切なバージョンを入手しましょう。
また既にcomposerを導入しているプロジェクトを前提として話を進めます。

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

```bash
$ 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の動確を行いましょう。

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

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

```bash
$ yum install -y libXrender libXext
```


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

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


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


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

```bash
$ composer require mikehaertl/phpwkhtmltopdf
```

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

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

```php: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](https://qiita-image-store.s3.amazonaws.com/0/33480/00b52037-bdb2-ffa5-e726-c0fbd756abde.png)


# 拡張して便利に
バイナリの位置とエンコード形式を初期設定。

```php: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);
    }
}
```

```php:example.php
(new Pdf($html))->send();
```

# 使用上の注意点
_https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1524_

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

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

# まとめ
以前書いたこちらの記事から一年が経ち、色々な変更が見受けれての改訂版でした。
[PHPでPDFを作成する時はwkhtmltopdf + snappyで戦え](http://qiita.com/morisuke/items/b9c18dcba99ba6501d6e)

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

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