Ga naar inhoud

HTML-weergavepijplijn

Bij een aanroep van writeHtml() wordt één voorwaartse doorgang over HyperText Markup Language (HTML) uitgevoerd: invoer tokeniseren, @page en stijlen oplossen, inhoud opmaken en Portable Document Format (PDF)-operatoren weergeven. Tussen de fasen wordt geen elementenboom bewaard.

Terminal window
composer require nextpdf/core:^3

De HTML-weergavepijplijn zet HTML+CSS, oftewel HTML plus Cascading Style Sheets (CSS), in één voorwaartse doorgang om naar PDF-contentstreamoperatoren. Er wordt geen blijvende documentboom opgebouwd. De onderstaande fasen weerspiegelen HtmlParser::parse() op main.

Fase 1 — Opschonen en normaliseren. HtmlParser::parse() weigert invoer groter dan 10 MB, verwijdert stuurtekens en normaliseert regeleinden: zowel CRLF als losse CR worden LF, conform de HTML-regeleindenormalisatie in de bron. Vervolgens worden alle instantievelden teruggezet, zodat status uit een eerdere aanroep niet kan doorwerken.

Fase 2 — @page- en stijlblokken extraheren. De parser extraheert eerst <style>-blokken en past daarna de gevonden @page-regels toe om de paginageometrie opnieuw in te stellen. Dit gebeurt voordat er tokens worden verwerkt, omdat de paginagrootte elke latere lay-outbeslissing beïnvloedt.

Fase 3 — Tokeniseren. HtmlTokenizer::cleanHtml() normaliseert witruimte, maar behoudt <pre>-inhoud. tokenize() produceert vervolgens een platte list<HtmlToken>. Dit is een tokenlijst, geen knooppuntgraaf. De pijplijn verwijdert teksttokens die alleen uit witruimte bestaan meteen. HtmlChildScanner::scan() bouwt indexmappen (aantallen onderliggende elementen, aantallen tags, leegheid) over de platte lijst, zodat structurele selectors geen boom nodig hebben.

Fase 4 — Optionele :has()-voorscan. Wanneer de experimentele functie css.has is ingeschakeld, voert CssResolver::resolveHasSelectors() één begrensde voorscan over de tokenlijst uit om de relationele selector op te lossen. Deze gedocumenteerde, begrensde stap is de uitzondering op de regel van één doorgang.

Fase 5 — Tokens verwerken (stijl, lay-out, weergave). HtmlParser::processTokens() doorloopt de tokenlijst eenmaal. Voor elk element lost het de cascade op (applicators van Laag 1 schrijven naar HtmlStyleState), berekent het de geometrie (lay-out van Laag 3) en zendt het PDF-operatoren uit (weergave van Laag 4). Stijlovererving gebruikt een HtmlStyleState-stack met push en pop. De cursor (x, y, marges, streamoffset) wordt tussen handlers verplaatst via HtmlBlockCursor-momentopnamen.

Fase 6 — Het resultaat retourneren. parse() retourneert een onveranderlijke HtmlRenderResult met de uitgezonden contentstream, de eindpositie van de cursor en de gebruikte lettertypesleutels. De aanroeper (writeHtml()) zet de cursor terug naar het paginacoördinatenstelsel.

Zie voor de scheiding in vier lagen binnen Fase 5 de pagina laagcontracten. Zie voor de eigenschap zonder bewaarde boom en de bijbehorende limieten de pagina streamingbeperkingen.

SymboolLocatieFase
Document::writeHtml(string $html): staticsrc/Core/Concerns/HasTextOutput.phpOpenbaar toegangspunt
HtmlParser::parse(string $html): HtmlRenderResultsrc/Html/HtmlParser.phpOrkestreert alle fasen
HtmlTokenizer::cleanHtml() / tokenize()src/Html/HtmlTokenizer.phpFase 3
HtmlChildScanner::scan()src/Html/HtmlChildScanner.phpIndexmappen van Fase 3
CssResolver::resolveHasSelectors()src/Html/CssResolver.phpFase 4 (afgeschermd)
HtmlRenderResult (stream, endX, endY, usedFontKeys)src/Html/HtmlRenderResult.phpFase 6

