Throttler
, (*1)
Introduction
Phalcon Throttler is a Rate Limiter for PHP Phalcon Framework., (*2)
It provides a simple interface to build Rate Limiters using various strategies as well as with a Redis Throttler ready out of the box., (*3)
PHP 7.1+ and Phalcon 3.1.2+ are required., (*4)
Installation
Throttler can be installed through Composer, just include "oaklabs/phalcon-throttler": "^0.1" to your composer.json and run composer update or composer install., (*5)
Usage
Throttling
Phalcon Throttler comes shipped with a Redis throttler by default.
It uses PhpRedis to communicate with the Redis server., (*6)
First of all we need a Redis instance.
We can then add a redis service in the Phalcon Dependency Injection container, (*7)
$di->setShared('redis', function () use ($config) {
$redis = new \Redis();
$redis->pconnect($config->redis->host, $config->redis->port);
$redis->auth($config->redis->password);
return $redis;
});
so that it can be used when we want to create an instance of the Redis Throttler.
We can set it up in the Dependency Injection container as well, (*8)
$di->setShared('throttler',function() use ($di) {
return new OakLabs\PhalconThrottler\RedisThrottler($di->get('redis'), [
'bucket_size' => 20,
'refill_time' => 600, // 10m
'refill_amount' => 10
]);
});
The second parameter allows to configure the behaviour of the Throttler:, (*9)
-
bucket_size: the number of allowed hits in the period of time of reference
-
refill_time: the amount of time after that the counter will completely or partially reset
-
refill_amount: the number of hits to be reset every time the refill_time passes
You are now able to successfully throttle users:, (*10)
$throttler = $this->getDI()->get('throttler');
$rateLimit = $throttler->consume($this->request->getClientAddress());
if ($rateLimit->isLimited()) {
// Do something
}
Strategies
The only question left is: which one is the appropriate place where the check should be performed?, (*11)
There is of course not an uniquely valid answer, several places can be used., (*12)
Check in the dispatcher, (*13)
A good strategy is to put the check during the Phalcon dispatcher lifecycle., (*14)
In the dependency injection we can use the Phalcon Event Manager to listen to the dispatcher event and bind it to some Security plugin, (*15)
$di->setShared('eventsManager',function() use ($di) {
$eventsManager = new \Phalcon\Events\Manager();
return $eventsManager;
});
$di->set('dispatcher', function () use ($di) {
//Create an EventsManager
$eventsManager = $di->getShared('eventsManager');
$security = new \MyNamespace\Security();
$eventsManager->attach('dispatch', $security);
$dispatcher = new \Phalcon\Mvc\Dispatcher();
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
and put our Rate Limiter in it, (*16)
<?php
namespace MyNamespace;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
use OakLabs\PhalconThrottler\ThrottlerInterface;
class Security extends Plugin
{
public function beforeDispatch(Event $event, Dispatcher $dispatcher)
{
/** @var ThrottlerInterface $throttler */
$throttler = $this->getDI()->get('throttler');
$rateLimit = $throttler->consume($this->request->getClientAddress());
if ($rateLimit->isLimited()) {
$dispatcher->forward(
[
'namespace' => 'MyNamespace\Http',
'controller' => 'error',
'action' => 'ratelimited',
'params' => $rateLimit->toArray()
]
);
}
}
}
and finally perform a redirection in case the User gets rate limited.
The information returned by the $rateLimit->toArray() method contains:, (*17)
[
'hits' => (int) // Number of hits in the reference period,
'remaining' =>(int) // Remaining hits before getting rate limited,
'period' => (int) // Reference period in seconds,
'hits_per_period' => (int) // Allowed number of hits in the reference period,
'warning' => (bool) // Whether a warning has been emitted,
'limited' => (bool) // Whether the User is rate limited
]
Contribution guidelines
Throttler follows PSR-1, PSR-2 and PSR-4 PHP coding standards, and semantic versioning., (*18)
Pull requests are welcome., (*19)
License
Throttler is free software distributed under the terms of the MIT license., (*20)