yaknet / rate-limiter
A high-performance, zero-dependency, pure PHP rate limiting component supporting Token Bucket and Sliding Window algorithms.
Requires
- php: >=8.2
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2026-05-31 19:53:14 UTC
README
A high-performance, zero-dependency, pure PHP rate limiting component. Supports standard rate-limiting algorithms and pluggable storage backends (vital for both persistent processes like WebSockets and shared-nothing environments like PHP-FPM).
Features
- ⚡ Zero External Production Dependencies: Extremely lightweight, fast, and easy to embed.
- 🛡️ Race-Condition Free: Leverages unique transactional read-modify-write logic using exclusive locks (
flock) on files and optimistic concurrency controls (WATCH/MULTI/EXEC) on Redis. - 🔄 Pluggable Storage Adapters:
InMemoryStorage: RAM-based array. Extremely fast, perfect for tests and long-running services (e.g. WebSocket servers).FileStorage: Local disk-based storage with robust file-locking. Works out of the box on any server (shared hosting, basic VPS) with zero external setup or engines.RedisStorage: Scalable storage compatible with both native PHPRedisextension (Phpredis) and userlandPredisclient library.
- 📈 Advanced Algorithms:
- Token Bucket: Allows quick bursts up to a capacity limit and refills tokens continuously based on high-resolution elapsed time.
- Sliding Window: Tracks logs in a rolling sliding window, preventing boundaries/fixed-window request resets.
Installation
Add this package to your project using Composer (ensure your local repository mapping is configured):
composer require yaknet/rate-limiter
Quick Start
1. Token Bucket Limiter (Using Zero-Dependency FileStorage)
Great for allowing bursts of traffic while ensuring a steady continuous refill rate:
<?php require 'vendor/autoload.php'; use YakNet\RateLimiter\Policy\TokenBucketLimiter; use YakNet\RateLimiter\Storage\FileStorage; // Initialize zero-dependency file-based storage $storage = new FileStorage(); // Capacity = 10 tokens, Refills at 2.0 tokens every second $limiter = new TokenBucketLimiter($storage, 10, 2.0); $clientIp = '127.0.0.1'; // Consume 1 token $limit = $limiter->consume($clientIp, 1); if ($limit->isAccepted()) { echo "✔ Request accepted! Remaining quota: " . $limit->getRemaining() . "\n"; } else { echo "✖ Request throttled! Please wait " . $limit->getRetryAfter() . " seconds.\n"; }
2. Sliding Window Limiter (Using Fast InMemoryStorage)
Perfect for sliding-log tracking inside persistent processes (e.g. your WebSocket loops):
<?php use YakNet\RateLimiter\Policy\SlidingWindowLimiter; use YakNet\RateLimiter\Storage\InMemoryStorage; // RAM storage (values persist within the active long-running thread) $storage = new InMemoryStorage(); // Limit = 5 requests per 10-second rolling window $limiter = new SlidingWindowLimiter($storage, 5, 10); $userId = 'user_99'; $limit = $limiter->consume($userId, 1); if ($limit->isAccepted()) { // Process request }
3. Distributed Redis Storage Setup
Compatible with both Phpredis and Predis:
use YakNet\RateLimiter\Policy\TokenBucketLimiter; use YakNet\RateLimiter\Storage\RedisStorage; // Using native PHP \Redis or Predis\Client $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); $storage = new RedisStorage($redis); $limiter = new TokenBucketLimiter($storage, 100, 10.0);
Verification & Testing
Verify that all algorithms and lock contention structures pass successfully:
composer test
Perform static analysis with PHPStan:
composer analyze
License
This project is licensed under the MIT License - see the LICENSE file for details.