Zum Inhalt springen

Eine TCPDF-6.x-Codebasis auf NextPDF migrieren

Das Paket nextpdf/compat-legacy stellt die öffentlichen Methodennamen, die Parameterreihenfolge und die Standardwerte von TCPDF 6.x über den Adapter NextPDF\Compat\Tcpdf\TCPDF auf Basis der NextPDF-Core-Engine bereit. Gehen Sie in dieser Reihenfolge vor: Wechseln Sie zuerst mit der kleinstmöglichen Änderung auf die Engine, weisen Sie nach, was bereits funktioniert, aktivieren Sie den Strict-Modus, um aufzulisten, was nicht funktioniert, korrigieren Sie die Aufrufstellen eine nach der anderen und ersetzen Sie den Adapter anschließend durch die moderne API. Der Adapter ist ein Migrationsgerüst, nicht das Ziel.

Voraussetzungen, gleich vorweg:

  • NextPDF Core und nextpdf/compat-legacy sind installiert.
  • Sie haben eine bestehende TCPDF-6.x-Codebasis mit einer Test-Suite. Die Suite ist das Sicherheitsnetz für jede der folgenden Stufen.

Dies ist eine Schritt-für-Schritt-Anleitung. Für das Verhalten einzelner TCPDF-Aufrufe pro Methode lesen Sie die Seite zur Methodenabdeckung. Für die vollständige Datei-für-Datei-Strategie mit Code lesen Sie die übergeordnete Migrationsseite. Beide sind unter „Siehe auch“ verlinkt.

Installieren Sie den Adapter zusätzlich zu Core. Entfernen Sie die echte TCPDF-Bibliothek noch nicht; wenn Sie beide behalten, können Sie die Ausgabe während der Migration vergleichen.

Terminal-Fenster
composer require nextpdf/compat-legacy

Bevor Sie Code ändern, vergewissern Sie sich, dass die Engine-Verknüpfung auflösbar ist (nextpdf/core ^3.0) und die Suite weiterhin läuft.

Der Adapter ist eine Kompatibilitätsschicht, kein Fork von TCPDF und kein exakter Klon. Von rund 120 untersuchten öffentlichen TCPDF-6.x-Methoden werden etwa 94 direkt auf eine NextPDF\Core\Document-Operation abgebildet und verhalten sich für die dokumentierten Parameter kompatibel. Eine klar abgegrenzte Minderheit nimmt entweder Legacy-Parameter entgegen, die die Engine nicht berücksichtigt (stillschweigendes Ignorieren), oder erzeugt überhaupt keine Ausgabe (nicht implementiert oder nicht zutreffend). Die maßgebliche, testverifizierte Abdeckungsmatrix liegt im Paket-Repository unter docs/TCPDF_COVERAGE.md. Wenn dieser Leitfaden und diese Matrix sich widersprechen, ist die Matrix maßgeblich.

Zwei Tatsachen prägen die gesamte Migration:

  • Die Ausgabebytes unterscheiden sich. Die Engine ist eine unabhängige PDF 2.0-Implementierung, daher unterscheiden sich die gerenderten Bytes von der TCPDF-Ausgabe, selbst wenn das sichtbare Ergebnis gleich aussieht. Tests, die exakte PDF-Bytes prüfen, müssen auf gerenderte Inhalte oder strukturelle Eigenschaften umgestellt werden.
  • Der Strict-Modus ist Ihr Audit-Werkzeug. Bei ausgeschaltetem Strict-Modus (der Standard) fallen Methoden, die das TCPDF-Verhalten nicht reproduzieren können, stillschweigend auf ein eingeschränktes Verhalten zurück. Bei eingeschaltetem Strict-Modus werfen diese Aufrufe eine TcpdfNotImplementedException, die genau die ignorierten Parameter und einen Migrationshinweis benennt. Führen Sie den Strict-Modus in einem eigenen Audit-Durchlauf aus, niemals in der Produktion.

