Skip to content
オープンソース・ワークショップ 永原 篤 edited this page Jan 12, 2022 · 9 revisions

サンプル実装

ブログに仮実装した場合です。
下記対応しています。

  • template.pdfの上に文字追記
  • 日本語をPDFに追記
  • 電子署名対応(Acrobat Reader専用)

PDF出力結果

sample.pdf

ファイル配置

  • resources\pdf\template.pdf PDFオーバーレイするファイル
  • resources\cert\tcpdf.crt 証明書
    • tcpdf.crt よりコピー
    • コピー元:vendor\tecnickcom\tcpdf\examples\data\cert\tcpdf.crt
  • ※ tcpdf, fpdiライブラリ、IPAフォントは、Connect-CMS最新githubから持ってこれます。
    • tcpdf PDF作成するPHPライブラリ
    • fpdi PDFオーバーレイに必要なPHPライブラリ(ベースとなるPDFの上に文字を追記できる)
    • IPAフォント 日本語フォント。PDFに日本語書き込みに使用

ダウンロード呼び出し blade

<a href="{{url('/')}}/download/plugin/blogs/downloadPdf/{{$page->id}}/{{$frame_id}}/"><span class="badge badge-info">PDF出力</span></a>

コントローラー BlogsPlugin

use setasign\Fpdi\Tcpdf\Fpdi;
(省略)
class BlogsPlugin extends UserPluginBase
{
(省略)
    /**
     *  関数定義(コアから呼び出す)
     */
    public function getPublicFunctions()
    {
        // 標準関数以外で画面などから呼ばれる関数の定義
        $functions = array();
        $functions['get']  = ['listCategories', 'rss', 'editBucketsRoles', 'settingBlogFrame', 'downloadPdf'];  // downloadPdf追加
        $functions['post'] = ['saveCategories', 'deleteCategories', 'saveBucketsRoles', 'saveBlogFrame'];
        return $functions;
    }
(省略)

