Перейти к содержимому
getnextpdf.com

Pro редакция

Webview — глубокий справочник

На этой странице документируются публичная поверхность NextPDF\Pro\Webview, модель запроса/ответа по диапазонам байтов и точные режимы сбоев за рамками публичной целевой страницы.

Эта возможность поставляется в составе NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы возможности. Сравнить редакции и получить лицензию.

Пофункционального лицензионного флага нет; код поставляется с редакцией Pro. PSR-17-фабрики ResponseFactoryInterface / StreamFactoryInterface и медиатип тела — это параметры конструктора времени выполнения, а не элементы управления лицензированием.

Окно терминала
composer require nextpdf/pro

Публичные типы в NextPDF\Pro\Webview:

  • LinearizedDocument — проверенный линеаризованный PDF, подготовленный к отдаче.
  • ByteRangeResponder — HTTP-объект-ответчик по диапазонам байтов RFC 9110.
  • ByteRange — один удовлетворимый включающий диапазон байтов над представлением.
  • FirstPageProber — структурное доказательство «первая страница до полного скачивания».

Типы исключений в NextPDF\Pro\Webview\Exception:

  • WebviewException (маркерный интерфейс), UnsupportedDocumentException, RangeNotSatisfiableException.

Класс final readonly с приватным конструктором; создавайте экземпляр через именованный конструктор.

  • static fromBytes(string $bytes): self — разбирает байты через LinearizationView::fromPdf() из стороны чтения Core. Бросает UnsupportedDocumentException, когда документ не линеаризован, когда объявленное /L не совпадает с фактической длиной в байтах либо когда смещение конца первой страницы /E не является положительным смещением внутри файла.
  • 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 (LinearizationView из Core).

Класс final readonly, реализованный только против PSR-7 / PSR-17.

  • __construct(ResponseFactoryInterface $responses, StreamFactoryInterface $streams, string $contentType = 'application/pdf') — бросает InvalidArgumentException, когда $contentType содержит управляющие символы (он интерполируется в заголовки ответа и multipart-частей; CR/LF и прочие управляющие байты отклоняются для предотвращения внедрения в заголовки).
  • respond(LinearizedDocument $document, ServerRequestInterface $request): ResponseInterface — отвечает на запрос диапазона для линеаризованного документа, используя собственный ETag документа.
  • respondToBytes(string $bytes, ServerRequestInterface $request, ?string $etag = null): ResponseInterface — отвечает на запрос диапазона для произвольных байтов (представления, которое должно поддерживать диапазоны, не будучи линеаризованным). ETag выводится из байтов, когда он null.
  • firstPageResponse(LinearizedDocument $document): ResponseInterface — строит 206, несущий ровно диапазон байтов первой страницы; серверная push-форма «первая страница до полного скачивания».

Объект-значение final readonly для одного удовлетворимого включающего диапазона байтов (RFC 9110 §14.1.2).

  • __construct(int $firstByte, int $lastByte, int $contentLength) — обеспечивает удовлетворимость 0 <= firstByte <= lastByte <= contentLength - 1; иначе бросает RangeNotSatisfiableException.
  • length(): int — включающая протяжённость (lastByte - firstByte + 1), всегда >= 1.
  • contentRange(): string — значение поля Content-Range по RFC 9110 §14.4 bytes first-last/length.

Публичные readonly-свойства: firstByte, lastByte, contentLength.

Класс final readonly, сконструированный из LinearizedDocument.

  • prefixLength(): int — минимальное число ведущих байтов, нужных для отрисовки первой страницы.
  • prefixFraction(): float — доля всего файла (0.0–1.0), которую представляет префикс; возвращает 1.0 для файла нулевой длины.
  • hintStreamWithinPrefix(): bool — лежит ли объект первичного потока подсказок полностью внутри префикса первой страницы (так что один лишь префикс позволяет читателю найти объекты страницы 1). Поток подсказок должен иметь положительную длину.
  • isFirstPageSelfContained(): bool — совокупное структурное доказательство: положительный префикс, помещающийся в файл и полностью содержащий поток подсказок.

Модель запроса/ответа по диапазонам байтов

