Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use a Composer-installed HTML-to-PDF renderer, not a browser print command. For a straightforward PHP implementation, Dompdf provides a short loadHtml() → render() → stream() flow. mPDF is another practical choice, especially for UTF-8 HTML, but it has its own extension and temporary-directory requirements. Neither is universally best: the right choice depends on your CSS, fonts, assets, PHP release, and deployment environment.

Choose the renderer before writing code

HTML-to-PDF libraries do not render exactly like Chrome or Firefox. Inventory the template first: does it use flexbox, CSS Grid, web fonts, long tables, SVG, remote images, or user-supplied markup? Then verify the selected package release against your PHP version and enabled extensions. Development-branch documentation can differ from stable-release requirements, so pin a version and read that version’s documentation.

Constraint Dompdf mPDF
Installation composer require dompdf/dompdf composer require mpdf/mpdf
Rendering model Mostly CSS 2.1-oriented PHP renderer UTF-8 HTML renderer with its own layout behavior
Important layout caveats No flexbox or CSS Grid; table rows must fit on one page; raw inline SVG has limitations Validate the actual template and pagination; do not assume browser-equivalent CSS
Runtime checks Package-release PHP requirements; cURL or allow_url_fopen for remote assets mbstring and GD; advanced features may need zlib, bcmath, or XML
Filesystem/operations Local files must stay inside configured chroot paths Use a dedicated writable temporary directory; external HTTP fetching can fail on PHP’s single-threaded development server

The table describes documented capabilities and requirements, not a speed or quality benchmark. Measure memory, latency, and output using your own documents if those factors affect a production decision.

Convert HTML to PDF with Dompdf

1. Install and bootstrap

From your project directory, install Dompdf with Composer:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
composer require dompdf/dompdf

Include Composer’s autoloader. Create a new Dompdf instance for each document; parser and rendering state should not be reused between unrelated documents.

2. Render a complete document

<?php
require __DIR__ . '/vendor/autoload.php';

use DompdfDompdf;
use DompdfOptions;

$html = '<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style>
    @page { margin: 22mm 18mm; }
    body { font-family: DejaVu Sans, sans-serif; font-size: 11pt; line-height: 1.45; }
    h1 { font-size: 22pt; margin: 0 0 12pt; }
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 0.2mm solid #999; padding: 5pt; }
  </style>
</head>
<body>
  <h1>Invoice</h1>
  <p>Generated from trusted, escaped application data.</p>
</body>
</html>';

$options = new Options();
$options->set('isRemoteEnabled', false);

$pdf = new Dompdf($options);
$pdf->loadHtml($html, 'UTF-8');
$pdf->setPaper('A4', 'portrait');
$pdf->render();
$pdf->stream('invoice.pdf', ['Attachment' => true]);

The paper and orientation can be changed, for example to letter and landscape. In a web response, send no HTML before stream(); accidental whitespace, warnings, or a UTF-8 byte-order mark can corrupt the PDF response. For an API or queue worker, obtain the rendered bytes using the package’s documented output method and store them rather than streaming them directly.

3. Load images and styles safely

Dompdf requires isRemoteEnabled to be true for remote assets, and PHP must have cURL or allow_url_fopen enabled. Local references must remain within the configured chroot. Prefer local, allowlisted assets whenever possible:

$options = new Options();
$options->set('chroot', __DIR__ . '/public/pdf-assets');
$options->set('isRemoteEnabled', false);

If a trusted, fixed remote image is unavoidable, enable remote loading only for that use case and enforce URL allowlists. Never let arbitrary user HTML choose unrestricted filesystem paths or fetch internal network addresses.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Convert HTML to PDF with mPDF

1. Install the package and verify extensions

composer require mpdf/mpdf

mPDF’s documented baseline requires the mbstring and GD extensions. Depending on the features you use, zlib, bcmath, or XML may also be required. Check the exact package release and your PHP image before deployment.

2. Write UTF-8 HTML and output the file

<?php
require __DIR__ . '/vendor/autoload.php';

$mpdf = new MpdfMpdf([
    'tempDir' => __DIR__ . '/var/mpdf-temp',
]);

$html = '<!doctype html>
<html lang="en">
<head><meta charset="utf-8"></head>
<body>
  <h1>Report</h1>
  <p>UTF-8 text: café, Ελληνικά, हिन्दी, 日本語.</p>
</body>
</html>';

$mpdf->WriteHTML($html);
$mpdf->Output(__DIR__ . '/var/report.pdf', MpdfOutputDestination::FILE);

For a browser download, use the package’s inline or download destination instead of FILE. Create the temporary directory before the request, make it writable by the PHP user, and dedicate it to mPDF: mPDF cleans old temporary files there. Do not point it at a shared directory containing unrelated application data.

mPDF warns that fetching external HTTP resources can fail on single-threaded servers such as PHP’s built-in server. Test remote assets behind Apache or nginx with PHP-FPM, or download approved assets before rendering.

Prepare HTML that survives PDF pagination

