PHPackages                             tobento/app-rate-limiter - 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. tobento/app-rate-limiter

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

tobento/app-rate-limiter
========================

App rate limiter support.

2.0(7mo ago)030MITPHPPHP &gt;=8.4

Since Jun 1Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/app-rate-limiter)[ Packagist](https://packagist.org/packages/tobento/app-rate-limiter)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-app-rate-limiter/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (3)Dependencies (11)Versions (5)Used By (0)

App Rate Limiter
================

[](#app-rate-limiter)

Rate limiter support for the app using the [Symfony - Rate Limiter](https://symfony.com/doc/current/rate_limiter.html) component as default implementation.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting Started](#getting-started)
    - [Requirements](#requirements)
- [Documentation](#documentation)
    - [App](#app)
    - [Rate Limiter Boot](#rate-limiter-boot)
        - [Rate Limiter Config](#rate-limiter-config)
    - [Basic Usage](#basic-usage)
        - [Using The Rate Limiter Creator](#using-the-rate-limiter-creator)
        - [Using The RateLimitRequests Middleware](#using-the-ratelimitrequests-middleware)
    - [Available Rate Limiter Registries](#available-rate-limiter-registries)
        - [Factory](#factory)
        - [Fixed Window](#fixed-window)
        - [Named](#named)
        - [No Limit](#no-limit)
        - [Sliding Window](#sliding-window)
        - [Token Bucket](#token-bucket)
    - [Register Named Rate Limiters](#register-named-rate-limiters)
    - [Events](#events)
- [Credits](#credits)

---

Getting Started
===============

[](#getting-started)

Add the latest version of the app rate limiter project running this command.

```
composer require tobento/app-rate-limiter

```

Requirements
------------

[](#requirements)

- PHP 8.4 or greater

Documentation
=============

[](#documentation)

App
---

[](#app)

Check out the [**App Skeleton**](https://github.com/tobento-ch/app-skeleton) if you are using the skeleton.

You may also check out the [**App**](https://github.com/tobento-ch/app) to learn more about the app in general.

Rate Limiter Boot
-----------------

[](#rate-limiter-boot)

The rate limiter boot does the following:

- installs and loads rate limiter config file
- implements rate limiter interfaces

```
use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\RateLimiterCreatorInterface;
use Tobento\App\RateLimiter\RegistriesInterface;
use Tobento\App\RateLimiter\FingerprintInterface;

// Create the app
$app = new AppFactory()->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Implemented interfaces:
$limiterCreator = $app->get(RateLimiterCreatorInterface::class);
$registries = $app->get(RegistriesInterface::class);
$fingerprint = $app->get(FingerprintInterface::class);

// Run the app
$app->run();
```

### Rate Limiter Config

[](#rate-limiter-config)

The configuration for the rate limiter is located in the `app/config/rate_limiter.php` file at the default App Skeleton config location where you can specify named rate limiters for your application.

Basic Usage
-----------

[](#basic-usage)

### Using The Rate Limiter Creator

[](#using-the-rate-limiter-creator)

After having [booted the rate limiter](#rate-limiter-boot), inject it in any service or controller. You may consider booting the [App Http - Routing Boot](https://github.com/tobento-ch/app-http#routing-boot) as well in order to get HTTP and Routing support.

```
use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\RateLimiterCreatorInterface;
use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\Http\Exception\TooManyRequestsException;

$app = new AppFactory()->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Http\Boot\ErrorHandler::class);
$app->boot(\Tobento\App\Http\Boot\Routing::class);
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Routes:
$app->route('POST', 'login', function(ServerRequestInterface $request, RateLimiterCreatorInterface $limiterCreator) {
    // create a rate limiter:
    $limiter = $limiterCreator->createFromRegistry(
        // a unique identifier of the client:
        id: $request->getServerParams()['REMOTE_ADDR'] ?? null,
        // define the rate limiter to use:
        registry: new SlidingWindow(limit: 5, interval: '5 minutes'),
    );

    // next hit the limiter and check if attempts exceeded:
    if ($limiter->hit()->isAttemptsExceeded()) {
        throw new TooManyRequestsException(
            retryAfter: $limiter->availableIn(),
            message: sprintf('Too Many Requests. Please retry after %d seconds.', $limiter->availableIn()),
            headers: [
                'X-RateLimit-Limit' => $limiter->maxAttempts(),
                'X-RateLimit-Remaining' => $limiter->remainingAttempts(),
                'X-RateLimit-Reset' => $limiter->availableAt()->getTimestamp(),
            ],
        );
    }

    // you may reset the attempts:
    // $limiter->reset();

    return 'response';
});

// Run the app:
$app->run();
```

Check out the [Available Rate Limiter Registries](#available-rate-limiter-registries) for its available limiter registries.

### Using The RateLimitRequests Middleware

[](#using-the-ratelimitrequests-middleware)

Use the `RateLimitRequests::class` middleware to rate limit routes easily.

```
use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\Middleware\RateLimitRequests;
use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\Http\Exception\TooManyRequestsException;

$app = new AppFactory()->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Http\Boot\ErrorHandler::class);
$app->boot(\Tobento\App\Http\Boot\Routing::class);
$app->boot(\Tobento\App\Http\Boot\RequesterResponser::class); // for redirection support
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Routes:
$app->route('POST', 'login', function() {
    // being rate limited!
    return 'response';
})->middleware([
    RateLimitRequests::class,

    // define the rate limiter to use:
    'registry' => new SlidingWindow(limit: 5, interval: '5 minutes'),

    // or by named rate limiter:
    //'registry' => 'login',
]);

$app->route('POST', 'register', function() {
    // being rate limited!
    return 'response';
})->middleware([
    RateLimitRequests::class,
    'registry' => new SlidingWindow(limit: 5, interval: '5 minutes'),

    // You may specify a redirect uri or route
    // which will redirect instead of throwing a TooManyRequestsException:
    'redirectUri' => '/register',
    'redirectRoute' => 'register',

    // You may specify a redirect message to be flashed.
    // The :seconds parameter value will be set by the middleware.
    'message' => 'Too many attempts. Please retry after :seconds seconds.',
    'messageLevel' => 'error', // default
    'messageKey' => 'email', // or null default
]);

// Run the app:
$app->run();
```

Available Rate Limiter Registries
---------------------------------

[](#available-rate-limiter-registries)

### Factory

[](#factory)

The `Factory` registry may be used to create a rate limiter from any factory:

```
use Tobento\App\RateLimiter\Registry\Factory;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new Factory(
        factory: RateLimiterFactory::class,
        config: [
            'policy' => 'sliding_window',
            'limit' => 5,
            'interval' => '5 Minutes',
        ],
    ),
);
```

### Fixed Window

[](#fixed-window)

The `FixedWindow` registry creates a [Symfony fixed window rate limiter](https://symfony.com/doc/current/rate_limiter.html#fixed-window-rate-limiter):

```
use Tobento\App\RateLimiter\Symfony\Registry\FixedWindow;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new FixedWindow(
        limit: 100,
        interval: '5 Minutes',

        // you may specify an id prefix:
        id: 'api',

        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default

        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);
```

You may define a cache for the name `ratelimiter` (default) or `api-ratelimiter` (custom) in the [App Cache - Config](https://github.com/tobento-ch/app-cache#cache-config), otherwise the primary cache is used as default.

### Named

[](#named)

The `Named` registry may be used to create a rate limiter from a named rate limiter:

```
use Tobento\App\RateLimiter\Registry\Named;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new Named('api'),
);
```

Check out the [Register Named Rate Limiters](#register-named-rate-limiters) section to learn more about it.

### No Limit

[](#no-limit)

The `NoLimit` registry creates a Symfony no limit rate limiter:

```
use Tobento\App\RateLimiter\Symfony\Registry\NoLimit;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new NoLimit(),
);
```

### Sliding Window

[](#sliding-window)

The `SlidingWindow` registry creates a [Symfony sliding window rate limiter](https://symfony.com/doc/current/rate_limiter.html#sliding-window-rate-limiter):

```
use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new SlidingWindow(
        limit: 100,
        interval: '5 Minutes',

        // you may specify an id prefix:
        id: 'api',

        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default

        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);
```

You may define a cache for the name `ratelimiter` (default) or `api-ratelimiter` (custom) in the [App Cache - Config](https://github.com/tobento-ch/app-cache#cache-config), otherwise the primary cache is used as default.

### Token Bucket

[](#token-bucket)

The `TokenBucket` registry creates a [Symfony token bucket rate limiter](https://symfony.com/doc/current/rate_limiter.html#token-bucket-rate-limiter):

```
use Tobento\App\RateLimiter\Symfony\Registry\TokenBucket;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new TokenBucket(
        limit: 5000,
        rateAmount: 500,
        rateInterval: '60 Minutes',

        // you may specify an id prefix:
        id: 'api',

        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default

        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);
```

You may define a cache for the name `ratelimiter` (default) or `api-ratelimiter` (custom) in the [App Cache - Config](https://github.com/tobento-ch/app-cache#cache-config), otherwise the primary cache is used as default.

Register Named Rate Limiters
----------------------------

[](#register-named-rate-limiters)

**Register Named Rate Limiter via Config**

You can register named rate limiters in the config file `app/config/rate_limiter.php`:

```
return [
    // ...
    'limiters' => [
        'api' => new TokenBucket(limit: 10, rateAmount: 5, rateInterval: '5 Minutes'),
        'login' => new FixedWindow(limit: 2, interval: '1 Minutes'),
    ],
];
```

**Register Named Rate Limiter via Boot**

```
use Tobento\App\Boot;
use Tobento\App\RateLimiter\Boot\RateLimiter;
use Tobento\App\RateLimiter\RegistriesInterface;
use Tobento\App\RateLimiter\Symfony\Registry\FixedWindow;

class RateLimitersBoot extends Boot
{
    public const BOOT = [
        // you may ensure the rate limiter boot.
        RateLimiter::class,
    ];

    public function boot()
    {
        // you may use the app on method to add only if requested:
        $app->on(
            RegistriesInterface::class,
            static function(RegistriesInterface $registries) {
                $registries->add(
                    name: 'api',
                    registry: new FixedWindow(limit: 2, interval: '1 Minutes'),
                );
            }
        );
    }
}
```

Events
------

[](#events)

**Available Events**

EventDescription`Tobento\App\RateLimiter\Event\AttemptsExceeded::class`The event will dispatch **after** the attempts exceeded**Supporting Events**

Simply, install the [App Event](https://github.com/tobento-ch/app-event) bundle.

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)
- [Seldaek Monolog](https://github.com/Seldaek/monolog)

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance63

Regular maintenance activity

Popularity7

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity61

Established project with proven stability

 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 ~122 days

Total

5

Last Release

222d ago

Major Versions

1.x-dev → 2.02025-10-02

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (9 commits)")

---

Tags

packagerate-limiterapptobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-app-rate-limiter/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-app-rate-limiter/health.svg)](https://phpackages.com/packages/tobento-app-rate-limiter)
```

PHPackages © 2026

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