    /**
     * PDFダウンロード
     */
    public function downloadPdf($request, $page_id, $frame_id)
    {
        $pdf = new Fpdi();

        // テンプレートPDFの設定
        $template_path = resource_path('pdf/template.pdf');
        $pdf->setSourceFile($template_path);

        // PDF プロパティ設定
        $pdf->SetTitle('Title aiueo あいうえお');  // PDFドキュメントのタイトルを設定  http://tcpdf.penlabo.net/method/s/SetTitle.html
        $pdf->SetAuthor('Author aiueo あいうえお');  // PDFドキュメントの著者名を設定  http://tcpdf.penlabo.net/method/s/SetAuthor.html
        $pdf->SetSubject('Subject aiueo あいうえお');  // PDFドキュメントのサブジェクト(表題)を設定  http://tcpdf.penlabo.net/method/s/SetSubject.html
        $pdf->SetKeywords('KEY1 KEY2 KEY3 あいうえお'); // PDFドキュメントのキーワードを設定 http://tcpdf.penlabo.net/method/s/SetKeywords.html
        $pdf->SetCreator('Creator aiueo あいうえお');  // PDFドキュメントの製作者名を設定  http://tcpdf.penlabo.net/method/s/SetCreator.html

        // set certificate file. 頭のfile://は必須
        $certificate = 'file://' . resource_path('cert/tcpdf.crt');
        $private_key = 'file://' . resource_path('cert/tcpdf.crt');

        // set additional information
        //$info = array(
        //    'Name' => 'TCPDF',
        //    'Location' => 'Office',
        //    'Reason' => 'Testing TCPDF',
        //    'ContactInfo' => 'http://www.tcpdf.org',
        //);

        // set document signature
        // only Acrobat Reader. https://github.com/tecnickcom/TCPDF/blob/main/tcpdf.php#L13463
        // $cert_type=1: ドキュメントへの変更は許可されません。 文書に変更を加えると、署名が無効になります。
        // $cert_type=2: 許可される変更は、フォームへの入力、ページテンプレートのインスタンス化、および署名です。 その他の変更は署名を無効にします。(デフォルト)
        //$pdf->setSignature($certificate, $certificate, 'tcpdfdemo', '', 2, $info);
        $pdf->setSignature($certificate, $private_key);

        // フォントを登録
        // 追加フォントをtcpdf用フォントファイルに変換してvendor\tecnickcom\tcpdf\fontsに登録
        $font = new \TCPDF_FONTS();
        // フォント・サブセットを使用するか(初期はtrueなので呼ばなくてもいい)
        // $pdf->setFontSubsetting(true);
        // ttfフォントファイルからtcpdf用フォントファイルを生成(tcpdf用フォントファイルがある場合は再生成しない)
        $fontX = $font->addTTFfont(resource_path('fonts/ipaexm.ttf'));

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

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

        ////
        //// 1ページ目
        ////
        // ページを追加
        $pdf->addPage();

        // テンプレートの適用
        $page = $pdf->importPage(1);
        $pdf->useTemplate($page);
        // テンプレートを背景とする
        $pdf->setPageMark();

        ////
        //// 氏名
        ////
        $name = 'コネクト 花子';
        // フォント設定
        $pdf->setFont('ipaexm', '', 20);
        // Y(縦mm)指定
        $pdf->SetY(74);
        // C=中央揃え http://tcpdf.penlabo.net/method/w/Write.html
        $pdf->Write(0, $name, '', false, 'C');

        ////
        //// シリアル番号
        ////
        $serial_number = '123456789';
        // フォント設定
        $pdf->setFont('ipaexm', '', 10);
        // X(横mm) / Y(縦mm)指定
        $pdf->SetXY(155, 20);
        $pdf->Write(0, $serial_number);

        ////
        //// 日付
        ////
        $date_of_pdf_issue = '2021/01/01';
        // X(横mm) / Y(縦mm)指定
        $pdf->SetXY(155, 25);
        $pdf->Write(0, $date_of_pdf_issue);

        ////
        //// 2ページ目(詳細)
        ////
        // ページを追加
        $pdf->addPage();

        // テンプレートの適用
        $page = $pdf->importPage(2);
        $pdf->useTemplate($page);
        // テンプレートを背景とする
        $pdf->setPageMark();

        // フォント設定
        $pdf->setFont('ipaexm', '', 10);
        // Y(縦mm)指定
        $pdf->SetY(16);

        $titles = [
            'date' => '日付',
            'detail' => '詳細',
            'source' => '情報源'
        ];
        $datas = [
            [
                'date' => '2021/01/01',
                'detail' => 'ハワイの歴史(history of Hawaii)では、アメリカ合衆国50番目の州として登録されているハワイ州を構成するハワイ諸島における歴史を詳述する。',
                'source' => 'wikipedia'
            ],
            [
                'date' => '2021/01/01',
                'detail' => 'フリードリヒ2世は、神聖ローマ帝国ホーエンシュタウフェン朝の皇帝、及びシチリア王。イタリア史関係では、イタリア名のフェデリーコ2世で呼ばれることが多い',
                'source' => 'wikipedia'
            ],
        ];

        // HTML書き込み
        $pdf->writeHTML(
            $this->view("blogs_pdf", compact('name', 'serial_number', 'date_of_pdf_issue', 'titles', 'datas'))->render()
        );

        // 出力指定 ファイル名+拡張子、D(ダウンロード)/I(ブラウザ表示:デフォ)
        // $pdf->output('sample.pdf', 'D');
        $pdf->output('sample.pdf', 'I');

        return redirect()->back();
    }
}

PDFのHTML部分 resources\views\plugins\user\blogs\default\blogs_pdf.blade.php

