PHP code example of monkeyscloud / monkeyslegion-rate-limit
1. Go to this page and download the library: Download monkeyscloud/monkeyslegion-rate-limit library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
monkeyscloud / monkeyslegion-rate-limit example snippets
use MonkeysLegion\Mlc\Loader;
use MonkeysLegion\RateLimit\Provider\RateLimitProvider;
// 1. Load the MLC config
$config = $loader->loadOne('rate-limit');
// 2. Bootstrap the entire rate limit stack
$services = RateLimitProvider::register(
config: $config->get('rate_limit', []),
logger: $logger, // PSR-3 logger
);
// 3. Register the middleware in the router
$router->registerMiddleware(
'rate-limit',
$services['middleware'],
priority: 100,
);
$router->addGlobalMiddleware('rate-limit');
// In your container definitions (e.g., di/definitions.php)
use MonkeysLegion\RateLimit\Provider\RateLimitProvider;
use MonkeysLegion\RateLimit\RateLimiterManager;
use MonkeysLegion\RateLimit\Middleware\RateLimitMiddleware;
return [
// Load config
'rate_limit.config' => fn(Config $config) => $config->get('rate_limit', []),
// Bootstrap services
'rate_limit.services' => fn(array $config, LoggerInterface $logger) =>
RateLimitProvider::register(config: $config, logger: $logger),
// Individual service bindings
RateLimiterManager::class => fn(array $services) => $services['manager'],
RateLimitMiddleware::class => fn(array $services) => $services['middleware'],
];
use MonkeysLegion\RateLimit\RateLimiterManager;
use MonkeysLegion\RateLimit\Middleware\RateLimitMiddleware;
use MonkeysLegion\RateLimit\Storage\RedisStorage;
use MonkeysLegion\RateLimit\Storage\ResilientStorage;
use MonkeysLegion\RateLimit\Storage\InMemoryStorage;
use MonkeysLegion\RateLimit\RateLimiter;
// 1. Create Redis connection
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$redis->select(1);
// 2. Wrap with resilience
$storage = new ResilientStorage(
primary: new RedisStorage($redis, prefix: 'ml_rl:'),
failOpen: true,
fallback: new InMemoryStorage(),
logger: $logger,
);
// 3. Create manager and register named limiters
$manager = new RateLimiterManager($storage);
$manager->define('api', fn() => [
'maxAttempts' => 100,
'windowSeconds' => 60,
'by' => 'ip',
'algorithm' => 'token_bucket',
]);
$manager->define('auth', fn() => [
'maxAttempts' => 5,
'windowSeconds' => 300,
'by' => 'ip',
'algorithm' => 'sliding_window',
]);
// 4. Create middleware and register
$middleware = new RateLimitMiddleware($manager);
$router->registerMiddleware('rate-limit', $middleware, priority: 100);
$router->addGlobalMiddleware('rate-limit');
// 5. Initialize facade for programmatic use
RateLimiter::init($manager);
use MonkeysLegion\RateLimit\Attributes\RateLimit;
use MonkeysLegion\RateLimit\Algorithm;
#[RoutePrefix('/api/v2/users')]
final class UserController
{
// 60 requests per minute, per IP (token bucket)
#[Route('GET', '/', name: 'users.index')]
#[RateLimit(maxAttempts: 60, windowSeconds: 60)]
public function index(): Response { /* ... */ }
// 5 login attempts per 5 minutes, per IP (sliding window)
#[Route('POST', '/login', name: 'users.login')]
#[RateLimit(maxAttempts: 5, windowSeconds: 300, algorithm: Algorithm::SlidingWindow)]
public function login(): Response { /* ... */ }
// Stacked: global IP limit + per-user per-route limit
#[Route('POST', '/', name: 'users.create')]
#[RateLimit(maxAttempts: 1000, windowSeconds: 3600, by: 'ip')]
#[RateLimit(maxAttempts: 10, windowSeconds: 60, by: 'user+route')]
public function create(): Response { /* ... */ }
// Reference a named limiter from config
#[Route('GET', '/search', name: 'users.search')]
#[RateLimit(limiter: 'api')]
public function search(): Response { /* ... */ }
}
use MonkeysLegion\RateLimit\RateLimiter;
// After bootstrap (RateLimiter::init() was called by the Provider)
$result = RateLimiter::attempt('login:192.168.1.1', maxAttempts: 5, windowSeconds: 300);
if ($result->exceeded) {
echo "Try again in {$result->retryAfter} seconds";
}
// Check without consuming
if (RateLimiter::tooManyAttempts('api:10.0.0.1', 100, 60)) {
// Already at limit
}
// Clear all state for a key (e.g., after password reset)
RateLimiter::clear('login:192.168.1.1');
use MonkeysLegion\RateLimit\Attributes\RateLimit;
use MonkeysLegion\RateLimit\Algorithm;
$attr = new RateLimit(maxAttempts: 100, windowSeconds: 60, by: 'ip+route');
$result = $manager->fromAttribute($attr, $request);
if (!$result->allowed) {
// Handle rate limit exceeded
}
// Works with named limiters too
$attr = new RateLimit(limiter: 'api');
$result = $manager->fromAttribute($attr, $request);
// Old way — still works
#[Throttle(max: 60, per: 60, by: 'ip')]
// New way — more features
#[RateLimit(maxAttempts: 60, windowSeconds: 60, by: 'ip', algorithm: Algorithm::TokenBucket)]
// Custom telemetry callback example
$middleware = new RateLimitMiddleware($manager, metricsCallback: function (
string $metricName,
array $labels,
): void {
// Emit to Prometheus, StatsD, or any monitoring backend
Telemetry::counter($metricName, $labels);
});