如何用PHP项目实现幸运抽奖?

wen java案例 4

本文目录导读:

如何用PHP项目实现幸运抽奖?

  1. 基础随机抽奖(最简单方案)
  2. 权重抽奖(按概率分配)
  3. 完整的抽奖系统(含数据库操作)
  4. 数据库表结构
  5. 前端抽奖页面示例
  6. API接口文件 (lottery_api.php)
  7. 安全性和优化建议
  8. 使用建议

我来介绍几种PHP实现幸运抽奖的常见方案,从简单到复杂逐步实现。

基础随机抽奖(最简单方案)

<?php
// 基础随机抽奖
function basicLottery($participants) {
    $winner = $participants[array_rand($participants)];
    return $winner;
}
// 使用示例
$users = ['用户A', '用户B', '用户C', '用户D', '用户E'];
$winner = basicLottery($users);
echo "中奖者:{$winner}";
?>

权重抽奖(按概率分配)

<?php
class WeightedLottery {
    private $prizes = [];
    public function addPrize($name, $weight) {
        $this->prizes[] = [
            'name' => $name,
            'weight' => $weight
        ];
    }
    public function draw() {
        $totalWeight = array_sum(array_column($this->prizes, 'weight'));
        $random = mt_rand(1, $totalWeight * 100) / 100;
        $currentWeight = 0;
        foreach ($this->prizes as $prize) {
            $currentWeight += $prize['weight'];
            if ($random <= $currentWeight) {
                return $prize['name'];
            }
        }
        return null;
    }
}
// 使用示例
$lottery = new WeightedLottery();
$lottery->addPrize('一等奖(iPhone)', 1);   // 1%概率
$lottery->addPrize('二等奖(耳机)', 10);    // 10%概率
$lottery->addPrize('三等奖(优惠券)', 30);   // 30%概率
$lottery->addPrize('谢谢参与', 59);          // 59%概率
$result = $lottery->draw();
echo "恭喜获得:{$result}";
?>

完整的抽奖系统(含数据库操作)