Заголовок раздела «Модель запроса/ответа по диапазонам байтов»

ByteRangeResponder следует RFC 9110 §14. После вычисления длины и сильного SHA-256-ETag он читает заголовки Range и If-Range и решает:

УсловиеСтатусПримечания
Нет применимого Range, либо If-Range не совпадает с текущим сильным ETag200 OKПолное тело. Учитывается только форма If-Range с сильным тегом сущности (RFC 9110 §13.1.5).
Нераспознанная единица диапазона или синтаксически невалидный Range200 OKЗаголовок игнорируется (RFC 9110 §14.2).
Один удовлетворимый диапазон206 Partial ContentНесёт Content-Range.
Несколько удовлетворимых диапазонов206 Partial Contentmultipart/byteranges с выведенной границей.
Валидные диапазоны байтов, ни один не удовлетворим416 Range Not SatisfiableНесёт Content-Range: bytes */length (RFC 9110 §15.3.7).

Каждый ответ объявляет Accept-Ranges: bytes и сильный ETag. Ответы 200 и 206 также устанавливают Content-Type и Content-Length.

Разбор диапазонов принимает только единицу bytes=. Он поддерживает явный first-last, открытый first- (ограничивается концом) и суффикс -N (последние N байтов; суффикс не меньше представления выбирает его целиком). Голый - (или любая иначе некорректная спецификация) делает весь заголовок Range синтаксически невалидным, поэтому заголовок игнорируется и возвращается полное представление 200 OK. Суффикс -0 либо любая спецификация, чьё первое смещение находится на конце или за ним, — это неудовлетворимая спецификация, и она отбрасывается; если ни одна спецификация в заголовке не удовлетворима, ответ — 416 Range Not Satisfiable. Большие десятичные смещения сравниваются без опоры на насыщение при целочисленном переполнении, поэтому 30-значное значение Range обрабатывается платформонезависимо. Перекрывающиеся удовлетворимые диапазоны объединяются до построения какого-либо тела; по-настоящему различные (неперекрывающиеся) диапазоны сохраняются как отдельные multipart-части.

WebviewException — это маркерный интерфейс, расширяющий Throwable; перехватывайте его, чтобы обрабатывать всю подсистему единообразно. Оба конкретных исключения его реализуют.

  • 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-объект-ответчик не бросает RangeNotSatisfiableException для клиентских заголовков Range — неудовлетворимый HTTP-диапазон — это ответ 416 (RFC 9110 §15.3.7), а не исключение. Это исключение зарезервировано для прямого программного среза, где запрос за пределами границ — это ошибка вызывающей стороны. ByteRangeResponder::__construct() бросает обычное InvalidArgumentException (а не WebviewException), когда настроенный contentType содержит управляющие символы.

Объект-ответчик ограничивает число различных объединённых диапазонов, учитываемых на один запрос (класс усиления multipart-диапазонов, Apache HTTPD CVE-2011-3192). Когда запрос просит больше объединённых диапазонов, чем предел, либо больше суммарных байтов, чем всё представление, Range игнорируется и возвращается полный 200. Multipart-граница выводится детерминированно и перевыводится, пока не будет гарантировано не встречаться внутри тела, сохраняя воспроизводимый вывод и одновременно исключая столкновение границ.

Поведение по диапазонам байтов следует RFC 9110 (HTTP Semantics): §14 (запросы диапазонов), §13.1.5 (If-Range), §14.4 (Content-Range) и §15.3.7 (416). Разметка линеаризованного документа — это модель Fast Web View из ISO 32000-2 Annex F. Модуль не утверждает никаких иных внешних идентификаторов пунктов сверх поведения, проверенного его тестами.

  • respondToBytes() отдаёт диапазоны над произвольными байтами, когда семантика первой страницы не нужна.
  • HTTP-дата-валидатор If-Range трактуется как несовпадение → полный 200 (клиент просто перезапрашивает).
  • ETag — это SHA-256-хэш, используемый исключительно как сильный валидатор кэша; этот модуль не выполняет подписания или иных криптографических операций и не определяет поведения, специфичного для FIPS.

Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов — вне области рассмотрения.