- How do I install setasign/fpdi in a Laravel project with Composer?
- Run composer require setasign/fpdi together with the PDF engine you plan to use, such as setasign/fpdf, tecnickcom/tcpdf, or setasign/tfpdf. FPDI deliberately does not pin an engine dependency, so you must add one yourself in composer.json. Once installed, the classes are PSR-4 autoloaded under the setasign\Fpdi namespace, so no manual require calls are needed.
- Does FPDI support Laravel 11 and PHP 8.3?
- Yes. FPDI 2.6.x supports modern PHP versions, and v2.6.9 explicitly verifies compatibility with PHP 8.6. Since Laravel 10 and 11 typically run on PHP 8.1 or newer, current FPDI releases fit without adjustment. Only if you maintain a legacy Laravel app on PHP 7.1 should you pin an older line such as 2.3.x.
- Can FPDI import multiple PDF pages as templates in one document?
- Yes. You call setSourceFile once per source PDF, then loop over importPage for each page number you need and place them with useTemplate on the generated document. A single source page can be imported and placed multiple times, and you can override its width and height per placement. This makes it straightforward to build multi-page invoices or contracts from a branded template file.
- How do I use FPDI with TCPDF or tFPDF instead of FPDF?
- Require the matching engine package and use FPDI's engine-specific class instead of the base Fpdi class. With TCPDF you extend setasign\Fpdi\Tcpdf\Fpdi, and with tFPDF you use setasign\Fpdi\Tfpdf\Fpdi via the FpdiTrait. The template import API, including setSourceFile, importPage, and useTemplate, stays the same across engines.
- Is FPDI a replacement for dompdf or Snappy in a Laravel application?
- No. FPDI imports pages from existing PDF documents and reuses them as templates inside FPDF, TCPDF, or tFPDF, whereas dompdf and Snappy render HTML into PDFs. Many Laravel teams use both: they generate content with an HTML-to-PDF tool and use FPDI to overlay dynamic data onto a pre-approved branded template. Treat FPDI as complementary template tooling rather than a full rendering engine.
- How do I generate PDFs with FPDI inside a Laravel queue job?
- Instantiate the FPDI class inside the job's handle method, import your template pages, write your dynamic content, and store the result with the Storage facade. Using Output('S') returns the PDF as a string, which you can pass straight to Storage::put without touching the local filesystem. Because FPDI keeps the parsed document in memory, keep queue timeouts and memory limits generous and chunk very large batches.
- Can FPDI read PDF templates from S3 or a stream in Laravel?
- Yes. FPDI can read source PDFs from files, strings, or streams, so Storage::get from an S3 disk works when you pass the raw bytes through a stream reader. You are not tied to local paths, which fits Laravel's filesystem abstraction. For very large templates, downloading to a temporary file first is often simpler and keeps memory use predictable.
- How should I handle corrupted or malformed PDF uploads with FPDI?
- Wrap FPDI calls in try/catch blocks, because invalid structures and unresolvable objects raise exceptions during setSourceFile or importPage. Recent 2.6.x patches add parser resilience, including recursion handling in v2.6.4 and escaped dictionary key parsing in v2.6.9. As defence in depth, restrict template uploads to trusted sources and enforce execution time and memory limits around the import.
- What are FPDI's performance and memory limits at high volume?
- The version 2 rewrite reports up to 100 percent faster parsing with lower memory consumption than version 1, but memory still scales with the size of the imported PDFs. For workloads in the thousands of documents per hour, benchmark on your real templates and offload generation to queue workers. Streaming the output instead of buffering large strings, and reusing a single parsed source where possible, keeps spikes manageable.
- Is FPDI actively maintained, and which version should I pin?
- FPDI 2 is the maintained line, with regular patch releases such as v2.6.9 that fix parser edge cases and verify new PHP versions. Version 1 is deprecated and no longer developed, so avoid it in any new Laravel project. Pinning with a caret constraint like ^2.6 gives you safe patch updates, and upgrades within 2.6.x have so far introduced no breaking API changes.