PHPでPDF帳票を出力する方法(TCPDF + FPDI)

  • 216
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

PHPでPDFを出力する場合、PDFlibFPDFharu などさまざまなソリューションがありますが、たとえば、請求書や納品書といった、レイアウトが複雑なデザインの帳票を出力したいときには、 既存のPDFをテンプレートとして活用し、そこに必要な文字だけ配置していく ことでソースコードをシンプルに保つことができます。

既存のPDFをテンプレートとして読み込むことができ、かつ無償で活用できるライブラリとして、TCPDFFPDI の組み合わせをご紹介します。

テンプレートとなるPDFを作成する

PDFの読み込みを行うFPDIは、有償のパーサーを別途導入しない場合、PDF 1.5以上のファイルをパースすることができません。テンプレートとなるPDFファイルは PDF 1.4以下の圧縮形式で作成する必要があります。

また、PHP上から文字を配置する場合、座標を使用するため(左から10mm、上から20mmの位置から…といった具合)、Illustratorなどのソフトを使用したほうが効率的です。

ss1.jpg

たとえば、上の例ではIllustratorを使用して領収書のひな形を作成し、ドキュメント上に X : 42mm / Y : 108mm の位置に 幅 : 56mm × 高さ : 10mm のグレーのボックスを配置しています。ここにPHPを使って宛名を差し込んでいきます。

IllustratorからPDF 1.4互換のファイルを作成する

Illustrator CCの場合、「ファイルの種類」で「Adobe PDF」を選択し、続いて表示されるダイアログ上の、「互換性のある形式」で「Acrobat 5(PDF 1.4)」を選択します。

ライブラリをダウンロードする

TCPDF

  1. TCPDFをダウンロードします。ドキュメントなどが必要でなければ tcpdf_min_* を選択すればよいでしょう。
  2. ダウンロードしたファイルは解凍して、PHPのinclude_path上に tcpdf というフォルダ名で配置しました。Symfony2で使用する場合は、libフォルダなどを作成し、autoload.phpに以下のように追記します。
autoload.php
$loader = require __DIR__.'/../vendor/autoload.php';

AnnotationRegistry::registerLoader(array($loader, 'loadClass'));

// include_pathを追加する
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../lib');

return $loader;

フォント

  1. 日本語のフォントを使用したいので、今回は MigMixフォント を使用させてもらいます。MigMix 2Pをダウンロードしたら、解凍して migmix-2p-bold.ttfmigmix-2p-regular.ttftcpdf/fonts/ フォルダに配置します。
  2. tcpdf/fonts/ フォルダにはPHP実行ユーザに書き込み権限が必要ですので、パーミッションを変更しておきましょう。

FPDI

  1. FPDIをダウンロードします
  2. ダウンロードしたファイルは解凍して、TCPDFを配置した tcpdf フォルダ内に配置しましょう。この時点で tcpdf フォルダ内は以下のような配置になっているはずです。
lib/
    tcpdf/
        fonts/
            migmix-2p-bold.ttf
            migmix-2p-regular.ttf
        fpdi.php
        …(ほか、FPDIのファイル群)
        tcpdf.php
        …(ほか、TCPDFのファイル群)

ライブラリを使用して、PDFを出力する

準備はここまでです。
あとは、PHPからテンプレートとなるPDFを読み込み、文字列を追加して出力します。
以下はSymfony2のコントローラですが、もちろんほかのフレームワークでも同様の書き方でPDFを出力可能かと思います。

PdfController.php
<?php

namespace Awesome\DemoBundle\Controller;

// include_pathからTCPDFとFPDIを読み込む
require_once('tcpdf/tcpdf.php');
require_once('tcpdf/fpdi.php');

use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class DeliveriesPdfController extends Controller
{
    public function listAction(Request $request)
    {
        $receipt = new \FPDI();

        // PDFの余白(上左右)を設定
        $receipt->SetMargins(0, 0, 0);

        // ヘッダーの出力を無効化
        $receipt->setPrintHeader(false);

        // フッターの出力を無効化
        $receipt->setPrintFooter(false);

        // フォントを登録
        $fontPathRegular = $this->getLibPath() . '/tcpdf/fonts/migmix-2p-regular.ttf';
        $regularFont = $receipt->addTTFfont($fontPathRegular, '', '', 32);

        $fontPathBold = $this->getLibPath() . '/tcpdf/fonts/migmix-2p-bold.ttf';
        $boldFont = $receipt->addTTFfont($fontPathBold, '', '', 32);

        // ページを追加
        $receipt->AddPage();

        // テンプレートを読み込み
        $receipt->setSourceFile($this->getLibPath() . '/tcpdf/tpl/receipt.pdf');

        // 読み込んだPDFの1ページ目のインデックスを取得
        $tplIdx = $receipt->importPage(1);

        // 読み込んだPDFの1ページ目をテンプレートとして使用
        $receipt->useTemplate($tplIdx, null, null, null, null, true);

        // 書き込む文字列のフォントを指定
        $receipt->SetFont($regularFont, '', 11);

        // 書き込む文字列の文字色を指定
        $receipt->SetTextColor(255, 0, 0);

        // X : 42mm / Y : 108mm の位置に
        $receipt->SetXY(42, 108);

        // 文字列を書き込む
        $receipt->Write(0, '山田 太郎');

        $response = new Response(
            // Output関数の第一引数にはファイル名、第二引数には出力タイプを指定する
            // 今回は文字列で返してほしいので、ファイル名はnull、出力タイプは S = String を選択する
            $receipt->Output(null, 'S'),
            200,
            array('content-type' => 'application/pdf')
        );

        // レスポンスヘッダーにContent-Dispositionをセットし、ファイル名をreceipt.pdfに指定
        $response->headers->set('Content-Disposition', 'attachment; filename="receipt.pdf"');

        return $response;
    }

    /**
     * @return string
     */
    private function getLibPath()
    {
        return realpath(sprintf('%s/../lib', $this->get('kernel')->getRootDir()));
    }
}

これで、文字列が追加されたPDFが得られます。

ss2.jpg

もちろんこのまま $receipt->AddPage(); を続ければ、領収書をまとめてPDFとして出力することもできます。

以下のページを参考にさせていただきました :
TCPDFとFPDIの使い方メモ