Library / SDK
mikehaertl/php-pdftk avatar
mikehaertl/php-pdftk

php-pdftk: a PHP face for a command line tool that already does the job

A PDF conversion and form utility based on pdftk

1,017 stars135 forksPHPMIT

At a glance

What is it?
php-pdftk is an MIT-licensed PHP library that wraps the `pdftk` command line tool to fill PDF forms, split and combine files, and manage encryption, with UTF-8 safe FDF and XFDF generation as a bonus. The judgement is that the wrapper's real value is its error handling and its PDF form workflow, and that the `pdftk` binary dependency is the thing to plan for.
Who is it for?
php-pdftk fits a PHP application that has to fill a PDF form with data, stamp and assemble documents, or remove and set encryption, and that would rather call a well-known binary than implement PDF internals in PHP.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 94 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A PHP wrapper around pdftk, and what that means for you

php-pdftk is a PDF conversion and form utility based on `pdftk`. The framing in the README is that it brings the full power of `pdftk` to PHP, and more.

The word "based on" is doing the work here. This is not a pure PHP PDF implementation. It is a PHP API over the `pdftk` command line tool, and the requirements are explicit: the `pdftk` command must be installed and working on your system. Every operation in this library is ultimately a command invocation.

That has an obvious downside and an obvious upside, and the library leans into both. The downside is a native binary dependency, with all that implies for deployment, container images and version matching. The upside is that PDF handling is a mature, well-documented command line tool with a man page covering every operation, and the README tells you to consult that man page for the details of each operation and the options available. You are not locked into this library's idea of how a form should be filled, because pdftk's own documentation is the reference.

The feature list covers the operations you would expect. Fill forms, either from an XFDF or FDF file or from a data array, which is UTF-8 safe for unflattened forms and requires pdftk 2.x. Create XFDF or FDF files from PHP arrays, UTF-8 safe. Create FDF files from filled PDF forms. Combine pages from several PDF files into a new one. Split a PDF into one file per page. Add background or overlay PDFs. Read out metadata about the PDF and its form fields. Set passwords and permissions. And remove passwords.

The licence is MIT, with a `LICENSE` file at the repository root. The package is `mikehaertl/php-pdftk` on Packagist, and the last push was on 2026-07-21 with the repository not archived, so the most recent release, 0.14.4 from 2026-07-15, is close to the tip of the tree.

Files, handles and passwords, all set at construction time

The constructor is where you declare which PDFs the instance will work on, and the options are worth understanding because they set the vocabulary for the operations that follow.

php
// Create an instance for a single file
$pdf = new Pdf('/path/to/form.pdf');

// Alternatively add files later. Handles are autogenerated in this case.
$pdf = new Pdf();
$pdf->addFile('/path/to/file1.pdf');
$pdf->addFile('/path/to/file2.pdf');

// Add files with own handle
$pdf = new Pdf();
$pdf->addFile('/path/to/file1.pdf', 'A');
$pdf->addFile('/path/to/file2.pdf', 'B');
// Add file with handle and password
$pdf->addFile('/path/to/file3.pdf', 'C', 'secret*password');

A handle is the name a file is referred to by in later operations, and it is needed when you are working with more than one file and referring to a specific one. Some files also require a password or need an alias to be used as a handle in some operations, such as `cat` or `shuffle`.

There is a version constraint on handles, and the documentation puts it in a note: in version 2.x of pdftk a handle can be one or more upper case letters. That is a pdftk 2.x change, and it explains the `A`, `B`, `C` in the example above.

Passwords are attached at the same point. The single-argument form is a plain password, and the array form pairs a file with a password, using the `*` separator for the owner and user passwords:

php
// Shortcut to pass all files to the constructor
$pdf = new Pdf([
  'A' => ['/path/to/file1.pdf', 'secret*password1'],
  'B' => ['/path/to/file2.pdf', 'secret*password2'],
]);

One operation per instance, and a check for false that people skip

There is a constraint in the documentation that shapes how you write the calling code, and it is stated as important: you can always only perform one of the listed operations on a single PDF instance. A workaround is mentioned for the case where you need multiple operations.

The reason is not hard to see. An operation like `cat` produces a new document, and the library is chaining a sequence of commands into a single invocation of `pdftk`. Once that invocation has been run and its output captured, the instance has done its job.

