Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Rate Limiter Laravel Package

symfony/rate-limiter

Symfony Rate Limiter provides token bucket rate limiting for your app. Create limiters with RateLimiterFactory and a storage backend (e.g., in-memory), then reserve tokens with blocking waits or consume instantly to allow/skip work based on availability.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the package** (unchanged):
   ```bash
   composer require symfony/rate-limiter
  1. Define a rate limiter (unchanged):

    use Symfony\Component\RateLimiter\RateLimiterFactory;
    use Symfony\Component\RateLimiter\Storage\RedisStorage;
    
    $storage = new RedisStorage('redis://localhost');
    $factory = new RateLimiterFactory([
        'id' => 'api_endpoint',
        'policy' => 'token_bucket',
        'limit' => 100,
        'rate' => ['interval' => '1 minute'],
    ], $storage);
    
    $limiter = $factory->create();
    
  2. First use case: Laravel middleware (unchanged):

    use Symfony\Component\HttpFoundation\Response;
    
    class RateLimitMiddleware
    {
        public function __construct(private RateLimiter $limiter) {}
    
        public function handle($request, Closure $next): Response
        {
            if (!$this->limiter->consume(1)->isAccepted()) {
                return response()->json(['error' => 'Too many requests'], 429)
                    ->header('Retry-After', $this->limiter->getRetryAfter()->format('U'));
            }
            return $next($request);
        }
    }
    

Key Starting Points (Updated)

  • Documentation: Symfony RateLimiter Docs
  • Storage Options: InMemoryStorage (dev), RedisStorage (prod), DatabaseStorage (custom)
  • Policies: token_bucket (default), fixed_window, sliding_window
  • Security Note: Added PHPStan rule for unsafe unserialize (v8.1.1). Ensure your static analysis tools are updated to catch potential serialization risks.

Implementation Patterns

1. Laravel Middleware Integration (Unchanged)

(Same as previous assessment)

2. Queue Job Throttling (Unchanged)

(Same as previous assessment)

3. Compound Rate Limiting (Unchanged)

(Same as previous assessment)

4. CLI Command Rate Limiting (Unchanged)

(Same as previous assessment)

5. Dynamic Limits via Config (Updated)

Use Case: Adjust limits per environment or feature flags.

// config/rate_limits.php
return [
    'api' => [
        'limit' => env('API_RATE_LIMIT', 100),
        'interval' => env('API_RATE_INTERVAL', '1 minute'),
        'policy' => env('API_RATE_POLICY', 'token_bucket'), // Explicitly set policy
    ],
    'auth' => [
        'limit' => 5,
        'interval' => '5 minutes',
    ],
];

// In middleware:
$config = config('rate_limits.api');
$limiter = (new RateLimiterFactory([
    'id' => 'api',
    'policy' => $config['policy'],
    'limit' => $config['limit'],
    'rate' => ['interval' => $config['interval']],
], $storage))->create();

Security Note: Validate serialized data if using custom storage. The new PHPStan rule (Unsafe unserialize) helps detect potential risks in deserialization logic.


Gotchas and Tips

Pitfalls (Updated)

  1. Storage Persistence (Unchanged)

    • Use RedisStorage in production.
  2. Token Bucket Edge Cases (Updated)

    • Negative tokens: Handle gracefully with reserve()->wait() for blocking operations.
    • Security: Avoid deserializing untrusted data. The new PHPStan rule (Unsafe unserialize) flags unsafe practices. Example:
      // Avoid this in custom storage:
      $data = unserialize($redis->get('limiter_data')); // Risky!
      
    • Fix: Use typed storage or validate data before deserialization.
  3. Time Synchronization (Unchanged)

    • Ensure NTP synchronization across servers.
  4. Retry-After Headers (Unchanged)

    • Convert DateTimeInterface to Unix timestamp:
      ->header('Retry-After', $limiter->getRetryAfter()->getTimestamp())
      
  5. Compound Limiter Short-Circuiting (Unchanged)

    • Ensure all sub-limiters are configured correctly.

Debugging Tips (Updated)

  1. Inspect Tokens (Unchanged)

    $tokens = $limiter->getTokens();
    $retryAfter = $limiter->getRetryAfter();
    
  2. Log Rate Limit Events (Unchanged)

    if (!$limiter->consume(1)->isAccepted()) {
        \Log::warning('Rate limit exceeded', [
            'retry_after' => $limiter->getRetryAfter()->format('Y-m-d H:i:s'),
            'remaining' => $limiter->getTokens(),
        ]);
    }
    
  3. Test Locally with InMemoryStorage (Unchanged)

    $storage = new InMemoryStorage();
    $factory = new RateLimiterFactory([...], $storage);
    
    • Reset storage between tests:
      $storage->delete('your_limiter_id');
      
  4. New: Static Analysis for Security

    • Run PHPStan with the Unsafe unserialize rule to catch serialization risks:
      vendor/bin/phpstan analyse --level=7 src/
      

Extension Points (Updated)

  1. Custom Storage (Unchanged) Implement StorageInterface for database-backed storage.

  2. Security Hardening

    • Avoid deserialization: Use JSON or native types for storage.
    • Example: Safe Redis storage with JSON:
      class JsonRedisStorage implements StorageInterface
      {
          public function load($id): array
          {
              $data = $this->redis->get($id);
              return $data ? json_decode($data, true) : [];
          }
      
          public function save($id, array $data): void
          {
              $this->redis->set($id, json_encode($data));
          }
      }
      
  3. Policy Validation

    • Validate policies dynamically (e.g., via config):
      $validPolicies = ['token_bucket', 'fixed_window', 'sliding_window'];
      if (!in_array($config['policy'], $validPolicies)) {
          throw new \InvalidArgumentException('Invalid rate limit policy');
      }
      

NO_UPDATE_NEEDED would not apply here due to the security-focused change in v8.1.1. The assessment has been updated to reflect the new PHPStan rule and added security considerations.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata