当前位置: 代码迷 >> 综合 >> 使用 Redis bitmap 在微擎内做公众号的签到活动
  详细解决方案

使用 Redis bitmap 在微擎内做公众号的签到活动

热度:23   发布时间:2023-12-23 07:03:48.0

先说下业务规则 首次签到可获得奖励 以及连续 2 天签到可获得奖励
因为使用的是 openid 而非用户的 uid
因此 此处的设计的 key 为 openid 而判断用户是否签到 的偏移量 为以某个起始时间 未开始的便宜来那个计算
另外还有一种方案是 以当天的日期为 key 而偏移量 则为用户的 uid (此处不采用的原因为 我们的业务 uid 总量不算大 但是 间隔比较大 可能造成很大的 0 间隔)

redis 事件记录 RedisManager
获取 单例 getRedisConn
签到 setSignUser ($openid)
判断今天签到 getTodaySign ($openid)
判断某天签到 getThisDaySign ($openid,$date)
计算总的签到数 countAllSignDay ($openid)
计算连续签到数 countContinueSignDay ($openid)
计算还差几次签到可抽奖 getAwardNeedDays ($openid)
鉴定今天是否能抽奖 decide_award ($openid)

class RedisManager
{private static $redisInstance;const SIGNSTARTDATA="2019-01-03";const CANAWARD=2002;const NOTAWARD=2004;const SIGNDAYSCANAWARD=2006;const SIGNDAYSCANNOTAWARD=2007;const FISRTSIGN=2008;const REPEATSIGN=2009;const SUFFIX="_2019";const PREFIX="sign_";private function __construct(){}static public function getRedisConn(){if(!self::$redisInstance instanceof self){self::$redisInstance = new self;}$temp = self::$redisInstance;return $temp->connRedis();}static  function connRedis(){     try {$redis_ocean = new Redis();$redis_ocean->connect("127.0.0.1","6333");$redis_ocean->auth("Zdklingchen");}catch (Exception $e){echo $e->getMessage().'<br/>';}return $redis_ocean;}static function setSignUser($openid){//签到$redis=RedisManager::getRedisConn();$cacheKey=RedisManager::PREFIX.$openid.RedisManager::SUFFIX;$startDate = RedisManager::SIGNSTARTDATA;$todayDate = date("Y-m-d");       $startTime = strtotime($startDate);$todayTime = strtotime($todayDate);$offset = floor(($todayTime - $startTime) / 86400);return  $redis->setBit($cacheKey, $offset, 1);}static function getTodaySign($openid){//判断某个openid 今天$redis=RedisManager::getRedisConn();$cacheKey=RedisManager::PREFIX.$openid.RedisManager::SUFFIX;$startDate = RedisManager::SIGNSTARTDATA;$todayDate = date("Y-m-d");       $startTime = strtotime($startDate);$todayTime = strtotime($todayDate);$offset = floor(($todayTime - $startTime) / 86400);$bitStatus = $redis->getBit($cacheKey, $offset);return $bitStatus;}static function getThisDaySign($openid,$date){//判断某个openid 是否在某天签到 0/1$redis=RedisManager::getRedisConn();$cacheKey=RedisManager::PREFIX.$openid.RedisManager::SUFFIX;$startDate = RedisManager::SIGNSTARTDATA;$todayDate = $date;       $startTime = strtotime($startDate);$todayTime = strtotime($todayDate);$offset = floor(($todayTime - $startTime) / 86400);$bitStatus = $redis->getBit($cacheKey, $offset);return $bitStatus;}static  function countAllSignDay($openid){//计算累计签到次数$redis=RedisManager::getRedisConn();$cacheKey=RedisManager::PREFIX.$openid.RedisManager::SUFFIX;return  $redis->bitCount($cacheKey);}static  function countContinueSignDay($openid){//计算连续签到次数$redis=RedisManager::getRedisConn();$cacheKey=RedisManager::PREFIX.$openid.RedisManager::SUFFIX;             $todayIsSign=RedisManager::getTodaySign($openid);if ($todayIsSign == 0) {$todayDate=date("Y-m-d",strtotime("-1 day"));       }else{$todayDate = date("Y-m-d"); }$startDate = RedisManager::SIGNSTARTDATA;$startTime = strtotime($startDate);  $todayTime = strtotime($todayDate);$offset = floor(($todayTime - $startTime) / 86400);$countContinueSignDayNum=0;for ($i=$offset; $i >= 0; $i--) {            $BitRes=$redis->getBit($cacheKey, $i);if ($BitRes == 1) {$countContinueSignDayNum++;continue;}else{break;}}return $countContinueSignDayNum;}static function getAwardNeedDays($openid){$todayIsSign=RedisManager::getTodaySign($openid);$totalCountSign=RedisManager::countAllSignDay($openid);if ($totalCountSign == 1 && $todayIsSign == 1) {//今天还没签到$data=array("code"=>RedisManager::FISRTSIGN,"needsDays"=>2,"msg"=> "First sign has sign,can get arawd",);return $data;}if ($totalCountSign == 0 && $todayIsSign == 0) {//今天还没签到$data=array("code"=>RedisManager::FISRTSIGN,"needsDays"=>0,"msg"=> "First sign has  not sign",);return $data;}else{$YesterDay=date("Y-m-d",strtotime("-1 day"));$YesterDaySignData=RedisManager::getThisDaySign($openid,$YesterDay);if ($YesterDaySignData == 0) {//昨日没签到if ($todayIsSign == 0) {$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>2,"msg"=> "Today is  not sign And YesterDay is not sign ",);return $data;}else{$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>1,"msg"=> "Today  has  sign But YesterDay is not sign  ",);return $data;}}else{$continueSignNum=RedisManager::countContinueSignDay($openid);if ($totalCountSign == $continueSignNum && $totalCountSign > 0 ) {//签到一直没间断if ($todayIsSign == 0) {if ($totalCountSign%2 == 0 ) {$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>1,"msg"=> "Today is  not sign  But sign is continue  ",);return $data;}else{$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>2,"msg"=> "Today is  not sign  But sign is continue   ",);return $data;}}else{//今天签到了if ($totalCountSign%2 == 0 ) {$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>1,"msg"=> "Today has sign And sign is continue  ",);return $data;}else{$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>2,"msg"=> "Today has sign And sign is continue  ",);return $data;}}}else{if ($todayIsSign == 0) {if ($continueSignNum%2 == 0 ) {$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>1,"msg"=> "Today is  not sign But sign is not  continue  ",);return $data;}else{$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>2,"msg"=> "Today is  not sign  But sign is not  continue   ",);return $data;}}else{if ($continueSignNum%2 == 0 ) {$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>2,"msg"=> "Today is  has  sign  But sign is not  continue   ",);return $data;}else{$data=array("code"=>RedisManager::SIGNDAYSCANAWARD,"needsDays"=>1,"msg"=> "Today is  has  sign  But sign is not  continue   ",);return $data;}}}}}}static function decide_award($openid){ //返回一个数组 2004 不抽奖 2002抽奖      $todayIsSign=RedisManager::getTodaySign($openid);$totalCountSign=RedisManager::countAllSignDay($openid);if ($todayIsSign == 0) {//今天没签到$data=array("code"=>RedisManager::NOTAWARD,"msg"=>"今日还没签到",);return $data;}if ($todayIsSign == 1 && $totalCountSign == 1) {//首次签到 今天签到 +总签到数=1$data=array("code"=>RedisManager::CANAWARD,"msg"=>"首次签到",);return $data;}else{$YesterDay=date("Y-m-d",strtotime("-1 day"));$YesterDaySignData=RedisManager::getThisDaySign($openid,$YesterDay);if ($YesterDaySignData == 0) {  //昨天没签到$data=array("code"=>RedisManager::NOTAWARD,"msg"=>"签到成功,但是您昨天没签到,明天继续签到可获得奖励",);return $data;}else{//因为今天已经签到 所以 连续签到从今天算 最小为1$continueSignNum=RedisManager::countContinueSignDay($openid);if ($totalCountSign == 2 &&  $continueSignNum == 2 ) {//总签到 跟连续签到 都为2 则说明昨天是首次签到$data=array("code"=>RedisManager::NOTAWARD,"msg"=>"签到成功,明天继续签到可获得奖励",);return $data;}else{//昨天签到不是首次签到 if ($totalCountSign == $continueSignNum && $totalCountSign > 0 ) {//首次签到一直没断if ($totalCountSign%2 == 0 ) {//偶数次不发$data=array("code"=>RedisManager::NOTAWARD,"msg"=>"签到成功,明天继续签到可获得奖励",);return $data;}else{$data=array("code"=>RedisManager::CANAWARD,"msg"=>"签到成功,今天可抽奖",);return $data;}}else{if ($continueSignNum%2 == 0 ) {//偶数次发$data=array("code"=>RedisManager::CANAWARD,"msg"=>"签到成功,今天可抽奖",);return $data;}else{$data=array("code"=>RedisManager::NOTAWARD,"msg"=>"签到成功,明天继续签到可获得奖励",);return $data;}}}        }}}private function __clone(){}}