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\Cache;
4
 
5
use Closure;
6
use Illuminate\Contracts\Cache\Repository as Cache;
7
use Illuminate\Support\InteractsWithTime;
8
 
9
class RateLimiter
10
{
11
    use InteractsWithTime;
12
 
13
    /**
14
     * The cache store implementation.
15
     *
16
     * @var \Illuminate\Contracts\Cache\Repository
17
     */
18
    protected $cache;
19
 
20
    /**
21
     * The configured limit object resolvers.
22
     *
23
     * @var array
24
     */
25
    protected $limiters = [];
26
 
27
    /**
28
     * Create a new rate limiter instance.
29
     *
30
     * @param  \Illuminate\Contracts\Cache\Repository  $cache
31
     * @return void
32
     */
33
    public function __construct(Cache $cache)
34
    {
35
        $this->cache = $cache;
36
    }
37
 
38
    /**
39
     * Register a named limiter configuration.
40
     *
41
     * @param  string  $name
42
     * @param  \Closure  $callback
43
     * @return $this
44
     */
45
    public function for(string $name, Closure $callback)
46
    {
47
        $this->limiters[$name] = $callback;
48
 
49
        return $this;
50
    }
51
 
52
    /**
53
     * Get the given named rate limiter.
54
     *
55
     * @param  string  $name
56
     * @return \Closure
57
     */
58
    public function limiter(string $name)
59
    {
60
        return $this->limiters[$name] ?? null;
61
    }
62
 
63
    /**
64
     * Attempts to execute a callback if it's not limited.
65
     *
66
     * @param  string  $key
67
     * @param  int  $maxAttempts
68
     * @param  \Closure  $callback
69
     * @param  int  $decaySeconds
70
     * @return mixed
71
     */
72
    public function attempt($key, $maxAttempts, Closure $callback, $decaySeconds = 60)
73
    {
74
        if ($this->tooManyAttempts($key, $maxAttempts)) {
75
            return false;
76
        }
77
 
78
        return tap($callback() ?: true, function () use ($key, $decaySeconds) {
79
            $this->hit($key, $decaySeconds);
80
        });
81
    }
82
 
83
    /**
84
     * Determine if the given key has been "accessed" too many times.
85
     *
86
     * @param  string  $key
87
     * @param  int  $maxAttempts
88
     * @return bool
89
     */
90
    public function tooManyAttempts($key, $maxAttempts)
91
    {
92
        if ($this->attempts($key) >= $maxAttempts) {
93
            if ($this->cache->has($this->cleanRateLimiterKey($key).':timer')) {
94
                return true;
95
            }
96
 
97
            $this->resetAttempts($key);
98
        }
99
 
100
        return false;
101
    }
102
 
103
    /**
104
     * Increment the counter for a given key for a given decay time.
105
     *
106
     * @param  string  $key
107
     * @param  int  $decaySeconds
108
     * @return int
109
     */
110
    public function hit($key, $decaySeconds = 60)
111
    {
112
        $key = $this->cleanRateLimiterKey($key);
113
 
114
        $this->cache->add(
115
            $key.':timer', $this->availableAt($decaySeconds), $decaySeconds
116
        );
117
 
118
        $added = $this->cache->add($key, 0, $decaySeconds);
119
 
120
        $hits = (int) $this->cache->increment($key);
121
 
122
        if (! $added && $hits == 1) {
123
            $this->cache->put($key, 1, $decaySeconds);
124
        }
125
 
126
        return $hits;
127
    }
128
 
129
    /**
130
     * Get the number of attempts for the given key.
131
     *
132
     * @param  string  $key
133
     * @return mixed
134
     */
135
    public function attempts($key)
136
    {
137
        $key = $this->cleanRateLimiterKey($key);
138
 
139
        return $this->cache->get($key, 0);
140
    }
141
 
142
    /**
143
     * Reset the number of attempts for the given key.
144
     *
145
     * @param  string  $key
146
     * @return mixed
147
     */
148
    public function resetAttempts($key)
149
    {
150
        $key = $this->cleanRateLimiterKey($key);
151
 
152
        return $this->cache->forget($key);
153
    }
154
 
155
    /**
156
     * Get the number of retries left for the given key.
157
     *
158
     * @param  string  $key
159
     * @param  int  $maxAttempts
160
     * @return int
161
     */
162
    public function remaining($key, $maxAttempts)
163
    {
164
        $key = $this->cleanRateLimiterKey($key);
165
 
166
        $attempts = $this->attempts($key);
167
 
168
        return $maxAttempts - $attempts;
169
    }
170
 
171
    /**
172
     * Get the number of retries left for the given key.
173
     *
174
     * @param  string  $key
175
     * @param  int  $maxAttempts
176
     * @return int
177
     */
178
    public function retriesLeft($key, $maxAttempts)
179
    {
180
        return $this->remaining($key, $maxAttempts);
181
    }
182
 
183
    /**
184
     * Clear the hits and lockout timer for the given key.
185
     *
186
     * @param  string  $key
187
     * @return void
188
     */
189
    public function clear($key)
190
    {
191
        $key = $this->cleanRateLimiterKey($key);
192
 
193
        $this->resetAttempts($key);
194
 
195
        $this->cache->forget($key.':timer');
196
    }
197
 
198
    /**
199
     * Get the number of seconds until the "key" is accessible again.
200
     *
201
     * @param  string  $key
202
     * @return int
203
     */
204
    public function availableIn($key)
205
    {
206
        $key = $this->cleanRateLimiterKey($key);
207
 
208
        return max(0, $this->cache->get($key.':timer') - $this->currentTime());
209
    }
210
 
211
    /**
212
     * Clean the rate limiter key from unicode characters.
213
     *
214
     * @param  string  $key
215
     * @return string
216
     */
217
    public function cleanRateLimiterKey($key)
218
    {
219
        return preg_replace('/&([a-z])[a-z]+;/i', '$1', htmlentities($key));
220
    }
221
}