📄
mPDFでPDF作成してFPDIで連結させる
はじめに
CodeigniterでviewファイルからPDFを生成して、ファイルを連結させたときのメモ。
- Codeigniter3系
- PHP 5.6
ライブラリのインストール
当初TCPDFを使ってPDFファイルの生成をやろうとしたが、使用できるCSSがとても限られてしまった為mPDFを採用した。TCPDFはFPDIでファイル連結を行うためにインストールしている。
composer require mpdf/mpdf
composer require tecnickcom/tcpdf
composer require setasign/fpdi
mPDFでPDFファイル生成
// viewに渡す情報
$this->data['view_param'] = $param;
// viewのhtmlを文字列で取得
$html = $this->load->view('index', param, true)
$mpdf = new mpdf([
'mode' => 'ja',
'format' => 'A4',
'margin_left' => 0,
'margin_right' => 0,
'margin_top' => 0,
'margin_bottom' => 0,
'margin_header' => 0,
'margin_footer' => 0,
'default_font' => 'sans-serif',
]);
$mpdf->WriteHTML($html);
$tmp_file = uniqid() . '.pdf';
$mpdf->Output($_SERVER['DOCUMENT_ROOT'] .'/'.$tmp_file, \Mpdf\Output\Destination::FILE);
// S3にアップロード(省略)
// tmpファイル削除
unlink($_SERVER['DOCUMENT_ROOT'] . '/'.$tmp_file);
サイズはA4、日本語で出力する以外はview側でデザインを入れているので設定していない。
作成したファイル自体はs3に置きたかったので、一時的にtmpファイルを作成しs3にアップロード後に削除している。
FPDIでファイル連結
$files = array(
'./files/pdf1.pdf',
'./files/pdf2.pdf',
'./files/pdf3.pdf',
'./files/pdf4.pdf',
);
$pdf = new Fpdi\TcpdfFpdi();
$pdf->setPrintHeader( false );
$pdf->setPrintFooter( false );
foreach( $files as $file ) {
// tmpファイルとしてサーバーに配置
$tmp_file = uniqid() . '.pdf';
file_put_contents($_SERVER['DOCUMENT_ROOT']. '/' .$tmp_file, file_get_contents($file));
$count = $pdf->setSourceFile($_SERVER['DOCUMENT_ROOT'] . '/' .$tmp_file);
// ページ追加
for ( $i = 1; $i <= $count; $i++ ) {
$pdf->addPage();
$pdf->useTemplate( $pdf->importPage( $i, PageBoundaries::CROP_BOX, true, true) );
}
// ファイル削除
unlink($_SERVER['DOCUMENT_ROOT'] . '/' .$tmp_file);
}
// ファイル生成
$tmp_file = uniqid() . '.pdf';
$pdf->Output($_SERVER['DOCUMENT_ROOT']. '/' .$tmp_file, "F");
ハマったところ
aタグのリンクが機能しない
連結後のファイルを確認して気付いたのがaタグのリンクが機能していなかったこと。よくよく確認するとmPDFでファイル生成した時点ではリンクとして機能しているが、連結するとリンクになっていなかった。
→importPage()の第4引数をtrueにすることで解決
参考: https://manuals.setasign.com/fpdi-manual/v2/the-fpdi-class/#c_setasignFpdiFpdiTraitimportPage
フッターの位置固定
各ページにフッターを表示したかったのだが、positionが効かず苦労した。
結果body直下の要素として配置したところpositionが効いてうまくいった。
例
<html>
<body>
<div>
コンテナー
</div>
<div style="position: fixed; bottom: 0;">
フッター
</div>
</body>
</html>
display: inline-boxが効かない
公式ドキュメントによると、すべてのHTML要素は、ブロック要素またはインライン要素として扱われるようにmPDFにハードコードされており、CSSを使用して変更することはできないとのこと。
デザインの通りに組んだHTMLをmPDFで同じように表示するにはある程度mPDF専用に調整する必要がある。
Discussion