Introduction
Laravel includes a simple to use rate limiting abstraction which, in conjunction with your application's cache, provides an easy way to limit any action during a specified window of time.
Note:
If you are interested in rate limiting incoming HTTP requests, please consult the rate limiter middleware documentation.
Cache Configuration
Typically, the rate limiter utilizes your default
application cache as defined by the default
key within your application's cache
configuration file. However, you may specify which cache
driver the rate limiter should use by defining a
limiter
key within your application's
cache
configuration file:
'default' => 'memcached',
'limiter' => 'redis',
Basic Usage
The Illuminate\Support\Facades\RateLimiter
facade may be used to interact with the rate limiter.
The simplest method offered by the rate limiter is the
attempt
method, which rate limits a given
callback for a given number of seconds.
The attempt
method returns
false
when the callback has no remaining
attempts available; otherwise, the attempt
method will return the callback's result or
true
. The first argument accepted by the
attempt
method is a rate limiter
"key", which may be any string of your
choosing that represents the action being rate
limited:
use Illuminate\Support\Facades\RateLimiter;
$executed = RateLimiter::attempt(
'send-message:'.$user->id,
$perMinute = 5,
function() {
// Send message...
}
);
if (! $executed) {
return 'Too many messages sent!';
}
If necessary, you may provide a fourth argument to the
attempt
method, which is the "decay
rate", or the number of seconds until the available
attempts are reset. For example, we can modify the
example above to allow five attempts every two
minutes:
$executed = RateLimiter::attempt(
'send-message:'.$user->id,
$perTwoMinutes = 5,
function() {
// Send message...
},
$decayRate = 120,
);
Manually Incrementing Attempts
If you would like to manually interact with the rate
limiter, a variety of other methods are available. For
example, you may invoke the tooManyAttempts
method to determine if a given rate limiter key has
exceeded its maximum number of allowed attempts per
minute:
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
return 'Too many attempts!';
}
RateLimiter::increment('send-message:'.$user->id);
// Send message...
Alternatively, you may use the remaining
method to retrieve the number of attempts remaining for
a given key. If a given key has retries remaining, you
may invoke the increment
method to
increment the number of total attempts:
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) {
RateLimiter::increment('send-message:'.$user->id);
// Send message...
}
If you would like to increment the value for a given rate
limiter key by more than one, you may provide the
desired amount to the increment
method:
RateLimiter::increment('send-message:'.$user->id, amount: 5);
Determining Limiter Availability
When a key has no more attempts left, the
availableIn
method returns the number of
seconds remaining until more attempts will be
available:
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
$seconds = RateLimiter::availableIn('send-message:'.$user->id);
return 'You may try again in '.$seconds.' seconds.';
}
RateLimiter::increment('send-message:'.$user->id);
// Send message...
Clearing Attempts
You may reset the number of attempts for a given rate
limiter key using the clear
method. For
example, you may reset the number of attempts when a
given message is read by the receiver:
use App\Models\Message;
use Illuminate\Support\Facades\RateLimiter;
/**
* Mark the message as read.
*/
public function read(Message $message): Message
{
$message->markAsRead();
RateLimiter::clear('send-message:'.$message->user_id);
return $message;
}