-
Notifications
You must be signed in to change notification settings - Fork 0
Modifying Existing PDFs
PdfEditor::open() (or PdfEditor::fromBytes()) opens an existing non-encrypted PDF and lets you update its metadata, append new pages, fill its AcroForm fields, and sign it - all without touching the original bytes. Every change is written as an appended incremental revision, so the original content (including any signatures already present) remains byte-for-byte intact.
Encrypted sources are rejected at open time with a clear PdfException. Decrypt the file first (e.g. with qpdf --decrypt) before opening it here.
Both classic xref tables and cross-reference streams (PDF 1.5+) are supported.
use DragonOfMercy\PhpPdf\PdfEditor;
$pdf = PdfEditor::open('invoice.pdf'); // open from file path
// or
$pdf = PdfEditor::fromBytes($pdfBytes); // open from a string of bytesUse the fluent setters to update the document's information dictionary. When the file already contains an XMP metadata packet, it is refreshed to stay consistent.
$pdf = PdfEditor::open('report.pdf');
$pdf->setTitle('Annual Report 2025')
->setAuthor('Acme Corp')
->setSubject('Finance')
->setKeywords('annual report finance 2025')
->setCreator('ReportGenerator 3.0');
$pdf->save('report-updated.pdf');
// or get the bytes directly:
$bytes = $pdf->output();All five setters are optional - set only what you need. save() writes to a file; output() returns the PDF bytes as a string.
appendPage() appends a blank page and returns a fully functional Page object. You can draw on it with the complete page API: cells, images, tables, barcodes, SVG, Markdown, and so on.
use DragonOfMercy\PhpPdf\PdfEditor;
use DragonOfMercy\PhpPdf\Font;
$pdf = PdfEditor::open('contract.pdf');
$page = $pdf->appendPage();
$page->setFont(Font::helvetica(), 11);
$page->cell(0, 10, 'Addendum - see attachment A');
$pdf->save('contract-with-addendum.pdf');The appended page is part of the same incremental revision as any metadata edits you make, so a single save() / output() call writes everything at once.
Open a PDF that contains an AcroForm, inspect its fields, set values, and save. Each filled field gets a generated appearance stream (/AP) so the value is rendered without relying on viewer-side rendering, and /NeedAppearances false is written.
use DragonOfMercy\PhpPdf\PdfEditor;
$pdf = PdfEditor::open('form.pdf');
foreach ($pdf->formFields() as $field) {
echo $field->name, ' [', $field->type, ']', PHP_EOL;
}formFields() returns list<FormFieldInfo>. field($name) returns a single FormFieldInfo or throws if the name is not found.
$pdf = PdfEditor::open('application.pdf');
$pdf->setField('FullName', 'Alice Dupont'); // text (single-line or multiline)
$pdf->setField('Subscribed', true); // checkbox
$pdf->setField('Gender', 'female'); // radio (export-name string)
$pdf->setField('Country', 'ch'); // combobox (export key)
$pdf->setField('Languages', ['en', 'fr']); // listbox (one or more export keys)
$pdf->save('application-filled.pdf');| Field type | Value type | Notes |
|---|---|---|
| Text (single-line) | string |
Written as-is. |
| Text (multiline) | string |
Newlines preserved. |
| Checkbox | bool |
true checks the field. |
| Radio button | string |
The export name of the button to select. |
| Combobox | string |
The export key of the chosen option. |
| Listbox | string|list<string> |
Pass an array to select multiple items. |
Limitations. Appearance generation supports Standard-14 /DR fonts only; fields whose default-resource font is embedded or non-standard throw a PdfException. Fields are not flattened - they remain interactive after filling.
PdfEditor::sign(), addSignature(), addDocumentTimestamp(), and enableLtv() work on an opened PDF with full parity to Document. Each signature, document timestamp, or /DSS is written as a stacked incremental revision that leaves the original bytes intact and cryptographically covers every prior byte - including any metadata edits, appended pages, and field fills, which are written as the first revision.
use DragonOfMercy\PhpPdf\PdfEditor;
use DragonOfMercy\PhpPdf\Signature\SigningCertificate;
use DragonOfMercy\PhpPdf\Signature\Tsa;
$pdf = PdfEditor::open('form.pdf');
$pdf->setField('FullName', 'Alice');
$pdf->sign(
SigningCertificate::fromPkcs12('cert.p12', 'password'),
field: 'Approval',
reason: 'I approve this document',
timestamp: Tsa::http('https://freetsa.org/tsr'),
)->save('signed.pdf');See the Digital Signatures page for the full API reference: signature formats (adbe.pkcs7.detached / ETSI.CAdES.detached), multiple signers, document timestamps, long-term validation (LTV / PAdES-B-LT / B-LTA), and visible signature appearance.
- Encrypted PDFs are rejected at open time.
- Appearance generation (form-fill) uses Standard-14
/DRfonts only. - Form fields are not flattened after filling.
- A source whose
/AcroFormis a direct (inline) dictionary is rejected when signing - the/AcroFormmust be an indirect reference. - The visible signature caption (when using
SignatureAppearance) is drawn with Standard-14 Helvetica only.
-
Reading Existing PDFs - low-level
PdfReaderfor parsing and object access - Digital Signatures - full signature API reference
- Interactive Forms - creating forms from scratch in a new document
MIT licensed. Source on GitHub - if phppdf helps you, you can buy me a coffee.