跳转到内容
getnextpdf.com

Enterprise 版本

NextPDF Enterprise 快速入门

本教程带你从一个空项目走到两个可用的 Enterprise 结果。首先你验证一个已有的已签名 PDF 并读取它的 MainIndication。然后你用长期生成器把一个已签名文档提升到 PAdES B-LT。每一步都会展示你应当预期的确切输出或异常。NextPDF 记录的是能力,而非认证:它不持有任何 PAdES 或 eIDAS 认证,也不授予任何认证。

该能力随 NextPDF Enterprisenextpdf/enterprise)一同发布,并通过 Enterprise 级别的许可证信封激活。没有该授权的部署不会加载此能力的类。比较各版本并获取许可证

  • Composer 已配置好私有 NextPDF 仓库。请先按照 安装与认证 操作。
  • 你已拥有从 app.getnextpdf.com 账户下载的 Enterprise 许可证信封许可与激活 说明了该信封是什么以及它放在哪里。
  • 第 3 步需要一个用于验证的已签名 PDF。B-LT 部分还需要你的签名者证书以及访问 OCSP/CRL 响应器的网络权限。

引入 Enterprise 包。它依赖 nextpdf/corenextpdf/pro,因此 Composer 会带上整个技术栈:

Terminal window
composer require nextpdf/enterprise
composer show nextpdf/enterprise

如果 composer show 打印出该包及其版本,说明安装成功。现在按照 许可与激活 的描述,把已签名的许可证信封放到你的部署会加载它的位置。仅安装该包并不授予 Enterprise 能力;激活的许可证才会选定版本。

向授权评估器询问你的许可证授予了什么。你的引导流程会在激活期间获得经过验证的 NextPDF\Enterprise\Licensing\LicenseKey;把它传入:

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Licensing\EntitlementEvaluator;
use NextPDF\Enterprise\Licensing\LicenseKey;
/** @var LicenseKey|null $license The verified license from activation. */
$result = (new EntitlementEvaluator())->evaluate($license);
echo 'status: ' . $result->status->value . PHP_EOL;
echo 'edition: ' . ($result->edition?->value ?? 'none') . PHP_EOL;
echo 'runtime: ' . ($result->runtimeAllowed ? 'allowed' : 'disabled') . PHP_EOL;

在拥有有效 Enterprise 许可证时,你会看到:

status: active
edition: enterprise
runtime: allowed

该步骤背后的方法:

public function evaluate(?LicenseKey $license, ?DateTimeImmutable $now = null): EntitlementResult

抛出或失败方式:它从不抛出异常。缺失许可证会返回一个失败即关闭的 EntitlementResult,其 EntitlementStatus::NoLicense,且 runtimeAllowed 为 false(见第 4 步)。

从已签名的 PDF 中提取签名,然后运行基础 AdES 验证。该引擎实现了 ETSI EN 319 102-1 的各个验证级别;validateBasic() 是第 5.2 条的流程——结构、摘要、签名密码学以及证书链:

<?php
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Validation\AdESValidationEngine;
use NextPDF\Enterprise\Security\Validation\CmsSignatureDataExtractor;
use NextPDF\Enterprise\Signature\SignatureExtractor;
$pdf = file_get_contents(__DIR__ . '/contract-signed.pdf');
if ($pdf === false) {
throw new RuntimeException('Could not read contract-signed.pdf');
}
$signatures = (new SignatureExtractor())->extract($pdf);
if ($signatures === []) {
throw new RuntimeException('The PDF carries no signature dictionary.');
}
$engine = new AdESValidationEngine(extractor: new CmsSignatureDataExtractor());
$report = $engine->validateBasic(
$signatures[0]['signedBytes'], // the exact /ByteRange-covered bytes
$signatures[0]['contents'], // the DER CMS SignedData from /Contents
);
echo $report->mainIndication->name . PHP_EOL;
echo ($report->subIndication?->name ?? '(none)') . PHP_EOL;

对于一个格式良好、通过了本示例中配置的基础结构、摘要、密码学与链检查的签名,你会看到:

