compat-legacy を本番環境で運用する
このアダプターは HTTP ハンドラー、キューワーカー、長時間実行プロセスで安全に運用できます。レガシー TCPDF 6.2.13 より安全です。本番環境で特に多い 2 つのリスクである、バッファーへの直接出力とエラー時の die() が取り除かれているためです。このページでは、正しく運用する方法を説明します。
前提条件: /integrations/tcpdf-compat/migration/ に記載された strict モード監査を完了し、strict モードを オフ にしてデプロイしてください。
ワーカーとハンドラーでの出力の処理
「ワーカーとハンドラーでの出力の処理」という見出しのセクションレガシー TCPDF の Output() は、アクティブな出力バッファーに直接書き込みます。そのため HTTP フレームワークのレスポンスが壊れ、キューワーカーの動作に支障が出ます。代わりに、このアダプターは安全な出力先ブリッジを通じて出力を振り分けます。
呼び出し元に適した出力先を使用してください。
| コンテキスト | 出力先 | 理由 |
|---|---|---|
| ストレージに書き込むキューワーカー | Output($path, 'F') | ファイルへ書き込み、空文字列を返す。バッファーとは相互作用しない。 |
| 生成後の attach/upload | Output($name, 'S') | PDF のバイト列を返す。送り先は呼び出し元で制御する。 |
| メール添付 | Output($name, 'E') | Content-Type: application/pdf 付きの base64 MIME 本文を返す。 |
| 呼び出し元で制御する HTTP レスポンス | Output($name, 'S') | バイト列を取得し、ヘッダーと本文を呼び出し元で設定する。 |
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
/** * Render an invoice in a queue worker. Returns the storage path. * * @throws \RuntimeException on a render failure (Error() throws, not die()). */function renderInvoiceJob(array $invoice, string $storageDir): string{ $pdf = new TCPDF('P', 'mm', 'A4'); $pdf->SetFont('helvetica', '', 12); $pdf->AddPage(); $pdf->Cell(0, 10, 'Invoice ' . $invoice['number'], 0, 1);
$path = $storageDir . '/invoice-' . $invoice['number'] . '.pdf';
try { $pdf->Output($path, 'F'); // writes file, no buffer pollution } catch (TcpdfNotImplementedException $e) { // Only reachable if strict mode is on — it must NOT be in production. throw new \RuntimeException('Adapter strict-mode gap in production: ' . $e->getMessage(), 0, $e); } catch (\RuntimeException $e) { // Error() throws RuntimeException instead of die(). throw new \RuntimeException('PDF render failed: ' . $e->getMessage(), 0, $e); }
return $path;}HTTP ハンドラーでは 'S' を優先し、ヘッダーは呼び出し元で設定してください。
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Report');
$bytes = $pdf->Output('report.pdf', 'S');
header('Content-Type: application/pdf');header('Content-Length: ' . strlen($bytes));header('Content-Disposition: inline; filename="report.pdf"');echo $bytes;失敗の処理
「失敗の処理」という見出しのセクションError() は RuntimeException をスローし、die() を呼び出しません。これは、レガシー TCPDF から移行する際の運用上の最も大きな変更点です。
- すべてのレンダリングエントリーポイントを
try/catchで囲んでください。 - この例外をアプリケーション側のエラー契約(HTTP 5xx、ジョブの失敗、リトライ、デッドレター)にマッピングしてください。
- レンダリングが失敗してもプロセスが終了すると想定しないでください。終了しません。
定期的な strict モード CI ジョブを実行している場合(推奨)、そこで発生する TcpdfNotImplementedException は有効な検出結果です。あるコードパスが、サポートされていない TCPDF パラメーターに依存しています。これは不安定なテストではなく、移行作業項目として扱ってください。
ライフサイクルとリソースの処理
「ライフサイクルとリソースの処理」という見出しのセクション- ドキュメントは、最初に出力を呼び出した時点で PDF のバイト列を遅延構築します。
Close()は任意です。呼び出すとバイト列がキャッシュされます。Open()は安全な no-op です。 endPage()は何もしません。ページのライフサイクルは NextPDF が管理します。ホットループからは削除してください。価値はありません。- ジョブの合間は、アダプターを PHP のガベージコレクションに任せてください。
_destroy()はアダプターのキャッシュデータをリセットしますが、通常のワーカーループで明示的に呼び出す必要はありません。 - ドキュメントごとに新しいアダプターを構築してください。長時間実行するワーカーで、無関係なドキュメント間で 1 つのアダプターインスタンスを使い回さないでください。ドキュメントの状態はインスタンスごとに保持されます。
パフォーマンスの指針
「パフォーマンスの指針」という見出しのセクション- このアダプターは薄い委譲レイヤーです。コストの大半は、アダプターではなくエンジン側で発生します。
- レガシー定数は、起動時に一度だけ定義してください。
LegacyDefaults::register()とLegacyBootstrap::enableAliases()はどちらも冪等ガードで保護されているため、繰り返し呼び出しても低コストです。リクエストごとに定数を定義するのは無駄な処理です。 - ブラウザー以外のコンテキストでは、
'I'/'D'よりもOutput(..., 'S')または'F'を優先してください。inline/download パスはフレームワークに依存しない出力を生成しますが、通常ワーカーでは望ましくありません。 - 大量生成の場合は、アダプターではなくエンジンをプロファイリングしてください。アダプター自体のページあたりのオーバーヘッドは、レンダリングに比べれば小さなものです。
- 各アダプターインスタンスは独立しており、それぞれが独自のドキュメント状態を保持します。各作業単位が独自のアダプターインスタンスを使用している限り、プロセスレベルおよびワーカーレベルの並行処理は安全です。
LegacyBootstrapとLegacyDefaultsの冪等性ガードは、プロセスローカルな静的状態を使用します。一般的な PHP の per-request/per-worker モデルでは安全です。これらは、スレッド間で可変状態を共有する用途には設計されていません。
本番投入前チェックリスト
「本番投入前チェックリスト」という見出しのセクション- strict モード監査が完了し、本番環境では strict モードをオフにして運用している。
- すべてのレンダリングエントリーポイントを
RuntimeExceptionに対してtry/catchで囲んでいる(die()に依存していない)。 - ワーカーは
Output(..., 'F')または'S'を使用し、インラインパスは決して使用していない。 - レガシー定数を、最初の構築前に起動時に一度だけ定義している。
- リグレッションを検出するための定期的な strict モード CI ジョブを用意している。
- バイトレベルのテストアサーションを再ベースライン化している(/integrations/tcpdf-compat/migration/ を参照)。
- /integrations/tcpdf-compat/security-and-operations/ — 暗号化、署名の方針、堅牢化
- /integrations/tcpdf-compat/troubleshooting/ — 本番環境の障害パターンと修正方法
- /integrations/tcpdf-compat/configuration/ — strict モードと定数の衛生管理
- /integrations/tcpdf-compat/migration/ — 本番投入前に必ず実施すべき監査