本文目录导读:

我来详细介绍PHP实现用户邮箱绑定的完整方案。
数据库设计
首先创建用户表和邮箱验证表:
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE,
email_verified TINYINT(1) DEFAULT 0,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 邮箱验证码表
CREATE TABLE email_verifications (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
email VARCHAR(100) NOT NULL,
verification_code VARCHAR(6) NOT NULL,
expires_at DATETIME NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
发送验证邮件功能
<?php
// send_verification.php
require_once 'config.php'; // 数据库配置
require_once 'vendor/autoload.php'; // 如果是使用composer安装PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
function sendVerificationEmail($email, $code) {
$mail = new PHPMailer(true);
try {
// 服务器设置
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com'; // SMTP服务器
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com'; // SMTP用户名
$mail->Password = 'your_password'; // SMTP密码
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
// 发件人
$mail->setFrom('your@gmail.com', 'Your Website');
// 收件人
$mail->addAddress($email);
// 内容
$mail->isHTML(true);
$mail->Subject = '邮箱验证';
$mail->Body = "您的验证码是:<b>$code</b><br>该验证码有效期为10分钟。";
$mail->AltBody = "您的验证码是:$code";
$mail->send();
return true;
} catch (Exception $e) {
error_log("邮件发送失败: {$mail->ErrorInfo}");
return false;
}
}
// 生成验证码
function generateVerificationCode($length = 6) {
return str_pad(rand(0, pow(10, $length)-1), $length, '0', STR_PAD_LEFT);
}
?>
绑定邮箱处理页面
<?php
// bind_email.php
session_start();
require_once 'config.php';
// 检查用户是否登录
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
$user_id = $_SESSION['user_id'];
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
// 1. 发送验证码
if ($action === 'send_code') {
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if (!$email) {
echo json_encode(['success' => false, 'message' => '邮箱格式不正确']);
exit;
}
// 检查邮箱是否已被其他用户绑定
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = ? AND id != ?");
$stmt->execute([$email, $user_id]);
if ($stmt->fetch()) {
echo json_encode(['success' => false, 'message' => '该邮箱已被其他账号绑定']);
exit;
}
// 生成验证码并保存
$code = generateVerificationCode();
$expires_at = date('Y-m-d H:i:s', strtotime('+10 minutes'));
$stmt = $pdo->prepare("INSERT INTO email_verifications (user_id, email, verification_code, expires_at) VALUES (?, ?, ?, ?)");
$stmt->execute([$user_id, $email, $code, $expires_at]);
// 发送邮件
if (sendVerificationEmail($email, $code)) {
echo json_encode(['success' => true, 'message' => '验证码已发送']);
} else {
echo json_encode(['success' => false, 'message' => '发送失败,请稍后重试']);
}
exit;
}
// 2. 验证并绑定邮箱
if ($action === 'verify_code') {
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$code = $_POST['code'] ?? '';
if (!$email || empty($code)) {
echo json_encode(['success' => false, 'message' => '参数不完整']);
exit;
}
// 验证验证码
$stmt = $pdo->prepare("SELECT * FROM email_verifications WHERE user_id = ? AND email = ? AND verification_code = ? AND expires_at > NOW() ORDER BY created_at DESC LIMIT 1");
$stmt->execute([$user_id, $email, $code]);
$verification = $stmt->fetch();
if (!$verification) {
echo json_encode(['success' => false, 'message' => '验证码无效或已过期']);
exit;
}
// 更新用户邮箱
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("UPDATE users SET email = ?, email_verified = 1 WHERE id = ?");
$stmt->execute([$email, $user_id]);
// 清理旧的验证记录
$stmt = $pdo->prepare("DELETE FROM email_verifications WHERE user_id = ?");
$stmt->execute([$user_id]);
$pdo->commit();
echo json_encode(['success' => true, 'message' => '邮箱绑定成功']);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => '绑定失败,请稍后重试']);
}
exit;
}
}
?>
前端HTML示例
<!-- bind_email.html -->
<!DOCTYPE html>
<html>
<head>绑定邮箱</title>
<style>
.form-group { margin-bottom: 15px; }
.btn { padding: 10px 20px; cursor: pointer; }
.message { margin-top: 10px; padding: 10px; border-radius: 5px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="container">
<h2>绑定邮箱</h2>
<div id="message" class="message" style="display:none;"></div>
<form id="emailForm">
<div class="form-group">
<label for="email">邮箱地址:</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<button type="button" id="sendCodeBtn" onclick="sendCode()">发送验证码</button>
<span id="timer" style="display:none;"></span>
</div>
<div class="form-group">
<label for="code">验证码:</label>
<input type="text" id="code" name="code" maxlength="6" pattern="\d{6}" required>
</div>
<div class="form-group">
<button type="submit" onclick="verifyCode(event)">确认绑定</button>
</div>
</form>
</div>
<script>
let countdown = 60;
let timerInterval = null;
// 发送验证码
function sendCode() {
const email = document.getElementById('email').value;
if (!validateEmail(email)) {
showMessage('请输入有效的邮箱地址', 'error');
return;
}
// 禁用发送按钮
document.getElementById('sendCodeBtn').disabled = true;
startCountdown();
fetch('bind_email.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=send_code&email=${encodeURIComponent(email)}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage('验证码已发送到您的邮箱', 'success');
} else {
showMessage(data.message, 'error');
document.getElementById('sendCodeBtn').disabled = false;
clearInterval(timerInterval);
document.getElementById('timer').style.display = 'none';
}
})
.catch(error => {
showMessage('发送失败,请稍后重试', 'error');
document.getElementById('sendCodeBtn').disabled = false;
clearInterval(timerInterval);
document.getElementById('timer').style.display = 'none';
});
}
// 验证验证码
function verifyCode(event) {
event.preventDefault();
const email = document.getElementById('email').value;
const code = document.getElementById('code').value;
if (!email || !code) {
showMessage('请填写完整信息', 'error');
return;
}
fetch('bind_email.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `action=verify_code&email=${encodeURIComponent(email)}&code=${code}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
showMessage('邮箱绑定成功!', 'success');
setTimeout(() => {
window.location.href = 'profile.php'; // 跳转到个人设置页面
}, 2000);
} else {
showMessage(data.message, 'error');
}
})
.catch(error => {
showMessage('验证失败,请稍后重试', 'error');
});
}
// 显示消息
function showMessage(text, type) {
const messageDiv = document.getElementById('message');
messageDiv.textContent = text;
messageDiv.className = `message ${type}`;
messageDiv.style.display = 'block';
}
// 邮箱验证
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
// 倒计时
function startCountdown() {
const timerSpan = document.getElementById('timer');
timerSpan.style.display = 'inline';
timerSpan.textContent = `(${countdown}秒后可重新发送)`;
timerInterval = setInterval(() => {
countdown--;
timerSpan.textContent = `(${countdown}秒后可重新发送)`;
if (countdown <= 0) {
clearInterval(timerInterval);
document.getElementById('sendCodeBtn').disabled = false;
timerSpan.style.display = 'none';
countdown = 60;
}
}, 1000);
}
</script>
</body>
</html>
配置文件示例
<?php
// config.php
$host = 'localhost';
$dbname = 'your_database';
$username = 'your_username';
$password = 'your_password';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
?>
安全建议
- 使用HTTPS:确保所有通信都使用HTTPS加密
- 限制发送频率:防止恶意用户频繁发送验证码
- 验证码有效期:建议设置为10-15分钟
- 使用CSRF Token:防止跨站请求伪造攻击
- 输入验证:前后端都要进行输入验证和过滤
- 记录日志:记录所有邮箱绑定操作的日志
这个完整的实现考虑了安全性、用户体验和代码的可维护性,可以根据你的具体需求进行调整。