Salta ai contenuti

Eseguire la migrazione da Dompdf a NextPDF

Questa guida accompagna la migrazione di un codebase basato su Dompdf alla pipeline Html di NextPDF. Dompdf e NextPDF seguono lo stesso schema — caricare l’HTML, eseguire il rendering, emettere un PDF — quindi la maggior parte dei call site può essere convertita in modo meccanico. Il lavoro effettivo consiste nella mappatura delle opzioni e nella gestione del delta di supporto CSS. NextPDF e Dompdf sono motori indipendenti: un layout prodotto da Dompdf è quindi compatibile con il risultato di NextPDF, non identico byte per byte. Questa guida copre la mappatura dei verbi, la mappatura delle chiavi di opzione, le differenze di comportamento e una sequenza di migrazione sicura.

Il supporto di NextPDF per una funzionalità HTML/CSS non garantisce che un determinato documento Dompdf venga riprodotto pixel per pixel. La matrice di supporto CSS è la fonte autorevole per stabilire quali funzionalità sono Verified. Questa guida descrive il comportamento; non rivendica l’equivalenza visiva.

Terminal window
composer require nextpdf/core:^3

Mantenere dompdf/dompdf installato durante la transizione (la sequenza di migrazione sicura esegue entrambi affiancati finché ogni call site non sia stato migrato), quindi rimuoverlo una volta completato il passaggio.

L’oggetto Dompdf di Dompdf è una facade unica che possiede il DOM, il foglio di stile, il frame tree e il canvas. NextPDF separa queste responsabilità: un NextPDF\Core\Document possiede il modello di pagina e l’output, e un solo metodo, writeHtml(), guida la pipeline HTML. Non esiste un passaggio separato in due fasi «render poi output». writeHtml() impagina il contenuto mentre lo scrive, e il documento viene emesso con save(), output() o getPdfData().

