Download the PHP package restruct/wkhtmltopdf-static without Composer

On this page you can find all versions of the php package restruct/wkhtmltopdf-static. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package wkhtmltopdf-static

restruct/wkhtmltopdf-static

Maintained by Restruct. If this package saves you time, you can support ongoing maintenance.

Pre-built wkhtmltopdf 0.12.6.1 (patched Qt) for PHP projects — bundled static-ish binaries, a fluent PHP wrapper, and a multi-arch Docker fallback for platforms without a native binary.

Why this package exists: the wkhtmltopdf project is archived — 0.12.6.1-3 is the final release, forever. Its binary depends on a patched Qt and a set of aging shared libraries that get harder to satisfy with every new OS release. This package preserves a known-good build in two forms: bundled binaries for platforms that can still run them natively, and a frozen Ubuntu 22.04 Docker image (ghcr.io/restruct/wkhtmltopdf:0.12.6, amd64+arm64) for everything else.

New to Docker or fuzzy on how the pieces fit? Read HOW-IT-WORKS.md — a from-scratch explainer of the image/container/registry/multi-arch story behind this package.

Installation

Requires PHP ≥ 8.1 and symfony/process (^6 or ^7).

Quick start

Every wkhtmltopdf CLI option is reachable — common ones have named methods (pageSize(), orientation(), dpi(), headerHtml(), footerCenter(), javascriptDelay(), username()/password() for HTTP auth, …), everything else via the generic setters:

generateFromHtml()/generateFromUrl() return a WkhtmltoPdfResult (->isSuccessful(), ->output, ->errorOutput, ->exitCode); the getOutput*() variants return raw bytes and throw on failure.

Migrating from knplabs/knp-snappy

The API is a drop-in style replacement:

No binary path needed — resolution is automatic (see below).

Like Snappy, generateFromHtml() and generateFromUrl() create the output file's directory when it does not exist yet, and throw a RuntimeException when it cannot be created (from 1.0.3). Temp files (the HTML input and the getOutput*() PDF) are written to sys_get_temp_dir() and removed after each call.

How execution works: binary first, Docker fallback

