<?php
/**
* create by jxkshu
* Date 2017-09-28
* 用户签到领取红包
*/
/**
Redis
set: key signed:user:mark 标记已签到用户
val user_id zset key signed:user:today:share:num 记录当天用户分享的次数,凌晨4点删除
score 分享的次数
val 用户ID
zset key signed:user:today:replenishment:num 记录当天用户已经补签的次数,凌晨4点删除
score 当天补签的次数
val 用户ID
*/
header("content-type:text/html;charset=utf-8");
require_once('api.base.php'); class m_signed extends base
{
private $redis = null;
private $log_dir = null; public function __construct(){
parent::__construct(); $this->init();
// parent::signer($_POST);
// parent::tokengoon($_POST); // 连接redis
$this->redis = new MyRedis;
$this->redis = $this->redis->getRedisCli(); // 创建单个文件夹
$this->log_dir = __DIR__ . '/../log/return_red_envelope/signed/';
if(!is_dir($this->log_dir)):
mkdir($this->log_dir);
chmod($this->log_dir, 0777);
endif;
} /**
* 用户 签到或者补签
* @param array $post 客户端传递的数据
* @return array 抢红包后的数据
*/
public function signed($post){ parent::signer($_POST);
parent::tokengoon($_POST);
$user_id = (int)trim($post['user_id']); // 延迟0.2秒,防并发
usleep(200000);
// 判断用户是签到还是补签
if( empty($post['type']) || $post['type']==0):
// 判断用户是否已签
$key = 'signed:user:mark';
if(($this->redis->sIsMember($key, $user_id))):
return ['status'=>'fail', 'msg'=>'已签到'];
else:
// 二次判断用户是否已经签到
$day_start = strtotime(date('Y-m-d 0:0:0',time()));
$day_end = strtotime(date('Y-m-d 0:0:0',time()))+86399;
$sql = "SELECT count(id) as total from sign_red_envelopes where uid=$user_id and time>=$day_start and time<=$day_end and amount>0";
$sign_num = (int) parent::result_first($sql);
if($sign_num>0):
return ['status'=>'fail', 'msg'=>'已签到'];
endif;
endif;
// 用户签到
$res = $this->userSigned($user_id, $post['time']);
else:
if( $post['time'] >= strtotime(date('Y-m-d 0:0:0'))):
return ['status'=>'fail', 'msg'=>'日期错误'];
endif;
$res = $this->userReplenishment($user_id, $post['time']);
endif; if($res['status']=='fail'):
$this->writeLog(__FILE__, __LINE__, $res['msg']);
endif;
return $res;
} /**
* 用户补签
* @param int $user_id 用户ID
* @param int $time 用户签到时间
* @return array status:状态、msg:信息、amount:奖励金额、replenishment_num:剩余可以补签的次数
*/
protected function userReplenishment($user_id, $time){ // 获取用户当天已经补签的次数
$replenishment = $this->redis->zScore('signed:user:today:replenishment:num', $user_id);
// 获取用户当天线下消费额度
$tim = date('Ymd');
$sql = "SELECT sum(amount) as total_amount FROM payinfo where pay_dateint='$tim' and uid=$user_id and status=1 and is_ol_verify=0";
$total_amount = (int) parent::result_first($sql); // 判断用户补签次数是否超出
$total_amount = (int) ($total_amount/58);
$replenishment = (int)$replenishment;
if( $total_amount<=$replenishment ):
return ['status'=>'fail', 'msg'=>'补签失败,消费额度不足!'];
endif; // 补签次数累加1
$res = $this->redis->zIncrBy('signed:user:today:replenishment:num', 1, $user_id);
if(empty($res)):
return ['status'=>'fail', 'msg'=>'补签次数累加失败!'];
endif; //获取用户补签奖励金额
$amount = mt_rand(50, 100) / 100; // 记录用户补签信息
$data = [
'uid' => $user_id,
'type' => 1,
'amount' => $amount,
'time' => $time,
];
$res = parent::insert('sign_red_envelopes', $data);
if(empty($res)):
return ['status'=>'fail', 'msg'=>'写入补签红包记录数据库失败!'];
endif; // 累加用户签到奖励
$sql = "UPDATE userinfo SET sign_reward=(sign_reward+$amount),total_sign_reward=(total_sign_reward+$amount) where id=$user_id limit 1";
$res = parent::query($sql);
if(empty($res)):
return ['status'=>'fail', 'msg'=>'累加用户补签奖励失败!'];
endif;
return ['status'=>'success', 'msg'=>'用户补签成功', 'amount'=>$amount, 'replenishment_num'=>($total_amount-$replenishment)];
} /**
* 用户签到
* @param int $user_id 用户ID
* @param int $time 用户签到时间
* @return array
*/
protected function userSigned($user_id, $time){ // 获取签到奖励金额
$amount = self::getSignedAmount($user_id);
$data = [
'uid' => $user_id,
'amount' => $amount,
'time' => $time,
];
$res = parent::insert('sign_red_envelopes', $data);
if(empty($res)):
return ['status'=>'fail', 'msg'=>'写入签到红包记录数据库失败!'];
endif; // 累加用户签到奖励
$sql = "UPDATE userinfo SET sign_reward=(sign_reward+$amount),total_sign_reward=(total_sign_reward+$amount) where id=$user_id limit 1";
$res = parent::query($sql);
if(empty($res)):
return ['status'=>'fail', 'msg'=>'累加用户签到奖励失败!'];
endif; // 标记用户已经签到
$res = $this->redis->sAdd('signed:user:mark', $user_id);
return ['status'=>'success', 'amount'=>$amount];
} /**
* 获取用户签到奖励金额
* @param int $user_id
* @return float 奖励金额
*/
protected static function getSignedAmount($user_id){ // 判断用户是不是第一次签到
$sql = "SELECT count(id) as total FROM sign_red_envelopes where uid=$user_id limit 1";
$total = parent::result_first($sql); // 获取签到奖励金额
if(empty($total)):
// 首次签到
$amount = mt_rand(1,2);
else:
//提升红包额度
$sql = "SELECT share_num from userinfo where id=$user_id limit 1";
$share_num = parent::result_first($sql);
$share_num = ($share_num>20 ? 20 : $share_num);
$min = (0.1 + (0.1 * ($share_num*0.1))) * 100;
$max = (1 + (1*($share_num*0.05))) * 100;
$max = ($max>200 ? 200 : $max); $amount = mt_rand($min, $max) / 100;
$amount = number_format($amount, 2);
endif; return $amount;
} // -------------------------------- 用户将奖励提转到58券 /**
* 用户将奖励提转到58券
* @param array $post=>user_id 用户id
* @return array
*/
public function rewardTo58voucher($post){ parent::signer($_POST);
parent::tokengoon($_POST);
// 获取用户已经累计的签到红包
$sql = 'SELECT id,sign_reward FROM userinfo WHERE id='.$post['user_id'].' limit 1';
$userinfo = parent::fetch_first($sql);
if($userinfo['sign_reward']<20):
return ['errcode'=>'44','msg'=>'代金券未满20'];
endif; // 红包转换成58券
$sql='UPDATE userinfo SET sign_reward=0, red_reward=(red_reward+'.$userinfo['sign_reward'].') WHERE id='.$post['user_id'].' LIMIT 1';
$res = parent::query($sql);
if(empty($res)):
return ['errcode'=>'3','msg'=>'服务器异常!'];
endif;
// 记录行为到红包
$tim = time();
$data = [
'uid'=>$post['user_id'],
'orderid'=>'',
'amount'=>$userinfo['sign_reward'],
'packet_status'=>1,
'receive_time'=>date('Y-m-d H:i:s', $tim),
'packet_type'=>6,
'add_time'=>date('Y-m-d H:i:s', $tim),
'dateint'=>date('Ymd', $tim),
];
$res = parent::insert('redpacket', $data);
if(empty($res)):
return ['errcode'=>'400','msg'=>'提转成功!但记录提转信息失败!'];
endif;
return ['errcode'=>0,'msg'=>'提转成功!'];
} /**
* 获取剩余补签次数
* @param int $user_id 用户ID
* @return array
*/
public function getSignCard($user_id){ parent::signer($_POST);
parent::tokengoon($_POST);
// 获取用户当天已经补签的次数
$replenishment = $this->redis->zScore('signed:user:today:replenishment:num', $user_id);
// 获取用户当天线下消费额度
$tim = date('Ymd');
//$sql = "SELECT sum(amount) as total_amount FROM payinfo where pay_dateint='$tim' and uid=$user_id and status=1 and (order_type=0 or order_type=4)";
$sql = "SELECT sum(amount) as total_amount FROM payinfo where pay_dateint='$tim' and uid=$user_id and status=1 "; $total_amount = (int) parent::result_first($sql); // 判断用户补签次数是否超出
$total_amount = (int) ($total_amount/58);
$replenishment = (int) $replenishment; return ['card_num'=>($total_amount - $replenishment)];
} // 用户分享朋友圈来提升签到红包额度
public function userShareAppToPeople($user_id){ parent::signer($_POST);
// 将分享次数暂时记录到redis,每天凌晨定时任务在写入数据库
$key = 'signed:user:today:share:num';
$res = $this->redis->zIncrBy($key, 1, $user_id);
return ['signed_num'=>$res];
} // 写日志
private function writeLog($fil, $row, $remarks=''){
$file = $this->log_dir . 'signed-'.date('Y-m').'.txt';
$content = $fil.' Line ' . $row . ' failed '.date('Y-m-d H:i:s')." $remarks \n\r";
file_put_contents($file, $content, FILE_APPEND);
} //---------------------------- 获取用户签到界面的信息 public function getSignPageInfo($post){ parent::signer($_POST);
parent::tokengoon($_POST);
$user_id = parent::parseuid($post);
$data = []; // 分享URL
$tim = time();
$salt = '58_life_circle_sign_share';
$sign = mb_strcut(md5('58_life_circle_sign_share'.$tim), 0, 6, 'utf8');
$data['share_url'] = 'http://api.licheepay.com/lzf/html/sign_share/h5.html?uid='.$user_id.'&time='.$tim.'&sign='.$sign;
// 广告图
$data['header_advert'] = [
// [
// 'img'=> 'http://adm.licheepay.com/upload/mall/1509331172.png',
// 'url'=> 'app_web_$$$https://s.click.taobao.com/7IlNyYw$$$',
// ],
// [
// 'img'=> 'http://adm.licheepay.com/upload/mall/1509523936.png',
// 'url'=> 'app_web_>>>http://mp.weixin.qq.com/s/BDSD_jDgCmMxfCdieLxtxg<<<',
// ],
[
'img'=> 'http://adm.licheepay.com/upload/img/ad/20170508161142.png',
'url'=> 'app_web_>>>http://mp.weixin.qq.com/s/BDSD_jDgCmMxfCdieLxtxg<<<',
], ];
// 获取累计签到奖励
$sql = 'SELECT sign_reward,total_sign_reward FROM userinfo WHERE id='.$user_id.' limit 1';
$temp_user_sign = parent::fetch_first($sql);
$data['sign_reward'] = $temp_user_sign['sign_reward'];
$data['total_sign_reward'] = $temp_user_sign['total_sign_reward']; // 签到奖励提取状态【是否可提取】
$data['extract_status'] = 0;
if($temp_user_sign['sign_reward']>=20):
$data['extract_status'] = 1;
endif; // 签到说明
$data['sign_explain'] = '1、签到后可抢代金券红包,满20券可用
2、用户每天可签到一次,每次可获得随机劵奖励
3、代金券每月15号自动清零,满20券请及时领取
4、线下消费满58元,可手动补签1次,当天有效
5、签到后分享好友,好友参与可提高次日红包金额'; // 签到状态
// 判断用户是否已签
$data['signed_status'] = 0;
$key = 'signed:user:mark';
if(($this->redis->sIsMember($key, $user_id))):
$data['signed_status'] = 1;
endif;
// // 二次判断用户是否已经签到 2017-11-01屏蔽
$day_start = strtotime(date('Y-m-d 0:0:0',time()));
$day_end = strtotime(date('Y-m-d 0:0:0',time()))+86399;
$sql = "SELECT count(id) as total from sign_red_envelopes where uid=$user_id and time>=$day_start and time<=$day_end and amount>0";
$sign_num = (int) parent::result_first($sql);
if($sign_num<1):
$data['signed_status'] = 0;
else:
$data['signed_status'] = 1;
endif; // 时间戳
$data['time'] = time();
return $data;
} // 获取用户签到信息日历
public function getUserSignInfoCalendar($post){ parent::signer($_POST);
parent::tokengoon($_POST);
$user_id = parent::parseuid($post); // 当前月份
$total_day = date('t');
$current_month = date('m');
$first_day = strtotime(date("Y-m-01"));
$last_day = $first_day + ($total_day*86400) - 1;
$sql = "SELECT FROM_UNIXTIME(time,'%e') as day,type
FROM sign_red_envelopes
WHERE uid=$user_id and time>=$first_day and time<=$last_day";
//获取用户签到信息
$sign_info = parent::fetch_all($sql);
// 获取用户补签卡
$card_num = $this->getSignCard($user_id);
$card_num = $card_num['card_num']; $today = date('d');
// 1:未签、 2:已签到、3:已补签 4:可补签、 5:漏签、 6:不可签、
$temp_current = [];
for ($i=$total_day; $i>0; $i--) {
$status = 0;
// 签到或者补签
foreach ($sign_info as $sign) {
if($sign['day']==$i):
$status = empty($sign['type']) ? 2 : 3;
break;
endif;
}
// 1:未签
if($status==0 && $i==$today):
$status = 1;
endif;
//4:可补签
if($status==0 && $i<$today && $card_num>0):
$status = 4;
$card_num--;
endif;
// 6:不可签
if($status==0 && $i>$today):
$status = 6;
endif;
// 5:漏签
if($status==0):
$status = 5;
endif;
$temp_current[$i] = $status;
} // 上月份
$last_month = date('m', time()) - 1;
if( $last_month<1 ):
$last_month = 12;
$time_str = (date('Y',time()) - 1) . '-12-01';
$total_day = date('t', strtotime($time_str));
$first_day = strtotime($time_str);
$last_day = $first_day + ($total_day*86400) - 1;
else:
$time_str = date('Y',time()) .'-'.$last_month.'-01';
$total_day = date('t', strtotime( $time_str));
$last_month = date('m', strtotime( $time_str));
$first_day = strtotime( $time_str);
$last_day = $first_day + ($total_day*86400) - 1;
endif;
$sql = "SELECT FROM_UNIXTIME(time,'%e') as day,type
FROM sign_red_envelopes
WHERE uid=$user_id and time>=$first_day and time<=$last_day";
//获取用户签到信息
$sign_info = parent::fetch_all($sql);
// 2:已签到、3:已补签 4:可补签、 5:漏签、
$temp_last = [];
for ($i=$total_day; $i>0; $i--) {
$status = 0;
// 签到或者补签
foreach ($sign_info as $sign) {
if($sign['day']==$i):
$status = empty($sign['type']) ? 2 : 3;
endif;
}
//可补签
if($status==0 && $card_num>0):
$status = 4;
$card_num--;
endif;
// 5:漏签
if($status==0):
$status = 5;
endif; $temp_last[$i] = $status;
} ksort($temp_current); //当前月份
ksort($temp_last); //上月份
$data = [
[
'month'=>$current_month,
'status' =>array_values($temp_current)
],
[
'month' =>$last_month,
'status'=>array_values($temp_last)
],
];
return $data;
} }//end

下载地址

php用户签到,领取红包的更多相关文章

  1. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  2. 基于Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  3. 记我的小网站发现的Bug之一 —— 某用户签到了两次

    1.故事背景 今天上午我忙完手中的事情之后突然想起来我还没签到,于是赶紧打开签到页面,刚点击了签到按钮,提示"签到成功,获得25阅读额度!",正准备退出浏览器,忽然发现签到列表有异 ...

  4. Redis实战篇(二)基于Bitmap实现用户签到功能

    很多应用上都有用户签到的功能,尤其是配合积分系统一起使用.现在有以下需求: 签到1天得1积分,连续签到2天得2积分,3天得3积分,3天以上均得3积分等. 如果连续签到中断,则重置计数,每月重置计数. ...

  5. 利用redis的bitmap实现用户签到功能

    一.场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 比如签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 显 ...

  6. java redis 实现用户签到功能(很普通简单的签到功能)

    业务需求是用户每天只能签到一次,而且签到后用户增加积分,所以把用户每次签到时放到redis 缓存里面,然后每天凌晨时再清除缓存,大概简单思想是这样的 直接看代码吧如下 @Transactional @ ...

  7. 用NSCalendar和UICollectionView自定义日历,并实现签到显示

    前一段时间因为工作需要实现了一个可以签到的日历,来记录一下实现的思路 效果如图:   这里的基本需求是: 1,显示用户某个月的签到情况,已经签到的日子打个圈,没有签到且在某个时间范围内的可以签到,其他 ...

  8. php实现签到功能

    首先我在数据库里建了两张表,一个是用户的积分表,一个是签到状态表,分来用来记录用户的积分数和先到状态 在用户签到状态表中我们有一个字段,last_sign_time,即上一次签到时间,每次可以签到的时 ...

  9. TOJ5398: 签到大富翁(简单模拟) and TOJ 5395: 大于中值的边界元素(数组的应用)

    Python代码!!! 5395 传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=53 ...

随机推荐

  1. raid10 五块硬盘/raid5(三块使用,两块备份)

    raid 10五块硬盘 第一步:在虚拟机中在添加五块硬盘 第二步:使用mdadm命令创建RAID10,名称为“/dev/md0/” -C代表创建操作,-v显示创建过程,-a yes检查RAID名称,- ...

  2. [Web 前端] 013 css 内外边距

    1. css 内间距 也称:"内补白"或"内补丁" 参数 释义 padding 检索或设置对象四边的内部边距,如 padding:10px; padding:5 ...

  3. 关于java的数组

    一定要写成 int[] arr = new int[30] 这样每个元素默认为0; 介样子的 如果写成 int[] arr = {1,2,3,4}; 那么他的长度就是4

  4. Acwing.835. Trie字符串统计(模板)

    维护一个字符串集合,支持两种操作: “I x”向集合中插入一个字符串x: “Q x”询问一个字符串在集合中出现了多少次. 共有N个操作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母 ...

  5. 51nod - 1586 - 约数和 - 打表 - 思维

    https://www.51nod.com/Challenge/Problem.html#problemId=1586 一眼看过去居然一点思路都没有的,一言不合就打表,打贡献表. #include & ...

  6. 大神级回答exists与in的区别

    google搜了一下,很多帖子,而且出发点不同,各有各的道理,但是有一个帖子讲的特别好: http://zhidao.baidu.com/question/134174568.html 忍不住在百度上 ...

  7. EasyUI之DataGrid分页

    第一步创建分页DataGrid <table id="dg"> <thead> <tr> <th data-options="f ...

  8. python学习笔记(13):python并发编程以及系统常用模块

    一.进程与线程 1.进程:程序的一次执行(程序装载入内存,系统分配资源运行).n 每个进程有自己的内存空间.数据栈等,只能使用进程间通讯,而不能直接共享信息 2.线程:所有线程运行在同一个进程中,共享 ...

  9. 20191115PHP cookie登入实例

    首先是登入页面 <form action="" method="post"> <input type="text" nam ...

  10. vue主动刷新页面及列表数据删除后的刷新方法

    在继刷新当前页面,重载页面数据那篇之后 那一篇 深入理解数据驱动 以上算是开发过程中的一个坑,用了一段时间,今天再读代码的时候,感觉被坑的很严重. 1. 获取列表方法 2.重新获取数据 3.这样再次调 ...