php实现签到功能

连续签到送积分
1.数据表设计
积分表

CREATE TABLE `yixiang_users_coinrecord` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `uid` varchar(20) NOT NULL COMMENT '用户的uid',
 `type` varchar(20) NOT NULL COMMENT '收支类型',
 `totalcoin` int(11) NOT NULL COMMENT '总数量',
 `action` varchar(20) NOT NULL COMMENT '收支行为',
 `addtime` varchar(255) NOT NULL COMMENT '添加时间',
 PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=7160 DEFAULT CHARSET=utf8

签到表

CREATE TABLE `yixiang_signin` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `uid` varchar(100) NOT NULL COMMENT '用户id',
 `cont_days` varchar(100) NOT NULL COMMENT '连续签到天数',
 `last_signin_time` int(11) NOT NULL COMMENT '最后一次签到时间',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8

2.代码

     /**
     * 签到
     */
    public function signin()
    {
        $this->uid_exist();
        // $this->uid = 505;
        $time = getdate();
        $today_zero = mktime(0,0,0,$time['mon'],$time['mday'],$time['year']);
        $signin_log = M('signin')->where(array('uid'=>$this->uid))->order("id desc")->find();
        //一个月有多少天
        $month_have_day = date("t",strtotime($time['year']."-".$time['mon']));
        //如果今天的日期小于最后一次签到时间         最后一次签到时间小于明天
        if ($today_zero < $signin_log['last_signin_time'] && $signin_log['last_signin_time'] < ($today_zero+(60*60*24)) )
        {
            $this->weberror(self::THIS_ACTION_ERROR,"你今日已经签过到咯");
        }else{
            M()->startTrans();
            //如果是1号,将其设置为0
            if ($time['mday'] ==1){
                $updateData = array(
                    'uid'=>$this->uid,
                    'cont_days' => 1,
                    'last_signin_time' => time()
                );
                $update = M('signin')->add($updateData);
                $gold = $this->get_reward_goldcoin($this->uid,'sign_days');
            }else{
                // 如果不是1号判断有没有连续签到,具体方法是判断昨天有没有签到,如果签到了,连续签到次数加一,如果没有签到,连续次数归一
                if ( ($today_zero-24*60*60) < $signin_log['last_signin_time']  && $signin_log['last_signin_time'] < $today_zero )
                {
                    $updateData = array(
                        'uid'=>$this->uid,
                        'cont_days' => $signin_log['cont_days']+1,
                        'last_signin_time' => time()
                    );
                    $update = M('signin')->add($updateData);
                    $cont_days = $signin_log['cont_days']+1; //连续签到天数
                   
                    switch ($cont_days)
                    {
                        case 7 : $gold = $this->get_reward_goldcoin($this->uid,'sign_7days');break;
                        case 15 : $gold = $this->get_reward_goldcoin($this->uid,'sign_15days');break;
                        case $month_have_day : $gold = $this->get_reward_goldcoin($this->uid,'sign_1month');break;
                        default:$gold = $this->get_reward_goldcoin($this->uid,'sign_days');
                    }
                }else{ //昨天没有签到
                    $updateData = array(
                        'uid'=>$this->uid,
                        'cont_days' => 1,
                        'last_signin_time' => time()
                    );
                    $update = M('signin')->add($updateData);
                    $gold = $this->get_reward_goldcoin($this->uid,'sign_days');
                }
            }

            if($update && $gold){
                M()->commit();
                $LastData = M('signin')->where(array('uid'=>$this->uid))->order("id desc")->find();
                if ($LastData['cont_days'] == $month_have_day){
                    $returnGold = M("m_config")->where(array("ckey"=>"sign_1month"))->getField("cvalue");
                }elseif ($LastData['cont_days'] == 15){
                    $returnGold = M("m_config")->where(array("ckey"=>"sign_15days"))->getField("cvalue");
                }elseif ($LastData['cont_days'] == 7){
                    $returnGold = M("m_config")->where(array("ckey"=>"sign_7days"))->getField("cvalue");
                }else{
                    $returnGold = M("m_config")->where(array("ckey"=>"sign_days"))->getField("cvalue");
                }
                $this->websuccess(self::OUTPUT_SUCCESS,'恭喜你获得 '.$returnGold.'享金');
            }else{
                M()->rollback();
                $this->weberror(self::THIS_ACTION_ERROR,"签到失败");
            }
        }
    }
    
    
        /**
     * 获得签到记录
     */
    public function getsignin()
    {
         $this->uid_exist();
        // $this->uid = 505;
        $time = getdate();
        $today_zero = mktime(0,0,0,$time['mon'],$time['mday'],$time['year']);
        $signin_log = M('signin')->where(array('uid'=>$this->uid))->order("id desc")->find();
        $count = M('signin')->where(array('uid'=>$this->uid))->count();
        //一个月有多少天
        $month_have_day = date("t",strtotime($time['year']."-".$time['mon']));
      
        //今天是否已经签到
        if ($today_zero < $signin_log['last_signin_time'] && $signin_log['last_signin_time'] < ($today_zero+(60*60*24)) )
        {
            $issignin = true;
        }else{
            $issignin = false;
        }
        $records = M('signin')->where(array('uid'=>$this->uid))->select();
        $golds = 0;
        foreach ($records as $record)
        {
            $month_have_day = date("t",$record['last_signin_time']);
            switch ($record['cont_days'])
            {
                case 7:$golds+=100;break;
                case 15:$golds+=200;break;
                case $month_have_day:$golds+=300;break;
                default:$golds+=20;
            }
        }
        $data = array(
          'year'=>$time['year'],
          'month'=>$time['mon'],
          'cont_days' =>$signin_log['cont_days'],
          'month_have_days'=>$month_have_day,
          'count'=>$count,
          'issignin'=>$issignin,
          'gold'=>$golds
        );
        $this->websuccess(self::OUTPUT_SUCCESS,"返回的数据",$data);
    }
    

另外一种实现方法:redis的bitmap

通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。8个bit可以组成一个Byte,所以bitmap本身会极大的节省储存空间。

  • 考虑到每月初需要重置连续签到次数,按用户每月存一条签到数据(也可以每年存一条数据)。

  • Key的格式为u:sign:uid:yyyyMM,Value则采用长度为4个字节(32位)的位图(最大月份只有31天)。
    是32个0101011111111111的字母,也可以设置40位(也就是40个0,1)

  • 位图的每一位代表一天的签到,1表示已签,0表示未签。

例如u:sign:1000:201902表示ID=1000的用户在2019年2月的签到记录。

# 用户2月17号签到
SETBIT u:sign:1000:201902 16 1 # 偏移量是从0开始,所以要把17减1

# 检查2月17号是否签到
GETBIT u:sign:1000:201902 16 # 偏移量是从0开始,所以要把17减1

# 统计2月份的签到次数
BITCOUNT u:sign:1000:201902

# 获取2月份前28天的签到数据
BITFIELD u:sign:1000:201902 get u28 0

# 获取2月份首次签到的日期
BITPOS u:sign:1000:201902 1 # 返回的首次签到的偏移量,加上1即为当月的某一天
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值