<?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)); } }
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
Console | Folder | 0755 |
|
|
Events | Folder | 0755 |
|
|
RateLimiting | Folder | 0755 |
|
|
ApcStore.php | File | 2.53 KB | 0644 |
|
ApcWrapper.php | File | 1.85 KB | 0644 |
|
ArrayLock.php | File | 2.03 KB | 0644 |
|
ArrayStore.php | File | 4.55 KB | 0644 |
|
CacheLock.php | File | 1.79 KB | 0644 |
|
CacheManager.php | File | 10.44 KB | 0644 |
|
CacheServiceProvider.php | File | 1.32 KB | 0644 |
|
DatabaseLock.php | File | 3.52 KB | 0644 |
|
DatabaseStore.php | File | 10.1 KB | 0644 |
|
DynamoDbLock.php | File | 1.56 KB | 0644 |
|
DynamoDbStore.php | File | 14.63 KB | 0644 |
|
FileLock.php | File | 271 B | 0644 |
|
FileStore.php | File | 9 KB | 0644 |
|
HasCacheLock.php | File | 681 B | 0644 |
|
LICENSE.md | File | 1.05 KB | 0644 |
|
Lock.php | File | 3.46 KB | 0644 |
|
LuaScripts.php | File | 462 B | 0644 |
|
MemcachedConnector.php | File | 2.33 KB | 0644 |
|
MemcachedLock.php | File | 1.42 KB | 0644 |
|
MemcachedStore.php | File | 6.18 KB | 0644 |
|
NoLock.php | File | 692 B | 0644 |
|
NullStore.php | File | 2.34 KB | 0644 |
|
PhpRedisLock.php | File | 829 B | 0644 |
|
RateLimiter.php | File | 4.93 KB | 0644 |
|
RedisLock.php | File | 1.75 KB | 0644 |
|
RedisStore.php | File | 9.83 KB | 0644 |
|
RedisTagSet.php | File | 3.07 KB | 0644 |
|
RedisTaggedCache.php | File | 2.8 KB | 0644 |
|
Repository.php | File | 16.67 KB | 0644 |
|
RetrievesMultipleKeys.php | File | 1.13 KB | 0644 |
|
TagSet.php | File | 2.46 KB | 0644 |
|
TaggableStore.php | File | 421 B | 0644 |
|
TaggedCache.php | File | 2.5 KB | 0644 |
|
composer.json | File | 1.49 KB | 0644 |
|