setasign/fpdf
FPDF is a free PHP class for generating PDF files with pure PHP. Clone of official releases, installable via Composer as setasign/fpdf. No active development in this repository.
Architecture fit. setasign/fpdf is a Composer-packaged mirror of the upstream FPDF single-class library: pure PHP, no extensions beyond optional GD/FreeType for images and embedded fonts, no service provider, no facade, no config surface, no container coupling. It instantiates cleanly inside a controller, an invokable action, a queued job, or an artisan command. That makes it architecturally trivial to add and easy to regret — the risk is never framework integration, it is that imperative PDF code gets sprinkled across controllers and becomes the hardest layer to change later.
The TPM-relevant characteristic is that FPDF is a drawing API, not a templating engine. There is no Blade/HTML/CSS path; every layout is Cell/MultiCell/SetXY arithmetic in PHP. Three planning consequences follow:
Recommended architecture, cheap on day one and expensive to retrofit: a thin PdfGenerator contract bound in a service provider, with FPDF as one implementation behind it. All call sites depend on the contract; FPDF types appear in exactly one class. That single decision preserves the swap-and-contains option to Dompdf/mPDF/Browsershot later.
Integration feasibility. High, and deliberately unglamorous: composer require setasign/fpdf:^1.9 plus a five-line spike proves the happy path in an afternoon. The feasibility risk to manage is fitness, not installation:
AddFont() plus code-page work, or pairing with FPDI/mPDF. Treat this as a roadmap scope decision in discovery, not a sprint-2 discovery. It is the single most common reason teams reject FPDF after committing to it.NOASSERTION because FPDF ships its own permissive non-SPDX terms. Practical impact is low; process impact is real — open the legal review at kickoff so it does not block a release candidate, and expect it to be re-asked at every security review.Technical risk.
| Risk | Likelihood | Impact | TPM stance |
|---|---|---|---|
| Unicode/RTL requirement appears mid-build | Medium | High | Decision gate before template build-out. A "yes" changes the tool choice. |
| Layout estimate underestimated (flowing text, tables, pagination around images) | High | Medium–High | Teams routinely under-scope this 3–5×. Estimate against a real document, not a hello-world. |
| Mirror-only supply chain, single upstream maintainer | Certain | Medium | Pin the version, vendor the font metrics you rely on, name an owner, log as a dependency. |
| Licence ambiguity stalls launch | Medium | Medium | Legal ticket opened at kickoff, closed before RC. |
| Silent layout regressions on refactor | High | Medium | Golden-file / visual-diff tests are mandatory scope, not a nice-to-have. |
| PHP 8.x deprecations in legacy-style code | Medium | Low–Medium | CI matrix job against target PHP; treat warnings as findings. |
| Package metadata used as adoption evidence (780 stars, 0 dependents, future-dated release) | Certain | Low | Do not cite these in a build-vs-buy deck — it is a mirror, not a community project. Cite upstream history instead. |
Key questions.
NOASSERTION review, and by when?Stack fit. Position FPDF as a narrow server-side capability in a Laravel monolith: transactional documents with fixed structure and variable data — invoices, receipts, order confirmations, statements, certificates, packing slips — plus internal/admin exports where layout control matters and branding does not. It is a poor fit for any document whose design is owned by marketing or changes frequently, and disqualifying for Unicode-heavy, form-based, signed, or accessibility-regulated output.
Bring a fit matrix to scoping:
Migration path. Two credible entry routes, both cheap:
pdf.class.php includes or abandoned TCPDF forks onto the pinned Composer package. This is the strongest TPM case for adoption — it converts an unmanaged, unversioned liability into a pinned dependency with a contract around it. Do it one template at a time, with golden-file comparison against the legacy output before cutting over.Either way, keep FPDF behind PdfGenerator from commit one, and store generated documents rather than regenerating on read — it makes later renderer swaps non-events and gives you a diffable artifact for regression tests.
Compatibility. Verify against the actual runtime first: target PHP version (add a CI job that fails on deprecations), ext-gd and FreeType availability for images and embedded fonts, and memory limits sufficient for the largest realistic document. Font licensing matters too — embedding a commercial TTF into generated PDFs is a licensing question, not an engineering one, and it is the kind of thing discovered at the worst moment. For Laravel specifically, nothing collides: no competing service provider, no global helpers, no config publish. Version-pin to ^1.9 and commit the lockfile.
Sequencing.
PdfGenerator contract, FPDF implementation, one template, golden-file tests, queued job writing to S3, config-driven output path.The sequencing point that matters most to a TPM: the renderer choice must be reversible, and reversibility is purchased in sprint 1, not later. Everything else can be reprioritized.
Maintenance. Low ongoing, but not zero, and the shape is unusual: there is no upstream roadmap to consume and no patches to absorb. This repository mirrors official FPDF releases and explicitly takes no development. In practice you pin the version, own it, and touch it only when you add templates or move PHP major versions. The flip side is that a defect in FPDF is yours to work around — there is no one to escalate to and no upstream feature request to file. Mitigations are cheap and should be budgeted in sprint 1: a pinned version in the lockfile, vendored font metrics for the fonts you embed, golden-file regression tests, and a single named maintainer for the PDF layer.
Support. No support contract, no SLA, no CVE response process. For internal reports and routine invoices this is acceptable and should be stated plainly rather than softened. For regulated, contractual, or customer-facing documents where a defect has financial or legal consequence, the absence of a support path is a genuine risk to accept explicitly at the leadership level — with the containment plan (swap the one implementation class to mPDF or Dompdf) written down as the answer if it ever becomes a problem. The NOASSERTION licence flag will resurface at every security review; close it once with legal, record the conclusion, and reference it thereafter.
Scaling. Generation is CPU-bound and synchronous in nature; scaling is a queue-and-worker problem rather than a library problem. Put generation in a queued job, stream output directly to object storage rather than buffering in the request cycle, and set explicit memory and timeout ceilings per job so a pathological document does not take down a worker. Bulk back-office generation (thousands of statements monthly) is fine behind a queue with concurrency limits and a dead-letter path. Two scaling caveats to carry in the capacity plan: embedded font subsets add to each file's size if not subset strategically, and page count — not document count — is the real cost driver for large reports.
Failure modes. Enumerate these in the runbook before launch, because each has a distinct detection and response:
Ramp-up. Effectively zero for the library, real for the layout discipline. Any PHP developer can emit a PDF in an hour; producing a maintainable template system takes a sprint of pattern-setting. Onboarding cost is concentrated in two places: the imperative coordinate model (engineers accustomed to HTML/CSS will find it slow at first, and should be told so up front rather than discovering it), and the Unicode constraint, which must be documented as a hard boundary in the service class rather than folklore. Plan for one engineer to own the pattern and review the first three templates; after that it is repeatable work. Stakeholder expectation-setting is a real ramp-up item too — the honest framing to the requesting team is: "PDF invoices next sprint, clean and consistent, not redesigned; a new visual layout later is a tooling conversation, not a tweak."
How can I help you explore Laravel packages today?