Langes HTML über mehrere Seiten umbrechen
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Lassen Sie lange Inhalte mit automatischen Seitenumbrüchen über mehrere Seiten fließen. Fügen Sie eine Gliederung hinzu, damit Leser zwischen Abschnitten springen können. Dieses Recipe folgt examples/12-bookmarks-and-toc.php.
Installation
Abschnitt betitelt „Installation“composer require nextpdf/core:^3Die Versionsbedingung passt zum Paket nextpdf/core. Das Beispiel setzt PHP 8.4 voraus.
Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“setAutoPageBreak(true, $margin) weist die Engine an, eine neue Seite zu beginnen, sobald Inhalt die Schwelle des unteren Rands überschreitet. Die Engine trennt langen Text, der über multiCell() oder writeHtml() geschrieben wird, an dieser Grenze. Das CSS-Fragmentation-Modul (css_break_3) ist in der Support-Matrix als Verified eingestuft und bestimmt das Umbruchverhalten der HTML-Pipeline.
bookmark($title, $level) fügt einen Gliederungseintrag hinzu, der auf die aktuelle Position verweist. Ein PDF-Gliederungseintrag ist mit einem Ziel verknüpft, damit der Benutzer direkt zu einer Seite springen kann (ISO 32000-2). Die Engine schreibt dieses Ziel als Dest-Eintrag des Elements (ISO 32000-2). Das Argument level verschachtelt Einträge zu einem hierarchischen Inhaltsverzeichnis in der Seitenleiste des Readers.
Die Pipeline bleibt single-pass (ADR-001). Die Paginierung wird beim Ausgeben des Streams entschieden, nicht anhand eines vorgehaltenen Layout-Baums.
API-Oberfläche
Abschnitt betitelt „API-Oberfläche“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.
Die vollständige PHPDoc-Tabelle wird aus dem Quellcode generiert.
Codebeispiel — Schnellstart
Abschnitt betitelt „Codebeispiel — Schnellstart“<?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');Codebeispiel — Produktion
Abschnitt betitelt „Codebeispiel — Produktion“Dieses Beispiel ist eigenständig und lässt sich im Harness ausführen. Es erstellt ein Dokument mit mehreren Kapiteln, einer verschachtelten Gliederung und automatischen Seitenumbrüchen und spiegelt examples/12-bookmarks-and-toc.php wider.
<?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";Erwartete STDOUT-Ausgabe:
Wrote paginate-long-html.pdfGrenzfälle & Fallstricke
Abschnitt betitelt „Grenzfälle & Fallstricke“- Deaktivieren und dann vergessen. Wenn der automatische Seitenumbruch deaktiviert ist, schneidet die Engine Inhalte jenseits des unteren Rands ab, statt sie weiterfließen zu lassen. Aktivieren Sie ihn vor langen Inhalten wieder.
- Nicht umbrechbarer Inhalt. Ein einzelner Block, der höher als die nutzbare Seitenhöhe ist, kann
UnsplittableContentExceptionauslösen. Eine sehr hohe Tabellenzeile oder ein großes Bild kann die Ursache sein. Teilen Sie den Quellinhalt auf. - Lesezeichen vor dem Inhalt setzen. Rufen Sie
bookmark()an der Position auf, auf die das Ziel zeigen soll. Platzieren Sie es unmittelbar vor der Überschrift, die Sie als Nächstes schreiben, auf der gewünschten Seite. - Kopf- und Fußzeile reservieren Platz. Eine Druck-Kopfzeile oder -Fußzeile verringert die nutzbare Inhaltshöhe; die Umbruchschwelle berücksichtigt das. Wenn Sie beide deaktivieren — wie im Beispiel —, steht die volle Inhaltshöhe zur Verfügung.
- Verschachtelung der Gliederung.
levelist die Verschachtelungstiefe. Ein untergeordneter Eintrag mitlevel: 1muss auf einen übergeordneten Eintrag mitlevel: 0folgen. Andernfalls flacht der Reader den Gliederungsbaum ab.
Performance
Abschnitt betitelt „Performance“Die Engine entscheidet die Paginierung während des einzelnen Ausgabedurchlaufs. Der Aufwand wächst linear mit der Inhaltslänge, O(n). Das Budget ist wall_ms: 2000, peak_mb: 96. Die Wall-Zeit fällt etwas höher aus als bei einseitigen Recipes, weil die seitenübergreifende xref und die Gliederung aufgebaut werden. Das Streaming-Modell hält den Speicherbedarf begrenzt, und die Gliederung bleibt eine kleine, flache Liste.
Auszug aus der CSS-Support-Matrix (nur Verified-Zeilen)
Abschnitt betitelt „Auszug aus der CSS-Support-Matrix (nur Verified-Zeilen)“Reproduziert werden nur die Verified-Zeilen aus der inhaltlich geprüften CSS-Support-Matrix.
| W3C-Modul | Level | Status | Nachweis |
|---|---|---|---|
CSS Fragmentation (css_break_3) | 3 | Verified | src/Html/Fragmentation/, tests/Unit/Html/PagedMedia/ |
CSS Table (css_tables_3) | 3 | Verified | src/Html/Table/ + Golden-PDFs |
CSS Cascading and Inheritance (css_cascade_3) | 3 | Verified | src/Html/Cascade/ |
@page-Selektoren für benannte Seiten sind Teil von CSS Paged Media. Prüfen Sie in der Matrix den aktuellen Grad dieses Moduls, bevor Sie sich darauf verlassen.
Einschränkungen des Single-Pass-Streamings (ADR-001)
Abschnitt betitelt „Einschränkungen des Single-Pass-Streamings (ADR-001)“Die Engine gibt Seitenumbrüche aus, während der Stream fließt. Es gibt keinen vorgehaltenen Baum für einen erneuten Umbruch; daher ist eine Umbruchentscheidung endgültig, sobald sie getroffen wurde. Manche Inhalte benötigen ihre endgültige Seitenzahl erst nach dem Layout, zum Beispiel ein Querverweis. Solche Inhalte sind eingeschränkt; erstellen Sie sie daher mit dieser Einschränkung im Hinterkopf.
Schichtverträge (ADR-010)
Abschnitt betitelt „Schichtverträge (ADR-010)“Die Paginierung liegt beim Page-Break-Controller, nicht beim Parser. Der Parser gibt keine rohen Seitenübergangs-Operatoren aus; er fordert einen Umbruch über den Controller-Vertrag an.
Speicherbudget für große Dokumente
Abschnitt betitelt „Speicherbudget für große Dokumente“Das Streaming-Modell hält nur den Puffer der aktuellen Seite plus die flache Gliederungsliste vor, nicht alle Seiten auf einmal. Ein sehr langes Dokument bleibt unter der ADR-020-Obergrenze, weil die Engine fertige Seiten ausschreibt. Tabellen und Flex-Container halten sich weiterhin an die Grenze von 5,000 Knoten pro Kontext.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Ein bösartiges Dokument kann keinen unbegrenzten Speicher erzwingen. Die Obergrenzen für Elemente und Verschachtelung (ADR-001) und das Knotenbudget pro Kontext (ADR-020) begrenzen den Aufwand. Prüfen Sie Länge und Struktur von langem Inhalt, der von Benutzern bereitgestellt wird. Die Engine rendert einen vom Angreifer kontrollierten Gliederungstitel als Text und interpretiert ihn niemals.
Konformität
Abschnitt betitelt „Konformität“| Aussage | Spezifikation | Abschnitt | reference_id |
|---|---|---|---|
| Jeder Gliederungseintrag kann mit einem Ziel verknüpft sein, sodass der Benutzer direkt dorthin springt. | ISO 32000-2 | iso32000_2_sec12#x1.x5.p4 | |
| Der Dest-Eintrag eines Gliederungseintrags benennt das Ziel, das angezeigt wird, wenn der Eintrag aktiviert wird. | ISO 32000-2 | iso32000_2_sec12#x1.x11.p30 |
Dieses Recipe zeigt, wie NextPDF lange Inhalte fließen lässt und eine Gliederung aufbaut. CSS Fragmentation ist in der Support-Matrix als Verified eingestuft.
Kommerzieller Kontext
Abschnitt betitelt „Kommerzieller Kontext“Nicht zutreffend.