Устранение неполадок в пакете NextPDF для Laravel
Краткий обзор
Заголовок раздела «Краткий обзор»На этой странице каждый наблюдаемый сбой пакета сопоставлен с проверенной первопричиной на уровне исходного кода. В каждой записи указаны симптом, причина и способ устранения.
Установка
Заголовок раздела «Установка»composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configКонцептуальный обзор
Заголовок раздела «Концептуальный обзор»Большинство сообщений о проблемах относится к пяти группам: обнаружение, разрешение зависимостей в контейнере, подпись, задания очереди и имена файлов в ответах по протоколу передачи гипертекста (HTTP). По замыслу пакет сообщает об ошибках явно. Ненастроенные необязательные возможности возвращают null, а небезопасный ввод вызывает типизированные исключения. Обычно симптом прямо указывает на причину.
API: от симптома к причине
Заголовок раздела «API: от симптома к причине»Обнаружение и загрузка
Заголовок раздела «Обнаружение и загрузка»| Симптом | Проверенная причина | Решение |
|---|---|---|
| После установки поставщик не регистрируется | В приложении отключено обнаружение через extra.laravel.dont-discover | Удалите пакет из dont-discover или зарегистрируйте NextPdfServiceProvider вручную в bootstrap/providers.php |
config('nextpdf') пуст | Конфигурация не была объединена, потому что ни одна из заявленных привязок не была разрешена (отложенный поставщик) | Разрешите любую запись provides() или подтвердите обнаружение командой php artisan package:discover --ansi |
config/nextpdf.php не создан командой публикации | Несовпадение тега публикации | Используйте точный тег: php artisan vendor:publish --tag=nextpdf-config |
| RuntimeException: “NextPDF requires the ext-mbstring/ext-zlib PHP extension” (требуется расширение PHP) | Необходимое расширение PHP отсутствует во время выполнения | Установите или включите mbstring и zlib в php.ini |
Разрешение зависимостей в контейнере
Заголовок раздела «Разрешение зависимостей в контейнере»| Симптом | Проверенная причина | Решение |
|---|---|---|
app(SignerInterface::class) возвращает null | Подпись отключена или сертификат пуст в nextpdf.signature | Задайте signature.enabled = true и действительный signature.certificate; установите nextpdf/premium, чтобы подключить конкретную реализацию средства подписи |
app(TsaClient::class) возвращает null | nextpdf.tsa.url пуст | Настройте tsa.url (и при необходимости credentials/pins) |
| Класс типа версии PDF/A не найден | nextpdf.pdfa имеет значение не null, но nextpdf/premium не установлен | Установите nextpdf/premium или верните pdfa в значение null |
| Класс не найден при разрешении контракта электронного счёта | Привязки зарегистрированы, но конкретные реализации Premium отсутствуют | Установите nextpdf/premium; контракты электронных счётов разрешаются отложенно, и без Premium ошибка возникает только при первом разрешении |
| Один и тот же документ изменён в двух логических операциях | Привязка документа работает как фабрика; вы повторно использовали один разрешённый экземпляр | Разрешайте новый PdfDocumentInterface для каждого документа |
Контейнер без записи выбрасывает исключение “не найдено” при вызове get() (PHP Standard Recommendation 11 (PSR-11) §1.1.2). Контракты электронных счётов привязаны, поэтому has() контейнера возвращает true. Ошибка возникает из-за отсутствующей конкретной реализации Premium на этапе создания объекта, а не из-за самого контейнера.
Задания очереди
Заголовок раздела «Задания очереди»| Симптом | Проверенная причина | Решение |
|---|---|---|
InvalidArgumentException: Path traversal sequences are not allowed | Выходной путь содержит сегмент .. | Используйте абсолютный путь без обхода каталогов внутри своего каталога хранилища |
InvalidArgumentException: Stream wrappers are not allowed | В пути используется схема, например php:// | Используйте обычный путь в файловой системе |
InvalidArgumentException: Output path contains null bytes | Путь содержит нулевой байт \0 | Очистите путь перед отправкой задания |
InvalidArgumentException: Output path must end with .pdf extension | Путь не заканчивается на .pdf (без учёта регистра) | Используйте суффикс .pdf (или .PDF) |
| Задание выполняется, но файл пуст или неверен | Замыкание-построитель не вернуло настроенный документ | Верните документ из построителя; задание сохраняет возвращённое значение |
| Задание использует неверную очередь или тайм-аут | nextpdf.queue.* задан не так, как ожидалось | Задайте queue.queue, queue.connection и queue.timeout; для tries и backoff нужен подкласс |
Проверки пути выполняются внутри handle() на воркере, поэтому недопустимый путь приводит к ошибке во время выполнения, а не при отправке задания. Это сделано намеренно: воркер проверяет сериализованную полезную нагрузку очереди там, где он её потребляет.
HTTP-ответы и имена файлов
Заголовок раздела «HTTP-ответы и имена файлов»| Симптом | Проверенная причина | Решение |
|---|---|---|
Неожиданно имя загружаемого файла равно document.pdf (значение по умолчанию) | Вы передали пустое имя файла; фабрика использует значение по умолчанию | Передайте непустое имя файла |
| В имени файла пропали путь или специальные символы | Средство очистки имён файлов удаляет разделители пути, управляющие символы и нулевые байты | Передавайте только базовое имя файла; это ожидаемое усиление защиты |
| Имя файла с символами вне ASCII отображается в некоторых клиентах как кракозябры | Ответ выдаёт filename*= согласно Request for Comments 5987 (RFC 5987) для имён с символами вне ASCII; старые клиенты читают резервное имя в ASCII | Ожидаемо; укажите безопасное для ASCII имя, если для устаревшего клиента требуется точное совпадение |
Потоковый ответ не содержит Content-Length | Потоковые ответы по замыслу не содержат Content-Length (вывод по частям) | Ожидаемо; используйте непотоковые inline()/download(), если требуется заголовок длины |
Пример кода — диагностика
Заголовок раздела «Пример кода — диагностика»# Confirm the provider is discoveredphp artisan package:discover --ansi
# Inspect merged configurationphp artisan tinker --execute="dump(config('nextpdf.queue'));"<?php
declare(strict_types=1);
use NextPDF\Contracts\SignerInterface;
$signer = app(SignerInterface::class);
if ($signer === null) { // Signing not configured, or nextpdf/premium not installed. // Continue without a signature, or fail with a clear message.}Граничные случаи и подводные камни
Заголовок раздела «Граничные случаи и подводные камни»- При отложенном поставщике свежая установка может выглядеть “сломанной” до первого подходящего разрешения. Считайте наличие пакета в списке
package:discoverпризнаком успеха. - Если
image_cache_mb = null, пакет использует резервное значение 50 МБ; только0отключает кэш. Сообщение “кэш не отключается” обычно означает, что использовалиnull. - Если
signature.level = null, пакет неявно использует резервный уровень PDF Advanced Electronic Signatures (PAdES) B-B. Сообщение о “неожиданном B-B” обычно означает, что уровень оставили незаданным.
Производительность
Заголовок раздела «Производительность»Если первые запросы на долгоживущем воркере выполняются медленно, реестр шрифтов разбирается по требованию. Заполните nextpdf.preload_fonts, чтобы прогрев выполнялся один раз при загрузке воркера. Подробности см. в /integrations/laravel/configuration/ и /integrations/laravel/boot-and-discovery/.
Примечания по безопасности
Заголовок раздела «Примечания по безопасности»Отклонение путей и имён файлов — меры безопасности, а не ошибки. Не обходите их, выполняя предварительное декодирование или ослабляя проверки. Вместо этого направляйте вывод файлов через контролируемый путь хранилища. См. /integrations/laravel/security-and-operations/.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Источник | Пункт | reference_id (идентификатор ссылки) |
|---|---|---|---|
| Отсутствующая запись контейнера приводит к ошибке “не найдено” при вызове get() | PSR-11 Container (контейнер) | §1.1.2 |
См. также
Заголовок раздела «См. также»- /integrations/laravel/install/ — шаги обнаружения и публикации
- /integrations/laravel/configuration/ — каждый ключ и его значение по умолчанию
- /integrations/laravel/production-usage/ — внедрение зависимостей (DI) и шаблоны очередей
- /integrations/laravel/security-and-operations/ — зачем нужны проверки путей