Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Cache;
4
 
5
use Exception;
6
use Illuminate\Contracts\Cache\LockProvider;
7
use Illuminate\Contracts\Cache\Store;
8
use Illuminate\Contracts\Filesystem\LockTimeoutException;
9
use Illuminate\Filesystem\Filesystem;
10
use Illuminate\Filesystem\LockableFile;
11
use Illuminate\Support\InteractsWithTime;
12
 
13
class FileStore implements Store, LockProvider
14
{
15
    use InteractsWithTime, HasCacheLock, RetrievesMultipleKeys;
16
 
17
    /**
18
     * The Illuminate Filesystem instance.
19
     *
20
     * @var \Illuminate\Filesystem\Filesystem
21
     */
22
    protected $files;
23
 
24
    /**
25
     * The file cache directory.
26
     *
27
     * @var string
28
     */
29
    protected $directory;
30
 
31
    /**
32
     * Octal representation of the cache file permissions.
33
     *
34
     * @var int|null
35
     */
36
    protected $filePermission;
37
 
38
    /**
39
     * Create a new file cache store instance.
40
     *
41
     * @param  \Illuminate\Filesystem\Filesystem  $files
42
     * @param  string  $directory
43
     * @param  int|null  $filePermission
44
     * @return void
45
     */
46
    public function __construct(Filesystem $files, $directory, $filePermission = null)
47
    {
48
        $this->files = $files;
49
        $this->directory = $directory;
50
        $this->filePermission = $filePermission;
51
    }
52
 
53
    /**
54
     * Retrieve an item from the cache by key.
55
     *
56
     * @param  string|array  $key
57
     * @return mixed
58
     */
59
    public function get($key)
60
    {
61
        return $this->getPayload($key)['data'] ?? null;
62
    }
63
 
64
    /**
65
     * Store an item in the cache for a given number of seconds.
66
     *
67
     * @param  string  $key
68
     * @param  mixed  $value
69
     * @param  int  $seconds
70
     * @return bool
71
     */
72
    public function put($key, $value, $seconds)
73
    {
74
        $this->ensureCacheDirectoryExists($path = $this->path($key));
75
 
76
        $result = $this->files->put(
77
            $path, $this->expiration($seconds).serialize($value), true
78
        );
79
 
80
        if ($result !== false && $result > 0) {
81
            $this->ensurePermissionsAreCorrect($path);
82
 
83
            return true;
84
        }
85
 
86
        return false;
87
    }
88
 
89
    /**
90
     * Store an item in the cache if the key doesn't exist.
91
     *
92
     * @param  string  $key
93
     * @param  mixed  $value
94
     * @param  int  $seconds
95
     * @return bool
96
     */
97
    public function add($key, $value, $seconds)
98
    {
99
        $this->ensureCacheDirectoryExists($path = $this->path($key));
100
 
101
        $file = new LockableFile($path, 'c+');
102
 
103
        try {
104
            $file->getExclusiveLock();
105
        } catch (LockTimeoutException $e) {
106
            $file->close();
107
 
108
            return false;
109
        }
110
 
111
        $expire = $file->read(10);
112
 
113
        if (empty($expire) || $this->currentTime() >= $expire) {
114
            $file->truncate()
115
                ->write($this->expiration($seconds).serialize($value))
116
                ->close();
117
 
118
            $this->ensurePermissionsAreCorrect($path);
119
 
120
            return true;
121
        }
122
 
123
        $file->close();
124
 
125
        return false;
126
    }
127
 
128
    /**
129
     * Create the file cache directory if necessary.
130
     *
131
     * @param  string  $path
132
     * @return void
133
     */
134
    protected function ensureCacheDirectoryExists($path)
135
    {
136
        $directory = dirname($path);
137
 
138
        if (! $this->files->exists($directory)) {
139
            $this->files->makeDirectory($directory, 0777, true, true);
140
 
141
            // We're creating two levels of directories (e.g. 7e/24), so we check them both...
142
            $this->ensurePermissionsAreCorrect($directory);
143
            $this->ensurePermissionsAreCorrect(dirname($directory));
144
        }
145
    }
146
 
147
    /**
148
     * Ensure the created node has the correct permissions.
149
     *
150
     * @param  string  $path
151
     * @return void
152
     */
153
    protected function ensurePermissionsAreCorrect($path)
154
    {
155
        if (is_null($this->filePermission) ||
156
            intval($this->files->chmod($path), 8) == $this->filePermission) {
157
            return;
158
        }
159
 
160
        $this->files->chmod($path, $this->filePermission);
161
    }
162
 
163
    /**
164
     * Increment the value of an item in the cache.
165
     *
166
     * @param  string  $key
167
     * @param  mixed  $value
168
     * @return int
169
     */
170
    public function increment($key, $value = 1)
171
    {
172
        $raw = $this->getPayload($key);
173
 
174
        return tap(((int) $raw['data']) + $value, function ($newValue) use ($key, $raw) {
175
            $this->put($key, $newValue, $raw['time'] ?? 0);
176
        });
177
    }
178
 
179
    /**
180
     * Decrement the value of an item in the cache.
181
     *
182
     * @param  string  $key
183
     * @param  mixed  $value
184
     * @return int
185
     */
186
    public function decrement($key, $value = 1)
187
    {
188
        return $this->increment($key, $value * -1);
189
    }
190
 
191
    /**
192
     * Store an item in the cache indefinitely.
193
     *
194
     * @param  string  $key
195
     * @param  mixed  $value
196
     * @return bool
197
     */
198
    public function forever($key, $value)
199
    {
200
        return $this->put($key, $value, 0);
201
    }
202
 
203
    /**
204
     * Remove an item from the cache.
205
     *
206
     * @param  string  $key
207
     * @return bool
208
     */
209
    public function forget($key)
210
    {
211
        if ($this->files->exists($file = $this->path($key))) {
212
            return $this->files->delete($file);
213
        }
214
 
215
        return false;
216
    }
217
 
218
    /**
219
     * Remove all items from the cache.
220
     *
221
     * @return bool
222
     */
223
    public function flush()
224
    {
225
        if (! $this->files->isDirectory($this->directory)) {
226
            return false;
227
        }
228
 
229
        foreach ($this->files->directories($this->directory) as $directory) {
230
            $deleted = $this->files->deleteDirectory($directory);
231
 
232
            if (! $deleted || $this->files->exists($directory)) {
233
                return false;
234
            }
235
        }
236
 
237
        return true;
238
    }
239
 
240
    /**
241
     * Retrieve an item and expiry time from the cache by key.
242
     *
243
     * @param  string  $key
244
     * @return array
245
     */
246
    protected function getPayload($key)
247
    {
248
        $path = $this->path($key);
249
 
250
        // If the file doesn't exist, we obviously cannot return the cache so we will
251
        // just return null. Otherwise, we'll get the contents of the file and get
252
        // the expiration UNIX timestamps from the start of the file's contents.
253
        try {
254
            $expire = substr(
255
                $contents = $this->files->get($path, true), 0, 10
256
            );
257
        } catch (Exception $e) {
258
            return $this->emptyPayload();
259
        }
260
 
261
        // If the current time is greater than expiration timestamps we will delete
262
        // the file and return null. This helps clean up the old files and keeps
263
        // this directory much cleaner for us as old files aren't hanging out.
264
        if ($this->currentTime() >= $expire) {
265
            $this->forget($key);
266
 
267
            return $this->emptyPayload();
268
        }
269
 
270
        try {
271
            $data = unserialize(substr($contents, 10));
272
        } catch (Exception $e) {
273
            $this->forget($key);
274
 
275
            return $this->emptyPayload();
276
        }
277
 
278
        // Next, we'll extract the number of seconds that are remaining for a cache
279
        // so that we can properly retain the time for things like the increment
280
        // operation that may be performed on this cache on a later operation.
281
        $time = $expire - $this->currentTime();
282
 
283
        return compact('data', 'time');
284
    }
285
 
286
    /**
287
     * Get a default empty payload for the cache.
288
     *
289
     * @return array
290
     */
291
    protected function emptyPayload()
292
    {
293
        return ['data' => null, 'time' => null];
294
    }
295
 
296
    /**
297
     * Get the full path for the given cache key.
298
     *
299
     * @param  string  $key
300
     * @return string
301
     */
302
    protected function path($key)
303
    {
304
        $parts = array_slice(str_split($hash = sha1($key), 2), 0, 2);
305
 
306
        return $this->directory.'/'.implode('/', $parts).'/'.$hash;
307
    }
308
 
309
    /**
310
     * Get the expiration time based on the given seconds.
311
     *
312
     * @param  int  $seconds
313
     * @return int
314
     */
315
    protected function expiration($seconds)
316
    {
317
        $time = $this->availableAt($seconds);
318
 
319
        return $seconds === 0 || $time > 9999999999 ? 9999999999 : $time;
320
    }
321
 
322
    /**
323
     * Get the Filesystem instance.
324
     *
325
     * @return \Illuminate\Filesystem\Filesystem
326
     */
327
    public function getFilesystem()
328
    {
329
        return $this->files;
330
    }
331
 
332
    /**
333
     * Get the working directory of the cache.
334
     *
335
     * @return string
336
     */
337
    public function getDirectory()
338
    {
339
        return $this->directory;
340
    }
341
 
342
    /**
343
     * Get the cache key prefix.
344
     *
345
     * @return string
346
     */
347
    public function getPrefix()
348
    {
349
        return '';
350
    }
351
}