コンテンツにスキップ

TCPDF 6.x のコードベースを NextPDF に移行する

nextpdf/compat-legacy パッケージは、TCPDF 6.x の公開メソッド名、パラメーターの順序、デフォルト値を、NextPDF\Compat\Tcpdf\TCPDF アダプターを通じて NextPDF コアエンジン上で公開します。移行は次の順序で進めます。まず最小限の変更でエンジンへ載せ替え、すでに動作する範囲を確認し、strict モードを有効にして動作しない部分を洗い出し、呼び出し箇所を 1 つずつ修正し、最後にアダプターを廃止してモダン API へ移します。アダプターは移行の足場であり、最終的なゴールではありません。

前提条件は次のとおりです。

  • NextPDF コアと nextpdf/compat-legacy がインストールされていること。
  • テストスイートを備えた既存の TCPDF 6.x コードベースがあること。このスイートは、以降のすべての段階でセーフティネットになります。

本ページは how-to ガイドです。個々の TCPDF 呼び出しについて、メソッドごとの動作はメソッドカバレッジのページを参照してください。コード付きのファイル単位の完全な移行戦略については、上流の移行ページを参照してください。どちらも「関連項目」にリンクがあります。

アダプターをコアと並べてインストールします。元の TCPDF ライブラリはまだ削除しないでください。両方を残しておくことで、移行中に出力を比較できます。

Terminal window
composer require nextpdf/compat-legacy

コードを変更する前に、エンジンへの参照が resolve(解決)されること(nextpdf/core ^3.0)と、テストスイートが引き続き実行できることを確認します。

アダプターは互換レイヤーであり、TCPDF のフォークでも、バイト単位で同一のクローンでもありません。調査対象とした約 120 個の TCPDF 6.x の公開メソッドのうち、約 94 個は NextPDF\Core\Document の操作に直接マッピングされ、ドキュメント化されたパラメーターについて互換的に動作します。一部の明確に定義されたメソッドは、エンジンが反映しないレガシーパラメーターを受け取って無視する(silent-ignore)か、まったく出力を生成しません(未実装または該当なし)。正式な、テストで検証済みのカバレッジマトリクスは、パッケージリポジトリの docs/TCPDF_COVERAGE.md にあります。本ガイドとそのマトリクスが食い違う場合は、マトリクスが優先されます。

移行全体の方向性を決める事実が 2 つあります。

  • 出力バイトは異なります。 エンジンは独立した PDF 2.0 実装であるため、見た目の結果が同じであっても、生成されるバイトは TCPDF の出力とは異なります。PDF の正確なバイトをアサートするテストは、レンダリングされた内容や構造的なプロパティを基準として再ベースライン化する必要があります。
  • strict モードは監査ツールです。 strict モードがオフ(デフォルト)の場合、TCPDF の動作を再現できないメソッドは、何も通知せずに動作が縮退します。strict モードがオンの場合、それらの呼び出しは TcpdfNotImplementedException をスローし、無視されたパラメーターを正確に示したうえで移行のヒントを提示します。strict モードは専用の監査パスで実行し、本番環境では決して使用しないでください。

アダプターは、ラップしているエンジンドキュメントも getDocument() を通じて公開しており、これは NextPDF\Core\Document を返します。これが移行の出口です。呼び出し箇所を 1 つずつモダン API へ移行し、最終的にアダプターを削除できるようにします。

関心事サーフェス
構築new NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4')
オプトインのグローバルエイリアスNextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases()
監査を有効化TCPDF::setStrictMode(true)
監査用の例外NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException
モダン API への脱出ハッチTCPDF::getDocument(): NextPDF\Core\Document
出力TCPDF::Output(string $name, string $dest)S, F, E, I, D

LegacyBootstrap::enableAliases() はべき等です。このメソッドは、\TCPDF\TCPDF_STATIC\TCPDF_FONTS\TCPDF_COLORS\TCPDF_IMAGES を、これらのクラスがまだ存在しない場合にのみ登録します。メソッドごとの完全なカバレッジと出力先の動作は、「関連項目」にリンクされているメソッドカバレッジおよびクイックスタートのページに記載されています。

コード内の import を変更し、TCPDF 形式の呼び出しはそのまま残して、PDF を生成します。

quickstart-first.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->SetCreator('Quickstart');
$pdf->SetTitle('First Document');
$pdf->SetFont('helvetica', '', 12);
$pdf->AddPage();
$pdf->Cell(0, 10, 'Hello from the NextPDF engine', 1, 1, 'C');
$pdf->Output(__DIR__ . '/quickstart.pdf', 'F');

Output($name, 'F') はファイルを書き出し、空文字列を返します。レガシーの TCPDF とは異なり、アダプターの Output() はアクティブな出力バッファーには書き出さないため、キューワーカーや、レスポンスを自前で制御する HTTP ハンドラーの中で安全に呼び出せます。

グローバル名前空間で new \TCPDF(...) を構築している呼び出し箇所に手を加えられない場合は、起動時に一度だけオプトインのエイリアスを有効化します。

quickstart-alias.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Legacy code now resolves \TCPDF to the adapter:
$pdf = new \TCPDF('P', 'mm', 'A4');
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Legacy call site, modern engine');
$pdf->Output(__DIR__ . '/aliased.pdf', 'F');