Der Adapter stellt das gekapselte Engine-Dokument außerdem über getDocument() bereit, das das NextPDF\Core\Document zurückgibt. Das ist der Ausstiegspfad: Migrieren Sie die Aufrufstellen eine nach der anderen auf die moderne API, bis Sie den Adapter entfernen können.

AnliegenOberfläche
Erzeugennew NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4')
Optionale globale AliaseNextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases()
Das Audit aktivierenTCPDF::setStrictMode(true)
Audit-ExceptionNextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException
Notausstieg zur modernen APITCPDF::getDocument(): NextPDF\Core\Document
AusgabeTCPDF::Output(string $name, string $dest)S, F, E, I, D

LegacyBootstrap::enableAliases() ist idempotent. Es registriert \TCPDF, \TCPDF_STATIC, \TCPDF_FONTS, \TCPDF_COLORS und \TCPDF_IMAGES nur dann, wenn diese Klassen noch nicht existieren. Die vollständige Abdeckung pro Methode und das Verhalten der Ausgabeziele finden Sie auf den Seiten zur Methodenabdeckung und zum Quickstart, die unter „Siehe auch“ verlinkt sind.

Ändern Sie den Import, behalten Sie die Aufrufe im TCPDF-Stil bei und erzeugen Sie ein 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') schreibt die Datei und gibt einen leeren String zurück. Anders als beim Legacy-TCPDF gibt Output() des Adapters nichts in den aktiven Output-Buffer aus, daher können Sie es bedenkenlos in einem Queue-Worker oder einem HTTP-Handler aufrufen, der seine eigene Antwort steuert.

Wenn Sie Aufrufstellen, die new \TCPDF(...) im globalen Namespace verwenden, nicht ändern können, aktivieren Sie die optionalen Aliase einmalig beim Bootstrapping.

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');

Aktivieren Sie keine Aliase, solange die echte TCPDF-Bibliothek noch autoloadbar ist. Der Alias wird übersprungen, wenn bereits eine \TCPDF-Klasse existiert, sodass Sie womöglich unbemerkt das Legacy-TCPDF weiterverwenden. Bevorzugen Sie während der Migration dateiweise Imports.

Der migrationssichere Schritt ist das Strict-Modus-Audit. Führen Sie einen repräsentativen Produktionspfad oder die Suite mit eingeschaltetem Strict-Modus aus und sammeln Sie jede TcpdfNotImplementedException. Jede davon ist ein Arbeitspaket: Sie benennt die Methode, die ignorierten Parameter und einen Hinweis.

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");
}

Wählen Sie für jede Lücke die aufwandsärmste korrekte Lösung: Lassen Sie einen Parameter weg, auf den Sie sich nie verlassen haben, oder drücken Sie die Absicht über die moderne API via getDocument() neu aus. Der Notausstieg deckt alles ab, was die TCPDF-Oberfläche nicht ausdrücken kann.

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');

