跳转到内容

一致性(conformance):ConformanceMode 的路由与验证边界

NextPDF\Conformance 带有唯一的判别符(discriminator),用来告诉 writer 文件锁定哪一个 ISO 合约。库只输出合约定义的结构。它不会、也无法保证最终产出的文件符合规范。只有外部验证器(validator)才能认证一致性。

Terminal window
composer require nextpdf/core:^3

Conformance 模块有两个公开类型。ConformanceMode 是一个带底层值的枚举(enum),用来命名目标合约(PlainPdfUa1PdfUa2PdfA2PdfA3PdfA3bPdfA3uPdfA4PdfA4ePdfA4f)。ConformancePolicy 是一个不可变的值对象,把模式与彼此正交的严格度开关组合在一起。

模式是下游 writer 各个闸门(gate)的唯一事实来源。在这个枚举出现之前,引擎会根据零散的标记推断「这份文件是否已按规范添加标签?」——而那些标记四散各处。ConformanceMode::isTagged()isAccessibility()isArchival()pdfaPart()pdfaConformanceLetter()requiresPdf17() 各自返回一个类型化答案,供 writer 直接读取。目录(catalog)、/MarkInfo、文件头继承关系,以及 XMP 的 pdfaid 标记都会与所声明的意图保持一致。

请准确理解这条支持边界。NextPDF Core 输出 这些标准定义的结构。ISO 19005-4:2020 §6.7.3 规定了用于记录某个文件宣称属于哪个 PDF/A 变体的识别架构。ISO 19005-4:2020 明确规定,一致性的实际判定必须依据其第 5 条进行——也就是依照规范性要求,由检查工具来判定,而不是由生成文件的库来判定。ISO 14289-2:2024 §6 把一致性界定为某个 文件 满足的属性。NextPDF 设置模式是构成合规文件的必要输入。但模式本身并不是一致性的结果。

这正是 CSS 支持矩阵所采用的「已验证对宣称」(Verified-versus-Claimed)纪律。只有在存在一次通过的测试或 oracle 执行结果,并附有引用条号时,某项能力才算 已验证。其余一切都只是库 输出 的实现——有用,但不是一致性保证。一致性是最终文件经过验证器验证后才具备的属性,而不是库的承诺。请用 veraPDF 验证输出(见下方「一致性」一节)。

还有第二条边界对归档工作很重要。PDF/A-4 的 创建——OutputIntent 字典、内嵌的 ICC 配置文件,以及 XMP 扩展架构——随 nextpdf/pro 扩展包提供,而非由 Core 提供。在仅安装 Core 的环境里,Document::enablePdfA() 会抛出 InvalidConfigException,因为 security.pdfa 能力并未注册。Core 仍保留 ConformanceMode 这个判别符(因此自省与 PDF/UA-2 加标签路径都可运行),但它无法独自创建 PDF/A-4 文件。

类型种类主要成员
NextPDF\Conformance\ConformanceModeenum: stringPlainPdfUa1PdfUa2PdfA2PdfA3PdfA3bPdfA3uPdfA4PdfA4ePdfA4fisTagged()isAccessibility()isArchival()requiresPdfUa2PageTabs()pdfaPart(): ?intpdfaConformanceLetter(): stringrequiresPdf17(): bool
NextPDF\Conformance\ConformancePolicyfinal readonly class__construct(ConformanceMode $mode = PdfUa2, bool $strictUa2 = false, bool $rejectUnvalidatedLang = false, …)lax()strictUa2()withUax9IsolateSupport()withoutAstShadowMode()withBlackPointCompensation()withStrictOcspProducedAtTolerance()withAllowStaleOcsp()

ConformancePolicy 在其构造函数中强制一条不变式:严格的 PDF/UA-2 开关只有在模式为 PdfUa2 时才适用,而且 strictUa2 = true 会强制 rejectUnvalidatedLang = true。不一致的组合会抛出 InvalidConfigException,而不是默默降级。

<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformanceMode;
$mode = ConformanceMode::PdfA4f;
// Introspect the declared contract — these drive writer-side gates.
$mode->pdfaPart(); // 4
$mode->pdfaConformanceLetter(); // 'F'
$mode->requiresPdf17(); // false (PDF/A-4 is PDF 2.0 lineage)
$mode->isArchival(); // true

Core 随附的、能够端到端演练一份一致性合约的路径,就是 PDF/UA-2 加标签路径。下面这个可执行示例(examples/31-pdfua2-tagged.php)同时也是严格 PDF/UA-2 配置文件的 oracle 目标。

