Pro edição
Webview
Em resumo
Seção intitulada “Em resumo”O Webview entrega um PDF linearizado (Fast Web View) por HTTP para que um cliente possa começar a renderizar a página 1 a partir de um pequeno prefixo inicial enquanto o restante do arquivo ainda está em trânsito. Ele encapsula os bytes brutos como um LinearizedDocument, responde a requisições Range com respostas de conteúdo parcial do RFC 9110 por meio de um ByteRangeResponder PSR-7, e pode provar (via FirstPageProber) que a primeira página é autocontida no prefixo.
Disponibilidade e licenciamento
Seção intitulada “Disponibilidade e licenciamento”Esse recurso vem no NextPDF Pro (nextpdf/pro) e é ativado com um envelope de licença de nível Pro. Uma implantação sem essa habilitação não carrega as classes do recurso. Compare as edições e obtenha uma licença.
Não há um sinalizador de licença separado por recurso. O responder é conectado às suas próprias fábricas PSR-17 em runtime — uma ResponseFactoryInterface e uma StreamFactoryInterface — e o media type tem como padrão application/pdf como um argumento do construtor, não como uma chave de licença.
Instalação
Seção intitulada “Instalação”composer require nextpdf/proO código está sob o namespace NextPDF\Pro\Webview.
Visão conceitual
Seção intitulada “Visão conceitual”Um PDF linearizado é disposto de modo que a primeira página do documento — o dicionário de parâmetros de linearização, o stream de hint primário e os objetos da página 1 — fique em uma seção inicial que termina no offset /E. O Webview transforma esse layout em entrega progressiva.
LinearizedDocument::fromBytes() analisa os bytes por meio da LinearizationView do lado de leitura do Core (o Pro nunca reimplementa a análise de linearização) e rejeita qualquer coisa que não seja um documento linearizado utilizável: não linearizado de forma alguma, um comprimento /L declarado que não corresponde ao comprimento real em bytes, ou um offset /E de fim da primeira página que não seja um offset positivo dentro do arquivo. A construção é, portanto, total — uma vez que você detenha um LinearizedDocument, cada offset que ele expõe é confiável.
ByteRangeResponder, então, responde a uma requisição HTTP. Ele é implementado apenas contra PSR-7 / PSR-17, sem acoplamento a framework. Ele sempre anuncia Accept-Ranges: bytes e um ETag SHA-256 forte e determinístico, analisa o cabeçalho Range do cliente conforme o RFC 9110 §14, e retorna um 200 OK completo, um único intervalo 206 Partial Content, uma resposta 206 multipart/byteranges para vários intervalos, ou um 416 Range Not Satisfiable.
FirstPageProber é o lado da prova estrutural: ele quantifica o prefixo da primeira página, a fração de todo o arquivo que esse prefixo representa e se o stream de hint primário está totalmente dentro dele — a propriedade que permite a um leitor localizar os objetos da página 1 apenas a partir do prefixo.
Por que funciona assim
Seção intitulada “Por que funciona assim”O Webview nunca reanalisa a linearização por conta própria. Ele toma emprestada a LinearizationView do lado de leitura do Core, de modo que a camada de entrega herda um único parser auditado em vez de uma segunda cópia que pode divergir. A construção é deliberadamente total. LinearizedDocument::fromBytes() rejeita um layout malformado de imediato, portanto cada offset em que uma resposta Range confia foi validado primeiro. O responder fala apenas PSR-7 e PSR-17, então o mesmo código serve um PDF linearizado a partir de qualquer stack HTTP. É essa disciplina que torna a entrega progressiva por intervalo segura para expor a clientes não confiáveis em volume.
Contexto de design: Geração de documentos em alto volume.
Como funciona a entrega progressiva por intervalo de bytes
Seção intitulada “Como funciona a entrega progressiva por intervalo de bytes”- Construa um
LinearizedDocumenta partir dos bytes do PDF renderizado. Uma entrada inválida levantaUnsupportedDocumentExceptionde imediato. - Entregue o documento e o
ServerRequestInterfacePSR-7 recebido aoByteRangeResponder::respond(). O responder lêRange(e a pré-condição opcionalIf-Range) e produz oResponseInterfacePSR-7 correto. - O cliente requisita primeiro o prefixo inicial (ou você o envia via push com
firstPageResponse()), renderiza a página 1 e, em seguida, requisita os intervalos restantes conforme o usuário rola a página.
O modelo de intervalo de bytes usa offsets inclusivos conforme o RFC 9110 §14.1.2: um ByteRange é firstByte–lastByte sobre uma representação de contentLength, e seu campo Content-Range é bytes first-last/length.
Contrato de comportamento
Seção intitulada “Contrato de comportamento”LinearizedDocument::fromBytes()é total: um documento não linearizado, uma divergência de/L, ou um offset/Enão positivo / fora do arquivo levantam, cada um,UnsupportedDocumentExceptionem vez de produzir um documento inseguro.- O
ETagé uma entity-tag SHA-256 forte sobre os bytes exatos, memoizada uma única vez na construção. Uma entrada de renderização idêntica produz bytes idênticos e, portanto, umETagidêntico, de modo que os caches e oIf-Rangese comportem de forma previsível. - Uma requisição sem
Rangeaplicável retorna200 OKcom o corpo completo. UmIf-Rangeque não corresponde aoETagforte atual faz com que oRangeseja ignorado e um200completo seja retornado (RFC 9110 §13.1.5). Apenas a forma de entity-tag forte deIf-Rangeé honrada; umIf-Rangede data HTTP é tratado como não correspondente. - Uma unidade de intervalo não reconhecida ou um
Rangesintaticamente inválido é ignorado e um200completo é retornado (RFC 9110 §14.2). - Um intervalo satisfazível retorna
206 Partial ContentcomContent-Range; vários intervalos satisfazíveis retornam206multipart/byteranges. Intervalos de bytes válidos sem nenhum satisfazível retornam416comContent-Range: bytes */length(RFC 9110 §15.3.7). firstPageResponse()emite um206carregando exatamente o intervalo de bytes da primeira página[0, /E - 1]— a forma de server-push de “primeira página antes do download completo”.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”O exemplo a seguir reflete a API pública documentada. O repositório não fornece um exemplo executável para este módulo.
use NextPDF\Pro\Webview\LinearizedDocument;use NextPDF\Pro\Webview\ByteRangeResponder;
$document = LinearizedDocument::fromBytes($pdfBytes);$responder = new ByteRangeResponder($responseFactory, $streamFactory);
$response = $responder->respond($document, $request);Exemplo de código — Push da primeira página e sondagem
Seção intitulada “Exemplo de código — Push da primeira página e sondagem”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);}Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”- O Webview requer um PDF genuinamente linearizado. Se o documento renderizado não for linearizado, habilite a linearização no momento da renderização, ou sirva-o com entrega completa simples —
respondToBytes()ainda pode servir intervalos sobre bytes arbitrários (não linearizados) quando você precisa apenas de suporte a intervalos, e não da semântica de primeira página. - As atualizações incrementais importam: um documento que recebeu anexos além do seu
/Ldeclarado é rejeitado como uma divergência de comprimento, porque os offsets de intervalo de bytes deixariam de ser confiáveis. - O responder limita o número de intervalos distintos que honra por requisição. Uma requisição que pede mais intervalos coalescidos do que o limite, ou mais bytes totais do que toda a representação, tem seu
Rangeignorado e recebe um200completo.
Desempenho
Seção intitulada “Desempenho”O prefixo da primeira página é o offset /E de fim da primeira página fixado ao comprimento do arquivo, de modo que FirstPageProber::prefixFraction() informa quão pequeno é o fetch inicial em relação a todo o arquivo — para um documento de muitas páginas, esse é todo o propósito do Fast Web View. A construção da resposta fatia a string de bytes em memória; o custo é proporcional aos bytes selecionados. O ETag é calculado uma vez por documento. Meça com documentos representativos.
Notas de segurança
Seção intitulada “Notas de segurança”Trate a entrada como não confiável. LinearizedDocument::fromBytes() valida os invariantes de linearização antes que qualquer offset seja usado. O responder rejeita um contentType que contenha caracteres de controle para evitar injeção de cabeçalho, deriva um boundary de multipart com garantia de não ocorrer dentro do corpo, e coalesce intervalos sobrepostos e limita sua quantidade e tamanho total para se defender contra a classe de negação de serviço por amplificação de intervalo multipart (Apache HTTPD CVE-2011-3192). Este módulo não registra nenhum conteúdo de documento.
Conformidade
Seção intitulada “Conformidade”A entrega por intervalo de bytes segue o RFC 9110 (HTTP Semantics) — §14 para requisições de intervalo, §13.1.5 para If-Range e §15.3.7 para 416. O modelo de documento linearizado é o layout Fast Web View descrito no ISO 32000-2 Annex F. O módulo não afirma nenhum identificador de cláusula externo além do comportamento verificado por seus testes.
Nota sobre o limite do Enterprise
Seção intitulada “Nota sobre o limite do Enterprise”O Enterprise não altera o comportamento do Webview. O Enterprise acrescenta recursos de conformidade e arquivamento de nível superior, documentados separadamente; eles não são necessários para servir um PDF linearizado por intervalos de bytes.
Limite de publicação
Seção intitulada “Limite de publicação”Esta página documenta apenas o comportamento externamente observável e a superfície pública de API suportada. Caminhos de namespace internos, classes auxiliares, tabelas de mecanismos, nomes de arquivos de runbook e prefixos de ticket estão fora de escopo.