thinkphp:redis+lua实现短信发送频率限制(thinkphp v6.0.12LTS)
一,配置:
.env中
[REDIS0] TYPE = redis HOST = 127.0.0.1 PORT = 6379 PASSWORD =
二,php代码:
1,lib\util\SmsRateUtil.php
<?php namespace app\lib\util; //短信验证码发送频率 class SmsRateUtil { //redis连接 private $redis; //60秒内不允许重复发送 private $sendSeconds = "60"; //一天内最多发10条 private $dayCount = "10"; //构造 public function __construct($redis){ $this->redis = $redis; } /* 用lua脚本实现访问redis保存访问次数 KEYS[1] : 主键,此处是手机号 KEYS[2] : 主键过期的秒数,如果主键存在,表示不允许再次发送 KEYS[3]: 每手机号每天时间内最多允许发送的条数 */ function setRate($mobile) { $lua = <<<SCRIPT local key = KEYS[1] local keyseconds = tonumber(KEYS[2]) local daycount = tonumber(KEYS[3]) local keymobile = 'SmsAuthKey:'..key local keycount = 'SmsAuthCount:'..key --redis.log(redis.LOG_NOTICE,' keyseconds: '..keyseconds..';daycount:'..daycount) local current = redis.call('GET', keymobile) --redis.log(redis.LOG_NOTICE,' current: keymobile:'..current) if current == false then --redis.log(redis.LOG_NOTICE,keymobile..' is nil ') local count = redis.call('GET', keycount) if count == false then redis.call('SET', keycount,1) redis.call('EXPIRE',keycount,86400) redis.call('SET', keymobile,1) redis.call('EXPIRE',keymobile,keyseconds) return '1' else local num_count = tonumber(count) if num_count+1 > daycount then return '2' else redis.call('INCRBY',keycount,1) redis.call('SET', keymobile,1) redis.call('EXPIRE',keymobile,keyseconds) return '1' end end else --redis.log(redis.LOG_NOTICE,keymobile..' is not nil ') return '0' end SCRIPT; $key = $mobile; //执行lua脚本 $sequence = $this->redis->eval($lua, [$key,$this->sendSeconds,$this->dayCount], 3); //检查是否出错 $luaError = $this->redis->getLastError(); if (isset($luaError)) { // print_r($luaError); } //返回 return $sequence; } }
2,从controller中调用:
class Sms extends BaseController { //redis连接 private $redis; //构造 public function __construct(App $app = null){ //继承父类的构造方法 parent::__construct($app); //创建连接 $redis = new \Redis(); $port = env('redis0.port', '6379'); $port = intval($port); $redis->connect(env('redis0.host', '127.0.0.1'),$port); $redis->select(0); $this->redis = $redis; } //判断是否可以发送短信验证码 public function rate() { //得到参数 $mobile = $this->request->param('mobile','','string'); echo "mobile:".$mobile.":<br/>"; //判断是否可以发送 $rate = new SmsRateUtil($this->redis); $ret = $rate->setRate($mobile); echo "ret:".$ret.":<br/>"; //返回的说明信息 $res = ""; if ($ret == '1') { $res = "可以发短信"; } else if ($ret == '0') { $res = "请超过60秒之后再发短信"; } else if ($ret == '2') { $res = "当前手机号本日内发送数量已超限制"; } else { $res = "发生错误"; } echo "res:".$res.":<br/>"; }
三,测试效果
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
原文: https://blog.imgtouch.com/index.php/2023/06/05/thinkphp-redis-lua-shi-xian-duan-xin-fa-song-pin-lyu-xian/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
或: https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
四,查看thinkphp的版本:
liuhongdi@lhdpc:/data/php/imgtouch$ php think version v6.0.12LTS