コンテンツにスキップ

フォーム: 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 のフィールド 1 個(@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(enum)requiresFieldList()フィールドロックのスコープ(@since 2.0.0

完全な PHPDoc の表については、composer docs:generate-api-php -- --module=Form を実行してください。

ソース: 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 をたどる完全修飾のドット区切りパスです。同じ完全修飾名を持つ 2 つの終端フィールドは、ビューアー上では同一の論理フィールドになります。一意性の確保は呼び出し側の責任です。
  • FieldMdpAction::requiresFieldList() は、フィールドリストが必須となる場合を示します。必須リストを伴わない Include/Exclude アクションは不正なロックです。フラグを確認してください。
  • FormFlattener::flatten() は設計上、インタラクティブ性を失わせます。結果は静的なコンテンツです。後でインタラクティブ性が必要になる場合は、インタラクティブなソースを保持してください。
  • アピアランスストリームはウィジェットごとに出力されます。アピアランスを持たないフィールドは、ビューアー間でレンダリングが一貫しません。フィールドを省略するのではなく、マネージャーにアピアランスを生成させてください。
  • signatureField() はフィールドのプレースホルダーのみを作成します。実際の署名の生成は Security/署名レイヤーの役割であり、このモジュールの役割ではありません。

フィールドの作成とシリアライズはフィールド数に対して O(n) であり、さらにウィジェットごとに Form XObject のアピアランスストリームが 1 個生成されます。フラット化のコストは、フィールド数ではなくレンダリングされるコンテンツ量に比例します。デフォルトの参照ワークロードは、1500 ms の実時間/64 MB のピーク予算内に収まります。再現性プロファイルは structural です。つまり、オブジェクト番号とトレーラーの /ID は実行ごとに変化します。同じフォームを持つ 2 つのドキュメントは構造的には等価ですが、バイト単位では同一になりません。

フォームフィールドの値はユーザー入力です。このモジュールは 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/ のオラクルおよびゴールデンスイートによって検証されます。