跳到內容
getnextpdf.com

Enterprise 版本

NextPDF Enterprise 快速上手

本教學帶你從一個空專案走到兩個可運作的 Enterprise 成果。首先你會驗證一份既有的已簽署 PDF 並讀取它的 MainIndication。接著你會以長期產製器將一份已簽署文件升級為 PAdES B-LT。每個步驟都會顯示你應預期的確切輸出或例外。NextPDF 記述的是能力,而非認證:它並不持有任何 PAdES 或 eIDAS 認證,也不授予任何認證。

此能力隨 NextPDF Enterprisenextpdf/enterprise)一同提供,並以 Enterprise 層級的授權信封啟用。一個不具備該權利的部署不會載入此能力的類別。比較版本並取得授權

  • Composer 已設定為指向私有的 NextPDF 儲存庫。請先依照 安裝與驗證 進行。
  • 你已備妥 Enterprise 授權信封,由你在 app.getnextpdf.com 的帳戶下載。授權與啟用 說明了此信封是什麼以及該放在哪裡。
  • 步驟 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::NoLicenseruntimeAllowed 為 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 物件編號。產製器預設採用嚴格的撤銷強制執行:缺少撤銷素材會引發例外,而非靜默地輸出一份空洞的「B-LT」檔案。

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

拋出或失敗的情形:當鏈驗證失敗、當憑證已撤銷,或當嚴格預設下缺少撤銷素材時,會拋出 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,而嚴格預設拒絕在沒有證據的情況下寫入 B-LT 宣告。檢查主機是否能連上回應者,或僅在你明確接受一次只警告的執行時才傳入 enforcementMode: RevocationEnforcementMode::PERMISSIVE——除非缺少的撤銷證據已被明確接受並記錄在案,否則絕不要為正式生產或合規工作流程將此類輸出標示為 B-LT。相關:在沒有 TSA 用戶端的情況下請求 B-LTA 會以 LtvException: TSA client required for document timestamps 失敗。