契約 / 擷取
擷取領域包含讀取與驗證 PDF,以及將其內容轉為結構化資料的各項契約。這些契約涵蓋檢查器、相容性驗證器、PDF/A 管理器、匯入物件契約、嵌入與向量索引契約,以及電子發票驗證器子命名空間。
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 也不會變動。