#author("2018-09-30T01:00:06+00:00","","")
* TCPDFでPDF帳票の作成 [#j23de1e5]
#setlinebreak(on);

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

//- [[HTMLをPDFに変換して出力する>#va993123]]
//- [[既存のPDFテンプレートに値を埋め込んで出力する>#rd36ac9d]]

#contents
-- 参考
--- https://tcpdf.org/
--- https://www.setasign.com/products/fpdi/

** インストール [#t0ee2a3e]
#html(<div style="padding-left:10px">)

たぶん Composer でやる方が良いが。。

** 適当なフォルダを作る [#n0661f21]
#html(<div style="padding-left:10px">)
#myterm2(){{
mkdir test-tcpdf
cd test-tcpdf
}}
#html(</div>)

** TCPDFインストール [#u684149f]
#html(<div style="padding-left:10px">)
https://github.com/tecnickcom/tcpdf  から git clone
#myterm2(){{
git clone https://github.com/tecnickcom/TCPDF.git
}}
#html(</div>)


** 利用方法 [#y08c131f]
** FPDIインストール [#y91532e4]
#html(<div style="padding-left:10px">)
いくつかの利用方法がある。
PDFをテンプレートにして値を埋め込む場合は必須
https://www.setasign.com/products/fpdi/downloads/
#myterm2(){{
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 ../
}}
#html(</div>)

*** 直接生成 [#r5500e97]
** インストール後のフォルダ構成 [#u4d864a6]
#html(<div style="padding-left:10px">)
だいたいこんな感じ。
#myterm2(){{
test-tcpdf
├── FPDI
│&#160;&#160; ├── LICENSE.txt
│&#160;&#160; ├── README.md
│&#160;&#160; ├── composer.json
│&#160;&#160; └── src
│&#160;&#160;     ├── FpdfTpl.php
│&#160;&#160;     ├── FpdfTplTrait.php
│&#160;&#160;     ├── Fpdi.php
│&#160;&#160;     ├── FpdiException.php
│&#160;&#160;     ├── FpdiTrait.php
│&#160;&#160;     ├── PdfParser
│&#160;&#160;     ├── PdfReader
│&#160;&#160;     ├── Tcpdf
│&#160;&#160;     ├── TcpdfFpdi.php
│&#160;&#160;     ├── Tfpdf
│&#160;&#160;     └── autoload.php
├── TCPDF
│&#160;&#160; ├── CHANGELOG.TXT
│&#160;&#160; ├── LICENSE.TXT
│&#160;&#160; ├── README.md
│&#160;&#160; ├── composer.json
│&#160;&#160; ├── config
│&#160;&#160; ├── examples
│&#160;&#160; ├── fonts
│&#160;&#160; ├── include
│&#160;&#160; ├── tcpdf.php
│&#160;&#160; ├── tcpdf_autoconfig.php
│&#160;&#160; ├── tcpdf_barcodes_1d.php
│&#160;&#160; ├── tcpdf_barcodes_2d.php
│&#160;&#160; ├── tcpdf_import.php
│&#160;&#160; ├── tcpdf_parser.php
│&#160;&#160; └── tools
}}
#html(</div>)

*** HTMLから変換する [#va993123]
#html(<div style="padding-left:10px">)

#html(</div>)
// インストール END

*** dummy [#kfa69edd]
** HTMLからPDFを出力する [#va993123]
#html(<div style="padding-left:10px">)

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

html2pdf.php
#mycode2(){{
<?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;
}

?>
}}
#html(</div>)

*** dummy [#u7927062]
** 既存のPDFテンプレートに値を埋め込んで出力する [#rd36ac9d]
#html(<div style="padding-left:10px">)
#html(</div>)

*** dummy [#o4f14ddf]
*** テンプレートとなるPDFの作成 [#n528bd21]
#html(<div style="padding-left:10px">)
#html(</div>)
別にTCPDFで作らなくても良いが。

print_template.php
#mycode2(){{
<?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');

?>
}}
&br;
#myterm2(){{
# 実行
php print_template.php
# 作成したテンプレートをカレントディレクトリにコピー
cp /tmp/template.pdf ./
}}

#html(</div>)
// 利用方法 end

** 利用例(サンプル) [#h184155a]
*** 作成したテンプレートに値を埋め込む [#p0b508e3]
#html(<div style="padding-left:10px">)

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

use_template.php
#mycode2(){{
<?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データだけ取得する場合

?>
}}
#html(</div>)

#html(</div>)


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