Skip to content

NextPDF for CodeIgniter 4

nextpdf/codeigniter connects the NextPDF Portable Document Format (PDF) engine to a CodeIgniter 4 application through the framework’s Services layer. You build PDF documents in controllers, jobs, or commands, then return them as native CodeIgniter Hypertext Transfer Protocol (HTTP) responses.

Terminal window
composer require nextpdf/codeigniter

The package composer.json requires php >=8.4 <9.0, nextpdf/core ^3.0 || ^5.2, and codeigniter4/framework ^4.6. It also suggests nextpdf/artisan, nextpdf/premium, and codeigniter4/queue. For the full requirements table, optional packages, and verification steps, see /integrations/codeigniter/install/.

NextPDF is a PHP 8.4 PDF 2.0 engine. The core engine (nextpdf/core) is framework-agnostic. It does not know about HTTP, routing, or dependency wiring. nextpdf/codeigniter is the adapter that connects the engine to a CodeIgniter 4 application. With the adapter in place, you do not wire registries, factories, or response handling yourself.

The package adds four things to a CodeIgniter 4 application:

  • A Services class (NextPDF\CodeIgniter\Config\Services) that CodeIgniter discovers automatically. It exposes named services: fontRegistry, imageRegistry, documentFactory, pdfDocument, pdf, tsaClient, and pdfSigner.
  • A Pdf library (NextPDF\CodeIgniter\Libraries\Pdf) — a high-level controller application programming interface (API). It wraps a single disposable document and turns it into a response in one call.
  • A PdfResponse helper (NextPDF\CodeIgniter\Http\PdfResponse) that creates a CodeIgniter DownloadResponse for inline preview or download. It attaches a fixed set of response-hardening headers.
  • Two global helper functions, pdf() and pdf_document(). They are registered through the Composer files autoload entry and the package Registrar.

The package also detects optional NextPDF extensions when it builds a document. When nextpdf/artisan is installed and a Chrome binary is configured, the document gets the Chrome renderer. When NextPDF Pro is installed, PDF/A output and digital signing are available through the same Services surface. Detection is conditional and silent. The package never requires an extension that is not present.

Why a Services class and not a container binding

Section titled “Why a Services class and not a container binding”

CodeIgniter 4 does not ship a PSR-11 dependency-injection container. Instead, it uses a Services locator. A Services locator is a framework-discovered class with static factory methods. Each method returns either a shared instance or a fresh one. PSR-11 discourages the service-locator pattern — passing a container into an object so the object can fetch its own dependencies — in PSR-11 §1.3 with the modal verb SHOULD NOT. The package follows CodeIgniter’s locator convention. It also keeps the locator surface minimal and explicit: every service is a named factory method with a bool $getShared parameter, and callers receive concrete objects rather than a container handle.

This design keeps the CodeIgniter integration consistent with the Laravel and Symfony integrations. Each integration exposes the same logical services through its own framework’s idiom.

Entry pointTypeReturnsLifetime
Services::fontRegistry()serviceFontRegistryInterfaceshared (warmed, then locked)
Services::imageRegistry()serviceImageRegistryshared (bounded least recently used (LRU) cache)
Services::documentFactory()serviceDocumentFactoryInterfaceshared (stateless)
Services::pdfDocument(false)serviceNextPDF\Core\Documentfresh per call
Services::pdf(false)serviceNextPDF\CodeIgniter\Libraries\Pdffresh per call
Services::tsaClient()service?TsaClientshared; null when no timestamp authority (TSA) URL
Services::pdfSigner(false)service?SignerInterfacefresh; null when signing disabled
pdf()helperPdffresh per call
pdf_document()helperDocumentfresh per call
PdfResponse::inline() / download()staticDownloadResponseper call
GeneratePdfJobqueue jobone per dispatch

A controller returns a PDF in three lines. Services::pdf() returns a fresh Pdf library that wraps a fresh document. download() then creates a CodeIgniter DownloadResponse.

<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;
use NextPDF\CodeIgniter\Config\Services;
final class InvoiceController extends BaseController
{
public function download(int $id): DownloadResponse
{
$pdf = Services::pdf();
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
}
}

The full runnable walkthrough is in /integrations/codeigniter/quickstart/. It covers routing, inline preview, and the pdf() and pdf_document() helper variations.

In production, request a non-shared instance with Services::pdf(false). Catch the single base exception, NextPDF\Exception\NextPdfException; every core and extension failure extends it. Log the failure with context instead of swallowing the error.

try {
$pdf = Services::pdf(false);
$pdf->document()->addPage();
$pdf->document()->cell(0, 10, "Invoice #{$id}");
return $pdf->download("invoice-{$id}.pdf");
} catch (NextPdfException $e) {
$logger->error('pdf.invoice.failed', [
'invoice_id' => $id,
'exception' => $e::class,
'message' => $e->getMessage(),
]);
return $this->response
->setStatusCode(ResponseInterface::HTTP_INTERNAL_SERVER_ERROR)
->setJSON(['error' => 'pdf_generation_failed', 'invoice_id' => $id]);
}

The complete production controller is in /integrations/codeigniter/production-usage/. It adds observability timing, worker-safe lifetimes, and asynchronous generation.

  • The font and image registries are process-lifetime singletons. A document is never shared. pdfDocument and pdf return a fresh instance on every call, so one request cannot leak content into another. Services::pdf(false) and pdf() both return a fresh library that wraps a fresh document.
  • The package requires the mbstring and zlib PHP extensions. The font registry validates them once per process. If either extension is absent, the font registry raises a runtime error that names the missing extension.
  • Optional-extension behavior depends on what is installed in the same application. With only nextpdf/core present, the signing and PDF/A paths return null or are skipped. They never fail loudly.

The integration adds no measurable overhead beyond the engine itself. The font registry is parsed once and then locked. The image registry is an LRU cache bounded by the imageCacheMb setting (50 MB by default). The core engine and document content govern PDF build cost, not the adapter. The per-page budget for this documentation set is 1500 ms wall / 128 MB peak. Real recipes set their own budget in front-matter.

PdfResponse attaches a fixed set of response headers to every PDF it emits: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy: default-src 'none', X-Robots-Tag: noindex, nofollow, and Referrer-Policy: no-referrer. Filenames are sanitized, and non-ASCII names are emitted with a Request for Comments (RFC) 5987 extended parameter. The queue job restricts builder callables to the App\PdfBuilders namespace and confines output paths to WRITEPATH/pdfs/. See /integrations/codeigniter/security-and-operations/ for the full threat model.

  • Module discovery relies on Composer’s PSR-4 autoloading. A namespace prefix maps to a base directory, and the fully qualified class name maps to a file path (PSR-4 §x1.x3).
  • The Services design follows the locator guidance discussed under PSR-11 §1.3.

NextPDF core is Apache-2.0. Digital signatures, PDF/A archiving, and Factur-X e-invoice embedding are provided by NextPDF Pro and NextPDF Enterprise. The CodeIgniter package exposes the corresponding service methods. Those methods return null until the matching Premium package is installed in the same application.

  • /integrations/codeigniter/install/ — install and verify the package.
  • /integrations/codeigniter/quickstart/ — first PDF in a controller.
  • /integrations/codeigniter/configuration/ — every configuration key.
  • /integrations/codeigniter/boot-and-discovery/ — how CodeIgniter finds the Services class.
  • /integrations/codeigniter/integration/ — wiring reference and smoke test.