A framework independent, flexible and highly extensible rate limiter for PHP.
It is best installed it through packagist
by including sunspikes/php-ratelimiter in your project composer.json require:
"require": {
"sunspikes/php-ratelimiter": "dev-master"
}You can also download it from Github, but no autoloader is provided so you'll need to register it with your own PSR-4 compatible autoloader.
// 1. Make a rate limiter with limit 3 attempts in 10 minutes$cacheAdapter = newDesarrollaCacheAdapter((newDesarrollaCacheFactory())->make());
$settings = newElasticWindowSettings(3, 600);
$ratelimiter = newRateLimiter(newThrottlerFactory($cacheAdapter), newHydratorFactory(), $settings);
// 2. Get a throttler for path /login $loginThrottler = $ratelimiter->get('/login');
// 3. Register a hit$loginThrottler->hit()
// 4. Check if it reached the limitif ($loginThrottler->check()) {
// access permitted
} else {
// access denied
}
// Or combine the steps 3 & 4if ($loginThrottler->access()) {
// access permitted
} else {
// access denied
}
// To get the number of hitsprint$loginThrottler->count(); // or count($throttler)By default PHP Ratelimiter uses the desarolla2 cache adapter, the sample configuration provided in config/config.php
You can configure the drivers in config.php, for example to use memcache change the driver to 'memcache'
return [
'default_ttl' => 3600,
'driver' => 'memcache',
'memcache' => [
//....
],
];The PHP Ratelimiter is highly extensible, you can have custom adapters by implementing Sunspikes\Ratelimit\Cache\Adapter\CacheAdapterInterface
For example to use Doctrine cache adapter
class DoctrineCacheAdapter implements CacheAdapterInterface
{
publicfunction__construct($cache)
{
$this->cache = $cache;
}
// Implement the methods
}
// Build adapter using APC cache driver$adapter = newDoctrineCacheAdapter(new \Doctrine\Common\Cache\ApcCache());Also you can have custom hydrators by implementing Sunspikes\Ratelimit\Throttle\Hydrator\DataHydratorInterface
For example to use a Symfony Request object instead of custom URL for ratelimiting
class RequestHydrator implements DataHydratorInterface
{
publicfunctionhydrate($data, $limit, $ttl)
{
// Make the key string$key = $data->getClientIp() . $data->getPathInfo();
returnnewData($key, $limit, $ttl);
}
}
// Hydrate the request to Data object$hydrator = newRequestHydrator();Then decorate or extend the HydratorFactory to recognize your data
useHydrator\FactoryInterface;
class MyHydratorFactory implements FactoryInterface
{
private$defaultFactory;
publicfunction__construct(FactoryInterface$defaultFactory)
{
$this->defaultFactory = $defaultFactory;
}
publicfunctionmake($data)
{
if ($datainstanceof Request) {
returnnewRequestHydrator();
}
return$this->defaultFactory->make($data);
}
}An elastic window throttler will allow X requests in Y seconds. Any further access attempts will be counted, but return false as status. Note that the window will be extended with Y seconds on every hit. This means there need to be no hits during Y seconds for the counter to be reset to 0.
See Overview example for instantiation.
All the following throttlers use time functions, thus needing a different factory for construction:
$cacheAdapter = newDesarrollaCacheAdapter((newDesarrollaCacheFactory())->make());
$timeAdapter = newPhpTimeAdapter();
$throttlerFactory = newTimeAwareThrottlerFactory($cacheAdapter, $timeAdapter);
$hydratorFactory = newHydratorFactory();
//$settings = ...$ratelimiter = newRateLimiter($throttlerFactory, $hydratorFactory, $settings);A fixed window throttler will allow X requests in the Y seconds since the first request. Any further access attempts will be counted, but return false as status. The window will not be extended at all.
// Make a rate limiter with limit 120 attempts per minute$settings = newFixedWindowSettings(120, 60);A moving window throttler will allow X requests during the previous Y seconds. Any further access attempts will be counted, but return false as status. The window is never extended beyond Y seconds.
// Make a rate limiter with limit 120 attempts per minute$settings = newMovingWindowSettings(120, 60);A leaky bucket throttler will allow X requests divided over time Y.
Any access attempts past the threshold T (default: 0) will be delayed by Y / (X - T)
access() will return false if delayed, hit() will return the number of milliseconds waited
Note: Time limit for this throttler is in milliseconds, where it is seconds for the other throttler types!
// Make a rate limiter with limit 120 attempts per minute, start delaying after 30 requests$settings = newLeakyBucketSettings(120, 60000, 30);The retrial queue encapsulates another throttler. When this throttler receives a hit which would fail on the internal throttler, the request is delayed until the internal throttler has capacity again.
// Make a leaky bucket ratelimiter which delays any overflow$settings = newRetrialQueueSettings(newLeakyBucketSettings(120, 60000, 120));Krishnaprasad MG [@sunspikes]
Please feel free to send pull requests.
This is an open-sourced software licensed under the MIT license.