<?php
// 数据库配置文件 config.php
define('DB_HOST', 'localhost');
define('DB_NAME', 'lottery_db');
define('DB_USER', 'root');
define('DB_PASS', 'password');
// 抽奖系统主类
class LotterySystem {
    private $db;
    private $userId;
    public function __construct($userId) {
        $this->userId = $userId;
        $this->connectDB();
    }
    private function connectDB() {
        try {
            $this->db = new PDO(
                "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME,
                DB_USER,
                DB_PASS
            );
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            die("数据库连接失败:" . $e->getMessage());
        }
    }
    // 检查抽奖资格
    private function checkEligibility() {
        $today = date('Y-m-d');
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) FROM lottery_records 
             WHERE user_id = ? AND DATE(created_at) = ?"
        );
        $stmt->execute([$this->userId, $today]);
        return $stmt->fetchColumn() == 0; // 每人每天限抽一次
    }
    // 获取奖品配置
    private function getPrizes() {
        $stmt = $this->db->query("SELECT * FROM prizes WHERE status = 1");
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    // 执行抽奖
    public function draw() {
        // 检查资格
        if (!$this->checkEligibility()) {
            return ['success' => false, 'message' => '今日已抽奖,请明天再来'];
        }
        // 获取奖品
        $prizes = $this->getPrizes();
        if (empty($prizes)) {
            return ['success' => false, 'message' => '暂无可用奖品'];
        }
        // 权重抽奖逻辑
        $totalWeight = array_sum(array_column($prizes, 'weight'));
        $random = mt_rand(1, $totalWeight);
        $currentWeight = 0;
        $winPrize = null;
        foreach ($prizes as $prize) {
            $currentWeight += $prize['weight'];
            if ($random <= $currentWeight) {
                $winPrize = $prize;
                break;
            }
        }
        // 记录抽奖结果
        $this->recordLottery($winPrize);
        // 更新库存
        $this->updateStock($winPrize);
        return [
            'success' => true,
            'prize' => $winPrize['name'],
            'level' => $winPrize['level']
        ];
    }
    private function recordLottery($prize) {
        $stmt = $this->db->prepare(
            "INSERT INTO lottery_records (user_id, prize_id, prize_name, created_at) 
             VALUES (?, ?, ?, NOW())"
        );
        $stmt->execute([
            $this->userId,
            $prize['id'],
            $prize['name']
        ]);
    }
    private function updateStock($prize) {
        $stmt = $this->db->prepare(
            "UPDATE prizes SET stock = stock - 1 
             WHERE id = ? AND stock > 0"
        );
        $stmt->execute([$prize['id']]);
    }
    // 获取用户抽奖记录
    public function getRecords($limit = 10) {
        $stmt = $this->db->prepare(
            "SELECT * FROM lottery_records 
             WHERE user_id = ? 
             ORDER BY created_at DESC 
             LIMIT ?"
        );
        $stmt->execute([$this->userId, $limit]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}
// 使用示例
$userId = 123; // 当前用户ID
$lottery = new LotterySystem($userId);
$result = $lottery->draw();
if ($result['success']) {
    echo "🎉 恭喜获得:{$result['prize']}";
} else {
    echo "❌ {$result['message']}";
}
?>

数据库表结构

-- 奖品表
CREATE TABLE `prizes` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(100) NOT NULL COMMENT '奖品名称',
    `level` int(11) NOT NULL COMMENT '奖项等级',
    `weight` int(11) NOT NULL COMMENT '权重',
    `stock` int(11) NOT NULL DEFAULT 0 COMMENT '库存',
    `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态',
    `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 抽奖记录表
CREATE TABLE `lottery_records` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_id` int(11) NOT NULL COMMENT '用户ID',
    `prize_id` int(11) DEFAULT NULL COMMENT '奖品ID',
    `prize_name` varchar(100) DEFAULT NULL COMMENT '奖品名称',
    `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `user_id` (`user_id`),
    KEY `created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 插入测试数据
INSERT INTO `prizes` (`name`, `level`, `weight`, `stock`) VALUES
('一等奖 iPhone 15', 1, 1, 3),
('二等奖 AirPods', 2, 5, 20),
('三等奖 50元优惠券', 3, 20, 100),
('四等奖 10元优惠券', 4, 30, 500),
('谢谢参与', 5, 44, 99999);

前端抽奖页面示例

<!DOCTYPE html>
<html>
<head>幸运抽奖</title>
    <style>
        .lottery-container {
            text-align: center;
            padding: 50px;
        }
        .prize-box {
            width: 300px;
            height: 300px;
            border: 3px solid #ffd700;
            border-radius: 10px;
            margin: 20px auto;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            cursor: pointer;
            transition: transform 0.3s;
        }
        .prize-box:hover {
            transform: scale(1.05);
        }
        .prize-box.spinning {
            animation: spin 0.5s linear infinite;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            25% { transform: rotate(5deg); }
            75% { transform: rotate(-5deg); }
            100% { transform: rotate(0deg); }
        }
        .btn-draw {
            padding: 15px 30px;
            font-size: 18px;
            background: #ff4757;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        .btn-draw:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        .result {
            margin: 20px 0;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div class="lottery-container">
        <h1>🎰 幸运大转盘</h1>
        <div class="prize-box" id="prizeBox">
            点击抽奖
        </div>
        <div class="result" id="result"></div>
        <button class="btn-draw" id="drawBtn" onclick="draw()">开始抽奖</button>
        <!-- 历史记录 -->
        <div style="margin-top: 50px;">
            <h3>抽奖记录</h3>
            <table border="1" style="margin: auto;">
                <tr>
                    <th>时间</th>
                    <th>奖品</th>
                </tr>
                <?php foreach ($lottery->getRecords() as $record): ?>
                <tr>
                    <td><?php echo $record['created_at']; ?></td>
                    <td><?php echo $record['prize_name']; ?></td>
                </tr>
                <?php endforeach; ?>
            </table>
        </div>
    </div>
    <script>
        function draw() {
            const btn = document.getElementById('drawBtn');
            const box = document.getElementById('prizeBox');
            const result = document.getElementById('result');
            btn.disabled = true;
            box.classList.add('spinning');
            result.innerHTML = '抽奖中...';
            // 发送AJAX请求
            fetch('lottery_api.php?action=draw', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                }
            })
            .then(response => response.json())
            .then(data => {
                setTimeout(() => {
                    box.classList.remove('spinning');
                    btn.disabled = false;
                    if (data.success) {
                        result.innerHTML = `🎉 恭喜获得:${data.prize}`;
                        box.style.background = 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)';
                    } else {
                        result.innerHTML = `😅 ${data.message}`;
                    }
                }, 2000);
            })
            .catch(error => {
                box.classList.remove('spinning');
                btn.disabled = false;
                result.innerHTML = '抽奖失败,请重试';
            });
        }
    </script>
</body>
</html>

API接口文件 (lottery_api.php)

<?php
header('Content-Type: application/json');
session_start();
require_once 'LotterySystem.php';
$action = $_GET['action'] ?? '';
$userId = $_SESSION['user_id'] ?? 0;
if (!$userId) {
    echo json_encode(['success' => false, 'message' => '请先登录']);
    exit;
}
$lottery = new LotterySystem($userId);
switch ($action) {
    case 'draw':
        $result = $lottery->draw();
        echo json_encode($result);
        break;
    case 'records':
        $records = $lottery->getRecords();
        echo json_encode(['success' => true, 'records' => $records]);
        break;
    default:
        echo json_encode(['success' => false, 'message' => '无效请求']);
}
?>

安全性和优化建议

<?php
// 1. 防刷机制
class AntiCheat {
    // IP限制
    public function checkIP() {
        $ip = $_SERVER['REMOTE_ADDR'];
        $key = "lottery_ip_{$ip}";
        // Redis限流
        $count = $redis->incr($key);
        if ($count > 100) { // 每小时100次限制
            die('操作过于频繁');
        }
    }
    // 并发控制
    public function lockUser($userId) {
        $lockKey = "lottery_lock_{$userId}";
        return $redis->setnx($lockKey, 1); // 分布式锁
    }
    public function unlockUser($userId) {
        $lockKey = "lottery_lock_{$userId}";
        $redis->del($lockKey);
    }
}
// 2. 库存控制
function checkStockWithLock($prizeId) {
    $db->beginTransaction();
    try {
        $stmt = $db->prepare("SELECT stock FROM prizes WHERE id = ? FOR UPDATE");
        $stmt->execute([$prizeId]);
        $stock = $stmt->fetchColumn();
        if ($stock <= 0) {
            throw new Exception('库存不足');
        }
        // 扣减库存
        $stmt = $db->prepare("UPDATE prizes SET stock = stock - 1 WHERE id = ?");
        $stmt->execute([$prizeId]);
        $db->commit();
        return true;
    } catch (Exception $e) {
        $db->rollBack();
        return false;
    }
}
?>

使用建议

  1. 初始化:配置数据库连接和奖品数据
  2. 安全性:添加验证码、登录检查、频率限制
  3. 性能优化:使用Redis缓存奖品配置
  4. 日志记录:记录所有抽奖操作,便于审计
  5. 奖品发放:中奖后及时发放奖品,避免争议

这个系统可以根据实际需求灵活调整,添加更多功能如:积分抽奖、活动管理、数据分析等。

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