Zum Inhalt springen

compat-legacy im Produktivbetrieb einsetzen

Der Adapter lässt sich gefahrlos in HTTP-Handlern, Queue-Workern und langlaufenden Prozessen betreiben. Er ist sicherer als das Legacy-TCPDF 6.2.13, weil die beiden häufigsten Risiken im Produktivbetrieb beseitigt sind: die direkte Ausgabe in den Puffer und die() bei Fehlern. Diese Seite beschreibt, wie Sie ihn korrekt einsetzen.

Voraussetzung: Schließen Sie das Strict-Mode-Audit unter /integrations/tcpdf-compat/migration/ ab und stellen Sie die Anwendung mit deaktiviertem Strict-Mode (off) bereit.

Das Legacy-TCPDF-Output() schreibt direkt in den aktiven Ausgabepuffer. Dadurch können Antworten in HTTP-Frameworks beschädigt und Queue-Worker lahmgelegt werden. Der Adapter leitet die Ausgabe stattdessen über eine sichere Ziel-Bridge.

Verwenden Sie das Ziel, das zum jeweiligen Aufrufer passt:

KontextZielWarum
Queue-Worker, der in den Speicher schreibtOutput($path, 'F')Schreibt die Datei und gibt einen leeren String zurück. Keine Interaktion mit dem Puffer.
Erzeugen und anschließend attach/uploadOutput($name, 'S')Gibt die PDF-Bytes zurück; Sie steuern, wohin sie weitergegeben werden.
E-Mail-AnhangOutput($name, 'E')Gibt einen base64-codierten MIME-Body mit Content-Type: application/pdf zurück.
HTTP-Antwort, die Sie selbst steuernOutput($name, 'S')Rufen Sie die Bytes ab und setzen Sie anschließend Ihre eigenen Header und den Body.
examples/production-worker.php
<?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;
}

Verwenden Sie in einem HTTP-Handler vorzugsweise 'S' und setzen Sie die Header selbst:

examples/production-http.php
<?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() wirft eine RuntimeException; es ruft niemals die() auf. Das ist mit Abstand die größte betriebliche Änderung gegenüber dem Legacy-TCPDF.

  • Umschließen Sie jeden Render-Einstiegspunkt mit try/catch.
  • Bilden Sie die Ausnahme auf den Fehlervertrag Ihrer Anwendung ab (HTTP 5xx, fehlgeschlagener Job, Retry, Dead-Letter).
  • Gehen Sie nicht davon aus, dass der Prozess bei einem Render-Fehler endet; das tut er nicht.

Wenn Sie einen regelmäßigen Strict-Mode-CI-Job betreiben (empfohlen), ist eine dort auftretende TcpdfNotImplementedException ein echter Befund: Ein Codepfad verlässt sich auf einen nicht unterstützten TCPDF-Parameter. Behandeln Sie ihn als Migrationsarbeitspaket, nicht als instabilen Test.

  • Das Dokument erzeugt seine PDF-Bytes verzögert erst beim ersten Ausgabeaufruf. Close() ist optional; ein Aufruf speichert die Bytes im Cache. Open() ist ein gefahrloser No-Op.
  • endPage() hat keine Wirkung; NextPDF verwaltet den Seitenlebenszyklus. Entfernen Sie es aus Hot Loops; es bringt keinen Mehrwert.
  • Lassen Sie PHP den Adapter zwischen Jobs per Garbage Collection abräumen. _destroy() setzt die zwischengespeicherten Daten des Adapters zurück; in normalen Worker-Schleifen müssen Sie es jedoch nicht explizit aufrufen.
  • Erzeugen Sie für jedes Dokument einen frischen Adapter. Verwenden Sie eine Adapter-Instanz in einem langlaufenden Worker nicht für voneinander unabhängige Dokumente wieder; der Dokumentstatus gilt pro Instanz.
  • Der Adapter ist eine dünne Delegationsschicht; die Kosten entstehen in der Engine, nicht im Adapter.
  • Definieren Sie Legacy-Konstanten einmalig beim Boot. LegacyDefaults::register() und LegacyBootstrap::enableAliases() sind beide idempotent und abgesichert, sodass wiederholte Aufrufe günstig sind. Konstanten pro Request zu definieren, ist verschwendete Arbeit.
  • Bevorzugen Sie Output(..., 'S') oder 'F' gegenüber 'I'/'D' in Nicht-Browser-Kontexten. Die Inline-/Download-Pfade erzeugen framework-unabhängige Ausgaben, die Sie in einem Worker normalerweise nicht möchten.
  • Profilen Sie bei umfangreicher Generierung die Engine, nicht den Adapter. Das Budget pro Seite für den Eigen-Overhead des Adapters ist im Verhältnis zum Rendering gering.
  • Jede Adapter-Instanz ist unabhängig und hält ihren eigenen Dokumentstatus. Nebenläufigkeit auf Prozess- oder Worker-Ebene ist sicher, solange jede Arbeitseinheit ihre eigene Adapter-Instanz verwendet.
  • Die Idempotenz-Wächter in LegacyBootstrap und LegacyDefaults verwenden prozesslokalen statischen Status; sie sind in typischen PHP-per-request/per-worker-Modellen sicher. Sie sind nicht dafür ausgelegt, veränderbaren Status über Threads hinweg zu teilen.
  • Strict-Mode-Audit abgeschlossen; die Produktion läuft mit deaktiviertem Strict-Mode.
  • Alle Render-Einstiegspunkte sind mit try/catch für RuntimeException umschlossen (kein Verlass auf die()).
  • Worker verwenden Output(..., 'F') oder 'S', niemals den Inline-Pfad.
  • Legacy-Konstanten einmalig beim Boot definiert, vor der ersten Konstruktion.
  • Ein regelmäßiger Strict-Mode-CI-Job ist eingerichtet, um Regressionen abzufangen.
  • Byte-genaue Test-Assertions sind als neue Baseline festgelegt (siehe /integrations/tcpdf-compat/migration/).
  • /integrations/tcpdf-compat/security-and-operations/ — Verschlüsselung, Signaturstrategie, Härtung
  • /integrations/tcpdf-compat/troubleshooting/ — Fehlermuster im Produktivbetrieb und deren Behebung
  • /integrations/tcpdf-compat/configuration/ — Strict-Mode und sauberer Umgang mit Konstanten
  • /integrations/tcpdf-compat/migration/ — das Audit, das vor dem Produktivbetrieb abgeschlossen sein muss