Rozwiązywanie problemów z pakietem NextPDF dla Laravela
W skrócie
Dział zatytułowany „W skrócie”Ta strona pomaga powiązać każdą widoczną awarię pakietu ze zweryfikowaną przyczyną źródłową w kodzie. Każdy wpis zawiera objaw, przyczynę i rozwiązanie.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configPrzegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”Większość zgłaszanych problemów mieści się w jednej z pięciu grup: wykrywanie, rozstrzyganie w kontenerze, podpisywanie, zadania w kolejce oraz nazwy plików w protokole Hypertext Transfer Protocol (HTTP). Pakiet celowo zgłasza błędy jawnie. Nieskonfigurowane funkcje opcjonalne zwracają null, a niebezpieczne dane wejściowe powodują zgłoszenie typowanych wyjątków. Objaw zwykle prowadzi bezpośrednio do przyczyny.
Powierzchnia API — od objawu do przyczyny
Dział zatytułowany „Powierzchnia API — od objawu do przyczyny”Wykrywanie i uruchamianie
Dział zatytułowany „Wykrywanie i uruchamianie”| Objaw | Zweryfikowana przyczyna | Rozwiązanie |
|---|---|---|
| Dostawca usług nie jest zarejestrowany po instalacji | Aplikacja wyłącza wykrywanie za pomocą extra.laravel.dont-discover | Usuń pakiet z dont-discover albo zarejestruj NextPdfServiceProvider ręcznie w bootstrap/providers.php |
config('nextpdf') jest puste | Konfiguracja nie została scalona, ponieważ nie rozstrzygnięto żadnego zadeklarowanego wiązania (dostawca odroczony) | Rozstrzygnij dowolny wpis provides() lub potwierdź wykrywanie poleceniem php artisan package:discover --ansi |
Plik config/nextpdf.php nie został utworzony podczas publikowania | Użyto niezgodnego znacznika publikowania | Użyj dokładnie tego znacznika: php artisan vendor:publish --tag=nextpdf-config |
| RuntimeException: „NextPDF requires the ext-mbstring/ext-zlib PHP extension” | W środowisku uruchomieniowym brakuje jednego z wymaganych rozszerzeń Hypertext Preprocessor (PHP) | Zainstaluj lub włącz mbstring oraz zlib w php.ini |
Rozstrzyganie w kontenerze
Dział zatytułowany „Rozstrzyganie w kontenerze”| Objaw | Zweryfikowana przyczyna | Rozwiązanie |
|---|---|---|
app(SignerInterface::class) zwraca null | Podpisywanie jest wyłączone albo certyfikat w nextpdf.signature jest pusty | Ustaw signature.enabled = true oraz prawidłowy signature.certificate; zainstaluj nextpdf/premium, aby udostępnić konkretną implementację podpisującego |
app(TsaClient::class) zwraca null | nextpdf.tsa.url jest puste | Skonfiguruj tsa.url (oraz credentials/pins, jeśli są potrzebne) |
| Nie znaleziono klasy dla typu wersji PDF/A | nextpdf.pdfa nie jest null, ale nextpdf/premium nie jest zainstalowany | Zainstaluj nextpdf/premium lub przywróć pdfa do wartości null |
| Nie znaleziono klasy podczas rozstrzygania kontraktu e-faktury | Wiązania są zarejestrowane, ale brakuje konkretnych implementacji Premium | Zainstaluj nextpdf/premium; kontrakty e-faktury są rozstrzygane leniwie, więc bez Premium błąd pojawia się dopiero przy pierwszym rozstrzygnięciu |
| Ten sam dokument został zmodyfikowany w dwóch logicznych operacjach | Wiązanie dokumentu jest fabryką; jedna rozstrzygnięta instancja została użyta ponownie | Rozstrzygaj nowy PdfDocumentInterface dla każdego dokumentu |
Gdy w kontenerze brakuje danego wpisu, wywołanie get() zgłasza wyjątek not-found (PHP Standard Recommendation 11 (PSR-11) §1.1.2). Kontrakty e-faktury są powiązane, więc metoda has() kontenera zwraca true. Brak konkretnej implementacji Premium zgłasza błąd dopiero podczas konstrukcji, a nie na poziomie samego kontenera.
Zadania w kolejce
Dział zatytułowany „Zadania w kolejce”| Objaw | Zweryfikowana przyczyna | Rozwiązanie |
|---|---|---|
InvalidArgumentException: Path traversal sequences are not allowed | Ścieżka wyjściowa zawiera segment .. | Użyj ścieżki bezwzględnej bez sekwencji przejścia, wewnątrz katalogu przechowywania |
InvalidArgumentException: Stream wrappers are not allowed | Ścieżka używa schematu, takiego jak php:// | Użyj zwykłej ścieżki systemu plików |
InvalidArgumentException: Output path contains null bytes | Ścieżka zawiera bajt \0 | Oczyść ścieżkę przed wysłaniem zadania |
InvalidArgumentException: Output path must end with .pdf extension | Ścieżka nie kończy się na .pdf (bez rozróżniania wielkości liter) | Użyj rozszerzenia .pdf (lub .PDF) |
| Zadanie wykonuje się, ale plik jest pusty lub nieprawidłowy | Domknięcie konstruktora nie zwróciło skonfigurowanego dokumentu | Zwróć dokument z konstruktora; zadanie zapisuje zwróconą wartość |
| Zadanie używa niewłaściwej kolejki lub limitu czasu | nextpdf.queue.* nie jest ustawione zgodnie z oczekiwaniami | Ustaw queue.queue, queue.connection oraz queue.timeout; tries i backoff wymagają utworzenia podklasy |
Sprawdzanie ścieżki odbywa się wewnątrz handle() w procesie roboczym, więc nieprawidłowa ścieżka powoduje błąd podczas wykonywania, a nie przy wysyłaniu zadania. Jest to zamierzone: proces roboczy weryfikuje zserializowany ładunek kolejki tam, gdzie go przetwarza.
Odpowiedzi HTTP i nazwy plików
Dział zatytułowany „Odpowiedzi HTTP i nazwy plików”| Objaw | Zweryfikowana przyczyna | Rozwiązanie |
|---|---|---|
Nazwa pobieranego pliku ma niespodziewanie wartość document.pdf | Przekazano pustą nazwę pliku; fabryka używa wartości domyślnej | Przekaż niepustą nazwę pliku |
| Nazwa pliku utraciła ścieżkę lub znaki specjalne | Mechanizm czyszczenia nazw plików usuwa separatory ścieżek, znaki sterujące i bajty zerowe | Przekaż tylko bazową nazwę pliku; to oczekiwane zabezpieczenie |
| Nazwa pliku spoza ASCII w niektórych klientach wyświetla się jako krzaki (mojibake) | Odpowiedź emituje Request for Comments 5987 (RFC 5987) filename*= dla nazw spoza ASCII; starsze klienty odczytują wartość zapasową w ASCII | Zachowanie oczekiwane; podaj nazwę bezpieczną dla ASCII, jeśli starszy klient ma wyświetlić ją dokładnie |
Odpowiedź strumieniowa nie ma nagłówka Content-Length | Odpowiedzi strumieniowe z założenia pomijają Content-Length (wyjście fragmentowane) | Zachowanie oczekiwane; użyj niestrumieniowych inline()/download(), jeśli wymagany jest nagłówek długości |
Przykładowy kod — diagnostyka
Dział zatytułowany „Przykładowy kod — diagnostyka”# 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.}Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”- Gdy dostawca jest odroczony, świeża instalacja może wyglądać na „uszkodzoną” aż do pierwszego istotnego rozstrzygnięcia. Potraktuj pojawienie się pakietu w wyniku
package:discoverjako sygnał powodzenia. - Gdy
image_cache_mb = null, pakiet przyjmuje wartość zapasową 50 MB; tylko0wyłącza pamięć podręczną. Zgłoszenie „pamięć podręczna się nie wyłącza” zwykle oznaczało użycienull. - Gdy
signature.level = null, pakiet niejawnie przyjmuje wartość zapasową PDF Advanced Electronic Signatures (PAdES) B-B. Zgłoszenie „nieoczekiwany B-B” zwykle oznaczało, że poziom pozostawiono nieustawiony.
Wydajność
Dział zatytułowany „Wydajność”Jeśli pierwsze żądania w długo działającym procesie roboczym są wolne, oznacza to, że rejestr czcionek analizuje dane na żądanie. Wypełnij nextpdf.preload_fonts, aby rozgrzewka wykonała się jeden raz przy uruchomieniu procesu roboczego. Szczegóły znajdziesz w /integrations/laravel/configuration/ oraz /integrations/laravel/boot-and-discovery/.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”Odrzucanie ścieżek i nazw plików to mechanizmy zabezpieczające, a nie błędy. Nie omijaj ich przez wstępne dekodowanie ani rozluźnianie kontroli. Zamiast tego kieruj zapis plików przez kontrolowaną ścieżkę przechowywania. Zobacz /integrations/laravel/security-and-operations/.
Zgodność
Dział zatytułowany „Zgodność”| Stwierdzenie | Źródło | Klauzula | reference_id |
|---|---|---|---|
| Brak wpisu w kontenerze powoduje not-found przy get() | PSR-11 Container | §1.1.2 |
Zobacz też
Dział zatytułowany „Zobacz też”- /integrations/laravel/install/ — kroki wykrywania i publikowania
- /integrations/laravel/configuration/ — każdy klucz i jego wartość domyślna
- /integrations/laravel/production-usage/ — wzorce wstrzykiwania zależności (DI) i kolejek
- /integrations/laravel/security-and-operations/ — dlaczego istnieją kontrole ścieżek