<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// Set the tagged-PDF contract BEFORE writing content so the HTML pipeline
// wires the TaggedContentEmitter at parser-construction time.
$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Accessible report');
// … write content …
$doc->save(__DIR__ . '/out/report-ua2.pdf');
// The library has now emitted PDF/UA-2 structures. It has NOT asserted
// conformance. Verify the file with the pinned veraPDF oracle:
//
// php oracle/run.php pdfua.strict
//
// (Requires the veraPDF Docker image — opt-in; see "Conformance" below.)
  • PDF/A-4 的创建属于 Premium。 在仅安装 Core 的环境里,Document::enablePdfA() 会抛出 InvalidConfigExceptionsecurity.pdfa 无法使用)。Core 掌握的是判别符,而不是 OutputIntent/ICC/XMP 的输出。请见 /specifications/pdfa4/
  • 总括枚举项与变体枚举项。 PdfA4 是总括枚举项,返回的 pdfaConformanceLetter() 为空。ISO 19005-4:2020 §6.7.3 规定,既不符合 PDF/A-4e 也不符合 PDF/A-4f 的文件不提供 pdfa:conformance。仅在 Annex B/Annex A 变体时才使用 PdfA4e / PdfA4f
  • 严格 PDF/UA-2 采用选择加入。 ConformancePolicy::lax() 是不破坏向后兼容的默认值。strictUa2() 会强制 /MarkInfo /Marked true 并拒绝不符合 BCP-47 的内容。在非 PdfUa2 模式上启用它会抛出异常。
  • isTagged() 会识别变体。 PlainPdfA2PdfA3bPdfA4e 都会返回未加标签。writer 不得假设归档模式就代表存在一棵结构树。
  • 通过的模式不等于通过的文件。 设置 PdfA4 并不会让输出成为有效的 PDF/A-4 文件。请运行验证器。

ConformanceModeConformancePolicy 都是纯值类型:枚举项的 resolve(解析)与 match 分派都是 O(1),除了那个不可变的 policy 对象之外不会额外分配内存。它们对写入路径不会增加任何可测量的成本。主导模块预算(wall_ms: 1500)的是 writer,而不是这个判别符。veraPDF oracle 是带外的 CI 步骤,并非文件生成的一部分。

应用在 ConformancePolicy 上的严格开关,用来守住 fail-closed 的安全行为:securityPkiRfc5280Strict(RFC 5280 §6 路径验证)、strictOcspProducedAtTolerance(RFC 6960 §4.2.2.1 时间偏移窗口),以及 allowStaleOcsp(默认为 false——拒绝 OCSP 中缺少 nextUpdate 的响应)。这些默认值偏保守,并会按照已文档化的向后兼容策略,在未来某个主版本中切换为严格。关于签名路径的细节,请见 安全性模块与本项目的威胁模型。

NextPDF 不认证一致性。它输出下列标准定义的结构,再由独立的验证器判定某个 文件 是否符合规范。

标准条号NextPDF Core 的作为状态
ISO 14289-2:2024(PDF/UA-2)§6通过 Core 的加标签路径输出结构树、/MarkInfo /Marked true(严格)、/Lang,以及 pdfuaid XMP已验证的配置文件:当 veraPDF 二进制文件存在时(选择加入的闸门),pdfua.strict 由 veraPDF oracle 验证(php oracle/run.php pdfua.strict
ISO 19005-4:2020(PDF/A-4 归档格式)§6.7.3通过 ConformanceMode 输出 pdfaid:part / pdfa:conformance 判别符已宣称(判别符输出,有单元测试佐证);PDF/A-4 文件 的创建仅限 Premium
ISO 32000-2:2020(PDF 2.0)§7.5.2基础的 catalog/document 结构已宣称(基础引擎行为)

支持不等于一致性。 NextPDF Core 输出 PDF/UA-2 与 PDF/A-4 的识别结构(属于实现,由 tests/Unit/Conformance/ 中的测试佐证)。某个 文件 是否符合 PDF/A-4 或 PDF/UA-2,只能由执行对应配置文件的验证器来断定。根据 ISO 19005-4:2020 第 5 条,一致性判定是验证器的职责,而不是生成文件的库。

veraPDF 闸门会明确说明自身依赖。 这个 oracle(oracle/run.phporacle/lib/OracleRunner.php)会调用一个固定版本的 veraPDF Docker 镜像。当 Docker 或该镜像不存在时,执行器会以代码 2(基础设施失败)退出,并且不会验证任何内容。因此 pdfua.strict 配置文件是一道选择加入的一致性闸门:它只在存在 veraPDF 二进制文件的机器上证明一致性。NextPDF 不随附任何内置验证器;在验证器缺席时,也不会作出任何一致性宣称。

引用内容由 NextPDF 合规语料库改写而成。完整的 64 字符 reference_id 摘要记录在页面 front-matter 与 _normative-evidence-conf.md 之中。