Skip to content

Instantly share code, notes, and snippets.

@stevebauman
Created October 29, 2019 16:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevebauman/48ef5c189e8a62a799e70ad043067631 to your computer and use it in GitHub Desktop.
Save stevebauman/48ef5c189e8a62a799e70ad043067631 to your computer and use it in GitHub Desktop.
A Laravel validation rule for throttling form requests.
<?php
namespace App\Http\Requests;
use App\Rules\Throttle;
use Illuminate\Foundation\Http\FormRequest;
class SubmissionFormRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'my-field' => [
'required',
'max:250',
new Throttle('submission', $maxAttempts = 5, $decayInMinutes = 10)
],
];
}
}
<?php
namespace App\Rules;
use Illuminate\Http\Request;
use Illuminate\Cache\RateLimiter;
use Illuminate\Contracts\Validation\Rule;
class Throttle implements Rule
{
/**
* The throttle key.
*
* @var string
*/
protected $key = 'validation';
/**
* The maximum number of attempts a user can perform.
*
* @var int
*/
protected $maxAttempts = 5;
/**
* The amount of minutes to restrict the requests by.
*
* @var int
*/
protected $decayInMinutes = 10;
/**
* Create a new rule instance.
*
* @param string $key
* @param int $maxAttempts
* @param int $decayInMinutes
*
* @return void
*/
public function __construct($key = 'validation', $maxAttempts = 5, $decayInMinutes = 10)
{
$this->key = $key;
$this->maxAttempts = $maxAttempts;
$this->decayInMinutes = $decayInMinutes;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value)
{
if ($this->hasTooManyAttempts()) {
return false;
}
$this->incrementAttempts();
return true;
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return __('Too many attempts. Please try again later.');
}
/**
* Determine if the user has too many failed login attempts.
*
* @return bool
*/
protected function hasTooManyAttempts()
{
return $this->limiter()->tooManyAttempts(
$this->throttleKey(), $this->maxAttempts
);
}
/**
* Increment the login attempts for the user.
*
* @return void
*/
protected function incrementAttempts()
{
$this->limiter()->hit(
$this->throttleKey(), $this->decayInMinutes
);
}
/**
* Get the throttle key for the given request.
*
* @return string
*/
protected function throttleKey()
{
return $this->key . '|' . $this->request()->ip();
}
/**
* Get the rate limiter instance.
*
* @return \Illuminate\Cache\RateLimiter
*/
protected function limiter()
{
return app(RateLimiter::class);
}
/**
* Get the current HTTP request.
*
* @return \Illuminate\Http\Request
*/
protected function request()
{
return app(Request::class);
}
}
@marchershey
Copy link

Thank you for this!

@abumusazangi
Copy link

@stevebauman
How do i get the number of remaining seconds in message function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment