核心原理
- 生成隨機字串 → 存入
$_SESSION['captcha']
- GD 庫繪製干擾線、噪點、字元 → 輸出 PNG 圖片
- 登入時比對
$_POST['captcha'] 與 Session 值
驗證碼生成器 captcha.php
<?php
session_start();
if (isset($_GET['act']) && $_GET['act'] === 'init') {
header('Content-Type: image/png');
$code = strval(rand(1000, 9999)); // 4位數字
$_SESSION['captcha_code'] = $code;
$img = imagecreate(80, 30);
$bg = imagecolorallocate($img, 255, 255, 255);
$fg = imagecolorallocate($img, 0, 0, 0);
$noise = imagecolorallocate($img, 180, 180, 180);
// 干擾線
for ($i=0; $i<5; $i++) {
imageline($img, rand(0,80), rand(0,30), rand(0,80), rand(0,30), $noise);
}
// 干擾點
for ($i=0; $i<50; $i++) {
imagesetpixel($img, rand(0,80), rand(0,30), $noise);
}
// 繪製字元
imagestring($img, 5, 10, 5, $code, $fg);
imagepng($img);
imagedestroy($img);
exit;
}
?>
前端整合
<form action="login.php" method="POST">
<input type="text" name="captcha" maxlength="4" required />
<img src="captcha.php?act=init" id="captchaImg" style="cursor:pointer" title="點擊刷新" />
<script>
document.getElementById('captchaImg').onclick = function() {
this.src = 'captcha.php?act=init&' + Date.now();
};
</script>
<input type="submit" value="登入" />
</form>
登入驗證 login.php
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = trim($_POST['captcha']);
$stored = $_SESSION['captcha_code'] ?? '';
if (empty($input) || strcasecmp($input, $stored) !== 0) {
die('驗證碼錯誤!');
}
// 驗證通過,繼續帳密檢查...
unset($_SESSION['captcha_code']); // 一次性使用
}
?>
Session vs Cookie 選擇
| 方案 | 優點 | 缺點 |
| Session(推薦) | 伺服端儲存,不易竄改;自動過期 | Session 失效導致驗證失敗 |
| Cookie | 跨 Session 存活 | 客戶端可讀/竄改,安全性極低 |
進階強化建議
- 字元集擴充:英數混合、排除易混淆字元 (0/O, 1/I/l)
- 使用 TTF 字體
imagettftext() 繪製扭曲字元
- 加入語音驗證碼無障礙支援
- 限制同 IP 請求頻率,防暴力刷新
- 考慮成熟庫:
gregwar/captcha、mewebstudio/captcha (Composer 安裝)