smalot/pdfparser
Standalone PHP library to extract data from PDF files: parse objects and headers, read metadata, pull text from ordered pages, and handle compressed PDFs. Install via Composer. Note: limited maintenance; secured documents and form data extraction aren't supported.
Architecture fit
smalot/pdfparser is a pure-PHP, dependency-free PDF reader that surfaces a small, stable façade: Parser::parseFile() / parseContent() → Document → getText(), getPages(), getDetails(). For a TPM this is the ideal shape: a single seam (DocumentTextExtractor interface) that can sit behind an adapter and be swapped for pdftotext, Tika, or a cloud OCR API without touching call sites.getText() is a text stream, not a document model — do not scope "structured parsing" onto it.Integration feasibility
composer require smalot/pdfparser, PHP 7.1+ (works on 8.x per the 2.7/2.8 release notes), no config, no services, no migrations. A working prototype is a few lines.Config::setRetainImageContent(false) (added v1.1.0) drops image payloads from memory — this is the single highest-value performance setting for image-heavy corpora and should be the default in our wrapper.PDFObject.php rewrite (~20 issues) confirm the internal API is churny; internal classes (Font, PDFObject, Header) are not a safe extension surface. Consume only the public façade.Technical risk
memory_limit or max_execution_time, and gzuncompress() on corrupt streams has historically produced fatal errors. Mitigation is architectural (queue + hard worker timeout), not configurable.Dependents: 0, which contradicts the package's real-world ubiquity (it underpins several popular Laravel PDF-to-text wrappers). Treat dependency/stars telemetry as unreliable inputs; verify against Packagist and our own composer audit.Key questions
pdftotext, which is faster and more battle-tested but adds a system dependency?Stack fit
PdfTextExtractor contract bound in a service provider so the implementation is swappable and testable (fakes for unit tests, no real PDF fixtures needed in the fast suite).UploadController → store original to disk/S3 → dispatch ExtractPdfText job → queued worker parses → persist document_text (raw + normalized) + extraction metadata → downstream index/summarize.pdf-extraction) with its own worker pool, its own memory_limit, and --timeout set below the job's retry_after to prevent duplicate execution on timeout.needs_ocr boolean. This is what makes the swap decision reversible later.Migration path
pdftotext/Tika.needs_ocr documents; backfill previously flagged documents via a replayable job (keep originals, never discard them — extraction must always be re-runnable after a parser upgrade).Compatibility
"smalot/pdfparser": "2.9.*") and commit the lockfile; do not float. The v2.x internal churn plus limited upstream responsiveness makes silent minor drift an unnecessary gamble.Sequencing
setRetainImageContent(false)).pdftotext behind the same contract) — keep the interface honest by proving a second implementation fits.Maintenance
Support
Scaling
Failure modes
needs_ocr flag.setRetainImageContent(false), worker memory_limit, and pre-flight size gating.retry_after, idempotent jobs, and a failed_at-style terminal state so a document isn't retried forever.gzuncompress on corrupt data) — wrap every parse in try/catch with a broad catch; treat the library as untrusted input processing.Ramp-up
How can I help you explore Laravel packages today?