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

Identity Card Laravel Package

ofcold/identity-card

ofcold/identity-card is a Laravel/PHP package for Chinese resident ID numbers. It validates 18-digit identity cards, generates valid numbers for testing, and parses birth date, gender, age, and region details. Use it for form validation, user data checks, and API workflows in Laravel apps or standal...

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package:

    composer require ofcold/identity-card
    

    Laravel 5.5+ users get auto-discovery; on older versions register Ofcold\IdentityCard\IdentityCardServiceProvider in config/app.php and add 'IdentityCard' => Ofcold\IdentityCard\IdentityCardFacade::class to your aliases.

  2. Publish the config (region data, error messages, default behaviors) before touching any code:

    php artisan vendor:publish --provider="Ofcold\IdentityCard\IdentityCardServiceProvider"
    

    Review config/identity-card.php for the region data source and any message overrides.

  3. Look first at:

    • The README's fluent example (IdentityCard::make($number) then chained getters).
    • The bundled region data file — this is what determines whether a syntactically valid ID passes the "region exists" check.
    • The Validator extension point if you plan to wrap it in a FormRequest rule.
  4. First use case — validate on entry, parse on success:

    use Ofcold\IdentityCard\IdentityCard;
    
    $card = IdentityCard::make($request->input('id_number'));
    
    if ($card === false) {
        return back()->withErrors(['id_number' => 'Invalid ID card number.']);
    }
    
    return [
        'region'       => $card->getArea(),           // province/city/district string
        'birthday'     => $card->getBirthday()->toDateString(),
        'gender'       => $card->getGender(),         // 'male' / 'female'
        'age'          => $card->getAge(),
        'zodiac'       => $card->getZodiac(),
        'constellation'=> $card->getConstellation(),
    ];
    
  5. Run a quick Tinker sanity check with a known-good 18-digit number (and one with a deliberately wrong checksum digit) before wiring it into a flow — it's the fastest way to confirm the region data and checksum behave as you expect.

Implementation Patterns

  • Validation rule integration: Prefer the package's Laravel validation rule over manual calls inside controllers. Use it in a FormRequest:

    public function rules(): array
    {
        return [
            'id_number' => ['required', 'string', new IdentityCardRule()],
        ];
    }
    

    This keeps validation declarative and centralised, and surfaces the package's error messages through the standard validation bag.

  • Service injection vs. facade: For anything beyond a one-liner, inject IdentityCardService (or construct IdentityCard::make() in a small dedicated service) rather than calling the facade from deep inside a controller. It makes the class testable and lets you swap a stub.

  • Parsing into a DTO: Wrap parsing in your own value object — IdentityData::fromNumber($id) — so controllers and views depend on your shape, not the package's. This is the single most important pattern for avoiding lock-in if you ever swap packages.

  • Registration / KYC form: Validate format first (fast rule), then resolve region and birthday. Reject future birthdays and implausibly old ones by comparing getBirthday() against now(). Do not trust the derived age alone for compliance checks — recompute from the birthday at the point of use.

  • Seeding and test fixtures: Use the generator to populate factories with realistic IDs:

    User::factory()->create([
        'id_number' => IdentityCard::fake()->getIdentityCard(), // or ->generate()
    ]);
    

    Cache a small pool of generated IDs in setUp() for large seeders so you don't regenerate tens of thousands in a loop.

  • Bulk imports: When importing CSV of users, validate each row and collect failures rather than throwing on the first invalid ID. A per-row try/catch around IdentityCard::make() — or a truthiness check if false is returned — is safer than letting exceptions halt the import.

  • Version pinning: Pin to a specific minor ("ofcold/identity-card": "3.3.*") and add a small regression test with a fixed known-good ID plus each derived field (region, birthday, gender, zodiac, constellation). The 3.3.2 release fixed the horoscope/constellation output specifically — that is exactly the kind of output you want locked down by a test.

Gotchas and Tips

  • false vs. exception: Depending on the entry point, IdentityCard::make() may return false on invalid input rather than throwing. Always check truthiness before chaining getters, or you'll get a method-call-on-false in production. If you prefer exceptions, use the explicit validator or try/catch around an exception-throwing method.

  • 15-digit vs. 18-digit: 15-digit legacy IDs have no checksum and no gender digit in the 17th position — the package infers gender from the last digit differently. Some methods (age, checksum) may behave differently or be unavailable for 15-digit numbers. Decide explicitly whether you accept 15-digit IDs at all; for new KYC flows you probably shouldn't. Normalise 15-digit to 18-digit up front if you need a single canonical format.

  • Checksum is not validity: The checksum (the 18th digit MOD 11-2 rule) catches typos, not fraud. Never equate "passes validation" with "authentic person". Keep a real verification path (carrier/authority API) separate.

  • Region data staleness: The "region exists" check is only as fresh as the bundled region dataset. Administrative divisions change (new districts, renamed counties). Keep the package up to date, and if you reject valid new-area IDs in production, that's your first suspect — not the checksum.

  • Birthday returns a date object: getBirthday() typically returns a Carbon/DateTime, not a string. Cast with ->toDateString() before storing, or the Eloquent model will stringify it unexpectedly. Also check the timezone used when computing getAge() — a birthday "today" in UTC may read as tomorrow in Asia/Shanghai.

  • Zodiac vs. Western zodiac: Chinese "zodiac" (rat, ox, tiger…) and Western "constellation"/"horoscope" (Aries, Leo…) are both exposed. They are different fields — don't confuse getZodiac() with getConstellation(), especially around Chinese New Year (the zodiac changes on lunar new year, not Jan 1) and around cusp dates (e.g. Leo/Virgo boundary). The 3.3.2 patch touched horoscope output — verify cusp boundaries with a fixed test if you surface constellations.

  • Config caching in production: The published config is cached with php artisan config:cache. If you override messages or change region data paths, run php artisan config:clear && php artisan config:cache or your changes silently won't apply. This is the number one "why is the error message / region check still wrong" debugging step.

  • Masking for logs and UI: Do not log or render full ID numbers. Mask to 110101********1234 (keep first 6 and last 4) before any Log::info, exception message, or response payload. Store the number encrypted-at-rest or hashed if you only need equality lookups.

  • Extension points: Prefer a decorator/service around the package for formatting, caching derived profile data, or swapping region sources. Never edit vendor files — composer install will wipe them and the change won't survive a deploy.

  • Debugging checklist when a real ID won't validate: (1) Trim whitespace and confirm 15/18-digit length; (2) recompute the checksum by hand for the last digit; (3) confirm the region code exists in the current dataset (look it up directly); (4) confirm the birth date is a real calendar date (the package rejects 2023-02-30, but check the year isn't outside the allowed range); (5) check you're not running against a cached config with an old data path.

  • Testing generators: fake() IDs are structurally valid and are great for factories and seeder data, but do not use them as fixtures for testing specific region/gender assertions unless the generator lets you pin those — otherwise your test is coupled to whatever random value it produced.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager