Bỏ qua để đến nội dung

Khắc phục sự cố với gói NextPDF Laravel

Hãy dùng trang này để đối chiếu từng lỗi có thể quan sát trong gói với nguyên nhân gốc rễ đã được xác minh ở cấp mã nguồn. Mỗi mục nêu rõ triệu chứng, nguyên nhân và cách khắc phục.

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

Hầu hết vấn đề được báo cáo thuộc năm nhóm: phát hiện, phân giải container, ký, công việc hàng đợi và tên tệp Hypertext Transfer Protocol (HTTP). Gói này được thiết kế để báo lỗi rõ ràng. Các tính năng tùy chọn chưa cấu hình sẽ trả về null, còn dữ liệu đầu vào không an toàn sẽ phát sinh ngoại lệ có kiểu. Triệu chứng thường chỉ thẳng tới nguyên nhân.

Bề mặt API — triệu chứng đến nguyên nhân

Phần tiêu đề “Bề mặt API — triệu chứng đến nguyên nhân”
Triệu chứngNguyên nhân đã xác minhCách khắc phục
Provider không được đăng ký sau khi cài đặtỨng dụng đã tắt phát hiện bằng extra.laravel.dont-discoverXóa gói khỏi dont-discover, hoặc đăng ký thủ công NextPdfServiceProvider trong bootstrap/providers.php
config('nextpdf') rỗngCấu hình không được hợp nhất vì chưa có binding được quảng bá nào được phân giải (deferred provider)Phân giải bất kỳ mục provides() nào, hoặc xác nhận phát hiện bằng php artisan package:discover --ansi
config/nextpdf.php không được lệnh publish tạo raTag publish không khớpDùng đúng tag: php artisan vendor:publish --tag=nextpdf-config
RuntimeException: “NextPDF requires the ext-mbstring/ext-zlib PHP extension”Thiếu phần mở rộng Hypertext Preprocessor (PHP) bắt buộc khi chạyCài đặt hoặc bật mbstringzlib trong php.ini
Triệu chứngNguyên nhân đã xác minhCách khắc phục
app(SignerInterface::class) trả về nullTính năng ký bị tắt, hoặc chứng chỉ rỗng trong nextpdf.signatureĐặt signature.enabled = true và một signature.certificate hợp lệ; cài đặt nextpdf/premium để cung cấp lớp triển khai cụ thể của signer
app(TsaClient::class) trả về nullnextpdf.tsa.url rỗngCấu hình tsa.url (và credentials/pins khi cần)
Không tìm thấy lớp cho một kiểu phiên bản PDF/Anextpdf.pdfa khác null nhưng nextpdf/premium chưa được cài đặtCài đặt nextpdf/premium, hoặc đặt lại pdfa về null
Không tìm thấy lớp khi phân giải một contract hóa đơn điện tửCác binding đã được đăng ký, nhưng thiếu các lớp triển khai cụ thể của PremiumCài đặt nextpdf/premium; các contract hóa đơn điện tử được phân giải lười (lazy) và chỉ thất bại ở lần phân giải đầu tiên khi không có Premium
Cùng một tài liệu bị thay đổi qua hai thao tác logicBinding của tài liệu là một factory; bạn đã tái sử dụng một thực thể đã phân giảiPhân giải một PdfDocumentInterface mới cho mỗi tài liệu

Một container không có mục tương ứng sẽ ném ngoại lệ not-found khi gọi get() (PHP Standard Recommendation 11 (PSR-11) §1.1.2). Các contract hóa đơn điện tử đã được bind, nên has() của container trả về true. Lỗi phát sinh tại thời điểm khởi tạo là do thiếu lớp triển khai cụ thể của Premium, chứ không phải do bản thân container.

Triệu chứngNguyên nhân đã xác minhCách khắc phục
InvalidArgumentException: Path traversal sequences are not allowedĐường dẫn đầu ra có chứa .. dưới dạng một đoạn đường dẫnDùng một đường dẫn tuyệt đối, không có chuỗi traversal, nằm trong thư mục lưu trữ của bạn
InvalidArgumentException: Stream wrappers are not allowedĐường dẫn dùng một scheme như php://Dùng một đường dẫn hệ thống tệp thông thường
InvalidArgumentException: Output path contains null bytesĐường dẫn có chứa \0 — một byte nullLàm sạch đường dẫn trước khi dispatch
InvalidArgumentException: Output path must end with .pdf extensionĐường dẫn không kết thúc bằng .pdf (không phân biệt chữ hoa chữ thường)Dùng hậu tố .pdf (hoặc .PDF)
Công việc chạy nhưng tệp rỗng hoặc saiClosure của builder không trả về tài liệu đã cấu hìnhTrả về tài liệu từ builder; công việc sẽ lưu giá trị được trả về
Công việc dùng sai hàng đợi hoặc thời gian chờnextpdf.queue.* không được đặt như mong đợiĐặt queue.queue, queue.connectionqueue.timeout; triesbackoff đòi hỏi phải tạo lớp con