Il contenuto di pagina scritto da NextPDF è painting su content stream secondo ISO 32000-2 (ISO 32000-2 §8, iso32000_2_sec8#x1.x3.p14). La geometria di pagina controllata dall’opzione paper-size si mappa sul MediaBox dell’oggetto pagina (ISO 32000-2 §7, iso32000_2_sec7#x1.x104.p10). Si tratta di fondamenti del motore condivisi da qualsiasi writer conforme. Tuttavia l’algoritmo di layout che trasforma il CSS in quel contenuto è proprio di NextPDF e differisce da quello di Dompdf (vedere Differenze di comportamento).

L’API Html di NextPDF è documentata nel riferimento del modulo Html (generato automaticamente da PHPDoc). I principali punti di ingresso usati di seguito sono: Document::createStandalone(), Document::writeHtml(string $html): static, Document::writeHtmlCell(...), Document::output(?string, OutputDestination), Document::save(string $path): void, Document::getPdfData(): string e il value object NextPDF\Core\Config (pageSize, margins, fontsDirectory).

I nomi dell’API pubblica di Dompdf riportati di seguito sono stati confermati rispetto al repository pubblico upstream (dompdf/dompdf, master); vedere il sidecar di provenienza _source-sidecar-upstream-api.md presente nel repo. Nessun testo della documentazione upstream viene riprodotto.

DompdfNextPDFNote
new Dompdf($options)Document::createStandalone($config)Dompdf accetta un oggetto Options; NextPDF accetta un NextPDF\Core\Config. Per worker di lunga durata usare DocumentFactory anziché createStandalone().
$dompdf->loadHtml($html, $encoding)$doc->writeHtml($html)NextPDF tratta l’input come UTF-8; transcodificare l’input non UTF-8 prima della chiamata, anziché passare un argomento di codifica.
$dompdf->loadHtmlFile($file)$doc->writeHtml(file_get_contents($file))NextPDF non ha una variante di caricamento da file; leggere autonomamente il file affinché la policy di I/O resti nel proprio codice.
$dompdf->setPaper($size, $orientation)ConfigpageSize (un value object PageSize)Vedere la mappa delle opzioni.
$dompdf->render()(implicito)NextPDF esegue l’impaginazione durante writeHtml(); non esiste una fase di rendering separata. Rimuovere la chiamata render().
$dompdf->output()$doc->getPdfData()Restituisce i byte del PDF.
$dompdf->stream($name, $opts)$doc->output($name, OutputDestination::Download)NextPDF separa la destinazione tramite l’enum OutputDestination.
$dompdf->setBasePath($p) / setProtocol() / setBaseHost()(la risoluzione delle risorse è diversa)NextPDF risolve le risorse relative rispetto al working set del documento, non rispetto a una tripletta base path/protocol; vedere Differenze di comportamento.
$dompdf->addInfo($label, $value)$doc->setTitle() / setAuthor() / API dei metadatiLe coppie di informazioni free-form di Dompdf si mappano sui setter di metadati tipizzati (informazioni di documento ISO 32000-2 §14, iso32000_2_sec14#x1.x5.p5).
$dompdf->setHttpContext($ctx)(nessun equivalente)NextPDF non recupera risorse remote tramite uno stream context; vedere Non supportato / nessun equivalente diretto.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Dompdf:
// $dompdf = new Dompdf();
// $dompdf->loadHtml('<h1>Invoice</h1>');
// $dompdf->setPaper('A4', 'portrait');
// $dompdf->render();
// file_put_contents('out.pdf', $dompdf->output());
// NextPDF — the createStandalone() default page size is A4 portrait:
$doc = Document::createStandalone();
$doc->setTitle('Invoice');
$doc->addPage();
$doc->writeHtml('<h1>Invoice</h1>');
$doc->save(__DIR__ . '/out.pdf');
echo "Wrote out.pdf\n";

Questo rispecchia examples/08-html-basic.php (l’esempio eseguibile di questa guida), con dimensione di pagina e margini espliciti non predefiniti. È l’equivalente di un setPaper() di Dompdf più una configurazione dei margini tramite Options.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\OutputDestination;
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\ValueObjects\Margin;
use NextPDF\ValueObjects\PageSize;
// Equivalent of: $dompdf->setPaper('letter','portrait') + margin options.
// US Letter portrait = 612 x 792 pt.
// Margin constructor order is (top, right, bottom, left) — all 0.5in here.
$config = new Config(
pageSize: new PageSize(612.0, 792.0, 'Letter'),
margins: new Margin(36.0, 36.0, 36.0, 36.0), // top,right,bottom,left; 0.5in in points
);
$doc = Document::createStandalone($config);
$doc->setTitle('Quarterly Report');
$doc->setAuthor('Finance');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color:#1E3A8A;">Quarterly Report</h1>
<p>This report renders through the NextPDF Html pipeline. The CSS subset that
is <strong>Verified</strong> for production is the support-matrix authority,
not this page.</p>
<table border="1">
<tr><th>Region</th><th>Total</th></tr>
<tr><td>EMEA</td><td>1,204</td></tr>
</table>
HTML;
$doc->writeHtml($html);
// Equivalent of $dompdf->stream('report.pdf'):
$doc->output('report.pdf', OutputDestination::Download);
  • Nessun render in due fasi. Il codice Dompdf che ispeziona lo stato tra render() e output() (per esempio leggendo il conteggio delle pagine) non ha alcun analogo in NextPDF in quel punto esatto del flusso. Interrogare invece il documento dopo writeHtml().
  • Codifica. NextPDF elimina il parametro $encoding di Dompdf: convertire l’input in UTF-8 prima di writeHtml(). Il passaggio di byte Latin-1 produce mojibake, non un errore.
  • render() lasciato al suo posto. Una chiamata residua in stile $dompdf->render() non ha alcun metodo NextPDF e produrrà un fatal «undefined method». Eliminarla durante il passaggio, non sostituirla con uno stub.
  • PHP inline. L’opzione enable_php di Dompdf valuta <script type="text/php">. Per scelta progettuale NextPDF non ha alcuna esecuzione di PHP nel documento (è una superficie di injection). Spostare quella logica nel proprio PHP prima di writeHtml().
  • Risoluzione delle risorse relative. Dompdf risolve <img src> rispetto alla tripletta base path/protocol/host. NextPDF risolve rispetto al working set del documento. Durante la migrazione, passare percorsi assoluti o data URI pre-risolti per eliminare la variabile.

writeHtml() esegue l’impaginazione in un’unica passata in streaming (ADR-001). Dopo l’impaginazione non viene trattenuto alcun oggetto frame-tree intermedio, quindi la memoria di picco segue le dimensioni del documento anziché il numero di nodi DOM. Il budget di prestazioni per l’esempio di questa guida è wall_ms: 2000, peak_mb: 128. Documenti grandi: suddividere l’HTML lungo i confini di addPage() anziché costruire un’unica stringa di più megabyte.

  • Nessun recupero remoto tramite stream context. NextPDF non implementa il percorso di recupero remoto setHttpContext() / enable_remote di Dompdf. Risolvere e validare gli asset remoti nella propria applicazione, quindi passare byte o data URI. Questo elimina la superficie SSRF introdotta da enable_remote.
  • Nessuna esecuzione di codice nel documento. L’assenza di un equivalente di enable_php è una scelta deliberata di hardening, non una lacuna.
  • I metadati di documento impostati tramite i setter tipizzati vengono scritti nel dizionario delle informazioni / XMP ISO 32000-2 §14 (iso32000_2_sec14#x1.x5.p5). Non inserirvi dati segreti.
AffermazioneSpecificaClausolareference_id
Il contenuto di pagina è painting su content stream nel modello opaque/transparent.ISO 32000-2§8
La dimensione della carta si mappa sul boundary box dell’oggetto pagina.ISO 32000-2§7
I font HTML vengono scritti come programmi di font embedded/subset.ISO 32000-2§9
L’elaborazione di white-space / line-breaking è specifica del motore.CSS Text 3§6.5

NextPDF produce contenuto ISO 32000-2. Non afferma che un documento Dompdf migrato sia visivamente identico. Un cambio di renderer richiede sempre una nuova revisione dell’output.

Non applicabile. Core copre il percorso di migrazione HTML-to-PDF descritto qui.


Team che usano dompdf/dompdf per la conversione HTML-to-PDF lato server e vogliono adottare il motore NextPDF. Se vengono chiamati solo loadHtml / setPaper / render / output, la mappatura dei verbi copre l’intera superficie utilizzata.

Rientrano nell’ambito: i verbi della facade Dompdf, le chiavi Options, le aspettative di parità delle funzionalità CSS, la risoluzione delle risorse, i metadati. Sono fuori ambito: gli oggetti interni di Dompdf FrameTree/Canvas/Stylesheet (NextPDF non ha analoghi pubblici — non migrare il codice che vi accede; sostituirlo con l’API pubblica).

La copertura riguarda la compatibilità comportamentale, non uno shim drop-in. NextPDF non ha alcuno shim per la classe Dompdf (a differenza del percorso TCPDF — vedere /migration/tcpdf-compat/). Si riscrive ogni call site usando la mappatura dei verbi. Le righe Verified della matrice di supporto CSS determinano interamente le aspettative relative alle funzionalità CSS. Questa guida non ripete lo stato per singola proprietà.

Opzione Dompdf (chiave / setter)NextPDFNote
default_paper_size / setDefaultPaperSize() ; setPaper($size,...)Config->pageSize (PageSize VO)Le dimensioni con nome diventano dimensioni esplicite in punti; new PageSize(595.276, 841.890, 'A4') è il valore predefinito di createStandalone().
default_paper_orientation / setDefaultPaperOrientation()scambiare PageSize width/heightNextPDF non ha un flag di orientamento; una pagina in orizzontale è un PageSize con width > height.
dpi / setDpi()(non è un’impostazione globale)NextPDF lavora in punti PDF (1/72 di pollice); il dimensionamento delle immagini è per singola immagine, non un moltiplicatore DPI di documento. Ricalcolare in punti le dimensioni fisse in pixel.
enable_remote / setIsRemoteEnabled()(nessun equivalente — per scelta progettuale)Risolvere gli asset remoti nel proprio codice; vedere Note di sicurezza.
enable_html5_parser / setIsHtml5ParserEnabled()(esegue sempre il parsing dell’HTML)Nessun interruttore; il parser è la pipeline.
enable_php / setIsPhpEnabled()(nessun equivalente — per scelta progettuale)Il PHP nel documento non è supportato; spostare la logica fuori dal template.
font_dir / setFontDir()Config->fontsDirectorySingola stringa di directory dei font.
chroot(risolvere nell’app)NextPDF non accetta un’opzione di jail del filesystem; validare il percorso prima di passare i byte.
default_font / setDefaultFont()CSS font-family / font registratoImpostare il valore predefinito tramite il foglio di stile di base o la registrazione del font, non un’opzione globale.
enable_font_subsetting / setIsFontSubsettingEnabled()(esegue sempre il subsetting)NextPDF esegue sempre il subsetting dei font incorporati (ISO 32000-2 §9, iso32000_2_sec9#x1.x45.p7); non esiste un «off» — un percorso Dompdf con il flag disattivato non ha equivalente e non è necessario.
  • Motore di layout. Dompdf e NextPDF sono implementazioni di layout CSS indipendenti. Il collassamento del white-space e il line breaking sono specificati ma sensibili al motore (CSS Text 3 §6.5, css_text_3#x1.x6.x5.p20). Aspettarsi differenze di a capo e di paginazione su testo denso. Ridefinire la baseline dei diff visivi dopo la migrazione.
  • Punto di render. Nessun confine in due fasi render()/output() (vedere Casi limite).
  • Risoluzione delle risorse. Base-path/protocol/host rispetto al working set del documento.
  • Modello DPI. Punti rispetto al moltiplicatore DPI di Dompdf.
  • Metadati. Coppie free-form addInfo() rispetto ai setter tipizzati (ISO 32000-2 §14, iso32000_2_sec14#x1.x5.p5).

Queste sono differenze di comportamento documentate, non difetti di uno dei due motori.

  • enable_php (PHP nel documento) — assente intenzionalmente.
  • setHttpContext() / enable_remote per il recupero remoto — assente intenzionalmente.
  • Accesso pubblico a FrameTree / Canvas / Stylesheet — nessun analogo pubblico.
  • dpi come moltiplicatore globale di documento — non modellato.

Il codice che dipende da questi non «migra». Lo si rimuove o lo si riesprime nel codice applicativo secondo le righe precedenti.

  1. Aggiungere nextpdf/core accanto a dompdf/dompdf (non rimuovere ancora Dompdf).
  2. Scegliere un documento a basso rischio. Riscrivere il suo call site con la mappatura dei verbi; eliminare la chiamata render().
  3. Generare entrambi i PDF per lo stesso input e confrontarli visivamente. Considerare previste le differenze (motori indipendenti) e stabilire l’accettazione per ogni documento.
  4. Convertire l’uso delle opzioni tramite la mappa delle opzioni; ricalcolare in punti le dimensioni derivate dai DPI.
  5. Pre-risolvere gli asset remoti/relativi in percorsi assoluti o data URI per eliminare la variabile di risoluzione.
  6. Ripetere per ogni documento, dal rischio più basso al più alto. Mantenere entrambi i motori installati finché l’ultimo call site non è migrato.
  7. Rimuovere dompdf/dompdf da composer.json solo dopo l’ultimo passaggio.
  • Acquisire uno snapshot dell’output Dompdf di documenti rappresentativi prima di modificare il codice (golden input, non golden byte — i byte differiranno).
  • Per ogni documento migrato, sottoporre l’output di NextPDF al proprio controllo di accettazione (diff visivo, asserzioni di estrazione del testo). Il comportamento della pipeline HTML di NextPDF è coperto da examples/08-html-basic.php e dalla suite Html core tests/. L’accettazione della migrazione è specifica del documento ed è responsabilità dell’utente asserirla.
  • Aggiungere un test di regressione per ogni documento migrato in modo da rilevare un futuro aggiornamento del motore.

Ogni affermazione di comportamento di NextPDF in questa pagina è supportata da un test, un esempio, una firma del sorgente o un ADR presenti nel repo — oppure, quando si tratta di una proprietà del formato PDF, dalle clausole ISO 32000-2 / CSS fissate via RAG nel citations: del front matter e dalla tabella Conformità. Il comportamento di Dompdf è asserito solo come «motore indipendente — aspettarsi differenze documentate». Non viene rivendicata alcuna parità che un artefatto presente nel repo non dimostri.

Affermazione di comportamento di NextPDFEvidenza nel repo (percorso)
createStandalone() ha come pagina predefinita A4 verticale (595.276 × 841.890 pt).src/Core/Config.php (valore predefinito PageSize(595.276, 841.890, 'A4')); tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php (createStandaloneWithNullConfigBuildsDocumentWithA4Defaults).
writeHtml() esegue l’impaginazione in un’unica passata in streaming; nessun DOM trattenuto dopo l’impaginazione.docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md; src/Core/Concerns/HasTextOutput.php (writeHtml()).
writeHtml() crea automaticamente la prima pagina quando non ne esiste alcuna.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (writeHtmlAutoCreatesFirstPageWhenNoPagesExist).
output() / save() / getPdfData() sono i verbi di emissione (nessun processo in due fasi render/output).src/Core/Concerns/HasOutput.php (output(), save(), getPdfData()); tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
La destinazione di output è l’enum NextPDF\Contracts\OutputDestination (Inline/Download/File/String).src/Contracts/OutputDestination.php; tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
I font HTML vengono sempre scritti come programmi embedded/subset.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (recordUsedCharactersAffectsFontSubsetting); ISO 32000-2 §9 (front matter citations:).
I setter di metadati tipizzati (setTitle/setAuthor) sostituiscono il free-form addInfo().src/Core/Concerns/HasMetadata.php (setTitle(), setAuthor()); tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php.
Pipeline HTML end-to-end (l’esempio eseguibile di questa guida).examples/08-html-basic.php; suite tests/Unit/Html/ core.
Il white-space / line-breaking è specifico del motore (delta di layout).CSS Text 3 §6.5 (front matter citations: + Conformità).

Poiché entrambi i pacchetti restano installati fino al passaggio finale, il rollback per un call site non convertito significa riportare quel singolo call site al percorso Dompdf. Dopo il passaggio finale, il rollback significa ripristinare dompdf/dompdf e il call site precedente dal controllo di versione. Non è coinvolta alcuna migrazione di dati — solo codice.

Vedere Prestazioni. Il modello a passata singola implica che la migrazione non introduce un costo di mantenimento in memoria del frame tree. La principale variazione di costo per documento è la ri-risoluzione anticipata degli asset (passo 5), che è possibile mettere in cache.

  • Lasciare render() al suo posto (fatal undefined method).
  • Passare byte non UTF-8 dopo aver eliminato $encoding (mojibake silenzioso).
  • Aspettarsi un output identico byte per byte o pixel per pixel (motori indipendenti — questa guida non rivendica mai un drop-in o una compatibilità al 100%).
  • Affidarsi a template enable_php (devono essere rimossi tramite refactoring).
  • Trattare la matrice di supporto CSS come puramente indicativa — è l’autorità sulle funzionalità Verified per ciò che ci si deve aspettare.