php实现签到功能
連續簽到送積分
1.數據表設計
積分表
簽到表
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=utf82.代碼
/*** 簽到*/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號,將其設置為0if ($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即為當月的某一天總結
- 上一篇: php的socket通信
- 下一篇: thinkphp6集成JWT