php 红包雨 实现
红包雨功能实现思路
红包雨是一种常见的互动营销活动,用户在规定时间内点击屏幕上随机出现的红包获取奖励。PHP后端主要负责红包的生成、发放规则和数据处理。
数据库设计
需要创建至少两张表存储红包和用户领取记录:

CREATE TABLE `red_packets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`amount` decimal(10,2) NOT NULL COMMENT '红包金额',
`total` int(11) NOT NULL COMMENT '红包总数',
`remaining` int(11) NOT NULL COMMENT '剩余数量',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
CREATE TABLE `user_red_packets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`packet_id` int(11) NOT NULL,
`amount` decimal(10,2) NOT NULL,
`received_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `packet_id` (`packet_id`)
);
红包生成逻辑
使用PHP生成固定金额或随机金额红包:

function createRedPacket($totalAmount, $totalNumber) {
$packet = [
'amount' => $totalAmount,
'total' => $totalNumber,
'remaining' => $totalNumber
];
// 插入数据库
$db->insert('red_packets', $packet);
return $db->lastInsertId();
}
前端交互接口
提供API接口供前端获取红包数据:
// 获取可用红包列表
function getAvailablePackets() {
$sql = "SELECT id, amount, remaining FROM red_packets WHERE remaining > 0";
return $db->query($sql)->fetchAll();
}
// 领取红包
function receivePacket($userId, $packetId) {
$db->beginTransaction();
try {
// 检查红包剩余
$packet = $db->query("SELECT * FROM red_packets WHERE id = ? FOR UPDATE", [$packetId])->fetch();
if (!$packet || $packet['remaining'] <= 0) {
throw new Exception('红包已领完');
}
// 计算金额(固定或随机)
$amount = $packet['amount'] / $packet['total']; // 固定金额
// $amount = mt_rand(1, $packet['amount'] * 100) / 100; // 随机金额
// 记录领取
$db->insert('user_red_packets', [
'user_id' => $userId,
'packet_id' => $packetId,
'amount' => $amount
]);
// 更新红包剩余
$db->update('red_packets',
['remaining' => $packet['remaining'] - 1],
['id' => $packetId]
);
$db->commit();
return $amount;
} catch (Exception $e) {
$db->rollBack();
throw $e;
}
}
性能优化建议
使用Redis缓存红包信息减少数据库压力:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 红包库存缓存
function getPacketRemaining($packetId) {
global $redis;
$key = "packet:{$packetId}:remaining";
$remaining = $redis->get($key);
if ($remaining === false) {
$remaining = $db->query("SELECT remaining FROM red_packets WHERE id = ?", [$packetId])->fetchColumn();
$redis->set($key, $remaining);
}
return $remaining;
}
安全注意事项
- 接口需要验证用户身份防止刷红包
- 重要操作使用数据库事务保证数据一致性
- 对单个用户设置领取次数限制
- 使用分布式锁处理高并发下的超发问题
// 使用Redis分布式锁
function acquireLock($lockKey, $timeout = 3) {
global $redis;
$identifier = uniqid();
$end = time() + $timeout;
while (time() < $end) {
if ($redis->setnx($lockKey, $identifier)) {
$redis->expire($lockKey, $timeout);
return $identifier;
}
usleep(10000); // 10ms
}
return false;
}
前端实现要点
- 使用WebSocket或定时轮询获取红包位置信息
- 红包在屏幕随机位置出现并下落动画
- 点击红包后调用领取接口
- 展示领取结果和累计金额
完整实现需要考虑活动时间控制、风控策略、数据统计等功能模块。根据实际需求可扩展更多玩法如不同价值红包、连击奖励等。






