<?php
/**
* 表單驗證類別
* 方法回傳:true 通過,false 失敗
*/
class FormValidator {
public static string $error = '';
/**
* 中文字串驗證 (僅允許中文字元)
* @param string $str 待驗證字串
* @param int $min 最小長度
* @param int $max 最大長度 (0 表不限制)
* @return bool
*/
public function checkChinese(string $str, int $min, int $max = 0): bool {
$max = $max ?: $min; // 若 max=0 則固定長度 = min
$pattern = '/^[\x{4e00}-\x{9fa5}]{' . $min . ',' . $max . '}$/u';
$result = (bool)preg_match($pattern, $str);
if (!$result) self::$error = "中文長度需在 $min-$max 字之間";
return $result;
}
/**
* Email 格式驗證
* @param string $email
* @return bool
*/
public function checkEmail(string $email): bool {
// RFC 5322 簡化版,實務建議使用 filter_var($email, FILTER_VALIDATE_EMAIL)
$pattern = '/^[\w\-\.]+@[\w\-]+(\.[\w\-]+)+$/';
$result = (bool)preg_match($pattern, $email);
if (!$result) self::$error = 'Email 格式不正確';
return $result;
}
/**
* 台灣手機號碼驗證 (09xxxxxxxx)
* @param string $mobile
* @return bool
*/
public function checkMobileTW(string $mobile): bool {
$pattern = '/^09\d{8}$/';
$result = (bool)preg_match($pattern, $mobile);
if (!$result) self::$error = '手機格式應為 09xxxxxxxx';
return $result;
}
/**
* 大陸手機號碼驗證 (1[3-9]xxxxxxxx)
* @param string $mobile
* @return bool
*/
public function checkMobileCN(string $mobile): bool {
$pattern = '/^1[3-9]\d{9}$/';
$result = (bool)preg_match($pattern, $mobile);
if (!$result) self::$error = '手機格式應為 1[3-9]xxxxxxxxx';
return $result;
}
/**
* QQ 號碼驗證 (5-11 位數字,首位非 0)
* @param string $qq
* @return bool
*/
public function checkQQ(string $qq): bool {
$pattern = '/^[1-9]\d{4,10}$/';
$result = (bool)preg_match($pattern, $qq);
if (!$result) self::$error = 'QQ 號碼格式不正確';
return $result;
}
/**
* 身分證字號驗證 (台灣:1 英文字母 + 9 數字)
* @param string $id
* @return bool
*/
public function checkIdCardTW(string $id): bool {
// 格式檢查
if (!preg_match('/^[A-Z][12]\d{8}$/i', $id)) {
self::$error = '身分證格式:1 英文字母 + 9 位數字';
return false;
}
// 檢查碼驗證演算法
$letters = 'ABCDEFGHJKLMNPQRSTUVXYWZIO'; // 實際對應表需查表
$letter = strtoupper($id[0]);
$num = strpos($letters, $letter);
if ($num === false) {
self::$error = '身分證首碼字母無效';
return false;
}
$num += 10;
$sum = (int)($num / 10) + ($num % 10) * 9;
$weights = [8, 7, 6, 5, 4, 3, 2, 1, 1];
for ($i = 0; $i < 9; $i++) {
$sum += (int)$id[$i + 1] * $weights[$i];
}
if ($sum % 10 !== 0) {
self::$error = '身分證檢查碼錯誤';
return false;
}
return true;
}
/**
* 大陸身分證 (18 位數字 或 17 位數字 + X/x)
* @param string $id
* @return bool
*/
public function checkIdCardCN(string $id): bool {
$pattern = '/^\d{17}[\dXx]$/';
$result = (bool)preg_match($pattern, $id);
if (!$result) self::$error = '身分證格式:18 位數字或 17 位數字+X';
return $result; // 簡化版,未實作校驗碼演算法
}
/**
* 通用帳號格式:字母/數字/底線,首字不為數字,長度限制
* @param string $str
* @param int $min
* @param int $max
* @return bool
*/
public function checkUsername(string $str, int $min, int $max): bool {
$pattern = '/^[a-zA-Z_]\w{' . ($min - 1) . ',' . ($max - 1) . '}$/';
$result = (bool)preg_match($pattern, $str);
if (!$result) self::$error = "帳號長度 $min-$max 位,首字需為字母或底線";
return $result;
}
/**
* 密碼強度驗證:至少含大小寫、數字、特殊符號,長度 8-20
* @param string $pwd
* @return bool
*/
public function checkPasswordStrong(string $pwd): bool {
$checks = [
'/[a-z]/' => '需含小寫字母',
'/[A-Z]/' => '需含大寫字母',
'/\d/' => '需含數字',
'/[\W_]/' => '需含特殊符號',
'/^.{8,20}$/' => '長度需 8-20 位',
];
foreach ($checks as $pattern => $msg) {
if (!preg_match($pattern, $pwd)) {
self::$error = $msg;
return false;
}
}
return true;
}
/**
* 通用正則驗證
* @param string $str
* @param string $pattern 正則模式 (含分隔符)
* @param string $errorMsg 失敗訊息
* @return bool
*/
public function checkRegex(string $str, string $pattern, string $errorMsg = '格式不符合'): bool {
$result = (bool)preg_match($pattern, $str);
if (!$result) self::$error = $errorMsg;
return $result;
}
}
<?php
require_once 'FormValidator.php';
$validator = new FormValidator();
$_POST = [
'username' => 'john_doe',
'password' => 'Pass123!',
'email' => 'john@example.com',
'mobile' => '0912345678',
'realname' => '張三',
'idcard' => 'A123456789',
];
$rules = [
'username' => fn() => $validator->checkUsername($_POST['username'], 4, 16),
'password' => fn() => $validator->checkPasswordStrong($_POST['password']),
'email' => fn() => $validator->checkEmail($_POST['email']),
'mobile' => fn() => $validator->checkMobileTW($_POST['mobile']),
'realname' => fn() => $validator->checkChinese($_POST['realname'], 2, 10),
'idcard' => fn() => $validator->checkIdCardTW($_POST['idcard']),
];
$errors = [];
foreach ($rules as $field => $check) {
if (!$check()) {
$errors[$field] = FormValidator::$error;
}
}
if ($errors) {
// 回傳錯誤給前端
echo json_encode(['success' => false, 'errors' => $errors]);
} else {
echo json_encode(['success' => true, 'message' => '驗證通過']);
}
?>
| 驗證項目 | 正則 | 說明 |
|---|---|---|
| 中文 | /^[\x{4e00}-\x{9fa5}]{min,max}$/u | Unicode 範圍 \x{4e00}-\x{9fa5} 涵蓋常用漢字,u 修飾符啟用 UTF-8 模式 |
/^[\w\-\.]+@[\w\-]+(\.[\w\-]+)+$/ | 簡化版;生產環境建議 filter_var($email, FILTER_VALIDATE_EMAIL) | |
| 台灣手機 | /^09\d{8}$/ | 09 開頭共 10 碼 |
| 大陸手機 | /^1[3-9]\d{9}$/ | 1[3-9] 開頭共 11 碼 |
/^[1-9]\d{4,10}$/ | 5-11 位,首位非 0 | |
| 台灣身分證 | /^[A-Z][12]\d{8}$/i | 首字母,次碼 1/2 (性別),共 10 碼;需額外檢查碼演算法 |
| 大陸身分證 | /^\d{17}[\dXx]$/ | 18 位,最後一位可能為 X |
| 帳號 | /^[a-zA-Z_]\w{min-1,max-1}$/ | 首字母或底線,其後字母數字底線 |
| 強密碼 | 多條件檢查 | 大小寫、數字、特殊符號、長度 8-20 |
filter_var($val, FILTER_VALIDATE_*)。interface ValidationRule {
public function validate(string $value): bool;
public function getError(): string;
}
class ChineseLengthRule implements ValidationRule {
private int $min, $max; private string $error = '';
public function __construct(int $min, int $max) { $this->min=$min; $this->max=$max; }
public function validate(string $v): bool {
$ok = (bool)preg_match('/^[\x{4e00}-\x{9fa5}]{'.$this->min.','.$this->max.'}$/u', $v);
if (!$ok) $this->error = "長度需 {$this->min}-{$this->max} 字";
return $ok;
}
public function getError(): string { return $this->error; }
}
// 使用
$validator = new class {
public function validate(array $data, array $rules): array {
$errors = [];
foreach ($rules as $field => $rule) {
if (!$rule->validate($data[$field] ?? '')) {
$errors[$field] = $rule->getError();
}
}
return $errors;
}
};
$errors = $validator->validate($_POST, [
'realname' => new ChineseLengthRule(2, 10),
'username' => new RegexRule('/^[a-zA-Z_]\w{3,15}$/', '帳號格式錯誤'),
]);
此驗證類別涵蓋華語圈最常見表單欄位,程式碼結構清晰,易於擴充自定義規則與整合現代框架驗證元件。