Risoluzione dei problemi del pacchetto Laravel NextPDF
In breve
Sezione intitolata “In breve”Questa pagina riconduce ogni modalità di errore osservabile del pacchetto alla relativa causa radice verificata nel codice sorgente. Ogni voce riporta sintomo, causa e soluzione.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configPanoramica concettuale
Sezione intitolata “Panoramica concettuale”La maggior parte dei problemi segnalati rientra in cinque gruppi: discovery, risoluzione del container, firma, job in coda e nomi file HTTP. Per scelta progettuale, il pacchetto segnala gli errori in modo esplicito. Le funzionalità opzionali non configurate restituiscono null e gli input non sicuri generano eccezioni tipizzate. Di conseguenza, il sintomo indica solitamente in modo diretto la causa.
Superficie API — dal sintomo alla causa
Sezione intitolata “Superficie API — dal sintomo alla causa”Discovery e avvio
Sezione intitolata “Discovery e avvio”| Sintomo | Causa verificata | Soluzione |
|---|---|---|
| Provider non registrato dopo l’installazione | L’applicazione ha disattivato la discovery tramite extra.laravel.dont-discover | Rimuovere il pacchetto da dont-discover oppure registrare NextPdfServiceProvider manualmente in bootstrap/providers.php |
config('nextpdf') è vuoto | Configurazione non unita perché nessun binding dichiarato è stato risolto (provider deferred) | Risolvere una qualsiasi voce di provides() oppure verificare la discovery con php artisan package:discover --ansi |
config/nextpdf.php non creato dalla pubblicazione | Tag di pubblicazione non corrispondente | Usare esattamente questo tag: php artisan vendor:publish --tag=nextpdf-config |
| RuntimeException: “NextPDF requires the ext-mbstring/ext-zlib PHP extension” | Un’estensione PHP richiesta è assente in fase di runtime | Installare o abilitare mbstring e zlib in php.ini |
Risoluzione del container
Sezione intitolata “Risoluzione del container”| Sintomo | Causa verificata | Soluzione |
|---|---|---|
app(SignerInterface::class) restituisce null | Firma disabilitata o certificato vuoto in nextpdf.signature | Impostare signature.enabled = true e un signature.certificate valido; installare nextpdf/premium per la classe concreta del signer |
app(TsaClient::class) restituisce null | nextpdf.tsa.url è vuoto | Configurare tsa.url (e credentials/pins secondo necessità) |
| Class-not-found per un tipo di versione PDF/A | nextpdf.pdfa non è null ma nextpdf/premium non è installato | Installare nextpdf/premium oppure reimpostare pdfa su null |
| Class-not-found durante la risoluzione di un contract per la fatturazione elettronica | I binding sono registrati, ma le classi concrete Premium sono assenti | Installare nextpdf/premium; i contract per la fatturazione elettronica vengono risolti in modo lazy e generano un errore solo alla prima risoluzione in assenza di Premium |
| Lo stesso documento viene modificato in due operazioni logiche distinte | Il binding del documento è una factory; è stata riutilizzata un’unica istanza già risolta | Risolvere un nuovo PdfDocumentInterface per ogni documento |
Quando il container non contiene la voce, get() genera un’eccezione not-found (PSR-11 §1.1.2). I contract per la fatturazione elettronica sono associati, quindi il metodo has() del container restituisce true. L’errore emerge dalla classe concreta Premium mancante durante la costruzione, non dal container stesso.
Job in coda
Sezione intitolata “Job in coda”| Sintomo | Causa verificata | Soluzione |
|---|---|---|
InvalidArgumentException: Path traversal sequences are not allowed | Il percorso di output contiene un .. come segmento | Usare un percorso assoluto, privo di traversal, all’interno della directory di storage |
InvalidArgumentException: Stream wrappers are not allowed | Il percorso corrisponde a uno schema come php:// | Usare un semplice percorso di filesystem |
InvalidArgumentException: Output path contains null bytes | Il percorso contiene un byte \0 | Sanificare il percorso prima del dispatch |
InvalidArgumentException: Output path must end with .pdf extension | Il percorso non termina con .pdf (senza distinzione tra maiuscole e minuscole) | Usare un suffisso .pdf (o .PDF) |
| Il job viene eseguito ma il file è vuoto o errato | La closure del builder non ha restituito il documento configurato | Restituire il documento dal builder; il valore restituito è ciò che viene salvato |
| Il job usa la coda o il timeout errati | nextpdf.queue.* non è impostato come previsto | Impostare queue.queue, queue.connection, queue.timeout; tries e backoff richiedono il subclassing |
I controlli sul percorso vengono eseguiti dentro handle() sul worker, quindi un percorso errato fallisce in fase di esecuzione, non al dispatch. Si tratta di una scelta intenzionale: il payload serializzato sul transport della coda viene convalidato nel punto in cui viene consumato.
Risposte HTTP e nomi file
Sezione intitolata “Risposte HTTP e nomi file”| Sintomo | Causa verificata | Soluzione |
|---|---|---|
Il nome file del download risulta document.pdf in modo inatteso | È stato passato un nome file vuoto; la factory applica il valore predefinito | Passare un nome file non vuoto |
| Il nome file non contiene più il percorso o i caratteri speciali | Il sanitizer del nome file rimuove i separatori di percorso, i caratteri di controllo e i byte null | Passare solo il nome file di base; si tratta di una misura di hardening prevista |
| Il nome file non ASCII mostra mojibake in alcuni client | Per i nomi non ASCII viene emesso RFC 5987 filename*=; i client meno recenti leggono il fallback ASCII | Comportamento previsto; fornire un nome ASCII-safe se serve una corrispondenza esatta su un client legacy |
La risposta in streaming non ha Content-Length | Le risposte in streaming omettono Content-Length per scelta progettuale (output chunked) | Comportamento previsto; usare inline()/download() non in streaming se è richiesto un header di lunghezza |
Esempio di codice — diagnostica
Sezione intitolata “Esempio di codice — diagnostica”# 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.}Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Il provider deferred fa sì che una nuova installazione possa apparire «non funzionante» fino alla prima risoluzione pertinente. Il segnale corretto di esito positivo è la presenza del pacchetto nell’elenco di
package:discover. image_cache_mb = nullricade su 50 MB; solo0disabilita la cache. Una segnalazione di «cache non disabilitata» di solito deriva dall’uso dinull.signature.level = nullricade silenziosamente su PAdES B-B. Una segnalazione di «B-B inatteso» di solito deriva da un livello lasciato non impostato.
Prestazioni
Sezione intitolata “Prestazioni”Se le prime richieste su un worker a lunga durata sono lente, il registro dei font sta eseguendo il parsing su richiesta. Valorizzare nextpdf.preload_fonts in modo che il warmup venga eseguito una sola volta all’avvio del worker. Per i dettagli, vedere /integrations/laravel/configuration/ e /integrations/laravel/boot-and-discovery/.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Il rifiuto di percorsi e nomi file è un controllo di sicurezza, non un bug. Non aggirarlo pre-decodificando o allentando i controlli. Instradare invece l’output dei file attraverso un percorso di storage controllato. Vedere /integrations/laravel/security-and-operations/.
Conformità
Sezione intitolata “Conformità”| Asserzione | Fonte | Clausola | reference_id |
|---|---|---|---|
| Una voce mancante nel container genera not-found su get() | PSR-11 Container | §1.1.2 |
Vedere anche
Sezione intitolata “Vedere anche”- /integrations/laravel/install/ — procedura di discovery e pubblicazione
- /integrations/laravel/configuration/ — ogni chiave e il relativo valore predefinito
- /integrations/laravel/production-usage/ — pattern di DI e coda
- /integrations/laravel/security-and-operations/ — perché esistono i controlli sui percorsi