markhor / laravel-pakistan-validator
Pakistani CNIC and phone number validation, normalization, value objects and Eloquent casts for Laravel.
Package info
github.com/hasnainriazkayanii/laravel-pakistan-validator
pkg:composer/markhor/laravel-pakistan-validator
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0
- illuminate/database: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- illuminate/validation: ^11.0|^12.0
Requires (Dev)
- larastan/larastan: ^2.9|^3.0
- laravel/pint: ^1.13
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-12 23:01:47 UTC
README
Validation, normalization and value objects for Pakistani CNIC numbers and phone numbers in Laravel.
pk_cnicandpk_phonevalidation rules (string and object style)- Accepts every format users actually type, including Urdu digits, and normalizes to one canonical form
- Immutable
CnicandPhoneNumbervalue objects (province, gender, masked CNIC, E.164, carrier hint) - Eloquent casts that store clean data (
3520212345671,+923001234567) - English and Urdu error messages
- No config, no migrations, no runtime dependencies beyond Laravel
Requires PHP 8.2+ and Laravel 11 or 12.
Installation
composer require markhor/laravel-pakistan-validator
The service provider is auto-discovered.
Validation
use Markhor\PakistanValidator\Rules\PakistaniCnic; use Markhor\PakistanValidator\Rules\PakistaniPhone; $request->validate([ 'cnic' => ['required', 'pk_cnic'], 'mobile' => ['required', 'pk_phone'], // mobile only (default) 'landline' => ['nullable', 'pk_phone:landline'], 'contact' => ['required', 'pk_phone:any'], // or rule objects 'cnic2' => [new PakistaniCnic], 'mobile2' => [PakistaniPhone::mobile()], ]);
| Input | Result |
|---|---|
35202-1234567-1, 3520212345671, ۳۵۲۰۲-۱۲۳۴۵۶۷-۱ |
valid CNIC |
0300-1234567, 03001234567, +92 300 1234567, 923001234567, 00923001234567, 3001234567 |
valid mobile |
051-1234567, +92 21 12345678 |
valid landline (pk_phone:landline / :any) |
Value objects
use Markhor\PakistanValidator\ValueObjects\{Cnic, PhoneNumber}; $cnic = Cnic::parse('35202-1234567-1'); // throws InvalidCnicException when invalid $cnic->digits; // 3520212345671 $cnic->formatted(); // 35202-1234567-1 $cnic->masked(); // 35202-*******-1 (safe for logs/UI) $cnic->province(); // Province::Punjab $cnic->gender(); // Gender::Male (odd last digit = male, even = female) $phone = PhoneNumber::tryParse('0300 1234567'); // null when invalid $phone->e164(); // +923001234567 $phone->national(); // 0300-1234567 $phone->international(); // +92 300 1234567 $phone->isMobile(); // true $phone->carrier(); // Carrier::Jazz (hint only, see below)
Eloquent casts
use Markhor\PakistanValidator\Casts\{CnicCast, PhoneNumberCast}; protected function casts(): array { return [ 'cnic' => CnicCast::class, // stored as 13 digits 'phone' => PhoneNumberCast::class, // stored as E.164 ]; } $user->cnic = '35202-1234567-1'; $user->cnic->masked(); User::where('cnic', Cnic::parse($input)->digits)->first();
Assigning an invalid value throws InvalidArgumentException, so validate input first.
Translations
php artisan vendor:publish --tag=pakistan-validator-lang
Messages exist for en and ur. Custom messages passed to the validator ('pk_cnic' => '...') always win.
What this package does not do
- It checks structure, not existence. There is no public CNIC checksum; confirming that a CNIC or number is real needs NADRA/Verisys or an SMS/OTP check.
- Carrier detection is a hint. Mobile Number Portability means a prefix does not prove the current operator.
- Province and gender are derived from conventions (first digit, last digit parity) and should not be used for legal decisions.
- CNIC values are personal data. Prefer
masked()in logs and UI; exceptions never include the offending value.
Testing
composer install
composer test
composer analyse
composer format
Contributing
Operator prefix allocations change. PRs updating Carrier::fromPrefix() must include a test and a source.
License
MIT. See LICENSE.md.