PDF extraction

Working with a PDF with PHP: A Modern API Guide

Ditch legacy libraries. Learn how to handle any PDF with PHP using a modern REST API. Our guide covers hosting, extraction, conversion, and security.

June 11, 2026 14 min read okraPDF
pdf with phpphp pdf apipdf extraction phpphp pdf hostingokrapdf

You're probably here because a normal PHP feature request turned into a PDF problem.

The ticket sounds simple at first. Let users upload invoices. Let support search contracts. Let finance pull line items out of statements. Then you open the first real document and remember that PDF generation and PDF understanding are completely different jobs. One is controlled output. The other is document forensics.

A lot of older PHP advice starts with FPDF, TCPDF, or Dompdf. That's still useful if you need to create a report your own app controls. It's much less useful when users send you scans, malformed exports, or vendor PDFs with weird text layers. For teams dealing with insurance packets, invoices, and compliance-heavy docs, the hard part often looks closer to document review than document printing. If you work with policy PDFs, this effective policy review guide is a good example of the kind of downstream workflow that breaks if extraction is unreliable.

Table of Contents

The Modern PHP Developer's PDF Problem

The modern pdf with PHP problem usually starts with a mismatch between the task and the tool.

If your app needs to generate a clean invoice from database data, a PHP PDF library is fine. If your app needs to ingest a supplier invoice that came from outside your system, you're dealing with missing structure, unpredictable encoding, and often scanned pages pretending to be text documents. Those are different engineering problems, and treating them like the same problem wastes time.

The PHP ecosystem has taught PDF output for a long time. PHP instructional material has treated PDF generation as a standard capability, and current examples still show MySQL-backed reports built with libraries like mPDF and FPDF through established PHP workflows, which is why so many developers start there when a PDF ticket lands on their desk (instructional material on PDF workflows in PHP).

The gap most teams hit

What breaks first usually isn't file upload. It's meaning.

You can read bytes from a PDF. That doesn't mean you can reliably answer questions like these:

  • What's the invoice number? It may be visible to a person but not tagged as a field.
  • Where are the line items? Tables often exist visually, not structurally.
  • Can you search it? Not if the document is just an image.
  • Can you compare versions? Not easily if object ordering changed.

Practical rule: If the PDF came from your own template, a library can work. If the PDF came from users, vendors, scanners, or legacy systems, assume ingestion will be the hard part.

That's why an API-first approach is often the more practical path. You let PHP stay focused on application logic, auth, queues, and storage policy, while a document service handles parsing, normalization, extraction, conversion, and delivery details that traditional generation libraries were never built to own.

When to Use a Library and When to Use an API

The PHP PDF ecosystem is mature. That matters because you're not choosing between “possible” and “impossible.” You're choosing between tools that solve different classes of problems. According to this overview of PHP PDF libraries, Dompdf has more than 134 million downloads and is described as the most popular PHP PDF library, while TCPDF, mPDF, Snappy, and FPDF remain widely used alternatives in production environments.

An infographic comparing when to use libraries versus APIs for creating and processing PDFs with PHP.

Libraries are good at controlled output

Use a library when your application owns the source content and layout.

That usually means:

Use caseWhy a library fits
App-generated invoicesData already lives in PHP and your DB
Internal reportsLayout is predictable
Exporting dashboard viewsHTML or drawing primitives are enough
Simple certificates or receiptsDeterministic output matters more than parsing

Libraries work best when you can answer this question clearly: what should the document look like before generation starts?

If the answer is “we know exactly,” local generation is straightforward. FPDF-style APIs are deterministic. HTML-to-PDF tools fit when you already have templates in HTML and CSS.

APIs make more sense for outside-world PDFs

An API becomes the better choice when the PDF is the input, not the output.

That includes jobs like:

  • Extracting tables from uploaded statements
  • Turning a PDF into JSON for app workflows
  • Converting contracts to editable formats
  • Hosting a PDF and generating a shareable link
  • Running redaction before delivery

HTML-to-PDF tools such as Dompdf and mPDF are often chosen when developers want to convert existing HTML/CSS into PDF, but that path comes with layout and fidelity trade-offs. The typical flow is build HTML, render it, then stream or save the file, and complex CSS or external assets can behave differently from a browser's rendering pipeline (HTML-to-PDF workflow demonstration).

A library helps when you're drawing the page. An API helps when you need to understand the document.

If you're evaluating document tooling beyond raw generation, it's useful to explore our API Hub and compare the kinds of endpoints that exist across extraction, conversion, and processing workflows. That gives you a clearer picture of where local PHP code should stop and external document processing should start.

Before you extract anything, you need a stable file location. That's the first place teams overbuild.

They wire up local storage, add object storage, think about public access, then start writing signed-download logic before they've even proved the product flow. For a lot of pdf with PHP work, the fastest useful primitive is simpler: upload the file and get back a link.

A hand using a laptop to convert a PDF document into a shareable link using an API.

Start with hosting, not parsing