WkhtmltoPdfStatic::run() picks a strategy per call:

  1. binary — if a wkhtmltopdf binary is resolved, it runs as a plain OS process. Fastest; Docker not involved at all.
  2. docker: otherwise, if a Docker image is configured and the Docker daemon responds, each call runs a throwaway container: docker run --rm --init --name wkhtmltopdf-<random> --user <uid>:<gid> -v /tmp:/tmp <image> <args>. The system temp dir is volume-mounted so input HTML and output PDF are visible to both host and container, and from 1.2.0 each allowPath() folder is mounted read-only at the same path. An output path outside the temp dir is rendered into the temp dir and moved there afterwards (from 1.2.0; see Docker hardening for what the extra flags do (from 1.2.0).
  3. Neither available → RuntimeException.

Configuration (constants / environment)

bootstrap.php (included automatically on first use, guarded by defined() checks) resolves two constants:

Constant / env var Resolution order
WKHTMLTOPDF_PATH 1. pre-defined constant → 2. env var → 3. macOS: bundled x64/mac binary (runs on Apple Silicon via Rosetta 2) → 4. Linux: /usr/local/bin/wkhtmltopdf (system install), then bundled x64/linux binary
WKHTMLTOPDF_DOCKER_IMAGE 1. pre-defined constant → 2. env var → 3. Linux default: ghcr.io/restruct/wkhtmltopdf:0.12.6@sha256:3b95bf589c125dbcbbb0e33619d1241953d6da019d80272d85858816d01c8396 (pinned by digest from 1.2.0, see The Docker image)
WKHTMLTOPDF_DOCKER_NETWORK 1. pre-defined constant → 2. env var → 3. empty: Docker's default network (from 1.2.0)
WKHTMLTOPDF_LOCAL_FILE_ACCESS 1. pre-defined constant → 2. env var → 3. permissive (from 1.2.0, see Local file access)

Typical .env on a server:

If both resolve, the native binary wins.

A binary only counts as resolved if it can actually start (from 1.1.0). Each candidate path is run once with --version (10 s timeout) and must exit 0; the result is cached for the rest of the PHP process, so this costs one extra process start per path, not one per render. A binary that is executable but cannot start, for example because a shared library is missing, is skipped: the next candidate in the table above is tried, and if none starts the Docker strategy is used. Up to 1.0.3 only the exec bit was checked, so such a binary was chosen anyway and every render failed. WkhtmltoPdfStatic::probeBinary($path) runs the same check by hand.

Security

wkhtmltopdf is a browser. It runs JavaScript, follows URLs and reads files, with a QtWebKit engine that was frozen when the project was archived in 2020 and gets no security fixes. Treat it like that:

Local file access

wkhtmltopdf 0.12.6 blocks a page from loading other local files by default, and a blocked file makes the render exit 1 (checked with the bundled binary). The input HTML is written to a temp file, so this also covers relative URLs in it. You have two ways to allow local files:

WKHTMLTOPDF_LOCAL_FILE_ACCESS lets a project rule out the wide option (from 1.2.0):

Value --enable-local-file-access --allow --disable-local-file-access added
permissive (default) passed passed no
allowlist refused passed yes
deny refused refused yes

Refused means WkhtmltoPdfStatic::run(), and with it every render method, throws an InvalidArgumentException before anything is started. An unknown value throws a RuntimeException, so a typo never means permissive. The added --disable-local-file-access matters for a binary other than the bundled one: wkhtmltopdf 0.12.5 and older allow local file access by default. The default stays permissive in 1.x so existing renders that rely on enable-local-file-access keep working; consider setting allowlist and moving to allowPath().

Under the Docker strategy each allowPath() folder is bind-mounted read-only into the container at the same path (from 1.2.0), so file:// URLs into it work as with the binary. The folder must then be an existing directory, and /, top-level directories, whole home directories and system trees such as /etc are refused; enableLocalFileAccess() reaches only the temp dir there. HTML that inlines its assets (data: URIs) needs none of this and can run with deny. Details, and what each mode did in our renders: docs/troubleshooting.md.

Docker hardening

From 1.2.0 the Docker strategy runs each container with:

Membership of the docker group is root-equivalent. Whoever can talk to the Docker daemon can start a container that mounts the host's / and change anything on it. Adding the PHP user to that group therefore gives PHP (and anything that gets code execution in PHP) root on the host. Prefer the native binary where it runs. Where Docker is needed, consider rootless Docker, whose daemon runs as an unprivileged user, so the socket grants that user's rights instead of root.

Platform support

Platform Native binary Docker image
macOS x64 ✅ bundled (x64/mac) —
macOS ARM (Apple Silicon) ✅ bundled x64 binary via Rosetta 2 ✅ native linux/arm64 (in OrbStack/Docker Desktop)
Linux x64 ✅ bundled (x64/linux, Ubuntu 22.04+, see below) or system deb ✅ linux/amd64
Linux ARM64 ❌ upstream never shipped one ✅ linux/arm64

The Docker image is the answer for every platform without a workable native binary — and the long-term insurance for when OS upgrades break the native ones.

The bundled Linux binary

x64/linux/wkhtmltopdf is the upstream wkhtmltopdf 0.12.6.1 (patched Qt) binary, taken unchanged from the official Ubuntu 22.04 (jammy) amd64 package (from 1.1.0). It links OpenSSL 3, so it runs on Ubuntu 22.04 and 24.04. It does not run on Ubuntu 20.04 or older, which ship OpenSSL 1.1 only. Up to 1.0.3 the bundled binary was an older build linked against OpenSSL 1.1, which in turn could not start on 22.04 and later (#6).

Source https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
.deb sha256 4f723b2691ad8638a9df960e0421d346d7315083e3583a334f33362280ddba15
Binary sha256 750c92708349321a502b92e5e6c16b25499318ec24d1175cc8a81b6aefa321b2 (usr/local/bin/wkhtmltopdf in the .deb)
Version wkhtmltopdf 0.12.6.1 (with patched qt)

Upstream publishes no checksums for its release assets (neither on the release page nor on wkhtmltopdf.org), so the .deb sha256 above is the one we computed on download. It matches the value several unrelated public projects pin for the same file, and the binary matches the MD5 in the .deb's own md5sums list. To check the bundled binary yourself:

Runtime libraries (Ubuntu 24.04)

The binary links these shared libraries (its ELF DT_NEEDED list): libjpeg.so.8, libpng16.so.16, libXrender.so.1, libfontconfig.so.1, libfreetype.so.6, libX11.so.6, libssl.so.3, libcrypto.so.3, libz.so.1, plus the C/C++ runtime (libc, libm, libstdc++, libgcc_s). Fontconfig also needs at least one font installed to render text.

On the official Ubuntu 24.04 server cloud image (package manifest of 2026-09-26) all of these are already installed except libxrender1. A server provisioned with more packages (Laravel Forge, for example) usually has that one too. To be sure on any 24.04 server, run this; apt skips what is already installed:

On 22.04 two of the package names differ: use libpng16-16 and libssl3 instead of libpng16-16t64 and libssl3t64. Then check that nothing is missing:

The upstream .deb also depends on xfonts-75dpi and xfonts-base (X bitmap fonts). The binary starts and renders without them; install them only if your HTML relies on those fonts. CI runs the test suite against the bundled binary on Ubuntu 24.04 with exactly the apt line above.

The Docker image

ghcr.io/restruct/wkhtmltopdf:0.12.6: public, multi-arch (linux/amd64 + linux/arm64). Ubuntu 22.04 with the official final wkhtmltopdf deb and all runtime libraries frozen in.

From 1.2.0 the default reference is pinned to the digest of the multi-platform index:

With a digest, Docker pulls exactly that index and ignores the tag, so re-pushing (or hijacking) the 0.12.6 tag cannot change what runs. Each platform's manifest is itself content-addressed from the index, so one digest covers amd64 and arm64. To check what the registry serves:

Both must print the digest above. If you set WKHTMLTOPDF_DOCKER_IMAGE yourself, pin it the same way. Backups of the image and the .deb files it was built from, and how to restore or rebuild from them, are described in HOW-IT-WORKS.md.

Built from build/Dockerfile:

Server deployment (pulling the image, adding the PHP user to the docker group, a deploy-script line) is outlined in HOW-IT-WORKS.md; keep host-specific notes in your own project docs.

Native install on Ubuntu servers (verified on 22.04 jammy AND 24.04 noble)

Hard-won gotchas from getting this running on a production server:

Package contents

Running the tests

The render tests need a working wkhtmltopdf (the bundled binary or the Docker image) and are skipped without one.

Visual check

A change of wkhtmltopdf version, of strategy (bundled binary, native install, Docker) or of the fonts on a host can change the size and placement of everything on a page without any error. The visual check renders a fixed fixture and compares the result, so such a change shows up as a red test with a diff image instead of in a client's documents. It lives in tests/Visual/ (dev only, not in dist installs) and needs restruct/xpdf-static (require-dev, for pdfinfo and pdftopng) and ext-gd.

What it compares, per render:

The fixture

tests/Visual/fixture/ holds plain HTML and CSS with everything sized in mm: a frame exactly on the paper edge and one 10 mm in, rulers with a tick per mm, a 50 x 50 mm box, a generated PNG (make-image.php, no SVG) shown at 50 x 25 mm, a monospace block with known line wraps (five 10-digit groups per line), host-font samples in several sizes, a table with mm column widths, forced and avoided page breaks, and an HTML header and footer. The cases use the option sets that real document pipelines need:

Case Options Pages
fullbleed margins 0px, --enable-local-file-access, --disable-smart-shrinking; two exact 210 x 297 mm page boxes, the second with its text pushed 210 mm down by padding 2 x A4
lowquality fullbleed plus --lowquality (knp-snappy passes it by default, this wrapper does not) 2 x A4
flow margins 16 mm top, 20 mm bottom, 0 sides; flowing content with page-break-before/after/inside, an element pulled 16 mm up into the margin 3 x A4
header-footer margins 25 / 20 mm, --header-html, --footer-html (page X / Y), spacing 5 mm 2 x A4

Fonts are host fonts only: 'DejaVu Sans Mono', monospace for the fixed text (DejaVu comes with the apt line above; macOS falls back to its own monospace font), and sans-serif, Arial, Helvetica, sans-serif and serif for the samples, as most templates use. Line heights are fixed in mm wherever text flows, so the page count does not depend on the fonts; the pixels do, which is how a host font change is caught. An @font-face webfont was tried and dropped: the bundled macOS binary applied it in only 30 of 40 renders of the same files (loaded by file URL, as a data: URI, and with --javascript-delay 1000) and used a system font in the others, which no fixed baseline can absorb. Keep that in mind for real templates too. Later measurements (webfont formats, javascript-delay, Docker): docs/troubleshooting.md.

Baselines per platform

Fonts and the macOS and Linux builds of wkhtmltopdf render text differently, so the baseline PNGs are per platform: tests/Visual/baselines/darwin/ (bundled macOS binary) and tests/Visual/baselines/linux/ (bundled Linux binary on Ubuntu 24.04 with the apt line above). The platform is where the rendering happens, so the Docker strategy compares against linux even on a Mac. Between the two, every mm-placed element (frames, rulers, box, image, table) lands on the same pixel; only the text differs. On the CI runner the generic serif and monospace families render in a sans-serif font, so name a real font family when a template needs one: on Linux wkhtmltopdf resolves only real family names, not generic families or aliases (see docs/troubleshooting.md). Docker on Apple Silicon runs the arm64 image, a different build; for this fixture its pages are pixel-identical to the amd64 image and to the bundled binary on a stock Ubuntu 24.04, and all three differ from the linux baselines only in the text samples, because the GitHub runner has more fonts installed (measured 2026-10-12).

Running it

The tests are skipped when ext-gd, xpdf or the renderer is missing (CI treats a skip as a failure). Strategies: auto (whatever this package resolves, through the wrapper), bundled, native (/usr/local/bin/wkhtmltopdf), docker or docker:<image>, or a path to any wkhtmltopdf binary. A platform without baselines fails rather than passes, and proposes its render as baselines under out/proposed-baselines/.

The group also holds must-fail controls: the fullbleed case rendered with smart shrinking back on, --zoom 1.02, a 4 px left margin and --page-size Letter must each be reported as different. If one of those ever passes, the check has gone blind to that kind of change.

The same check without PHPUnit, plus a direct comparison of two strategies or binaries (no baselines involved), for use before switching a host:

Exit code 0 is a pass, 1 differences, 2 a usage error or missing prerequisite. Look at new baseline PNGs before committing them: a baseline is a claim that this output is right.

What it showed on the bundled macOS binary (0.12.6)

Measured with compare bundled bundled --b-opt=... against the fullbleed case:

Troubleshooting

docs/troubleshooting.md collects what we measured: fonts (generic families on Linux, WOFF2, webfonts on the macOS binary), local file access per mode and under Docker, page size and smart shrinking, binaries that do not start (exit 127), timeouts and leftover containers, and how to verify a restored image backup.

License

composer.json declares this as (MIT AND LGPL-3.0-or-later). See LICENSE for the full terms.


All versions of wkhtmltopdf-static with dependencies

PHP Build Version
Package Version
Requires php Version >=8.1
symfony/process Version ^6.0 || ^7.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package restruct/wkhtmltopdf-static contains the following files

Loading the files please wait ...