跳到內容

Form:AcroForm 互動式欄位與扁平化

Form 模組用來建立 PDF 互動式表單。它可以建立文字、核取方塊、選項按鈕、選擇(清單/下拉)、按鈕與簽章欄位,並將這些欄位組織成 parent/child 階層。它會將欄位寫成帶有外觀串流的 PDF 物件,也可以將表單扁平化為靜態頁面內容。

Terminal window
composer require nextpdf/core:^3

PDF 互動式表單即 AcroForm:一種文件層級的欄位階層,其中終端欄位會與頁面上的小工具註解配對。ISO 32000-2 §12.7 定義了這種表單及其欄位字典,包含 AcroForm 根節點與欄位階層。本模組是引擎針對這個模型提供的編碼器。

FormFieldManager 是主要介面,提供 textField()checkBox()radioButton()button()signatureField() 建構器、追蹤這些欄位,並透過 writeFields() 將其序列化。它會依 §8.10 要求,為每個小工具發出一份 Form XObject 外觀串流(/Subtype /Form/BBox)。FormField 是欄位值物件。FormFieldDictionaryBuilder 會將欄位轉成對應的 PDF 字典,並套用類型專屬的項目與旗標位元(文字、核取方塊、選擇、按鈕)。管理器與 FormField@since 1.0.0。字典建構器為 @since 1.1.0

FormFieldHierarchy 會建立 parent/child 欄位樹模型:addChild()getRootFieldNames()getChildren()getParent(),以及 walkDepthFirst() 訪問器。完整限定的欄位名稱就是沿著此階層形成的點分路徑,這正是 §12.7 為巢狀欄位所指定的模型。

FormFlattener 會將表單算繪為靜態頁面內容——flatten() 會回傳 FlattenResult——讓填妥的表單得以凍結並封存。FieldMDPFieldMdpAction 會建立欄位鎖定轉換的模型。已簽署的文件可鎖定一組具名欄位,防止後續修改。FieldMdpAction 會列舉鎖定範圍。其 requiresFieldList() 會指出哪些情況必須提供明確的欄位清單。FieldMDP@since 2.0.0

類別主要成員角色
FormFieldManagertextField()checkBox()radioButton()button()signatureField()addChildField()getHierarchy()writeFields()欄位建構器+序列化器(@since 1.0.0
FormField欄位值物件一個 AcroForm 欄位(@since 1.0.0
FormFieldDictionaryBuilderbuildFieldDictionary()applyTextFieldOptions()applyCheckBoxOptions()applyChoiceFieldOptions()applyButtonOptions()欄位到字典的建構器(@since 1.1.0
FormFieldHierarchyaddChild()getRootFieldNames()getChildren()getParent()walkDepthFirst()Parent/child 欄位樹(@since 2.0.0
FormFlattenerflatten(array $fields, array $pages): FlattenResult將表單扁平化為靜態內容(@since 1.0.0
FieldMDPtoTransformParams()欄位鎖定(FieldMDP)轉換(@since 2.0.0
FieldMdpAction(列舉)requiresFieldList()欄位鎖定範圍(@since 2.0.0

執行 composer docs:generate-api-php -- --module=Form 即可取得完整的 PHPDoc 表格。

來源:examples/30-form-fields.php

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Form\FormFieldManager;
$form = new FormFieldManager();
$form->textField(name: 'applicant_name', x: 50, y: 700, w: 200, h: 18);
$form->checkBox(name: 'agree_terms', x: 50, y: 660, size: 12);
$form->radioButton(name: 'plan', x: 50, y: 620, size: 12 /* + option set */);
// The Writer invokes $form->writeFields(...) during document serialization.

為已簽署文件建立一組欄位,並以 FieldMDP 鎖定已簽署的欄位。

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Form\FieldMDP;
use NextPDF\Form\FieldMdpAction;
use NextPDF\Form\FormFieldManager;
$form = new FormFieldManager();
$form->textField(name: 'contract_value', x: 50, y: 700, w: 160, h: 18);
$form->signatureField(name: 'approver_sig', x: 50, y: 600, w: 200, h: 60);
// Lock only the named fields after signing.
$lock = new FieldMDP(
action: FieldMdpAction::Include,
fields: ['contract_value'],
);
$transformParams = $lock->toTransformParams();
// $transformParams is attached to the signature's transform method by the signing layer.
  • 欄位名稱是沿著 FormFieldHierarchy 形成的完整限定點分路徑。在檢視器中,兩個具有相同完整限定名稱的終端欄位會被視為同一個邏輯欄位——確保唯一性是呼叫端的責任。
  • FieldMdpAction::requiresFieldList() 會告訴你何時必須提供欄位清單。若 Include/Exclude 動作未附帶所需的清單,就是格式錯誤的鎖定;請檢查該旗標。
  • FormFlattener::flatten() 依設計會移除互動性——其結果為靜態內容。若日後仍需要互動式來源,請加以保留。
  • 每個小工具都會各自發出外觀串流。沒有外觀的欄位在不同檢視器間可能算繪不一致;請讓管理器產生外觀,而非略過它。
  • signatureField() 只會建立欄位佔位符。產生實際簽章是 Security/簽署層的工作,而非本模組。

欄位建立與序列化的時間複雜度在欄位數量上為 O(n),另加每個小工具一份 Form XObject 外觀串流。扁平化成本會隨算繪內容,而非欄位數量成長。預設參考工作負載維持在 1500 ms 牆鐘時間/64 MB 峰值預算之內。可重現性設定檔為 structural:物件編號與尾段 /ID 在不同次執行間會有所不同。兩份具有相同表單的文件在結構上相等,但並非位元組完全相同。

表單欄位值是使用者輸入。本模組會為 PDF 序列化跳脫字串值(PdfStringEscaper),讓欄位值無法跳出其 PDF 字串並注入結構。當表單經過加密時,欄位內容會由文件的 AES-256 加密涵蓋。FieldMDP 是一項安全控制:它會鎖定具名欄位,防止簽署後遭修改。若欄位鎖定與已簽署的欄位集不相符,便會削弱該控制——請審慎設定鎖定範圍。請將任何從填妥表單擷取出的值視為不可信的輸入。請參閱 /modules/core/security/ 中的引擎安全模型。

本模組發出的表單結構遵循 ISO 32000-2 §12.7 中的互動式表單模型——AcroForm 根節點與欄位字典,以及文件欄位階層。依 §8.10,各小工具的外觀會以 Form XObject 形式發出,並以內嵌方式記載於 src/Form/。這些是由 tests/Unit/Form/ 驗證的實作事實,並非端對端 PDF 2.0 符合性的聲明。完整文件的符合性是由 /modules/core/conformance/ 中的 oracle 與黃金測試套件驗證。