The output pattern is consistent across the examples. Each operation returns the instance, so calls chain, and the chain ends with `saveAs()` or `send()`:

php
$pdf = new Pdf('/path/to/my.pdf');
$result = $pdf->cat(1, 5)
    ->cat([7, 4, 9])
    ->saveAs('/path/to/new.pdf');
if ($result === false) {
    $error = $pdf->getError();
}

Two details in that snippet matter. The return value of the terminal call is what you check, and it is `false` on failure. And the error text is retrieved separately with `getError()`.

The README is explicit about the check: always check for errors. Every example in the documentation repeats the `if ($result === false)` block, and the reason is that a failed pdftk invocation is otherwise silent, since the chained calls look like they succeeded.

The two ways to get the output are `saveAs($name)`, which writes the PDF locally, and `send()`, which sends it to the browser. If you pass a filename to `send($name)` the client browser will open a download dialogue, whereas without a filename it will usually display the PDF inline.

That second behaviour is the one to think about. Inline display means the response is a PDF with the right content type, and a download dialogue means an attachment. Which one you want depends on whether the user is looking at a document or taking it away.

Filling a form, and the UTF-8 caveat that comes with it

Form filling is the feature that justifies the library, and it comes with a specific instruction that is easy to miss.

php
use mikehaertl\pdftk\Pdf;

// Fill form with data array
$pdf = new Pdf('/full/path/to/form.pdf');
$result = $pdf->fillForm([
        'name'=>'ÄÜÖ äüö мирано čárka',
        'nested.name' => 'valX',
    ])
    ->needAppearances()
    ->saveAs('filled.pdf');

The array keys are field names, and a dotted name addresses a nested field. The values are the data, and the example deliberately uses non-ASCII characters in several scripts.

The note that follows is the important one. When filling in UTF-8 data, you should always add the `needAppearances()` option. This makes sure that the PDF reader takes care of using the right fonts for rendering, something that pdftk cannot do for you. And `flatten()` does not really work well if you have special characters in your data.

That is a genuine limitation of the approach rather than a bug in the wrapper. pdftk writes the text into the PDF but does not embed or select an appropriate font for characters outside the base encoding, so the appearance stream is marked as needing regeneration and the reading application does the work. If you flatten the form, that opportunity is lost and the text renders with whatever font the form specified.

There is a middle path for one specific case. If you use `pdftk-java` 3.3.0 or newer and the embedded font does not support UTF-8 characters, you can replace it with a local font:

php
$result = $pdf->fillForm($data)
    ->replacementFont('/usr/share/fonts/dejavu/DejaVuSans.ttf')
    ->saveAs('filled.pdf');

So the two options are: leave the appearance stream to the reader, or pick a font that covers your characters and embed it. The first is simpler and works with any reader, the second gives you control and works with flatten.

XFDF and FDF generation, which pdftk does not do

One feature is explicitly labelled as a bonus that is not available from `pdftk` itself, and it is the one piece of genuine added value in the library.

php
use mikehaertl\pdftk\XfdfFile;
use mikehaertl\pdftk\FdfFile;

$xfdf = new XfdfFile(['name' => 'Jürgen мирано']);
$xfdf->saveAs('/path/to/data.xfdf');

$fdf = new FdfFile(['name' => 'Jürgen мирано']);
$fdf->saveAs('/path/to/data.fdf');

So the library can produce the two data file formats that `fillForm` consumes, from a plain PHP array, and it does so UTF-8 safe. Since `fillForm` can then be pointed at the generated XFDF or FDF file, the workflow is: build your data as a PHP array with whatever encoding your application uses, write it out as XFDF or FDF, and feed it back in.

The value here is the encoding. `pdftk` can read an XFDF or FDF file, but the round trip from a PHP array with non-ASCII data is the part the library handles, and the example uses a name with German, Cyrillic and accented Latin characters to make the point.

Note that the two classes are separate, `XfdfFile` and `FdfFile`, with separate `saveAs` calls, and neither takes a `Pdf` instance. They are standalone writers.

The remaining operations, `cat`, `shuffle` and the rest, are thin wrappers over pdftk's own command surface, and the documentation sends you to the pdftk man page for the details. The `cat` example in the README is the most involved of them, because it shows the full syntax:

