PHP 內建的 **Ctype 擴展** 提供一組極快的字符串字元類型檢測函數,底層調用 C 標準庫 `
| 函數 | 檢測內容 | 等價字元類別 | 典型用途 |
|---|---|---|---|
ctype_alnum | 字母數字 | `[A-Za-z0-9]` | 用戶名、編號、Token 驗證 |
ctype_alpha | 純字母 | `[A-Za-z]` | 姓名、純文字欄位 |
ctype_cntrl | 控制字元 | `\n\r\t\0\x0B` 等非打印控制碼 | 檢測二進制數據混入、異常輸入 |
ctype_digit | 純數字 | `[0-9]` | **ID、年齡、數量、純數字驗證首選** |
ctype_graph | 可打印非空白 | `[^\s]` (含標點符號) | 密碼強度檢測 (必須含可見字元) |
ctype_lower | 全小寫字母 | `[a-z]` | 強制小寫字段 (如 slug) |
ctype_print | 可打印含空白 | `[\s\S]` 但排除控制字元 | 文本內容安全過濾 |
ctype_punct | 標點符號 | `[^\w\s]` (非字母數字下劃線空白) | 特殊符號驗證 |
ctype_space | 空白字元 | `\s` (空格、Tab、換行等) | 檢測全空白輸入 |
ctype_upper | 全大寫字母 | `[A-Z]` | 代碼、縮寫驗證 |
ctype_xdigit | 十六進制 | `[0-9A-Fa-f]` | 顏色值、Hash、MAC 地址驗證 |
<?php
// 1. 基礎用法
$username = 'JohnDoe123';
if (ctype_alnum($username)) {
echo "用戶名合法";
}
// 2. 關鍵陷阱:整數傳入會返回 false (因被當作 ASCII 碼值處理)
$id = 12345;
var_dump(ctype_digit($id)); // false (檢測字元碼 12345)
var_dump(ctype_digit((string)$id)); // true **必須強制轉字符串**
// 3. 空字符串行為 (PHP 5.1+ 統一返回 false)
var_dump(ctype_alnum('')); // false
// 4. 組合驗證:密碼必須含字母+數字+標點 (8-20位)
function strongPassword(string $pwd): bool {
if (strlen($pwd) < 8 || strlen($pwd) > 20) return false;
$hasAlpha = false; $hasDigit = false; $hasPunct = false;
for ($i = 0; $i < strlen($pwd); $i++) {
$ch = $pwd[$i];
if (ctype_alpha($ch)) $hasAlpha = true;
elseif (ctype_digit($ch)) $hasDigit = true;
elseif (ctype_punct($ch)) $hasPunct = true;
}
return $hasAlpha && $hasDigit && $hasPunct;
}
?>
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 純數字 ID/年齡/數量 | ctype_digit((string)$val) | **最快**,無正則編譯,語義明確 |
| 純字母/字母數字 | ctype_alpha/alnum | 同左 |
| Email/URL/IP 驗證 | filter_var($val, FILTER_VALIDATE_EMAIL/URL/IP) | 內建標準驗證,支援複雜規範 |
| 複雜格式 (身份證、手機號、郵編) | preg_match | 正則表達力不可替代 |
| 整數/浮點數/布林類型判斷 | is_int/is_float/is_bool | 變量類型檢測,非字符串內容檢測 |
| 多字節字符 (中文、日文、Emoji) | 禁用 Ctype,用 `preg_match('/^\p{Han}+$/u', $str)` 或 `mb_check_encoding` | Ctype **僅支援單字節 ASCII**,多字節會逐字節檢測導致誤判 |
<?php
$str = str_repeat('a', 1000) . '1'; // 1001 字元
$iter = 100000;
$t = microtime(true);
for ($i=0;$i<$iter;$i++) ctype_alpha($str);
echo "ctype_alpha: " . (microtime(true)-$t) . "s\n"; // ~0.04s
$t = microtime(true);
for ($i=0;$i<$iter;$i++) preg_match('/^[a-zA-Z]+$/', $str);
echo "preg_match: " . (microtime(true)-$t) . "s\n"; // ~0.18s (慢 4-5 倍)
$t = microtime(true);
for ($i=0;$i<$iter;$i++) is_string($str) && !preg_match('/[^a-zA-Z]/', $str);
echo "is_string+preg: " . (microtime(true)-$t) . "s\n";
?>
**結論:單字節字元類別檢測,Ctype 完勝正則 3-5 倍效能。**
<?php
class StringValidator
{
public static function alnum(string $str): bool { return $str !== '' && ctype_alnum($str); }
public static function alpha(string $str): bool { return $str !== '' && ctype_alpha($str); }
public static function digit(string $str): bool { return $str !== '' && ctype_digit($str); }
public static function xdigit(string $str): bool { return $str !== '' && ctype_xdigit($str); }
// 組合規則
public static function username(string $str): bool {
return self::alnum($str) && strlen($str) >= 4 && strlen($str) <= 20;
}
public static function hexColor(string $str): bool {
return (strlen($str) === 6 || strlen($str) === 3) && self::xdigit($str);
}
}
// 使用
if (StringValidator::digit($_POST['age'] ?? '')) { /* ... */ }
if (StringValidator::hexColor($_POST['color'] ?? '')) { /* ... */ }
?>
善用 Ctype,讓輸入驗證又快又穩。