契约 / 提取
提取领域提供用于读取和验证 PDF,并将其内容转换为结构化数据的各项契约。这些契约包括检查器、合规性验证器、PDF/A 管理器、导入对象契约、嵌入与向量 Index(索引)契约,以及电子发票验证器子命名空间。
composer require nextpdf/core:^3概念总览
标题为“概念总览”的章节InspectorInterface 会读取原始 PDF。它会返回结构化的 InspectResult,其中列出文档中的对象。任何需要读取非本引擎生成的 PDF 的工具,都应使用该接口。
ExternalComplianceValidatorInterface 会桥接到外部检查工具,例如 veraPDF。该检查工具会测试 PDF/A 与 PDF/UA。未配置任何检查工具时,null 实现会返回「不可用」结果。没有 veraPDF 的站点仍可正常运行。ProfileValidatorInterface 会依据部署配置文件检查执行环境,查看必要和建议的扩展,并返回带类型信息的判定结果。
PdfAManagerInterface 会在 PDF/A 文档写入过程中保持其符合规格。它会阻止 JavaScript、JavaScript 表单动作以及内置加密。PDF/A 禁止这三者。它还会检查每个字体是否已嵌入,设置符合规格的元数据,并在目录(catalog)之前先写入所需对象。实际类随 Pro 版提供。Core 会通过 class_exists() 找到它,并将其转换为该契约。开源引擎因此不包含任何付费依赖。
有两个契约涵盖导入对象:ImportedFormObjectInterface 与 EmbeddedPdfObjectInterface。它们为从既有 PDF 读取的对象提供带类型的访问方式,随后引擎即可将这些对象重新嵌入。无损路径会保留原始字典字节。对于来自对象流的对象,后备路径会提供已解析的字典数组。每个重新嵌入的对象都是一个 PDF 间接对象,并由对象编号与世代编号共同命名——ISO 32000-2 §7.3.10。
嵌入契约服务于搜索工作。EmbeddingServiceInterface 会将文本转换为密集向量,并报告模型大小与名称。调用方会在运行时进行调整。Pro 版运行 CPU 模型。Enterprise 版运行 GPU 模型。VectorIndexInterface 会构建最近邻索引并对其进行搜索。它是供核心使用的小型进程内索引。更大规模的搜索位于仅限 Enterprise 使用的契约中。
EInvoice 这个分组提供跨版本层级的电子发票检查器。ValidatorInterface 会对 CII 或 UBL 内容执行预检。SchematronRunnerInterface 会执行商业规则检查。ValidationResult 会收集发现项与规则违规。检查器必须通过结果报告来拒绝不良输入,而不是抛出异常。它还必须防范 DOCTYPE 和过大的内容。
API 接口
标题为“API 接口”的章节| 类型 | 种类 | 主要成员 | 稳定性 | 起始版本 |
|---|---|---|---|---|
InspectorInterface | interface | inspect(string, InspectConfig): InspectResult | 实验性 | 2.2.0 |
ExternalComplianceValidatorInterface | interface | validate(string, ComplianceFlavour), isAvailable() | 实验性 | 2.4.0 |
ProfileValidatorInterface | interface | validate(DeploymentProfile): DeploymentProfileResult | 实验性 | 2.4.0 |
PdfAManagerInterface | interface | validateNoJavaScript(), validateFont(), validateNoEncryption(), applyOutputProfile(), writeRequiredObjects() | 稳定 | 1.10.0 |
ImportedFormObjectInterface | interface | getWidth(), getHeight(), getEmbeddedObjects(), getResourcesDict(), getMediaBox(), getContentStream() | 稳定 | 1.8.0 |
EmbeddedPdfObjectInterface | interface | getRawDictionaryBytes(), getRawStreamData(), getDictionary() | 稳定 | 1.8.0 |
EmbeddingServiceInterface | interface | embed(), batchEmbed(), getDimension(), getModelName() | 实验性 | 2.1.0 |
VectorIndexInterface | interface | build(), search(), delete(), count() | 实验性 | 2.1.0 |
EInvoice\ValidatorInterface | interface | validate(string, ValidatorContext): ValidationResult | 实验性 | 5.1.0 |
EInvoice\ValidationResult | final readonly class | $isValid, getErrors(), getWarnings(), fail() | 实验性 | 5.1.0 |
EInvoice 命名空间还发布了 SchematronRunnerInterface、ProfileInterface、ValidationFinding、RuleViolation,以及 ProfileType、RuleSeverity 和 ValidationFindingLevel 枚举。
程序范例——快速上手
标题为“程序范例——快速上手”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\InspectorInterface;use NextPDF\Inspect\InspectConfig;
/** * Inspect a PDF and report its object count. * * @param InspectorInterface $inspector A configured inspector. * @param string $pdfData Raw PDF bytes. */function describe(InspectorInterface $inspector, string $pdfData): \NextPDF\Inspect\InspectResult{ return $inspector->inspect($pdfData, new InspectConfig());}此函数依赖该契约。任何检查器实现都能满足它。
程序范例——正式环境
标题为“程序范例——正式环境”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\EInvoice\ValidatorInterface;use NextPDF\Contracts\EInvoice\ValidatorContext;use NextPDF\Contracts\ExternalComplianceValidatorInterface;use NextPDF\ValueObjects\ComplianceFlavour;use Psr\Log\LoggerInterface;
final readonly class InvoiceConformanceService{ public function __construct( private ValidatorInterface $invoiceValidator, private ExternalComplianceValidatorInterface $pdfaValidator, private LoggerInterface $logger, ) {}
/** * Validate the invoice XML, then the PDF/A-3 carrier. * * @param string $xml The CII or UBL invoice payload. * @param string $pdfPath Absolute path to the PDF/A-3 carrier. */ public function validate(string $xml, string $pdfPath, ValidatorContext $ctx): bool { $result = $this->invoiceValidator->validate($xml, $ctx);
if (!$result->isValid) { $this->logger->warning('Invoice XML invalid', [ 'errors' => \count($result->getErrors()), ]);
return false; }
if (!$this->pdfaValidator->isAvailable()) { $this->logger->info('PDF/A validator unavailable; skipping carrier check.');
return true; }
$carrier = $this->pdfaValidator->validate($pdfPath, ComplianceFlavour::PdfA3b);
return $carrier->isConformant(); }}此服务会明确处理验证器不可用的情况,而不会假设验证器一定存在。
边界情况与陷阱
标题为“边界情况与陷阱”的章节EInvoice\ValidatorInterface::validate()对格式错误的输入会返回失败的ValidationResult。它不会因为格式正确性违规而抛出异常。请检查$isValid,不要为了这种情况用 try/catch 包住该调用。ExternalComplianceValidatorInterface::isAvailable()必须在依赖判定结果之前先检查。null 实现会返回「不可用」。将其视为「不符合规范」会产生伪阴性。EmbeddedPdfObjectInterface::getRawDictionaryBytes()对于来自对象流的对象会返回null。请改用getDictionary()作为后备。不要假设原始字节一定存在。EmbeddingServiceInterface::getDimension()会因版本层级而异。配置固定宽度向量的代码必须在运行时读取维度,而不是写死。VectorIndexInterface::build()要求向量列表与 id 列表长度相等且维度一致。不一致会引发InvalidArgumentException。请在构建之前先验证。
检查与验证的成本会随文件大小和对象数量增加。1500 毫秒墙钟时间与 64 MB 峰值内存的 performance_budget 覆盖单个中等规模文件。外部 veraPDF 调用会额外产生验证器自身的进程处理时间。该处理时间不计入引擎预算,应在请求路径之外执行。嵌入成本会随文本长度增加,批处理远比在循环中逐条处理更便宜,在 GPU 模型上尤其如此。请优先使用 batchEmbed()。对于进程内索引,向量搜索相对于索引大小是次线性的。再现性配置文件为 structural。验证报告会记录时间戳和环境指纹。两次执行在这些字段上会有差异,而符合规范的判定结果会保持相同。
安全性注意事项
标题为“安全性注意事项”的章节提取会读取非本引擎创建的文件,因此每笔输入都不可信。检查器与电子发票验证器都会解析外部提供的字节。电子发票验证器必须在解析之前拦截带有 DOCTYPE、过大以及包含禁用控制字符的内容,以防范 XML 外部实体与 billion-laughs 攻击。导入对象的重新嵌入会从外部 PDF 复制字节。恶意来源对象可能携带有害内容,因此重新嵌入会保留字节而不执行它们。PDF/A 强制机制会移除 JavaScript 与动作。PDF/A 管理器会拒绝 JavaScript 与加密,因为两者在该配置文件中均被禁止,且两者在长期保存的归档文件中都是滥用途径。请始终将受检查的内容、导入对象与发票 XML 视为恶意输入。
符合性
标题为“符合性”的章节| 主张 | 标准 | 条款 | 佐证 |
|---|---|---|---|
| PDF/A-4 禁止 JavaScript 与 JavaScript 表单动作;PDF/A 管理器会拒绝两者。 | ISO 19005-4 | §6.7.1 | 按条款引用(不在语料库中) |
| 每个重新内嵌的对象都是以对象编号与世代识别的 PDF 间接对象。 | ISO 32000-2 | §7.3.10 |
ISO 19005-4 按条款引用。它不在可验证的引用语料库中,因此不会记录 reference_id。ISO 32000-2 的间接对象主张已固定在词汇表中。两者均为改写。引擎不会复现任何规范性文字。
商业脉络
标题为“商业脉络”的章节Core 定义并冻结提取契约。PdfAManagerInterface、EmbeddingServiceInterface 与 VectorIndexInterface 背后的生产环境代码随 Pro 与 Enterprise 版提供,包含 CPU 与 GPU 嵌入模型,以及完整的 PDF/A 强制路径。Core 会在运行时通过 class_exists() resolve(解析)这些类。开源引擎因此不包含任何商业依赖,且 API 在升级时不会变动。