-
Notifications
You must be signed in to change notification settings - Fork 0
Modifying Existing PDFs
PdfEditor::open() (or PdfEditor::fromBytes()) opens an existing 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.
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 (unencrypted)
$pdf = PdfEditor::open('protected.pdf', 'pass'); // open an encrypted PDF
// or from bytes:
$pdf = PdfEditor::fromBytes($pdfBytes);
$pdf = PdfEditor::fromBytes($pdfBytes, 'pass');PdfEditor now supports editing encrypted PDFs. Pass the document password as the second argument to open() or fromBytes(). The password is optional: PDFs protected with only a permissions password (empty user password) open without a password argument; a supplied password is tried as the user password first, then as the owner password.
The appended incremental revision is automatically re-encrypted using the source document's scheme and recovered file key. The original /Encrypt dictionary and /ID pair are forwarded intact so the edited file remains a valid encrypted PDF that opens with the same password.
Supported encryption schemes: RC4 40-bit, RC4 128-bit, AES-128, AES-256.
use DragonOfMercy\PhpPdf\PdfEditor;
// Permissions-only encryption (empty user password) - no password argument needed:
$pdf = PdfEditor::open('readonly.pdf');
$pdf->setTitle('Updated title');
$pdf->save('readonly-updated.pdf');
// User- or owner-password protected:
$pdf = PdfEditor::open('locked.pdf', 'secret');
$pdf->setTitle('Updated title');
$page = $pdf->appendPage();
$page->cell(0, 10, 'New page added to an encrypted document');
$pdf->save('locked-updated.pdf');Signing limitation. Signing, adding document timestamps, and enabling LTV on an encrypted PDF is not yet supported. PdfEditor throws a PdfException with a clear message if a signature, timestamp, or LTV request is made on an encrypted source. Metadata edits, appended pages, and AcroForm field fills are fully supported.
Use 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. |
Font support for appearances. Appearance generation supports three categories of /DR font:
- Standard-14 fonts (Helvetica, Courier, Times) - always available.
-
Simple embedded fonts (Type1 / TrueType): the library reuses the font from the source PDF (referenced, not re-embedded) and uses its
/Widthsfor measurement and its/Encoding(WinAnsiEncoding base, with/Differences) for encoding. -
Composite embedded fonts (Type0, Identity-H, CIDFontType2 / FontFile2): the library reuses the TrueType composite font from the source PDF and generates a 2-byte GID hex appearance stream. Supported encoding: Identity-H with a
CIDFontType2descendant and an embedded/FontFile2(TrueType) program.
Fail-fast limits that throw a PdfException naming the field: CFF (/FontFile3) composite fonts are not yet supported; non-Identity-H Type0 encodings are not yet supported; simple fonts with a base encoding other than WinAnsiEncoding are rejected; a font missing /Widths is rejected; and a character not representable in the font's encoding is rejected (no silent substitution).
$editor = PdfEditor::open('form.pdf');
$editor->setField('name', 'Jane Doe');
$editor->setField('agree', true);
$editor->flattenFields(); // freeze every value-bearing field
// or: $editor->flattenFields(['name']); // freeze a subset
$editor->save('flattened.pdf');Flattening burns each widget's appearance into the page content and removes the interactivity. Signature and push-button fields are preserved. It works on encrypted sources and is written as an incremental revision, so the original bytes stay intact.
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.
- Signing, adding document timestamps, and enabling LTV on an encrypted source PDF are not yet supported (
PdfEditorthrows aPdfExceptionat sign time; metadata edits, appended pages, and form field fills work normally on encrypted sources). - Appearance generation (form-fill) supports Standard-14 fonts, non-Standard-14 simple fonts (Type1 / TrueType) embedded in the source
/DR, and Type0 composite fonts using Identity-H encoding with aCIDFontType2//FontFile2TrueType descendant. CFF (/FontFile3) composite fonts and non-Identity-H Type0 encodings are not yet supported (the library throws aPdfExceptionnaming the field). - 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.