{{--
 * 詳細PDFテンプレート
--}}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <style type="text/css">
            .left {  text-align: left; }
            .center {  text-align: center; }
            .right {  text-align: right; }
            .font_table { font-size: 0.9em; }
            .table_head { color: white; background-color: orange; }

            /* セル幅 */
            .table_width_date { width: 10%; }
            .table_width_detail { width: 75%; }
            .table_width_source { width: 15%; }
        </style>
    </head>

    <body>
        <div class="right">
            氏名:{{$name}}<br />
            シリアル番号:{{$serial_number}}<br />
            日付:{{$date_of_pdf_issue}}
        </div>
        <br />

        <table border="1" width="100%" cellpadding="2" class="font_table">
            <thead>
                <tr class="table_head">
                    <th class="table_width_date">{!! $titles['date'] !!}</th>
                    <th class="table_width_detail center">{!! $titles['detail'] !!}</th>
                    <th class="table_width_source center">{!! $titles['source'] !!}</th>
                </tr>
            </thead>
            <tbody>
                @foreach ($datas as $d)
                <tr>
                    <td class="table_width_date">{!! $d['date'] !!}</td>
                    <td class="table_width_detail">{!! $d['detail'] !!}</td>
                    <td class="table_width_source">{!! $d['source'] !!}</td>
                </tr>
                @endforeach
            </tbody>
        </table>
    </body>
</html>

エラー対応1

パワーポイントからPDFを作成時に画像圧縮すると、下記エラーでPDFテンプレートとして使えなかった。
パワーポイントで名付けて保存>その他のオプション>最適化:標準でPDF保存すると解決しました。

エラーログ1

[2021-02-01 15:01:25] local.ERROR: This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details) {"userId":1,"exception":"[object] (setasign\\Fpdi\\PdfParser\\CrossReference\\CrossReferenceException(code: 267): This PDF document probably uses a compression technique which is not supported by the free parser shipped with FPDI. (See https://www.setasign.com/fpdi-pdf-parser for more details) at C:\\projects\\connect-cms\\htdocs\\connect-cms\\vendor\\setasign\\fpdi\\src\\PdfParser\\CrossReference\\CrossReference.php:257)

情報源1

エラー対応2

電子署名埋め込みでopenssl_pkcs7_sign(): error getting private keyエラー。

エラーログ2

[2021-02-01 22:17:41] local.ERROR: openssl_pkcs7_sign(): error getting private key {"exception":"[object] (ErrorException(code: 0): openssl_pkcs7_sign(): error getting private key at C:\\projects\\connect-cms\\htdocs\\connect-cms\\vendor\\tecnickcom\\tcpdf\\tcpdf.php:7616)

対応2-1

下記コマンドでコンバートした証明書を使う。

/*
NOTES:
 - To create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt
 - To export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12
 - To convert pfx certificate to pem: openssl pkcs12 -in tcpdf.pfx -out tcpdf.crt -nodes
*/

参照元:TCPDF電子署名埋め込み-サンプル052

対応2-2

コントローラーで証明書読み込み時に、頭にfile://をつける。
つけないと同エラーがでました。

        // set certificate file. 頭のfile://は必須
        $certificate = 'file://' . resource_path('cert/tcpdf.crt');

        // set additional information
        $info = array(
            'Name' => 'TCPDF',
            'Location' => 'Office',
            'Reason' => 'Testing TCPDF',
            'ContactInfo' => 'http://www.tcpdf.org',
        );

        // set document signature
        $pdf->setSignature($certificate, $certificate, 'tcpdfdemo', '', 2, $info);

エラー対応3

画面からPDF出力時に「TCPDF ERROR: Could not include font definition file: ipaexg」が出る場合。

原因3

vendor/tecnickcom/tcpdf/fonts ディレクトリにApache 実行ユーザの書き込み権限がない場合。

対応3

上記ディレクトリにApache 実行ユーザの書き込み権限を付与する。

情報源2

参考リンク

Clone this wiki locally