PHPackages                             wal3fo/phone-country - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. wal3fo/phone-country

ActiveLibrary[Validation &amp; Sanitization](/categories/validation)

wal3fo/phone-country
====================

Resolve country code from phone number for Laravel, with AI-powered normalization, disambiguation, fraud detection, and metadata enrichment.

v1.0.0(2mo ago)1201MITPHPPHP ^8.0

Since Apr 11Pushed 2mo agoCompare

[ Source](https://github.com/wal3fo/Phone-Country-Resolver)[ Packagist](https://packagist.org/packages/wal3fo/phone-country)[ RSS](/packages/wal3fo-phone-country/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (1)Dependencies (2)Versions (4)Used By (0)

[![phone-country-resolver](.github/assets/banner.svg)](.github/assets/banner.svg)
[![Packagist Version](https://camo.githubusercontent.com/7091626d790c6b8de0845aa89a9a82b1e8a32badd16706d527033da729a99185/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f77616c33666f2f70686f6e652d636f756e7472793f7374796c653d666c61742d73717561726526636f6c6f723d366565376237266c6162656c436f6c6f723d306431313137)](https://packagist.org/packages/wal3fo/phone-country)[![Total Downloads](https://camo.githubusercontent.com/e243e3e533e25ba006b4f3c6141394d234d4bc989772d76b6bc40777525f9037/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f77616c33666f2f70686f6e652d636f756e7472793f7374796c653d666c61742d73717561726526636f6c6f723d383138636638266c6162656c436f6c6f723d306431313137)](https://packagist.org/packages/wal3fo/phone-country)[![PHP](https://camo.githubusercontent.com/535adacd57b3c92453e484e8952ec1a62ec7481f2a4f404817ee80b5f89fcfb1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e302532422d3737374242343f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d306431313137)](https://php.net)[![Laravel](https://camo.githubusercontent.com/a2045c870b4ab907559e90e054d54d23bc3b3eff46322e144afa55c70a111a11/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d382d2d31332d4646324432303f7374796c653d666c61742d737175617265266c6162656c436f6c6f723d306431313137)](https://laravel.com)[![License](https://camo.githubusercontent.com/29d5ec6eb6b3544920440dbd0e602956df118c4f5b77770c4416fe21d398144e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f77616c33666f2f70686f6e652d636f756e7472793f7374796c653d666c61742d73717561726526636f6c6f723d666239323363266c6162656c436f6c6f723d306431313137)](LICENSE)

**Resolve ISO 3166-1 alpha-2 country codes from phone numbers.**
Rich metadata · Flag &amp; geography · Number formatting · HTML card output · Zero dependencies.

```
composer require wal3fo/phone-country
```

---

Features
--------

[](#features)

FeatureMethodDescription🔍 Country resolution`resolveCountryCode()`Returns the ISO alpha-2 code from any phone format🌐 Rich analysis`analyze()`Full country metadata, number type, formatting, and more🏳️ Flag &amp; geography`analyze()`Emoji flag, region, continent, and capital city💱 Currency &amp; language`analyze()`ISO 4217 currency, currency name, and primary language🕐 Timezone`analyze()`IANA timezone for 180+ countries📐 Formatting`analyze()`National and international number formats🖼️ HTML card`toHtml()`Self-contained, styled HTML card — no external dependencies✅ Validation rule`PhoneCountryRule`Laravel validation rule with allowlist and strict mode---

Quick start
-----------

[](#quick-start)

```
use Wal3fo\PhoneCountry\PhoneCountryService;

$analysis = PhoneCountryService::analyze('+212612345678');

// ── Country & identity ────────────────────────────────────
$analysis->countryCode;        // 'MA'
$analysis->countryName;        // 'Morocco'
$analysis->flag;               // '🇲🇦'
$analysis->dialingCode;        // '212'
$analysis->e164;               // '+212612345678'

// ── Geography ─────────────────────────────────────────────
$analysis->region;             // 'Northern Africa'
$analysis->continent;          // 'Africa'
$analysis->capital;            // 'Rabat'

// ── Cultural metadata ─────────────────────────────────────
$analysis->timezone;           // 'Africa/Casablanca'
$analysis->currency;           // 'MAD'
$analysis->currencyName;       // 'Moroccan Dirham'
$analysis->language;           // 'Arabic'

// ── Number analysis ───────────────────────────────────────
$analysis->nationalNumber;     // '612345678'
$analysis->numberType;         // 'MOBILE'
$analysis->isValid;            // true
$analysis->isPossible;         // true
$analysis->digitCount;         // 9

// ── Formatting ────────────────────────────────────────────
$analysis->formatNational;        // '61 23 45 67 8'
$analysis->formatInternational;   // '+212 612 345 678'

// ── Input metadata ────────────────────────────────────────
$analysis->raw;                // '+212612345678'
$analysis->normalized;         // '212612345678'
$analysis->inputFormat;        // 'E164'
$analysis->usedFallback;       // false
$analysis->resolvedAt;         // '2025-01-01T00:00:00+00:00'

// ── Output helpers ────────────────────────────────────────
$analysis->explanation;        // HTML  summary card
$analysis->toArray();          // full associative array
$analysis->toJson();           // JSON string
$analysis->toHtml();           // self-contained HTML card
```

---

Core methods
------------

[](#core-methods)

### `resolveCountryCode()`

[](#resolvecountrycode)

Resolves a phone number and returns the ISO 3166-1 alpha-2 country code.

```
PhoneCountryService::resolveCountryCode('+212612345678');       // 'MA'
PhoneCountryService::resolveCountryCode('00212612345678');      // 'MA'
PhoneCountryService::resolveCountryCode('0612345678', 'MA');    // 'MA'  ← local fallback
PhoneCountryService::resolveCountryCode('0612345678');          // 'XX'  ← unresolvable
```

Returns `'XX'` when the number cannot be resolved to any country.

### `analyze()`

[](#analyze)

Analyzes a phone number and returns a rich `PhoneAnalysis` value object.

```
$analysis = PhoneCountryService::analyze('+33612345678');

$analysis->countryCode;   // 'FR'
$analysis->countryName;   // 'France'
$analysis->flag;          // '🇫🇷'
$analysis->timezone;      // 'Europe/Paris'
$analysis->currency;      // 'EUR'
$analysis->language;      // 'French'
$analysis->numberType;    // 'MOBILE'
$analysis->isValid;       // true
$analysis->toHtml();      // styled HTML card
```

With a local number and fallback country:

```
$analysis = PhoneCountryService::analyze('0612345678', 'MA');
$analysis->countryCode;   // 'MA'
$analysis->e164;          // '+212612345678'
$analysis->inputFormat;   // 'LOCAL'
$analysis->usedFallback;  // true
```

### Validation rule

[](#validation-rule)

```
use Wal3fo\PhoneCountry\Rules\PhoneCountryRule;

// Any valid international number
'phone' => ['required', new PhoneCountryRule()]

// With Morocco as local fallback
'phone' => ['required', new PhoneCountryRule('MA')]

// Restrict to a country allowlist
'phone' => ['required', new PhoneCountryRule(['MA', 'FR', 'ES'])]

// Strict mode — reject local 0xxx format
'phone' => ['required', new PhoneCountryRule('MA', strict: true)]
```

Example in a Form Request:

```
use Wal3fo\PhoneCountry\Rules\PhoneCountryRule;

class RegisterRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name'  => ['required', 'string'],
            'phone' => ['required', 'string', new PhoneCountryRule('MA')],
        ];
    }
}
```

### Dependency injection

[](#dependency-injection)

```
class UserProfileController extends Controller
{
    public function __construct(
        protected PhoneCountryService $phoneService
    ) {}

    public function update(Request $request)
    {
        $analysis = $this->phoneService->analyze($request->phone_number);

        $user->update([
            'phone'        => $analysis->e164,
            'country_code' => $analysis->countryCode,
        ]);
    }
}
```

---

`analyze()` — rich pipeline
---------------------------

[](#analyze--rich-pipeline)

### 🌐 Country metadata

[](#-country-metadata)

Every resolved number returns full geographic and cultural data:

```
$a = PhoneCountryService::analyze('+966512345678');  // Saudi Arabia

$a->countryCode;    // 'SA'
$a->countryName;    // 'Saudi Arabia'
$a->flag;           // '🇸🇦'
$a->region;         // 'Western Asia'
$a->continent;      // 'Asia'
$a->capital;        // 'Riyadh'
$a->currency;       // 'SAR'
$a->currencyName;   // 'Saudi Riyal'
$a->language;       // 'Arabic'
$a->timezone;       // 'Asia/Riyadh'
```

Covers 180+ countries with IANA timezone · ISO 4217 currency · capital city · world region.

### 📐 Number formatting

[](#-number-formatting)

`analyze()` produces both national and international formatted strings:

```
$a = PhoneCountryService::analyze('+212612345678');
$a->formatNational;        // '61 23 45 67 8'
$a->formatInternational;   // '+212 612 345 678'
$a->nationalNumber;        // '612345678'
$a->digitCount;            // 9

$b = PhoneCountryService::analyze('+33612345678');
$b->formatNational;        // '61 23 45 67'
$b->formatInternational;   // '+33 612 345 678'
```

### 🔢 Number type &amp; validity

[](#-number-type--validity)

```
$a = PhoneCountryService::analyze('+212612345678');
$a->numberType;   // 'MOBILE'
$a->isValid;      // true   — passes length check for MA (exactly 9 digits)
$a->isPossible;   // true   — within ±1 of expected range

$b = PhoneCountryService::analyze('+18005551234');
$b->numberType;   // 'TOLL_FREE'

$c = PhoneCountryService::analyze('+19005551234');
$c->numberType;   // 'PREMIUM'
```

**Number types:** `MOBILE` · `FIXED_LINE` · `TOLL_FREE` · `PREMIUM` · `UNKNOWN`

### 🖼️ HTML card output

[](#️-html-card-output)

`toHtml()` returns a fully self-contained, styled card with no external dependencies:

```
$html = PhoneCountryService::analyze('+212612345678')->toHtml();
// Returns a  with inline CSS, flag, badges, and a data table
```

Ideal for debug views, Blade partials, or API responses that render in a browser.

The `explanation` magic property returns an HTML `` list summary:

```
echo PhoneCountryService::analyze('+33612345678')->explanation;
//
//   Number: +33612345678
//   Country: 🇫🇷 France (+33)
//   ...
//
```

### 🔄 Input format detection

[](#-input-format-detection)

`analyze()` recognizes and normalizes multiple input formats:

```
PhoneCountryService::analyze('+212612345678')->inputFormat;    // 'E164'
PhoneCountryService::analyze('00212612345678')->inputFormat;   // 'DOUBLE_ZERO'
PhoneCountryService::analyze('212612345678')->inputFormat;     // 'NUMERIC'
PhoneCountryService::analyze('0612345678', 'MA')->inputFormat; // 'LOCAL'
```

---

`PhoneAnalysis` reference
-------------------------

[](#phoneanalysis-reference)

### Properties

[](#properties)

PropertyTypeDescription`raw``string`Original input as-is`normalized``string`Cleaned digits (no `+`, spaces, or dashes)`e164``string`Canonical E.164 format, e.g. `+212612345678``nationalNumber``string`Number without the country calling code`dialingCode``string`Numeric calling code, e.g. `212``countryCode``string`ISO 3166-1 alpha-2, e.g. `MA``countryName``string`Full English name, e.g. `Morocco``flag``string`Emoji flag, e.g. `🇲🇦``region``string`World region, e.g. `Northern Africa``continent``string`Continent, e.g. `Africa``capital``string`Capital city, e.g. `Rabat``currency``string`ISO 4217 code, e.g. `MAD``currencyName``string`Currency name, e.g. `Moroccan Dirham``language``string`Primary language, e.g. `Arabic``timezone``string`IANA timezone, e.g. `Africa/Casablanca``numberType``string``MOBILE` / `FIXED_LINE` / `TOLL_FREE` / `PREMIUM` / `UNKNOWN``isValid``bool`Passes basic length check for the country`isPossible``bool`Within ±1 digit of expected length`digitCount``int`Total digit count of `nationalNumber``formatNational``string`National format, e.g. `06 12 34 56 78``formatInternational``string`International format, e.g. `+212 612 345 678``inputFormat``string``E164` / `DOUBLE_ZERO` / `NUMERIC` / `LOCAL``usedFallback``bool``true` if `localCountryCode` fallback was applied`resolvedAt``string`ISO 8601 UTC timestamp of resolution### Methods &amp; magic properties

[](#methods--magic-properties)

NameDescription`toArray()`Full associative array — ready for JSON responses`toJson(int $flags)`JSON string (default: `JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE`)`toHtml()`Self-contained HTML card with inline CSS`toUl()`HTML `` summary list`$analysis->explanation`Magic alias for `toUl()`---

Examples
--------

[](#examples)

InputCountryNameFormat`+212612345678``MA`Morocco`E164``00212612345678``MA`Morocco`DOUBLE_ZERO``212612345678``MA`Morocco`NUMERIC``0612345678` + `'MA'``MA`Morocco`LOCAL``+33612345678``FR`France`E164``+18005551234``US`United States`E164` (toll-free)`+966512345678``SA`Saudi Arabia`E164``0612345678``XX`Unknown`LOCAL`---

Installation &amp; configuration
--------------------------------

[](#installation--configuration)

```
composer require wal3fo/phone-country

# Optionally publish the config
php artisan vendor:publish --tag=phone-country-config
```

```
// config/phone-country.php
return [
    'default_country' => env('PHONE_COUNTRY_DEFAULT', 'XX'),
    'unknown_code'    => 'XX',
];
```

```
PHONE_COUNTRY_DEFAULT=MA
```

**Performance** — for high-volume workloads, cache `analyze()` results:

```
$analysis = Cache::remember("phone_analysis:{$phone}", 3600, fn () =>
    PhoneCountryService::analyze($phone)
);
```

---

File structure
--------------

[](#file-structure)

```
src/
├── PhoneCountryService.php          ← Main service — resolveCountryCode() and analyze()
├── PhoneCountryServiceProvider.php  ← Laravel service provider
├── PhoneAnalysis.php                ← Rich value object returned by analyze()
├── PhoneResult.php                  ← Lightweight value object
├── CountryMetadata.php              ← Static map: flag, region, capital, currency, language, timezone
├── Rules/
│   └── PhoneCountryRule.php         ← Laravel validation rule
└── AI/
    ├── PhoneNormalizer.php          ← Input cleaning & repair
    ├── NanpDisambiguator.php        ← +1 area-code map (25+ NANP countries)
    ├── FraudDetector.php            ← Toll-free / premium / VOIP signal detection
    ├── MetadataEnricher.php         ← Extended metadata enrichment
    └── PhoneExplainer.php           ← Plain-language explanation generator
config/
└── phone-country.php

```

---

Changelog
---------

[](#changelog)

### v1.0.0

[](#v100)

- Initial release with `resolveCountryCode()` and longest-prefix matching
- Added `analyze()` returning `PhoneAnalysis` value object
- Added `PhoneAnalysis` with flag, region, continent, capital, currency name, language, timezone
- Added national and international number formatting (`formatNational`, `formatInternational`)
- Added `isPossible` and `digitCount` for length plausibility checks
- Added input format detection (`E164`, `DOUBLE_ZERO`, `NUMERIC`, `LOCAL`)
- Added `usedFallback` and `resolvedAt` metadata
- Added `toHtml()` — self-contained HTML card with inline CSS
- Added `toJson()` and `toArray()` for API responses
- Added `explanation` magic property returning an HTML `` summary
- Added `CountryMetadata` — static map for 180+ countries
- Added `PhoneCountryRule` — Laravel validation rule with allowlist and strict mode
- Added `AI/` — PhoneNormalizer, NanpDisambiguator, FraudDetector, MetadataEnricher, PhoneExplainer

---

Contributing
------------

[](#contributing)

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/your-feature`
3. Commit your changes: `git commit -m 'Add your feature'`
4. Push to the branch: `git push origin feature/your-feature`
5. Open a Pull Request

---

License
-------

[](#license)

The MIT License (MIT). See [LICENSE](LICENSE) for full details.

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance86

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 93.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~11 days

Total

3

Last Release

76d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d2ce4983cf5acecde9209ea787f0a01c51fc9c653e25eb251e79dd6348299f67?d=identicon)[wal3fo](/maintainers/wal3fo)

---

Top Contributors

[![wal3fo](https://avatars.githubusercontent.com/u/92164512?v=4)](https://github.com/wal3fo "wal3fo (28 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (2 commits)")

### Embed Badge

![Health badge](/badges/wal3fo-phone-country/health.svg)

```
[![Health](https://phpackages.com/badges/wal3fo-phone-country/health.svg)](https://phpackages.com/packages/wal3fo-phone-country)
```

###  Alternatives

[illuminate/validation

The Illuminate Validation package.

18837.7M1.6k](/packages/illuminate-validation)[laravel-validation-rules/credit-card

Validate credit card number, expiration date, cvc

2422.3M6](/packages/laravel-validation-rules-credit-card)[danielebarbaro/laravel-vat-eu-validator

A simple package that validates EU VAT numbers against the central ec.europa.eu database

41401.6k](/packages/danielebarbaro-laravel-vat-eu-validator)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
