Merging PDF documents in PHP using FPDI and FPDF

Need to merge multiple PDFs into one file in your PHP application? In this DevTip, we'll explore how to combine PDF documents programmatically using PHP with the FPDI and FPDF libraries. These tools provide a straightforward way to handle PDF manipulation directly on your server.
Prerequisites
Before you start, ensure your environment meets these requirements:
- PHP 5.6 or higher (PHP 7+ recommended for better performance)
- Composer for managing PHP dependencies
- Basic understanding of PHP programming concepts
- The Zlib PHP extension must be enabled (required by FPDI)
Install FPDI and FPDF
You can install both libraries using Composer. Navigate to your project directory in the terminal and run:
composer require setasign/fpdf:1.8.* setasign/fpdi:^2.0
Composer handles autoloading, making the classes immediately available in your PHP scripts.
Generate a PDF with FPDF
FPDF is a library for generating PDF documents from scratch using PHP. Here's a simple example that
creates a one-page PDF file named hello_world.pdf
containing the text “Hello World!”:
<?php
require 'vendor/autoload.php';
// Use the global namespace for FPDF
$pdf = new \FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40, 10, 'Hello World!');
$pdf->Output('F', 'hello_world.pdf'); // 'F' saves to a local file
Import existing PDFs with FPDI
FPDI extends FPDF, adding the capability to import pages from existing PDF documents. You can then
place these imported pages into the PDF you are generating with FPDF. This example imports the first
page from existing.pdf
and saves it as imported.pdf
:
<?php
require 'vendor/autoload.php';
use setasign\Fpdi\Fpdi;
$pdf = new Fpdi();
// Specify the source PDF file
$pdf->setSourceFile('existing.pdf');
// Import the first page
$pageId = $pdf->importPage(1);
// Add a page to the new PDF
$pdf->AddPage();
// Use the imported page as a template
$pdf->useTemplate($pageId);
// Save the resulting PDF
$pdf->Output('F', 'imported.pdf');
Merge two PDFs
Combining the concepts, we can create a function to merge two PDF files page by page. This helper
function takes two input file paths ($a
, $b
) and an output path ($out
), reads all pages from
both input files, and writes them sequentially into the output file merged.pdf
. It includes basic
error handling.
<?php
require 'vendor/autoload.php';
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;
function mergeTwo(string $a, string $b, string $out): bool {
try {
$pdf = new Fpdi();
foreach ([$a, $b] as $file) {
if (!is_readable($file)) {
error_log("Cannot read file: $file");
return false; // Or throw an exception
}
$pageCount = $pdf->setSourceFile($file);
if ($pageCount === false) {
error_log("Could not set source file (invalid PDF?): $file");
return false;
}
for ($i = 1; $i <= $pageCount; $i++) {
$tpl = $pdf->importPage($i);
$size = $pdf->getTemplateSize($tpl);
// Add a page with the same size and orientation
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
$pdf->useTemplate($tpl);
}
}
$pdf->Output('F', $out);
return true;
} catch (PdfParserException $e) {
error_log('PDF Parser Error during merge: ' . $e->getMessage());
return false;
} catch (\Exception $e) { // Catch other potential exceptions
error_log('General error during PDF merge: ' . $e->getMessage());
return false;
}
}
// Example usage:
// Ensure a.pdf and b.pdf exist
// mergeTwo('a.pdf', 'b.pdf', 'merged.pdf');
Merge any number of PDFs
Often, you'll need to merge a dynamic list of PDF files. This function accepts an array of file paths and merges them into a single output file. It includes checks for file readability and handles potential parsing errors.
<?php
require 'vendor/autoload.php';
use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;
function mergeMany(array $files, string $out): bool {
try {
$pdf = new Fpdi();
foreach ($files as $file) {
if (!is_readable($file)) {
error_log("Cannot read file, skipping: $file");
continue; // Skip this file
}
$pageCount = $pdf->setSourceFile($file);
if ($pageCount === false) {
error_log("Could not set source file (invalid PDF?), skipping: $file");
continue; // Skip this file
}
for ($p = 1; $p <= $pageCount; $p++) {
$tpl = $pdf->importPage($p);
$size = $pdf->getTemplateSize($tpl);
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
$pdf->useTemplate($tpl);
}
}
// Only output if at least one page was added
if ($pdf->PageNo() > 0) {
$pdf->Output('F', $out);
return true;
} else {
error_log("No pages were successfully merged.");
return false;
}
} catch (PdfParserException $e) {
error_log("PDF Parser Error during mergeMany: " . $e->getMessage());
return false;
} catch (\Exception $e) {
error_log("General error during mergeMany: " . $e->getMessage());
return false;
}
}
// Example usage:
// $pdfFiles = ['doc1.pdf', 'doc2.pdf', 'doc3.pdf'];
// mergeMany($pdfFiles, 'combined_document.pdf');
Manage memory for large files
PDF processing, especially merging multiple or large documents, can be memory-intensive. Here are a few tips:
- Increase PHP Limits: If you encounter memory exhaustion errors, consider increasing PHP's
memory limit and execution time in your
php.ini
file or usingini_set()
at the start of your script (use with caution on shared hosting):ini_set('memory_limit', '256M'); // Adjust as needed, e.g., '512M', '1G' ini_set('max_execution_time', '300'); // 5 minutes, adjust as needed
- Release Resources: After generating the output PDF, explicitly unset the FPDI object and
suggest garbage collection to free up memory, especially in long-running scripts or loops:
// Assuming $pdf is your FPDI object after Output() unset($pdf); if (function_exists('gc_collect_cycles')) { gc_collect_cycles(); }
- Consider Alternatives: For very large files or high-volume merging where server-side processing might hit resource limits, offloading the task to a dedicated service can be more robust and scalable.
Use Transloadit's document processing
For production workloads—especially handling big files, merging many documents frequently, or
needing more advanced features—offloading the task can be more efficient and scalable. Transloadit's
/document/merge
Robot is designed for this:
- Merges multiple PDFs reliably.
- Can handle password-protected PDFs (if passwords are provided).
- Integrates into automated workflows with features like queuing and scaling for heavy jobs.
- Processes files without impacting your server's memory or execution time limits.
You can explore this in our 🤖 /document/merge Robot.
Wrap-up
FPDI and FPDF offer a powerful combination to merge documents into one in PHP directly on your server, requiring only a few lines of code for basic tasks. They are excellent choices for quick implementations and moderate workloads. However, when dealing with large-scale PDF manipulation, high throughput requirements, or complex workflows involving potentially large files, consider leveraging a cloud-based service like Transloadit to handle the heavy lifting, ensuring your application remains performant and scalable.