HTMLとCSSを使った直感的なPDF作成 wkhtmltopdf / phpwkhtmltopdf
EC-CUBEの2系をベースとして、ECサイトの構築をしていた時に受注の領収書や請求書をPDFで作成してユーザにDLしてもらうと思うのですが、EC-CUBE2.XX系では”FPDF“というライブラリを使用しています。
早速、デフォルトのテンプレートを変更するにあたり思ったことは…
- フォントが変
- 座標でそれぞれの要素を書き込むのが手間
- デザイン性が著しく悪い
とにかく使いづらかったです。 フォントが漢字(日本語)と金額等の数値で違和感があったり、座標が細かくプレビューしながら調節する時間の無駄感などなど…。 なんか他に、直感的に簡単にPDFを作成できるライブラリが無いかと探していたところ、別プロジェクトでHTML+CSSでPDFを作れるライブラリを使ってるとの情報をGETしました。
wkhtmltopdf と phpwkhtmltopdf
wkhtmltopdf はコマンドベースでHTMLをPDFに変えてくれるライブラリです。 phpwkhtmltopdfはそのコマンドベースのwkhtmltopdfをPHP上で操作できるようにしてくれた便利なラッパークラスです。
対応状況としてHTML5+CSS3が使えますので、特に気にしてコーディングする必要もありません。 導入方法としては以下が参考になると思います。
細かい設定とかに関してはあまり情報が無い&wkhtmltopdfのドキュメントが英語ではありますが、雰囲気で分かるので見れば理解できると思います。
EC-CUBE2.XX系で使う
基本的なコードは以下のようになります。
// composerのautoload.phpを読み込み require_once 'module/vendor/autoload.php'; // PDF作成クラスのインスタンス $pdf = new mikehaertl\wkhtmlto\Pdf([ // バイナリの位置とエンコード形式 'binary' => '/usr/local/bin/wkhtmltox/bin/wkhtmltopdf', 'encoding' => 'utf-8', // ヘッダー及びフッターを表示させる際、top or bottom でスペースを空けないと出てこないです 'margin-top' => 10, 'margin-right' => 0, 'margin-bottom' => 31, 'margin-left' => 0, 'no-outline', // 以下オプションについてはコード↓参照 'disable-smart-shrinking', 'header-html' => $header_html_path, Headerは繰り返さない為コメントアウト // [title]はメインテンプレート内titleタグ内を出力します // [page] は出力されるPDFの前ページ数です // [topage] は現在のページ 'header-center' => '[title] [page]/[topage]', 'header-spacing' => 4, // ヘッダーの間隔 'header-font-size' => 6, // ヘッダーフォントサイズ 'footer-html' => $footer_path, // フッターに使用するHTMLへのパス 'footer-spacing' => 8, // メインテンプレートとフッターの間隔 // CSSを別で管理する場合はこれ 'user-style-sheet' => $css_path // メインテンプレートの文字列データを渡す $pdf->addPage($main); // sendメソッドの第一引数にファイル名を指定すればダウンロード形式、指定無しでブラウザ出力になります。 $filename = 'Test.pdf'; $pdf->send($filename); ]);
以上が、今回使用したオプションです。 ‘margin-top’及び’footer-top’を設定しないと表示されないという罠に数時間てこずりました…。 それとメインテンプレートはHTMLの’文字列’を渡さないといけないのに、ヘッダーとフッターに関してはHTMLファイルへのパスを渡さないといけないという罠。 CSSに関してはメインテンプレートとフッター、ヘッダー全てに適応されるので1つでOKです。
フッターに動的コンテンツを埋め込みたい場合、今回EC-CUBEのテンプレートエンジンがSmartyなので一度、fetchで動的HTMLを生成したあと、予め用意しておいたからのHTMLファイルに書き込みして それを、読ませるという一手間二手間、遠回りしてる気がして仕方ない方法を行ってます。
公開ディレクト以下のパスしか読まないので一時ファイルを作っても結局公開下に置かないといけないので、その辺は上手い方法があれば更新したいと思います。(多分しない)