콘텐츠로 이동
getnextpdf.com

Pro 에디션

Webview — 심층 참조

이 페이지는 공개 NextPDF\Pro\Webview 표면, 바이트 범위 요청/응답 모델, 그리고 공개 랜딩 페이지를 넘어서는 정확한 실패 모드를 문서화합니다.

이 기능은 NextPDF Pro(nextpdf/pro)에 포함되어 있으며 Pro 등급 라이선스 봉투로 활성화됩니다. 그 자격이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션 비교 및 라이선스 받기.

기능별 라이선스 플래그는 없습니다. 코드는 Pro 에디션과 함께 배포됩니다. PSR-17 ResponseFactoryInterface / StreamFactoryInterface와 본문 미디어 타입은 라이선싱 제어가 아니라 런타임 생성자 매개변수입니다.

Terminal window
composer require nextpdf/pro

NextPDF\Pro\Webview 아래의 공개 타입:

  • LinearizedDocument — 전달을 위해 준비된 검증된 선형화 PDF.
  • ByteRangeResponder — RFC 9110 바이트 범위 HTTP responder.
  • ByteRange — 표현 위에서의 충족 가능한 포함 바이트 범위 하나.
  • FirstPageProber — 구조적 “전체 다운로드 전 첫 페이지” 증명.

NextPDF\Pro\Webview\Exception 아래의 예외 타입:

  • WebviewException(마커 인터페이스), UnsupportedDocumentException, RangeNotSatisfiableException.

private 생성자를 가진 final readonly 클래스입니다. 명명된 생성자를 통해 인스턴스화하십시오.

  • static fromBytes(string $bytes): self — Core의 읽기 측 LinearizationView::fromPdf()를 통해 바이트를 파싱합니다. 문서가 선형화되지 않았을 때, 선언된 /L이 실제 바이트 길이와 일치하지 않을 때, 또는 /E 첫 페이지 끝 오프셋이 파일 내부의 양수 오프셋이 아닐 때 UnsupportedDocumentException을 던집니다.
  • length(): int — 바이트 단위 문서 길이.
  • firstPagePrefixLength(): int — 완전한 첫 페이지를 담는 최소 선행 접두사. 파일 길이로 클램핑된 /E 오프셋입니다.
  • firstPageByteRange(): ByteRange — 첫 페이지를 전달하는 포함 범위 [0, /E - 1]. 접두사가 비어 있는 경우에만 RangeNotSatisfiableException을 던집니다(심층 방어. fromBytes()가 이미 0 < /E <= length를 보장합니다).
  • slice(int $firstByte, int $lastByte): string — 포함 오프셋을 사용하는 엄격한 프로그래밍적 슬라이스. 범위를 벗어나면 RangeNotSatisfiableException을 던집니다.
  • etag(): string — 바이트에 대한 강하고 결정적인 SHA-256 엔티티 태그. 생성 시 한 번 메모이즈됩니다.

공개 readonly 속성: bytes(원시 PDF 바이트)와 view(Core LinearizationView).

PSR-7 / PSR-17에 대해서만 구현된 final readonly 클래스입니다.

  • __construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf')$contentType이 제어 문자를 포함할 때 InvalidArgumentException을 던집니다(이는 응답 및 멀티파트 파트 헤더에 보간됩니다. CR/LF 및 기타 제어 바이트는 헤더 주입을 방지하기 위해 거부됩니다).
  • respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface — 문서 자신의 ETag를 사용하여 선형화 문서에 대한 범위 요청에 답합니다.
  • respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface — 임의의 바이트(선형화되지 않은 채로 범위를 지원해야 하는 표현)에 대한 범위 요청에 답합니다. etagnull일 때 ETag는 바이트에서 도출됩니다.
  • firstPageResponse(LinearizedDocument $document): ResponseInterface — 정확히 첫 페이지의 바이트 범위를 담은 206을 빌드합니다. “전체 다운로드 전 첫 페이지”의 서버 푸시 형식입니다.

단일 충족 가능한 포함 바이트 범위(RFC 9110 §14.1.2)를 위한 final readonly 값 객체입니다.

  • __construct(int $firstByte, int $lastByte, int $contentLength) — 충족 가능성 0 <= firstByte <= lastByte <= contentLength - 1을 강제합니다. 그렇지 않으면 RangeNotSatisfiableException을 던집니다.
  • length(): int — 포함 범위(lastByte - firstByte + 1). 항상 >= 1입니다.
  • contentRange(): string — RFC 9110 §14.4 Content-Range 필드 값 bytes first-last/length.

공개 readonly 속성: firstByte, lastByte, contentLength.

LinearizedDocument로부터 생성되는 final readonly 클래스입니다.

  • prefixLength(): int — 첫 페이지를 렌더링하는 데 필요한 최소 선행 바이트 수.
  • prefixFraction(): float — 접두사가 차지하는 전체 파일의 비율(0.0–1.0). 길이가 0인 파일에 대해서는 1.0을 반환합니다.
  • hintStreamWithinPrefix(): bool — 기본 힌트 스트림 객체가 첫 페이지 접두사 안에 완전히 들어 있는지(따라서 접두사만으로 리더가 1페이지 객체를 찾을 수 있는지). 힌트 스트림은 양의 길이를 가져야 합니다.
  • isFirstPageSelfContained(): bool — 결합된 구조적 증명: 파일 안에 들어가고 힌트 스트림을 완전히 담는 양의 접두사.

ByteRangeResponder는 RFC 9110 §14를 따릅니다. 길이와 강한 SHA-256 ETag를 계산한 후, RangeIf-Range 헤더를 읽고 결정합니다.

