Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pdfparser Laravel Package

prinsfrank/pdfparser

prinsfrank/pdfparser is an MIT-licensed PDF parsing library for PHP 8.1+ with no external dependencies. It is on average 2.6x faster and 5x more memory-efficient than smalot/pdfparser, supports encrypted PDFs, and is actively maintained.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Pure PHP Implementation: Standalone PHP library with no external dependencies (no imagick, ghostscript, or pdftotext bridges), so it remains portable across any PHP stack (Laravel, Symfony, Lumen). Unchanged in v3.8.0.
  • Low-Level PDF Parsing: Interprets PDF syntax directly (objects, streams, cross-references) rather than shelling out. The v3.7.0 cross-reference work (#570) and null-object handling (#571) remain in place; v3.8.0 does not touch the parsing substrate, so those conformance gains are retained without new substrate risk.
  • Layout Layer (materially expanded in v3.8.0): The library now carries a layout/heuristics layer, not just a syntax layer. #582 adds multi-column text extraction with gutter detection; #583 adds header/footer detection for multi-column layouts; #586–#591 tune the thresholds (minimum line count per column, minimum gutter/column width, 20% page-width guard, cropbox/mediabox boundary exclusion, run-length trigger). This is an architectural shift: output ordering is now inferred rather than purely syntactic, so "correct" output is a heuristic judgment, not a spec-mandated result.
  • Geometry Correctness: #590 computes page boundaries from actual offsets when cropbox/mediabox are absent, instead of a generic fallback. This is a correctness fix but also a coordinate-space change for documents with missing page boxes — relevant if we persist positional data.
  • Error Contract Tightening: #593 makes GetFont always return a font or throw, rather than returning null and throwing later. Better diagnosability, but it converts a previously-deferred failure into an earlier exception — relevant to anyone extending or decorating the font object layer.
  • Performance Layer (new): #592 caches advance width / right edge for positioned text elements; #594 caches fonts during column grouping; #595 reduces method/property calls on the right-edge path; #596 exits early on column-candidate checks. This is the first release with explicit hot-path optimization, and it is offset by the added cost of column detection — net throughput is an empirical question, not a given.
  • Modular Design: Decorator pattern for object types (Pages, XObjects, Fonts) unchanged. Annotation objects (#578) and markdown link output (#579) from v3.7.0 remain the newest, least-exercised surfaces.
  • Memory Efficiency: Still optimized for low footprint (streaming, file caching). v3.8.0 adds no memory claims; column grouping holds additional per-page state, so memory per page may rise modestly on column-heavy documents — verify on large multi-column PDFs.
  • Distribution Flexibility: PHAR usage remains documented; v3.8.0 README update (#597) documents the new column functionality. #584/#585 add a composer.lock and pin PHPStan — dev-only, zero consumer impact, but it stabilizes upstream CI and reduces "PHPStan broke our build" churn.

Integration Feasibility

  • Laravel Compatibility:
    • Native PHP; integrates via Composer with no Laravel-specific dependencies.
    • Wrappable in a service provider for DI (PdfParserServiceProvider).
    • Queue-friendly: ideal for asynchronous parsing of uploaded files.
    • Storage-aware: works with Storage::disk() or S3.
  • Performance Considerations:
    • useInMemoryStream=true for real-time/low-latency needs; false for batch/memory-constrained jobs.
    • Benchmark now, with intent: #592–#596 are the first upstream optimizations we've seen, but they are optimizations for the new column path. Net effect vs. our 3.5.0 baseline is undetermined. Measure single-column and multi-column documents separately — the caching work may help columns while adding nothing to plain pages.
    • We still have no verified perf baseline for 3.6.0–3.8.0. This release is the natural point to establish one.
  • Feature Leverage (expanded):
    • Multi-column extraction (#582/#583) is the highest-value capability in this release for us: annual reports, 10-Ks, academic papers, brochures, and newsletter-style PDFs previously required either a layout-aware third-party service or manual stitching. This potentially removes an external dependency.
    • Header/footer suppression improves clean-text quality for embedding/RAG ingestion by removing repeated boilerplate — a direct retrieval-quality win.
    • v3.7.0's annotations and markdown links remain available; link/annotation + column text now compose into a single structured extraction pass.

Technical Risk

  • Output Diff Risk (now dominant, and larger than in v3.7.0): Multi-column extraction reorders text for every document with a column-like layout. Unlike the #573 continuation fix (which corrected mangled strings in place), this changes reading order — the single most semantically load-bearing property of extracted text for search, summarization, and embeddings. Any consumer diffing, indexing, hashing, or summarizing extracted text must be re-baselined, and a scrambled reading order will look like a quality regression to end users even when the engine is "more correct."
  • Heuristic False Positives (new): Column detection can misfire on tables, forms, table-of-contents pages, sidebars, and slide decks, producing interleaved text. The tuning PRs (#586–#591) show the maintainer is actively trading precision against recall; thresholds will likely move again, which means column output should be treated as unstable across minor versions until it settles.
  • Default-On Behavior (unresolved): The release notes do not state whether column extraction is automatic or opt-in. This is the gating question for the whole upgrade — if it is default-on, the blast radius is every document; if it is opt-in, we can stage it behind a flag as we did with annotations. Confirm against README (#597) and the API surface before committing.
  • Error Contract Change (#593): GetFont now throws rather than returning null. Low risk for stock consumers, material if we wrote custom decorators or subclasses touching font resolution — audit before the bump. Expect a small increase in exception volume on malformed documents that previously limped through font resolution.
  • Geometry Change (#590): Documents with absent cropbox/mediabox now get offset-derived boundaries. Correct, but if we store coordinates or do our own layout post-processing, expect shifted values.
  • Encrypted PDFs: Password-protected parsing supported since v3.0; password must be supplied at parse time. Handle PdfParserException gracefully. Unchanged.
  • Residual Edge Cases: Corrupted PDFs can still throw cryptic errors; scanned docs, complex forms, and heavily columned documents with embedded tables remain the representative-sample gap to close. Annotation parsing (#578) and markdown link output (#579) are still the least battle-tested paths.
  • Upgrade Risk (v3.5.0 → v3.8.0): No breaking changes announced; three consecutive minor releases, semver-compliant. We have still never assessed v3.6.0, and v3.8.0's layout layer means the aggregate diff we absorb is substantially larger than the v3.7.0 assessment assumed.
  • Release Velocity Risk: v3.7.0 → v3.8.0 arrived quickly, and eight of v3.8.0's PRs are tuning the same heuristic. Pin the floor and upgrade deliberately; do not float ^3.
  • PHP Version: Requires PHP 8.2+ (readonly classes). No new floor announced.
  • Memory Limits: PDFs >100MB may hit memory_limit; raise it or use streaming mode. Column grouping adds per-page state — retest at the top of our size range.
  • Supply-chain / Sustainability: Human-written code statement and MIT license unchanged, which keeps procurement review cheap. v3.8.0 is entirely maintainer-authored (no external contributors this cycle, in contrast to v3.7.0). Bus factor remains effectively 1; keep the MIT fork option in the risk register.

Key Questions

  1. Column Enablement (new, blocking): Is multi-column extraction default-on or opt-in? If default-on, is there a config flag or separate method to revert to reading-order-v3.7.0 behavior? This determines whether the rollout is staged or a full-corpus event.
  2. Corpus Coverage for Columns: Do we hold representative samples of two-column papers, annual reports with sidebars, tables, TOC pages, and slide decks? Column heuristics regress most on exactly these.
  3. Downstream Consumers: Who consumes extracted text, markdown, or coordinates downstream (search index, embeddings, exports, regex extractors, summarizers)? Reading-order changes will alter their inputs. Who approves the diff?
  4. Re-baselining: Do we have a golden-file corpus with expected outputs, extended for the v3.7.0 shapes (#570–#579) and now for column ordering, header/footer suppression, and missing-page-box geometry (#582/#583/#590)?
  5. Performance: What is our measured throughput and peak memory on 3.5.0 vs. 3.8.0, split by single-column vs. multi-column documents? #592–#596 are unquantified for our workloads.
  6. Version Floor (updated): Do we adopt >= 3.8.0 (column capability, but unstable thresholds) or hold at 3.7.0 (stable, no column support)? If column extraction isn't needed in Q4, 3.7.0 remains the lower-risk floor.
  7. Extensibility Audit: Do we subclass or decorate the font object layer? #593's throw-instead-of-null changes that contract.
  8. Error Handling: How are invalid PDFs, missing passwords, and the new earlier font exceptions handled — retries, quarantine, fallback parser? Is the fallback invocation rate re-measured post-upgrade?
  9. Scaling: Single-process CLI or distributed (Horizon/Redis workers)? If column detection is materially more expensive, does it need its own queue?
  10. Monitoring: How are parse failures, per-document latency, and output-quality regressions tracked? Quality regressions rarely raise exceptions — they show up as user complaints or search-quality drops.
  11. v3.6.0 Gap (stale): Three minors have now shipped since our last assessed version. Either close the v3.6.0 question or formally accept the gap and rely on the golden-file corpus as the control.

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Service Container: Register as singleton/bound service for DI.
    • Filesystem: Storage facade for PDF upload/retrieval.
    • Queues: Offload parsing to ParsePdfJob; if column detection proves expensive, route multi-column-capable parsing to a dedicated queue.
    • Validation: Validate mime:application/pdf before parsing.
    • Config: Introduce an explicit pdfparser.columns.enabled (and header/footer suppression) config key so the layout behavior is a deployment decision, not a library default we inherit silently.
    • Persist extracted links/annotations to their own tables or JSON columns rather than cramming them into the document text field.
  • Microservices: Deploy as a separate parsing service (Symfony/Lumen) if parsing is shared across apps — this also lets different consumers sit on different parser versions during the transition.
  • CLI Tools: Artisan commands for batch runs (php artisan pdf:parse /path); PHAR path for environments without Composer.

Migration Path

  1. Collapse the Upgrade (recommended): If the v3.5.0 → v3.7.0 bump has not yet shipped, go directly to v3.8.0 and run a single re-baseline and a single re-index. Two staged upgrades means two full output diffs and two re-embedding passes for no additional safety.
  2. Pilot Phase: Swap in a non-critical module; compare text, images, metadata, links/annotations, and reading order on multi-column documents. Side-by-side human review on 20–30 column-heavy documents is worth more than any automated diff here.
  3. Incremental Rollout: Start with getText() on single-column documents (lowest risk, exercises the syntax and geometry changes), then enable column extraction on a tagged subset, then annotations and markdown links.
  4. Fallback Strategy: Keep the flag-gated fallback parser. Re-measure fallback invocation rate after the bump — #570 plus the improved geometry should retire hard failures, while column false positives may add a different, quality-driven fallback trigger.
  5. Upgrade Path (v3.5.0 → v3.8.0):
    • composer require prinsfrank/pdfparser:^3.8 (no expected code changes).
    • Read the updated README (#597) to confirm the multi-column API and whether it is default-on.
    • Audit any custom decorators against #593.
    • Re-run the golden-file corpus; review diffs, weighting reading-order changes separately from string-level changes.
    • Invalidate caches and re-index: text changes (#573, #582, #583) and markdown output changes (#579). Version cache keys by parser version and re-embed affected documents.
  6. Feature Enablement: Turn on column grouping, annotation extraction, and link emission per-endpoint behind config flags, so a defect in a heuristic path cannot degrade core text extraction for every consumer at once.

Compatibility

  • PHP 8.2+: Confirm target containers use php:8.2 or newer.
  • PDF Standards: Supports PDF 1.0–1.7; may struggle with PDF/A and PDF/X. Hybrid-xref and null-object handling (v3.7.0) plus offset-derived page boundaries (#590) improve real-world conformance, which matters most for archival and long-retention corpora.
  • Dependencies: No transitive runtime dependencies; no new ones introduced in v3.8.0. The added composer.lock (#584) is repository-side and does not affect consumers' resolution.
  • Behavioral Compatibility: Treat v3.8.0 as output-incompatible with v3.5.0 — not API-incompatible, but every downstream artifact derived from extracted text should be treated as invalidated.

Sequencing

  1. Setup:
    composer require prinsfrank/pdfparser:^3.8
    
    Add provider/service binding if using DI.
  2. Basic Integration (unchanged):
    use PrinsFrank\PdfParser\PdfParser;
    
    $parser = new PdfParser();
    $document = $parser->parseFile(storage_path('app/uploads/file.pdf'));
    $text = $document->getText();
    
  3. Advanced Features (extended in v3.8.0):
    • Multi-column text: verify the API and default behavior from the README; wrap in our own config flag regardless. Log which mode produced each stored artifact so re-extraction can target the right subset.
    • Images: iterate $document->getImages() and persist via Storage::put().
    • Encrypted PDFs: parseFile($path, password: '...') inside try/catch on PdfParserException.
    • Annotations: iterate annotation objects; validate on samples before broad enablement.
    • Links in markdown: snapshot output before/after — link markup is present since v3.7.0.
  4. Optimization:
    • Streaming mode + queues for batch.
    • Cache parsed results (Redis) with parser-version-scoped keys; bust on every parser deploy.
    • Run a one-off re-extraction/backfill job for documents whose stored text or markdown was produced pre-3.8.0 — and prioritize column-heavy documents, where the change is largest.

Operational Impact

Maintenance

  • Release Cadence: Frequent minors, still additive per semver, but the content is changing shape: v3.7.0 was correctness and capability, v3.8.0 is layout heuristics plus tuning. Expect follow-up tuning releases. Pin a floor and upgrade deliberately; do not float.
  • Heuristic Churn: Eight of v3.8.0's PRs tune column detection thresholds. Assume these move again. Budget a re-baseline per upgrade cycle rather than treating layout output as stable.
  • Library Updates: Monitor GitHub Releases. The new composer.lock and PHPStan pin mean upstream CI stability is better managed — a small positive for our own dependency hygiene story.
  • Dependency Management: No transitive runtime dependencies; no conflict surface.
  • Debugging: Log parse errors via Laravel logging; keep a sample corpus in CI — now including hybrid xref chains, null dictionary values, continued literal strings, annotation-bearing PDFs, link-rich documents, two-column layouts, sidebar-heavy reports, TOC pages, and PDFs with missing cropbox/mediabox.
  • Process Maturity: CONTRIBUTING edge-case guidance (#572, v3.7.0) remains; however v3.8.0 was single-maintainer authored, so contributor-base widening has not continued this cycle.
  • Maintainer Sustainability: Still effectively one primary maintainer (bus factor 1) with an explicit sponsorship ask. Keep the MIT fork option in the risk register.

Support

  • Community: Responsive maintainer; MIT license. v3.8.0 shows fast, focused iteration on a real user need (columns) — a strong responsiveness signal.
  • Documentation: README updated for the new functionality (#597), alongside the existing benchmarks, PHAR guidance, and human-written-code statement.
  • Laravel-Specific: No official Laravel package; wrap in a custom facade/service if multiple apps consume it.
  • SLAs: No formal SLA; MIT permits forking if maintenance stalls. The layout heuristic is now a meaningful piece of logic we would inherit on a fork — factor that into fork cost estimates, which rise with each capability release.

Scaling

  • Horizontal: Stateless parser; scale Horizon/Redis workers per queue.
  • Vertical: Raise memory_limit for large PDFs; prefer streaming + segmented processing beyond ~500MB.
  • New consideration: Column grouping is per-page analytical work with caching (#592/#594). Benchmark it against our largest multi-column documents before enabling it across a high-volume pipeline; if it is material, split into a dedicated queue with its own concurrency and its own latency SLO.

Failure Modes

  • Reading-Order Degradation (new, highest severity): Column detection misfires on tables, forms, TOCs, and sidebars, producing interleaved text. This is a silent quality failure — it raises no exception and can pass naive assertions. Mitigate with human-reviewed golden files for column-heavy documents and a sampled quality audit after each parser upgrade.
  • Silent data loss (further reduced): Prior fixes plus null-value and literal-string handling narrow the remaining class. Still assert on expected field counts and non-empty text, not just absence of exceptions.
  • Hard exceptions (mixed): #590 and the general trajectory reduce structural failures, but #593 deliberately converts a deferred null into an immediate throw, so some previously-tolerated documents may now surface exceptions earlier. Isolate per-document so one bad file can't fail a batch; record and continue.
  • Downstream output drift (heightened): Text, reading order, and markdown output all changed. Search indexes, embeddings, exported previews, and regex extractors built on pre-3.8.0 output may silently degrade. Mitigation: versioned cache keys, re-index on deploy, golden-file diffs in CI, and a named owner who signs off on the diff.
  • Newer code paths: Column grouping and header/footer detection (#582/#583) are brand new; annotation parsing and markdown link emission are one release old. Track extraction errors in these paths separately from core parsing.
  • Memory exhaustion: Fatal memory_limit kills the worker, not just the job — ensure workers restart and jobs retry with backoff/caps.
  • Mitigation posture: fallback parser behind a flag, per-document try/catch, alerting on parse-failure rate, sampled quality audits, golden-file regression suite, and a re-index runbook.

Ramp-Up

  • Engineering: Still very low for the API — Composer install plus ~10 lines to first value. The effort has shifted to semantics: choosing whether column extraction is on, defining expected reading order for our document classes, and re-baselining. Budget real reviewer time on column-heavy samples; this cannot be automated away.
  • Ops/Platform: Minimal for the library; the PHAR path adds artifact distribution and checksum verification if adopted.
  • Security/Procurement: Still fast to clear — no transitive dependencies, MIT, explicit human-written-code claim, sponsor-funded. Adding composer.lock upstream is neutral-to-positive for supply-chain review.
  • Estimated effort for the v3.5.0 → v3.8.0 bump: ~2–3 days (bump, README/API confirmation of column defaults, decorator audit for #593, corpus re-baseline including column documents, cache flush) plus re-index/re-embedding time proportional to corpus size — larger than the v3.7.0 estimate because reading order, not just string content, changes. Recommendation: schedule one deliberate upgrade to ^3.8 in the next maintenance window, with column extraction and header/footer suppression gated by our own config and validated on a tagged subset before broad enablement. If column extraction is not needed this quarter, ^3.7 remains the lower-risk floor and the upgrade can be deferred to the following window — but do not float the version in the interim.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc