Pro редакция
Webview — глубокий справочник
На этой странице документируются публичная поверхность NextPDF\Pro\Webview, модель запроса/ответа по диапазонам байтов и точные режимы сбоев за рамками публичной целевой страницы.
Доступность и лицензирование
Заголовок раздела «Доступность и лицензирование»Эта возможность поставляется в составе NextPDF Pro (nextpdf/pro) и активируется лицензионным конвертом уровня Pro. Развёртывание без этого права не загружает классы возможности. Сравнить редакции и получить лицензию.
Пофункционального лицензионного флага нет; код поставляется с редакцией Pro. PSR-17-фабрики ResponseFactoryInterface / StreamFactoryInterface и медиатип тела — это параметры конструктора времени выполнения, а не элементы управления лицензированием.
Поверхность публичного API
Заголовок раздела «Поверхность публичного API»composer require nextpdf/proПубличные типы в NextPDF\Pro\Webview:
LinearizedDocument— проверенный линеаризованный PDF, подготовленный к отдаче.ByteRangeResponder— HTTP-объект-ответчик по диапазонам байтов RFC 9110.ByteRange— один удовлетворимый включающий диапазон байтов над представлением.FirstPageProber— структурное доказательство «первая страница до полного скачивания».
Типы исключений в NextPDF\Pro\Webview\Exception:
WebviewException(маркерный интерфейс),UnsupportedDocumentException,RangeNotSatisfiableException.
LinearizedDocument
Заголовок раздела «LinearizedDocument»Класс 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).
ByteRangeResponder
Заголовок раздела «ByteRangeResponder»Класс 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-форма «первая страница до полного скачивания».
ByteRange
Заголовок раздела «ByteRange»Объект-значение 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.4bytes first-last/length.
Публичные readonly-свойства: firstByte, lastByte, contentLength.
FirstPageProber
Заголовок раздела «FirstPageProber»Класс 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 не совпадает с текущим сильным ETag | 200 OK | Полное тело. Учитывается только форма If-Range с сильным тегом сущности (RFC 9110 §13.1.5). |
Нераспознанная единица диапазона или синтаксически невалидный Range | 200 OK | Заголовок игнорируется (RFC 9110 §14.2). |
| Один удовлетворимый диапазон | 206 Partial Content | Несёт Content-Range. |
| Несколько удовлетворимых диапазонов | 206 Partial Content | multipart/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. Модуль не утверждает никаких иных внешних идентификаторов пунктов сверх поведения, проверенного его тестами.
Граничные случаи и поведение в режиме FIPS
Заголовок раздела «Граничные случаи и поведение в режиме FIPS»respondToBytes()отдаёт диапазоны над произвольными байтами, когда семантика первой страницы не нужна.- HTTP-дата-валидатор
If-Rangeтрактуется как несовпадение → полный200(клиент просто перезапрашивает). ETag— это SHA-256-хэш, используемый исключительно как сильный валидатор кэша; этот модуль не выполняет подписания или иных криптографических операций и не определяет поведения, специфичного для FIPS.
Граница публикации
Заголовок раздела «Граница публикации»Эта страница документирует только внешне наблюдаемое поведение и поддерживаемую публичную поверхность API. Внутренние пути пространств имён, вспомогательные классы, таблицы механизмов, имена файлов runbook и префиксы тикетов — вне области рассмотрения.