Completed
Push — master ( 4218b5...732555 )
by Jonathan
11s
created

Server::getSourcePathPrefix()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace League\Glide;
4
5
use InvalidArgumentException;
6
use League\Flysystem\FileExistsException;
7
use League\Flysystem\FilesystemInterface;
8
use League\Glide\Api\ApiInterface;
9
use League\Glide\Filesystem\FileNotFoundException;
10
use League\Glide\Filesystem\FilesystemException;
11
use League\Glide\Responses\ResponseFactoryInterface;
12
13
class Server
14
{
15
    /**
16
     * Source file system.
17
     * @var FilesystemInterface
18
     */
19
    protected $source;
20
21
    /**
22
     * Source path prefix.
23
     * @var string
24
     */
25
    protected $sourcePathPrefix;
26
27
    /**
28
     * Cache file system.
29
     * @var FilesystemInterface
30
     */
31
    protected $cache;
32
33
    /**
34
     * Cache path prefix.
35
     * @var string
36
     */
37
    protected $cachePathPrefix;
38
39
    /**
40
     * Whether to group cache in folders.
41
     * @var bool
42
     */
43
    protected $groupCacheInFolders = true;
44
45
    /**
46
     * Whether to cache with file extensions.
47
     * @var bool
48
     */
49
    protected $cacheWithFileExtensions = false;
50
51
    /**
52
     * Image manipulation API.
53
     * @var ApiInterface
54
     */
55
    protected $api;
56
57
    /**
58
     * Response factory.
59
     * @var ResponseFactoryInterface|null
60
     */
61
    protected $responseFactory;
62
63
    /**
64
     * Base URL.
65
     * @var string
66
     */
67
    protected $baseUrl;
68
69
    /**
70
     * Default image manipulations.
71
     * @var array
72
     */
73
    protected $defaults = [];
74
75
    /**
76
     * Preset image manipulations.
77
     * @var array
78
     */
79
    protected $presets = [];
80
81
    /**
82
     * Create Server instance.
83
     * @param FilesystemInterface $source Source file system.
84
     * @param FilesystemInterface $cache  Cache file system.
85
     * @param ApiInterface        $api    Image manipulation API.
86
     */
87 162
    public function __construct(FilesystemInterface $source, FilesystemInterface $cache, ApiInterface $api)
88
    {
89 162
        $this->setSource($source);
90 162
        $this->setCache($cache);
91 162
        $this->setApi($api);
92 162
    }
93
94
    /**
95
     * Set source file system.
96
     * @param FilesystemInterface $source Source file system.
97
     */
98 162
    public function setSource(FilesystemInterface $source)
99
    {
100 162
        $this->source = $source;
101 162
    }
102
103
    /**
104
     * Get source file system.
105
     * @return FilesystemInterface Source file system.
106
     */
107 6
    public function getSource()
108
    {
109 6
        return $this->source;
110
    }
111
112
    /**
113
     * Set source path prefix.
114
     * @param string $sourcePathPrefix Source path prefix.
115
     */
116 15
    public function setSourcePathPrefix($sourcePathPrefix)
117
    {
118 15
        $this->sourcePathPrefix = trim($sourcePathPrefix, '/');
119 15
    }
120
121
    /**
122
     * Get source path prefix.
123
     * @return string Source path prefix.
124
     */
125 6
    public function getSourcePathPrefix()
126
    {
127 6
        return $this->sourcePathPrefix;
128
    }
129
130
    /**
131
     * Get source path.
132
     * @param  string                $path Image path.
133
     * @return string                The source path.
134
     * @throws FileNotFoundException
135
     */
136 78
    public function getSourcePath($path)
137
    {
138 78
        $path = trim($path, '/');
139
140 78
        if (substr($path, 0, strlen($this->baseUrl)) === $this->baseUrl) {
141 3
            $path = trim(substr($path, strlen($this->baseUrl)), '/');
142 2
        }
143
144 78
        if ($path === '') {
145 3
            throw new FileNotFoundException('Image path missing.');
146
        }
147
148 75
        if ($this->sourcePathPrefix) {
149 6
            $path = $this->sourcePathPrefix.'/'.$path;
150 4
        }
151
152 75
        return rawurldecode($path);
153
    }
154
155
    /**
156
     * Check if a source file exists.
157
     * @param  string $path Image path.
158
     * @return bool   Whether the source file exists.
159
     */
160 18
    public function sourceFileExists($path)
161
    {
162 18
        return $this->source->has($this->getSourcePath($path));
163
    }
164
165
    /**
166
     * Set base URL.
167
     * @param string $baseUrl Base URL.
168
     */
169 12
    public function setBaseUrl($baseUrl)
170
    {
171 12
        $this->baseUrl = trim($baseUrl, '/');
172 12
    }
173
174
    /**
175
     * Get base URL.
176
     * @return string Base URL.
177
     */
178 6
    public function getBaseUrl()
179
    {
180 6
        return $this->baseUrl;
181
    }
182
183
    /**
184
     * Set cache file system.
185
     * @param FilesystemInterface $cache Cache file system.
186
     */
187 162
    public function setCache(FilesystemInterface $cache)
188
    {
189 162
        $this->cache = $cache;
190 162
    }
191
192
    /**
193
     * Get cache file system.
194
     * @return FilesystemInterface Cache file system.
195
     */
196 6
    public function getCache()
197
    {
198 6
        return $this->cache;
199
    }
200
201
    /**
202
     * Set cache path prefix.
203
     * @param string $cachePathPrefix Cache path prefix.
204
     */
205 12
    public function setCachePathPrefix($cachePathPrefix)
206
    {
207 12
        $this->cachePathPrefix = trim($cachePathPrefix, '/');
208 12
    }
209
210
    /**
211
     * Get cache path prefix.
212
     * @return string Cache path prefix.
213
     */
214 6
    public function getCachePathPrefix()
215
    {
216 6
        return $this->cachePathPrefix;
217
    }
218
219
    /**
220
     * Set the group cache in folders setting.
221
     * @param bool $groupCacheInFolders Whether to group cache in folders.
222
     */
223 15
    public function setGroupCacheInFolders($groupCacheInFolders)
224
    {
225 15
        $this->groupCacheInFolders = $groupCacheInFolders;
226 15
    }
227
228
    /**
229
     * Get the group cache in folders setting.
230
     * @return bool Whether to group cache in folders.
231
     */
232 6
    public function getGroupCacheInFolders()
233
    {
234 6
        return $this->groupCacheInFolders;
235
    }
236
237
    /**
238
     * Set the cache with file extensions setting.
239
     * @param bool $groupCacheInFolders Whether to cache with file extensions.
0 ignored issues
show
Bug introduced by
There is no parameter named $groupCacheInFolders. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
240
     */
241 21
    public function setCacheWithFileExtensions($cacheWithFileExtensions)
242
    {
243 21
        $this->cacheWithFileExtensions = $cacheWithFileExtensions;
244 21
    }
245
246
    /**
247
     * Get the cache with file extensions setting.
248
     * @return bool Whether to cache with file extensions.
249
     */
250 6
    public function getCacheWithFileExtensions()
251
    {
252 6
        return $this->cacheWithFileExtensions;
253
    }
254
255
    /**
256
     * Get cache path.
257
     * @param  string $path   Image path.
258
     * @param  array  $params Image manipulation params.
259
     * @return string Cache path.
260
     */
261 60
    public function getCachePath($path, array $params = [])
262
    {
263 60
        $sourcePath = $this->getSourcePath($path);
264
265 60
        if ($this->sourcePathPrefix) {
266 3
            $sourcePath = substr($sourcePath, strlen($this->sourcePathPrefix) + 1);
267 2
        }
268
269 60
        $params = $this->getAllParams($params);
270 60
        unset($params['s'], $params['p']);
271 60
        ksort($params);
272
273 60
        $md5 = md5($sourcePath.'?'.http_build_query($params));
274
275 60
        $cachedPath = $this->groupCacheInFolders ? $sourcePath.'/'.$md5 : $md5;
276
277 60
        if ($this->cachePathPrefix) {
278 3
            $cachedPath = $this->cachePathPrefix.'/'.$cachedPath;
279 2
        }
280
        
281 60
        if ($this->cacheWithFileExtensions) {
282 12
            $cachedPath .= '.'.(isset($params['fm']) ? $params['fm'] : pathinfo($path)['extension']);
283 8
        }
284
285 60
        return $cachedPath;
286
    }
287
288
    /**
289
     * Check if a cache file exists.
290
     * @param  string $path   Image path.
291
     * @param  array  $params Image manipulation params.
292
     * @return bool   Whether the cache file exists.
293
     */
294 33
    public function cacheFileExists($path, array $params)
295
    {
296 33
        return $this->cache->has(
297 33
            $this->getCachePath($path, $params)
298 22
        );
299
    }
300
301
    /**
302
     * Delete cached manipulations for an image.
303
     * @param  string $path Image path.
304
     * @return bool   Whether the delete succeeded.
305
     */
306 6
    public function deleteCache($path)
307
    {
308 6
        if (!$this->groupCacheInFolders) {
309 3
            throw new InvalidArgumentException(
310 1
                'Deleting cached image manipulations is not possible when grouping cache into folders is disabled.'
311 2
            );
312
        }
313
314 3
        return $this->cache->deleteDir(
315 3
            dirname($this->getCachePath($path))
316 2
        );
317
    }
318
319
    /**
320
     * Set image manipulation API.
321
     * @param ApiInterface $api Image manipulation API.
322
     */
323 162
    public function setApi(ApiInterface $api)
324
    {
325 162
        $this->api = $api;
326 162
    }
327
328
    /**
329
     * Get image manipulation API.
330
     * @return ApiInterface Image manipulation API.
331
     */
332 6
    public function getApi()
333
    {
334 6
        return $this->api;
335
    }
336
337
    /**
338
     * Set default image manipulations.
339
     * @param array $defaults Default image manipulations.
340
     */
341 18
    public function setDefaults(array $defaults)
342
    {
343 18
        $this->defaults = $defaults;
344 18
    }
345
346
    /**
347
     * Get default image manipulations.
348
     * @return array Default image manipulations.
349
     */
350 6
    public function getDefaults()
351
    {
352 6
        return $this->defaults;
353
    }
354
355
    /**
356
     * Set preset image manipulations.
357
     * @param array $presets Preset image manipulations.
358
     */
359 18
    public function setPresets(array $presets)
360
    {
361 18
        $this->presets = $presets;
362 18
    }
363
364
    /**
365
     * Get preset image manipulations.
366
     * @return array Preset image manipulations.
367
     */
368 6
    public function getPresets()
369
    {
370 6
        return $this->presets;
371
    }
372
373
    /**
374
     * Get all image manipulations params, including defaults and presets.
375
     * @param  array $params Image manipulation params.
376
     * @return array All image manipulation params.
377
     */
378 63
    public function getAllParams(array $params)
379
    {
380 63
        $all = $this->defaults;
381
382 63
        if (isset($params['p'])) {
383 6
            foreach (explode(',', $params['p']) as $preset) {
384 6
                if (isset($this->presets[$preset])) {
385 6
                    $all = array_merge($all, $this->presets[$preset]);
386 4
                }
387 4
            }
388 4
        }
389
390 63
        return array_merge($all, $params);
391
    }
392
393
    /**
394
     * Set response factory.
395
     * @param ResponseFactoryInterface|null $responseFactory Response factory.
396
     */
397 15
    public function setResponseFactory(ResponseFactoryInterface $responseFactory = null)
398
    {
399 15
        $this->responseFactory = $responseFactory;
400 15
    }
401
402
    /**
403
     * Get response factory.
404
     * @return ResponseFactoryInterface Response factory.
405
     */
406 6
    public function getResponseFactory()
407
    {
408 6
        return $this->responseFactory;
409
    }
410
411
    /**
412
     * Generate and return image response.
413
     * @param  string                   $path   Image path.
414
     * @param  array                    $params Image manipulation params.
415
     * @return mixed                    Image response.
416
     * @throws InvalidArgumentException
417
     */
418 6
    public function getImageResponse($path, array $params)
419
    {
420 6
        if (is_null($this->responseFactory)) {
421 3
            throw new InvalidArgumentException(
422 1
                'Unable to get image response, no response factory defined.'
423 2
            );
424
        }
425
426 3
        $path = $this->makeImage($path, $params);
427
428 3
        return $this->responseFactory->create($this->cache, $path);
429
    }
430
431
    /**
432
     * Generate and return Base64 encoded image.
433
     * @param  string              $path   Image path.
434
     * @param  array               $params Image manipulation params.
435
     * @return string              Base64 encoded image.
436
     * @throws FilesystemException
437
     */
438 6
    public function getImageAsBase64($path, array $params)
439
    {
440 6
        $path = $this->makeImage($path, $params);
441
442 6
        $source = $this->cache->read($path);
443
444 6
        if ($source === false) {
445 3
            throw new FilesystemException(
446 3
                'Could not read the image `'.$path.'`.'
447 2
            );
448
        }
449
450 3
        return 'data:'.$this->cache->getMimetype($path).';base64,'.base64_encode($source);
451
    }
452
453
    /**
454
     * Generate and output image.
455
     * @param  string                   $path   Image path.
456
     * @param  array                    $params Image manipulation params.
457
     * @throws InvalidArgumentException
458
     */
459 3
    public function outputImage($path, array $params)
460
    {
461 3
        $path = $this->makeImage($path, $params);
462
463 3
        header('Content-Type:'.$this->cache->getMimetype($path));
464 3
        header('Content-Length:'.$this->cache->getSize($path));
465 3
        header('Cache-Control:'.'max-age=31536000, public');
466 3
        header('Expires:'.date_create('+1 years')->format('D, d M Y H:i:s').' GMT');
467
468 3
        $stream = $this->cache->readStream($path);
469
470 3
        if (ftell($stream) !== 0) {
471 3
            rewind($stream);
472 2
        }
473 3
        fpassthru($stream);
474 3
        fclose($stream);
475 3
    }
476
477
    /**
478
     * Generate manipulated image.
479
     * @param  string                $path   Image path.
480
     * @param  array                 $params Image manipulation params.
481
     * @return string                Cache path.
482
     * @throws FileNotFoundException
483
     * @throws FilesystemException
484
     */
485 30
    public function makeImage($path, array $params)
486
    {
487 30
        $sourcePath = $this->getSourcePath($path);
488 30
        $cachedPath = $this->getCachePath($path, $params);
489
490 30
        if ($this->cacheFileExists($path, $params) === true) {
491 15
            return $cachedPath;
492
        }
493
494 15
        if ($this->sourceFileExists($path) === false) {
495 3
            throw new FileNotFoundException(
496 3
                'Could not find the image `'.$sourcePath.'`.'
497 2
            );
498
        }
499
500 12
        $source = $this->source->read(
501
            $sourcePath
502 8
        );
503
504 12
        if ($source === false) {
505 3
            throw new FilesystemException(
506 3
                'Could not read the image `'.$sourcePath.'`.'
507 2
            );
508
        }
509
510
        // We need to write the image to the local disk before
511
        // doing any manipulations. This is because EXIF data
512
        // can only be read from an actual file.
513 9
        $tmp = tempnam(sys_get_temp_dir(), 'Glide');
514
515 9
        if (file_put_contents($tmp, $source) === false) {
516
            throw new FilesystemException(
517
                'Unable to write temp file for `'.$sourcePath.'`.'
518
            );
519
        }
520
521
        try {
522 9
            $write = $this->cache->write(
523 6
                $cachedPath,
524 9
                $this->api->run($tmp, $this->getAllParams($params))
525 6
            );
526
527 6
            if ($write === false) {
528 3
                throw new FilesystemException(
529 4
                    'Could not write the image `'.$cachedPath.'`.'
530 2
                );
531
            }
532 8
        } catch (FileExistsException $exception) {
533
            // This edge case occurs when the target already exists
534
            // because it's currently be written to disk in another
535
            // request. It's best to just fail silently.
536
        }
537
538 6
        unlink($tmp);
539
540 6
        return $cachedPath;
541
    }
542
}
543