^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9_-]+\.[a-z0-9_-]+.*$ —— 僅驗證用戶名,域名部分極其寬鬆,user@126,com 也能通過。^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$ —— 修正域名結構,但未轉義點號 .,仍匹配逗號。^[_.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$ —— 限制頂級域 2-3 字符,但點號仍未轉義。^[_.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4}$ —— 轉義點號,支援 4 字符頂級域(如 .info)。$email = 'test@example.com';
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo '格式合法';
} else {
echo '格式非法';
}
優點:C 級實現、支援 IPv6 域名、國際化郵箱、自動處理邊界情況。缺點:不支援某些極其罕見的 RFC 合法地址(如帶註釋、引號字符串)。
function isValidEmailStrict(string $email): bool {
// 簡化版 RFC 5322,實際生產建議使用 egulias/email-validator 庫
$pattern = '/^
[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+ # local part
@
[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? # domain label
(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$ # more labels
/x';
return (bool)preg_match($pattern, $email);
}
| 層級 | 方法 | 用途 |
|---|---|---|
| 語法檢查 | filter_var / 正則 | 註冊表單即時驗證 |
| 域名 MX 記錄 | checkdnsrr($domain, 'MX') | 過濾明顯虛假域名 |
| SMTP 驗證 | 連接郵件服務器 RCPT TO | 高價值業務(需異步、緩存、限流) |
| 發送驗證碼 | 實際投遞郵件 | 最終確認擁有權,業界標準做法 |
function validateEmail(string $email, bool $checkMx = false): array {
// 1. 基礎格式
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return ['valid' => false, 'reason' => '格式不合法'];
}
// 2. 可選 MX 記錄檢查
if ($checkMx) {
$domain = substr(strrchr($email, '@'), 1);
if (!checkdnsrr($domain, 'MX')) {
return ['valid' => false, 'reason' => '域名無 MX 記錄'];
}
}
return ['valid' => true];
}
// 使用
$result = validateEmail($_POST['email'], true);
if (!$result['valid']) {
exit(json_encode(['code' => 400, 'msg' => $result['reason']]));
}
// 發送驗證碼郵件...
filter_var 覆蓋 99.9% 場景。eregi:PHP 7.0 已移除,統一用 preg_match(PCRE)。idn_to_ascii 轉換後再驗證。<input type="email"> 瀏覽器驗證規則與 PHP 不完全一致,後端必須再驗證一次。