Aller au contenu

Migrer de Dompdf vers NextPDF

Ce guide t’accompagne dans la migration d’une base de code reposant sur Dompdf vers le pipeline Html de NextPDF. Dompdf et NextPDF suivent le même schéma — charger du HTML, restituer, émettre un PDF — donc la plupart des sites d’appel se transposent mécaniquement. Le vrai travail consiste à établir la table de correspondance des options et à gérer les écarts de prise en charge CSS. NextPDF et Dompdf sont des moteurs indépendants : une mise en page produite par Dompdf est donc compatible avec le résultat de NextPDF, sans lui être identique à l’octet près. Ce guide couvre la correspondance des verbes, la correspondance des clés d’options, les différences de comportement et une séquence de migration sûre.

La prise en charge d’une fonctionnalité HTML/CSS par NextPDF ne garantit pas qu’un document Dompdf donné soit reproduit au pixel près. La matrice de prise en charge CSS fait autorité sur les fonctionnalités marquées Verified. Ce guide décrit le comportement ; il n’affirme aucune équivalence visuelle.

Fenêtre de terminal
composer require nextpdf/core:^3

Garde dompdf/dompdf installé pendant la transition (la séquence de migration sûre fait cohabiter les deux jusqu’à ce que chaque site d’appel soit basculé), puis supprime-le une fois la bascule terminée.

L’objet Dompdf fourni par Dompdf est une façade unique qui possède le DOM, la feuille de style, l’arbre de frames et le canevas. NextPDF sépare ces responsabilités : un NextPDF\Core\Document possède le modèle de page et la sortie, et une seule méthode, writeHtml(), pilote le pipeline HTML. Il n’y a pas d’étape séparée en deux phases « restituer puis émettre ». writeHtml() met le contenu en page au fur et à mesure qu’il l’écrit, et tu émets le document avec save(), output() ou getPdfData().