조건상태비고
적용 가능한 Range가 없거나, If-Range가 현재의 강한 ETag와 일치하지 않음200 OK전체 본문. If-Range의 강한 엔티티 태그 형식만 존중됩니다(RFC 9110 §13.1.5).
인식되지 않는 범위 단위 또는 구문적으로 유효하지 않은 Range200 OK헤더가 무시됩니다(RFC 9110 §14.2).
충족 가능한 범위 하나206 Partial ContentContent-Range를 담습니다.
충족 가능한 범위 여러 개206 Partial Content도출된 경계를 가진 multipart/byteranges.
유효한 바이트 범위, 충족 가능한 것 없음416 Range Not SatisfiableContent-Range: bytes */length를 담습니다(RFC 9110 §15.3.7).

모든 응답은 Accept-Ranges: bytes와 강한 ETag를 광고합니다. 200206 응답은 Content-TypeContent-Length도 설정합니다.

범위 파싱은 bytes= 단위만 받아들입니다. 명시적 first-last, 개방형 first-(끝으로 클램핑됨), 그리고 접미사 -N(최종 N바이트. 표현만큼 큰 접미사는 그 전체를 선택함)을 지원합니다. 단독 -(또는 그 외 잘못된 어떤 스펙이든)는 전체 Range 헤더를 구문적으로 유효하지 않게 만들므로, 헤더가 무시되고 전체 200 OK 표현이 반환됩니다. -0 접미사, 또는 첫 오프셋이 끝에 있거나 그것을 넘는 어떤 스펙이든 충족 불가능한 스펙이며 폐기됩니다. 헤더 내의 어떤 스펙도 충족 가능하지 않으면 응답은 416 Range Not Satisfiable입니다. 큰 십진 오프셋은 정수 오버플로 포화에 의존하지 않고 비교되므로, 30자리 Range 값이 플랫폼 독립적으로 처리됩니다. 겹치는 충족 가능한 범위는 어떤 본문이 빌드되기 전에 병합됩니다. 진정으로 별개인(겹치지 않는) 범위는 별도의 멀티파트 파트로 보존됩니다.

WebviewExceptionThrowable을 확장하는 마커 인터페이스입니다. 이를 catch하여 전체 서브시스템을 일관되게 처리하십시오. 두 구체 예외 모두 이를 구현합니다.

  • UnsupportedDocumentException(InvalidArgumentException을 확장) — 바이트가 사용 가능한 선형화 문서가 아닐 때 LinearizedDocument::fromBytes()에 의해 발생합니다. 명명된 생성자: notLinearized()(/Linearized 매개변수 딕셔너리 없음), lengthMismatch($declaredLength, $actualLength)(선언된 /L이 실제 길이와 일치하지 않음 — 잘림, /L을 넘는 증분 업데이트를 통한 추가, 또는 비적합), 그리고 malformedFirstPageOffset($firstPageEndOffset, $length)(/E 오프셋이 파일 내부의 양수 오프셋이 아님).
  • RangeNotSatisfiableException(OutOfRangeException을 확장) — 프로그래밍적 슬라이스 오류. 포함 범위가 문서 밖으로 벗어날 때 ByteRange::__construct()LinearizedDocument::slice() / firstPageByteRange()에 의해 발생합니다. 명명된 생성자: outOfBounds($firstByte, $lastByte, $length).

HTTP responder는 클라이언트 Range 헤더에 대해 RangeNotSatisfiableException을 던지지 않습니다 — 충족 불가능한 HTTP 범위는 예외가 아니라 416 응답입니다(RFC 9110 §15.3.7). 그 예외는 범위를 벗어난 요청이 호출자 오류인 직접 프로그래밍적 슬라이싱을 위해 예약되어 있습니다. 구성된 contentType이 제어 문자를 포함할 때 ByteRangeResponder::__construct()는 (WebviewException이 아니라) 평범한 InvalidArgumentException을 던집니다.

responder는 요청당 존중하는 별개의 병합된 범위 수를 제한합니다(멀티파트 범위 증폭 부류, Apache HTTPD CVE-2011-3192). 요청이 병합된 범위의 상한보다 더 많이 요청하거나, 전체 표현보다 더 많은 총 바이트를 요청할 때, Range가 무시되고 전체 200이 반환됩니다. 멀티파트 경계는 결정적으로 도출되며 본문 내부에 절대 나타나지 않도록 보장될 때까지 다시 도출되므로, 재현 가능한 출력을 보존하면서 경계 충돌을 배제합니다.

바이트 범위 동작은 RFC 9110(HTTP Semantics)을 따릅니다. §14(범위 요청), §13.1.5(If-Range), §14.4(Content-Range), 그리고 §15.3.7(416). 선형화된 문서 레이아웃은 ISO 32000-2 Annex F의 Fast Web View 모델입니다. 이 모듈은 자신의 테스트로 검증된 동작을 넘어서는 추가 외부 조항 식별자를 주장하지 않습니다.

  • respondToBytes()는 첫 페이지 시맨틱이 필요하지 않을 때 임의의 바이트에 대해 범위를 제공합니다.
  • If-Range HTTP 날짜 검증자는 비일치로 취급됩니다 → 전체 200(클라이언트는 단순히 다시 페치합니다).
  • ETag는 순수하게 강한 캐시 검증자로 사용되는 SHA-256 해시입니다. 이 모듈은 서명이나 기타 암호 연산을 수행하지 않으며 FIPS 특화 동작을 정의하지 않습니다.

이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 표, 런북 파일명, 그리고 티켓 접두사는 범위 밖입니다.