Enterprise 版本
Compliance — 深入參考
Compliance 模組會將完成的 PDF 導向外部的驗證 sidecar,並回傳單一的正規化結果。ComplianceGateway 會從 ComplianceProfile 解析出負責的 sidecar,強制執行 fail-closed 的可用性政策,並將每個工具的判定包裝進一個 ExternalValidationResult。橋接器隨附於 veraPDF(PDF/A、PDF/UA、PDF 2.0 Arlington)、EU DSS(PAdES 層級)、合併的 Mustang/KoSIT sidecar(ZUGFeRD、Factur-X、EN 16931),以及一個獨立的 KoSIT daemon。本模組也提供 AiReadyCertifier 就緒度蓋章,以及一個用於官方 KoSIT XRechnung 測試套件的執行器。
可用性與授權
標題為「可用性與授權」的區段此能力隨 NextPDF Enterprise(nextpdf/enterprise)提供,並以 Enterprise 層級的授權封套啟用。缺少該權益的部署不會載入此能力的類別。比較版本並取得授權。
Compliance/Evidence 介面由 enterprise.compliance.evidence 能力授權。缺少或過期的權益會拒絕該功能;它不會默默降級行為。
| 層級 | Compliance 介面 |
|---|---|
| Core | 行程內位元組串流與文法檢查;不委派給外部 sidecar。 |
| Pro | 行程內 EN 16931 / Factur-X / ZUGFeRD 驗證;無外部 sidecar。 |
| Enterprise | 外部驗證器閘道器(本模組),採統一結果與 fail-closed 政策。 |
Pro 的行程內電子發票驗證器與 Enterprise 的外部 ZUGFeRD sidecar 是不同的介面。外部驗證器閘道器僅隨 nextpdf/enterprise 套件提供。
公開 API 介面
標題為「公開 API 介面」的區段composer require nextpdf/enterprise:^3| 符號 | 參數 | 預設行為 | 回傳 | 擲出或失敗於 | 附註 |
|---|---|---|---|---|---|
ComplianceGateway::__construct | list<ExternalValidator> $validators、LoggerInterface $logger、bool $optional = false | 依工具名稱建立驗證器索引 | — | — | Optional 模式會將可用性檢查降級為僅發出警告 |
ComplianceGateway::validate | string $pdfContent、ComplianceProfile $profile、array $options = [] | 以 ComplianceProfile::toolName() 解析驗證器,檢查可用性,然後委派 | ?ExternalValidationResult | ComplianceSidecarUnavailableException;InvalidArgumentException(該工具未註冊驗證器) | 僅在 optional 模式且 sidecar 停擺時回傳 null |
ComplianceGateway::validateAllProfiles | string $pdfContent、string $toolName | 驗證對應到該工具的每個 profile | list<ExternalValidationResult> | 與 validate() 相同 | 略過 null(optional 模式)結果 |
ComplianceGateway::healthCheck | — | 探測每個已註冊 sidecar 的健康端點 | array<string, bool> | — | 回報可連線性;不驗證任何文件 |
ComplianceGateway::buildComplianceMatrix(靜態) | list<ExternalValidationResult> $results、string $commitSha | 將結果歸納為帶版本化結構描述的矩陣 | array<string, mixed> | — | 結構描述版本 1.0;記錄工具輸出,不主張任何東西 |
ComplianceProfile(enum) | 15 個以字串為底的 case | 將每個 profile 對應到一個標準標籤與一個工具 | — | — | standardReference(): string、toolName(): string |
ExternalValidator(interface) | — | 建構於 PSR-18 之上的 sidecar 橋接合約 | — | 傳輸失敗時 validate() 會擲出 ComplianceSidecarUnavailableException | getToolName()、isAvailable()、validate() |
VeraPdfValidator::validate | Interface 簽名 | 以 multipart POST 到 veraPDF REST sidecar;剖析 JSON 報告 | ExternalValidationResult | ComplianceSidecarUnavailableException;InvalidArgumentException(不支援的 profile) | PDF/A、PDF/UA、Arlington;僅剖析 JSON,絕不剖析 XML |
DssValidator::validate | Interface 簽名 | 以 Base64 JSON POST 到 EU DSS REST sidecar | ExternalValidationResult | ComplianceSidecarUnavailableException;InvalidArgumentException(不支援的 profile) | PAdES B-B 至 B-LTA;建構子拒絕低於一秒的逾時 |
ZugferdExternalValidator::validate | Interface 簽名 | 以 multipart POST 到合併的 Mustang/KoSIT sidecar | ExternalValidationResult | ComplianceSidecarUnavailableException(斷路器開啟時亦然);InvalidArgumentException(不支援的 profile) | ZUGFeRD 2.4、Factur-X 1.08、EN 16931;可選擇注入斷路器 |
KoSitValidator::validate | Interface 簽名 | 以原始 XML POST 到獨立的 KoSIT daemon | ExternalValidationResult | ComplianceSidecarUnavailableException;InvalidArgumentException(不支援的 profile) | 僅 EN 16931;以 fail-closed 方式剖析 Schematron SVRL 報告 |
ExternalValidationResult | 唯讀值物件 | 正規化的工具判定 | — | — | passes()、fails()、nonConformanceCount()、toComplianceMatrix() |
NonConformance | 唯讀值物件 | 單一發現項,含規則 id、條款、嚴重度、位置 | — | — | toArray() |
ComplianceSidecarUnavailableException | string $toolName、string $endpoint、int $code = 0、?Throwable $previous = null | Fail-closed 的 sidecar 不可用訊號 | — | — | 公開唯讀的 toolName 與 endpoint |
AiReadyCertifier::certify | string $pdfBytes | 評估三項就緒度準則;蓋上 XMP 來源證明 | array{0: AiReadyCertification, 1: string} | InvalidArgumentException(蓋章需要傳統的交叉參照表) | 當層級為 not_certified 時,第二個元素等於輸入 |
AiReadyCertification | 唯讀值物件 | 就緒度評估,含層級、準則數、問題、來源雜湊 | — | — | 內部就緒度標籤,非標準認證 |
XRechnungTestSuiteRunner::__construct | string $suitePath、ExternalValidator $validator、bool $useCuratedNegativeFallback = true | 解析已解壓的測試套件目錄 | — | InvalidArgumentException(目錄不存在) | 針對官方 KoSIT XRechnung 測試套件 |
XRechnungTestSuiteRunner::run | bool $stopOnFirstFailure = false | 透過橋接器驗證套件中的每個實例 | XRechnungTestSuiteResult | XRechnungTestSuiteException(驗證器不可用;沒有 XML 檔案) | 另有 isAvailable()、getSuitePath()、discoverTestFiles() |
XRechnungTestSuiteResult | 唯讀值物件 | 彙總的套件結果 | — | — | allPassed()、totalCount()、getFailures()、getErrors()、toSummary() |
XRechnungTestCaseResult | 唯讀值物件 | 各案例結果 | — | — | passed()、hasError()、getFilename() |
XRechnungTestSuiteException | 靜態建構子 | 套件執行期失敗訊號 | self | — | validatorUnavailable()、noTestFilesFound(string $suitePath) |
namespace NextPDF\Enterprise\Compliance;
final class ComplianceGateway{ /** @param list<ExternalValidator> $validators */ public function __construct( array $validators, private readonly LoggerInterface $logger, private readonly bool $optional = false, );
/** @param array<string, mixed> $options */ public function validate( string $pdfContent, ComplianceProfile $profile, array $options = [], ): ?ExternalValidationResult;
/** @return list<ExternalValidationResult> */ public function validateAllProfiles(string $pdfContent, string $toolName): array;
/** @return array<string, bool> */ public function healthCheck(): array;
/** * @param list<ExternalValidationResult> $results * @return array<string, mixed> */ public static function buildComplianceMatrix(array $results, string $commitSha): array;}interface ExternalValidator{ public function getToolName(): string;
public function isAvailable(): bool;
/** @param array<string, mixed> $options */ public function validate( string $pdfContent, ComplianceProfile $profile, array $options = [], ): ExternalValidationResult;}
enum ComplianceProfile: string{ case PdfA1b = 'pdfa-1b'; // PdfA2b, PdfA3b, PdfA4, PdfA4f, PdfUa1, PdfUa2, Pdf20Arlington, // PadesBasic, PadesTimestamp, PadesLongTerm, PadesArchive, // Zugferd24, FacturX108, En16931
public function standardReference(): string;
public function toolName(): string;}final class AiReadyCertifier{ /** @return array{0: AiReadyCertification, 1: string} Tuple of [certification, stamped PDF bytes] */ public function certify(string $pdfBytes): array;}行為合約
標題為「行為合約」的區段ComplianceGateway::validate() 會解析已註冊、其 getToolName() 與 ComplianceProfile::toolName() 相符的 ExternalValidator,檢查 isAvailable(),委派執行,並回傳一個正規化的 ExternalValidationResult。外部可觀察的規則如下:
- **Fail-closed 預設。**當所解析的 sidecar 不可用且 optional 模式關閉時,呼叫會引發
ComplianceSidecarUnavailableException。文件未被檢查;它絕不會被視為通過。 - **Optional 模式。**以
optional: true建構閘道器(操作者從NEXTPDF_COMPLIANCE_OPTIONAL環境變數接線)會將不可用的 sidecar 降級為一筆記錄下來的警告與null回傳。呼叫端必須將null視為「未檢查」。Optional 模式僅涵蓋預檢的可用性探測;驗證呼叫本身期間發生的傳輸失敗,在兩種模式下都會引發ComplianceSidecarUnavailableException。 - **未知 profile。**沒有已註冊驗證器的 profile 會引發
InvalidArgumentException;它絕不會默默通過。 - 通過語意。
ExternalValidationResult::passes()要求conformant為 true 且零個不符合項。每筆結果都帶有 profile、工具名稱與版本、主張數、發現項、已驗證位元組的 SHA-256、一個 UTC 時間戳,以及呼叫時長。 - 矩陣是記錄,而非主張。
buildComplianceMatrix()是一個靜態歸納器,會產生一個帶版本化結構描述的結構,內含工具版本與一個用於可追溯性的 commit SHA。它記錄工具輸出;它不主張任何東西。 - **資料流。**完整的 PDF 位元組串流會透過一個 PSR-18 用戶端傳輸到所設定的 sidecar。每次驗證都會透過 PSR-3 記錄,內含 profile、工具、通過/失敗、主張數與時長。
Profile 到工具的路由,如 ComplianceProfile::standardReference() 與 ::toolName() 所回傳:
| Profile case | 標準參考 | 工具 |
|---|---|---|
pdfa-1b, pdfa-2b, pdfa-3b, pdfa-4, pdfa-4f | ISO 19005-1/-2/-3/-4 (Level B; Level F for 4f) | veraPDF |
pdfua-1, pdfua-2 | ISO 14289-1:2014, ISO 14289-2:2024 | veraPDF |
pdf20-arlington | ISO 32000-2:2020 (Arlington model) | veraPDF |
pades-b-b, pades-b-t, pades-b-lt, pades-b-lta | ETSI EN 319 142-1 B-B through B-LTA | EU DSS |
zugferd-2.4, factur-x-1.08, en-16931 | ZUGFeRD 2.4 / Factur-X 1.08 / EN 16931-1:2017 | Mustang/KoSIT |
AiReadyCertifier::certify() 會評估三項準則:結構性簽章的存在、LTV 健康度,以及未加密。三項準則皆通過會得到 certified 層級;通過一或兩項得到 partial;零項得到 not_certified。在 certified 或 partial 時,它會附加一個增量更新,攜帶一個 XMP 來源證明串流與一個 Catalog 覆寫;原始位元組絕不會被更動。「certified」層級是 NextPDF 內部的就緒度標籤,不是標準認證。
VeraPdfValidator 只剖析 JSON sidecar 回應(沒有 XML;依設計即無 XXE 疑慮)。KoSitValidator 會剖析 daemon 的 XML SVRL 報告,並拒絕 DOCTYPE 宣告、停用網路存取,且將無法剖析的報告視為該呼叫的失敗。
邊界案例與失敗模式
標題為「邊界案例與失敗模式」的區段- Sidecar 逾時或傳輸錯誤會從橋接器呈現為
ComplianceSidecarUnavailableException;此時套用 fail-closed 預設。 - 非 200 的 sidecar 回應會產生一筆失敗結果,帶有工具專屬的發現項(例如
VERAPDF-HTTP-ERROR);它絕不是一致性通過。 - 格式不正確的 sidecar JSON 或 XML 主體是該呼叫的驗證失敗,而非一致性通過。
- 沒有簽章的 EU DSS 結果會以
DSS-NO-SIGNATURES失敗。TOTAL_PASSED以外的指示會以DSS-SIG-INVALID失敗。低於預期基準的簽章層級會以DSS-LEVEL-MISMATCH失敗。 DssValidator會在每次請求時,透過X-NextPDF-Timeout-Seconds標頭公布其各請求的逾時預算;整合者的 PSR-18 用戶端必須遵守它,如此停擺的 sidecar 才無法無限期地阻塞呼叫執行緒。ZugferdExternalValidator可選擇透過注入的斷路器路由 sidecar 呼叫;開啟的斷路器會對應到ComplianceSidecarUnavailableException(fail-fast,仍為 fail-closed)。預設是一個 no-op 斷路器。KoSitValidator::isAvailable()接受 daemon 健康探測回傳的 HTTP 200 與 405;daemon 在健康時會以 405 回應 GET。- 當原始文件缺少傳統的交叉參照表(例如交叉參照串流)時,
AiReadyCertifier蓋章會以InvalidArgumentExceptionfail-closed。 - 當驗證器不可用或套件不含 XML 檔案時,
XRechnungTestSuiteRunner::run()會拒絕執行;在啟用useCuratedNegativeFallback時,若套件未隨附任何無效實例,它會以一個精選的負面語料庫替代。
FIPS 模式行為
標題為「FIPS 模式行為」的區段本模組不執行任何簽署,也不保管金鑰。FIPS 模式的演算法政策由 Security 與 Signature 模組掌管。簽章一致性委派給 EU DSS,由它做出自己的判定。
一致性
標題為「一致性」的區段閘道器會將一致性判定委派給外部工具;這個設計反映了標準本身的界線——一致性是依要求判定,而不是由產生者主張。
| 行為 | 參考 |
|---|---|
| 符合處理器的義務;一致性依該標準判定 | ISO 19005-4:2020 §5.2 |
| PDF/A-4 檔案要求對比產生者自我主張 | ISO 19005-4:2020 §6.6.4 |
| PDF/UA-2 一致性是檔案的屬性 | ISO 14289-2:2024 §6 |
| PAdES baseline 簽章層級 | ETSI EN 319 142-1 §5.4.3 |
外部工具產生判定。NextPDF 並未持有任何認證,也不會授予任何認證;支援某項 profile 不等於符合它。驗證結果是供參考的技術性結構檢查記錄,而非法律意見;請洽詢你的合規團隊以判斷法規上的充分性。
開發註記
標題為「開發註記」的區段- 操作者負責託管與營運這些 sidecar、釘選它們的版本、限制它們的網路觸及範圍、驗證它們的 TLS,並掌控啟用 optional 模式的環境。Sidecar 端點是一道信任邊界;文件、結果與日誌的資料落地與保留控制,皆為操作者的責任。
buildComplianceMatrix()的輸出是為 CI 可追溯性而設計:釘選 commit SHA,並將矩陣與建置產物一同封存。- XRechnung 執行器預期官方測試套件已解壓到一個本機目錄;其建構子訊息會指名公開的下載來源。
- 內部機制細節保留在原始碼儲存庫的內部文件中,不在本手冊的範圍內。
發布邊界
標題為「發布邊界」的區段本頁僅記載外部可觀察的行為,以及受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、runbook 檔名與工單前綴皆不在範圍內。
另請參閱
標題為「另請參閱」的區段- Compliance 能力總覽
- Validation — 深入參考
- Evidence — 深入參考
- Pro Compliance — 行程內電子發票(不同的介面)
- Core Conformance