📄

mPDFでPDF作成してFPDIで連結させる

2024/06/10に公開

はじめに

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専用に調整する必要がある。

参考: https://mpdf.github.io/html-support/html-tags.html

Discussion