PHP 注册邀请码机制

wen PHP项目 3

本文目录导读:

PHP 注册邀请码机制

  1. 数据库设计
  2. 核心PHP代码实现
  3. 用户体验优化
  4. 安全考虑与最佳实践

我来为你详细介绍PHP注册邀请码机制的实现方案。

数据库设计

邀请码表

CREATE TABLE `invite_codes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(20) NOT NULL COMMENT '邀请码',
  `user_id` int(11) DEFAULT NULL COMMENT '生成邀请码的用户ID',
  `status` tinyint(1) DEFAULT '0' COMMENT '状态:0未使用,1已使用,2已过期',
  `used_by` int(11) DEFAULT NULL COMMENT '使用该邀请码的用户ID',
  `used_at` datetime DEFAULT NULL COMMENT '使用时间',
  `expire_at` datetime DEFAULT NULL COMMENT '过期时间',
  `created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_code` (`code`),
  KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

用户表设计

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(100) DEFAULT NULL,
  `invited_by` int(11) DEFAULT NULL COMMENT '邀请人用户ID',
  `created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心PHP代码实现

邀请码生成类

<?php
class InviteCode {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    /**
     * 生成邀请码
     * @param int $userId 用户ID
     * @param int $count 生成数量
     * @param int $expireDays 过期天数
     * @return array 生成的邀请码
     */
    public function generate($userId, $count = 1, $expireDays = 30) {
        $codes = [];
        $expireAt = date('Y-m-d H:i:s', strtotime("+{$expireDays} days"));
        for ($i = 0; $i < $count; $i++) {
            $code = $this->generateUniqueCode();
            $sql = "INSERT INTO invite_codes (code, user_id, expire_at) VALUES (?, ?, ?)";
            $stmt = $this->db->prepare($sql);
            $stmt->bind_param("sis", $code, $userId, $expireAt);
            if ($stmt->execute()) {
                $codes[] = $code;
            }
        }
        return $codes;
    }
    /**
     * 生成唯一邀请码
     */
    private function generateUniqueCode() {
        $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $code = '';
        $max = strlen($characters) - 1;
        do {
            $code = '';
            for ($i = 0; $i < 8; $i++) {
                $code .= $characters[random_int(0, $max)];
            }
        } while ($this->codeExists($code));
        return $code;
    }
    /**
     * 检查邀请码是否已存在
     */
    private function codeExists($code) {
        $sql = "SELECT id FROM invite_codes WHERE code = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("s", $code);
        $stmt->execute();
        $result = $stmt->get_result();
        return $result->num_rows > 0;
    }
    /**
     * 验证邀请码
     */
    public function validate($code) {
        $sql = "SELECT * FROM invite_codes WHERE code = ? AND status = 0";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("s", $code);
        $stmt->execute();
        $result = $stmt->get_result();
        if ($result->num_rows === 0) {
            return ['valid' => false, 'message' => '邀请码不存在或已被使用'];
        }
        $inviteCode = $result->fetch_assoc();
        // 检查过期
        if (strtotime($inviteCode['expire_at']) < time()) {
            return ['valid' => false, 'message' => '邀请码已过期'];
        }
        return ['valid' => true, 'data' => $inviteCode];
    }
    /**
     * 使用邀请码
     */
    public function useCode($code, $userId) {
        $sql = "UPDATE invite_codes 
                SET status = 1, used_by = ?, used_at = NOW() 
                WHERE code = ? AND status = 0";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("is", $userId, $code);
        return $stmt->execute();
    }
    /**
     * 获取用户的邀请记录
     */
    public function getInviteRecords($userId) {
        $sql = "SELECT u.username, u.created_at 
                FROM users u 
                WHERE u.invited_by = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("i", $userId);
        $stmt->execute();
        return $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    }
}

注册处理逻辑

