Rate Limiter
Webman Rate Limiter supports annotation-based rate limiting. It supports apcu, redis, and memory drivers.
Source Code Address
https://github.com/webman-php/rate-limiter
Installation
composer require webman/rate-limiter
Usage
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;
class UserController
{
#[RateLimiter(limit: 10)]
public function index(): string
{
// The default rate limit is based on IP, with the default time unit being 1 second
return 'Up to 10 requests per second per IP';
}
#[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
public function search(): string
{
// key: RateLimiter::UID, rate limiting is done based on user ID, requiring session('user.id') to be non-empty
return 'Up to 100 searches per user every 60 seconds';
}
#[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'Each person can only send 1 email per minute')]
public function sendMail(): string
{
// key: RateLimiter::SID, rate limiting is done based on session_id
return 'Email sent successfully';
}
#[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Today’s coupons have all been distributed, please come back tomorrow')]
#[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'Each user can only receive one coupon per day')]
public function coupon(): string
{
// key: 'coupon', where coupon is a custom key, meaning that rate limiting is globally conducted based on the coupon key, allowing up to 100 coupons to be sent per day
// At the same time, rate limiting is based on user ID, allowing each user to receive one coupon per day
return 'Coupon sent successfully';
}
#[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Each mobile number can receive up to 5 messages per day')]
public function sendSms2(): string
{
// When the key is a variable, you can get it using the [class, static method] format, for example, [UserController::class, 'getMobile'] will call the getMobile() method of UserController to get its return value as the key
return 'SMS sent successfully';
}
/**
* Custom key to get mobile number; must be a static method
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'Rate limit exceeded', exception: RuntimeException::class)]
public function testException(): string
{
// The default exception when exceeded is Webman\RateLimiter\RateLimitException, which can be changed via the exception parameter
return 'ok';
}
}
Notes
- The default time interval is 1 second
- You can set the time interval using ttl, for example,
ttl:60
means 60 seconds - The default rate limiting dimension is based on IP (default
127.0.0.1
has no rate limit, see the configuration section below) - It supports built-in IP rate limiting, UID rate limiting (requiring
session('user.id')
to be non-empty), and SID rate limiting (based onsession_id
) - If you are using nginx as a proxy, for IP rate limiting you need to forward the
X-Forwarded-For
header, see nginx proxy - When the limit is exceeded, a
Webman\RateLimiter\RateLimitException
exception will be triggered, and you can customize the exception class usingexception:xx
- When an exception is triggered due to exceeding the limit, the default error message is
Too Many Requests
, which can be customized usingmessage:xx
- The default error message can also be modified through Localization, for Linux, refer to the following commands
composer require symfony/translation mkdir resource/translations/zh_CN/ -p echo "<?php return [ 'Too Many Requests' => '请求频率受限' ];" > resource/translations/zh_CN/messages.php php start.php restart
Interface
Sometimes developers want to directly call the rate limiter from the code, as shown in the code below
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// Here mobile is used as the key
Limiter::check($mobile, 5, 24*60*60, 'Each mobile number can receive up to 5 messages per day');
return 'SMS sent successfully';
}
}
Configuration
config/plugin/webman/rate-limiter/app.php
<?php
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// Requests from these IPs will not be rate limited (only effective when the key is RateLimiter::IP)
'ip_whitelist' => [
'127.0.0.1',
],
];
- enable: Whether to enable rate limiting
- driver: One of
auto
,apcu
,memory
,redis
, when usingauto
, it will automatically select one fromapcu
andmemory
- stores:
redis
configuration, whereconnection
corresponds to thekey
inconfig/redis.php
- ip_whitelist: Whitelisted IPs will not be rate limited (only effective when the key is
RateLimiter::IP
)
Driver Selection
memory
-
Introduction
No extensions are required, and it offers the best performance. -
Usage Limitations
Rate limiting is only effective within the current process; rate limiting data is not shared across multiple processes, nor does it support cluster rate limiting. -
Applicable Scenarios
Windows development environments; businesses that do not require strict rate limiting; resisting CC attacks.
apcu
-
Installation of Extension
You need to install the apcu extension and set in php.iniapc.enabled=1 apc.enable_cli=1
If you do not know the location of php.ini, you can find it using the command
php --ini
-
Introduction
Slightly lower performance than memory, supports multi-process sharing of rate limiting data. -
Usage Limitations
Does not support clustering. -
Applicable Scenarios
Any development environment; online single machine rate limiting scenarios; scenarios where strict rate limiting is not required in a cluster; resisting CC attacks.
redis
-
Dependencies
You need to install the redis extension and install the Redis component, with the installation commandcomposer require -W illuminate/redis illuminate/events
-
Introduction
Performance is lower than apcu and supports both single machine and cluster precise rate limiting. -
Applicable Scenarios
Development environments; online single machine environments; cluster environments.