A free and easy-to-use rate limiter for PHP applications.
You need to limit network traffic access to a specific function in a specific timeframe. Rate limiting may help to stop some kinds of malicious activity such as brute force attacks, DDoS, and API abuse.
composer require snipershady/ratelimiter| Requirement | Version |
|---|---|
| PHP | >= 8.2 |
| ext-apcu | * |
| ext-redis | * |
| predis/predis | ^3.2 |
apt-get install php8.4-redis php8.4-apcu
# You can install php-redis and php-apcu module for the version you've installed on the system
# Minimum PHP version required: 8.2For CLI usage, remember to enable APCu in your php.ini:
apc.enable_cli=1| Backend | Enum | Description |
|---|---|---|
| APCu | CacheEnum::APCU |
Local in-memory cache, no external dependencies |
| Predis | CacheEnum::REDIS |
Redis via Predis library (pure PHP) |
| PhpRedis | CacheEnum::PHP_REDIS |
Redis via php-redis extension (C extension, better performance) |
Check if a key has exceeded the rate limit.
| Parameter | Type | Description |
|---|---|---|
$key |
string | Unique identifier for the rate limit (e.g., __METHOD__) |
$limit |
int | Maximum number of attempts allowed |
$ttl |
int | Time window in seconds |
Returns: true if the limit has been exceeded, false otherwise.
isLimitedWithBan(string $key, int $limit, int $ttl, int $maxAttempts, int $banTimeFrame, int $banTtl, ?string $clientIp): bool
Check if a key has exceeded the rate limit, with progressive ban support for repeat offenders.
| Parameter | Type | Description |
|---|---|---|
$key |
string | Unique identifier for the rate limit |
$limit |
int | Maximum number of attempts allowed |
$ttl |
int | Base time window in seconds |
$maxAttempts |
int | Max violations before triggering a ban |
$banTimeFrame |
int | Time window for counting violations |
$banTtl |
int | Extended time window when banned |
$clientIp |
string|null | Client IP for per-client banning |
Returns: true if the limit has been exceeded, false otherwise.
Remove a rate limit key, resetting its counter.
| Parameter | Type | Description |
|---|---|---|
$key |
string | The key to clear |
Returns: true on success, false on failure.
use Predis\Client;
use RateLimiter\Enum\CacheEnum;
use RateLimiter\Service\AbstractRateLimiterService;class Foo
{
public function controllerYouWantToRateLimit(): Response
{
$limiter = AbstractRateLimiterService::factory(CacheEnum::APCU);
$key = __METHOD__; // Name of the function you want to rate limit
$limit = 2; // Maximum attempts before the limit
$ttl = 3; // Time window in seconds
if ($limiter->isLimited($key, $limit, $ttl)) {
throw new Exception("LIMIT REACHED: YOU SHALL NOT PASS!");
}
// ... your code
}
}class Foo
{
public function controllerYouWantToRateLimit(): Response
{
$redis = new Client([
'scheme' => 'tcp',
'host' => '192.168.0.100',
'port' => 6379,
'persistent' => true,
]);
$limiter = AbstractRateLimiterService::factory(CacheEnum::REDIS, $redis);
$key = __METHOD__;
$limit = 2;
$ttl = 3;
if ($limiter->isLimited($key, $limit, $ttl)) {
throw new Exception("LIMIT REACHED: YOU SHALL NOT PASS!");
}
// ... your code
}
}class Foo
{
public function controllerYouWantToRateLimit(): Response
{
$redis = new \Redis();
$redis->pconnect(
'192.168.0.100', // host
6379, // port
2, // connect timeout
'persistent_id_rl' // persistent_id
);
$limiter = AbstractRateLimiterService::factory(CacheEnum::PHP_REDIS, $redis);
$key = __METHOD__;
$limit = 2;
$ttl = 3;
if ($limiter->isLimited($key, $limit, $ttl)) {
throw new Exception("LIMIT REACHED: YOU SHALL NOT PASS!");
}
// ... your code
}
}Use this when you want to progressively punish repeat offenders with longer timeouts.
class Foo
{
public function controllerYouWantToRateLimit(): Response
{
$redis = new Client([
'scheme' => 'tcp',
'host' => '192.168.0.100',
'port' => 6379,
'persistent' => true,
]);
$limiter = AbstractRateLimiterService::factory(CacheEnum::REDIS, $redis);
$key = __METHOD__;
$limit = 1; // Max attempts before limit
$ttl = 2; // Base time window (seconds)
$maxAttempts = 3; // Violations before ban kicks in
$banTimeFrame = 4; // Time window for counting violations
$banTtl = 10; // Extended timeout when banned
$clientIp = $_SERVER['REMOTE_ADDR'] ?? null;
if ($limiter->isLimitedWithBan($key, $limit, $ttl, $maxAttempts, $banTimeFrame, $banTtl, $clientIp)) {
throw new Exception("LIMIT REACHED: YOU SHALL NOT PASS!");
}
// ... your code
}
}| Command | Description |
|---|---|
composer test |
Run PHPUnit tests |
composer phpstan |
Run PHPStan static analysis |
composer cs-fix |
Fix code style with PHP-CS-Fixer |
composer cs-check |
Check code style (dry-run) |
composer rector |
Run Rector refactoring |
composer rector-dry |
Preview Rector changes |
composer quality |
Run all quality tools (Rector + CS-Fixer) |
composer quality-check |
Check quality without changes |
This project is licensed under the GPL-3.0-or-later License - see the LICENSE file for details.
Stefano Perrini - spinfo.it