Webシステムでありがちな印刷物の出力
HTMLとCSSを駆使して印刷用のページを作成するのが私のやり方。でもブラウザによって印刷結果が異なるのが悩みどころ。
どんな環境でも同じ印刷結果が欲しい
ビジネスにも耐えうる印刷物が欲しい。サーバサイドでPDFを動的に作ってくれる製品がないか探しました。私がさまよった製品は以下の通りです。
PDF出力ならwkhtmltopdf
HTMLファイルからPDFを作成してくれる優れものです。
ブラウザ同様にCSSを解釈・JavaScriptを実行し、その結果をPDFファイルにしてくれます。
wkhtmltopdfはCSS3も再現してくれます、見事なものです。
HTMLとCSSでPDFを作成できるので、PDF作成のために特別に覚えることはありません。
ライセンスもLGPLなのがうれしいところ。
IPAフォントをインストールしておけば、さらに美しいPDFが出来上がります。
使い方
wkhtmltopdf は /usr/local/bin に置いておきます。別にパスの通ったところでなくても良いです。
コマンドラインで実行できます。なのでPHPからは shell_exec()関数で呼んでやればOK。
[usr01@srv]$ wkhtmltopdf [option] <入力ファイル> <出力ファイル>
SELinux でツボる
SELinux が有効な環境だと wkhtmltopdf が動かずPDFが作れません。
適当なユーザでログインしてターミナルから wkhtmltopdf の実行はできます。しかしどうも Apache (httpd) からの実行が拒否されてるみたい。
解決策
この記事を参考に私なりに解釈しました。
PHP function is_executable returns false even though the file is definitely executable
wkhtmltopdf が実行される前に audit.log を追尾しておきます。
# tail -f /var/log/audit/audit.log | grep wkhtmltopdf
ここでPDF出力するPHPをブラウザから呼びます。
次のようなログが2行ほど採れるはずです。
type=AVC msg=audit(1324083604.241:1445): avc: denied { execmem } for pid=5129 comm="wkhtmltopdf-i38" scontext=unconfined_u:system_r:httpd_sys_script_t:s0 tcontext=unconfined_u:system_r:httpd_sys_script_t:s0 tclass=process type=SYSCALL msg=audit(1324083604.241:1445): arch=40000003 syscall=90 per=400000 success=no exit=-13 a0=bfa63df8 a1=1000 a2=c01000 a3=16eb16e items=0 ppid=9364 pid=5129 auid=0 uid=500 gid=500 euid=500 suid=500 fsuid=500 egid=500 sgid=500 fsgid=500 tty=(none) ses=15 comm="wkhtmltopdf-i38" exe="/hoge/path/wkhtmltopdf-0.11.0_rc1/linux_i386/wkhtmltopdf-i386" subj=unconfined_u:system_r:httpd_sys_script_t:s0 key=(null)
ログが採れたので、tailコマンドはCtrl+Cでおしまい。
wkhtmltopdf.audit ファイルを新規作成します。
# vim wkhtmltopdf.audit
ファイルの中身は先ほど採ったログをそのままコピペし保存します。
wkhtmltopdf.audit ファイルを元に wkhtmltopdf.te ファイル(ポリシーファイル)を作成します。
# cat wkhtmltopdf.audit | audit2allow -m wkhtmltopdf > wkhtmltopdf.te
作成したポリシーを適用します。
# cat wkhtmltopdf.audit | audit2allow -M wkhtmltopdf # semodule -i wkhtmltopdf.pp
これで、Apache (httpd) からwkhtmltopdfが実行できるようになりました。
Internet Explorer での不具合
2012/08/02 追記
「wkhtmltopdf」や「PHP PDF」といった検索キーワードでやってこられた方のために参考になればと思います。
動的に作ったPDFをブラウザで表示しようとした場合、Internet Explorer 8 で表示されない不具合がありました。
Firefox, Google Chrome, Internet Explorer 9ではブラウザ内で正しくPDFが表示されます。
しかし Internet Explorer 8は何を勘違いしているのか画面が真っ白なまま。レスポンスヘッダで application/pdf を付加しているにも関わらずです。
Internet Explorer でブラウザ内にPDFを表示する方法
次の記事を参考にしました。
IE8 Issue: PDF file is displayed as inline
以下のレスポンスヘッダを付加すると、Internet Explorer 8ブラウザ内でPDFが表示されます。
Content-Type: application/pdf Content-Disposition: inline Content-Length: ○○○ Pragma: Public Cache-Control: must-revalidate,post-check=0,pre-check=0 Expires: 0
私が試した限りでは、以下のレスポンスヘッダだけでも上手くいきました。
Content-Type: application/pdf Content-Length: ○○○ Cache-Control: must-revalidate,post-check=0,pre-check=0
私は完全にRFCを理解しているわけではないです。ここまで細かくレスポンスヘッダを設定すべきなのか、それともInternet Explorer 8が不出来なのかはわかりません。あと、Internet Explorer 7以下はテスト環境を用意することが非常に手間なので試していません。あしからず。
この記事のおかげでwkhtmltopdf使えるようになりました。感謝します!
ご覧くださいましてありがとうございます。数年前に書いた記事ですが、参考になれば幸いです。