本文目录导读:

- 项目结构
- 主页面 (index.php)
- 生成验证码数据 (captcha_data.php)
- 后端验证接口 (verify.php)
- 测试脚本 (test_upload.php)
- 使用说明
- 核心代码说明
- 安全特性
我将为您创建一个完整的PHP滑块验证码模拟系统,这个系统包含前端HTML/CSS/JavaScript和后端PHP验证逻辑。
项目结构
slider-captcha/
├── index.php # 主页面
├── verify.php # 验证接口
├── captcha_data.php # 生成验证码数据
└── style.css # 样式文件(可选,内联也可以)
主页面 (index.php)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">PHP滑块验证码</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
border-radius: 10px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
padding: 20px;
width: 400px;
}
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
font-size: 24px;
}
.captcha-container {
background: #f5f5f5;
border-radius: 8px;
padding: 15px;
margin-bottom: 15px;
}
.captcha-image {
position: relative;
width: 100%;
height: 200px;
border-radius: 5px;
overflow: hidden;
margin-bottom: 15px;
background: #ddd;
}
.captcha-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.slider-container {
position: relative;
width: 100%;
height: 40px;
background: #e0e0e0;
border-radius: 20px;
margin-bottom: 15px;
}
.slider-track {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #e0e0e0;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
color: #666;
font-size: 14px;
}
.slider-btn {
position: absolute;
top: -5px;
left: 0;
width: 50px;
height: 50px;
background: #4CAF50;
border: none;
border-radius: 50%;
cursor: pointer;
color: white;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: background 0.3s;
user-select: none;
}
.slider-btn:hover {
background: #45a049;
}
.slider-btn:active {
cursor: grabbing;
}
.result-message {
text-align: center;
padding: 10px;
border-radius: 5px;
margin-top: 15px;
font-size: 14px;
display: none;
}
.result-message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
display: block;
}
.result-message.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
display: block;
}
.refresh-btn {
width: 100%;
padding: 10px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
margin-top: 10px;
}
.refresh-btn:hover {
background: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<h2>🔒 滑块验证码</h2>
<div class="captcha-container">
<div class="captcha-image" id="captchaImage">
<!-- 图片将在这里显示 -->
</div>
<div class="slider-container">
<div class="slider-track">
<span>← 拖动滑块验证</span>
<span>→</span>
</div>
<button class="slider-btn" id="sliderBtn">→</button>
</div>
<div class="result-message" id="resultMessage"></div>
<button class="refresh-btn" onclick="refreshCaptcha()">刷新验证码</button>
</div>
</div>
<script>
let isDragging = false;
let startX = 0;
let currentX = 0;
let puzzleX = 0; // 拼图当前位置
let targetX = 0; // 目标位置
// 初始化
function initCaptcha() {
// 加载验证码数据
fetch('captcha_data.php')
.then(response => response.json())
.then(data => {
if (data.success) {
// 显示背景图片
const imageContainer = document.getElementById('captchaImage');
imageContainer.innerHTML = '';
// 创建背景图
const img = document.createElement('div');
img.style.width = '100%';
img.style.height = '100%';
img.style.background = `linear-gradient(135deg, #667eea ${Math.random() * 50}%, #764ba2 ${Math.random() * 50}%)`;
img.style.position = 'relative';
// 创建拼图块(模拟缺口)
const puzzle = document.createElement('div');
puzzle.style.position = 'absolute';
puzzle.style.width = '40px';
puzzle.style.height = '40px';
puzzle.style.top = data.puzzle_y + 'px';
puzzle.style.left = data.puzzle_x + 'px';
puzzle.style.border = '2px solid white';
puzzle.style.borderRadius = '5px';
puzzle.style.background = 'rgba(255,255,255,0.5)';
puzzle.style.boxShadow = '0 0 10px rgba(0,0,0,0.3)';
puzzle.style.transition = 'all 0.3s ease';
img.appendChild(puzzle);
imageContainer.appendChild(img);
// 设置目标位置
targetX = data.puzzle_x;
puzzleX = 0;
// 重置滑块
const sliderBtn = document.getElementById('sliderBtn');
sliderBtn.style.left = '0px';
document.getElementById('resultMessage').style.display = 'none';
// 保存数据用于验证
sessionStorage.setItem('captcha_id', data.id);
sessionStorage.setItem('target_x', targetX);
}
});
}
// 拖动事件
const sliderBtn = document.getElementById('sliderBtn');
sliderBtn.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', onDrag);
document.addEventListener('mouseup', endDrag);
// 触摸事件(移动端)
sliderBtn.addEventListener('touchstart', startDrag);
document.addEventListener('touchmove', onDrag);
document.addEventListener('touchend', endDrag);
function startDrag(e) {
if (sessionStorage.getItem('verified') === 'true') return;
isDragging = true;
const event = e.type === 'touchstart' ? e.touches[0] : e;
startX = event.clientX - currentX;
e.preventDefault();
// 重置滑块样式
sliderBtn.style.transition = 'none';
}
function onDrag(e) {
if (!isDragging) return;
const event = e.type === 'touchmove' ? e.touches[0] : e;
const dx = event.clientX - startX;
const maxX = document.querySelector('.slider-container').clientWidth - 50;
currentX = Math.max(0, Math.min(dx, maxX));
sliderBtn.style.left = currentX + 'px';
// 更新拼图位置
const puzzle = document.querySelector('.captcha-image div div');
if (puzzle) {
puzzle.style.left = (targetX - 40 + currentX) + 'px';
}
}
function endDrag() {
if (!isDragging) return;
isDragging = false;
// 检查是否接近目标位置
const tolerance = 20; // 允许的误差范围(像素)
const distance = Math.abs(currentX - targetX);
if (distance <= tolerance) {
// 验证成功
verifyCaptcha(true);
} else {
// 验证失败,重置滑块
resetSlider();
}
}
function resetSlider() {
currentX = 0;
sliderBtn.style.left = '0px';
sliderBtn.style.transition = 'left 0.3s ease';
sliderBtn.style.left = '0px';
const puzzle = document.querySelector('.captcha-image div div');
if (puzzle) {
puzzle.style.left = targetX + 'px';
}
setTimeout(() => {
sliderBtn.style.transition = 'none';
}, 300);
}
function verifyCaptcha(success) {
const resultMessage = document.getElementById('resultMessage');
if (success) {
resultMessage.className = 'result-message success';
resultMessage.innerHTML = '✅ 验证成功,拖动滑块验证通过';
sessionStorage.setItem('verified', 'true');
sliderBtn.style.background = '#4CAF50';
sliderBtn.innerHTML = '✓';
// 可以在这里执行后续操作,比如提交表单等
setTimeout(() => {
// 模拟提交成功
console.log('验证成功,可以继续操作');
}, 1000);
} else {
resultMessage.className = 'result-message error';
resultMessage.innerHTML = '❌ 验证失败,请重试';
sessionStorage.removeItem('verified');
}
}
function refreshCaptcha() {
sessionStorage.removeItem('verified');
sessionStorage.removeItem('captcha_id');
sessionStorage.removeItem('target_x');
currentX = 0;
sliderBtn.style.background = '#4CAF50';
sliderBtn.innerHTML = '→';
sliderBtn.style.left = '0px';
initCaptcha();
}
// 页面加载完成初始化
window.onload = initCaptcha;
</script>
</body>
</html>
生成验证码数据 (captcha_data.php)
<?php
header('Content-Type: application/json');
// 生成随机CSS颜色作为背景
function generateRandomColor() {
$colors = ['#667eea', '#764ba2', '#f093fb', '#4facfe', '#43e97b'];
return $colors[array_rand($colors)];
}
// 生成随机角度
function generateRandomGradient() {
$angle = rand(0, 360);
$color1 = generateRandomColor();
$color2 = generateRandomColor();
$percent = rand(0, 100);
return "linear-gradient($angle, $color1 $percent%, $color2)";
}
// 创建验证码会话
session_start();
// 生成唯一的验证码ID
$captcha_id = uniqid('captcha_', true);
// 图片大小
$image_width = 400;
$image_height = 200;
// 生成拼图位置(x坐标,保证拼图不超出边界)
$puzzle_size = 40;
$max_x = $image_width - $puzzle_size - 10;
$puzzle_x = rand(50, $max_x); // 左边留出50px空间
$puzzle_y = rand(10, $image_height - $puzzle_size - 10);
// 存储验证码数据到session
$_SESSION['captcha'][$captcha_id] = [
'puzzle_x' => $puzzle_x,
'puzzle_y' => $puzzle_y,
'created_at' => time()
];
// 生成成功响应
echo json_encode([
'success' => true,
'id' => $captcha_id,
'puzzle_x' => $puzzle_x,
'puzzle_y' => $puzzle_y,
'background' => generateRandomGradient(),
'image_width' => $image_width,
'image_height' => $image_height,
'puzzle_size' => $puzzle_size
]);
?>
后端验证接口 (verify.php)
<?php
header('Content-Type: application/json');
session_start();
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => '请求方法错误']);
exit;
}
// 获取POST数据
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
// 如果是表单提交,尝试获取POST参数
$data = $_POST;
}
// 验证参数
if (!isset($data['captcha_id']) || !isset($data['current_x']) || !isset($data['target_x'])) {
echo json_encode(['success' => false, 'message' => '缺少必要参数']);
exit;
}
$captcha_id = $data['captcha_id'];
$current_x = floatval($data['current_x']);
$target_x = floatval($data['target_x']);
// 检查是否存在验证码数据
if (!isset($_SESSION['captcha'][$captcha_id])) {
echo json_encode(['success' => false, 'message' => '验证码已过期,请刷新重试']);
exit;
}
$captcha_data = $_SESSION['captcha'][$captcha_id];
// 检查是否超时(5分钟有效)
$elapsed_time = time() - $captcha_data['created_at'];
if ($elapsed_time > 300) {
unset($_SESSION['captcha'][$captcha_id]);
echo json_encode(['success' => false, 'message' => '验证码已过期,请刷新重试']);
exit;
}
// 计算误差范围(允许±20像素误差)
$tolerance = 20;
$distance = abs($current_x - $target_x);
if ($distance <= $tolerance) {
// 验证通过,删除验证码数据(一次性使用)
unset($_SESSION['captcha'][$captcha_id]);
echo json_encode([
'success' => true,
'message' => '验证成功'
]);
} else {
echo json_encode([
'success' => false,
'message' => '验证失败',
'distance' => round($distance, 2)
]);
}
?>
测试脚本 (test_upload.php)
<?php
// 这是一个简单的测试页面,用于测试滑块验证码的交互效果
session_start();
// 检查是否已通过验证
$verified = isset($_SESSION['verified']) && $_SESSION['verified'] === true;
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">滑块验证码测试 - 表单示例</title>
<style>
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: #f0f2f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.test-container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
width: 350px;
}
h3 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
input[type="text"],
input[type="email"] {
width: 100%;
padding: 12px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
box-sizing: border-box;
}
button[type="submit"] {
width: 100%;
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
}
button[type="submit"]:hover {
background: #5a67d8;
}
.status-message {
text-align: center;
margin-top: 15px;
color: #f44336;
}
.success-message {
color: #4CAF50;
text-align: center;
padding: 20px;
background: #f0f9f4;
border-radius: 5px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="test-container">
<?php if ($verified): ?>
<h3>表单提交成功!</h3>
<div class="success-message">
✅ 验证码验证通过<br>
<a href="index.php">返回重新测试</a>
</div>
<?php else: ?>
<h3>表单测试</h3>
<form action="index.php" method="get">
<input type="text" placeholder="用户名" required>
<input type="email" placeholder="邮箱" required>
<button type="submit">前往滑块验证</button>
</form>
<p class="status-message">请先完成滑块验证码验证</p>
<?php endif; ?>
</div>
</body>
</html>
使用说明
-
将文件部署到支持PHP的服务器(如XAMPP、WAMP、LAMP等)
-
访问 index.php 查看滑块验证码效果
-
主要功能:
- 点击并拖动滑块到正确位置
- 验证成功后显示成功提示
- 支持刷新验证码
- 验证码一次性使用,5分钟有效
核心代码说明
前端部分
sliderBtn是滑块按钮isDragging控制拖动状态startDrag、onDrag、endDrag处理鼠标和触摸事件currentX记录当前滑块位置targetX记录目标位置
后端部分
captcha_data.php生成验证码数据verify.php验证滑块位置- 使用
session存储验证码数据 - 加入时间限制防止暴力破解
安全特性
- 验证码一次性使用
- 5分钟有效期
- 验证码数据存储在session中
- 服务器端验证,防止绕过
这个滑块验证码系统已经完整实现,可以直接部署使用,如果需要更多功能(如图片拼图、动态轨迹验证等),可以在此基础上进行扩展。