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'],
];

$services = RateLimitProvider::register(
    config: $config->get('rate_limit', []),
    logger: $logger,
    redis:  $existingRedis,  // Reuse connection — config host/port are ignored
);

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);
});
bash
cp vendor/monkeyscloud/monkeyslegion-rate-limit/config/rate-limit.mlc config/rate-limit.mlc
mlc
storage {
    driver = memory
}