首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 正則驗證 Email 地址完整實作 (RFC 5322 相容)

     編輯:PHP 綜合知識

驗證策略

採用分層驗證:長度檢查 → 格式正則 → 字元合法性 → DNS MX/A 記錄驗證。比單純正則更精準,避免誤攔合法地址 (如 user+tag@example.com、"quoted@string"@example.com)。

完整驗證函式

<?php
function validateEmail($email) {
    $isValid = true;
    
    // 1. 基礎結構檢查:必須包含 @ 且不在首尾
    $atIndex = strrpos($email, "@");
    if ($atIndex === false || $atIndex === 0 || $atIndex === strlen($email) - 1) {
        return false;
    }
    
    $domain = substr($email, $atIndex + 1);
    $local = substr($email, 0, $atIndex);
    $localLen = strlen($local);
    $domainLen = strlen($domain);
    
    // 2. 長度限制 (RFC 5321)
    if ($localLen < 1 || $localLen > 64) return false;      // Local-part 最長 64 字元
    if ($domainLen < 1 || $domainLen > 255) return false;   // Domain 最長 255 字元
    
    // 3. Local-part 開頭結尾不得為點號
    if ($local[0] === '.' || $local[$localLen - 1] === '.') return false;
    
    // 4. Local-part 不得有連續雙點
    if (strpos($local, '..') !== false) return false;
    
    // 5. Domain 字元合法性:字母、數字、連字號、點號
    if (!preg_match('/^[A-Za-z0-9\-\.]+$/', $domain)) return false;
    
    // 6. Domain 不得有連續雙點
    if (strpos($domain, '..') !== false) return false;
    
    // 7. Local-part 字元合法性 (非引號情況)
    // 允許:字母數字 ! # % & ` _ = / $ ' * + ? ^ { | } ~ . -
    $localUnquotedPattern = '/^(\\\.|[A-Za-z0-9!#%&`_=\/\$\'*+\?^{}|~.-])+$/';
    if (!preg_match($localUnquotedPattern, str_replace("\\\\", "", $local))) {
        // 8. 若不符合非引號規則,檢查是否為合法引號字串
        // 引號字串允許任意字元 (含空格、@、點號),但需雙引號包裹且內部引號需跳脫
        $quotedPattern = '/^"(\\\\"|[^"])+"$/';
        if (!preg_match($quotedPattern, str_replace("\\\\", "", $local))) {
            return false;
        }
    }
    
    // 9. DNS 驗證:域名必須存在 MX 或 A 記錄
    if (!checkdnsrr($domain, "MX") && !checkdnsrr($domain, "A")) {
        return false;
    }
    
    return true;
}

測試案例

Email預期說明
user@example.com✅ 通過標準格式
user.name@sub.domain.com✅ 通過子域名、點號
user+tag@example.com✅ 通過Plus addressing (Gmail 等支援)
"quoted string"@example.com✅ 通過引號字串含空格
"escaped\\"quote"@example.com✅ 通過引號內跳脫引號
user@[IPv6:2001:db8::1]❌ 失敗IP 字面形式未支援 (需擴展)
user@.com❌ 失敗域名以點號開頭
.user@example.com❌ 失敗Local-part 以點號開頭
user..name@example.com❌ 失敗連續雙點
user@nonexistentdomain.xyz❌ 失敗DNS 無記錄

現代替代方案

PHP 8.0+ 內建過濾器 (效能最佳)

function validateEmailModern($email) {
    // 1. 格式驗證
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
    
    // 2. DNS 驗證 (可選,增加延遲)
    $domain = substr(strrchr($email, "@"), 1);
    return checkdnsrr($domain, "MX") || checkdnsrr($domain, "A");
}

Symfony Validator / Laravel Validation (框架專案首選)

// Laravel
$request->validate(['email' => 'required|email|dns']);

// Symfony
use Symfony\Component\Validator\Constraints\Email;
$constraint = new Email(['mode' => 'strict', 'checkMX' => true]);

第三方庫:egulias/EmailValidator (最嚴格 RFC 相容)

composer require egulias/email-validator
use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\RFCValidation;
use Egulias\EmailValidator\Validation\DNSCheckValidation;

$validator = new EmailValidator();
$validator->isValid('user@example.com', new RFCValidation());       // 格式
$validator->isValid('user@example.com', new DNSCheckValidation());  // DNS

效能考量

  • checkdnsrr 會產生網路延遲 (通常 50-500ms),高頻呼叫建議:
  • 快取 DNS 結果 (Redis TTL 1 小時)
  • 僅在註冊/修改信箱時執行,登入驗證僅做格式檢查
  • 異步佇列處理 DNS 驗證,不阻塞用戶回應

常見誤區

  1. 過度簡化正則:/^.+@.+\..+$/ 會通過 a@b.c 但擋掉合法的 user+tag@example.com
  2. 過度複雜正則:幾百字元的「完美正則」難以維護、效能差、仍無法涵蓋所有邊界
  3. 忽略 DNS 驗證:格式合法 ≠ 域名存在,垃圾郵件常用隨機域名
  4. 信任前端驗證:瀏覽器 type="email" 易繞過,後端必須再驗證

建議採用「內建過濾器 + 可選 DNS 快取」的組合,兼顧效能、正確性與維護性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved