RateLimitManager.php in RESTful 7.2
File
src/RateLimit/RateLimitManager.php
View source
<?php
namespace Drupal\restful\RateLimit;
use Drupal\Component\Plugin\PluginBase;
use Drupal\restful\Exception\FloodException;
use Drupal\restful\Http\HttpHeader;
use Drupal\restful\Http\RequestInterface;
use Drupal\restful\Plugin\RateLimitPluginManager;
use Drupal\restful\Plugin\rate_limit\RateLimit;
use Drupal\restful\Plugin\resource\ResourceInterface;
class RateLimitManager implements RateLimitManagerInterface {
const UNLIMITED_RATE_LIMIT = -1;
protected $account;
protected $resource;
protected $plugins;
public function setAccount($account) {
$this->account = $account;
}
public function getAccount() {
return $this->account;
}
public function __construct(ResourceInterface $resource, array $plugin_options, $account = NULL, RateLimitPluginManager $manager = NULL) {
$this->resource = $resource;
$account = $account ? $account : $resource
->getAccount();
$this->account = $account ? $account : drupal_anonymous_user();
$manager = $manager ?: RateLimitPluginManager::create();
$options = array();
foreach ($plugin_options as $plugin_id => $rate_options) {
$instance_id = $resource
->getResourceName() . PluginBase::DERIVATIVE_SEPARATOR . $plugin_id;
$options[$instance_id] = array(
'id' => $plugin_id,
'resource' => $resource,
);
$options[$instance_id] += $rate_options;
}
$this->plugins = new RateLimitPluginCollection($manager, $options);
}
public function checkRateLimit(RequestInterface $request) {
$now = new \DateTime();
$now
->setTimestamp(REQUEST_TIME);
foreach ($this->plugins as $instance_id => $plugin) {
$limit = $plugin
->getLimit($this->account);
$period = $plugin
->getPeriod();
if ($limit == static::UNLIMITED_RATE_LIMIT) {
continue;
}
if (!$plugin
->isRequestedEvent($request)) {
continue;
}
if (!($rate_limit_entity = $plugin
->loadRateLimitEntity($this->account))) {
$rate_limit_entity = entity_create('rate_limit', array(
'timestamp' => REQUEST_TIME,
'expiration' => $now
->add($period)
->format('U'),
'hits' => 0,
'event' => $plugin
->getPluginId(),
'identifier' => $plugin
->generateIdentifier($this->account),
));
}
$new_period = new \DateTime();
$new_period
->setTimestamp($rate_limit_entity->expiration);
if ($rate_limit_entity
->isExpired()) {
$rate_limit_entity->timestamp = REQUEST_TIME;
$rate_limit_entity->expiration = $now
->add($period)
->format('U');
$rate_limit_entity->hits = 0;
if ($limit == 0) {
$exception = new FloodException('Rate limit reached');
$exception
->setHeader('Retry-After', $new_period
->format(\DateTime::RFC822));
throw $exception;
}
}
else {
if ($rate_limit_entity->hits >= $limit) {
$exception = new FloodException('Rate limit reached');
$exception
->setHeader('Retry-After', $new_period
->format(\DateTime::RFC822));
throw $exception;
}
}
$rate_limit_entity
->hit();
$remaining = $limit == static::UNLIMITED_RATE_LIMIT ? 'unlimited' : $limit - ($rate_limit_entity->hits + 1);
$response = restful()
->getResponse();
$headers = $response
->getHeaders();
$headers
->append(HttpHeader::create('X-Rate-Limit-Limit', $limit));
$headers
->append(HttpHeader::create('X-Rate-Limit-Remaining', $remaining));
$time_remaining = $rate_limit_entity->expiration - REQUEST_TIME;
$headers
->append(HttpHeader::create('X-Rate-Limit-Reset', $time_remaining));
}
}
public static function deleteExpired() {
$query = new \EntityFieldQuery();
$results = $query
->entityCondition('entity_type', 'rate_limit')
->propertyCondition('expiration', REQUEST_TIME, '>')
->execute();
if (!empty($results['rate_limit'])) {
$rlids = array_keys($results['rate_limit']);
entity_delete_multiple('rate_limit', $rlids);
}
}
}