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

Identitydocuments Laravel Package

werk365/identitydocuments

Laravel package for reading and validating identity documents. It parses MRZ data from passports and ID cards, verifies checksums, and extracts details such as names, document numbers, nationalities, birth dates, and expiry dates.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require werk365/identitydocuments
php artisan vendor:publish --tag=identitydocuments-config

Three things must be true before the first call succeeds:

  1. A supported framework version. As of 2.0.5 the package declares Laravel 9 support in addition to the older constraints; Laravel 10/11 are still not covered. Run composer require and read the constraint error before assuming it works — on Laravel 10+ you may need --ignore-platform-reqs or a fork. Check the PHP constraint resolved by Composer rather than trusting the old 7.4–8.1 range.
  2. Tesseract OCR installed on the host, not just the PHP wrapper. On Debian/Ubuntu: apt-get install tesseract-ocr tesseract-ocr-eng. In Docker, add it to the image — a php:8.1-fpm base will not have it.
  3. Writable temp space for the image the OCR binary reads.

First use case — a passport upload endpoint:

use Werk365\IdentityDocuments\IdentityDocuments;

$document = IdentityDocuments::parse($request->file('passport')->path());
$mrz = $document->getMrz();      // raw MRZ lines
// then map document number, DOB, expiry, nationality, sex off the MRZ

Where to look first, in order: the README (still the only real documentation), config/identitydocuments.php (binary paths, OCR language, temp dir), src/IdentityDocuments.php (the facade entry point and how it shells out), and the returned Document object — dd() it once and read the actual shape rather than trusting examples, because the accessors are thin and largely undocumented.

Start with a single hardcoded test image in tests/fixtures/ and get a full round trip working before touching your upload flow. Parsing a real passport is a 2–5 second operation; you want to know that early.

Implementation Patterns

Controller → Job → Model. Never call parse() inline in a request. The facade blocks on a subprocess. Push it to a queued job and return a "processing" state to the UI:

ProcessPassport::dispatch($documentId)->onQueue('ocr');

// in the job
$parsed = IdentityDocuments::parse(Storage::path($doc->image_path));
$doc->update([
    'document_number' => $parsed->getDocumentNumber(),
    'date_of_birth'   => $parsed->getDateOfBirth(),
    'expiry_date'     => $parsed->getExpiryDate(),
    'nationality'     => $parsed->getNationality(),
    'mrz_valid'       => $parsed->validateCheckDigits(),
]);

Crop before you OCR. Full-page OCR is the biggest source of failure. Passports have a fixed MRZ band across the bottom ~20% (TD3, two lines × 44 chars) or the bottom of the card (TD1, three lines × 30 chars). Cropping and upscaling to ~300 DPI before handing bytes to the parser dramatically improves the hit rate. If the package does not expose a crop hook, do it upstream with Intervention Image and feed the cropped file in.

Never trust the parse — validate. The MRZ carries its own check digits. Treat a failed check as "ask the user to re-upload or type it manually." Build a DocumentData DTO with confidence / needs_review flags and render an editable form pre-filled from the parse. This is the pattern that makes the package usable in production: OCR as assist, human as authority.

Manual fallback path always exists. A "enter details manually" link next to the upload is not a nice-to-have — you will hit documents it cannot read. Design the schema so manual entry writes the same columns with source = 'manual'.

Persistence: store the extracted fields in their own columns (or a JSON column) plus the raw MRZ string for audit. Delete or encrypt the source image — storing passport scans indefinitely is a GDPR liability. A common setup: encrypted S3 object, 30-day lifecycle policy, and only derived fields in MySQL.

Testing: put 3–5 fixture images in tests/fixtures/ (one clean passport, one ID card, one blurry failure case) and assert the parsed output. Because parsing shells out to a binary, mark these tests with a group (@group ocr) so CI without Tesseract can skip them, and mock the facade for the rest of your suite.

Gotchas and Tips

  • GPL-3.0 is the headline risk. This license is copyleft and viral. If you are shipping a closed-source SaaS or a distributed Laravel app, linking this package is legally murky at best. For commercial work, budget time to evaluate alternatives (robertprice/mrz-parser-style pure parsers, cloud APIs like Mindee/Regula/AWS Textract) or plan to isolate it behind a service boundary you can swap. Check composer show werk365/identitydocuments for the license field before you build on it — 2.0.5 did not change it.

  • 2.0.5 is a maintenance release, not a revival. The only note is "Laravel 9 support", and it landed as a patch bump — so expect no API changes and no breaking behaviour, just a widened composer.json constraint. That is genuinely useful if you are pinned to Laravel 9 (it removes the old --ignore-platform-reqs workaround), but it says nothing about Laravel 10/11, PHP 8.2+, or the OCR core. Treat the dependency as low-velocity: pin the version you validate against, and fork into your own namespace if you adopt it — you will still end up owning the maintenance for anything beyond Laravel 9.

  • The binary is the actual dependency. A Class '...' not found is easy; a sh: tesseract: not found inside a container is the one that eats an afternoon. Add tesseract-ocr to every environment image including CI, and make the path configurable rather than absolute.

  • Config caching. If you change the Tesseract path or language and nothing happens, php artisan config:cache with stale values is the culprit — or rather, not running php artisan config:clear. Same class of bug as every Laravel package config. Re-run vendor:publish --force only deliberately; the 2.0.5 upgrade should not have added config keys, but diff the published file after any bump.

  • Raw text is your debugger. When parsing fails, dump the OCR output before it reaches the MRZ parser. Nine times out of ten you'll see garbled characters from glare, skew, or a low-res phone photo — an image problem, not a parser problem. Build a small artisan command (php artisan id:debug path/to.jpg) that prints the raw OCR text and the parsed attempt side by side.

  • MRZ format variance. TD1 (ID cards), TD2, and TD3 (passports) have different line counts and field offsets. Confirm the package handles the document types you actually receive — many implementations assume TD3 only and silently produce garbage on national ID cards.

  • Extension points are thin. There's no documented driver abstraction for swapping OCR engines or parsers, and 2.0.5 adds none. If you need to change behaviour, expect to fork and edit src/ directly. Keep your own calls behind a small wrapper service (App\Services\DocumentParser) so the package is confined to one file when you migrate off it.

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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums