圖形驗證碼(CAPTCHA)是防止機器人惡意提交的經典方案。本文基於 PHP GD 庫,完整示範驗證碼圖片生成(干擾點、干擾線、隨機字元)、Session 儲存驗證碼、前端表單整合與「換一張」無刷新重載功能,程式碼可直接用於專案。
captcha.php<?php
session_start();
// 1. 建立 100x30 真彩色畫布
$image = imagecreatetruecolor(100, 30);
// 2. 白色背景
$bgcolor = imagecolorallocate($image, 255, 255, 255);
imagefill($image, 0, 0, $bgcolor);
// 3. 產生 4 位隨機字元
$captcha_code = "";
$charset = "abcdefghijkmnpqrstuvwxy3456789"; // 排除易混淆字元 o,0,1,l,i,2
for ($i = 0; $i < 4; $i++) {
$fontsize = 6; // 內建字體 1-5,6 為較大
$fontcolor = imagecolorallocate($image, rand(0, 120), rand(0, 120), rand(0, 120)); // 深色系
$char = $charset[rand(0, strlen($charset) - 1)];
$captcha_code .= $char;
// 隨機位置
$x = ($i * 100 / 4) + rand(5, 10);
$y = rand(5, 10);
imagestring($image, $fontsize, $x, $y, $char, $fontcolor);
}
// 4. 儲存至 Session(轉小寫比對不區分大小寫)
$_SESSION["authcode"] = strtolower($captcha_code);
// 5. 干擾點(100 個)
for ($i = 0; $i < 100; $i++) {
$pointcolor = imagecolorallocate($image, rand(50, 200), rand(50, 200), rand(50, 200));
imagesetpixel($image, rand(1, 99), rand(1, 29), $pointcolor);
}
// 6. 干擾線(2 條)
for ($i = 0; $i < 2; $i++) {
$linecolor = imagecolorallocate($image, rand(80, 220), rand(80, 220), rand(80, 220));
imageline($image, rand(1, 99), rand(1, 29), rand(1, 99), rand(1, 29), $linecolor);
}
// 7. 輸出 PNG
header("Content-Type: image/png");
imagepng($image);
imagedestroy($image);
?>
o,0,1,l,i,2 等易混淆字元$_SESSION['authcode'],驗證時比對imagedestroy() 防止記憶體洩漏form.php<?php
session_start();
if (isset($_POST["authcode"])) {
$input = strtolower(trim($_POST["authcode"]));
$stored = $_SESSION["authcode"] ?? '';
if ($input === $stored) {
echo "OK - 驗證通過";
// 清除驗證碼防重放
unset($_SESSION["authcode"]);
} else {
echo "NO - 驗證碼錯誤";
}
exit;
}
?>
<!doctype html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>驗證碼測試</title>
<style>
.captcha-img { border: 1px solid #ccc; vertical-align: middle; cursor: pointer; }
.refresh-link { margin-left: 10px; vertical-align: middle; }
</style>
</head>
<body>
<form action="form.php" method="post">
<p>
驗證碼圖片:
<img id="captchaImg" class="captcha-img" src="captcha.php?r=<?php echo rand(); ?>" alt="驗證碼">
<a href="javascript:void(0)" class="refresh-link" id="refreshCaptcha">換一張</a>
</p>
<p><input type="text" name="authcode" placeholder="請輸入驗證碼" autocomplete="off"></p>
<p><input type="submit" value="提交"></p>
</form>
<script>
document.getElementById('refreshCaptcha').onclick = function() {
document.getElementById('captchaImg').src = 'captcha.php?r=' + Math.random();
};
// 點擊圖片也可重載
document.getElementById('captchaImg').onclick = function() {
this.src = 'captcha.php?r=' + Math.random();
};
</script>
</body>
</html>
?r=... 破除瀏覽器快取,確保每次請求新圖片strtolower() 比對,提升用戶體驗imagettftext() + 自訂字體檔,字體更豐富、更難被 OCR 識別imageaffine() 仿射變換,增加機器識別難度| 現象 | 原因 | 解決 |
|---|---|---|
| 圖片顯示破圖 | GD 未安裝/啟用 | php -m | grep gd,安裝 php-gd |
| Session 失效 | session_start() 位置錯誤 | 確保輸出前調用,無 BOM、無空白輸出 |
| 驗證總是失敗 | 大小寫/空白差異 | 雙方統一 strtolower(trim()) |
| 中文亂碼 | 字體不支援中文 | 使用支援中文的 TTF 字體 |
PHP GD 庫提供了完整的圖形繪製能力,結合 Session 機制即可實作基礎驗證碼。本文範例涵蓋生成、驗證、前端整合全流程,並提供進階優化方向。實務中建議根據業務風險等級選擇:低風險用簡單 GD 驗證碼,中高風險接入成熟第三方服務,兼顧安全與用戶體驗。