-
Notifications
You must be signed in to change notification settings - Fork 0
Interactive Forms
PhpPdf supports AcroForm interactive forms. Fields are value objects placed on a page with $page->field(...). Every field type is immutable (final readonly); validation is eager in the constructor or deferred to Document::output().
use DragonOfMercy\PhpPdf\Form\{TextField, Checkbox, Radio, Combobox, Listbox, PushButton, ButtonAction, FieldAppearance};
use DragonOfMercy\PhpPdf\Color;
$pdf = new \DragonOfMercy\PhpPdf\Document();
$page = $pdf->addPage();
// Single-line text input
$page->field(new TextField(50.0, 50.0, 80.0, 8.0, name: 'firstname', value: 'Bob', required: true));
// Multi-line text area
$page->field(new TextField(50.0, 65.0, 80.0, 24.0, name: 'comment', multiline: true));
// Password field (input masked in the reader)
$page->field(new TextField(x: 20, y: 20, width: 60, height: 8, name: 'pwd', password: true));
// Checkbox
$page->field(new Checkbox(50.0, 95.0, 5.0, 5.0, name: 'agree'));
// Radio group - widgets sharing the same group name form one logical field
$page->field(new Radio(50.0, 110.0, 5.0, 5.0, group: 'civility', value: 'mr', checked: true));
$page->field(new Radio(50.0, 120.0, 5.0, 5.0, group: 'civility', value: 'mrs'));
// Combobox (dropdown)
$page->field(new Combobox(50.0, 135.0, 80.0, 8.0, name: 'country',
options: ['fr' => 'France', 'ch' => 'Suisse'], value: 'ch'));
// Listbox (multi-select)
$page->field(new Listbox(50.0, 150.0, 80.0, 24.0, name: 'interests',
options: ['music', 'sport', 'code'], value: ['sport'], multiSelect: true));Coordinates x, y, width, and height are in the document's user unit with a top-down Y axis, the same convention as Page::cell().
new TextField(float $x, float $y, float $width, float $height, string $name, ...)
| Parameter | Type | Description |
|---|---|---|
value |
string |
Initial display value (default '') |
multiline |
bool |
Multi-line text area; mutually exclusive with password
|
password |
bool |
Masked input; cannot be multiline or have a default value |
required |
bool |
Field must be filled before submission |
readOnly |
bool |
Value is locked in the viewer |
maxLength |
?int |
Maximum character count (positive) |
tooltip |
?string |
Tooltip shown on hover |
appearance |
?FieldAppearance |
Visual style |
actions |
?FieldActions |
JavaScript triggers |
defaultValue |
?string |
Value restored by a ResetForm button (/DV) |
new Checkbox(float $x, float $y, float $width, float $height, string $name, ...)
| Parameter | Type | Description |
|---|---|---|
checked |
bool |
Initial checked state |
required |
bool |
Field must be checked before submission |
readOnly |
bool |
State cannot be changed |
tooltip |
?string |
Tooltip shown on hover |
appearance |
?FieldAppearance |
Visual style |
actions |
?FieldActions |
JavaScript triggers (mouse/focus only) |
defaultValue |
?bool |
State restored by a ResetForm button |
new Radio(float $x, float $y, float $width, float $height, string $group, string $value, ...)
group is the shared field name; value is the export value (PDF /AS state name) for this widget. All Radio instances with the same group are emitted as one /Field with /Kids.
new Combobox(float $x, float $y, float $width, float $height, string $name, array $options, ...)
$options accepts two shapes:
-
list<string>-['France', 'Suisse', 'Belgique'] -
array<string, string>-['fr' => 'France', 'ch' => 'Suisse'](export value => display label)
value is the initial selection: a label (list shape) or an export key (map shape). Validation against $options is deferred to Document::output(). Set editable: true to allow the user to type a custom value.
new Listbox(float $x, float $y, float $width, float $height, string $name, array $options, ...)
Same two-shape $options contract as Combobox. value accepts a string, a list<string>, or null. When multiSelect is false a list longer than one element is rejected at output time.
All field types accept an appearance: new FieldAppearance(...) parameter.
use DragonOfMercy\PhpPdf\Form\{TextField, FieldAppearance};
use DragonOfMercy\PhpPdf\Color;
$page->field(new TextField(50.0, 50.0, 80.0, 8.0,
name: 'styled',
appearance: new FieldAppearance(
borderColor: Color::rgb(255, 0, 0),
borderWidth: 1.0,
backgroundColor: Color::rgb(240, 240, 240),
),
));FieldAppearance constructor parameters:
| Parameter | Type | Description |
|---|---|---|
borderColor |
?Color |
Widget border color |
borderWidth |
?float |
Border width in points (non-negative) |
backgroundColor |
?Color |
Widget background fill |
textColor |
?Color |
Text color inside the widget |
font |
?Font |
Font family for the widget text |
fontSize |
?float |
Font size in points (positive) |
align |
TextAlign |
Text alignment (default LEFT) |
hidden |
bool |
See advanced options below |
noExport |
bool |
See advanced options below |
borderStyle |
?FieldBorderStyle |
Border shape; see table below |
All parameters are optional; null means "use the PDF viewer default."
FieldAppearance accepts a borderStyle: FieldBorderStyle parameter that controls the widget border shape. The five cases map to the PDF /BS /S name:
| Case | PDF /S
|
Visual |
|---|---|---|
FieldBorderStyle::SOLID |
/S |
Plain solid line (default when omitted) |
FieldBorderStyle::DASHED |
/D |
Dashed line (3-unit dash array) |
FieldBorderStyle::BEVELED |
/B |
Raised 3-D bevel |
FieldBorderStyle::INSET |
/I |
Sunken 3-D inset |
FieldBorderStyle::UNDERLINE |
/U |
Bottom edge only |
use DragonOfMercy\PhpPdf\Form\{TextField, FieldAppearance, FieldBorderStyle};
use DragonOfMercy\PhpPdf\TabOrder;
$page->setTabOrder(TabOrder::ROW);
// Beveled border, excluded from form submission, with a default value
$page->field(new TextField(20, 20, 80, 8, name: 'amount', value: '0', defaultValue: '0',
appearance: new FieldAppearance(
borderWidth: 1.0,
borderStyle: FieldBorderStyle::BEVELED,
noExport: true,
)));
// Hidden field - present in the form data but not rendered on screen
$page->field(new TextField(20, 40, 80, 8, name: 'token',
appearance: new FieldAppearance(hidden: true)));Two boolean flags on FieldAppearance control special behaviors:
-
hidden: true- the field is present in the PDF object graph and its value participates in the form data, but it is not rendered on screen or printed. Sets the/Fannotation Hidden bit (bit 2). -
noExport: true- the field is visible in the reader but its value is excluded from form submissions triggered by aButtonAction::submit()button. Sets bit 3 of the/FfAcroForm flags.
TextField, Combobox, Listbox, and Checkbox accept a defaultValue parameter. When provided it is stored as the /DV PDF entry and is the value restored when a ResetForm button is clicked, independently of the current display value. When omitted, defaultValue falls back to value (unchanged behavior).
Page::setTabOrder(?TabOrder $order) writes a /Tabs entry on the page dictionary, telling compatible readers the order in which the Tab key moves through that page's fields. Pass null to clear the entry (reader default).
use DragonOfMercy\PhpPdf\TabOrder;
$page->setTabOrder(TabOrder::ROW); // left-to-right, top-to-bottom
$page->setTabOrder(TabOrder::COLUMN); // top-to-bottom, left-to-right
$page->setTabOrder(TabOrder::STRUCTURE); // document structure order
$page->setTabOrder(null); // clear (reader default)TabOrder lives in the root namespace DragonOfMercy\PhpPdf.
Place several fields with the same name and they become one logical field: editing one widget updates all others - the same mechanism radio buttons use to share a group value. The library emits a single parent /Field with one /Kids widget per placement.
use DragonOfMercy\PhpPdf\Form\TextField;
// One "customer" field shown at the top and repeated in the footer
$page->field(new TextField(20, 20, 80, 8, name: 'customer', value: 'ACME'));
$page->field(new TextField(20, 250, 80, 8, name: 'customer'));Rules:
- Linking applies to
TextField,Checkbox,Combobox, andListbox. Each placement keeps its own position andFieldAppearance. - Field-level properties (value, default value, flags, options, max length, tooltip, JavaScript actions) are taken from the first widget added; later same-name widgets contribute only their position and appearance.
- Mixing field types under one name, repeating a
PushButtonname, or repeating aSignatureFieldname throws aPdfException. - Attaching
actions:to anything other than the first widget of a linked group also throws.
Push buttons trigger an action on click and hold no value.
use DragonOfMercy\PhpPdf\Form\{PushButton, ButtonAction, FieldAppearance, SubmitFormat};
use DragonOfMercy\PhpPdf\Color;
// Reset every field in the form to its default value
$page->field(PushButton::of(
x: 20, y: 20, width: 40, height: 10,
name: 'reset', caption: 'Clear', action: ButtonAction::resetForm(),
));
// Open a URL in the browser
$page->field(PushButton::of(
x: 70, y: 20, width: 40, height: 10,
name: 'home', caption: 'Visit', action: ButtonAction::openUrl('https://example.com'),
));
// Submit the form data to a web endpoint (HTML POST)
$page->field(PushButton::of(
x: 20, y: 35, width: 40, height: 10,
name: 'send', caption: 'Submit',
action: ButtonAction::submit('https://example.com/post', SubmitFormat::HTML),
));
// With appearance
$page->field(PushButton::of(
x: 20, y: 50, width: 40, height: 10,
name: 'styled_reset', caption: 'Reset',
action: ButtonAction::resetForm(),
appearance: new FieldAppearance(
borderColor: Color::rgb(0, 0, 0),
borderWidth: 0.5,
backgroundColor: Color::rgb(230, 230, 230),
),
));PushButton::of() is a named constructor that mirrors the regular new PushButton(...) call. Three ButtonAction constructors are available:
| Named constructor | Description |
|---|---|
ButtonAction::resetForm() |
Resets all fields to their /DV default values |
ButtonAction::openUrl(string $url) |
Opens a URL in the system browser |
ButtonAction::submit(string $url, SubmitFormat $format, bool $get) |
Submits form data to $url
|
The format argument of ButtonAction::submit() selects the submission encoding:
SubmitFormat case |
Encoding |
|---|---|
FDF |
Adobe FDF envelope (default) |
HTML |
application/x-www-form-urlencoded |
XFDF |
XML variant of FDF |
PDF |
The entire PDF document is sent |
Pass get: true for an HTTP GET request instead of the default POST. This is mainly useful with SubmitFormat::HTML.
Form submission is carried out by Adobe Acrobat / Adobe Reader. Browser PDF viewers (Chrome, Firefox PDF.js) generally do not submit forms.
A signature field marks the location (and optional appearance) of a digital signature. On its own it is an unsigned placeholder a human can sign later in a desktop reader. Combined with Document::sign() (see Digital Signatures) the library applies a real PKCS#7 / CMS cryptographic signature at output time.
Any document containing at least one signature field automatically emits /SigFlags 3 in the AcroForm dictionary, enabling the signing UI in compatible readers.
use DragonOfMercy\PhpPdf\Form\{SignatureField, FieldAppearance};
use DragonOfMercy\PhpPdf\Color;
// A visible signing box (bordered). Left unsigned - the reader signs it.
$page->field(SignatureField::visible(
x: 20, y: 20, width: 80, height: 30, name: 'signature',
appearance: new FieldAppearance(borderColor: Color::rgb(0, 0, 0), borderWidth: 0.5),
));
// An invisible signature field (no on-page rendering)
$page->field(SignatureField::invisible(name: 'approval'));SignatureField::visible() places a rectangle at (x, y) with the given width and height in the document unit. SignatureField::invisible() creates a zero-size annotation (/Rect [0 0 0 0]) with no visual footprint - useful for metadata-level approval workflows.
Both named constructors accept optional required, readOnly, and tooltip parameters. SignatureField does not support JavaScript actions.
MIT licensed. Source on GitHub - if phppdf helps you, you can buy me a coffee.