Führen Sie den Strict-Modus als eigenen CI-Job aus, schalten Sie ihn anschließend ab und bringen Sie den auditierten Codepfad ins Deployment. Behalten Sie einen periodischen Strict-Modus-CI-Job bei, um Regressionen beim Refactoring abzufangen.

  • MultiCell() gibt 1 zurück, Write() gibt 0 zurück. Das sind Kompatibilitätsplatzhalter, keine berechneten Werte. Passen Sie jeden Code an, der anhand dieser Rückgabewerte verzweigt.
  • Error() wirft eine Exception, statt die() aufzurufen. Der Adapter löst eine RuntimeException aus. Code, der sich auf die Prozessbeendigung verlassen hat, muss die Exception abfangen.
  • Stillschweigend ignorierte Parameter. Methoden wie Image(), writeHTML(), SetProtection() und Bookmark() nehmen Legacy-Parameter entgegen, die ignoriert werden. Nutzen Sie den Strict-Modus, um sie zu finden. Für ein anklickbares Bild zeichnen Sie das Bild und fügen dann Document::link() über demselben Rechteck hinzu.
  • Nicht implementierte Methoden. setSignature(), addEmptySignatureAppearance() und endPage() sind No-Ops, die im Strict-Modus eine Exception werfen; Open() ist ein sicheres No-Op, das nie eine Exception wirft. Entfernen Sie endPage() und Open(). Für das Signieren ist eine kommerzielle NextPDF-Edition über die moderne Signatur-API erforderlich.
  • Die PDF-Version ist festgelegt. setPDFVersion() kann nicht auf eine ältere PDF-Version umstellen; die Ausgabe ist immer PDF 2.0. setUserRights() ist in PDF 2.0 veraltet und wird mit einem Hinweis ignoriert.
  • Alias-Konflikt. Wenn nach dem Entfernen von tecnickcom/tcpdf noch irgendetwas auf die echte TCPDF-Klasse auflöst, hat die Alias-Schutzbedingung gegriffen; importieren Sie den Adapter an diesen Aufrufstellen explizit.

Der Adapter delegiert an die Engine; der Aufwand für den Dokumentaufbau skaliert mit dem Inhalt, nicht mit der Adapterschicht. Da Output() des Adapters nicht in den Output-Buffer schreibt, ist es in einem Queue-Worker sicher. Verlagern Sie aufwendige Generierung im TCPDF-Stil vom Request-Thread weg, genauso wie Sie es bei jeder NextPDF-Generierung tun würden. Die Umstellung von Tests auf Byte-Ebene auf gerenderte Inhalte ist ein einmaliger Aufwand und liefert Tests, die künftige Engine-Upgrades überstehen.

  • Verschlüsselung. SetProtection() ignoriert die Legacy-Parameter mode und pubkeys; die Engine verwendet AES-256 für den Standard-Handler. Für zertifikatsbasierte Verschlüsselung nutzen Sie den modernen Einstiegspunkt für Public-Key-Verschlüsselung, den der Adapter bereitstellt, nicht die Legacy-Parameter.
  • Signaturen sind editionsabhängig freigeschaltet. Die Unterstützung für Baseline-Signaturen ist eine Funktion der kommerziellen Edition, die über die moderne Signatur-API mit einem Zertifikats-Value-Object erreicht wird; das Legacy-setSignature() ist ein No-Op. Dieser Leitfaden trifft für keine Edition Aussagen über Langzeitvalidierung oder zeitgestempelte Signaturprofile.
  • Lassen Sie das Audit explizit scheitern. Der Strict-Modus macht stillen Parameterverlust sichtbar, sodass ein Aufrufer erfährt, wenn seine Absicht nicht berücksichtigt wurde. Behandeln Sie die gesammelten Exceptions als Arbeitsliste für die Migration, nicht als Produktionsverhalten.
  • Schreiben Sie niemals einen leeren catch-Block. Das Audit-Beispiel fängt TcpdfNotImplementedException ab und schreibt eine definierte Arbeitspaket-Zeile.

Das vollständige Vorgehen zu Verschlüsselung und Signaturen während der Migration finden Sie auf der compat-legacy-Seite zu Sicherheit und Betrieb.

Dieser Leitfaden erhebt selbst keinen normativen Standardanspruch. Der Adapter schreibt PDF 2.0-Ausgabe (ISO 32000-2) und kann nicht auf eine ältere Version zurückgehen. Dieses Verhalten und die zugehörige Klausel sind auf der vorgelagerten Seite zur Methodenabdeckung verankert, die auch das OWASP-Prinzip des expliziten Scheiterns hinter dem Strict-Modus und die Einordnung des Abdeckungs-Audits nach ISO/IEC 25023 zur funktionalen Vollständigkeit festhält. Diese Cookbook-Seite beschreibt die Verwendung und verweist für diese Zitate auf jene Seite.