Afkomstig uit examples/08-html-basic.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Basic');
$doc->addPage();
$doc->writeHtml('<h1 style="color:#1E3A8A;">HTML Rendering</h1><p>One pass.</p>');
$doc->save(__DIR__ . '/output/08-html-basic.pdf');

Geef een opgemaakt rapport weer met een ingesloten <style>-blok. De pijplijn extraheert het stijlblok en past het toe voordat er tokens worden verwerkt.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Exception\HtmlParsingException;
function renderInvoice(string $bodyHtml, string $out): void
{
$doc = Document::createStandalone();
$doc->setTitle('Invoice');
$doc->addPage();
$html = '<style>@page { margin: 20mm; } '
. 'h1 { color: #1E3A8A; } '
. 'table { width: 100%; }</style>'
. $bodyHtml;
try {
$doc->writeHtml($html);
} catch (HtmlParsingException $e) {
// Sanitize/cap failures surface here. Do not retry.
throw $e;
}
$doc->save($out);
}
  • @page wordt vóór de tokens gelezen. Een @page-regel na de inhoud is nog steeds van toepassing, omdat stijlextractie vóór tokenisatie plaatsvindt. De paginageometrie ligt vóór Fase 5 vast.
  • <pre>-witruimte blijft behouden. cleanHtml() beschermt <pre>-inhoud; de pijplijn laat witruimte elders ineenklappen.
  • :has() is afgeschermd. Als de experimentele functie css.has niet is ingeschakeld, wordt Fase 4 niet uitgevoerd en komen :has()-selectors niet overeen.
  • Eén streambuffer. De pijplijn schrijft naar één stringbuffer. Reeds geschreven inhoud wordt nooit verplaatst. Er vindt geen herindeling plaats.
  • Limieten gelden tijdens de doorgang. De element- en nestingslimieten werpen een uitzondering op tijdens Fase 5, niet ervoor. Een document kan halverwege mislukken.

De pijplijn doorloopt in O(aantal tokens). Het bepalen van de kolombreedte van tabellen voegt per tabel een begrensde rijscan toe (Fase 5, TableParser). Wanneer ingeschakeld, voegt de :has()-voorscan één begrensde doorgang over de tokenlijst toe (Fase 4). Het geheugen is O(nestingsdiepte) voor de stijlstack, niet O(aantal elementen); zie streamingbeperkingen. De prestatiebenchmark van de HTML-weergavepijplijn beschermt tegen regressies met een drempel van 5% (samengevoegd werk, PR #564). Het performance_budget per pagina (wall_ms: 1500, peak_mb: 64) is het operationele plafond.

Fase 1 is de eerste beveiligingsgrens: de invoerlimiet van 10 MB, het verwijderen van stuurtekens en de regeleindenormalisatie worden alle vóór tokenisatie uitgevoerd. Tijdens Fase 5 schermt DefaultHtmlSecurityPolicy de toegestane tags, attributen, CSS-eigenschappen en URL-schema’s af. Zie het beveiligingsmodel van de HTML-module.

De regeleindenormalisatie volgt de regeleindeafhandeling van de HTML-standaard: CRLF en losse CR worden LF. CSS-conformiteit per eigenschap is gedocumenteerd in de CSS-ondersteuningsmatrix, en cascadegedrag is gedocumenteerd op css-resolver. Deze pagina herhaalt de ondersteuning per eigenschap niet.

Enterprise-mogelijkheid. Premium verbreedt de CSS-dekking op dezelfde pijplijn. De volgorde van zes fasen verandert niet tussen edities. Zie de CSS-ondersteuningsmatrix.