Paginer un long contenu HTML sur plusieurs pages
Répartis un long contenu sur plusieurs pages, avec des sauts de page automatiques. Ajoute un plan pour qu’un lecteur puisse passer directement d’une section à l’autre. Ce recipe reprend examples/12-bookmarks-and-toc.php.
Installation
Section intitulée « Installation »composer require nextpdf/core:^3Cette contrainte cible le package nextpdf/core. L’exemple s’exécute avec PHP 8.4.
Vue d’ensemble conceptuelle
Section intitulée « Vue d’ensemble conceptuelle »setAutoPageBreak(true, $margin) indique au moteur de commencer une nouvelle page dès que le contenu dépasserait le seuil de la marge inférieure. Le moteur fragmente à ce seuil le texte long produit avec multiCell() ou writeHtml(). Le module CSS Fragmentation (css_break_3) est noté Verified dans la matrice de prise en charge et sert de socle au comportement de saut pour le pipeline HTML.
bookmark($title, $level) ajoute un élément de plan qui pointe vers la position courante. Un élément de plan PDF associe une destination, ce qui permet à l’utilisateur d’atteindre directement une page (ISO 32000-2). Le moteur écrit cette destination dans l’entrée Dest de l’élément (ISO 32000-2). L’argument level détermine l’imbrication des éléments dans une table des matières hiérarchique, dans la barre latérale du lecteur.
Le pipeline reste en passe unique (ADR-001). La pagination est décidée au fil de l’émission du flux, et non par un arbre de mise en page gardé en mémoire.
Surface de l’API
Section intitulée « Surface de l’API »setAutoPageBreak(bool $enabled, float $margin = 20): static—NextPDF\Core\Concerns\HasPages.bookmark(string $title, int $level = 0, float $y = -1): static—NextPDF\Core\Concerns\HasNavigation.multiCell(...)/writeHtml(string $html): static—NextPDF\Core\Concerns\HasTextOutput.
Le tableau PHPDoc complet est généré à partir du code source.
Exemple de code — Démarrage rapide
Section intitulée « Exemple de code — Démarrage rapide »<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setAutoPageBreak(true, margin: 25);$doc->addPage();$doc->bookmark('Section 1', level: 0);$doc->setFont('helvetica', '', 11);
for ($i = 1; $i <= 80; $i++) { $doc->multiCell(0, 7, "Paragraph {$i} of a long flowing document.");}
$doc->save(__DIR__ . '/out.pdf');Exemple de code — Production
Section intitulée « Exemple de code — Production »Cet exemple est autonome et exécutable par le harnais. Il construit un document à plusieurs chapitres avec un plan imbriqué et des sauts de page automatiques, puis reprend examples/12-bookmarks-and-toc.php.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Bookmarks and Navigation');$doc->setPrintHeader(false);$doc->setPrintFooter(false);$doc->setAutoPageBreak(true, margin: 25);
$chapters = [ 'Chapter 1: Introduction' => ['What is NextPDF?', 'Key Features'], 'Chapter 2: Getting Started' => ['Installation', 'Your First PDF'], 'Chapter 3: Advanced Topics' => ['Worker-safe Architecture', 'Streaming Output'],];
$body = 'NextPDF is a modern PDF 2.0 library for PHP. This paragraph is ' . 'repeated so the content overflows the page and the engine inserts ' . 'an automatic page break at the bottom-margin threshold.';
foreach ($chapters as $chapter => $sections) { $doc->addPage(); $doc->bookmark($chapter, level: 0); $doc->setFont('helvetica', 'B', 18); $doc->cell(0, 12, $chapter, newLine: true); $doc->ln(3);
foreach ($sections as $section) { $doc->bookmark($section, level: 1); $doc->setFont('helvetica', 'B', 14); $doc->cell(0, 10, $section, newLine: true); $doc->setFont('helvetica', '', 11); for ($i = 0; $i < 12; $i++) { $doc->multiCell(0, 7, $body); } $doc->ln(4); }}
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/paginate-long-html.pdf');
echo "Wrote paginate-long-html.pdf\n";Sortie standard attendue :
Wrote paginate-long-html.pdfCas limites et pièges
Section intitulée « Cas limites et pièges »- Désactiver puis oublier de réactiver. Quand le saut de page automatique est désactivé, le moteur rogne le contenu qui dépasse la marge inférieure au lieu de le répartir. Réactive-le avant d’émettre un long contenu.
- Contenu insécable. Un bloc unique plus haut que la hauteur utile de la page peut lever
UnsplittableContentException. Une ligne de tableau très haute ou une grande image peut en être la cause. Découpe le contenu source. - Place le signet avant le contenu. Appelle
bookmark()à la position vers laquelle tu veux que la destination pointe. Place-le juste avant le titre que tu écris ensuite, sur la page voulue. - L’en-tête et le pied de page réservent de l’espace. Un en-tête ou un pied de page d’impression réduit la hauteur utile du contenu, et le seuil de saut en tient compte. En désactivant les deux, comme dans l’exemple, tu disposes de toute la hauteur du corps.
- Imbrication du plan.
levelest la profondeur d’imbrication. Un enfant aulevel: 1doit suivre un parent aulevel: 0. Sinon, le lecteur aplatit l’arbre du plan.
Performances
Section intitulée « Performances »Le moteur décide de la pagination pendant l’unique passe d’émission. Le coût est linéaire en fonction de la longueur du contenu, O(n). Le budget est wall_ms: 2000, peak_mb: 96. Le temps mural est légèrement plus élevé que pour les recipes à page unique, à cause de l’assemblage de la table xref multipage et du plan. Le modèle de streaming maintient une mémoire bornée, et le plan reste une petite liste plate.
Extrait de la matrice de prise en charge CSS (lignes Verified uniquement)
Section intitulée « Extrait de la matrice de prise en charge CSS (lignes Verified uniquement) »Seules les lignes Verified de la matrice de prise en charge CSS, dont l’exactitude a été auditée, sont reproduites.
| Module W3C | Niveau | Statut | Preuve |
|---|---|---|---|
CSS Fragmentation (css_break_3) | 3 | Verified | src/Html/Fragmentation/, tests/Unit/Html/PagedMedia/ |
CSS Table (css_tables_3) | 3 | Verified | src/Html/Table/ + PDF de référence |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verified | src/Html/Cascade/ |
@page désigne des sélecteurs de pages nommées qui font partie de CSS Paged Media. Consulte la matrice pour connaître le niveau actuel de ce module avant de t’y fier.
Contraintes du streaming en passe unique (ADR-001)
Section intitulée « Contraintes du streaming en passe unique (ADR-001) »Le moteur émet les sauts de page au fil du flux. Il n’existe aucun arbre conservé en mémoire pour redistribuer le contenu : une décision de saut est donc définitive une fois prise. Certains contenus ont besoin de leur numéro de page final après la mise en page, par exemple une référence croisée. Ce type de contenu est contraint ; rédige-le donc en gardant cette limitation à l’esprit.
Contrats de couche (ADR-010)
Section intitulée « Contrats de couche (ADR-010) »La pagination appartient au contrôleur de saut de page, pas à l’analyseur. L’analyseur n’émet pas d’opérateurs de transition de page bruts ; il demande un saut via le contrat du contrôleur.
Budget mémoire pour les documents volumineux
Section intitulée « Budget mémoire pour les documents volumineux »Le modèle de streaming conserve le tampon de la page courante et la liste plate du plan, mais pas toutes les pages à la fois. Un document très long reste dans la limite de l’ADR-020 parce que le moteur vide les pages terminées. Les tableaux et les conteneurs flex respectent toujours la limite de 5,000 nœuds par contexte.
Notes de sécurité
Section intitulée « Notes de sécurité »Un document hostile ne peut pas forcer une consommation mémoire illimitée. Les limites d’éléments et d’imbrication (ADR-001), ainsi que le budget de nœuds par contexte (ADR-020), bornent le travail. Valide la longueur et la structure d’un long contenu fourni par l’utilisateur. Le moteur rend comme du texte un titre de plan contrôlé par un attaquant, sans jamais l’interpréter.
Conformité
Section intitulée « Conformité »| Énoncé | Spécification | Clause | reference_id |
|---|---|---|---|
| Chaque élément de plan peut être associé à une destination afin que l’utilisateur l’atteigne directement. | ISO 32000-2 | iso32000_2_sec12#x1.x5.p4 | |
| L’entrée Dest d’un élément de plan nomme la destination affichée quand l’élément est activé. | ISO 32000-2 | iso32000_2_sec12#x1.x11.p30 |
Ce recipe montre comment NextPDF répartit un long contenu et construit un plan. CSS Fragmentation est noté Verified dans la matrice de prise en charge.
Contexte commercial
Section intitulée « Contexte commercial »Sans objet.