Salta ai contenuti
getnextpdf.com

Pro edizione

Webview

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.

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.

Terminal window
composer require nextpdf/pro

Il codice risiede sotto il namespace NextPDF\Pro\Webview.

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.

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.

  1. Costruire un LinearizedDocument dai byte del PDF renderizzato. Un input non valido solleva UnsupportedDocumentException fin da subito.
  2. Passare il documento e la ServerRequestInterface PSR-7 in arrivo a ByteRangeResponder::respond(). Il responder legge Range (e la precondizione opzionale If-Range) e produce la corretta ResponseInterface PSR-7.
  3. 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 è firstBytelastByte su una rappresentazione di contentLength, e il suo campo Content-Range è bytes first-last/length.

  • LinearizedDocument::fromBytes() è totale: un documento non linearizzato, una discrepanza /L o un offset /E non positivo / fuori dal file sollevano ciascuno UnsupportedDocumentException anziché 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 un ETag identico, così cache e If-Range si comportano in modo prevedibile.
  • Una richiesta senza alcun Range applicabile restituisce 200 OK con il corpo completo. Un If-Range che non corrisponde all’attuale ETag forte fa sì che il Range venga ignorato e venga restituito un 200 completo (RFC 9110 §13.1.5). Viene onorata solo la forma con entity-tag forte di If-Range; un If-Range con data HTTP è trattato come una non corrispondenza.
  • Un’unità di range non riconosciuta o un Range sintatticamente non valido viene ignorato e viene restituito un 200 completo (RFC 9110 §14.2).
  • Un range soddisfacibile restituisce 206 Partial Content con Content-Range; più range soddisfacibili restituiscono 206 multipart/byteranges. Byte range validi con nessuno soddisfacibile restituiscono 416 con Content-Range: bytes */length (RFC 9110 §15.3.7).
  • firstPageResponse() emette un 206 che trasporta esattamente il byte range della prima pagina [0, /E - 1] — la forma di server-push di “prima pagina prima del download completo”.

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);
}
  • 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 /L dichiarata 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 Range ignorato e riceve un 200 completo.

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.

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.

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.

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.

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.