如何用PHP项目实现用户邮箱绑定?

wen java案例 3

本文目录导读:

如何用PHP项目实现用户邮箱绑定?

  1. 数据库设计
  2. 发送验证邮件功能
  3. 绑定邮箱处理页面
  4. 前端HTML示例
  5. 配置文件示例
  6. 安全建议

我来详细介绍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());
}
?>

安全建议

  1. 使用HTTPS:确保所有通信都使用HTTPS加密
  2. 限制发送频率:防止恶意用户频繁发送验证码
  3. 验证码有效期:建议设置为10-15分钟
  4. 使用CSRF Token:防止跨站请求伪造攻击
  5. 输入验证:前后端都要进行输入验证和过滤
  6. 记录日志:记录所有邮箱绑定操作的日志

这个完整的实现考虑了安全性、用户体验和代码的可维护性,可以根据你的具体需求进行调整。

抱歉,评论功能暂时关闭!