使用 Redis bitmap 在微擎內做公眾號的簽到活動

hou3749887發表於2019-07-31

先說下業務規則 首次簽到可獲得獎勵 以及連續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

相關文章