Fusionar documentos PDF en PHP con FPDI y FPDF
¿Necesitas fusionar varios PDF en un solo archivo en tu aplicación PHP? En este DevTip veremos cómo combinar documentos PDF de forma programática en PHP con las bibliotecas FPDI y FPDF. Estas herramientas ofrecen una manera sencilla de manipular PDF directamente en tu servidor.
Requisitos previos
Antes de empezar, asegúrate de que tu entorno cumpla estos requisitos:
- Una versión de PHP 8 con soporte
- Composer para gestionar las dependencias de PHP
- Conocimientos básicos de conceptos de programación en PHP
- La extensión Zlib de PHP debe estar habilitada (la requiere FPDI)
Instalar FPDI y FPDF
Puedes instalar ambas bibliotecas con Composer. Ve al directorio de tu proyecto en la terminal y ejecuta:
composer require setasign/fpdf:1.8.* setasign/fpdi:^2.0
Composer se encarga de la carga automática, por lo que las clases quedan disponibles de inmediato en tus scripts de PHP.
Generar un PDF con FPDF
FPDF es una biblioteca para generar documentos PDF desde cero con PHP. Este es un ejemplo sencillo
que crea un archivo PDF de una página llamado hello_world.pdf con el texto «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
Importar PDF existentes con FPDI
FPDI extiende FPDF y añade la capacidad de importar páginas de documentos PDF existentes. Luego
puedes colocar esas páginas importadas en el PDF que estás generando con FPDF. Este ejemplo importa
la primera página de existing.pdf y la guarda como 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');
Fusionar dos PDF
Combinando estos conceptos, podemos crear una función que fusione dos archivos PDF página por
página. Esta función auxiliar recibe dos rutas de archivos de entrada ($a, $b) y una ruta
de salida ($out), lee todas las páginas de ambos archivos de entrada y las escribe de forma
secuencial en el archivo de salida merged.pdf. Incluye un manejo básico de errores.
<?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);
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');
Fusionar cualquier cantidad de PDF
A menudo necesitarás fusionar una lista dinámica de archivos PDF. Esta función acepta un array de rutas de archivo y los fusiona en un único archivo de salida. Incluye comprobaciones de que los archivos se puedan leer y maneja posibles errores de análisis.
<?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);
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');
Gestionar la memoria con archivos grandes
El procesamiento de PDF, sobre todo al fusionar varios documentos o documentos grandes, puede consumir mucha memoria. Aquí tienes algunos consejos:
- Aumenta los límites de PHP: Si te encuentras con errores de memoria agotada, considera
aumentar el límite de memoria y el tiempo de ejecución de PHP en tu archivo
php.inio usandoini_set()al inicio de tu script (úsalo con precaución en alojamiento compartido):ini_set('memory_limit', '256M'); // Adjust as needed, e.g., '512M', '1G' ini_set('max_execution_time', '300'); // 5 minutes, adjust as needed - Libera recursos: Después de generar el PDF de salida, elimina explícitamente el objeto FPDI y
sugiere la recolección de basura para liberar memoria, sobre todo en scripts o bucles de larga
duración:
// Assuming $pdf is your FPDI object after Output() unset($pdf); if (function_exists('gc_collect_cycles')) { gc_collect_cycles(); } - Considera alternativas: Para archivos muy grandes o fusiones de gran volumen en las que el procesamiento del lado del servidor podría alcanzar los límites de recursos, delegar la tarea en un servicio dedicado puede ser más robusto y escalable.
Usa el procesamiento de documentos de Transloadit
En cargas de trabajo de producción, sobre todo al manejar archivos grandes, fusionar muchos
documentos con frecuencia o necesitar funciones más avanzadas, delegar la tarea puede ser más
eficiente y escalable. El Robot /document/merge de Transloadit está
diseñado para esto:
- Fusiona varios PDF de forma confiable.
- Puede procesar PDF protegidos con contraseña (si se proporcionan las contraseñas).
- Se integra en flujos de trabajo automatizados con funciones como colas y escalado para trabajos pesados.
- Procesa los archivos sin afectar los límites de memoria ni de tiempo de ejecución de tu servidor.
Puedes explorar esto en nuestro Robot 🤖 /document/merge.
Conclusión
FPDI y FPDF forman una combinación potente para unir varios documentos en uno solo en PHP, directamente en tu servidor, y solo requieren unas pocas líneas de código para tareas básicas. Son excelentes opciones para implementaciones rápidas y cargas de trabajo moderadas. Sin embargo, cuando se trata de manipulación de PDF a gran escala, requisitos de alto rendimiento o flujos de trabajo complejos con archivos potencialmente grandes, considera apoyarte en un servicio en la nube como Transloadit para encargarse del trabajo pesado y así garantizar que tu aplicación siga siendo rápida y escalable.
