Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
phpunit:
strategy:
matrix:
php_version: [8.0, 8.1, 8.2, 8.3]
php_version: [8.4]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

## 环境需求

- PHP >= 5.6
- PHP >= 8.4

## 安装

Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"type": "library",
"require": {
"guzzlehttp/guzzle": "^6.2 || ^7.0",
"php": ">=8.0",
"ext-json": "*"
"php": ">=8.4",
"ext-json": "*",
"giggsey/libphonenumber-for-php": "^9.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5.8",
Expand Down
64 changes: 62 additions & 2 deletions src/PhoneNumber.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@

namespace Overtrue\EasySms;

use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;

/**
* Class PhoneNumberInterface.
*
Expand All @@ -22,13 +26,58 @@ class PhoneNumber implements Contracts\PhoneNumberInterface

protected ?int $IDDCode;

protected ?\libphonenumber\PhoneNumber $phoneNumberObject = null;

protected PhoneNumberUtil $phoneUtil;

/**
* PhoneNumberInterface constructor.
*/
public function __construct(int|string $numberWithoutIDDCode, ?string $IDDCode = null)
{
$this->number = $numberWithoutIDDCode;
$this->IDDCode = $IDDCode ? intval(ltrim($IDDCode, '+0')) : null;
$this->phoneUtil = PhoneNumberUtil::getInstance();
$numberStr = (string) $numberWithoutIDDCode;
$parsedIDDCode = $IDDCode ? intval(ltrim($IDDCode, '+0')) : null;

// Try to parse using libphonenumber
try {
if (null !== $parsedIDDCode) {
// If IDD code is provided, construct the phone number directly
$this->phoneNumberObject = new \libphonenumber\PhoneNumber();
$this->phoneNumberObject->setCountryCode($parsedIDDCode);
$this->phoneNumberObject->setNationalNumber($numberStr);

$this->IDDCode = $parsedIDDCode;
$this->number = is_numeric($numberWithoutIDDCode) && is_int($numberWithoutIDDCode) ? $numberWithoutIDDCode : $numberStr;
} elseif (str_starts_with($numberStr, '+')) {
// International format with +
$this->phoneNumberObject = $this->phoneUtil->parse($numberStr, null);
$this->IDDCode = $this->phoneNumberObject->getCountryCode();
$this->number = $this->phoneNumberObject->getNationalNumber();
} elseif (str_starts_with($numberStr, '00')) {
// International format with 00 prefix - need to provide a region for parsing
// Try parsing with common regions
$this->phoneNumberObject = $this->phoneUtil->parse($numberStr, 'CN');
$this->IDDCode = $this->phoneNumberObject->getCountryCode();
$this->number = $this->phoneNumberObject->getNationalNumber();
} else {
// No IDD code provided and no international prefix
// Keep the number as-is without parsing (backward compatibility)
$this->number = $numberWithoutIDDCode;
$this->IDDCode = null;

// But still try to parse for validation purposes
try {
$this->phoneNumberObject = $this->phoneUtil->parse($numberStr, 'CN');
} catch (NumberParseException $e) {
// Ignore parsing errors for backward compatibility
}
}
} catch (NumberParseException $e) {
// If parsing fails, fall back to storing the raw values
$this->number = $numberWithoutIDDCode;
$this->IDDCode = $parsedIDDCode;
}
}

/**
Expand All @@ -52,6 +101,10 @@ public function getNumber(): int|string
*/
public function getUniversalNumber(): string
{
if (null !== $this->phoneNumberObject && null !== $this->IDDCode && $this->phoneUtil->isValidNumber($this->phoneNumberObject)) {
return $this->phoneUtil->format($this->phoneNumberObject, PhoneNumberFormat::E164);
}

return $this->getPrefixedIDDCode('+').$this->number;
}

Expand All @@ -60,6 +113,13 @@ public function getUniversalNumber(): string
*/
public function getZeroPrefixedNumber(): string
{
if (null !== $this->phoneNumberObject && null !== $this->IDDCode) {
$e164 = $this->phoneUtil->format($this->phoneNumberObject, PhoneNumberFormat::E164);

// Convert +XX to 00XX
return '00'.substr($e164, 1);
}

return $this->getPrefixedIDDCode('00').$this->number;
}

Expand Down
49 changes: 49 additions & 0 deletions tests/PhoneNumberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,53 @@ public function testJsonEncode()
$n = new PhoneNumber(18888888888, 68);
$this->assertSame(json_encode(['number' => $n->getUniversalNumber()]), \json_encode(['number' => $n]));
}

public function testInternationalFormat()
{
// Test international format with +
$n = new PhoneNumber('+8618888888888');
$this->assertSame(86, $n->getIDDCode());
$this->assertSame('18888888888', $n->getNumber());
$this->assertSame('+8618888888888', $n->getUniversalNumber());
$this->assertSame('008618888888888', $n->getZeroPrefixedNumber());
}

public function testInternationalFormatWithoutPlus()
{
// Test international format starting with 00
$n = new PhoneNumber('008618888888888');
$this->assertSame(86, $n->getIDDCode());
$this->assertSame('18888888888', $n->getNumber());
$this->assertSame('+8618888888888', $n->getUniversalNumber());
}

public function testDifferentCountries()
{
// Test US number
$n = new PhoneNumber('+1 650 253 0000');
$this->assertSame(1, $n->getIDDCode());
$this->assertSame('+16502530000', $n->getUniversalNumber());

// Test Netherlands number
$n = new PhoneNumber('+31612345678');
$this->assertSame(31, $n->getIDDCode());
$this->assertSame('+31612345678', $n->getUniversalNumber());

// Test UK number
$n = new PhoneNumber('+44 117 496 0123');
$this->assertSame(44, $n->getIDDCode());
$this->assertSame('+441174960123', $n->getUniversalNumber());
}

public function testChineseMainlandCheck()
{
$n = new PhoneNumber(18888888888);
$this->assertTrue($n->inChineseMainland());

$n = new PhoneNumber(18888888888, 86);
$this->assertTrue($n->inChineseMainland());

$n = new PhoneNumber(18888888888, 1);
$this->assertFalse($n->inChineseMainland());
}
}