Le contenu de page que NextPDF écrit est du dessin de flux de contenu ISO 32000-2 (ISO 32000-2 §8, iso32000_2_sec8#x1.x3.p14). La géométrie de page que contrôle l’option de taille de papier correspond au MediaBox de l’objet page (ISO 32000-2 §7, iso32000_2_sec7#x1.x104.p10). Ce sont des fondamentaux du moteur, partagés par tout générateur conforme. Mais l’algorithme de mise en page qui transforme le CSS en ce contenu est propre à NextPDF, et il diffère de celui de Dompdf (voir Différences de comportement).

L’API Html de NextPDF est documentée dans la référence du module Html (générée automatiquement à partir du PHPDoc). Les principaux points d’entrée utilisés ci-dessous sont : Document::createStandalone(), Document::writeHtml(string $html): static, Document::writeHtmlCell(...), Document::output(?string, OutputDestination), Document::save(string $path): void, Document::getPdfData(): string, et l’objet valeur NextPDF\Core\Config (pageSize, margins, fontsDirectory).

Les noms de l’API publique de Dompdf ci-dessous sont vérifiés dans le dépôt public amont (dompdf/dompdf, master) — voir le fichier source _source-sidecar-upstream-api.md dans le dépôt. Aucun texte de documentation amont n’est reproduit.

DompdfNextPDFNotes
new Dompdf($options)Document::createStandalone($config)Dompdf prend un objet Options ; NextPDF prend un NextPDF\Core\Config. Pour les workers de longue durée, utilise DocumentFactory plutôt que createStandalone().
$dompdf->loadHtml($html, $encoding)$doc->writeHtml($html)NextPDF traite l’entrée comme de l’UTF-8 ; transcode l’entrée non-UTF-8 avant l’appel plutôt que de passer un argument d’encodage.
$dompdf->loadHtmlFile($file)$doc->writeHtml(file_get_contents($file))NextPDF n’a pas de variante de chargement de fichier ; lis toi-même le fichier pour que la politique d’E/S reste dans ton code.
$dompdf->setPaper($size, $orientation)ConfigpageSize (un objet valeur PageSize)Voir la table de correspondance des options.
$dompdf->render()(implicite)NextPDF réalise la mise en page pendant writeHtml() ; il n’y a pas de phase de rendu séparée. Supprime l’appel à render().
$dompdf->output()$doc->getPdfData()Renvoie les octets du PDF.
$dompdf->stream($name, $opts)$doc->output($name, OutputDestination::Download)NextPDF sépare la destination via l’énumération OutputDestination.
$dompdf->setBasePath($p) / setProtocol() / setBaseHost()(la résolution des ressources diffère)NextPDF résout les ressources relatives par rapport à l’ensemble de travail du document, et non à un triplet base path/protocol — voir Différences de comportement.
$dompdf->addInfo($label, $value)$doc->setTitle() / setAuthor() / API de métadonnéesLes paires d’info libres de Dompdf correspondent aux setters de métadonnées typés (ISO 32000-2 §14 information du document, iso32000_2_sec14#x1.x5.p5).
$dompdf->setHttpContext($ctx)(pas d’équivalent)NextPDF ne récupère pas de ressources distantes via un contexte de flux ; voir Non pris en charge / pas d’équivalent direct.
<?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";

Cet exemple reflète examples/08-html-basic.php (le support exécutable de ce guide), avec une taille de papier explicite autre que celle par défaut et des marges. C’est l’équivalent d’un setPaper() de Dompdf plus une configuration de marges 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);
  • Pas de rendu en deux phases. Le code Dompdf qui inspecte l’état entre render() et output() (par exemple lire le nombre de pages) n’a pas d’analogue NextPDF à cet endroit précis du pipeline. Interroge plutôt le document après writeHtml().
  • Encodage. NextPDF abandonne le paramètre $encoding de Dompdf : convertis l’entrée en UTF-8 avant writeHtml(). Passer des octets Latin-1 produit du mojibake, pas une erreur.
  • render() laissé en place. Un appel résiduel de style $dompdf->render() n’a pas de méthode NextPDF correspondante et provoquera une erreur fatale « undefined method ». Supprime-le pendant la bascule, ne le remplace pas par un stub.
  • PHP en ligne. L’option enable_php de Dompdf évalue <script type="text/php">. NextPDF n’a aucune exécution de PHP dans le document, par conception (c’est une surface d’injection). Déplace cette logique dans ton PHP avant writeHtml().
  • Résolution des ressources relatives. Dompdf résout <img src> par rapport au triplet base path/protocol/host. NextPDF résout par rapport à l’ensemble de travail du document. Pendant la migration, passe des chemins absolus ou des URI de données pré-résolues pour éliminer la variable.

writeHtml() met en page en une seule passe en flux (ADR-001). Aucun objet intermédiaire d’arbre de frames n’est conservé après la mise en page, donc la mémoire de pointe dépend de la taille du document plutôt que du nombre de nœuds du DOM. Le budget de performance pour l’exemple de ce guide est wall_ms: 2000, peak_mb: 128. Documents volumineux : découpe le HTML aux frontières des addPage() plutôt que de construire une seule chaîne de plusieurs mégaoctets.

  • Pas de récupération distante par contexte de flux. NextPDF n’implémente pas le parcours de récupération distante setHttpContext() / enable_remote de Dompdf. Résous et valide les ressources distantes dans ton application, puis passe des octets ou des URI de données. Cela supprime la surface SSRF que enable_remote comporte.
  • Pas d’exécution de code dans le document. L’absence d’un équivalent à enable_php est un durcissement délibéré, pas une lacune.
  • Les métadonnées de document que tu définis via les setters typés sont écrites dans le dictionnaire d’information ISO 32000-2 §14 / XMP (iso32000_2_sec14#x1.x5.p5). N’y place pas de secrets.
DéclarationSpécificationClausereference_id
Le contenu de page est du dessin de flux de contenu dans le modèle opaque/transparent.ISO 32000-2§8
La taille de papier correspond à la boîte de délimitation de l’objet page.ISO 32000-2§7
Les polices HTML sont écrites comme des programmes de police embedded/subset.ISO 32000-2§9
Le traitement des espaces blancs et des retours à la ligne est propre au moteur.CSS Text 3§6.5

NextPDF produit du contenu ISO 32000-2. Il n’affirme pas qu’un document Dompdf migré soit visuellement identique. Un changement de moteur de rendu exige toujours une nouvelle revue de la sortie.

Non applicable. Le cœur couvre le parcours de migration HTML-vers-PDF décrit ici.


Les équipes qui utilisent dompdf/dompdf pour du HTML-vers-PDF côté serveur et qui souhaitent passer au moteur NextPDF. Si tu n’appelles que loadHtml / setPaper / render / output, la correspondance des verbes couvre toute ta surface d’appel.

Dans le périmètre : les verbes de la façade Dompdf, les clés Options, les attentes de parité des fonctionnalités CSS, la résolution des ressources, les métadonnées. Hors périmètre : les objets internes FrameTree/Canvas/Stylesheet de Dompdf (NextPDF n’a pas d’analogues publics — ne migre pas le code qui les manipule ; remplace-le par l’API publique).

La couverture relève d’une behavioral compatibility, pas d’un shim drop-in. NextPDF n’a pas de shim de classe Dompdf (contrairement au parcours TCPDF — voir /migration/tcpdf-compat/). Tu réécris chaque site d’appel à l’aide de la correspondance des verbes. Les lignes Verified de la matrice de prise en charge CSS définissent à elles seules ce que tu peux attendre des fonctionnalités CSS. Ce guide ne reprend pas le statut par propriété.

Table de correspondance des options et de la configuration

Section intitulée « Table de correspondance des options et de la configuration »
Option Dompdf (clé / setter)NextPDFNotes
default_paper_size / setDefaultPaperSize() ; setPaper($size,...)Config->pageSize (objet valeur PageSize)Les tailles nommées deviennent des dimensions en points explicites ; new PageSize(595.276, 841.890, 'A4') est la valeur par défaut de createStandalone().
default_paper_orientation / setDefaultPaperOrientation()intervertir la PageSize width/heightNextPDF n’a pas d’indicateur d’orientation ; une page paysage est une PageSize dont la largeur > la hauteur.
dpi / setDpi()(ce n’est pas un réglage global)NextPDF travaille en points PDF (1/72 de pouce) ; le dimensionnement des images se fait par image, pas via un multiplicateur DPI au niveau du document. Recalcule les tailles en pixels fixes en points.
enable_remote / setIsRemoteEnabled()(pas d’équivalent — par conception)Résous les ressources distantes dans ton code ; voir Notes de sécurité.
enable_html5_parser / setIsHtml5ParserEnabled()(analyse toujours le HTML)Pas de bascule ; l’analyseur est le pipeline.
enable_php / setIsPhpEnabled()(pas d’équivalent — par conception)Le PHP dans le document n’est pas pris en charge ; sors la logique du template.
font_dir / setFontDir()Config->fontsDirectoryUne unique chaîne indiquant le répertoire de polices.
chroot(à résoudre dans l’application)NextPDF ne prend pas d’option de cloisonnement du système de fichiers ; effectue la validation des chemins avant de passer les octets.
default_font / setDefaultFont()CSS font-family / police enregistréeDéfinis la valeur par défaut via ta feuille de style de base ou l’enregistrement des polices, pas via une option globale.
enable_font_subsetting / setIsFontSubsettingEnabled()(sous-ensemble toujours)NextPDF crée toujours un sous-ensemble des polices intégrées (ISO 32000-2 §9, iso32000_2_sec9#x1.x45.p7) ; il n’y a pas de « off » — un parcours Dompdf avec l’indicateur désactivé n’a pas d’équivalent et n’est pas nécessaire.
  • Moteur de mise en page. Dompdf et NextPDF sont des implémentations de mise en page CSS indépendantes. L’effondrement des espaces blancs et les retours à la ligne sont spécifiés mais sensibles au moteur (CSS Text 3 §6.5, css_text_3#x1.x6.x5.p20). Attends-toi à des différences de retour à la ligne et de pagination sur du texte dense. Recrée la référence des diffs visuels après la migration.
  • Jointure de rendu. Pas de frontière en deux phases render()/output() (voir Cas limites).
  • Résolution des ressources. Base path/protocole/host contre ensemble de travail du document.
  • Modèle DPI. Points contre multiplicateur DPI de Dompdf.
  • Métadonnées. Paires addInfo() libres contre setters typés (ISO 32000-2 §14, iso32000_2_sec14#x1.x5.p5).

Ce sont des différences de comportement documentées, pas des défauts dans l’un ou l’autre moteur.

  • enable_php (PHP dans le document) — intentionnellement absent.
  • setHttpContext() / enable_remote récupération distante — intentionnellement absente.
  • Accès public à FrameTree / Canvas / Stylesheet — pas d’analogue public.
  • dpi comme multiplicateur global du document — non modélisé.

Le code qui dépend de ces éléments ne « migre » pas. Tu le supprimes ou le réexprimes dans le code de l’application selon les lignes ci-dessus.

  1. Ajoute nextpdf/core à côté de dompdf/dompdf (ne supprime pas encore Dompdf).
  2. Choisis un document à faible risque. Réécris son site d’appel avec la correspondance des verbes ; supprime l’appel à render().
  3. Génère les deux PDF pour la même entrée et compare-les visuellement. Traite les différences comme attendues (moteurs indépendants) et décide de l’acceptation document par document.
  4. Convertis l’usage des options via la table de correspondance des options ; recalcule en points les tailles dérivées du DPI.
  5. Pré-résous les ressources distantes/relatives en chemins absolus ou en URI de données pour éliminer la variable de résolution.
  6. Répète document par document, du risque le plus faible au plus élevé. Garde les deux moteurs installés jusqu’à ce que le dernier site d’appel soit basculé.
  7. Supprime dompdf/dompdf de composer.json seulement après la dernière bascule.
  • Prends un instantané de la sortie Dompdf de documents représentatifs avant de changer le code (entrées de référence, pas des octets de référence — les octets différeront).
  • Pour chaque document migré, soumets la sortie NextPDF à ta propre vérification d’acceptation (diff visuel, assertions d’extraction de texte). Le comportement du pipeline HTML propre à NextPDF est couvert par examples/08-html-basic.php et la suite Html du cœur tests/. L’acceptation de ta migration est spécifique au document et c’est à toi de la valider.
  • Ajoute un test de régression par document migré pour qu’une future mise à jour du moteur soit détectée.

Chaque déclaration de comportement NextPDF sur cette page est étayée par un test, un exemple, une signature source ou un ADR dans le dépôt — ou, lorsqu’il s’agit d’une propriété de format PDF, par les clauses ISO 32000-2 / CSS épinglées par RAG dans le citations: du frontmatter et la table de Conformité. Le comportement de dompdf est affirmé uniquement comme « moteur indépendant — attends-toi à des différences documentées ». Aucune parité n’est revendiquée sans preuve fournie par un artefact du dépôt.

Déclaration de comportement NextPDFPreuve dans le dépôt (chemin)
createStandalone() : page par défaut A4 portrait (595.276 × 841.890 pt).src/Core/Config.php (PageSize(595.276, 841.890, 'A4') par défaut) ; tests/Unit/Core/DocumentCreateStandaloneAndConfigWithersEdgeCaseTest.php (createStandaloneWithNullConfigBuildsDocumentWithA4Defaults).
writeHtml() met en page en une seule passe en flux ; aucun DOM conservé après la mise en page.docs/architecture/adr/ADR-001-stream-based-rendering-pipeline.md ; src/Core/Concerns/HasTextOutput.php (writeHtml()).
writeHtml() crée automatiquement la première page quand il n’en existe aucune.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (writeHtmlAutoCreatesFirstPageWhenNoPagesExist).
output() / save() / getPdfData() sont les verbes d’émission (pas de deux phases render/output).src/Core/Concerns/HasOutput.php (output(), save(), getPdfData()) ; tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
La destination de sortie est l’énumération NextPDF\Contracts\OutputDestination (Inline/Download/File/String).src/Contracts/OutputDestination.php ; tests/Unit/Core/Concerns/DocumentOutputDestinationDispatchTest.php.
Les polices HTML sont toujours écrites comme des programmes embedded/subset.tests/Unit/Core/Concerns/DocumentTextOutputFontSubsettingAndBorderEdgeCaseTest.php (recordUsedCharactersAffectsFontSubsetting) ; ISO 32000-2 §9 (citations: du frontmatter).
Les setters de métadonnées typés (setTitle/setAuthor) remplacent addInfo() en forme libre.src/Core/Concerns/HasMetadata.php (setTitle(), setAuthor()) ; tests/Unit/Core/Concerns/DocumentInfoMetadataSetterBaselineTest.php.
Pipeline HTML de bout en bout (le support exécutable de ce guide).examples/08-html-basic.php ; suite tests/Unit/Html/ du cœur.
Les espaces blancs / retours à la ligne sont propres au moteur (écart de mise en page).CSS Text 3 §6.5 (citations: du frontmatter + Conformité).

Comme les deux packages restent installés jusqu’à la bascule finale, le retour arrière d’un site d’appel non converti consiste à revenir au parcours Dompdf pour ce seul site d’appel. Après la bascule finale, le retour arrière consiste à restaurer dompdf/dompdf et le site d’appel précédent depuis le contrôle de version. Aucune migration de données n’est impliquée — uniquement du code.

Voir Performance. Le modèle en une seule passe signifie que la migration n’introduit pas de coût de rétention de l’arbre de frames. Le principal changement de coût par document est la re-résolution anticipée des ressources (étape 5), que tu peux mettre en cache.

  • Laisser render() en place (erreur fatale undefined method).
  • Passer des octets non-UTF-8 après avoir abandonné $encoding (mojibake silencieux).
  • S’attendre à une sortie identique à l’octet près ou au pixel près (moteurs indépendants — ce guide ne revendique jamais un drop-in ni une compatibilité à 100 %).
  • Compter sur les templates enable_php (doit être refactorisé).
  • Traiter la matrice de prise en charge CSS comme indicative — elle fait autorité sur les fonctionnalités Verified et sur ce qu’il faut attendre.