營銷活動中抽獎功能需滿足:可配置中獎概率、真隨機性、獎品數量限制、用戶參與次數限制(基於 QQ/手機/IP)。本文基於 ThinkPHP 3.x 實現一套生產可用的階段式抽獎邏輯。
獎品陣列按 中獎概率從小到大 排序,必須包含「不中獎」項,字段含義:
id:獎次序號prize:獎品描述v:權重值(相對概率)num:庫存數量$prize_arr = array(
0 => array('id'=>1, 'prize'=>'44元購買1G/年空間', 'v'=>1, 'num'=>1),
1 => array('id'=>2, 'prize'=>'55元購買1G/年空間', 'v'=>2, 'num'=>2),
2 => array('id'=>3, 'prize'=>'66元購買1G/年空間', 'v'=>5, 'num'=>2),
3 => array('id'=>4, 'prize'=>'77元購買1G/年空間', 'v'=>10, 'num'=>3),
4 => array('id'=>5, 'prize'=>'88元購買1G/年空間', 'v'=>15, 'num'=>4),
5 => array('id'=>6, 'prize'=>'99元購買1G/年空間', 'v'=>67, 'num'=>10), // 大獎/安慰獎
);
private function get_rand($proArr) {
$proSum = array_sum($proArr); // 總權重
foreach ($proArr as $key => $proCur) {
$randNum = mt_rand(1, $proSum); // 1~總權重
if ($randNum <= $proCur) {
return $key; // 命中
}
$proSum -= $proCur; // 權重前移
}
return ''; // 理論不會走到這裡
}
該算法時間複雜度 O(n),單次抽獎耗時微秒級,支撐高併發無壓力。
$rid = $this->get_rand($arr)num 則視為「獎品已抽完」,轉為不中獎rid、獎品信息、QQ、時間戳begin_time/stop_time 改為陣列,支援每日定時開獎<?php
class ChoujiangAction extends Action {
var $begin_time = "2012-12-25 14:00:00";
var $stop_time = "0";
var $prize_arr = [ /* 如上 */ ];
public function index() {
$Choujiang = M('Choujiang');
$this->assign('list', $Choujiang->where("rid>0")->order('id desc')->select());
$this->assign('begin_time', $this->begin_time);
$this->display();
}
public function make() {
$qq_no = trim($_POST['qq_no']);
import('ORG.Util.Input');
$qq_no = Input::getVar($qq_no);
if (empty($qq_no)) $this->ajaxReturn(1, '請正確填寫QQ號碼!');
// 時間校驗
if ($this->begin_time && time() < strtotime($this->begin_time))
$this->ajaxReturn(1, '抽獎還沒有開始...');
if ($this->stop_time && time() > strtotime($this->stop_time))
$this->ajaxReturn(1, '本次抽獎已經結束...');
$prize_arr = $this->prize_arr;
foreach ($prize_arr as $k => $v) $arr[$v['id']] = $v['v'];
$rid = $this->get_rand($arr);
$str = $prize_arr[$rid - 1]['prize'];
$Choujiang = M('Choujiang');
// 次數限制
if ($Choujiang->where("qq_no='{$qq_no}'")->count() >= 3) {
$str = '您3次抽獎機會已經用完!'; $rid = 0;
}
// 庫存限制
elseif ($Choujiang->where("rid={$rid}")->count() >= $prize_arr[$rid-1]['num']) {
$str = '很抱歉,您所抽中的獎項已經中完!'; $rid = 0;
}
$data = array('rid'=>$rid, 'pop'=>$str, 'qq_no'=>$qq_no, 'input_time'=>time());
$Choujiang->add($data);
$this->ajaxReturn(1, $str);
}
private function get_rand($proArr) { /* 如上 */ }
}
?>
這套方案邏輯清晰、擴展性強,通過「權重隨機 + 庫存校驗 + 次數限制」三重保障,滿足多數營銷抽獎場景。實際部署時請結合 Redis、資料庫事務進一步提升可靠性。