PHPackages                             four-bytes/four-rate-limiting - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. four-bytes/four-rate-limiting

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

four-bytes/four-rate-limiting
=============================

Generic rate limiting library for PHP APIs — Token Bucket, Fixed Window, Sliding Window, Leaky Bucket

1.3.1(2mo ago)0181MITPHPPHP ^8.4

Since Feb 26Pushed 2mo agoCompare

[ Source](https://github.com/four-bytes/four-rate-limiting)[ Packagist](https://packagist.org/packages/four-bytes/four-rate-limiting)[ RSS](/packages/four-bytes-four-rate-limiting/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (3)Used By (1)

four-rate-limiting
==================

[](#four-rate-limiting)

[![PHP Version](https://camo.githubusercontent.com/02463ad42fbbb8e930dc93f83e8b2ecd9ad3f718d33bb429f5f8f792f9cfd2e5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e342d626c75652e737667)](https://packagist.org/packages/four-bytes/four-rate-limiting)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)

Generic rate limiting library for PHP 8.4+. Four algorithms, header-based dynamic tracking, state persistence, PSR-16 cache backend.

Philosophy
----------

[](#philosophy)

This library provides **no API-specific presets**. Every API client knows its own rate limit rules best — configuration belongs in the consuming client, not in a generic library.

Installation
------------

[](#installation)

```
composer require four-bytes/four-rate-limiting
```

Quick Start
-----------

[](#quick-start)

```
use Four\RateLimit\RateLimiterFactory;
use Four\RateLimit\RateLimitConfiguration;

$config = new RateLimitConfiguration(
    algorithm: RateLimitConfiguration::ALGORITHM_TOKEN_BUCKET,
    ratePerSecond: 5.0,
    burstCapacity: 10,
);

$factory = new RateLimiterFactory();
$limiter = $factory->create($config);

if ($limiter->isAllowed('my-api')) {
    // execute request
}

// After the request: evaluate response headers
$limiter->updateFromHeaders('my-api', $response->getHeaders());
```

Algorithms
----------

[](#algorithms)

AlgorithmConstantWhen to useToken Bucket`ALGORITHM_TOKEN_BUCKET`Burst allowed, smooth averageFixed Window`ALGORITHM_FIXED_WINDOW`Fixed time window (e.g. per minute)Sliding Window`ALGORITHM_SLIDING_WINDOW`Rolling window (e.g. QPD without midnight reset)Leaky Bucket`ALGORITHM_LEAKY_BUCKET`Steady throughput, no burstConfiguration
-------------

[](#configuration)

```
new RateLimitConfiguration(
    algorithm: string,        // Algorithm constant
    ratePerSecond: float,     // Average rate
    burstCapacity: int,       // Max concurrent requests
    safetyBuffer: float,      // 0.0–1.0, default: 0.8
    endpointLimits: array,    // Endpoint-specific overrides
    headerMappings: array,    // Response headers → internal fields
    windowSizeMs: int,        // Window size in ms
    persistState: bool,       // Persist state across requests
    stateFile: ?string,       // Path to state file
);
```

Interface
---------

[](#interface)

```
interface RateLimiterInterface {
    public function isAllowed(string $key, int $tokens = 1): bool;
    public function waitForAllowed(string $key, int $tokens = 1, int $maxWaitMs = 30000): bool;
    public function getWaitTime(string $key): int;
    public function reset(string $key): void;
    public function resetAll(): void;
    public function getStatus(string $key): array;
    public function getTypedStatus(string $key): RateLimitStatus;
    public function getAllStatuses(): array;
    public function getAllTypedStatuses(): array;
    public function cleanup(int $maxAgeSeconds = 3600): int;
    public function updateFromHeaders(string $key, array $headers): void;
}
```

Advanced Usage
--------------

[](#advanced-usage)

### createCustom

[](#createcustom)

```
$limiter = $factory->createCustom(
    algorithm: RateLimitConfiguration::ALGORITHM_SLIDING_WINDOW,
    ratePerSecond: 1.0,
    burstCapacity: 60,
    safetyBuffer: 0.85,
    headerMappings: [
        'limit'     => 'X-RateLimit-Limit',
        'remaining' => 'X-RateLimit-Remaining',
    ],
    stateFile: '/tmp/my_api_state.json',
);
```

### Dynamic Header Tracking

[](#dynamic-header-tracking)

```
$limiter->updateFromHeaders('my-api', [
    'X-RateLimit-Limit'     => '60',
    'X-RateLimit-Remaining' => '42',
]);
```

### Rate Limit Status

[](#rate-limit-status)

```
$status = $limiter->getStatus('my-api');
// ['tokens' => 8, 'capacity' => 10, 'rate_per_second' => 5.0]
```

The `getTypedStatus()` method returns a typed DTO with all relevant information:

```
$status = $limiter->getTypedStatus('my-api');

// $status is a RateLimitStatus instance:
// RateLimitStatus {
//     algorithm: "sliding_window",
//     key: "my-api",
//     isRateLimited: false,
//     waitTimeMs: 0,
//     usagePercent: 42.5,
//     raw: [
//         'tokens' => 8.5,
//         'capacity' => 10,
//         'rate_per_second' => 1.157,
//         'last_update' => 1700000000,
//     ],
// }

if ($status->isRateLimited) {
    echo "Rate limited! Wait {$status->waitTimeMs}ms";
}

echo "Usage: {$status->usagePercent}%";
```

### PSR-16 Cache Backend

[](#psr-16-cache-backend)

The library supports any PSR-16 (`Psr\SimpleCache\CacheInterface`) implementation for distributed rate limiting (Redis, APCu, Memcached, etc.).

```
use Four\RateLimit\RateLimiterFactory;

/** @var \Psr\SimpleCache\CacheInterface $cache */
// Provide any PSR-16 compatible cache implementation

$factory = new RateLimiterFactory();
$limiter = $factory->create($config, $cache);

// The limiter now uses the cache backend for state persistence
$limiter->isAllowed('my-api');
```

### HTTP Client Integration

[](#http-client-integration)

`RateLimitMiddleware` encapsulates the complete rate limiting logic for HTTP clients:

- Pre-request: consume token via `waitForAllowed()`
- Post-response: synchronize header state via `updateFromHeaders()`
- 429 retry: exponential backoff with configurable retries

```
use Four\RateLimit\Http\RateLimitMiddleware;
use Four\RateLimit\RateLimiterFactory;
use Four\RateLimit\RateLimitConfiguration;
use Four\RateLimit\Exception\RateLimitExceededException;

$config = new RateLimitConfiguration(
    algorithm: RateLimitConfiguration::ALGORITHM_SLIDING_WINDOW,
    ratePerSecond: 1.157,
    burstCapacity: 150,
    headerMappings: [
        'limit'     => 'X-RateLimit-Limit',
        'remaining' => 'X-RateLimit-Remaining',
    ],
    windowSizeMs: 86_400_000,
    stateFile: '/tmp/my_api_rate_limit.json',
);

$factory = new RateLimiterFactory();
$limiter = $factory->create($config);

$middleware = new RateLimitMiddleware(
    rateLimiter: $limiter,
    key: 'my-api',
    maxRetries: 3,
    backoffMultiplier: 2.0,
    maxWaitMs: 10000,
    maxBackoffMs: 30000,
);

try {
    $response = $middleware->execute(fn() => $httpClient->sendRequest($request));
} catch (RateLimitExceededException $e) {
    // Rate limit exhausted after all retries
    echo "Key: {$e->key}, Wait: {$e->waitTimeMs}ms";
}
```

#### PSR-7 Header Compatibility

[](#psr-7-header-compatibility)

The library automatically normalizes PSR-7 headers (`array` → `array`). `$response->getHeaders()` can be passed directly to `updateFromHeaders()`.

---

Architecture
------------

[](#architecture)

```
Four\RateLimit\
├── RateLimiterInterface          # Contract for all rate limiters
├── RateLimiterFactory            # Creates rate limiters from config
├── RateLimitConfiguration        # Configuration value object
├── AbstractRateLimiter           # Base class with state persistence + PSR-16
├── RateLimitStatus               # Readonly DTO for status queries
├── Algorithm\
│   ├── TokenBucketRateLimiter    # Token bucket implementation
│   ├── FixedWindowRateLimiter    # Fixed window implementation
│   ├── SlidingWindowRateLimiter  # Sliding window implementation
│   └── LeakyBucketRateLimiter    # Leaky bucket implementation
├── Exception\
│   └── RateLimitExceededException # Rate limit + retries exhausted
└── Http\
    └── RateLimitMiddleware       # PSR-18 HTTP client integration

```

Tests
-----

[](#tests)

```
composer test
composer phpstan
composer cs-check
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE).

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance84

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

81d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/433108b332161ce972e4cab8308652a145ed1c3f132de17b04b21f524d4d2dae?d=identicon)[four-bytes-robby](/maintainers/four-bytes-robby)

---

Top Contributors

[![four-bytes-robby](https://avatars.githubusercontent.com/u/22675949?v=4)](https://github.com/four-bytes-robby "four-bytes-robby (7 commits)")

---

Tags

php-library

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/four-bytes-four-rate-limiting/health.svg)

```
[![Health](https://phpackages.com/badges/four-bytes-four-rate-limiting/health.svg)](https://phpackages.com/packages/four-bytes-four-rate-limiting)
```

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.8k18.5M1.6k](/packages/cakephp-cakephp)[algolia/algoliasearch-client-php

API powering the features of Algolia.

69333.0M114](/packages/algolia-algoliasearch-client-php)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[civicrm/civicrm-core

Open source constituent relationship management for non-profits, NGOs and advocacy organizations.

728272.9k20](/packages/civicrm-civicrm-core)[cognesy/instructor-php

The complete AI toolkit for PHP: unified LLM API, structured outputs, agents, and coding agent control

310107.9k1](/packages/cognesy-instructor-php)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
