本文目录导读:

我来介绍几种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;
}
}
?>
使用建议
- 初始化:配置数据库连接和奖品数据
- 安全性:添加验证码、登录检查、频率限制
- 性能优化:使用Redis缓存奖品配置
- 日志记录:记录所有抽奖操作,便于审计
- 奖品发放:中奖后及时发放奖品,避免争议
这个系统可以根据实际需求灵活调整,添加更多功能如:积分抽奖、活动管理、数据分析等。