<?php
class Register {
    private $db;
    private $inviteCode;
    public function __construct($db) {
        $this->db = $db;
        $this->inviteCode = new InviteCode($db);
    }
    /**
     * 注册新用户
     */
    public function register($username, $password, $invite_code = '') {
        // 1. 验证输入
        if (empty($username) || empty($password)) {
            return ['success' => false, 'message' => '用户名和密码不能为空'];
        }
        // 2. 检查用户名是否已存在
        if ($this->usernameExists($username)) {
            return ['success' => false, 'message' => '用户名已存在'];
        }
        // 3. 验证邀请码(如果开启强制邀请)
        if (!empty($invite_code)) {
            $inviteValidation = $this->inviteCode->validate($invite_code);
            if (!$inviteValidation['valid']) {
                return ['success' => false, 'message' => $inviteValidation['message']];
            }
        } elseif ($this->requireInviteCode()) {
            return ['success' => false, 'message' => '请填写邀请码'];
        }
        // 4. 创建用户
        $invitedBy = null;
        if (!empty($invite_code) && $inviteValidation['valid']) {
            $invitedBy = $inviteValidation['data']['user_id'];
        }
        $passwordHash = password_hash($password, PASSWORD_BCRYPT);
        $sql = "INSERT INTO users (username, password, invited_by) VALUES (?, ?, ?)";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("ssi", $username, $passwordHash, $invitedBy);
        if ($stmt->execute()) {
            $userId = $stmt->insert_id;
            // 5. 标记邀请码为已使用
            if (!empty($invite_code)) {
                $this->inviteCode->useCode($invite_code, $userId);
            }
            return ['success' => true, 'message' => '注册成功', 'user_id' => $userId];
        }
        return ['success' => false, 'message' => '注册失败'];
    }
    private function usernameExists($username) {
        $sql = "SELECT id FROM users WHERE username = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->bind_param("s", $username);
        $stmt->execute();
        return $stmt->get_result()->num_rows > 0;
    }
    private function requireInviteCode() {
        // 这里可以配置是否需要强制邀请码
        return true;
    }
}

控制器/接口示例

<?php
// 处理注册请求
class RegisterController {
    public function handleRegister() {
        // 模拟数据库连接
        $db = new mysqli('localhost', 'user', 'password', 'database');
        $register = new Register($db);
        $username = $_POST['username'] ?? '';
        $password = $_POST['password'] ?? '';
        $inviteCode = $_POST['invite_code'] ?? '';
        $result = $register->register($username, $password, $inviteCode);
        header('Content-Type: application/json');
        echo json_encode($result);
    }
    // 生成邀请码接口(仅限已登录用户)
    public function generateInviteCodes() {
        session_start();
        if (!isset($_SESSION['user_id'])) {
            echo json_encode(['success' => false, 'message' => '请先登录']);
            return;
        }
        $db = new mysqli('localhost', 'user', 'password', 'database');
        $inviteCode = new InviteCode($db);
        $count = $_POST['count'] ?? 1;
        $expireDays = $_POST['expire_days'] ?? 30;
        $codes = $inviteCode->generate($_SESSION['user_id'], $count, $expireDays);
        echo json_encode(['success' => true, 'codes' => $codes]);
    }
}

用户体验优化

前端表单示例

<!DOCTYPE html>
<html>
<head>注册</title>
</head>
<body>
    <form id="registerForm">
        <input type="text" name="username" placeholder="用户名" required>
        <input type="password" name="password" placeholder="密码" required>
        <input type="text" name="invite_code" placeholder="邀请码(必填)" required>
        <button type="submit">注册</button>
    </form>
    <script>
        document.getElementById('registerForm').addEventListener('submit', function(e) {
            e.preventDefault();
            // 使用ajax提交数据
        });
    </script>
</body>
</html>

邀请码状态检查

// 检查邀请码状态(AJAX接口)
public function checkInviteCode() {
    $code = $_GET['code'] ?? '';
    $inviteCode = new InviteCode($db);
    $result = $inviteCode->validate($code);
    if ($result['valid']) {
        echo json_encode(['valid' => true, 'message' => '邀请码有效']);
    } else {
        echo json_encode(['valid' => false, 'message' => $result['message']]);
    }
}

安全考虑与最佳实践

  1. 防并发问题:使用事务处理邀请码的使用
  2. 数据验证:严格验证所有输入
  3. SQL注入防护:使用预处理语句
  4. 邀请码长度:建议使用8-10位,包含字母和数字
  5. 过期策略:设置合理的过期时间
  6. 使用次数限制:限制单个用户可生成的邀请码数量
  7. 日志记录:记录所有邀请码的生成和使用记录
  8. 定期清理:定期清理过期的邀请码

这就是一个完整的PHP注册邀请码机制实现,可以根据实际需求进行调整和扩展。

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