Ga naar inhoud
getnextpdf.com

Pro editie

Webview

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.

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.

Terminal window
composer require nextpdf/pro

De code bevindt zich onder de NextPDF\Pro\Webview-namespace.

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.

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.

  1. Bouw een LinearizedDocument uit de gerenderde PDF-bytes. Ongeldige invoer werpt vooraf UnsupportedDocumentException.
  2. Geef het document en de inkomende PSR-7 ServerRequestInterface door aan ByteRangeResponder::respond(). De responder leest Range (en de optionele If-Range-preconditie) en produceert de juiste PSR-7 ResponseInterface.
  3. 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 firstBytelastByte over een representatie van contentLength, en zijn Content-Range-veld is bytes first-last/length.

  • LinearizedDocument::fromBytes() is totaal: een niet-gelineariseerd document, een /L-mismatch, of een niet-positieve / buiten-bestand-/E-offset werpen elk UnsupportedDocumentException in plaats van een onveilig document te produceren.
  • De ETag is een sterke SHA-256-entity-tag over de exacte bytes, eenmalig gememoïseerd bij constructie. Identieke render-invoer levert identieke bytes en daarmee een identieke ETag, zodat caches en If-Range zich voorspelbaar gedragen.
  • Een request zonder toepasselijke Range retourneert 200 OK met de volledige body. Een If-Range die niet overeenkomt met de huidige sterke ETag zorgt ervoor dat de Range wordt genegeerd en een volledige 200 wordt geretourneerd (RFC 9110 §13.1.5). Alleen de sterke-entity-tag-vorm van If-Range wordt gehonoreerd; een HTTP-date-If-Range wordt als een non-match behandeld.
  • Een niet-herkende range-unit of een syntactisch ongeldige Range wordt genegeerd en een volledige 200 wordt geretourneerd (RFC 9110 §14.2).
  • Eén bevredigbare range retourneert 206 Partial Content met Content-Range; meerdere bevredigbare ranges retourneren 206 multipart/byteranges. Geldige byte-ranges waarvan geen enkele bevredigbaar is, retourneren 416 met Content-Range: bytes */length (RFC 9110 §15.3.7).
  • firstPageResponse() zendt een 206 die exact de byte-range [0, /E - 1] van de eerste pagina draagt — de server-push-vorm van “eerste pagina vóór de volledige download”.

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);
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);
}
  • 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 Range genegeerd en wordt bediend met een volledige 200.

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.

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.

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 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.

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.