<?php
header('Content-Type: image/png');
// 1. 創建畫布
$width = 120;
$height = 40;
$image = imagecreatetruecolor($width, $height);
// 2. 背景色(淺色系)
$bgColor = imagecolorallocate($image, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
imagefill($image, 0, 0, $bgColor);
// 3. 字符池(去除易混淆字符:0/O, 1/I/l, 8/B 等)
$chars = '23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';
$charLen = strlen($chars);
$code = '';
$codeLen = 4;
// 4. 繪製驗證碼字符
for ($i = 0; $i < $codeLen; $i++) {
$char = $chars[mt_rand(0, $charLen - 1)];
$code .= $char;
$fontSize = mt_rand(18, 24);
$x = 10 + $i * 25 + mt_rand(-3, 3);
$y = mt_rand(25, 32);
$angle = mt_rand(-20, 20);
$color = imagecolorallocate($image, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
// 使用 TTF 字體需確認服務器字體路徑
// imagettftext($image, $fontSize, $angle, $x, $y, $color, $fontPath, $char);
// 內置字體備選
imagestring($image, 5, $x, $y, $char, $color);
}
// 5. 存入 Session 驗證
session_start();
$_SESSION['captcha_code'] = strtolower($code); // 不區分大小寫
// 6. 干擾點(噪點)
for ($i = 0; $i < 80; $i++) {
$color = imagecolorallocate($image, mt_rand(150, 255), mt_rand(150, 255), mt_rand(150, 255));
imagesetpixel($image, mt_rand(0, $width), mt_rand(0, $height), $color);
}
// 7. 干擾線
for ($i = 0; $i < 4; $i++) {
$color = imagecolorallocate($image, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
imageline($image,
mt_rand(0, $width/2), mt_rand(0, $height),
mt_rand($width/2, $width), mt_rand(0, $height),
$color
);
}
// 8. 輸出並銷毀
imagepng($image);
imagedestroy($image);
<img id="captcha" src="captcha.php" alt="點擊刷新" style="cursor:pointer;vertical-align:middle">
<input type="text" name="captcha" placeholder="輸入驗證碼">
<script>
document.getElementById('captcha').onclick = function() {
this.src = 'captcha.php?' + Date.now(); // 防緩存
};
</script>
session_start();
if (strtolower($_POST['captcha']) !== ($_SESSION['captcha_code'] ?? '')) {
exit('驗證碼錯誤');
}
// 通過後繼續業務邏輯
unset($_SESSION['captcha_code']); // 一次性使用
| 方向 | 建議 |
|---|---|
| 字體渲染 | 使用 imagettftext + TTF 字體(如 DejaVuSans),效果遠優於內置字體 |
| 安全性 | 字符池去除易混淆字符;驗證碼存入 Redis 並設置 5 分鐘過期 |
| 用戶體驗 | 增加語音驗證碼選項;失敗後不刷新頁面自動換圖 |
| 性能 | 高併發場景預生成驗證碼圖片池,或使用無 Session 的 JWT 簽名驗證碼 |
| 無障礙 | 提供語音播報按鈕,符合 WCAG 2.1 AA 級標準 |
生產環境建議直接使用成熟庫:mewebstudio/captcha (Laravel)、Gregwar/Captcha (通用),避免重複造輪子。