feat: 增加IP限流器
This commit is contained in:
89
extend/system/RateLimiter.php
Normal file
89
extend/system/RateLimiter.php
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace system;
|
||||||
|
|
||||||
|
use support\Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流器
|
||||||
|
* Class RateLimiter
|
||||||
|
* @package system
|
||||||
|
*/
|
||||||
|
class RateLimiter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 基础限流名
|
||||||
|
*/
|
||||||
|
const TOKEN_LIMITER = 'token_limiter_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌桶限流名
|
||||||
|
*/
|
||||||
|
const RATE_LIMIT_BUCKET = 'rate_limit_bucket_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础限流器
|
||||||
|
* @param string $name
|
||||||
|
* @param int $rate
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function baseLimit(string $name, int $rate = 10): bool
|
||||||
|
{
|
||||||
|
$bucketKey = self::TOKEN_LIMITER . $name;
|
||||||
|
$bucketData = Cache::get($bucketKey);
|
||||||
|
if (!$bucketData) {
|
||||||
|
$bucketData = [
|
||||||
|
'tokens' => $rate,
|
||||||
|
'lastRefillTime' => time()
|
||||||
|
];
|
||||||
|
Cache::set($bucketKey, $bucketData, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentTime = time();
|
||||||
|
$timePassed = $currentTime - $bucketData['lastRefillTime'];
|
||||||
|
$tokensToAdd = $timePassed * $rate;
|
||||||
|
$tokensToAdd = min($tokensToAdd, $rate);
|
||||||
|
$bucketData['tokens'] += $tokensToAdd;
|
||||||
|
$bucketData['lastRefillTime'] = $currentTime;
|
||||||
|
if ($bucketData['tokens'] <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bucketData['tokens']--;
|
||||||
|
Cache::set($bucketKey, $bucketData, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 令牌桶限流器
|
||||||
|
* @param string $name
|
||||||
|
* @param int $rate
|
||||||
|
* @param int $capacity
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function BucketLimit(string $name, int $rate = 10, int $capacity = 100): bool
|
||||||
|
{
|
||||||
|
$bucketKey = self::RATE_LIMIT_BUCKET . $name;
|
||||||
|
$bucketData = Cache::get($bucketKey);
|
||||||
|
if (!$bucketData) {
|
||||||
|
$bucketData = [
|
||||||
|
'tokens' => $capacity,
|
||||||
|
'lastRefillTime' => time()
|
||||||
|
];
|
||||||
|
Cache::set($bucketKey, $bucketData);
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentTime = time();
|
||||||
|
$elapsedTime = $currentTime - $bucketData['lastRefillTime'];
|
||||||
|
$refillTokens = (int)($elapsedTime * $rate);
|
||||||
|
$bucketData['tokens'] = min($bucketData['tokens'] + $refillTokens, $capacity);
|
||||||
|
$bucketData['lastRefillTime'] = $currentTime;
|
||||||
|
if ($bucketData['tokens'] <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bucketData['tokens']--;
|
||||||
|
Cache::set($bucketKey, $bucketData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user