Các kiểm tra đường dẫn chạy bên trong handle() trên worker, nên đường dẫn sai sẽ thất bại trong lúc thực thi, chứ không phải khi dispatch. Đây là chủ ý: worker xác thực payload hàng đợi đã tuần tự hóa ngay tại nơi nó tiêu thụ payload đó.

Triệu chứngNguyên nhân đã xác minhCách khắc phục
Tên tệp tải xuống là document.pdf một cách bất ngờBạn đã truyền một tên tệp rỗng; factory dùng giá trị mặc địnhTruyền một tên tệp không rỗng
Tên tệp bị mất phần đường dẫn hoặc các ký tự đặc biệtBộ làm sạch tên tệp loại bỏ các dấu phân tách đường dẫn, ký tự điều khiển và byte nullChỉ truyền tên tệp cơ sở; biện pháp tăng cường bảo mật này là điều dự kiến
Tên tệp không phải ASCII hiển thị thành mojibake trên một số ứng dụng kháchPhản hồi phát ra Request for Comments 5987 (RFC 5987) filename*= cho tên không phải ASCII; các ứng dụng khách cũ sẽ đọc bản dự phòng ASCIIĐây là điều dự kiến; hãy cung cấp tên an toàn với ASCII nếu một ứng dụng khách cũ buộc phải khớp chính xác
Phản hồi dạng luồng không có Content-LengthPhản hồi dạng luồng được thiết kế để bỏ qua Content-Length (đầu ra theo chunk)Đây là điều dự kiến; dùng inline()/download() dạng không phải luồng nếu cần header độ dài
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.
}

Trường hợp ngoại lệ & điểm cần lưu ý

Phần tiêu đề “Trường hợp ngoại lệ & điểm cần lưu ý”
  • Với deferred provider, một bản cài đặt mới có thể trông như “bị hỏng” cho đến lần phân giải liên quan đầu tiên. Hãy coi việc package:discover liệt kê gói là tín hiệu thành công.
  • Khi image_cache_mb = null, gói sẽ chuyển về 50 MB; chỉ có 0 mới tắt bộ nhớ đệm. Một báo cáo “bộ nhớ đệm không tắt” thường đã dùng null.
  • Khi signature.level = null, gói âm thầm chuyển về PDF Advanced Electronic Signatures (PAdES) B-B. Một báo cáo “B-B ngoài dự kiến” thường là do mức này chưa được đặt.

Nếu các yêu cầu đầu tiên trên một worker tồn tại lâu dài chạy chậm, font registry đang phân tích theo nhu cầu. Hãy điền nextpdf.preload_fonts để quá trình khởi động ấm (warmup) chạy một lần khi worker khởi động. Xem /integrations/laravel/configuration/ và /integrations/laravel/boot-and-discovery/ để biết chi tiết.

Việc từ chối đường dẫn và tên tệp là các biện pháp kiểm soát bảo mật, không phải lỗi. Đừng tìm cách lách chúng bằng cách giải mã trước hoặc nới lỏng các kiểm tra. Thay vào đó, hãy định tuyến đầu ra tệp qua một đường dẫn lưu trữ được kiểm soát. Xem /integrations/laravel/security-and-operations/.

Tuyên bốNguồnĐiều khoảnreference_id
Mục container bị thiếu sẽ ném not-found khi gọi get()PSR-11 Container§1.1.2
  • /integrations/laravel/install/ — các bước phát hiện và publish
  • /integrations/laravel/configuration/ — mọi khóa và giá trị mặc định tương ứng
  • /integrations/laravel/production-usage/ — dependency injection (DI) và các mẫu hàng đợi
  • /integrations/laravel/security-and-operations/ — lý do các kiểm tra đường dẫn tồn tại