itul/pdf-data
itul/pdf-data is a Laravel/PHP package for working with PDF data. It provides a simple, developer-friendly API to read PDF content and metadata, making it easier to integrate PDF processing and document inspection into Laravel applications.
The package is a low-signal dependency (0 stars, 0 dependents, no public docs beyond a one-line description), so treat the README and src/ as the source of truth before wiring anything in.
Install
composer require itul/pdf-data
If the repo is Bitbucket-only and not on Packagist, add a VCS repository entry to composer.json:
"repositories": [{
"type": "vcs",
"url": "https://bitbucket.org/bmooreitul/pdf-data"
}]
Where to look first
README.md – the only stated API surface is "pdfs into html forms, php arrays, images." Confirm the exact facade/class names; they aren't documented publicly.src/ – look for a service provider, a main parser class, and any config/ directory. Register the provider if it isn't auto-discovered (config/app.php → providers).composer.json of the package – check the underlying PDF engine (likely smalot/pdfparser, spatie/pdf-to-image, or a pdftotext/mutool shell dependency). That tells you the real capabilities and the real system requirements.tests/ – if present, fixtures are the fastest way to see expected output shapes.First use case
The most reliable entry point is extracting text/structure from a single PDF into a PHP array:
use Itul\PdfData\...; // confirm namespace from src/
$parser = new PdfParser(); // or app(PdfParser::class) if bound
$result = $parser->parse(storage_path('app/sample.pdf'));
// → ['pages' => [...], 'text' => '...', 'images' => [...]]
Save a known-good PDF as a fixture and dump $result with dd(). Do that before anything else — the shape of the output array is the contract you'll build against.
1. Wrap it behind your own service
Never call the package directly from controllers. The package is unmaintained-looking; isolate it so you can swap in smalot/pdfparser or spatie/pdf-to-text later without touching business logic.
interface PdfExtractor {
public function toArray(string $path): array;
public function toImages(string $path): array;
public function toHtml(string $path): string;
}
class ItulPdfExtractor implements PdfExtractor {
public function __construct(private \Itul\PdfData\Parser $parser) {}
public function toArray(string $path): array {
return $this->parser->parse($path)->toArray();
}
// ...
}
Bind it in a service provider. This is the single highest-value thing you can do with a package this obscure.
2. Always parse off the request cycle
PDF parsing is CPU- and memory-heavy. Use a queued job with an explicit timeout:
class ExtractPdfJob implements ShouldQueue {
public $timeout = 300;
public $tries = 2;
public function __construct(public string $path) {}
public function handle(ItulPdfExtractor $extractor) {
$data = $extractor->toArray(Storage::path($this->path));
PdfExtraction::updateOrCreate(
['path' => $this->path],
['data' => $data, 'status' => 'done']
);
}
}
3. Store both the raw output and a normalized projection
The package's array output is a passthrough of an underlying engine's parse tree — it's verbose and may change between minor versions. Persist it as JSON in a json column (or on a disk), then expose a normalized DTO via an accessor. When the package changes its shape, only your normalizer moves.
4. Image extraction → Storage pipeline
If toImages() is the feature you need, treat the raw output as file handles or blobs and push them straight to Storage::disk('s3')->put(...) in the same job. Don't hold N page images in memory as SplFileInfo objects — loop and release.
foreach ($extractor->toImages($path) as $i => $img) {
Storage::disk('s3')->put("pdfs/{$hash}/page-{$i}.png", $img->getContent());
}
5. "HTML forms" workflow
The "parses into HTML forms" claim is ambiguous — verify whether it produces form-fillable HTML or just HTML markup of the page content. If it's markup, treat it as an untrusted string, sanitize it before rendering (mews/purifier or HTMLPurifier), and cache the result (HTML from PDFs is often large). Do not inline it into Blade without escaping.
Maintenance risk is the headline. Zero stars and zero dependents means no community pressure to fix bugs. Pin the exact commit in composer.json rather than a ^1.0 (or worse, dev-master) — a Bitbucket branch update could silently break you:
"itul/pdf-data": "dev-master#<commit-sha>"
System dependencies bite. Most PDF-to-image tools shell out to ImageMagick/Ghostscript (imagick, gs, pdftoppm). These are not Composer dependencies. Verify they're installed in the same Docker image/CI container as PHP, or you'll get a "works locally, fails in prod" class of bug. Check php -m | grep -i imagick and which gs pdftoppm.
Memory and timeouts. PDFs are unpredictable. Raise memory_limit inside the job (not globally), and set $timeout. Large scanned PDFs can blow past 128M quickly. The parser may not free resources between pages — if you batch, spawn one job per PDF.
Encrypted / malformed PDFs. Almost every PHP PDF library fails loudly (or, worse, fatals) on password-protected or malformed files. Wrap every parse in a try/catch and validate file signatures (%PDF-) before passing in. Prefer finfo/mime_content_type checks at upload time over after-the-fact error handling.
Config quirks. If the package ships a config file, php artisan vendor:publish --provider="Itul\PdfData\...ServiceProvider" --tag=config and read it fully. Common footguns: defaulting to a temp dir under storage/ that doesn't exist, or expecting absolute paths when you pass Storage::path() relative paths. Normalize paths to absolute.
Output shape instability. Don't typehint against the package's returned arrays in your own code. Dump the array to a fixture, write tests against your normalized DTO, and keep the package's shape out of your domain layer.
Extension points are minimal. Without a documented contract, don't bank on extending the parser by subclassing — the internals are liable to change. Fork it (it's Bitbucket, so it's cheap) if you need to fix a bug, and maintain the fork, rather than relying on upstream patches that may never come.
Debugging. dd() early and often. If a parse returns empty text but valid images, the document is likely scanned — you'll need OCR (spatie/laravel-google-cloud-vision or Tesseract), which this package almost certainly doesn't provide despite "and more."
Before committing: run a 5-file smoke test (text PDF, scanned PDF, encrypted PDF, multi-page with images, malformed file) through the job. If any of them cause a fatal or hang, choose smalot/pdfparser (pure PHP, actively maintained) instead — this package's value proposition only holds if it genuinely does form extraction, which is rare and worth verifying first.
How can I help you explore Laravel packages today?