<?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. Vue—非父子组件间的传值(Bus/发布订阅模式/观察者模式/总线)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. Leveldb--Slice

    http://www.kuqin.com/database/20110919/265041.html Slice非常简单的数据结构,它包括length和一个指向外部字节数组的指针.为什么使用Slice ...

  3. 从建立yum仓库到搭建ftp以及http服务

    1 什么是yum仓库 yum工作需要依赖C/S架构工作模式的文件服务器,服务器中存放了yum工作时所需的程序包.yum接收到需要安装的程序包的名称之后,通过文件共享协议(或者文件传输协议),在配置文件 ...

  4. CentOS 5.5编译安装lnmp

    如果是安装Centos6.5记得Perl是必选的,否则无法安装VMWare Tools!!!!切记 如果出现make错误需要安装其他软件,装好后  make clean   make install ...

  5. Add JWT Bearer Authorization to Swagger and ASP.NET Core

    Add JWT Bearer Authorization to Swagger and ASP.NET Core     If you have an ASP.NET Core web applica ...

  6. spark复习笔记(7):sparkSQL

    一.saprkSQL模块,使用类sql的方式访问Hadoop,实现mr计算,底层使用的是rdd 1.hive //hadoop  mr  sql 2.phenoix //hbase上构建sql的交互过 ...

  7. C# List<object> 按特定字段排序

    using System; using System.Collections; using System.Collections.Generic; using System.Linq; using S ...

  8. IC设计流程介绍

    芯片设计分为前端设计和后端设计,前端设计(也称逻辑设计)和后端设计(也称物理设计)并没有统一严格的界限,涉及到与工艺有关的设计就是后端设计. 1. 规格制定        芯片规格,也就像功能列表一样 ...

  9. 5-基于TMS320C6678+XC7K325T的6U CPCIe高性能处理平台

    基于TMS320C6678+XC7K325T的6U CPCIe高性能处理平台 一.板卡概述      本板卡系自主研发,基于CPCI 6U架构,符合CPCI2.0标准.采用 DSP TMS320C66 ...

  10. pandas数据读取(DataFrame & Series)

    1.pandas数据的读取 pandas需要先读取表格类型的数据,然后进行分析 数据说明 说明 pandas读取方法 csv.tsv.txt 用逗号分割.tab分割的纯文本文件 pd.read_csv ...