php使用bitmap完成签到

在设计签到的同时,需要考虑补签问题。

在技术选型方面我选择了redis的bitmap。bitmap占用空间少,运行速度快。

我这里使用的是laravel。

laravel操作redis需要先composer

composer require predis/predis

首先是签到的代码

/**
     *用户签到接口  
     * @param int $uid
     */
    public static function sign($uid)
    {
        //获取当前时间
        $now = date('Ym');
        $day = date('d');
        //拼接bitmap的key
        $key = $uid.':'.$now;
        //查看是否签到过
        $date = Redis::getbit($key,$day);
        if($date){
            return showMsg(200,'今天签到过了');
        }
        //获取昨天时间
        $lastDay = date("d", strtotime("-1 day"));
        //查看昨天是否签到
        $lastDate = Redis::getbit($key,$lastDay);
        $user = \App\Models\EbUser::getOne($uid);
        Redis::setbit($key,0,1);
        //昨天签到(连签)
        if($lastDate){
            //积分叠加   bitmap存已签到
            $integral = $user['integral'] + 10 + ($user['sign_num']*15);
            $update['integral'] = $integral;
            $update['sign_num'] = $user['sign_num'] + 1;
            $result = EbUser::updateUser($uid,$update);
            Redis::setbit($key,$day,1);
            return showMsg(200,'连续签到成功');
        }
        //昨天未签到(断签)
        $update['sign_num'] = 1;
        $update['integral'] = $user['integral'] + 10;
        $result = EbUser::updateUser($uid,$update);
        Redis::setbit($key,$day,1);
        return showMsg(200,'断签了,签到成功');
    }

查询当月签到情况

/**
     * 查询用户本月签到情况
     * @param $uid
     */
    public static function getMonthSign($uid,$date)
    {
        //获取用户签到信息
        $key = $uid.':'.$date;
        $sign = Redis::get($key);
        //处理数据
        $bitmap_bin_str = self::strToBin($sign);
        //调试使用,输出本月每天签到情况
//        $month = date('t');
//        for($i=1;$i<=$month;$i++){
//            if(empty($bitmap_bin_str[$i])){
//                $bitmap_bin_str[$i] = 0;
//            }
//            if($bitmap_bin_str[$i]!=1){
//                echo "$i 日未签到";
//                echo "<br>";
//            }else{
//                echo "$i 日签到";
//                echo "<br>";
//            }
//        }
        return showMsg(200,'用户签到信息',$bitmap_bin_str);
    }

数据转数值

/**
     * 数据转换为数字
     * @param $str
     * @return string
     */
    public static function strToBin($str){
        $arr = preg_split('/(?<!^)(?!$)/u', $str);
        foreach($arr as &$v){
            $temp = unpack('H*', $v);
            $v = base_convert($temp[1], 16, 2);
            unset($temp);
        }
        return join(' ',$arr);
    }

用户补签,并重新计算连签次数

/**
     * 补签并重新计算连续签到
     * @param $uid
     * @param $date
     * @return false|string
     * 
     */
    public static function retroactive($uid, $date)
    {
        $now = date('Ymd');
        if ($date >= $now) {
            return showMsg('500', '补签的日期不能大于等于今天');
        }
        $day = substr($date, 6, 2);
        $month = substr($date, 0, 6);
        $key = $uid . ':' . $month;
        $sign = Redis::getbit($key, $day);
        if ($sign == 1) {
            return showMsg('200', '你已经签到过了不需要补签.');
        }
        Redis::setbit($key, $day, 1);
        $month = date('Ym');
        $day = date('d') - 1;
        $signKey = $uid . ':' . $month;
        $sign = Redis::getbit($signKey, $day);
        $i = 1;
        if ($sign == 1) {
            self::getNum($uid, $month, $day,$i);
            //获取当前时间
            $now = date('Ym');
            $day = date('d');
            //拼接bitmap的key
            $key = $uid . ':' . $now;
            //查看是否签到过
            $date = Redis::getbit($key, $day);
            if($date == 1){
                EbUser::updateUser($uid,['sign_num'=>$i+1]);
                return showMsg(200,'补签成功');
            }
            EbUser::updateUser($uid,['sign_num'=>$i]);
            return showMsg(200,'补签成功');
        }
        //获取当前时间
        $now = date('Ym');
        $day = date('d');
        //拼接bitmap的key
        $key = $uid . ':' . $now;
        //查看是否签到过
        $date = Redis::getbit($key, $day);
        if($date == 1){
            EbUser::updateUser($uid,['sign_num'=>1]);
            return showMsg(200,'补签成功');
        }
        EbUser::updateUser($uid,['sign_num'=>0]);
        return showMsg(200,'补签成功');
    }

通过递归获取连签天数

/**
     * 获取用户连续签到天数
     * @param $uid
     * @param $date
     * @param $day
     * @param $i
     */
    public static function getNum($uid, $date, $day,&$i)
    {
        try {
//            if (strlen($day) == 1) $day = '0' . $day;
            $key = $uid . ':' . $date;
            $sign = Redis::getbit($key, $day);
            if ($sign == 1) {
                $i ++;
                if ($day - 1 > 0) {
                    self::getNum($uid, $date, $day - 1,$i);
                }else{
                    //   \xff\xf4
                    $time = strtotime($date . '0' . $day) - 86400;
                    $mytime = date('Ymd', $time);
                    $day = substr($mytime, 6, 2);
                    $month = substr($mytime, 0, 6);
                    self::getNum($uid, $month, $day,$i);
                }
            }
//            return '连续签到'.$i.'天';
        }catch (\Exception $e){
            return showMsg(500,$e->getMessage());
        }
    }

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值