A hosted PDF URL solves several immediate problems:

  • Your app gets a canonical file location
  • Support can inspect the exact document users uploaded
  • Other services can consume the same file
  • You avoid mixing early product work with storage plumbing

If you want a browser upload form before wiring PHP, this walkthrough on uploading a file with HTML is a useful companion pattern.

A basic PHP upload flow

A plain cURL upload is enough to get started:

<?php

$ch = curl_init('https://api.okrapdf.com/v1/host');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => [
        'file' => new CURLFile(__DIR__ . '/invoice.pdf', 'application/pdf', 'invoice.pdf'),
    ],
]);

$response = curl_exec($ch);

if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}

$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode >= 400) {
    throw new RuntimeException("Upload failed: {$response}");
}

$data = json_decode($response, true);

print_r($data);

You'd typically expect a response shaped something like this:

[
    'id' => 'pdf_123',
    'url' => 'https://.../pdf_123',
]

Store the returned identifier in your own database, not just the URL. The URL is good for sharing. The document ID is better for downstream jobs and internal references.

A matching shell request is useful for smoke testing outside your app:

curl -X POST https://api.okrapdf.com/v1/host \
  -F "file=@invoice.pdf"

Later, when a PM asks for “share pdf” or “host pdf online,” you're not rebuilding the stack. You already have the primitive you need.

A quick product demo helps here:

<iframe width="100%" style="aspect-ratio: 16 / 9;" src="https://www.youtube.com/embed/bJfQ_tkRYRc" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

From PDF to Structured Data in PHP

Most “PDF with PHP” projects reach a point where they either become valuable or stall out.

A PDF link is useful. Structured data is what enables search, reconciliation, automation, and analytics. The messy part is that PDFs rarely carry business meaning in a clean shape. They carry visual layout, and your system has to infer the rest.

Why extraction breaks in production

The problem isn't basic file creation. The harder issue is document integrity. As the SAPP project notes through its parser and rebuild tooling, practical production work involves rebuilding PDFs, reordering objects, and comparing files object by object. That's a strong signal that the primary pain is malformed PDFs, inconsistent structure, and version drift, not “how do I make a PDF file exist.”

A flowchart showing four steps to transform PDF documents into structured data using PHP applications.

That's also why “extract text” is rarely enough. For invoices and statements, you usually need one of these instead:

  • Field extraction for dates, totals, vendor names, account details
  • Table extraction for line items
  • Structured JSON so your app can apply rules
  • CSV or spreadsheet output for accounting workflows

If your end goal is finance ops, this guide on streamline bookkeeping with PDF conversion is a practical example of why teams push beyond raw text and into table-friendly output.

An async PHP workflow that holds up

Document extraction should be treated as an asynchronous job. Even when a service is fast, your app design gets better if you don't tie user requests directly to document parsing.

A common flow looks like this:

  1. Submit the hosted PDF with a requested output format.
  2. Receive a job ID immediately.
  3. Poll a status endpoint or handle a webhook.
  4. Fetch results when the job finishes.

Here's a simple PHP version using cURL.

Start the job:

<?php

$payload = json_encode([
    'document_id' => 'pdf_123',
    'output' => 'json',
]);

$ch = curl_init('https://api.okrapdf.com/v1/extract');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . getenv('OKRAPDF_API_KEY'),
    ],
    CURLOPT_POSTFIELDS => $payload,
]);

$response = curl_exec($ch);

if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}

curl_close($ch);

$job = json_decode($response, true);
$jobId = $job['job_id'] ?? null;

if (!$jobId) {
    throw new RuntimeException('Missing job ID');
}

Poll for completion:

<?php

function waitForJob(string $jobId): array
{
    $deadline = time() + 60;

    while (time() < $deadline) {
        $ch = curl_init("https://api.okrapdf.com/v1/jobs/{$jobId}");

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . getenv('OKRAPDF_API_KEY'),
            ],
        ]);

        $response = curl_exec($ch);

        if ($response === false) {
            throw new RuntimeException(curl_error($ch));
        }

        curl_close($ch);

        $data = json_decode($response, true);
        $status = $data['status'] ?? 'unknown';

        if ($status === 'completed') {
            return $data;
        }

        if ($status === 'failed') {
            throw new RuntimeException('Extraction job failed');
        }

        sleep(2);
    }

    throw new RuntimeException('Timed out waiting for extraction job');
}

Working with the result in PHP

Once you have structured output, the rest feels like normal backend work again.

<?php

$result = waitForJob($jobId);

$invoice = [
    'invoice_number' => $result['data']['invoice_number'] ?? null,
    'invoice_date'   => $result['data']['invoice_date'] ?? null,
    'line_items'     => $result['data']['line_items'] ?? [],
];

foreach ($invoice['line_items'] as $item) {
    // persist or validate each row
}

Don't model extraction responses around one perfect vendor template. Model them around missing keys, uncertain fields, and partial success.

If you want to inspect a browser-based example of structured output first, the PDF to JSON tool is a handy reference for the kind of shape you should expect your application to consume.

Advanced PDF Conversions and Manipulations

