PDF Generation in PHP: Tools and Approaches That Produce Quality Output
Generating PDF documents from web applications is a common requirement for invoice generation, report creation, printable receipts, and automated documentation. PHP offers several approaches to this problem, each with distinct advantages and limitations. Choosing the right method early saves significant refactoring time later.
This guide covers the most practical tools available for PHP PDF generation, with working examples and guidance on when each approach works best.
Why PDF Generation Matters for Business Applications
Businesses need PDFs for documents that must look consistent across all devices and platforms. An invoice generated as HTML might render differently in Chrome versus Safari, or break entirely on a mobile device. A PDF preserves your formatting exactly, ensuring clients see what you intended regardless of how they open the document.
Beyond consistency, PDFs serve legal and professional purposes. Official documents, contracts, and financial statements carry more weight when presented as PDFs rather than web pages. The format is universally recognised and difficult to alter after creation.
Automating PDF generation also reduces manual work. Instead of exporting documents manually, your application can generate hundreds of invoices or reports on demand without human intervention.
Dompdf: A PHP-First Solution
Dompdf is a PHP library that converts HTML and CSS into PDF documents. It parses your HTML, applies CSS styling, and renders the result as a PDF file. For many PHP developers, this is the most straightforward approach because it leverages existing HTML knowledge.
Installing Dompdf via Composer
The easiest way to install Dompdf is through Composer:
composer require dompdf/dompdf
This pulls the latest stable version and its dependencies into your project.
Basic Dompdf Usage Example
Here is a simple example showing how to generate a PDF from HTML:
require_once 'vendor/autoload.php';
use Dompdf\Dompdf;
$dompdf = new Dompdf();
// Simple HTML content
$html = '
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
h1 { color: #333; }
table { width: 100%; border-collapse: collapse; }
td, th { border: 1px solid #ddd; padding: 8px; }
</style>
</head>
<body>
<h1>Invoice #12345</h1>
<p>Generated on: ' . date('Y-m-d') . '</p>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>Web Development</td><td>10</td><td>£750.00</td></tr>
<tr><td>Hosting Setup</td><td>1</td><td>£150.00</td></tr>
</table>
</body>
</html>';
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$dompdf->stream('invoice.pdf', ['Attachment' => true]);
This generates a simple invoice PDF and forces a download. Change the Attachment parameter to false to display the PDF inline in the browser instead.
Dompdf Limitations
Dompdf has a CSS compatibility level roughly equivalent to CSS 2.1. It handles most common styling well, but complex layouts with floating elements, advanced positioning, or newer CSS properties may not render correctly. If your design relies heavily on flexbox or grid layouts, test early to confirm Dompdf handles your specific use case.
External resources such as images, fonts, or stylesheets referenced via absolute URLs load correctly. Relative URLs work if you set the appropriate base path:
$dompdf->setOptions([
'rootPath' => '/var/www/myapp/public/'
]);
When Dompdf Works Well
- Invoices and receipts: Structured documents with tables, headers, and basic styling.
- Reports with tables: Data-heavy documents where layout is relatively linear.
- Simple letters and templates: Documents that do not require complex positioning.
- Developer-friendly projects: When your team is more comfortable with HTML and CSS than PDF-specific APIs.
wkhtmltopdf: High-Quality Rendering via WebKit
wkhtmltopdf uses the Qt WebKit rendering engine to convert HTML to PDF. Because it renders pages the same way a web browser does, it handles modern CSS, JavaScript, and complex layouts with greater accuracy than pure PHP libraries.
Installation
wkhtmltopdf is a command-line tool that must be installed on your server. On Ubuntu or Debian, install it with:
sudo apt update
sudo apt install wkhtmltopdf
For other operating systems, download the appropriate package from the wkhtmltopdf website.
Calling wkhtmltopdf from PHP
Once installed, you can call wkhtmltopdf directly from PHP using the exec or shell_exec functions:
<?php
$htmlFile = '/tmp/document.html';
$outputFile = '/var/www/myapp/public/invoices/output.pdf';
// Render the HTML to a temporary file first
file_put_contents($htmlFile, $htmlContent);
$command = "wkhtmltopdf --page-size A4 --orientation Portrait --print-media-type $htmlFile $outputFile";
$output = shell_exec($command . ' 2>&1');
// Check if the file was created successfully
if (file_exists($outputFile)) {
echo "PDF created successfully at $outputFile";
} else {
echo "PDF generation failed: " . $output;
}
?>
Useful wkhtmltopdf Options
wkhtmltopdf offers many command-line options for controlling output quality:
- Page size:
--page-size A4or--page-size Letter - Orientation:
--orientation Portraitor--orientation Landscape - Margins:
--margin-top 20mm --margin-bottom 20mm --margin-left 15mm --margin-right 15mm - Print media:
--print-media-typeforces the PDF to use print stylesheets - Header and footer:
--header-html urland--footer-html url - Zoom:
--zoom 1.2adjusts rendering scale
Handling Headers and Footers
Adding dynamic headers and footers requires separate HTML files or URLs:
$headerHtml = '<html><body style="font-size:10px; text-align:center;">Company Name - Invoice</body></html>';
$footerHtml = '<html><body style="font-size:10px; text-align:center;">Page <span class="page">/</span> <span class="topage"></span></body></html>';
file_put_contents('/tmp/header.html', $headerHtml);
file_put_contents('/tmp/footer.html', $footerHtml);
$command = "wkhtmltopdf --header-html /tmp/header.html --footer-html /tmp/footer.html $htmlFile $outputFile";
shell_exec($command);
wkhtmltopdf Limitations
The main drawback is that wkhtmltopdf requires a graphical environment to render pages. On headless servers without a display, you need Xvfb (a virtual framebuffer) to run wkhtmltopdf:
sudo apt install xvfb
xvfb-run wkhtmltopdf --page-size A4 input.html output.pdf
Additionally, wkhtmltopdf is slower than pure PHP libraries because it launches a separate process for each PDF. For high-volume generation, consider caching or queuing systems.
Snappy: A Modern Wrapper Around wkhtmltopdf
Snappy is a PHP library that provides a cleaner API for wkhtmltopdf. It handles process management, temporary files, and options more elegantly than raw shell commands.
Installing Snappy
composer require knplabs/knp-snappy
Basic Snappy Usage
require_once 'vendor/autoload.php';
use Knp\Snappy\Pdf;
$snappy = new Pdf('/usr/bin/wkhtmltopdf');
$snappy->setOption('page-size', 'A4');
$snappy->setOption('orientation', 'Portrait');
$snappy->setOption('print-media-type', true);
$snappy->setOption('margin-top', 15);
$snappy->setOption('margin-bottom', 15);
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="document.pdf"');
echo $snappy->getOutputFromHtml($htmlContent);
Snappy reduces boilerplate code significantly and makes your PDF generation logic easier to maintain.
TCPDF: For Maximum Control Over PDF Structure
TCPDF is a PHP library that generates PDFs without external dependencies. It has its own drawing API, which gives you precise control over every element in the document.
TCPDF suits scenarios where you need to create PDFs programmatically with custom graphics, barcodes, precise positioning, or non-standard page layouts. It handles Unicode text well, making it suitable for documents in multiple languages.
TCPDF Example
require_once 'vendor/autoload.php';
use TCPDF;
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, 'mm', PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->AddPage();
$pdf->SetFont('helvetica', 'B', 16);
$pdf->Cell(0, 10, 'Invoice #12345', 0, 1, 'C');
$pdf->SetFont('helvetica', '', 12);
$pdf->Ln(10);
$pdf->Cell(0, 10, 'Generated: ' . date('Y-m-d'), 0, 1, 'L');
$pdf->SetFont('helvetica', '', 10);
$pdf->Ln(10);
$pdf->MultiCell(100, 10, "Web Development\nHours: 10\nRate: £75/hour\nTotal: £750.00", 1, 'L');
$pdf->Output('invoice.pdf', 'I');
When TCPDF Is the Right Choice
- Custom graphics: Drawing charts, diagrams, or geometric shapes directly in the PDF.
- Barcodes and QR codes: Built-in support for various barcode formats.
- Multi-language documents: Excellent Unicode support for non-Latin character sets.
- Legacy systems: Environments where installing external tools is not possible.
Choosing the Right PDF Generation Approach
The best tool depends on your specific requirements. Consider these factors when making your decision.
Document Complexity
For simple documents with straightforward layouts, Dompdf is often sufficient and requires the least setup. For complex documents with modern CSS, multi-column layouts, or precise typography, wkhtmltopdf or Snappy produce more reliable results.
Server Environment
Pure PHP libraries like Dompdf and TCPDF run anywhere Composer is available. wkhtmltopdf requires installation on the server and, ideally, a graphical environment or Xvfb on headless systems. If you do not have server access or control over the hosting environment, stick with PHP-only solutions.
Performance Requirements
Dompdf and TCPDF run entirely in PHP, which is faster for small volumes. wkhtmltopdf launches a separate process per document, which adds overhead. For generating hundreds of PDFs in batch, pure PHP libraries are more efficient. For occasional on-demand generation, the performance difference is negligible.
Maintenance and Updates
Dompdf and Snappy have active communities and receive regular updates. TCPDF is well-maintained but has a steeper learning curve. wkhtmltopdf development has slowed in recent years, though it remains stable and widely used.
Best Practices for PHP PDF Generation
- Test with real content: Generate sample PDFs with actual data before committing to a tool. Render differences become obvious quickly.
- Separate HTML templates from logic: Keep your HTML templates clean and manage data separately. This makes styling easier and keeps your code organised.
- Use print stylesheets: If using wkhtmltopdf, a dedicated print stylesheet can simplify PDF-specific styling without affecting screen rendering.
- Handle fonts carefully: Custom fonts may not embed correctly across all tools. Test font rendering on different systems.
- Cache generated PDFs: If the same document is requested repeatedly, cache the PDF file rather than regenerating it each time.
- Set appropriate timeouts: Complex PDFs can take several seconds to generate. Adjust script timeouts accordingly.
Common Problems and How to Avoid Them
Missing Images
Images fail to appear when file paths are incorrect or when external URLs are blocked. Always use absolute paths or set the base path explicitly. Verify that image URLs are accessible from the server, not just from your local machine.
Inconsistent Font Rendering
Fonts can render differently across PDF libraries. Embed fonts directly when possible to ensure consistent output. For Dompdf, use web-safe fonts or embed custom fonts via CSS @font-face.
Memory Issues with Large Documents
Generating multi-page PDFs with many images can consume significant memory. Increase PHP memory limits for these operations:
ini_set('memory_limit', '256M');
Slow Generation on Shared Hosting
Shared hosting environments often restrict process execution, making wkhtmltopdf unusable. In these cases, use Dompdf or TCPDF. Alternatively, consider generating PDFs on a separate server or using an external API service.
Securing Your PDF Generation Setup
PDF generation can introduce security risks if not handled carefully. Temporary files created during rendering may expose sensitive data if left in accessible directories. Use secure temporary directories with appropriate permissions:
// Use PHP's sys_get_temp_dir() for secure temporary storage
$tempDir = sys_get_temp_dir();
// Generate a unique filename to prevent collisions
$tempFile = tempnam($tempDir, 'pdf_');
unlink($tempFile); // Remove the file, keep the directory path
Clean up temporary files immediately after generating the PDF. Never leave rendered HTML containing sensitive information in publicly accessible locations.
If your PDF generation processes user-submitted HTML, sanitise the input to prevent cross-site scripting or other attacks that could affect the server during rendering.
Related practical reading
These related guides can help you connect this topic with the wider website, server, security, and support decisions around it.
- GraphQL in PHP vs REST: When GraphQL Is the Better Choice - useful background for related development decisions
Getting Started with PHP PDF Generation
PHP offers several capable approaches to PDF generation, each suited to different requirements. Dompdf works well for HTML-centric workflows and straightforward documents. wkhtmltopdf delivers superior rendering quality for complex layouts. TCPDF provides maximum control for programmatically generated graphics and multi-language documents.
Start with the simplest tool that meets your needs. Generate sample documents with real content to verify output quality before committing to a specific approach. As your requirements grow more complex, you can migrate to more powerful tools without replacing your entire workflow.
If you need help evaluating which PDF generation approach fits your application, or if you are experiencing specific issues with an existing setup, you can get in touch with details of your application, document requirements, and hosting environment.