Khắc phục sự cố với gói NextPDF Laravel
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”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.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configTổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”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”Phát hiện và khởi động
Phần tiêu đề “Phát hiện và khởi động”| Triệu chứng | Nguyên nhân đã xác minh | Cá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-discover | Xóa gói khỏi dont-discover, hoặc đăng ký thủ công NextPdfServiceProvider trong bootstrap/providers.php |
config('nextpdf') rỗng | Cấ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 ra | Tag publish không khớp | Dù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ạy | Cài đặt hoặc bật mbstring và zlib trong php.ini |
Phân giải container
Phần tiêu đề “Phân giải container”| Triệu chứng | Nguyên nhân đã xác minh | Cách khắc phục |
|---|---|---|
app(SignerInterface::class) trả về null | Tí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ề null | nextpdf.tsa.url rỗng | Cấ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/A | nextpdf.pdfa khác null nhưng nextpdf/premium chưa được cài đặt | Cà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 Premium | Cà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 logic | Binding 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ải | Phâ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.
Công việc hàng đợi
Phần tiêu đề “Công việc hàng đợi”| Triệu chứng | Nguyên nhân đã xác minh | Cá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ẫn | Dù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 null | Là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 sai | Closure của builder không trả về tài liệu đã cấu hình | Trả 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.connection và queue.timeout; tries và backoff đò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 đó.
Phản hồi HTTP và tên tệp
Phần tiêu đề “Phản hồi HTTP và tên tệp”| Triệu chứng | Nguyên nhân đã xác minh | Cá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 định | Truyề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ệt | Bộ 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 null | Chỉ 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ách | Phả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-Length | Phả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 |
Mẫu mã — chẩn đoán
Phần tiêu đề “Mẫu mã — chẩn đoán”# 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.}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:discoverliệ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ó0mới tắt bộ nhớ đệm. Một báo cáo “bộ nhớ đệm không tắt” thường đã dùngnull. - 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.
Hiệu năng
Phần tiêu đề “Hiệu năng”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.
Ghi chú bảo mật
Phần tiêu đề “Ghi chú bảo mậ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/.
Tuân thủ
Phần tiêu đề “Tuân thủ”| Tuyên bố | Nguồn | Điều khoản | reference_id |
|---|---|---|---|
| Mục container bị thiếu sẽ ném not-found khi gọi get() | PSR-11 Container | §1.1.2 |
Xem thêm
Phần tiêu đề “Xem thêm”- /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