NextPDF Laravel パッケージのトラブルシューティング
このページでは、パッケージで観測される各障害モードを、ソースで検証済みの根本原因に対応付けます。各項目には、症状、原因、対処方法を記載しています。
インストール
「インストール」という見出しのセクションcomposer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-config概念の概要
「概念の概要」という見出しのセクション報告される問題のほとんどは、ディスカバリー、コンテナの resolve(解決)、署名、キュージョブ、HTTP ファイル名という 5 つのグループに分類されます。このパッケージは、設計上、エラーを明示的に発生させます。未構成のオプション機能は null を返し、安全でない入力は型付きの例外を発生させます。そのため、多くの場合は症状から原因を直接特定できます。
API サーフェス — 症状から原因へ
「API サーフェス — 症状から原因へ」という見出しのセクションディスカバリーとブート
「ディスカバリーとブート」という見出しのセクション| 症状 | 検証済みの原因 | 対処方法 |
|---|---|---|
| インストール後にプロバイダーが登録されない | アプリケーション側でオプトアウトに使用された設定 extra.laravel.dont-discover | 設定 dont-discover からのパッケージ削除、またはクラス NextPdfServiceProvider のファイル bootstrap/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 拡張機能が不足) | 実行時に必須の PHP 拡張機能が見つからない | 拡張機能 mbstring および zlib のインストールまたは有効化、ファイル php.ini の設定 |
コンテナ解決
「コンテナ解決」という見出しのセクション| 症状 | 検証済みの原因 | 対処方法 |
|---|---|---|
app(SignerInterface::class) が null を返す | nextpdf.signature で署名が無効、または証明書が空である | signature.enabled = true と有効な signature.certificate を設定します。署名の具象実装には nextpdf/premium をインストールします |
app(TsaClient::class) の戻り値が null | nextpdf.tsa.url が空である | 設定対象 tsa.url(必要に応じて credentials/pins も設定) |
| PDF/A バージョン型でクラスが見つからない | nextpdf.pdfa が null 以外だが、nextpdf/premium がインストールされていない | nextpdf/premium のインストール、または設定 pdfa の null への復帰 |
| e-invoice コントラクトの解決時にクラスが見つからない | バインディングは登録されているが、Premium の具象実装が存在しない | nextpdf/premium のインストール。e-invoice コントラクトは遅延解決され、Premium がない場合は最初の解決時にのみエラーになります |
| 2 つの論理操作にまたがって同じドキュメントが変更される | ドキュメントのバインディングはファクトリーである一方、解決済みのインスタンスを 1 つ再利用している | ドキュメントごとの新しい PdfDocumentInterface の解決 |
該当エントリーのないコンテナは、get() で not-found 例外をスローします(PSR-11 §1.1.2)。e-invoice コントラクトは バインド済み であるため、コンテナの 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。サブクラス化が必要なキーは tries と backoff |
パスのチェックはワーカー上の handle() 内で実行されるため、不正なパスはディスパッチ時ではなく実行時に失敗します。これは意図的なものです。キュートランスポート上でシリアライズされたペイロードは、実際に消費される場所で検証されます。
HTTP レスポンスとファイル名
「HTTP レスポンスとファイル名」という見出しのセクション| 症状 | 検証済みの原因 | 対処方法 |
|---|---|---|
ダウンロードのファイル名が、意図せず document.pdf になる | 空のファイル名が渡されたため、ファクトリーが既定値を設定している | 空でないファイル名の指定 |
| ファイル名からパスや特殊文字が失われた | ファイル名のサニタイザーが、パス区切り文字、制御文字、null バイトを除去する | ベースのファイル名のみを渡します。これは想定どおりのハードニングです |
| 非 ASCII のファイル名が、一部のクライアントで文字化けする | 非 ASCII の名前に対しては RFC 5987 の filename*= が出力されますが、古いクライアントは ASCII のフォールバックを読み取ります | 想定どおりの動作です。レガシークライアントで完全に一致させる必要がある場合は、ASCII セーフな名前を指定します |
ストリーミングレスポンスでヘッダー Content-Length が欠けている | ストリーミングレスポンスは、設計上 Content-Length を省略します(チャンク出力) | 想定どおりの動作です。length ヘッダーが必要な場合は、非ストリーミングの inline()/download() を使用します |
コードサンプル — 診断
「コードサンプル — 診断」という見出しのセクション# 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.}エッジケースと注意点
「エッジケースと注意点」という見出しのセクション- 遅延プロバイダーであるため、新規インストール直後は、対象エントリーの初回解決が行われるまで「壊れている」ように見えることがあります。正しい成功サインは、
package:discoverにパッケージが一覧表示されることです。 image_cache_mb = nullは 50 MB にフォールバックします。キャッシュを無効化できるのは0のみです。 「キャッシュが無効化されない」という報告では、通常nullが使われていました。signature.level = nullは、暗黙的に PAdES B-B にフォールバックします。「想定外の B-B」という報告では、通常 level が未設定のままになっていました。
パフォーマンス
「パフォーマンス」という見出しのセクション長時間稼働するワーカーで最初のリクエストが遅い場合、フォントレジストリがオンデマンドで解析を行っています。nextpdf.preload_fonts を設定し、ウォームアップがワーカーのブート時に一度だけ実行されるようにします。詳細については、/integrations/laravel/configuration/ と /integrations/laravel/boot-and-discovery/ を参照してください。
セキュリティに関する注意
「セキュリティに関する注意」という見出しのセクションパスとファイル名の拒否は、バグではなくセキュリティ対策です。事前にデコードしたり、チェックを緩めたりして回避しないでください。代わりに、管理されたストレージパスを経由してファイルを出力してください。/integrations/laravel/security-and-operations/. を参照してください。
| 主張 | ソース | 条項 | リファレンス ID |
|---|---|---|---|
| コンテナエントリーが欠落している場合、get() で not-found をスローする | PSR-11 コンテナ | §1.1.2 |
- /integrations/laravel/install/ — ディスカバリーと publish の手順
- /integrations/laravel/configuration/ — すべてのキーとその既定値
- /integrations/laravel/production-usage/ — DI とキューのパターン
- /integrations/laravel/security-and-operations/ — パスチェックが存在する理由