TCPDFでPDF帳票の作成

PHPライブラリ TCPDF でPDF帳票を作成する手順を記載する。
利用方法はいくつか考えられるが、実運用で使えそうな HTML->PDF変換テンプレートPDFへの値埋め込み だけ記載する。

インストール

適当なフォルダを作る

mkdir test-tcpdf
cd test-tcpdf

TCPDFインストール

https://github.com/tecnickcom/tcpdf から git clone

git clone https://github.com/tecnickcom/TCPDF.git

FPDIインストール

PDFをテンプレートにして値を埋め込む場合は必須
https://www.setasign.com/products/fpdi/downloads/

mkdir FPDI && cd FPDI
wget https://www.setasign.com/downloads/2102915/FPDI-2.1.0.zip
unzip FPDI-2.1.0.zip
rm -rf FPDI-2.1.0.zip
cd ../

インストール後のフォルダ構成

だいたいこんな感じ。

test-tcpdf
├── FPDI
│   ├── LICENSE.txt
│   ├── README.md
│   ├── composer.json
│   └── src
│       ├── FpdfTpl.php
│       ├── FpdfTplTrait.php
│       ├── Fpdi.php
│       ├── FpdiException.php
│       ├── FpdiTrait.php
│       ├── PdfParser
│       ├── PdfReader
│       ├── Tcpdf
│       ├── TcpdfFpdi.php
│       ├── Tfpdf
│       └── autoload.php
├── TCPDF
│   ├── CHANGELOG.TXT
│   ├── LICENSE.TXT
│   ├── README.md
│   ├── composer.json
│   ├── config
│   ├── examples
│   ├── fonts
│   ├── include
│   ├── tcpdf.php
│   ├── tcpdf_autoconfig.php
│   ├── tcpdf_barcodes_1d.php
│   ├── tcpdf_barcodes_2d.php
│   ├── tcpdf_import.php
│   ├── tcpdf_parser.php
│   └── tools

HTMLからPDFを出力する

スタイルシートも効くが、padding が効かない等、いくつかの制限がある模様。

html2pdf.php

<?php

include("./TCPDF/tcpdf.php");

define("MY_PDF_PAGE_ORIENTATION"   , "P");  // P:Portrait, L:Landscape
define("MY_PDF_FONT_NAME"          , "kozgopromedium");  // kozminproregular
define("MY_PDF_FONT_SIZE"          , 10);
define("MY_PDF_UNIT"               , "mm");
define("MY_PDF_PAGE_FORMAT"        , "A4");
define("MY_PDF_IMAGE_SCALE_RATIO"  , 1); 
define("MY_PDF_MARGIN_HEADER"      , 0); 
define("MY_PDF_MARGIN_FOOTER"      , 0); 
define("MY_PDF_MARGIN_TOP"         , 10);
define("MY_PDF_MARGIN_LEFT"        , 15);
define("MY_PDF_MARGIN_RIGHT"       , 15);
define("MY_PDF_MARGIN_BOTTOM"      , 20);

class MYPDF extends TCPDF {
    // フッタのカスタマイズ(ページ番号を出力する)
    public function Footer() {
        $this->SetY(-15);  // Position at 15 mm from bottom
        $this->SetFont('helvetica', 'I', 8); 
        $this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
    }   
}