php
$result = $pdf->cat(1, 5, 'A')                // pages 1-5 from A
    ->cat(3, null, 'B')             // page 3 from B
    ->cat(7, 'end', 'B', null, 'east') // pages 7-end from B, rotated East
    ->cat('end',3,'A','even')       // even pages 3-end in reverse order from A
    ->cat([2,3,7], 'C')             // pages 2,3 and 7 from C
    ->saveAs('/path/new.pdf');

The arguments are page ranges, a handle, a rotation direction, and the special keywords `end` and `even`. `shuffle` works like `cat` but creates streams and fills the new PDF with one page from each stream at a time, which is the standard way to interleave a set of documents.

The binary dependency is where deployments go wrong

The requirements section is where a careful reader should spend time, because the failure modes are environmental rather than logical.

The library is written for pdftk 2.x versions. You should be able to use it with pdftk 1.x, but not all methods will work there, and the documentation points to the pdftk man page on your system for details.

Then there is the known issue on Ubuntu with the `pdftk` package installed from snap. That version has no permission to write to the `/tmp` directory, so you can either set another temporary directory as described in the documentation or use another package. For Ubuntu 18.10 there is also a `pdftk-java` package available via apt which should work fine, and the same applies to Ubuntu 18.04 if you download it manually. The documentation also links an answer on askubuntu.

There is a further note that the pdftk version from the alternative PPA `ppa:malteworld/ppa` is no longer available, and the author now points to his askubuntu answer instead.

That is a stack of workarounds for one environmental problem, and it is a good illustration of what wrapping a command line tool costs. The snap packaging problem is not specific to this library, but this library is where you find out about it.

Installation of the library itself is unremarkable:

bash
composer require mikehaertl/php-pdftk

Composer is the recommended method, and the repository is a conventional PHP package with `composer.json` at the root, a `src/` directory, a `tests/` directory with `phpunit.xml.dist`, a `psalm.xml` for static analysis, a `.php-cs-fixer.dist.php` for code style, and a `vendor-bin/` directory.

The release cadence is steady. Version 0.14.2 came on 2025-10-01, 0.14.3 on 2026-06-24, and 0.14.4 on 2026-07-15, so the line has moved several times over the past year, with a longer gap in the middle.

Editorial conclusion

php-pdftk fits a PHP application that has to fill a PDF form with data, stamp and assemble documents, or remove and set encryption, and that would rather call a well-known binary than implement PDF internals in PHP. It does not fit a deployment that cannot run a native binary, since every operation shells out to `pdftk`, and it does not fit a team that needs reliable UTF-8 rendering of filled forms on its own, because the library explicitly hands that job to the PDF reader via `needAppearances()`. Verify first that the `pdftk` on the target machine is a 2.x build, since the library is written for 2.x and not all methods work on 1.x, that the binary can write to its temporary directory, which is the known failure with the snap package on Ubuntu, and that you call `needAppearances()` whenever the data contains non-ASCII characters.

Frequently asked questions

How do I install php-pdftk?

Use Composer with `composer require mikehaertl/php-pdftk`. The `pdftk` command must also be installed and working on the system, since the library wraps that binary rather than implementing PDF handling itself.

Which version of pdftk does php-pdftk require?

The library is written for pdftk 2.x versions. You should be able to use it with pdftk 1.x, but not all methods will work there, and the documentation points to the pdftk man page on your system for the details.

Why do my filled PDF forms show the wrong characters?

When filling in UTF-8 data you should always add the `needAppearances()` option, which makes the PDF reader use the right fonts for rendering, something pdftk cannot do for you. If you use `pdftk-java` 3.3.0 or newer and the embedded font lacks the characters, you can also set a `replacementFont`.

How do I check whether a php-pdftk operation failed?

The terminal call returns false on failure, and the error text is retrieved with `$pdf->getError()`. The documentation repeats the `if ($result === false)` check in every example and marks it as important.

Can php-pdftk create the XFDF or FDF data files itself?

Yes, and the documentation calls it a bonus feature not available from pdftk. The `XfdfFile` and `FdfFile` classes take a PHP array and write an XFDF or FDF file, UTF-8 safe, which can then be used with `fillForm`.

Official sources

  1. Issues
  2. License: MIT
  3. mikehaertl/php-pdftk on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mikehaertl-php-pdftk.svg)](https://hysenlabs.com/projects/mikehaertl-php-pdftk)

Was this useful?