captcha/ ├── index.html # 演示頁 ├── captcha.php # 驗證碼圖片生成端點 └── check.php # 驗證端點 (可選)
<?php
// captcha.php
session_start();
// 配置
$width = 100;
$height = 38;
$length = 4; // 字符數
$charset = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz'; // 去除易混淆 0/O/1/I/l
// 建立畫布
$img = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($img, 245, 245, 245); // 淺灰背景
imagefill($img, 0, 0, $bg);
// 干擾線
for ($i = 0; $i < 5; $i++) {
$color = imagecolorallocate($img, mt_rand(150, 200), mt_rand(150, 200), mt_rand(150, 200));
imageline($img, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $color);
}
// 干擾點
for ($i = 0; $i < 50; $i++) {
$color = imagecolorallocate($img, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
imagesetpixel($img, mt_rand(0, $width), mt_rand(0, $height), $color);
}
// 繪製字符
$code = '';
for ($i = 0; $i < $length; $i++) {
$char = $charset[mt_rand(0, strlen($charset) - 1)];
$code .= $char;
$x = 15 + $i * 20 + mt_rand(-2, 2);
$y = mt_rand(6, 14);
$angle = mt_rand(-15, 15);
$color = imagecolorallocate($img, mt_rand(0, 80), mt_rand(0, 80), mt_rand(0, 80));
// 使用 TTF 字體更美觀 (需字體文件)
// imagettftext($img, 20, $angle, $x, $y, $color, __DIR__.'/font.ttf', $char);
// 內置字體 fallback
imagestring($img, 5, $x, $y, $char, $color);
}
$_SESSION['captcha_code'] = strtolower($code); // 不區分大小寫
// 輸出
header('Content-Type: image/png');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
imagepng($img);
imagedestroy($img);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>驗證碼演示</title>
<style>
.captcha-wrap { display: flex; align-items: center; gap: 10px; }
.captcha-img { cursor: pointer; border: 1px solid #ddd; border-radius: 4px; }
.refresh-btn { padding: 6px 12px; background: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
.refresh-btn:hover { background: #0056b3; }
</style>
</head>
<body>
<h3>登入驗證碼</h3>
<div class="captcha-wrap">
<img id="captchaImg" class="captcha-img" src="captcha.php?t== time() ?>" alt="驗證碼" title="點擊刷新">
<button type="button" class="refresh-btn" id="refreshBtn">換一張</button>
</div>
<br><br>
<input type="text" id="captchaInput" placeholder="輸入驗證碼" maxlength="4" style="text-transform:uppercase">
<button onclick="verify()">提交驗證</button>
<p id="msg"></p>
<script>
const img = document.getElementById('captchaImg');
const btn = document.getElementById('refreshBtn');
function refresh() {
// 關鍵:加隨機參數避免瀏覽器緩存
img.src = 'captcha.php?t=' + Date.now() + Math.random();
}
// 點擊圖片或按鈕刷新
img.onclick = refresh;
btn.onclick = refresh;
async function verify() {
const code = document.getElementById('captchaInput').value.trim();
if (!code) return alert('請輸入驗證碼');
const res = await fetch('check.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'code=' + encodeURIComponent(code)
});
const data = await res.json();
document.getElementById('msg').innerHTML = data.ok
? '✅ 驗證通過'
: '❌ ' + data.msg;
if (!data.ok) refresh(); // 失敗自動刷新
}
</script>
</body>
</html>
<?php
// check.php
session_start();
header('Content-Type: application/json');
$input = strtolower(trim($_POST['code'] ?? ''));
$stored = $_SESSION['captcha_code'] ?? '';
if (!$input) {
echo json_encode(['ok' => false, 'msg' => '驗證碼不能為空']);
} elseif ($input === $stored) {
unset($_SESSION['captcha_code']); // 一次性使用
echo json_encode(['ok' => true]);
} else {
echo json_encode(['ok' => false, 'msg' => '驗證碼錯誤']);
}
| 類型 | 生成邏輯 | 適用場景 |
|---|---|---|
| 算術 | $a=rand(1,20); $b=rand(1,20); $op=['+','-'][rand(0,1)]; $q="$a$op$b=?"; $_SESSION['captcha']=$a+$b*-1; | 低安全、趣味 |
| 中文 | 字符集換成常用 500 漢字,TTF 必須支援中文 | 國內用戶友好 |
| 點選 | 生成 4-6 個隨機坐標,前端 Canvas 繪製,用戶按序點擊 | 防機器識別強 |
| 滑塊 | 前端 JS 拼圖邏輯,後端驗證軌跡/時間/誤差 | 高安全、體驗好 |
unset核心三步:GD 繪圖 → Session 存儲 → 前端隨機參數防緩存刷新。本示例 50 行代碼實現完整閉環,可直接集成至登入/註冊/表單提交流程。