Use a PDF-friendly CSS subset

  • Use explicit widths, margins, and page sizes rather than relying on viewport units.
  • Prefer normal document flow and tables for tabular data.
  • Do not depend on flexbox or CSS Grid when targeting Dompdf.
  • Keep table rows small enough to fit on one page; split very large records into separate rows or sections.
  • Use print-oriented rules such as @page, and test headings, footers, images, and page breaks with representative content.

Make fonts and encoding deliberate

Set a UTF-8 meta tag and pass UTF-8 input. Built-in PDF base fonts have limited character coverage. If your document contains accented, Cyrillic, Arabic, Indic, or CJK text, provide a font with the required glyphs and configure it according to the renderer’s documentation. Test real names and symbols, not only ASCII placeholders.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Escape application data

Generate the template separately from the data, escape text for the HTML context, and validate URLs and attributes. User input passed to mPDF must be vetted and sanitized beyond ordinary browser-level sanitization. The same rule applies to Dompdf: HTML-to-PDF processing can read files or make network requests if you configure it to do so.

A production workflow

  1. Pin the dependency. Commit composer.lock and verify the package’s PHP and extension requirements in CI.
  2. Build a deterministic template. Keep CSS and approved assets in known locations; avoid runtime dependence on third-party pages.
  3. Render in isolation. Create one renderer instance per document and set an explicit paper size and orientation.
  4. Validate the output. Check HTTP headers, PDF readability, page count, fonts, images, table breaks, and non-Latin text.
  5. Apply limits. Bound HTML size, image dimensions, render time, and memory. Queue large reports instead of blocking a web request.
  6. Observe failures. Log the package version, template identifier, render duration, memory peak, and sanitized error details; never log secrets or untrusted HTML.

Troubleshooting common failures

“Class not found” after installation

The request is probably not loading Composer’s autoloader, or the command ran in a different project directory. Confirm vendor/autoload.php exists, deploy the vendor directory or run Composer during deployment, and use the same PHP binary for Composer and the web worker.

Images or CSS are missing

Check URL resolution, file permissions, and the renderer’s resource policy. For Dompdf, remote loading is off unless isRemoteEnabled is enabled, and local files outside chroot are rejected. Convert relative paths to known local paths or allowlist specific remote hosts. For mPDF, test external fetching under the production web server rather than PHP’s built-in server.

Modern layout collapses

This is expected when the template relies on browser-only features. Replace flexbox or Grid with supported block/table layout for Dompdf, simplify selectors, and introduce explicit widths. If browser-level CSS fidelity is mandatory, a browser automation service may be a better architecture than a PHP-only renderer.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Text is blank, boxed, or garbled

Confirm UTF-8 at every stage, embed or configure a font covering the characters, and test that the deployed machine can read the font files. A font available on your laptop may not exist in the container or server.

Tables overlap or split badly

Reduce cell content, set predictable column widths, and test long values. Dompdf documents that table rows must fit on one page, so split oversized records rather than expecting a row to break cleanly.

Permission or temporary-file errors

Ensure the PHP worker can write the configured mPDF temporary directory and that it is dedicated to mPDF. Check container read-only mounts, SELinux/AppArmor policy, and cleanup jobs before changing permissions broadly.

The downloaded PDF is corrupt

Remove output before the PDF headers, disable display of PHP warnings in production, and return the correct content type. Save the bytes to disk first when debugging, then inspect the response for stray text or a partial render caused by a timeout.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When a URL, rather than a PHP template, is the source

If the document already exists as a public web page, a screenshot/PDF API can avoid maintaining a browser-rendering setup. ScreenshotNeo accepts one GET request and can return a PDF; it also supports waits, custom headers and cookies, JavaScript, page ranges, paper size, margins, and landscape output. It is not a replacement for sanitizing HTML you generate inside PHP, but it is useful when the input is a URL and browser behavior matters.

Or skip the browser setup

Call ScreenshotNeo’s endpoint with your page URL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

For PDF output, use the PDF options described in the ScreenshotNeo documentation and set the target URL to your own page. The service accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server gives Claude, Cursor, and other MCP clients take_screenshot, get_page_info, and capture_pdf tools.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Cost, reliability, and security decisions

  • Cost: Dompdf and mPDF run in your PHP infrastructure, so account for CPU, memory, storage, and operational work rather than assuming rendering is free.
  • Reliability: There is no documented universal speed advantage here. Benchmark your largest HTML, worst-case images, and longest tables on the exact production image.
  • Isolation: Treat HTML and resource URLs as potentially dangerous. Use allowlists, filesystem chroots, private-network protections, size limits, and timeouts.
  • Reproducibility: Pin versions, package fonts and assets, and keep a small visual regression corpus containing multilingual text, long tables, images, and page breaks.

Frequently Asked Questions

Can I convert HTML to PDF without installing a PHP library?

Yes, a URL-to-PDF service can render an existing web page, but PHP-generated or private HTML still needs a controlled handoff, authentication strategy, and resource policy. A Composer renderer keeps the conversion inside your application.

Which library should I choose for a new project?

Choose after testing the real template. Dompdf is a concise option for supported CSS; mPDF is a documented alternative with UTF-8 handling and additional extension and temporary-directory requirements.

Why does my PDF differ from the browser preview?

PHP renderers are not full browser engines. Unsupported CSS, font availability, pagination rules, and asset-loading policy can all change the result.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.