diff --git a/extend/catcher/library/rate/Redis.php b/extend/catcher/library/rate/Redis.php index 09268b1..be6fd62 100644 --- a/extend/catcher/library/rate/Redis.php +++ b/extend/catcher/library/rate/Redis.php @@ -14,9 +14,18 @@ use think\facade\Cache; trait Redis { + /** + * @var \Redis + */ protected $redis = null; - protected function getRedis() + /** + * 返回 redis + * + * @time 2020年07月02日 + * @return \Redis + */ + protected function getRedis(): \Redis { if (!$this->redis) { $this->redis = Cache::store('redis')->handler(); diff --git a/extend/catcher/library/rate/SlidingWindowLimit.php b/extend/catcher/library/rate/SlidingWindowLimit.php index ef90e0a..071fb9e 100644 --- a/extend/catcher/library/rate/SlidingWindowLimit.php +++ b/extend/catcher/library/rate/SlidingWindowLimit.php @@ -8,3 +8,64 @@ // +---------------------------------------------------------------------- // | Author: JaguarJack [ njphper@gmail.com ] // +---------------------------------------------------------------------- +namespace catcher\library\rate; + +use catcher\exceptions\FailedException; + +/** + * 滑动窗口 + * + * Class SlidingWindowLimit + * @package catcher\library\rate + */ +class SlidingWindowLimit +{ + use Redis; + + protected $key; + + protected $limit = 10; + + /** + * @var int + */ + protected $window = 5; + + public function __construct($key) + { + $this->key = $key; + } + + + public function overflow() + { + $now = microtime(true) * 1000; + + $redis = $this->getRedis(); + // 开启管道 + $redis->pipeline(); + // 去除非窗口内的元素 + $redis->zremrangeByScore($this->key, 0, $now - $this->window*1000); + // 获取集合内的所有元素数目 + $redis->zcard($this->key); + // 增加元素 + $redis->zadd($this->key, $now, $now); + // 设置过期 + $redis->expire($this->key, $this->window); + // 执行管道内命令 + $res = $redis->exec(); + + if ($res[1] > $this->limit) { + throw new FailedException('访问限制'); + } + + return true; + } + + public function setWindow($time) + { + $this->window = $time; + + return $this; + } +} \ No newline at end of file