跳转到内容

在 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/ — 发现顺序。