元の TCPDF ライブラリがまだオートロード可能な状態では、エイリアスを有効化しないでください。\TCPDF クラスがすでに存在する場合、エイリアスはスキップされます。そのため、気付かないままレガシーの TCPDF を使い続けてしまうおそれがあります。移行中は、ファイル単位の import を優先してください。

移行を安全に進めるためのステップは、strict モードによる監査です。代表的な本番経路、またはテストスイートを、strict モードを有効にして実行し、発生したすべての TcpdfNotImplementedException を収集します。それぞれが作業項目です。メソッド、無視されたパラメーター、ヒントが示されます。

migration-audit.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;
use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void
{
// ... your existing rendering code, unchanged ...
}
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->setStrictMode(true);
try {
renderInvoice($pdf);
$pdf->Output(__DIR__ . '/audit.pdf', 'F');
} catch (TcpdfNotImplementedException $exception) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $exception->getMessage() . "\n");
}

各差分について、最も低コストで正しい修正を選びます。これまで頼っていなかったパラメーターを削除するか、getDocument() を介してモダン API で意図を表現し直します。脱出ハッチは、TCPDF サーフェスでは表現できないものをすべて処理します。

migration-escape-hatch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
// Legacy path stays for the parts that already work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here —
// for example a clickable image (the legacy Image() link parameter
// is one of the silently ignored parameters):
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

strict モードは専用の CI ジョブとして実行し、その後オフにして、監査済みのコードパスをデプロイします。リファクタリングの過程で生じる回帰を検出するため、定期的な strict モードの CI ジョブを維持してください。

  • MultiCell()1 を返し、Write()0 を返します。 これらは互換性のためのプレースホルダーであり、計算された値ではありません。これらの戻り値で分岐するコードがある場合は、すべて調整してください。
  • Error()die() を呼び出す代わりに例外をスローします。 アダプターは RuntimeException を発生させます。プロセスの終了に依存していたコードは、この例外をキャッチする必要があります。
  • サイレントに無視されるパラメーター。 Image()writeHTML()SetProtection()Bookmark() といったメソッドは、無視されるレガシーパラメーターを受け取ります。これらを見つけるには strict モードを使用します。クリック可能な画像を作成するには、画像を描画したうえで、同じ矩形の上に Document::link() を追加します。
  • 未実装のメソッド。 setSignature()addEmptySignatureAppearance()endPage() は no-op であり、strict モードでは例外をスローします。Open() は決して例外をスローしない安全な no-op です。endPage()Open() は削除してください。署名には、モダンな署名 API を介した商用版の NextPDF エディションが必要です。
  • PDF のバージョンは固定です。 setPDFVersion() では古い PDF バージョンへダウンターゲットできず、出力は常に PDF 2.0 です。setUserRights() は PDF 2.0 では非推奨であり、notice を伴って無視されます。
  • エイリアスの競合。 tecnickcom/tcpdf を削除した後も、まだ元の TCPDF クラスへ解決されるものがある場合は、エイリアスに関する注意点が当てはまっています。該当する呼び出し箇所で、アダプターを明示的に import してください。

アダプターは処理をエンジンへ委譲します。ドキュメントの構築コストは、アダプターレイヤーではなく、内容に応じてスケールします。アダプターの Output() は出力バッファーへ書き出さないため、キューワーカーの中でも安全です。重い TCPDF 形式の生成は、他の NextPDF の生成と同じ方法でリクエストスレッドから切り離してください。バイトレベルのテストをレンダリングされた内容を基準として再ベースライン化する作業は一度きりのコストであり、将来のエンジンのアップグレードでも維持されるテストが得られます。

  • 暗号化。 SetProtection() はレガシーの mode および pubkeys パラメーターを無視します。エンジンは標準ハンドラーに AES-256 を使用します。証明書ベースの暗号化には、レガシーパラメーターではなく、アダプターで公開されているモダンな公開鍵暗号化のエントリーポイントを使用してください。
  • 署名はゲートされています。 Baseline 署名のサポートは、証明書のバリューオブジェクトを用いてモダンな署名 API を介して利用できる商用版の機能です。レガシーの setSignature() は no-op です。本ガイドは、いずれのエディションについても、長期検証またはタイムスタンプ付き署名プロファイルに関する主張を一切行いません。
  • 監査中は明示的に失敗させます。 strict モードはサイレントなパラメーターの欠落を可視化するため、呼び出し元は自分の意図が反映されなかったことを把握できます。収集した例外は、本番環境の動作としてではなく、移行作業のリストとして扱ってください。
  • 空の catch ブロックは決して書かないでください。 監査の例では、TcpdfNotImplementedException をキャッチし、定義済みの作業項目の行を書き出します。

移行中の暗号化と署名に関する全体的な方針は、compat-legacy のセキュリティおよび運用のページに記載されています。

本ガイド自体は、規範的な標準への準拠を一切主張しません。アダプターは PDF 2.0(ISO 32000-2)の出力を書き出し、古いバージョンへダウンターゲットすることはできません。その動作と該当する条項は上流のメソッドカバレッジのページに固定されており、同ページには strict モードの背後にある OWASP の明示的失敗(fail-explicitly)の原則と、カバレッジ監査における ISO/IEC 25023 の機能完全性の位置づけも記録されています。本クックブックのページでは使い方を改めて述べ、それらの引用についてはそのページに委ねます。