
本文介绍一种不依赖第三方服务(如 recaptcha)的纯 php 本地验证码机制,通过会话验证与表单提交拦截,强制用户完成验证码后才能访问目标页面,并附带防自动化的时间验证建议。
本文介绍一种不依赖第三方服务(如 recaptcha)的纯 php 本地验证码机制,通过会话验证与表单提交拦截,强制用户完成验证码后才能访问目标页面,并附带防自动化的时间验证建议。
要实现“用户必须通过验证码才能加载某页面”的功能,核心思路是:将目标页面设为受保护资源,访问时先重定向至验证码验证页;验证成功后,通过会话(session)标记授权状态,再放行访问。整个流程完全基于 PHP 原生能力,无需外部 API 或网络请求。
✅ 基础实现步骤
-
生成验证码图像与会话存储
使用gd扩展动态生成简单文字验证码(如 4 位随机字母+数字),同时将正确答案存入$_SESSION['captcha_answer'],并设置合理的过期时间(例如 5 分钟):
// captcha.php
session_start();
$_SESSION['captcha_answer'] = $code = substr(str_shuffle('ABCDEFGHJKLMNPQRSTUVWXYZ23456789'), 0, 4);
header('Content-Type: image/png');
$im = imagecreatetruecolor(120, 40);
$bg = imagecolorallocate($im, 255, 255, 255);
imagefilledrectangle($im, 0, 0, 120, 40, $bg);
$text_color = imagecolorallocate($im, 64, 64, 64);
imagestring($im, 5, 30, 12, $code, $text_color);
imagepng($im);
imagedestroy($im);-
验证码验证页(verify.php)
包含表单提交、服务端校验、时间戳防护(防脚本快速重放):
// verify.php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user_input = trim($_POST['captcha'] ?? '');
$start_time = $_SESSION['captcha_start_time'] ?? 0;
// ⚠️ 防御:要求用户至少停留 2 秒才允许提交(防止自动化秒填)
if (time() - $start_time < 2) {
die('操作过快,请人工参与。');
}
if (isset($_SESSION['captcha_answer']) &&
strtolower($user_input) === strtolower($_SESSION['captcha_answer'])) {
$_SESSION['captcha_verified'] = true;
$_SESSION['verified_at'] = time();
header('Location: protected_page.php');
exit;
} else {
$error = '验证码错误,请重试。';
}
}
$_SESSION['captcha_start_time'] = time(); // 记录访问时间<!-- verify.php 表单部分 --> <form method="post"> <img src="captcha.php?<?php echo time(); ? alt="如何在 PHP 中实现本地化验证码页面访问控制" >" alt="验证码" onclick="this.src='captcha.php?'+Date.now()"> <input type="text" name="captcha" placeholder="请输入验证码" required> <button type="submit">提交</button> <?php if (isset($error)) echo "<p style='color:red'>$error</p>"; ?> </form>
-
受保护页面入口控制(protected_page.php)
所有需保护的页面顶部统一加入权限检查逻辑:
// protected_page.php
session_start();
if (!($_SESSION['captcha_verified'] ?? false) ||
($_SESSION['verified_at'] ?? 0) < time() - 1800) { // 30 分钟有效期
header('Location: verify.php');
exit;
}
// ✅ 此处开始输出真实页面内容
echo "<h1>欢迎访问受保护页面!</h1>";
echo "<p>您已通过人工验证,当前会话有效。</p>";⚠️ 注意事项与增强建议
-
安全性补充:
- 启用
session_regenerate_id(true)在验证成功后刷新 session ID,防止会话固定攻击; - 对
captcha.php添加header('Cache-Control: no-store, no-cache, must-revalidate');避免浏览器缓存验证码图片; - 生产环境建议结合 IP 限流(如每 IP 每小时最多 5 次验证尝试)。
- 启用
-
可用性优化:
立即学习“PHP免费学习笔记(深入)”;
- 提供“换一张”按钮(通过 JS 刷新图片
src并更新时间戳参数); - 支持语音验证码或无障碍文本描述(对视障用户友好);
- 可扩展为“链接级保护”——如提问者所述,动态生成带唯一 token 的保护链接(
/protect?token=abc123),后台映射到真实 URL 并绑定验证状态。
- 提供“换一张”按钮(通过 JS 刷新图片
不推荐仅靠前端或纯 JS 方案:
验证逻辑必须在服务端完成,任何前端隐藏字段、JS 计时器均可被绕过,time()校验也必须依赖服务端$_SESSION时间戳,而非客户端Date.now()。
该方案轻量、可控、无外链依赖,适用于中小型网站或内部系统的关键页面访问控制场景。如需更高安全等级(如对抗 OCR 或高级爬虫),可叠加行为分析(鼠标轨迹、点击延迟)或升级为数学题/逻辑题等语义型验证码。



















