跳到內容

排解 CodeIgniter 4 上的 NextPDF 問題

下列每個症狀,都對應到套件或 Framework(框架)原始碼中已驗證的成因。每一項也都提供具體修正方式。

在解析服務時,CodeIgniter 會掃描已探索到的 Config\Services 類別,尋找相符的方法。回傳 null 表示 framework 從未探索到套件的 Services 類別。

成因與對應修正如下:

  • 自動探索已停用。 主機應用程式可能設定了 Config\Modules::$discoverInComposer = false。若是如此,請把 nextpdf/codeigniter 加進 $composerPackages['only']。只有當這個旗標為 true 時,探索才會掃描 Composer 套件。
  • 自動載入器已過時。 Composer 會把命名空間前綴 NextPDF\CodeIgniter\ 對映到它的基底目錄。過時的 classmap 會讓類別無法被找到(PSR-4 §x1.x3)。請執行 composer dump-autoload
  • $aliases 清單被精簡了。 探索只會針對 Config\Modules::$aliases 中的項目執行。套件需要 services,helper 則需要 registrars。請把這兩個項目都還原回去。

這些 helper 會透過兩種途徑註冊:套件的 Composer files 自動載入項目,以及套件的 Registrar。出現未定義函式錯誤,表示 files 項目尚未載入。

  • 請執行 composer dump-autoload,重建 files 自動載入清單。
  • 請確認 nextpdf/codeigniter 有出現在 vendor/composer/autoload_files.php 之中。
  • 暫時可直接呼叫 Services::pdf(false)Services::pdfDocument(false)。這些 helper 只是上述呼叫的薄包裝層。

解析覆寫值時,BaseConfig 會以小寫的短類別名稱作為前綴。這個類別是 NextPdf,所以前綴是 nextpdf。它不是 nextPdf,也不是 NextPdf

  • 請使用 nextpdf.fontsPath,不要使用 nextPdf.fontsPath
  • 以小數點指定巢狀鍵:nextpdf.signature.certificate
  • 完整限定的形式 NextPDF\CodeIgniter\Config\NextPdf.fontsPath 也可以使用。

當你擴充 NextPdf 類別並指派不完整的陣列時,整個陣列會被取代。因此,你覆寫的陣列務必提供其中每一個鍵。完整陣列範例請見 /integrations/codeigniter/configuration/.

RuntimeException: NextPDF requires the ext-… PHP extension

標題為「RuntimeException: NextPDF requires the ext-… PHP extension」的區段

字型登錄會在每個程序中各驗證一次 mbstringzlib。它會拋出這個錯誤,並附上缺少的擴充功能名稱。請在執行時使用的 PHP 中安裝或啟用所指名的擴充功能。接著重新啟動 worker 或 PHP-FPM pool。

RuntimeException: NextPdf fontsPath contains invalid characters

標題為「RuntimeException: NextPdf fontsPath contains invalid characters」的區段

字型登錄會拒絕這類 fontsPath:內含 stream wrapper(://)或 null 位元組。請把 fontsPath 設成單純的檔案系統路徑。不要讓它指向 php://phar:// 或類似的包裝路徑。

PdfResponse 會淨化檔名。已驗證的行為如下:

  • 空白或只含空白字元的檔名會變成 document.pdf
  • 沒有 .pdf(或 .PDF)副檔名的名稱,會被加上 .pdf。既有的 .PDF 會原樣保留。
  • 非 ASCII 的名稱會產生一個 ASCII 後備值,以及一個 RFC 5987 filename*=UTF-8''… 參數,因此現代瀏覽器會顯示原始名稱。這是預期行為,不是 bug。
  • 路徑分隔符號、null 位元組,以及 CR/LF 都會被去除。

每個 PdfResponse 回應都會帶有 X-Content-Type-OptionsX-Frame-OptionsContent-Security-PolicyX-Robots-Tag,以及 Referrer-Policy。如果它們在用戶端消失,表示有 proxy 或下游應用程式移除或覆寫了它們。請在你的反向 proxy 前後都檢查一次回應。

佇列會把推送的工作名稱與 Config\Queue::$jobHandlers 的鍵做比對,並拒絕任何未註冊的名稱。請以名稱鍵註冊該工作,然後推送那個名稱:

app/Config/Queue.php
public array $jobHandlers = ['generate-pdf' => GeneratePdfJob::class];
// dispatch
\service('queue')->push('pdf-queue', 'generate-pdf', [...]);

GeneratePdfJob::class 當成工作名稱推送會失敗。第二個引數是名稱鍵,不是類別字串。

工作在開始任何作業之前會先驗證它的酬載。已驗證的拒絕情形與對應訊息如下:

成因訊息片段
builder 缺少、為空,或不是字串non-empty static callable string
builder 不屬於 App\PdfBuildersnot allowed
builder 格式看似正確但不可呼叫not a valid callable
outputPath 缺少或為空non-empty string
outputPath 不位於 WRITEPATH/pdfs/outside of allowed directory
outputPath 的結尾不是 .pdfmust end with .pdf

請修正酬載,讓 builder 成為一個 App\PdfBuilders\<Class>::<method> 靜態 callable。並確認輸出路徑會解析到 WRITEPATH/pdfs/ 之內,且帶有 .pdf 副檔名。

codeigniter4/queue 是套件開發環境專用的相依套件。執行 worker 的應用程式必須直接引入它:

Terminal window
composer require codeigniter4/queue
  • composer show nextpdf/codeigniter — 確認套件已成功解析。
  • composer dump-autoload — 重建探索與 helper 的自動載入。
  • php spark routes — 確認你的 PDF 路由已註冊。
  • 最快的探索檢查方式,是寫一個控制器來呼叫 Services::pdfDocument(false),並斷言其結果是一個 Document
  • 類別到路徑的對映 — 與探索失敗相關(PSR-4 Autoloader §x1.x3)。
  • /integrations/codeigniter/install/ — 探索需求。
  • /integrations/codeigniter/configuration/ — .env 前綴與陣列覆寫規則。
  • /integrations/codeigniter/production-usage/ — 正確的佇列註冊方式。
  • /integrations/codeigniter/boot-and-discovery/ — 探索順序。