在 Web 開發中,手機號碼驗證是表單檢核的基礎環節。雖然正則表達式能快速實現格式檢查,但隨著運營商不斷推出新號段,單純靠正則維護已力不從心。本文將系統梳理 PHP 手機號驗證的演進歷程,提供從基礎正則到號段白名單的完整方案,並探討實戰中的避坑指南。
了解號段分佈是編寫正則的前提。三大運營商核心號段如下:
提示:號段更新頻率極高,建議定期同步工信部最新公告,或接入第三方號段庫 API。
$pattern = '/^1[3-9]\d{9}$/';
優點:簡潔、效能高;缺點:無法過濾不存在的號段(如 120、110 等)。
$pattern = '/^(?:13\d|14[5-9]|15[0-35-9]|16[25-7]|17[0-8]|18\d|19[0-35-9])\d{8}$/';
涵蓋主流號段,但新號段推出後需手動維護。
function isMobile(string $mobile): bool
{
// 1. 基礎格式檢查
if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
return false;
}
// 2. 號段白名單檢查(建議從配置檔或資料庫讀取)
$prefix = substr($mobile, 0, 3);
$validPrefixes = [
130,131,132,133,134,135,136,137,138,139,
145,146,147,148,149,
150,151,152,153,155,156,157,158,159,
162,165,166,167,
170,171,172,173,174,175,176,177,178,
180,181,182,183,184,185,186,187,188,189,
190,191,192,193,195,196,197,198,199
];
return in_array((int)$prefix, $validPrefixes, true);
}
class MobileValidator
{
private static array $prefixCache = [];
public static function validate(string $mobile, bool $strict = true): bool
{
$mobile = trim($mobile);
if ($mobile === '') return false;
// 基礎正則
if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
return false;
}
if (!$strict) return true;
// 嚴格模式:號段白名單
$prefix = (int)substr($mobile, 0, 3);
return self::isValidPrefix($prefix);
}
private static function isValidPrefix(int $prefix): bool
{
if (empty(self::$prefixCache)) {
self::$prefixCache = array_flip([
130,131,132,133,134,135,136,137,138,139,
145,146,147,148,149,
150,151,152,153,155,156,157,158,159,
162,165,166,167,
170,171,172,173,174,175,176,177,178,
180,181,182,183,184,185,186,187,188,189,
190,191,192,193,195,196,197,198,199
]);
}
return isset(self::$prefixCache[$prefix]);
}
}
// 使用範例
$mobile = '13800138000';
if (MobileValidator::validate($mobile)) {
echo '手機號格式正確';
} else {
echo '手機號格式錯誤';
}
從文本中批量提取手機號並驗證:
function extractMobiles(string $text): array
{
preg_match_all('/1[3-9]\d{9}/', $text, $matches);
$mobiles = array_unique($matches[0] ?? []);
return array_filter($mobiles, fn($m) => MobileValidator::validate($m));
}
$content = '聯繫電話:13800138000,備用:15912345678,無效:12012345678';
$validMobiles = extractMobiles($content);
// 結果:['13800138000', '15912345678']
libphonenumber 等成熟庫,勿自行維護跨國正則。isset($cache[$prefix]) 替代 in_array(),時間複雜度從 O(n) 降為 O(1)。PHP 手機號驗證的核心不在於寫一個「完美正則」,而在於建立可維護的驗證體系:基礎正則攔截格式錯誤 → 白名單精準過濾號段 → 短信驗證確認真實性。將號段白名單外部化(配置檔、資料表、遠端 API),才能應對運營商頻繁變更的號段策略,實現長期穩定的驗證能力。