Once you stop treating PDFs as final artifacts, more workflows open up.

A legal team receives a contract PDF and wants editable text for revision. A commerce team uploads a product catalog and wants page images for a storefront. A design team gets a PDF brief from a client and wants to move it into a design workflow. Those are all legitimate pdf with PHP tasks, but they're not good candidates for hand-built library code.

A hand-drawn illustration showing PDF to DOCX conversion and extracting images from a product catalog PDF.

A few real conversion scenarios

Take a product catalog first. The business asks for thumbnail images from each page so merchandisers can preview spreads in the admin panel. You don't want to manually render pages with a stack of local binaries if the main value is just “PDF in, image set out.”

Or take a contract. Users don't want a regenerated imitation of the contract. They want the original document converted into something editable enough for redlines and review comments.

Then there's design handoff. Teams sometimes receive PDFs as source material even when the destination is a design system or mockup flow. The useful abstraction isn't page drawing. It's conversion.

The request pattern stays simple

The nice part is that the app-side flow doesn't really change much. You already have a hosted document ID. You submit a job with a target format and wait for the result.

<?php

$payload = json_encode([
    'document_id' => 'pdf_123',
    'target' => 'docx',
]);

$ch = curl_init('https://api.okrapdf.com/v1/convert');

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . getenv('OKRAPDF_API_KEY'),
    ],
    CURLOPT_POSTFIELDS => $payload,
]);

$response = curl_exec($ch);

if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}

curl_close($ch);

print_r(json_decode($response, true));

For image extraction or another target format, only the requested target changes.

That's a better fit than trying to force generation libraries into reverse. In production, pure PHP PDF generation is useful because it keeps output deterministic, but developers still have to manage pagination, font embedding, and file output directly, and complex layouts require careful manual composition even with feature-rich tools like FPDF (SitePoint's discussion of pure PHP PDF generation trade-offs).

If the job is “understand or transform an existing PDF,” don't start by drawing a new PDF.

Securing and Serving PDFs in Your Application

A customer opens their portal, clicks a statement link, and gets a PDF that was sitting behind a predictable storage URL. The file renders fine. The problem is that delivery bypassed your app, your authorization rules, and your audit trail.

That failure mode shows up in otherwise solid PHP codebases because file serving often gets treated as infrastructure instead of application logic. For PDFs that contain personal data, legal records, invoices, or claim documents, the serving path is part of the feature.

Redaction belongs in the release flow

Redaction is not only an editing task. It affects which file a specific user is allowed to receive.

In practice, that means keeping the original document under tighter access rules and creating audience-specific derivatives when the business case calls for it. A support agent may need a version with account numbers masked. An external recipient may need a version with addresses removed. Your application should decide which asset is valid for that request, then record what was delivered.

A workable pattern looks like this:

  • Keep the original in restricted storage with the narrowest access possible.
  • Create redacted variants for defined use cases such as support review, external sharing, or compliance review.
  • Serve the correct variant per request based on role, tenant, or workflow state.
  • Log the document ID, variant, user, and timestamp so you can answer access questions later.

Put your PHP app in front of delivery

The safest default is simple. Every PDF request goes through your application first.

Let PHP verify the session, check authorization against your own business rules, and then either fetch the file server-side or request a short-lived file URL from your document service. That gives you one place to enforce policy instead of scattering access decisions across buckets, CDN rules, and front-end code.

The benefits are immediate:

PatternWhy it matters
Auth check before accessBlocks direct object exposure
Temporary accessLimits damage from copied links
Per-request policyEnforces role and tenant rules at the application layer
Centralized loggingGives you an audit trail for document access

This is also where an API-based workflow helps more than a library. FPDF, TCPDF, or mPDF can create output, but they do not solve expiring access, document-level authorization, derivative selection, or delivery logging. Those are application concerns, and a hosted document API fits them better than another layer of file path handling.

PHP has supported direct PDF responses for years, and the core pattern is still the same: set the right headers and stream bytes back to the browser, as shown in the PHP manual documentation for header(). The difference in a modern app is that you should stream a vetted asset through an authorized route, not expose raw storage links and hope object names stay private.

If you need the controller-side details, this guide on sending a PDF from your PHP app to the browser is a good reference for the delivery mechanics.

Putting It All Together Your Next Steps

Most PDF headaches in PHP come from starting at the wrong layer.

If the job is controlled document generation, a library is often enough. If the job is ingesting, extracting, converting, redacting, or securely serving real-world PDFs, an API-based workflow usually gets you to a working product faster and with fewer edge-case failures.

The practical stack is simple. Host the file first. Treat extraction and conversion as async jobs. Store document IDs in your own database. Serve documents through your application instead of handing out raw storage links. Keep generation libraries for the narrow cases where your app fully owns layout.

That approach lets you spend your time on business rules instead of PDF internals.


If you want to try the fastest part first, upload one real document to OkraPDF and start with the free hosting flow at OkraPDF Host. It's a simple way to turn “we need PDF support” into a working document pipeline.