PHP code example of sanmai / rate-limiter

1. Go to this page and download the library: Download sanmai/rate-limiter 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/ */

    

sanmai / rate-limiter example snippets


// Import necessary classes
use SlidingWindowCounter\RateLimiter\RateLimiter;
use SlidingWindowCounter\Cache\MemcachedAdapter;

// Create a rate limiter for an IP address with 1-minute windows and 1-hour observation period
$rateLimiter = RateLimiter::create(
    '192.168.1.1',          // Subject being rate limited (e.g., IP address)
    'api_requests',         // Name for your rate limiter
    60,                     // Window size: 60 seconds (1 minute)
    3600,                   // Observation period: 3600 seconds (1 hour)
    new MemcachedAdapter($memcached)
);

// Record a request from this client
$rateLimiter->increment();

// You can also increment by a specific amount (for weighted actions)
$rateLimiter->increment(2); // Count this action as 2 requests

// Check if the client has exceeded window limit (100 requests per minute)
$windowResult = $rateLimiter->checkWindowLimit(100);

if ($windowResult->isLimitExceeded()) {
    // Window limit exceeded - client is sending requests too quickly
    echo $windowResult->getLimitExceededMessage();
    // Example output: "Rate limit exceeded for 192.168.1.1: 120 actions in the window (limit: 100)"
    
    // Return 429 Too Many Requests response
    header('HTTP/1.1 429 Too Many Requests');
    header('Retry-After: 60');
    exit;
}

// Check if the client has exceeded period limit (1000 requests per hour)
$periodResult = $rateLimiter->checkPeriodLimit(1000);

if ($periodResult->isLimitExceeded()) {
    // Period limit exceeded - client has sent too many requests in the observation period
    echo $periodResult->getLimitExceededMessage();
    
    // Return 429 Too Many Requests response
    header('HTTP/1.1 429 Too Many Requests');
    header('Retry-After: 3600');
    exit;
}

// Get information about the current rate limit status
$windowResult = $rateLimiter->checkWindowLimit(100);

// Subject being rate limited
$subject = $windowResult->getSubject(); // e.g., "192.168.1.1"

// Current count in the window
$count = $windowResult->getCount();

// Maximum limit
$limit = $windowResult->getLimit();

// Type of limit
$limitType = $windowResult->getLimitType(); // "window" or "period"

// Get the limit message (only if exceeded)
$message = $windowResult->getLimitExceededMessage();

// Get the latest value in the current window
$currentValue = $rateLimiter->getLatestValue();

// Get the total across all windows in the observation period
$totalRequests = $rateLimiter->getTotal();

// General rate limiter with 1-minute windows and 1-hour observation period
$generalLimiter = RateLimiter::create($clientIp, 'general_api', 60, 3600, $cache);

// Check if client exceeds 100 requests per minute
$windowResult = $generalLimiter->checkWindowLimit(100);

// Check if client exceeds 1000 requests per hour
$periodResult = $generalLimiter->checkPeriodLimit(1000);

// Stricter limiter for sensitive endpoints with same time parameters
$sensitiveLimiter = RateLimiter::create($clientIp, 'sensitive_api', 60, 3600, $cache);

// Check if client exceeds 10 requests per minute for sensitive endpoints
$sensitiveWindowResult = $sensitiveLimiter->checkWindowLimit(10);

// Check if client exceeds 50 requests per hour for sensitive endpoints
$sensitivePeriodResult = $sensitiveLimiter->checkPeriodLimit(50);

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
    $ip = $request->getServerParams()['REMOTE_ADDR'];
    
    // Create rate limiter
    $rateLimiter = RateLimiter::create($ip, 'api_requests', 60, 3600, $this->cache);
    
    // Increment the counter
    $rateLimiter->increment();
    
    // Check window limit (e.g., 100 requests per minute)
    $windowResult = $rateLimiter->checkWindowLimit(100);
    if ($windowResult->isLimitExceeded()) {
        return $this->createRateLimitResponse(
            $windowResult->getLimitExceededMessage(),
            60
        );
    }
    
    // Check period limit (e.g., 1000 requests per hour)
    $periodResult = $rateLimiter->checkPeriodLimit(1000);
    if ($periodResult->isLimitExceeded()) {
        return $this->createRateLimitResponse(
            $periodResult->getLimitExceededMessage(),
            3600
        );
    }
    
    // Limits not exceeded, continue with the request
    return $handler->handle($request);
}

try {
    // Create the rate limiter
    $rateLimiter = RateLimiter::create($ip, 'api_requests', 60, 3600, $cache);
    
    // Increment and check limits
    $rateLimiter->increment();
    $windowResult = $rateLimiter->checkWindowLimit(100);
    
    // Handle rate limit exceeded
    if ($windowResult->isLimitExceeded()) {
        // Log the rate limit event
        $this->logger->warning('Rate limit exceeded', [
            'ip' => $ip,
            'count' => $windowResult->getCount(),
            'limit' => $windowResult->getLimit(),
            'type' => $windowResult->getLimitType()
        ]);
        
        // Return appropriate response
        return $this->createRateLimitResponse(
            $windowResult->getLimitExceededMessage(),
            60
        );
    }
} catch (Exception $e) {
    // If the cache service is unavailable, fail open (allow the request)
    $this->logger->error('Rate limiter error', ['exception' => $e]);
    
    // Continue processing the request
    return $handler->handle($request);
}