$pdf = new MYPDF(MY_PDF_PAGE_ORIENTATION, MY_PDF_UNIT, MY_PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetTitle('PDF出力テスト');
//$pdf->SetSubject('TCPDF Tutorial');
//$pdf->SetHeaderData(null, null, null, null);
//$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);
//$pdf->setHeaderFont(Array(MY_PDF_FONT_NAME, '', MY_PDF_FONT_SIZE));
//$pdf->setFooterFont(Array(MY_PDF_FONT_NAME, '', MY_PDF_FONT_SIZE));
//$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetMargins(MY_PDF_MARGIN_LEFT, MY_PDF_MARGIN_TOP, MY_PDF_MARGIN_RIGHT);
//$pdf->SetHeaderMargin(MY_PDF_MARGIN_HEADER);
//$pdf->SetFooterMargin(MY_PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, MY_PDF_MARGIN_BOTTOM);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(true);
$pdf->setImageScale(MY_PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont(MY_PDF_FONT_NAME, "", 10);

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

// PDFに変換するHTML
$html =<<<_EO_HTML_
<style>
table {
    border-collapse: collapse;
}
table tr th {
    background-color: #efe;
    border: 1px solid #333;
    padding: 10px; /* 効かない */  
}
table tr td {
    border: 1px solid #333;
    padding: 10px; /* 効かない */  
}
.center {
    text-align: center;
}
</style>

<h1>TCPDFテスト</h1>
<table cellpadding="5">
<thead>
<tr>
    <th>列1</th><th>列2</th><th>列3</th>
</tr>
</thead>
<tbody>
<tr>
    <td>2018-01-01</td><td>テスト1</td><td class="center">100</td>
</tr>
<tr>
    <td>2018-01-02</td><td>テスト2</td><td class="center">200</td>
</tr>
</tbody>
</table>
_EO_HTML_;

$pdf->writeHTML($html, true, false, true, false, '');

// 2ページ目追加
//$pdf->lastPage();
//$pdf->AddPage();
//$pdf->writeHTML($html, true, false, true, false, '');

/*
 * Output の第2引数にI,D,FI,FD を指定すればHTTPレスポンスヘッダ(Content-TypeやContent-Disposition)を自動的に出力してくれる。
 * 自分でヘッダを調整したい場合は、S でデータだけ取得して自分でヘッダを吐く。
 * (ファイル名に日本語を含めたい場合など.)
 */
$data = null;
$fileName = "テスト.pdf";
//$pdf->Output($fileName, 'I');     // ブラウザに表示
//$pdf->Output($fileName, 'D');     // ダウンロードダイアログを表示
//$pdf->Output($fileName, 'F');     // サーバにファイルを保存
$data = $pdf->Output(null,'S');     // PDFドキュメントを文字列として返却
//$pdf->Output($fileName, 'FI');    // ファイルに保存して、ブラウザにも表示
//$pdf->Output($fileName, 'FD');    // ファイルに保存して、ダウンロードダイアログを表示
//$data = $pdf->Output(null, 'E');  // Base64エンコード済みのPDFドキュメントを返却(メールに添付するmultipartコンテンツ用なのでContent-Typeなどのヘッダーが付く)

if ($data != null) {
    // ブラウザにそのまま表示
    header('Content-Type: application/pdf');
    header('Content-Disposition: inline; filename="'.basename($fileName).'"');
    // ダウンロード
    //header('Content-Type: application/octet-stream', false);
    //header('Content-Disposition: attachment; filename="'.basename($fileName).'"');
    echo $data;
}

?>

既存のPDFテンプレートに値を埋め込んで出力する

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

別にTCPDFで作らなくても良いが。

print_template.php

<?php

include("./TCPDF/tcpdf.php");

define("MY_PDF_PAGE_ORIENTATION"   , "P");  // P:Portrait, L:Landscape
define("MY_PDF_FONT_NAME"          , "kozgopromedium");  // kozminproregular
define("MY_PDF_FONT_SIZE"          , 10);
define("MY_PDF_UNIT"               , "mm");
define("MY_PDF_PAGE_FORMAT"        , "A4");
define("MY_PDF_IMAGE_SCALE_RATIO"  , 1); 
define("MY_PDF_MARGIN_HEADER"      , 0);
define("MY_PDF_MARGIN_FOOTER"      , 0);
define("MY_PDF_MARGIN_TOP"         , 10);
define("MY_PDF_MARGIN_LEFT"        , 15);
define("MY_PDF_MARGIN_RIGHT"       , 15);
define("MY_PDF_MARGIN_BOTTOM"      , 20);

$pdf = new TCPDF(MY_PDF_PAGE_ORIENTATION, MY_PDF_UNIT, MY_PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetTitle('PDF 出力テスト');
$pdf->SetMargins(MY_PDF_MARGIN_LEFT, MY_PDF_MARGIN_TOP, MY_PDF_MARGIN_RIGHT);
$pdf->SetAutoPageBreak(TRUE, MY_PDF_MARGIN_BOTTOM);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(true);
$pdf->setImageScale(MY_PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont(MY_PDF_FONT_NAME, "", 10);
$pdf->AddPage();


$html =<<<_EO_HTML_
<style>
table.tbl {
    border-collapse: collapse;
}
table.tbl tr th {
    background-color: #efe;
    border: 1px solid #333;
    padding: 10px; /* 効かない */  
}
table.tbl tr td {
    border: 1px solid #333;
    padding: 10px; /* 効かない */  
}
.center {
    text-align: center;
}
</style>
<h1>PDF出力テスト</h1>
<table class="tbl" cellpadding="5">
<tr><th>列1</th><th>列2</th><th>列3</th></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
_EO_HTML_;

$pdf->writeHTML($html, true, false, true, false, '');

// ファイルに保存
$fileName = "/tmp/template.pdf";
$pdf->Output($fileName, 'F');

?>


# 実行
php print_template.php
# 作成したテンプレートをカレントディレクトリにコピー
cp /tmp/template.pdf ./

作成したテンプレートに値を埋め込む

ここから、実際にPDFテンプレートに値を埋め込むプログラム。
※出力位置の調整が若干面倒。

use_template.php

<?php
use setasign\Fpdi;

include("./TCPDF/tcpdf.php");
include("./FPDI/src/autoload.php");

define("MY_PDF_PAGE_ORIENTATION"   , "P");  // P:Portrait, L:Landscape
define("MY_PDF_FONT_NAME"          , "kozgopromedium");  // kozminproregular
define("MY_PDF_FONT_SIZE"          , 10);
define("MY_PDF_UNIT"               , "mm");
define("MY_PDF_PAGE_FORMAT"        , "A4");
define("MY_PDF_IMAGE_SCALE_RATIO"  , 1); 
define("MY_PDF_MARGIN_HEADER"      , 0); 
define("MY_PDF_MARGIN_FOOTER"      , 0); 
define("MY_PDF_MARGIN_TOP"         , 10);
define("MY_PDF_MARGIN_LEFT"        , 15);
define("MY_PDF_MARGIN_RIGHT"       , 15);
define("MY_PDF_MARGIN_BOTTOM"      , 20);

//class MYPDF extends TCPDF {
class MYPDF extends Fpdi\TcpdfFpdi {
    // フッタのカスタマイズ(ページ番号を出力する)
    public function Footer() {
        $this->SetY(-15);  // Position at 15 mm from bottom
        $this->SetFont('helvetica', 'I', 8); 
        $this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
    }   
}

$pdf = new MYPDF(MY_PDF_PAGE_ORIENTATION, MY_PDF_UNIT, MY_PDF_PAGE_FORMAT, true, 'UTF-8', false);

$pdf->SetTitle('PDFテンプレートに値を埋め込むテスト');
$pdf->SetMargins(MY_PDF_MARGIN_LEFT, MY_PDF_MARGIN_TOP, MY_PDF_MARGIN_RIGHT);
$pdf->SetAutoPageBreak(TRUE, MY_PDF_MARGIN_BOTTOM);
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(true);
$pdf->setImageScale(MY_PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont(MY_PDF_FONT_NAME, "", 10);
$pdf->AddPage();

// テンプレート読み込んでページに適用
$pdf->setSourceFile('./template.pdf');
$pdf->useTemplate($pdf->importPage(1));

// 出力位置の調整が少し面倒
function printRow($pdf, $index, $cols){
    $y = 31 + $index * 8;
    $posX = array(15, 75, 135);
    foreach ($cols as $i => $col) {
        $x = $posX[$i];
        $pdf->SetXY($posX[$i], $y);
        $pdf->Write(0, $col);
    }   
}

for ($i = 0; $i < 10; $i++) {
    $no = $i + 1;
    printRow($pdf, $i, array("test${no}-1", "test${no}-2", "test${no}-3"));
}

// 作成したPDFをブラウザに表示
$fileName = "use_template.pdf";
$pdf->Output($fileName, 'I');
//$data = $pdf->Output(null,'S');   // PDFデータだけ取得する場合

?>

トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS