Esecuzione di compat-legacy in produzione
In sintesi
Sezione intitolata “In sintesi”L’adattatore può essere usato in sicurezza nei gestori HTTP, nei worker di coda e nei processi a lunga esecuzione. Rispetto a TCPDF legacy 6.2.13 è più sicuro, perché elimina i due rischi di produzione più comuni: l’output diretto nel buffer e il die() in caso di errore. Questa pagina spiega come usarlo correttamente.
Prima di procedere, completare l’audit in modalità strict in /integrations/tcpdf-compat/migration/ ed eseguire il deploy con la modalità strict disattivata.
Gestione dell’output nei worker e nei gestori
Sezione intitolata “Gestione dell’output nei worker e nei gestori”Il metodo Output() di TCPDF legacy scrive direttamente nel buffer di output attivo. Nei framework HTTP questo corrompe le risposte e, nei worker di coda, interrompe l’elaborazione. L’adattatore instrada invece l’output attraverso un bridge di destinazione sicuro.
Usare la destinazione adatta al chiamante:
| Contesto | Destinazione | Perché |
|---|---|---|
| Worker di coda che scrive nello storage | Output($path, 'F') | Scrive il file e restituisce una stringa vuota. Nessuna interazione con il buffer. |
| Generazione seguita da attach/upload | Output($name, 'S') | Restituisce i byte del PDF; la destinazione resta sotto il controllo del chiamante. |
| Allegato email | Output($name, 'E') | Restituisce un corpo MIME in base64 con Content-Type: application/pdf. |
| Risposta HTTP gestita dal chiamante | Output($name, 'S') | Ottenere i byte, quindi impostare intestazioni e corpo della risposta. |
<?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;}In un gestore HTTP, preferire 'S' e impostare manualmente le intestazioni:
<?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;Gestione degli errori
Sezione intitolata “Gestione degli errori”Error() solleva una RuntimeException; non chiama mai die(). È la modifica operativa più importante rispetto a TCPDF legacy.
- Racchiudere ogni punto di ingresso del rendering in
try/catch. - Mappare l’eccezione sul contratto di gestione degli errori dell’applicazione (HTTP 5xx, job fallito, retry, dead-letter).
- Non dare per scontato che il processo termini in caso di errore di rendering: non è così.
Quando si esegue un job CI periodico in modalità strict (consigliato), una TcpdfNotImplementedException in quel contesto è un segnale reale: un percorso di codice dipende da un parametro TCPDF non supportato. Trattarla come un’attività di migrazione, non come un test instabile.
Ciclo di vita e gestione delle risorse
Sezione intitolata “Ciclo di vita e gestione delle risorse”- Il documento genera i propri byte PDF in modalità lazy alla prima chiamata di output.
Close()è facoltativo; se chiamato, memorizza i byte nella cache.Open()è un no-op sicuro. endPage()non fa nulla: NextPDF gestisce il ciclo di vita delle pagine. Rimuoverlo dai cicli critici; non aggiunge alcun valore.- Lasciare che PHP rimuova l’adattatore tramite garbage collection tra un job e l’altro.
_destroy()reimposta i dati memorizzati nella cache dell’adattatore, ma non è necessario chiamarlo esplicitamente nei normali cicli dei worker. - Creare un nuovo adattatore per ogni documento. Non riutilizzare un’unica istanza dell’adattatore per documenti non correlati in un worker a lunga esecuzione; lo stato del documento è specifico per ciascuna istanza.
Indicazioni sulle prestazioni
Sezione intitolata “Indicazioni sulle prestazioni”- L’adattatore è un leggero livello di delega; il costo è dominato dal motore, non dall’adattatore.
- Definire le costanti legacy una sola volta all’avvio.
LegacyDefaults::register()eLegacyBootstrap::enableAliases()sono idempotenti e protetti, quindi le chiamate ripetute hanno un costo contenuto. Definire le costanti a ogni richiesta è lavoro sprecato. - Preferire
Output(..., 'S')o'F'rispetto a'I'/'D'nei contesti non basati su browser. I percorsi inline/download producono output non mediato dal framework, cosa che di solito non si desidera in un worker. - Per la generazione ad alto volume, profilare il motore, non l’adattatore. Il budget per pagina relativo all’overhead proprio dell’adattatore è ridotto rispetto al rendering.
Concorrenza
Sezione intitolata “Concorrenza”- Ogni istanza dell’adattatore è indipendente e mantiene il proprio stato del documento. La concorrenza a livello di processo o di worker è sicura, purché ogni unità di lavoro usi la propria istanza dell’adattatore.
- Le protezioni di idempotenza in
LegacyBootstrapeLegacyDefaultsusano stato statico locale al processo; sono sicure nei tipici modelli PHP per-request/per-worker. Non sono progettate per condividere stato mutabile tra thread.
Checklist pre-produzione
Sezione intitolata “Checklist pre-produzione”- Audit in modalità strict completato; la produzione viene eseguita con la modalità strict disattivata.
- Tutti i punti di ingresso del rendering racchiusi in
try/catchperRuntimeException(senza fare affidamento sudie()). - I worker usano
Output(..., 'F')o'S', mai il percorso inline. - Costanti legacy definite una sola volta all’avvio, prima della prima istanziazione.
- È presente un job CI periodico in modalità strict per individuare le regressioni.
- Asserzioni di test a livello di byte riallineate (vedere /integrations/tcpdf-compat/migration/).
Vedere anche
Sezione intitolata “Vedere anche”- /integrations/tcpdf-compat/security-and-operations/ — cifratura, strategia di firma, hardening
- /integrations/tcpdf-compat/troubleshooting/ — pattern di errore in produzione e relative correzioni
- /integrations/tcpdf-compat/configuration/ — modalità strict e igiene delle costanti
- /integrations/tcpdf-compat/migration/ — l’audit da completare prima della produzione