Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Routing\Middleware;
4
 
5
use Closure;
6
use Illuminate\Cache\RateLimiter;
7
use Illuminate\Contracts\Redis\Factory as Redis;
8
use Illuminate\Redis\Limiters\DurationLimiter;
9
 
10
class ThrottleRequestsWithRedis extends ThrottleRequests
11
{
12
    /**
13
     * The Redis factory implementation.
14
     *
15
     * @var \Illuminate\Contracts\Redis\Factory
16
     */
17
    protected $redis;
18
 
19
    /**
20
     * The timestamp of the end of the current duration by key.
21
     *
22
     * @var array
23
     */
24
    public $decaysAt = [];
25
 
26
    /**
27
     * The number of remaining slots by key.
28
     *
29
     * @var array
30
     */
31
    public $remaining = [];
32
 
33
    /**
34
     * Create a new request throttler.
35
     *
36
     * @param  \Illuminate\Cache\RateLimiter  $limiter
37
     * @param  \Illuminate\Contracts\Redis\Factory  $redis
38
     * @return void
39
     */
40
    public function __construct(RateLimiter $limiter, Redis $redis)
41
    {
42
        parent::__construct($limiter);
43
 
44
        $this->redis = $redis;
45
    }
46
 
47
    /**
48
     * Handle an incoming request.
49
     *
50
     * @param  \Illuminate\Http\Request  $request
51
     * @param  \Closure  $next
52
     * @param  array  $limits
53
     * @return \Symfony\Component\HttpFoundation\Response
54
     *
55
     * @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
56
     */
57
    protected function handleRequest($request, Closure $next, array $limits)
58
    {
59
        foreach ($limits as $limit) {
60
            if ($this->tooManyAttempts($limit->key, $limit->maxAttempts, $limit->decayMinutes)) {
61
                throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
62
            }
63
        }
64
 
65
        $response = $next($request);
66
 
67
        foreach ($limits as $limit) {
68
            $response = $this->addHeaders(
69
                $response,
70
                $limit->maxAttempts,
71
                $this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
72
            );
73
        }
74
 
75
        return $response;
76
    }
77
 
78
    /**
79
     * Determine if the given key has been "accessed" too many times.
80
     *
81
     * @param  string  $key
82
     * @param  int  $maxAttempts
83
     * @param  int  $decayMinutes
84
     * @return mixed
85
     */
86
    protected function tooManyAttempts($key, $maxAttempts, $decayMinutes)
87
    {
88
        $limiter = new DurationLimiter(
89
            $this->redis, $key, $maxAttempts, $decayMinutes * 60
90
        );
91
 
92
        return tap(! $limiter->acquire(), function () use ($key, $limiter) {
93
            [$this->decaysAt[$key], $this->remaining[$key]] = [
94
                $limiter->decaysAt, $limiter->remaining,
95
            ];
96
        });
97
    }
98
 
99
    /**
100
     * Calculate the number of remaining attempts.
101
     *
102
     * @param  string  $key
103
     * @param  int  $maxAttempts
104
     * @param  int|null  $retryAfter
105
     * @return int
106
     */
107
    protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null)
108
    {
109
        return is_null($retryAfter) ? $this->remaining[$key] : 0;
110
    }
111
 
112
    /**
113
     * Get the number of seconds until the lock is released.
114
     *
115
     * @param  string  $key
116
     * @return int
117
     */
118
    protected function getTimeUntilNextRetry($key)
119
    {
120
        return $this->decaysAt[$key] - $this->currentTime();
121
    }
122
}