检查现有签章,理解信任边界
本 recipe(示例)使用 Core inspector 检测 PDF 是否带有签章,并明确边界:检测到签章并不等于已经验证该签章。密码学验证、信任路径验证与撤销检查由 Premium 或外部方案负责。
先决条件
标题为“先决条件”的章节- 已安装 Core:
composer require nextpdf/core:^3。 - 一份要检查的 PDF 文件。
- 读取 PDF 字节。
- 创建一个
Inspector并调用inspect()。 - 读取
InspectResult::$hasSigned。true表示文件中存在签章字典。 - 读取
InspectResult::$isEncrypted以及风险标志,作为辅助上下文。 - 将文件交给验证器,由验证器做出密码学判定。inspector 报告的是是否存在签章,而不是签章是否有效。
下图说明两件事:本 recipe 要厘清的边界是 存在不等于有效;真正的验证还必须完成完整的检查项。
完整示例
标题为“完整示例”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\Inspector;use NextPDF\Inspect\InspectConfig;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');if ($pdfData === false || $pdfData === '') { fwrite(STDERR, "Cannot read incoming.pdf\n"); exit(1);}
$inspector = new Inspector();
// InspectConfig::quick() selects InspectDepth::Quick. This is the only// depth that runs offline: a default Inspector has no Spectrum sidecar,// and without a sidecar Quick is the sole path that returns a result.// Standard and Full require the sidecar (see the SIDECAR-001 edge case).$result = $inspector->inspect( $pdfData, InspectConfig::quick(),);
// hasSigned reports the PRESENCE of a signature dictionary.// It does NOT mean the signature verifies.if ($result->hasSigned) { echo "A signature is present in incoming.pdf\n"; echo "Encrypted: " . ($result->isEncrypted ? 'yes' : 'no') . "\n"; echo "Next step: run a cryptographic verifier before trusting it.\n";} else { echo "No signature found in incoming.pdf\n";}预期输出
标题为“预期输出”的章节对于已签署的输入:
A signature is present in incoming.pdfEncrypted: noNext step: run a cryptographic verifier before trusting it.对于未签署的输入:
No signature found in incoming.pdf边界案例
标题为“边界案例”的章节- 存在不等于有效 — 边界。
InspectResult::$hasSigned只报告文件中存在一个签章字典。它不会检查 CMS 结构、byte-range 摘要、签署证书、证书链或撤销状态。被篡改的文件仍可能报告hasSigned = true。绝不可将存在性当作完整性或作者身份的证明。 - 完整验证需要什么。 一次完整的判定会重新计算 byte-range 摘要并加以比对(ISO 32000-2 §12.8.1),验证 CMS SignedData,建立并检查到受信任锚点的 X.509 路径,并通过 OCSP 或 CRL 检查撤销。对于长期保存的输入,验证数据存放在 DSS 中(ETSI EN 319 142-2 §6.3.1)。这些操作由
SignerInterface与LtvManagerInterface契约背后的实现执行;生产环境实现随 Pro 与 Enterprise 版本提供。外部验证器是另一条受支持的路径。 - 检查深度与 sidecar(旁路服务,SIDECAR-001)。 默认的
new Inspector()并未配置 Spectrum sidecar。没有 sidecar 时,只有InspectDepth::Quick会返回结果。InspectDepth::Quick使用进程内的 PHP 后备路径。InspectDepth::Standard与InspectDepth::Full都需要 sidecar。如果没有可用的 sidecar,它们会抛出InspectException,代码为INSPECT-SIDECAR-001(「Spectrum sidecar is required for Standard/Full depth inspection」,retryable = true)。InspectConfig构造函数的 默认深度是Standard。因此,不带参数的new InspectConfig()(或new InspectConfig(depth: InspectDepth::Standard))无法离线使用。它会在读取hasSigned之前就抛出 SIDECAR-001。请改用InspectConfig::quick()做离线的存在性检测,如本 recipe 所示。Core 中没有任何一种深度会执行密码学上的签章验证。 - 空白输入。 空字符串会抛出
InspectException,代码为INSPECT-INPUT-001。请在读取时做好防护。 - 多个签章。 存在性标志不会计算签章数量,也不会区分批准签章与文档时间戳。当数量或每个签章的判定结果很重要时,请使用专用的验证器。
符合性
标题为“符合性”的章节| 陈述 | 规范 | 条款 | 参考 ID |
|---|---|---|---|
签章值存放在签章字典的 Contents 条目中。 | ISO 32000-2 | §12.8.1 | |
验证会在 ByteRange 上重新计算摘要,并排除签章值本身。 | ISO 32000-2 | §12.8.1 | |
| 长期验证数据存放在 DSS 中。 | ETSI EN 319 142-2 | §6.3.1 |
本 recipe 只检测签章是否存在。它不会主张任何签章有效、受信任或未被撤销。该判定属于密码学验证器的职责。