為什麼不用正則?
- 正則複雜、難維護、易有邊界漏洞(如 Unicode、IDN、IPv6)。
- PHP 內建
filter_var() 經過 C 層優化、符合 RFC 標準、效能更好。
三大驗證一鍵搞定
// 1. Email
$email = 'user@example.com';
var_dump(filter_var($email, FILTER_VALIDATE_EMAIL)); // string(17) "user@example.com" 或 false
// 2. URL
$url = 'https://www.example.com/path?query=1#hash';
var_dump(filter_var($url, FILTER_VALIDATE_URL)); // 通過
var_dump(filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_HOST_REQUIRED)); // 需有主機名
var_dump(filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED)); // 需有 scheme
// 3. IP (IPv4 / IPv6)
$ipv4 = '192.168.1.1';
$ipv6 = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
var_dump(filter_var($ipv4, FILTER_VALIDATE_IP)); // IPv4 通過
var_dump(filter_var($ipv6, FILTER_VALIDATE_IP)); // IPv6 通過
var_dump(filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)); // 強制 IPv4
var_dump(filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); // 強制 IPv6
var_dump(filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)); // 排除私有 IP
var_dump(filter_var($ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)); // 排除保留 IP
進階:清理與轉換過濾器
| 過濾器 | 用途 | 旗標範例 |
FILTER_SANITIZE_EMAIL | 移除非法字元,保留合法 Email 字元 | - |
FILTER_SANITIZE_URL | 移除非法 URL 字元 | - |
FILTER_SANITIZE_STRING | 移除標籤、編碼特殊字元(PHP 8.1 棄用) | FILTER_FLAG_NO_ENCODE_QUOTES |
FILTER_SANITIZE_FULL_SPECIAL_CHARS | HTML 編碼 <>&\"'(PHP 8.1+ 推薦) | - |
FILTER_CALLBACK | 自訂 callback 函數 | 自行實作 |
整合驗證函數庫
class Validator {
public static function email(string $v): bool {
return (bool)filter_var($v, FILTER_VALIDATE_EMAIL);
}
public static function url(string $v, bool $requireHost = true): bool {
$flags = $requireHost ? FILTER_FLAG_HOST_REQUIRED : 0;
return (bool)filter_var($v, FILTER_VALIDATE_URL, $flags);
}
public static function ip(string $v, bool $allowPrivate = true, bool $ipv6 = true): bool {
$flags = 0;
if (!$allowPrivate) $flags |= FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
if (!$ipv6) $flags |= FILTER_FLAG_IPV4;
return (bool)filter_var($v, FILTER_VALIDATE_IP, $flags);
}
public static function int(string $v, int $min = null, int $max = null): bool {
$opts = ['options' => ['min_range' => $min, 'max_range' => $max]];
return filter_var($v, FILTER_VALIDATE_INT, $opts) !== false;
}
public static function float(string $v, float $min = null, float $max = null): bool {
$opts = ['options' => ['min_range' => $min, 'max_range' => $max]];
return filter_var($v, FILTER_VALIDATE_FLOAT, $opts) !== false;
}
}
// 使用
if (!Validator::email($_POST['email'])) throw new Exception('Email 格式錯誤');
if (!Validator::url($_POST['website'])) throw new Exception('網址格式錯誤');
if (!Validator::ip($_POST['client_ip'], allowPrivate: false)) throw new Exception('不允許私有 IP');
常見誤區
- filter_var 回傳值:驗證通過回傳「過濾後的值」(非單純 true),失敗回傳
false。務必用 === false 或 (bool) 判斷。
- Email 驗證嚴格度:
FILTER_VALIDATE_EMAIL 允許 user@localhost 等非公網域名,嚴格場景需搭配 DNS MX 紀錄查詢。
- URL 必須含 Scheme:預設需
https:// 或 https://,純 example.com 會失敗。