Pro edizione
Webview
In breve
Sezione intitolata “In breve”Webview recapita un PDF linearizzato (Fast Web View) su HTTP così che un client possa iniziare a renderizzare la pagina 1 da un piccolo prefisso iniziale mentre il resto del file è ancora in transito. Avvolge i byte grezzi come un LinearizedDocument, risponde alle richieste Range con risposte partial-content RFC 9110 tramite un ByteRangeResponder PSR-7 e può dimostrare (tramite FirstPageProber) che la prima pagina è autocontenuta nel prefisso.
Disponibilità e licenza
Sezione intitolata “Disponibilità e licenza”Questa funzionalità è distribuita in NextPDF Pro (nextpdf/pro) e si attiva con un envelope di licenza di livello Pro. Un deployment privo di tale entitlement non carica le classi della funzionalità. Confronta le edizioni e ottieni una licenza.
Non esiste un flag di licenza separato per singola funzionalità. Il responder è cablato alle proprie factory PSR-17 a runtime — una ResponseFactoryInterface e una StreamFactoryInterface — e il media type predefinito è application/pdf come argomento del costruttore, non come interruttore di licenza.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/proIl codice risiede sotto il namespace NextPDF\Pro\Webview.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Un PDF linearizzato è disposto in modo che la prima pagina del documento — il dizionario dei parametri di linearizzazione, il primary hint stream e gli oggetti della pagina 1 — risieda in una sezione iniziale che termina all’offset /E. Webview trasforma quella disposizione in recapito progressivo.
LinearizedDocument::fromBytes() analizza i byte attraverso la LinearizationView lato lettura del Core (Pro non re-implementa mai il parsing della linearizzazione) e rifiuta qualsiasi cosa che non sia un documento linearizzato utilizzabile: non linearizzato affatto, una lunghezza /L dichiarata che non corrisponde alla lunghezza reale in byte, o un offset di fine prima pagina /E che non è un offset positivo all’interno del file. La costruzione è quindi totale — una volta che si possiede un LinearizedDocument, ogni offset che espone è affidabile.
ByteRangeResponder risponde quindi a una richiesta HTTP. È implementato solo rispetto a PSR-7 / PSR-17, senza accoppiamento a un framework. Pubblicizza sempre Accept-Ranges: bytes e un ETag SHA-256 forte e deterministico, analizza l’header Range del client secondo RFC 9110 §14 e restituisce un 200 OK completo, un 206 Partial Content a singolo range, una risposta 206 multipart/byteranges per più range, oppure un 416 Range Not Satisfiable.
FirstPageProber è il lato della prova strutturale: quantifica il prefisso della prima pagina, la frazione dell’intero file che quel prefisso rappresenta e se il primary hint stream giace interamente al suo interno — la proprietà che consente a un lettore di localizzare gli oggetti della pagina 1 dal solo prefisso.
Perché funziona così
Sezione intitolata “Perché funziona così”Webview non ri-analizza mai la linearizzazione per conto proprio. Prende in prestito la LinearizationView lato lettura del Core, così il layer di recapito eredita un unico parser sottoposto ad audit anziché una seconda copia soggetta a deriva. La costruzione è deliberatamente totale. LinearizedDocument::fromBytes() rifiuta in anticipo una disposizione malformata, così ogni offset di cui una risposta Range si fida è stato convalidato prima. Il responder parla solo PSR-7 e PSR-17, così lo stesso codice serve un PDF linearizzato da qualsiasi stack HTTP. È questa disciplina a rendere il recapito progressivo per range sicuro da esporre a client non attendibili su larga scala.
Contesto di progettazione: Generazione di documenti ad alto volume.
Come funziona il servizio progressivo byte-range
Sezione intitolata “Come funziona il servizio progressivo byte-range”- Costruire un
LinearizedDocumentdai byte del PDF renderizzato. Un input non valido sollevaUnsupportedDocumentExceptionfin da subito. - Passare il documento e la
ServerRequestInterfacePSR-7 in arrivo aByteRangeResponder::respond(). Il responder leggeRange(e la precondizione opzionaleIf-Range) e produce la correttaResponseInterfacePSR-7. - Il client richiede prima il prefisso iniziale (oppure lo si invia tramite
firstPageResponse()), renderizza la pagina 1, quindi richiede i range rimanenti man mano che l’utente scorre.
Il modello byte-range usa offset inclusivi secondo RFC 9110 §14.1.2: un ByteRange è firstByte–lastByte su una rappresentazione di contentLength, e il suo campo Content-Range è bytes first-last/length.
Contratto di comportamento
Sezione intitolata “Contratto di comportamento”LinearizedDocument::fromBytes()è totale: un documento non linearizzato, una discrepanza/Lo un offset/Enon positivo / fuori dal file sollevano ciascunoUnsupportedDocumentExceptionanziché produrre un documento non sicuro.- L’
ETagè un entity-tag SHA-256 forte sui byte esatti, memoizzato una sola volta alla costruzione. Un input di rendering identico produce byte identici e quindi unETagidentico, così cache eIf-Rangesi comportano in modo prevedibile. - Una richiesta senza alcun
Rangeapplicabile restituisce200 OKcon il corpo completo. UnIf-Rangeche non corrisponde all’attualeETagforte fa sì che ilRangevenga ignorato e venga restituito un200completo (RFC 9110 §13.1.5). Viene onorata solo la forma con entity-tag forte diIf-Range; unIf-Rangecon data HTTP è trattato come una non corrispondenza. - Un’unità di range non riconosciuta o un
Rangesintatticamente non valido viene ignorato e viene restituito un200completo (RFC 9110 §14.2). - Un range soddisfacibile restituisce
206 Partial ContentconContent-Range; più range soddisfacibili restituiscono206multipart/byteranges. Byte range validi con nessuno soddisfacibile restituiscono416conContent-Range: bytes */length(RFC 9110 §15.3.7). firstPageResponse()emette un206che trasporta esattamente il byte range della prima pagina[0, /E - 1]— la forma di server-push di “prima pagina prima del download completo”.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”Quanto segue riflette l’API pubblica documentata. Il repository non distribuisce un esempio eseguibile per questo modulo.
use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;
$document = LinearizedDocument::fromBytes($pdfBytes);$responder = new ByteRangeResponder($responseFactory, $streamFactory);
$response = $responder->respond($document, $request);Esempio di codice — Push e probing della prima pagina
Sezione intitolata “Esempio di codice — Push e probing della prima pagina”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);}Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Webview richiede un PDF genuinamente linearizzato. Se il documento renderizzato non è linearizzato, abilitare la linearizzazione al momento del rendering, oppure servirlo con recapito completo semplice —
respondToBytes()può comunque servire range su byte arbitrari (non linearizzati) quando serve solo il supporto ai range, non la semantica della prima pagina. - Gli incremental update contano: un documento a cui è stato fatto un append oltre la sua
/Ldichiarata viene rifiutato come discrepanza di lunghezza, perché gli offset byte-range non sarebbero più affidabili. - Il responder limita il numero di range distinti che onora per richiesta. Una richiesta che chiede più range coalescenti del limite, o più byte totali dell’intera rappresentazione, ha il suo
Rangeignorato e riceve un200completo.
Prestazioni
Sezione intitolata “Prestazioni”Il prefisso della prima pagina è l’offset di fine prima pagina /E ridotto alla lunghezza del file, così FirstPageProber::prefixFraction() riporta quanto piccolo sia il fetch iniziale rispetto all’intero file — per un documento di molte pagine questo è esattamente lo scopo di Fast Web View. La costruzione della risposta affetta la stringa di byte in memoria; il costo è proporzionale ai byte selezionati. L’ETag viene calcolato una volta per documento. Misurare con documenti rappresentativi.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Trattare l’input come non attendibile. LinearizedDocument::fromBytes() convalida gli invarianti di linearizzazione prima che venga usato qualsiasi offset. Il responder rifiuta un contentType contenente caratteri di controllo per prevenire l’header injection, deriva un boundary multipart garantito non comparire all’interno del corpo, e unifica i range sovrapposti limitandone il numero e la dimensione totale per difendersi dalla classe di denial-of-service da multipart range-amplification (Apache HTTPD CVE-2011-3192). Questo modulo non registra alcun contenuto del documento.
Conformità
Sezione intitolata “Conformità”Il recapito byte-range segue RFC 9110 (HTTP Semantics) — §14 per le richieste di range, §13.1.5 per If-Range e §15.3.7 per 416. Il modello di documento linearizzato è la disposizione Fast Web View descritta da ISO 32000-2 Annex F. Il modulo non asserisce ulteriori identificatori di clausola esterni oltre al comportamento verificato dai suoi test.
Nota sul confine Enterprise
Sezione intitolata “Nota sul confine Enterprise”Enterprise non modifica il comportamento di Webview. Enterprise aggiunge funzionalità di conformità e archiviazione di livello superiore documentate separatamente; non sono richieste per servire un PDF linearizzato su byte range.
Confine di pubblicazione
Sezione intitolata “Confine di pubblicazione”Questa pagina documenta solo il comportamento osservabile esternamente e la superficie di API pubblica supportata. Percorsi di namespace interni, classi helper, tabelle di meccanismi, nomi di file di runbook e prefissi di ticket sono fuori ambito.