Impaginare contenuti HTML lunghi su più pagine
In breve
Sezione intitolata “In breve”Distribuire contenuti lunghi su più pagine tramite interruzioni di pagina automatiche. Aggiungere una struttura per consentire al lettore di spostarsi tra le sezioni. Questa ricetta segue examples/12-bookmarks-and-toc.php.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/core:^3Il vincolo fa riferimento al pacchetto nextpdf/core. L’esempio è eseguibile con PHP 8.4.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”setAutoPageBreak(true, $margin) indica al motore di iniziare una nuova pagina ogni volta che il contenuto supererebbe la soglia del margine inferiore. Il motore frammenta il testo lungo scritto tramite multiCell() o writeHtml() in corrispondenza di quel limite. Il modulo CSS Fragmentation (css_break_3) è classificato come Verificato nella matrice di supporto e gestisce il comportamento di interruzione per la pipeline HTML.
bookmark($title, $level) aggiunge un elemento della struttura che punta alla posizione corrente. Un elemento della struttura PDF associa una destinazione, così l’utente può passare direttamente a una pagina (ISO 32000-2). Il motore scrive quella destinazione come voce Dest dell’elemento (ISO 32000-2). L’argomento level annida gli elementi in un sommario gerarchico nella barra laterale del lettore.
La pipeline rimane a passaggio singolo (ADR-001). L’impaginazione viene decisa durante l’emissione del flusso, non da un albero di layout mantenuto in memoria.
Superficie API
Sezione intitolata “Superficie 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.
La tabella PHPDoc completa è generata dal codice sorgente.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?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');Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Questo esempio è autonomo ed eseguibile tramite l’harness. Crea un documento con più capitoli, una struttura annidata e interruzioni di pagina automatiche, e ricalca 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";STDOUT previsto:
Wrote paginate-long-html.pdfCasi limite e insidie
Sezione intitolata “Casi limite e insidie”- Disabilitarla e dimenticarsene. Quando l’interruzione di pagina automatica è disabilitata, il motore ritaglia il contenuto oltre il margine inferiore anziché distribuirlo. Riabilitarla prima di un contenuto lungo.
- Contenuto non suddivisibile. Un singolo blocco più alto dell’altezza utile della pagina può generare
UnsplittableContentException. Una riga di tabella molto alta o un’immagine di grandi dimensioni possono causarla. Suddividere il contenuto di origine. - Inserire il segnalibro prima del contenuto. Chiamare
bookmark()nel punto verso cui si desidera far puntare la destinazione. Posizionarlo immediatamente prima del titolo che verrà scritto subito dopo, nella pagina desiderata. - Intestazione e piè di pagina riservano spazio. Un’intestazione o un piè di pagina di stampa riduce l’altezza utile del contenuto, e la soglia di interruzione ne tiene conto. Disabilitandoli entrambi, come fa l’esempio, si ottiene l’altezza completa del corpo.
- Annidamento della struttura.
levelè la profondità di annidamento. Un elemento figlio alevel: 1deve seguire un elemento padre alevel: 0. In caso contrario, il lettore appiattisce l’albero della struttura.
Prestazioni
Sezione intitolata “Prestazioni”Il motore decide l’impaginazione durante un unico passaggio di emissione. Il costo è lineare rispetto alla lunghezza del contenuto, O(n). Il budget è wall_ms: 2000, peak_mb: 96. Il tempo effettivo risulta leggermente superiore rispetto alle ricette a pagina singola a causa dell’assemblaggio della tabella xref multipagina e della struttura. Il modello di streaming mantiene limitato l’uso della memoria e la struttura resta un piccolo elenco piatto.
Estratto della matrice di supporto CSS (solo righe Verificato)
Sezione intitolata “Estratto della matrice di supporto CSS (solo righe Verificato)”Sono riportate solo le righe Verificato della matrice di supporto CSS sottoposta a verifica.
| Modulo W3C | Livello | Stato | Evidenza |
|---|---|---|---|
CSS Fragmentation (css_break_3) | 3 | Verificato | src/Html/Fragmentation/, tests/Unit/Html/PagedMedia/ |
CSS Table (css_tables_3) | 3 | Verificato | src/Html/Table/ + PDF golden |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verificato | src/Html/Cascade/ |
@page definisce i selettori di pagina denominata e fa parte di CSS Paged Media. Consultare la matrice per conoscere la classificazione corrente di tale modulo prima di farvi affidamento.
Vincoli dello streaming a passaggio singolo (ADR-001)
Sezione intitolata “Vincoli dello streaming a passaggio singolo (ADR-001)”Il motore emette le interruzioni di pagina man mano che il flusso procede. Non esiste alcun albero mantenuto in memoria da ridistribuire, quindi una decisione di interruzione è definitiva una volta presa. Alcuni contenuti richiedono il numero di pagina definitivo dopo il layout, ad esempio un riferimento incrociato. Tale contenuto è soggetto a vincoli, pertanto va creato tenendo presente questa limitazione.
Contratti di livello (ADR-010)
Sezione intitolata “Contratti di livello (ADR-010)”L’impaginazione è di competenza del controller delle interruzioni di pagina, non del parser. Il parser non emette operatori grezzi di transizione di pagina; richiede l’interruzione tramite il contratto del controller.
Budget di memoria per documenti di grandi dimensioni
Sezione intitolata “Budget di memoria per documenti di grandi dimensioni”Il modello di streaming mantiene il buffer della pagina corrente e l’elenco piatto della struttura, non tutte le pagine contemporaneamente. Un documento molto lungo rimane entro il limite massimo dell’ADR-020 perché il motore scarica le pagine completate. Le tabelle e i contenitori flex rispettano comunque il limite di 5,000 nodi per contesto.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Un documento ostile non può forzare un utilizzo illimitato della memoria. I limiti sugli elementi e sull’annidamento (ADR-001) e il budget di nodi per contesto (ADR-020) delimitano il lavoro. Convalidare la lunghezza e la struttura del contenuto lungo fornito dall’utente. Il motore rende come testo un titolo della struttura controllato da un utente malintenzionato e non lo interpreta mai.
Conformità
Sezione intitolata “Conformità”| Dichiarazione | Specifica | Clausola | reference_id |
|---|---|---|---|
| A ogni elemento della struttura può essere associata una destinazione, così l’utente può passarvi direttamente. | ISO 32000-2 | iso32000_2_sec12#x1.x5.p4 | |
| La voce Dest di un elemento della struttura indica la destinazione visualizzata all’attivazione dell’elemento. | ISO 32000-2 | iso32000_2_sec12#x1.x11.p30 |
Questa ricetta mostra come NextPDF distribuisce contenuti lunghi e crea una struttura. CSS Fragmentation è classificato come Verificato nella matrice di supporto.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Non applicabile.