콘텐츠로 이동

NextPDF Laravel 패키지 문제 해결

이 페이지는 패키지에서 관찰되는 각 실패 모드를 소스에서 검증한 근본 원인과 연결합니다. 각 항목에는 증상, 원인, 해결 방법을 명시합니다.

Terminal window
composer require nextpdf/laravel
php artisan vendor:publish --tag=nextpdf-config

보고된 문제의 대부분은 발견, 컨테이너 해석, 서명, 큐 작업, HTTP 파일 이름이라는 다섯 그룹으로 나뉩니다. 이 패키지는 설계상 실패가 명확하게 드러나도록 합니다. 구성되지 않은 선택적 기능은 null을 반환하고, 안전하지 않은 입력은 형식화된 예외를 발생시킵니다. 따라서 증상은 대개 원인을 직접 가리킵니다.

증상검증된 원인해결 방법
설치 후 프로바이더가 등록되지 않음애플리케이션이 extra.laravel.dont-discover로 해당 패키지를 옵트아웃함패키지를 dont-discover에서 제거하거나, NextPdfServiceProviderbootstrap/providers.php에 수동으로 등록합니다
config('nextpdf')가 비어 있음선언된 바인딩이 해석되지 않아 구성이 병합되지 않음(지연 프로바이더)해석해야 할 항목은 provides()에 포함된 항목 중 하나입니다. 발견을 확인하려면 php artisan package:discover --ansi
config/nextpdf.php가 publish로 생성되지 않음publish 태그 불일치정확한 태그를 사용합니다: php artisan vendor:publish --tag=nextpdf-config
RuntimeException: “NextPDF requires the ext-mbstring/ext-zlib PHP extension” 발생필수 PHP 확장이 런타임에 누락됨활성화해야 할 확장은 mbstringzlib입니다. 설치하거나 php.ini에서 활성화합니다
증상검증된 원인해결 방법
app(SignerInterface::class)null을 반환함nextpdf.signature에서 서명이 비활성화되었거나 인증서가 비어 있음signature.enabled = true와 유효한 signature.certificate를 설정합니다. 서명자 구상 구현을 사용하려면 nextpdf/premium을 설치합니다
app(TsaClient::class)가 반환하는 값이 nullnextpdf.tsa.url이 비어 있음구성해야 할 항목은 tsa.url입니다(필요에 따라 credentials/pins도)
PDF/A 버전 유형에 대한 클래스를 찾을 수 없음nextpdf.pdfa가 null이 아니지만 nextpdf/premium이 설치되지 않음설치해야 할 패키지는 nextpdf/premium입니다. 또는 pdfa 값을 null로 다시 설정합니다
전자 인보이스 계약을 해석하는 중 클래스를 찾을 수 없음바인딩은 등록되었지만 Premium 구상 구현이 없음설치해야 할 패키지는 nextpdf/premium입니다. 전자 인보이스 계약은 지연 해석되어 Premium이 없으면 처음 해석할 때만 오류가 발생합니다
두 논리적 작업에서 동일한 문서가 변경됨문서 바인딩은 팩토리인데, 해석된 인스턴스 하나를 재사용함문서마다 새 PdfDocumentInterface를 해석합니다

컨테이너에 항목이 없으면 get()에서 not-found 예외가 발생합니다(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입니다. triesbackoff는 서브클래싱이 필요합니다

경로 검사는 워커의 handle() 내부에서 실행되므로, 잘못된 경로는 디스패치 시점이 아니라 실행 시점에 실패합니다. 이는 의도된 동작입니다. 큐 전송을 위해 직렬화된 페이로드는 소비되는 지점에서 검증됩니다.

증상검증된 원인해결 방법
다운로드 파일 이름이 예상과 달리 document.pdf빈 파일 이름이 전달되어 팩토리가 기본값을 적용함비어 있지 않은 파일 이름을 전달합니다
파일 이름에서 경로나 특수 문자가 사라짐파일 이름 정제기가 경로 구분자, 제어 문자, null 바이트를 제거함기본 파일 이름만 전달합니다. 이는 의도된 강화입니다
일부 클라이언트에서 비 ASCII 파일 이름이 깨져 보임비 ASCII 이름에는 RFC 5987 filename*=가 생성되며, 구형 클라이언트는 ASCII 대체값을 읽습니다의도된 동작입니다. 레거시 클라이언트에서 정확한 일치가 필요하다면 ASCII로 안전한 이름을 제공합니다
스트리밍 응답에 Content-Length 헤더가 없음스트리밍 응답은 설계상 Content-Length를 생략합니다(청크 출력)의도된 동작입니다. 길이 헤더가 필요하면 스트리밍이 아닌 inline()/download()를 사용합니다
Terminal window
# Confirm the provider is discovered
php artisan package:discover --ansi
# Inspect merged configuration
php artisan tinker --execute="dump(config('nextpdf.queue'));"
resource: src/Laravel/NextPdfServiceProvider.php (null-check pattern)
<?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 MB로 대체되며, 0만 캐시를 비활성화합니다. “캐시가 비활성화되지 않음”이라는 보고는 대개 null을 사용한 경우입니다.
  • signature.level = null은 조용히 PAdES B-B로 대체됩니다. “예상치 못한 B-B” 보고는 대개 레벨을 설정하지 않은 경우입니다.

장기 실행 워커에서 첫 요청이 느리다면, 글꼴 레지스트리가 온디맨드로 구문 분석을 수행하고 있기 때문입니다. nextpdf.preload_fonts를 채워 두면 워커 부팅 시 워밍업이 한 번 실행됩니다. 자세한 내용은 /integrations/laravel/configuration/ 및 /integrations/laravel/boot-and-discovery/를 참고하세요.

경로 및 파일 이름 거부는 버그가 아니라 보안 통제입니다. 사전 디코딩하거나 검사를 완화해 이를 우회하지 마세요. 대신 파일 출력을 통제된 스토리지 경로를 통해 라우팅하세요. 자세한 내용은 /integrations/laravel/security-and-operations/를 참고하세요.

주장출처조항reference_id (참조 ID)
컨테이너 항목이 없으면 get()에서 not-found가 발생함PSR-11 Container (컨테이너 규격)§1.1.2
  • /integrations/laravel/install/ — 발견 및 publish 단계
  • /integrations/laravel/configuration/ — 모든 키와 기본값
  • /integrations/laravel/production-usage/ — DI 및 큐 패턴
  • /integrations/laravel/security-and-operations/ — 경로 검사가 존재하는 이유