RateLimiter.php
TLDR
The file RateLimiter.php
is a part of the Illuminate\Cache
namespace in the Demo Projects
project. This file contains the RateLimiter
class that provides functionality for rate limiting in a web application.
Methods
__construct(Cache $cache)
This is the constructor method of the RateLimiter
class. It takes an instance of Cache
and assigns it to the cache
property of the class.
for(string $name, Closure $callback)
This method is used to register a named limiter configuration. It takes a string $name
and a closure $callback
as parameters. The limiter configuration is stored in the $limiters
array of the class.
limiter(string $name)
This method is used to get a named rate limiter from the registered limiters. It takes a string $name
as a parameter and returns the corresponding limiter closure if it exists, otherwise it returns null
.
attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60)
This method is used to execute a callback if it is not limited. It takes a $key
, $maxAttempts
, $callback
, and an optional $decaySeconds
parameter. If the number of attempts for the key is less than the maximum allowed attempts, the callback is executed. The method returns the result of the callback.
tooManyAttempts($key, $maxAttempts)
This method is used to determine if the given key has been "accessed" too many times. It takes a $key
and $maxAttempts
as parameters. If the number of attempts for the key is greater than or equal to the maximum allowed attempts, and a timer is set in the cache for the key, the method returns true
, otherwise it returns false
.
hit($key, $decaySeconds = 60)
This method is used to increment the counter for a given key for a given decay time. It takes a $key
and an optional $decaySeconds
parameter. The method adds a timer and a counter for the key in the cache and increments the counter. If the counter was not previously set and the counter value after increment is 1, the counter is set to 1 in the cache. The method returns the incremented counter value.
attempts($key)
This method is used to get the number of attempts for the given key. It takes a $key
as a parameter and returns the number of attempts stored in the cache for that key.
resetAttempts($key)
This method is used to reset the number of attempts for the given key. It takes a $key
as a parameter and removes the key from the cache.
remaining($key, $maxAttempts)
This method is used to get the number of retries left for the given key. It takes a $key
and $maxAttempts
as parameters and returns the remaining number of retries calculated as the difference between the maximum allowed attempts and the number of attempts for the key.
retriesLeft($key, $maxAttempts)
This method is an alias for the remaining
method. It takes a $key
and $maxAttempts
as parameters and returns the remaining number of retries.
clear($key)
This method is used to clear the hits and lockout timer for the given key. It takes a $key
as a parameter and removes the key and its timer from the cache.
availableIn($key)
This method is used to get the number of seconds until the "key" is accessible again. It takes a $key
as a parameter and calculates the remaining time in seconds by subtracting the current time from the timer value stored in the cache for the key. The method returns the remaining time in seconds.
cleanRateLimiterKey($key)
This method is used to clean the rate limiter key from unicode characters. It takes a $key
as a parameter and removes any unicode characters from the key using regular expressions and the htmlentities
function. The method returns the cleaned key.
Classes
There are no other classes defined in this file.
<?php
namespace Illuminate\Cache;
use Closure;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Support\InteractsWithTime;
class RateLimiter
{
use InteractsWithTime;
/**
* The cache store implementation.
*
* @var \Illuminate\Contracts\Cache\Repository
*/
protected $cache;
/**
* The configured limit object resolvers.
*
* @var array
*/
protected $limiters = [];
/**
* Create a new rate limiter instance.
*
* @param \Illuminate\Contracts\Cache\Repository $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
/**
* Register a named limiter configuration.
*
* @param string $name
* @param \Closure $callback
* @return $this
*/
public function for(string $name, Closure $callback)
{
$this->limiters[$name] = $callback;
return $this;
}
/**
* Get the given named rate limiter.
*
* @param string $name
* @return \Closure|null
*/
public function limiter(string $name)
{
return $this->limiters[$name] ?? null;
}
/**
* Attempts to execute a callback if it's not limited.
*
* @param string $key
* @param int $maxAttempts
* @param \Closure $callback
* @param int $decaySeconds
* @return mixed
*/
public function attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60)
{
if ($this->tooManyAttempts($key, $maxAttempts)) {
return false;
}
if (is_null($result = $callback())) {
$result = true;
}
return tap($result, function () use ($key, $decaySeconds) {
$this->hit($key, $decaySeconds);
});
}
/**
* Determine if the given key has been "accessed" too many times.
*
* @param string $key
* @param int $maxAttempts
* @return bool
*/
public function tooManyAttempts($key, $maxAttempts)
{
if ($this->attempts($key) >= $maxAttempts) {
if ($this->cache->has($this->cleanRateLimiterKey($key).':timer')) {
return true;
}
$this->resetAttempts($key);
}
return false;
}
/**
* Increment the counter for a given key for a given decay time.
*
* @param string $key
* @param int $decaySeconds
* @return int
*/
public function hit($key, $decaySeconds = 60)
{
$key = $this->cleanRateLimiterKey($key);
$this->cache->add(
$key.':timer', $this->availableAt($decaySeconds), $decaySeconds
);
$added = $this->cache->add($key, 0, $decaySeconds);
$hits = (int) $this->cache->increment($key);
if (! $added && $hits == 1) {
$this->cache->put($key, 1, $decaySeconds);
}
return $hits;
}
/**
* Get the number of attempts for the given key.
*
* @param string $key
* @return mixed
*/
public function attempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->get($key, 0);
}
/**
* Reset the number of attempts for the given key.
*
* @param string $key
* @return mixed
*/
public function resetAttempts($key)
{
$key = $this->cleanRateLimiterKey($key);
return $this->cache->forget($key);
}
/**
* Get the number of retries left for the given key.
*
* @param string $key
* @param int $maxAttempts
* @return int
*/
public function remaining($key, $maxAttempts)
{
$key = $this->cleanRateLimiterKey($key);
$attempts = $this->attempts($key);
return $maxAttempts - $attempts;
}
/**
* Get the number of retries left for the given key.
*
* @param string $key
* @param int $maxAttempts
* @return int
*/
public function retriesLeft($key, $maxAttempts)
{
return $this->remaining($key, $maxAttempts);
}
/**
* Clear the hits and lockout timer for the given key.
*
* @param string $key
* @return void
*/
public function clear($key)
{
$key = $this->cleanRateLimiterKey($key);
$this->resetAttempts($key);
$this->cache->forget($key.':timer');
}
/**
* Get the number of seconds until the "key" is accessible again.
*
* @param string $key
* @return int
*/
public function availableIn($key)
{
$key = $this->cleanRateLimiterKey($key);
return max(0, $this->cache->get($key.':timer') - $this->currentTime());
}
/**
* Clean the rate limiter key from unicode characters.
*
* @param string $key
* @return string
*/
public function cleanRateLimiterKey($key)
{
return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key));
}
}