在 CodeIgniter 4 中排查 NextPDF 问题
下列每个症状都对应软件包或 Framework(框架)源代码中已验证的成因。每一项也都附有具体的修正方式。
发现与 resolve(解析)
标题为“发现与 resolve(解析)”的章节Services::pdfDocument() 返回 null
标题为“Services::pdfDocument() 返回 null”的章节解析某项服务时,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。请把这两个项目都恢复回去。
pdf() 或 pdf_document() 未定义
标题为“pdf() 或 pdf_document() 未定义”的章节这些 helper 通过两条途径注册:软件包的 Composer files 自动加载项目,以及软件包的 Registrar。出现未定义函数的错误,表示 files 项目没有载入。
- 请执行
composer dump-autoload,以重建files自动加载清单。 - 请确认
nextpdf/codeigniter有出现在vendor/composer/autoload_files.php之中。 - 暂时的做法是直接调用
Services::pdf(false)或Services::pdfDocument(false)。这些 helper 只是这些调用的薄封装层。
.env 覆盖值被忽略
标题为“.env 覆盖值被忽略”的章节解析覆盖值时,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”的章节字体注册表会在每个进程中验证一次 mbstring 与 zlib。它会抛出这个错误,并附上缺少的扩展名称。请在运行时使用的 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-Options、X-Frame-Options、Content-Security-Policy、X-Robots-Tag,以及 Referrer-Policy。如果它们在客户端不见了,表示有 proxy 或应用程序在下游把它们移除或覆盖了。请分别在反向 proxy 前后检查响应。
QueueException:推送作业时出现
标题为“QueueException:推送作业时出现”的章节队列会将推送的作业名称与 Config\Queue::$jobHandlers 的键进行比对,并拒绝任何未注册的名称。请用名称键注册该作业,然后推送该名称:
public array $jobHandlers = ['generate-pdf' => GeneratePdfJob::class];
// dispatch\service('queue')->push('pdf-queue', 'generate-pdf', [...]);把 GeneratePdfJob::class 作为作业名称来推送会失败。第二个参数是名称键,不是类字符串。
InvalidArgumentException:由作业抛出
标题为“InvalidArgumentException:由作业抛出”的章节作业在开始执行任何工作之前会先验证它的负载。已验证的拒绝场景与对应消息如下:
| 成因 | 消息片段 |
|---|---|
builder 缺少、为空,或不是字符串 | non-empty static callable string |
builder 不属于 App\PdfBuilders | not allowed |
builder 符合模式但不可调用 | not a valid callable |
outputPath 缺少或为空 | non-empty string |
outputPath 不位于 WRITEPATH/pdfs/ | outside of allowed directory |
outputPath 的结尾不是 .pdf | must end with .pdf |
请修正负载,让 builder 是一个 App\PdfBuilders\<Class>::<method> 静态 callable。并确认输出路径会解析到 WRITEPATH/pdfs/ 之内,且带有 .pdf 扩展名。
class … BaseJob not found
标题为“class … BaseJob not found”的章节codeigniter4/queue 是软件包的开发环境专用依赖包。运行 worker 的应用程序必须直接引入它:
composer require codeigniter4/queuecomposer 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/ — 发现顺序。