* @version : HUOSDK 8.0 */ namespace huolib\sms; use huolib\constant\CommonConst; use huolib\status\MemberStatus; use huolib\tool\StrUtils; use think\App; use think\Cache; /** * 短信积累 */ class Sms { protected $options = []; protected $tag; protected $sms_setting = []; /* 短信设置 */ protected $key = ''; protected $sms_content = [ 'send_time' => 0,/* 发送时间戳 */ 'renew_time' => 0,/* 可以重新发送时间 */ 'expire_time' => 0,/* 10min钟内过期 */ 'end_time' => 0,/* 第一次发送后到end_time前发送时间 */ 'send_cnt' => 0,/* 今日发送次数 */ 'sms_code' => 0,/* 短信验证码 */ 'sms_type' => 0,/* 短信发送类型 */ ]; protected $max_cnt = 50; /* 单个手机号每日发送最大数量 */ protected $expire_time = 600; /* 过期时间 */ protected $end_time = CommonConst::CONST_DAY_SECONDS; /* 结束时间 */ protected $renew_time = 120; /* 可以重新发送时间 */ public function __construct() { /* 获取短信设置 */ $_conf_file = GLOBAL_CONF_PATH."extra/sms/setting.php"; if (file_exists($_conf_file)) { $_sms_setting = include $_conf_file; foreach ($_sms_setting as $_key => $_val) { if (0 != $_val) { $this->sms_setting[$_key] = $_val; } } } } /** * 标准返回 * * @param $code * * @return mixed */ private function getReturnByCode($code) { $_rdata['code'] = $code; $_rdata['msg'] = MemberStatus::getMsg($code); $_rdata['data'] = []; return $_rdata; } /** * 发送短信验证码 * * @param $mobile * @param $type * * @return mixed */ public function send($mobile, $type) { /* 检查手机号格式是否正确 */ $_rs = StrUtils::checkPhone($mobile); if (false == $_rs) { return $this->getReturnByCode(MemberStatus::PHONE_ERROR); } $_rs = SmsType::checkSmsType($type); if (false == $_rs) { return $this->getReturnByCode(MemberStatus::CODE_TYPE_ERROR); } $_is_not_send = $this->isNotSend($mobile); if (true !== $_is_not_send) { /* 手机短信码已发送 */ return $this->getReturnByCode(MemberStatus::PHONE_HAS_SEND); } $_sms_code = $this->genSmsCode(); $_send_rs = $this->sendExec($mobile, $type, $_sms_code); if (MemberStatus::NO_ERROR != $_send_rs) { /* 验证码发送失败 */ return $this->getReturnByCode($_send_rs); } $_sms_content = $this->get($mobile); $_end_time = strtotime(date('Y-m-d')) + $this->end_time; if (empty($_sms_content)) { $_sms_content = $this->sms_content; $_sms_content['end_time'] = $_end_time; } $_sms_content['send_time'] = time(); $_sms_content['renew_time'] = $_sms_content['send_time'] + $this->renew_time; $_sms_content['expire_time'] = $_sms_content['send_time'] + $this->expire_time; $_sms_content['send_cnt']++; $_sms_content['sms_code'] = $_sms_code; $_sms_content['sms_type'] = $type; $this->set($mobile, $_sms_content); /* 验证码发送成功 */ return $this->getReturnByCode(MemberStatus::NO_ERROR); } /** * 校验手机验证码 * * @param $mobile * @param $sms_code * @param $type * * @return mixed */ public function check($mobile, $sms_code, $type) { // TODO: wuyonghong 2018/4/26 添加校验 if (APP::$debug) { return $this->getReturnByCode(MemberStatus::NO_ERROR); } /* 检查手机号格式是否正确 */ $_rs = StrUtils::checkPhone($mobile); if (false == $_rs) { return $this->getReturnByCode(MemberStatus::PHONE_ERROR); } $_rs = SmsType::checkSmsType($type); if (false == $_rs) { return $this->getReturnByCode(MemberStatus::CODE_TYPE_ERROR); } $_sms_content = $this->get($mobile); if (empty($_sms_content) || empty($_sms_content['sms_code'])) { /* 查询是否发送过验证码 */ return $this->getReturnByCode(MemberStatus::CODE_NOT_SEND); } $_now_time = time(); if (empty($_sms_content['expire_time']) || ($_sms_content['expire_time'] < $_now_time && !APP::$debug)) { /* 查询验证码是否过期 */ $_sms_content['sms_type'] = ''; $_sms_content['sms_code'] = ''; $_sms_content['send_time'] = 0; $_sms_content['renew_time'] = 0; $_sms_content['expire_time'] = 0; $this->set($mobile, $_sms_content); return $this->getReturnByCode(MemberStatus::CODE_IS_EXPIRED); } if ($_sms_content['sms_code'] != $sms_code) { /* 验证码错误 */ return $this->getReturnByCode(MemberStatus::CODE_ERROR); } if (!APP::$debug) { /* 调试模式可以一直验证 */ /* 验证成功 */ $_sms_content['sms_type'] = ''; $_sms_content['sms_code'] = ''; $_sms_content['send_time'] = 0; $_sms_content['renew_time'] = 0; $_sms_content['expire_time'] = 0; $this->set($mobile, $_sms_content); } return $this->getReturnByCode(MemberStatus::NO_ERROR); } /** * 生成短信验证码 * * @return string */ private function genSmsCode() { $_sms_code = rand(100000, 999999); return $_sms_code.''; } /** * 获取Cache key * * @param string $mobile * * @return string */ public function getKey($mobile = '') { return 'sms_'.$mobile; } /** * 判断短信是否发送 * * @param $mobile * * @return mixed true 表示未发送 其他 表示已发送 */ private function isNotSend($mobile) { $_sms_content = $this->get($mobile); if (empty($_sms_content)) { return true; } $_now_time = time(); if ($_sms_content['end_time'] >= $_now_time) { /* 超过最后时间,删除所有 */ $this->clear($mobile); return true; } if ($_sms_content['renew_time'] > $_now_time) { /* 未超过限定时间 */ return $this->getReturnByCode(MemberStatus::PHONE_HAS_SEND); } if ($_sms_content['send_cnt'] >= $this->max_cnt) { /* 每日最多发送次数 */ return $this->getReturnByCode(MemberStatus::PHONE_SEND_MORE); } return true; } /** * 获取内容 * * @param $mobile * * @return mixed */ private function get($mobile) { $_key = $this->getKey($mobile); return Cache::get($_key); } /** * 设置键值 * * @param $mobile * @param $data */ private function set($mobile, $data) { $_key = $this->getKey($mobile); Cache::set($_key, $data); } private function clear($mobile) { $_key = $this->getKey($mobile); Cache::rm($_key); } /** * 执行发送短信验证码 * * @param $mobile * @param $type * @param $sms_code * * @return bool */ private function sendExec($mobile, $type, $sms_code) { $_rs_code = MemberStatus::NO_ERROR; foreach ($this->sms_setting as $_key => $_val) { $_class_name = '\\huolib\\sms\\driver\\'.ucwords($_key); $_class = new $_class_name(); $_rs_code = $_class->send($mobile, $type, $sms_code); if (MemberStatus::NO_ERROR == $_rs_code) { break; } } return $_rs_code; } /** * @return int */ public function getMaxCnt() { return $this->max_cnt; } /** * @param int $max_cnt */ public function setMaxCnt($max_cnt) { $this->max_cnt = $max_cnt; } /** * @return int */ public function getExpireTime() { return $this->expire_time; } /** * @param int $expire_time */ public function setExpireTime($expire_time) { $this->expire_time = $expire_time; } /** * @return int */ public function getRenewTime() { return $this->renew_time; } /** * @param int $renew_time */ public function setRenewTime($renew_time) { $this->renew_time = $renew_time; } }