gordonsarah / tz-phone
Validate, normalize, and identify Tanzanian mobile numbers by telecom operator (Vodacom, Airtel, Yas / Mixx by Yas, Halotel, TTCL).
Requires
- php: ^8.1
Requires (Dev)
- laravel/pint: ^1.21
- pestphp/pest: ^2.36
Suggests
- ext-pdo_sqlite: Enables the standalone SQLite prefix store.
- illuminate/database: Enables Laravel migrations and Eloquent models for database-backed prefixes.
- illuminate/support: Enables Laravel service provider, config publishing, Artisan commands, and the tz_phone validation rule.
Provides
None
Conflicts
None
Replaces
None
README
A PHP package (with optional Laravel extras) that validates, normalizes, and identifies Tanzanian mobile numbers using the TCRA National Numbering Plan.
Sponsored by TechMorah.
Features
- Validate Tanzanian mobile numbers (
isValid()), including Laraveltz_phoneandtz_phone:vodacom - Normalize messy input (
0754 123 456,255754123456,+255754123456) into E.164 and local form - Identify the telecom company from the prefix: Vodacom, Airtel, Yas (Mixx by Yas / Tigo / Zantel), Halotel, TTCL, Smile, and others
- Identify the mobile-money wallet: M-Pesa, Airtel Money, Mixx by Yas, HaloPesa, T-Pesa
- Format numbers as E.164 (
+255754123456), local (0754123456), and international (+255 754 123 456) - Manage prefixes in the database — add, update, or remove codes when TCRA assigns new ranges, without changing package code
- Laravel extras: validation rule, Artisan commands, Eloquent models, config publish, auto-discovery
- Plain PHP works without Laravel; optional SQLite store for the same prefix tables
- MIT License
It maps the prefix to the original network:
| Operator | Company | Mobile money | Prefixes | Status |
|---|---|---|---|---|
| Vodacom | Vodacom Tanzania PLC | M-Pesa | 074, 075, 076, 079 | operational |
| Airtel | Airtel Tanzania PLC | Airtel Money | 068, 069, 078 | operational |
| Yas (Tigo / Mixx) | Honora Tanzania PLC | Mixx by Yas | 065, 067, 071, 077 | operational (077 former Zantel) |
| Halotel | Viettel Tanzania PLC | HaloPesa | 061, 062 | 062 not operational |
| TTCL | Tanzania Telecommunications Corporation | T-Pesa | 073 | operational |
| Smile | Smile Communications Tanzania Limited | — | 066 | reserved (still circulating) |
| Amotel | Mkulima African Telecommunication Company Limited | — | 063 | reserved |
| CooTel | Wiafrica Tanzania Limited | — | 064 | reserved |
| MO Mobile | MO Mobile Holding Limited | — | 072 | reserved |
070 is reserved by TCRA and is not assigned until you add it in the database. Prefixes live in data (config or database), not hardcoded if statements.
PHP packages are published on Packagist, not pub.dev. pub.dev is the registry for Dart/Flutter.
Installation
composer require gordonsarah/tz-phone
Laravel 10+ will auto-discover the service provider. Then create the prefix tables and seed TCRA defaults:
php artisan vendor:publish --tag=tz-phone-config php artisan migrate php artisan tz-phone:seed
After that, prefixes are read from the database. Adding a new TCRA code is a row change, not a code change.
Usage
use GordonSarah\TzPhone\PhoneNumber; $phone = PhoneNumber::parse('255 754 123 456'); $phone->isValid(); // true $phone->getCountryCode(); // 255 $phone->getNetworkOperator(); // Vodacom $phone->getOperatorId(); // vodacom $phone->getCompany(); // Vodacom Tanzania PLC $phone->getMobileMoney(); // M-Pesa $phone->getPrefix(); // 075 $phone->getNumber(); // 255754123456 $phone->getE164(); // +255754123456 $phone->getLocalNumber(); // 0754123456 $phone->getInternational(); // +255 754 123 456
Accepted input shapes:
0754123456754123456255754123456+255754123456- spaced / dashed variants such as
255 754 123 456
Helper:
tz_phone('0712345678')->getMobileMoney(); // Mixx by Yas
Identify Mixx by Yas, Vodacom, Airtel, Halotel, TTCL
$phone = PhoneNumber::parse('0712345678'); $phone->belongsTo('Yas'); // true $phone->belongsTo('Mixx by Yas'); // true $phone->belongsTo('Tigo'); // true (former brand) $phone->belongsTo('vodacom'); // false
Manage prefixes from the database
Laravel uses your app database (MySQL, PostgreSQL, or SQLite). Tables:
tz_phone_operators— telecom company / brand / wallettz_phone_prefixes—075→ Vodacom,071→ Yas, and so on
Artisan:
php artisan tz-phone:list php artisan tz-phone:add-operator smile --name=Smile --company="Smile Communications Tanzania Limited" php artisan tz-phone:add-prefix vodacom 070 --status=operational --notes="New TCRA assignment" php artisan tz-phone:remove-prefix 062 php artisan tz-phone:seed
Eloquent (Filament, Nova, or your own admin):
use GordonSarah\TzPhone\Laravel\Models\TzPhoneOperator; use GordonSarah\TzPhone\Laravel\Models\TzPhonePrefix; $yas = TzPhoneOperator::where('slug', 'yas')->first(); TzPhonePrefix::create([ 'operator_id' => $yas->id, 'prefix' => '070', 'status' => 'operational', 'notes' => 'Added after TCRA gazette', ]);
Plain PHP with SQLite (no Laravel):
use GordonSarah\TzPhone\OperatorRegistry; use GordonSarah\TzPhone\Stores\DatabaseOperatorStore; $store = DatabaseOperatorStore::sqlite(__DIR__.'/tz-phone.sqlite'); $store->seedFromConfig(OperatorRegistry::defaultConfig()); $registry = OperatorRegistry::instance()->useStore($store); $registry->addPrefix('vodacom', '070'); // written to SQLite
Laravel validation
use GordonSarah\TzPhone\Laravel\Rules\TzPhoneRule; $request->validate([ 'phone' => ['required', new TzPhoneRule()], ]); // Only Vodacom or Airtel $request->validate([ 'phone' => ['required', TzPhoneRule::make('vodacom', 'airtel')], ]);
String rule (after the service provider is loaded):
$request->validate([ 'phone' => 'required|tz_phone', 'vodacom_msisdn' => 'required|tz_phone:vodacom', ]);
Facade:
use GordonSarah\TzPhone\Laravel\Facades\TzPhone; TzPhone::parse('0784123456')->getNetworkOperator(); // Airtel TzPhone::addPrefix('vodacom', '070');
Bootstrap demo
composer install php -S 127.0.0.1:8080 -t example
Open http://127.0.0.1:8080 to try numbers against the live registry.
Caveats
- Prefix lookup identifies the original assigned network, not necessarily the current operator after mobile number portability.
062is assigned to Halotel but listed not operational in TCRA 2025.066/063/064/072are historical or reserved ranges that still identify a company;isValid(true)rejects them.- This package covers mobile NDCs (
06X/07X), not fixed-line geographic numbers.
Testing
composer test
composer format
Changelog
Please see CHANGELOG.
Security
Please review SECURITY for how to report vulnerabilities.
Credits
- Sarah Gordon · GordonSarah
- Sponsored by TechMorah
- Numbering data from the Tanzania Communications Regulatory Authority
License
The MIT License (MIT). Please see LICENSE.