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

先说下业务规则 首次签到可获得奖励 以及连续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(){} }
本作品采用《CC 协议》,转载必须注明作者和本文链接
MrHou
打赏
hou3749887
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1