Pro editie
Webview
In het kort
Sectie met titel “In het kort”Webview levert een gelineariseerde (Fast Web View) PDF over HTTP zodat een client kan beginnen met het renderen van pagina 1 vanaf een kleine leidende prefix terwijl de rest van het bestand nog onderweg is. Het verpakt de ruwe bytes als een LinearizedDocument, beantwoordt Range-requests met RFC 9110 partial-content-responses via een PSR-7 ByteRangeResponder, en kan (via FirstPageProber) bewijzen dat de eerste pagina zelfstandig in de prefix zit.
Beschikbaarheid en licentiëring
Sectie met titel “Beschikbaarheid en licentiëring”Deze mogelijkheid wordt geleverd in NextPDF Pro (nextpdf/pro) en wordt geactiveerd met een licentie-envelop van het Pro-niveau. Een deployment zonder die entitlement laadt de klassen van deze mogelijkheid niet. Vergelijk edities en vraag een licentie aan.
Er is geen aparte licentievlag per feature. De responder wordt op runtime bedraad aan je eigen PSR-17-factories — een ResponseFactoryInterface en een StreamFactoryInterface — en het media-type is standaard application/pdf als constructorargument, geen licentieschakelaar.
Installatie
Sectie met titel “Installatie”composer require nextpdf/proDe code bevindt zich onder de NextPDF\Pro\Webview-namespace.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”Een gelineariseerde PDF is zo opgemaakt dat de eerste pagina van het document — de linearization parameter dictionary, de primaire hint stream en de objecten van pagina 1 — in een leidende sectie staat die eindigt bij de /E-offset. Webview zet die opmaak om in progressieve aflevering.
LinearizedDocument::fromBytes() parseert de bytes via de read-side LinearizationView van Core (Pro herimplementeert linearisatie-parsing nooit) en wijst alles af wat geen bruikbaar gelineariseerd document is: helemaal niet gelineariseerd, een gedeclareerde /L-lengte die niet overeenkomt met de werkelijke bytelengte, of een /E-end-of-first-page-offset die geen positieve offset binnen het bestand is. De constructie is daarom totaal — zodra je een LinearizedDocument vasthoudt, is elke offset die het blootstelt betrouwbaar.
ByteRangeResponder beantwoordt vervolgens een HTTP-request. Het is uitsluitend tegen PSR-7 / PSR-17 geïmplementeerd, zonder framework-koppeling. Het adverteert altijd Accept-Ranges: bytes en een sterke, deterministische SHA-256-ETag, parseert de Range-header van de client volgens RFC 9110 §14, en retourneert ofwel een volledige 200 OK, een 206 Partial Content single range, een 206 multipart/byteranges-response voor meerdere ranges, of een 416 Range Not Satisfiable.
FirstPageProber is de structurele bewijszijde: het kwantificeert de first-page-prefix, de fractie van het hele bestand die die prefix vertegenwoordigt, en of de primaire hint stream er volledig binnen ligt — de eigenschap die een lezer in staat stelt pagina-1-objecten alleen uit de prefix te lokaliseren.
Waarom het zo werkt
Sectie met titel “Waarom het zo werkt”Webview herparseert linearisatie nooit zelf. Het leent de read-side LinearizationView van Core, zodat de afleveringslaag één geauditeerde parser erft in plaats van een tweede, uiteendrijvende kopie. De constructie is bewust totaal. LinearizedDocument::fromBytes() wijst een misvormde opmaak vooraf af, zodat elke offset die een Range-response vertrouwt eerst is gevalideerd. De responder spreekt alleen PSR-7 en PSR-17, zodat dezelfde code een gelineariseerde PDF vanuit elke HTTP-stack serveert. Die discipline is wat progressieve range-aflevering veilig maakt om op volume aan niet-vertrouwde clients bloot te stellen.
Ontwerpachtergrond: Documentgeneratie op grote schaal.
Hoe progressieve byte-range-bediening werkt
Sectie met titel “Hoe progressieve byte-range-bediening werkt”- Bouw een
LinearizedDocumentuit de gerenderde PDF-bytes. Ongeldige invoer werpt voorafUnsupportedDocumentException. - Geef het document en de inkomende PSR-7
ServerRequestInterfacedoor aanByteRangeResponder::respond(). De responder leestRange(en de optioneleIf-Range-preconditie) en produceert de juiste PSR-7ResponseInterface. - De client vraagt eerst de leidende prefix op (of je pusht die met
firstPageResponse()), rendert pagina 1, en vraagt vervolgens de resterende ranges op terwijl de gebruiker scrollt.
Het byte-range-model gebruikt inclusieve offsets volgens RFC 9110 §14.1.2: een ByteRange is firstByte–lastByte over een representatie van contentLength, en zijn Content-Range-veld is bytes first-last/length.
Gedragscontract
Sectie met titel “Gedragscontract”LinearizedDocument::fromBytes()is totaal: een niet-gelineariseerd document, een/L-mismatch, of een niet-positieve / buiten-bestand-/E-offset werpen elkUnsupportedDocumentExceptionin plaats van een onveilig document te produceren.- De
ETagis een sterke SHA-256-entity-tag over de exacte bytes, eenmalig gememoïseerd bij constructie. Identieke render-invoer levert identieke bytes en daarmee een identiekeETag, zodat caches enIf-Rangezich voorspelbaar gedragen. - Een request zonder toepasselijke
Rangeretourneert200 OKmet de volledige body. EenIf-Rangedie niet overeenkomt met de huidige sterkeETagzorgt ervoor dat deRangewordt genegeerd en een volledige200wordt geretourneerd (RFC 9110 §13.1.5). Alleen de sterke-entity-tag-vorm vanIf-Rangewordt gehonoreerd; een HTTP-date-If-Rangewordt als een non-match behandeld. - Een niet-herkende range-unit of een syntactisch ongeldige
Rangewordt genegeerd en een volledige200wordt geretourneerd (RFC 9110 §14.2). - Eén bevredigbare range retourneert
206 Partial ContentmetContent-Range; meerdere bevredigbare ranges retourneren206multipart/byteranges. Geldige byte-ranges waarvan geen enkele bevredigbaar is, retourneren416metContent-Range: bytes */length(RFC 9110 §15.3.7). firstPageResponse()zendt een206die exact de byte-range[0, /E - 1]van de eerste pagina draagt — de server-push-vorm van “eerste pagina vóór de volledige download”.
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”Het volgende weerspiegelt de gedocumenteerde publieke API. De repository levert geen uitvoerbaar voorbeeld voor deze module.
use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;
$document = LinearizedDocument::fromBytes($pdfBytes);$responder = new ByteRangeResponder($responseFactory, $streamFactory);
$response = $responder->respond($document, $request);Codevoorbeeld — First-page push en probing
Sectie met titel “Codevoorbeeld — First-page push en probing”use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;use NextPDF\Pro\Webview\FirstPageProber;use NextPDF\Pro\Webview\Exception\UnsupportedDocumentException;
try { $document = LinearizedDocument::fromBytes($pdfBytes);} catch (UnsupportedDocumentException $e) { // Not a usable linearized document — fall back to plain full delivery. // ... return;}
$prober = new FirstPageProber($document);if ($prober->isFirstPageSelfContained()) { // Push exactly the first page's bytes for an instant render. $response = (new ByteRangeResponder($responseFactory, $streamFactory)) ->firstPageResponse($document);}Randgevallen en valkuilen
Sectie met titel “Randgevallen en valkuilen”- Webview vereist een werkelijk gelineariseerde PDF. Als het gerenderde document niet gelineariseerd is, schakel dan linearisatie in op render-tijd, of bedien het met gewone volledige aflevering —
respondToBytes()kan nog steeds ranges bedienen over willekeurige (niet-gelineariseerde) bytes wanneer je alleen range-ondersteuning nodig hebt, niet de first-page-semantiek. - Incrementele updates zijn van belang: een document dat is uitgebreid voorbij zijn gedeclareerde
/L, wordt afgewezen als een lengte-mismatch, omdat byte-range-offsets dan niet langer betrouwbaar zouden zijn. - De responder begrenst het aantal distincte ranges dat het per request honoreert. Een request die om meer samengevoegde ranges vraagt dan de cap, of om meer totale bytes dan de hele representatie, krijgt zijn
Rangegenegeerd en wordt bediend met een volledige200.
Prestaties
Sectie met titel “Prestaties”De first-page-prefix is de /E-end-of-first-page-offset geklemd op de bestandslengte, dus FirstPageProber::prefixFraction() rapporteert hoe klein de initiële fetch is ten opzichte van het hele bestand — voor een document met veel pagina’s is dat het hele punt van Fast Web View. Het bouwen van de response slicet de in-memory bytestring; de kosten zijn evenredig met de geselecteerde bytes. De ETag wordt eenmaal per document berekend. Meet met representatieve documenten.
Beveiligingsnotities
Sectie met titel “Beveiligingsnotities”Behandel invoer als niet-vertrouwd. LinearizedDocument::fromBytes() valideert linearisatie-invarianten voordat een offset wordt gebruikt. De responder wijst een contentType met control characters af om header-injectie te voorkomen, leidt een multipart boundary af die gegarandeerd niet binnen de body voorkomt, en voegt overlappende ranges samen en begrenst hun aantal en totale grootte om te verdedigen tegen de multipart-range-amplification-klasse van denial-of-service (Apache HTTPD CVE-2011-3192). Deze module logt geen documentinhoud.
Conformiteit
Sectie met titel “Conformiteit”Byte-range-aflevering volgt RFC 9110 (HTTP Semantics) — §14 voor range-requests, §13.1.5 voor If-Range, en §15.3.7 voor 416. Het gelineariseerde-documentmodel is de Fast Web View-opmaak die wordt beschreven in ISO 32000-2 Annex F. De module beweert geen verdere externe clausule-identifiers buiten gedrag dat door zijn tests is geverifieerd.
Enterprise-grensnotitie
Sectie met titel “Enterprise-grensnotitie”Enterprise wijzigt het gedrag van Webview niet. Enterprise voegt apart gedocumenteerde compliance- en archiveringsfeatures van een hogere tier toe; die zijn niet vereist om een gelineariseerde PDF over byte-ranges te bedienen.
Publicatiegrens
Sectie met titel “Publicatiegrens”Deze pagina documenteert uitsluitend extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, hulpklassen, mechanismetabellen, runbook-bestandsnamen en ticket-prefixen vallen buiten de scope.