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 by leveraging the FPDI and FPDF libraries.

Prerequisites

Before we begin, ensure you have the following:

  • PHP 7.1 or higher
  • Composer installed
  • Basic knowledge of PHP

Installing FPDI and FPDF libraries

First, install the required libraries using Composer. Open your terminal and run:

composer require setasign/fpdf:1.8.* setasign/fpdi:^2.5

This command installs FPDF and FPDI with their recommended versions for your project.

Basic usage of FPDF

FPDF is a PHP class that enables you to generate PDF files from scratch. Here’s an example of creating a simple PDF with FPDF:

<?php
declare(strict_types=1);

require 'vendor/autoload.php';

use FPDF;

$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', 'B', 16);
$pdf->Cell(40, 10, 'Hello World!');
$pdf->Output('F', 'hello_world.pdf');

This script generates a PDF file named hello_world.pdf containing the text "Hello World!".

Importing existing PDFs with FPDI

FPDI extends FPDF by allowing you to import pages from existing PDF documents. The following example demonstrates how to import the first page of an existing PDF:

<?php
declare(strict_types=1);

require 'vendor/autoload.php';

use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;

try {
    $pdf = new Fpdi();
    $pdf->AddPage();
    $pdf->setSourceFile('existing.pdf');
    $tplId = $pdf->importPage(1);
    $pdf->useTemplate($tplId);
    $pdf->Output('F', 'imported.pdf');
} catch (PdfParserException $e) {
    error_log("PDF Parser Error: " . $e->getMessage());
}

This script imports the first page of existing.pdf and generates a new PDF called imported.pdf.

Merging two PDFs

Let’s combine our knowledge to merge two PDF documents. The following function imports all pages from two PDFs and merges them:

<?php
declare(strict_types=1);

require 'vendor/autoload.php';

use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;

function mergePDFs(string $file1, string $file2, string $outputFile): bool {
    try {
        $pdf = new Fpdi();

        // Import pages from the first PDF
        $pageCount = $pdf->setSourceFile($file1);
        for ($i = 1; $i <= $pageCount; $i++) {
            $tplId = $pdf->importPage($i);
            $pdf->AddPage();
            $pdf->useTemplate($tplId);
        }

        // Import pages from the second PDF
        $pageCount = $pdf->setSourceFile($file2);
        for ($i = 1; $i <= $pageCount; $i++) {
            $tplId = $pdf->importPage($i);
            $pdf->AddPage();
            $pdf->useTemplate($tplId);
        }

        $pdf->Output('F', $outputFile);

        // Free memory
        unset($pdf);
        gc_collect_cycles();

        return true;
    } catch (PdfParserException $e) {
        error_log("PDF Parser Error: " . $e->getMessage());
        return false;
    }
}

mergePDFs('document1.pdf', 'document2.pdf', 'merged.pdf');

This function takes two input files, imports all pages sequentially, and outputs a merged PDF.

Handling multiple PDFs dynamically

To merge an arbitrary number of PDFs, adjust the function to accept an array of file paths:

<?php
declare(strict_types=1);

require 'vendor/autoload.php';

use setasign\Fpdi\Fpdi;
use setasign\Fpdi\PdfParser\PdfParserException;

function mergePDFs(array $files, string $outputFile): bool {
    try {
        $pdf = new Fpdi();

        foreach ($files as $file) {
            if (!file_exists($file)) {
                throw new \RuntimeException("File not found: $file");
            }

            $pageCount = $pdf->setSourceFile($file);
            for ($i = 1; $i <= $pageCount; $i++) {
                $tplId = $pdf->importPage($i);
                $pdf->AddPage();
                $pdf->useTemplate($tplId);
            }
        }

        $pdf->Output('F', $outputFile);

        // Free memory
        unset($pdf);
        gc_collect_cycles();

        return true;
    } catch (PdfParserException $e) {
        error_log("PDF Parser Error: " . $e->getMessage());
        return false;
    } catch (\RuntimeException $e) {
        error_log("Error: " . $e->getMessage());
        return false;
    }
}

$filesToMerge = ['document1.pdf', 'document2.pdf', 'document3.pdf'];
if (mergePDFs($filesToMerge, 'merged_multiple.pdf')) {
    echo "PDFs merged successfully.";
} else {
    echo "Failed to merge PDFs. Check error log for details.";
}

This version iterates over an array of PDFs, merging each document into a single output file.

PDF compatibility and limitations

When working with FPDI, keep these compatibility points in mind:

  • FPDI supports PDF versions up to 1.7.
  • Encrypted PDFs require additional handling and may not be supported out-of-the-box.
  • Linearized PDFs (optimized for web viewing) are supported.
  • Certain PDF features—such as forms, annotations, and interactive elements—might not be preserved.
  • For large or complex PDFs, monitor memory usage and consider processing documents in smaller batches.

Alternative PDF libraries

If FPDI does not fully meet your requirements, consider exploring other PHP libraries for PDF manipulation:

  • TCPDF offers comprehensive PDF generation and editing features, including support for advanced layout and formatting.
  • tFPDF is a Unicode-enabled variant of FPDF, useful if you require extensive support for non-Latin characters.

Evaluate these alternatives based on your project’s complexity and specific needs.

Conclusion

Merging PDF documents in PHP with FPDI and FPDF provides a powerful solution for managing document workflows programmatically. This approach is flexible, allowing you to handle everything from simple PDF creation to complex, dynamic merging operations.

For more complex document processing needs or large-scale operations, consider using Transloadit's Document Processing service for a scalable, feature-rich solution.