TOTAL_PASSED
(none)

MainIndication 恰好有三种情形:TOTAL_PASSEDTOTAL_FAILEDINDETERMINATE。该引擎是失败即关闭的:一项它无法肯定确立的检查会得到 INDETERMINATE,绝不会静默通过。这里的通过是本引擎各项检查下的验证结果,而非信任或认证声明——信任锚与长期证据属于 验证页面 上更深入的级别。

public function extract(string $pdfData): array

抛出或失败方式:如果输入不是有效的 PDF,则抛出 InvalidArgumentException。格式错误的 /ByteRange/Contents 会产生空字符串(失败即关闭),绝不会得到肯定的结果。

public function validateBasic(string $signedData, string $signature): ValidationReport

抛出或失败方式:在验证失败时它从不抛出异常。每一个缺陷都映射为一个 ValidationReport 指示,例如 HASH_FAILURESIG_CRYPTO_FAILURE

现在把一个刚签名的文档升级到 B-LT。长期生成器会收集证书链外加 OCSP/CRL 证据,并写入文档安全存储(DSS)。它延续了 签名页面 所描述的签名流程,该流程为你提供输出缓冲区、对象注册表以及签名的 /Contents 十六进制:

use NextPDF\Enterprise\Security\Ltv\LtvManager;
use NextPDF\Security\Signature\CertificateInfo;
use NextPDF\Security\Signature\SignatureLevel;
$certInfo = CertificateInfo::fromPkcs12('/secure/signer.p12', $p12Password);
// $httpClient is any PSR-18 client; it fetches OCSP responses and CRLs.
$ltv = new LtvManager($certInfo, $httpClient, level: SignatureLevel::PAdES_B_LT);
// $buffer, $registry, and $signatureContentsHex come from the signing pass.
$dssObjectNumber = $ltv->enableLtv($buffer, $registry, $signatureContentsHex);

返回值是用于文档目录 /DSS 条目的 DSS 对象编号。该生成器默认采用 strict 吊销强制执行:缺失吊销材料会抛出异常,而不是静默地生成一个空洞的 “B-LT” 文件。

public function enableLtv(BinaryBuffer $buffer, ObjectRegistry $registry, string $signatureContentsHex): int

抛出或失败方式:当链验证失败、证书被吊销,或在 strict 默认下缺失吊销材料时,抛出 NextPDF\Enterprise\Security\Ltv\LtvException

第 2 步打印 status: no_licenseruntime: disabled,且结果会携带警告 No license configured. Enterprise runtime is disabled. Install a license or purchase one at https://nextpdf.dev/pricing。随后,一次受授权限制的调用会抛出 NextPDF\Accelerator\Exception\SpectrumAuthenticationException,其代码为 SPEC-LIC-001,例如 Capability '...' requires a valid license.。解决方法:按照 许可与激活 放置并激活信封,然后重新运行第 2 步。

InvalidArgumentException: Input does not start with %PDF header

标题为“InvalidArgumentException: Input does not start with %PDF header”的章节

SignatureExtractor::extract() 收到了某个并非 PDF 的东西——错误的路径、空读取,或一个压缩过的下载文件。请检查你加载的文件。空的 $signatures 列表则是另一回事:文件是 PDF,但它不携带 /Type /Sig 字典,所以没有可验证的内容。

LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0

标题为“LtvException: Strict revocation: LTV warning: no revocation data for certificate at chain position 0”的章节

enableLtv() 无法为某个链证书获得 OCSP 响应或 CRL,而 strict 默认拒绝在没有证据的情况下写出 B-LT 声明。请检查主机对响应器的可达性,或仅在你明确接受仅告警运行时才传入 enforcementMode: RevocationEnforcementMode::PERMISSIVE——除非缺失的吊销证据被明确接受并记录在案,否则绝不要在生产或合规工作流中把这类输出标记为 B-LT。相关:在没有 TSA 客户端的情况下请求 B-LTA 会失败并抛出 LtvException: TSA client required for document timestamps