Completed
Pull Request — master (#166)
by
unknown
02:20
created

Server::handlePost()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 51
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 12.4085

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
eloc 32
c 2
b 0
f 0
nc 5
nop 0
dl 0
loc 51
ccs 11
cts 33
cp 0.3333
crap 12.4085
rs 9.0968

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace TusPhp\Tus;
4
5
use TusPhp\File;
6
use Carbon\Carbon;
7
use TusPhp\Request;
8
use TusPhp\Response;
9
use Ramsey\Uuid\Uuid;
10
use TusPhp\Cache\Cacheable;
11
use TusPhp\Events\UploadMerged;
12
use TusPhp\Events\UploadCreated;
13
use TusPhp\Events\UploadComplete;
14
use TusPhp\Events\UploadProgress;
15
use TusPhp\Middleware\Middleware;
16
use TusPhp\Exception\FileException;
17
use TusPhp\Exception\ConnectionException;
18
use TusPhp\Exception\OutOfRangeException;
19
use Symfony\Component\HttpFoundation\BinaryFileResponse;
20
use Symfony\Component\HttpFoundation\Response as HttpResponse;
21
22
class Server extends AbstractTus
23
{
24
    /** @const string Tus Creation Extension */
25
    const TUS_EXTENSION_CREATION = 'creation';
26
27
    /** @const string Tus Termination Extension */
28
    const TUS_EXTENSION_TERMINATION = 'termination';
29
30
    /** @const string Tus Checksum Extension */
31
    const TUS_EXTENSION_CHECKSUM = 'checksum';
32
33
    /** @const string Tus Expiration Extension */
34
    const TUS_EXTENSION_EXPIRATION = 'expiration';
35
36
    /** @const string Tus Concatenation Extension */
37
    const TUS_EXTENSION_CONCATENATION = 'concatenation';
38
39
    /** @const array All supported tus extensions */
40
    const TUS_EXTENSIONS = [
41
        self::TUS_EXTENSION_CREATION,
42
        self::TUS_EXTENSION_TERMINATION,
43
        self::TUS_EXTENSION_CHECKSUM,
44
        self::TUS_EXTENSION_EXPIRATION,
45
        self::TUS_EXTENSION_CONCATENATION,
46
    ];
47
48
    /** @const int 460 Checksum Mismatch */
49
    const HTTP_CHECKSUM_MISMATCH = 460;
50
51
    /** @const string Default checksum algorithm */
52
    const DEFAULT_CHECKSUM_ALGORITHM = 'sha256';
53
54
    /** @var Request */
55
    protected $request;
56
57
    /** @var Response */
58
    protected $response;
59
60
    /** @var string */
61
    protected $uploadDir;
62
63
    /** @var string */
64
    protected $uploadKey;
65
66
    /** @var Middleware */
67
    protected $middleware;
68
69
    /**
70
     * @var int Max upload size in bytes
71
     *          Default 0, no restriction.
72
     */
73
    protected $maxUploadSize = 0;
74
75
    /**
76
     * TusServer constructor.
77
     *
78
     * @param Cacheable|string $cacheAdapter
79
     *
80
     * @throws \ReflectionException
81
     */
82 3
    public function __construct($cacheAdapter = 'file')
83
    {
84 3
        $this->request    = new Request;
85 3
        $this->response   = new Response;
86 3
        $this->middleware = new Middleware;
87 3
        $this->uploadDir  = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'uploads';
88
89 3
        $this->setCache($cacheAdapter);
90 3
    }
91
92
    /**
93
     * Set upload dir.
94
     *
95
     * @param string $path
96
     *
97
     * @return Server
98
     */
99 1
    public function setUploadDir(string $path) : self
100
    {
101 1
        $this->uploadDir = $path;
102
103 1
        return $this;
104
    }
105
106
    /**
107
     * Get upload dir.
108
     *
109
     * @return string
110
     */
111 1
    public function getUploadDir() : string
112
    {
113 1
        return $this->uploadDir;
114
    }
115
116
    /**
117
     * Get request.
118
     *
119
     * @return Request
120
     */
121 1
    public function getRequest() : Request
122
    {
123 1
        return $this->request;
124
    }
125
126
    /**
127
     * Get request.
128
     *
129
     * @return Response
130
     */
131 1
    public function getResponse() : Response
132
    {
133 1
        return $this->response;
134
    }
135
136
    /**
137
     * Get file checksum.
138
     *
139
     * @param string $filePath
140
     *
141
     * @return string
142
     */
143 1
    public function getServerChecksum(string $filePath) : string
144
    {
145 1
        return hash_file($this->getChecksumAlgorithm(), $filePath);
146
    }
147
148
    /**
149
     * Get checksum algorithm.
150
     *
151
     * @return string|null
152
     */
153 1
    public function getChecksumAlgorithm() : ?string
154
    {
155 1
        $checksumHeader = $this->getRequest()->header('Upload-Checksum');
156
157 1
        if (empty($checksumHeader)) {
158 1
            return self::DEFAULT_CHECKSUM_ALGORITHM;
159
        }
160
161 1
        list($checksumAlgorithm, /* $checksum */) = explode(' ', $checksumHeader);
162
163 1
        return $checksumAlgorithm;
164
    }
165
166
    /**
167
     * Set upload key.
168
     *
169
     * @param string $key
170
     *
171
     * @return Server
172
     */
173
    public function setUploadKey(string $key) : self
174
    {
175
        $this->uploadKey = $key;
176
177
        return $this;
178
    }
179
180
    /**
181
     * Get upload key from header.
182
     *
183
     * @return string|HttpResponse
184
     */
185
    public function getUploadKey()
186
    {
187
        if ( ! empty($this->uploadKey)) {
188
            return $this->uploadKey;
189
        }
190
191
        $key = $this->getRequest()->header('Upload-Key') ?? Uuid::uuid4()->toString();
192
193
        if (empty($key)) {
194
            return $this->response->send(null, HttpResponse::HTTP_BAD_REQUEST);
195
        }
196
197
        $this->uploadKey = $key;
198
199
        return $this->uploadKey;
200
    }
201
202
    /**
203
     * Set middleware.
204
     *
205
     * @param Middleware $middleware
206
     *
207
     * @return self
208
     */
209 1
    public function setMiddleware(Middleware $middleware) : self
210
    {
211 1
        $this->middleware = $middleware;
212
213 1
        return $this;
214
    }
215
216
    /**
217
     * Get middleware.
218
     *
219
     * @return Middleware
220
     */
221 1
    public function middleware() : Middleware
222
    {
223 1
        return $this->middleware;
224
    }
225
226
    /**
227
     * Set max upload size.
228
     *
229
     * @param int $uploadSize
230
     *
231
     * @return Server
232
     */
233 1
    public function setMaxUploadSize(int $uploadSize) : self
234
    {
235 1
        $this->maxUploadSize = $uploadSize;
236
237 1
        return $this;
238
    }
239
240
    /**
241
     * Get max upload size.
242
     *
243
     * @return int
244
     */
245 1
    public function getMaxUploadSize() : int
246
    {
247 1
        return $this->maxUploadSize;
248
    }
249
250
    /**
251
     * Handle all HTTP request.
252
     *
253
     * @return HttpResponse|BinaryFileResponse
254
     */
255 5
    public function serve()
256
    {
257 5
        $this->applyMiddleware();
258
259 5
        $requestMethod = $this->getRequest()->method();
260
261 5
        if ( ! in_array($requestMethod, $this->getRequest()->allowedHttpVerbs())) {
262 1
            return $this->response->send(null, HttpResponse::HTTP_METHOD_NOT_ALLOWED);
263
        }
264
265 4
        $clientVersion = $this->getRequest()->header('Tus-Resumable');
266
267 4
        if ($clientVersion && $clientVersion !== self::TUS_PROTOCOL_VERSION) {
268 1
            return $this->response->send(null, HttpResponse::HTTP_PRECONDITION_FAILED, [
269 1
                'Tus-Version' => self::TUS_PROTOCOL_VERSION,
270
            ]);
271
        }
272
273 3
        $method = 'handle' . ucfirst(strtolower($requestMethod));
274
275 3
        return $this->{$method}();
276
    }
277
278
    /**
279
     * Apply middleware.
280
     *
281
     * @return void
282
     */
283 1
    protected function applyMiddleware()
284
    {
285 1
        $middleware = $this->middleware()->list();
286
287 1
        foreach ($middleware as $m) {
288 1
            $m->handle($this->getRequest(), $this->getResponse());
289
        }
290 1
    }
291
292
    /**
293
     * Handle OPTIONS request.
294
     *
295
     * @return HttpResponse
296
     */
297 2
    protected function handleOptions() : HttpResponse
298
    {
299
        $headers = [
300 2
            'Allow' => implode(',', $this->request->allowedHttpVerbs()),
301 2
            'Tus-Version' => self::TUS_PROTOCOL_VERSION,
302 2
            'Tus-Extension' => implode(',', self::TUS_EXTENSIONS),
303 2
            'Tus-Checksum-Algorithm' => $this->getSupportedHashAlgorithms(),
304
        ];
305
306 2
        $maxUploadSize = $this->getMaxUploadSize();
307
308 2
        if ($maxUploadSize > 0) {
309 1
            $headers['Tus-Max-Size'] = $maxUploadSize;
310
        }
311
312 2
        return $this->response->send(null, HttpResponse::HTTP_OK, $headers);
313
    }
314
315
    /**
316
     * Handle HEAD request.
317
     *
318
     * @return HttpResponse
319
     */
320 5
    protected function handleHead() : HttpResponse
321
    {
322 5
        $key = $this->request->key();
323
324 5
        if ( ! $fileMeta = $this->cache->get($key)) {
325 1
            return $this->response->send(null, HttpResponse::HTTP_NOT_FOUND);
326
        }
327
328 4
        $offset = $fileMeta['offset'] ?? false;
329
330 4
        if (false === $offset) {
331 1
            return $this->response->send(null, HttpResponse::HTTP_GONE);
332
        }
333
334 3
        return $this->response->send(null, HttpResponse::HTTP_OK, $this->getHeadersForHeadRequest($fileMeta));
335
    }
336
337
    /**
338
     * Handle POST request.
339
     *
340
     * @return HttpResponse
341
     */
342 3
    protected function handlePost() : HttpResponse
343
    {
344 3
        $fileName   = $this->getRequest()->extractFileName();
345 3
        $uploadType = self::UPLOAD_TYPE_NORMAL;
346
347 3
        if (empty($fileName)) {
348 1
            return $this->response->send(null, HttpResponse::HTTP_BAD_REQUEST);
349
        }
350
351 2
        if ( ! $this->verifyUploadSize()) {
352 1
            return $this->response->send(null, HttpResponse::HTTP_REQUEST_ENTITY_TOO_LARGE);
353
        }
354
355 1
        $uploadKey = $this->getUploadKey();
356 1
        $filePath  = $this->uploadDir . DIRECTORY_SEPARATOR . $fileName;
357
358 1
        if ($this->getRequest()->isFinal()) {
359 1
            return $this->handleConcatenation($fileName, $filePath);
360
        }
361
362
        if ($this->getRequest()->isPartial()) {
363
            $filePath   = $this->getPathForPartialUpload($uploadKey) . $fileName;
364
            $uploadType = self::UPLOAD_TYPE_PARTIAL;
365
        }
366
367
        $checksum = $this->getClientChecksum();
368
        $location = $this->getRequest()->url() . $this->getApiPath() . '/' . $uploadKey;
369
        $metaInfo = $this->getRequest()->extractAllMeta();
370
371
        $meta = array_merge($metaInfo, [
372
            'name' => $fileName,
373
            'offset' => 0,
374
            'size' => $this->getRequest()->header('Upload-Length'),
375
            'file_path' => $filePath,
376
            'location' => $location,
377
        ]);
378
        $file = $this->buildFile($meta)->setKey($uploadKey)->setChecksum($checksum);
379
380
        $this->cache->set($uploadKey, $file->details() + ['upload_type' => $uploadType]);
381
382
        $this->event()->dispatch(
383
            UploadCreated::NAME,
384
            new UploadCreated($file, $this->getRequest(), $this->getResponse())
385
        );
386
387
        return $this->response->send(
388
            null,
389
            HttpResponse::HTTP_CREATED,
390
            [
391
                'Location' => $location,
392
                'Upload-Expires' => $this->cache->get($uploadKey)['expires_at'],
393
            ]
394
        );
395
    }
396
397
    /**
398
     * Handle file concatenation.
399
     *
400
     * @param string $fileName
401
     * @param string $filePath
402
     *
403
     * @return HttpResponse
404
     */
405
    protected function handleConcatenation(string $fileName, string $filePath) : HttpResponse
406
    {
407
        $partials  = $this->getRequest()->extractPartials();
408
        $uploadKey = $this->getUploadKey();
409
        $files     = $this->getPartialsMeta($partials);
410
        $filePaths = array_column($files, 'file_path');
411
        $location  = $this->getRequest()->url() . $this->getApiPath() . '/' . $uploadKey;
412
413
        $metaInfo = $this->getRequest()->extractAllMeta();
414
        $meta = array_merge($metaInfo, [
415
            'name' => $fileName,
416
            'offset' => 0,
417
            'size' => 0,
418
            'file_path' => $filePath,
419
            'location' => $location,
420
        ]);
421
        $file = $this->buildFile($meta)->setFilePath($filePath)->setKey($uploadKey);
422
423
        $file->setOffset($file->merge($files));
424
425
        // Verify checksum.
426
        $checksum = $this->getServerChecksum($filePath);
427
428
        if ($checksum !== $this->getClientChecksum()) {
429
            return $this->response->send(null, self::HTTP_CHECKSUM_MISMATCH);
430
        }
431
432
        $file->setChecksum($checksum);
433
        $this->cache->set($uploadKey, $file->details() + ['upload_type' => self::UPLOAD_TYPE_FINAL]);
434
435
        // Cleanup.
436
        if ($file->delete($filePaths, true)) {
437
            $this->cache->deleteAll($partials);
438
        }
439
440
        $this->event()->dispatch(
441
            UploadMerged::NAME,
442
            new UploadMerged($file, $this->getRequest(), $this->getResponse())
443
        );
444
445
        return $this->response->send(
446
            ['data' => ['checksum' => $checksum]],
447
            HttpResponse::HTTP_CREATED,
448
            [
449
                'Location' => $location,
450
            ]
451
        );
452
    }
453
454
    /**
455
     * Handle PATCH request.
456
     *
457
     * @return HttpResponse
458
     */
459
    protected function handlePatch() : HttpResponse
460
    {
461
        $uploadKey = $this->request->key();
462
463
        if ( ! $meta = $this->cache->get($uploadKey)) {
464
            return $this->response->send(null, HttpResponse::HTTP_GONE);
465
        }
466
467
        $status = $this->verifyPatchRequest($meta);
468
469
        if (HttpResponse::HTTP_OK !== $status) {
470
            return $this->response->send(null, $status);
471
        }
472
473
        $file     = $this->buildFile($meta);
474
        $checksum = $meta['checksum'];
475
476
        try {
477
            $fileSize = $file->getFileSize();
478
            $offset   = $file->setKey($uploadKey)->setChecksum($checksum)->upload($fileSize);
479
480
            // If upload is done, verify checksum.
481
            if ($offset === $fileSize) {
482
                if ( ! $this->verifyChecksum($checksum, $meta['file_path'])) {
483
                    return $this->response->send(null, self::HTTP_CHECKSUM_MISMATCH);
484
                }
485
486
                $this->event()->dispatch(
487
                    UploadComplete::NAME,
488
                    new UploadComplete($file, $this->getRequest(), $this->getResponse())
489
                );
490
            } else {
491
                $this->event()->dispatch(
492
                    UploadProgress::NAME,
493
                    new UploadProgress($file, $this->getRequest(), $this->getResponse())
494
                );
495
            }
496
        } catch (FileException $e) {
497
            return $this->response->send($e->getMessage(), HttpResponse::HTTP_UNPROCESSABLE_ENTITY);
498
        } catch (OutOfRangeException $e) {
499
            return $this->response->send(null, HttpResponse::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);
500
        } catch (ConnectionException $e) {
501
            return $this->response->send(null, HttpResponse::HTTP_CONTINUE);
502
        }
503
504
        return $this->response->send(null, HttpResponse::HTTP_NO_CONTENT, [
505
            'Content-Type' => self::HEADER_CONTENT_TYPE,
506
            'Upload-Expires' => $this->cache->get($uploadKey)['expires_at'],
507
            'Upload-Offset' => $offset,
508
        ]);
509
    }
510
511
    /**
512
     * Verify PATCH request.
513
     *
514
     * @param array $meta
515
     *
516
     * @return int
517
     */
518
    protected function verifyPatchRequest(array $meta) : int
519
    {
520
        if (self::UPLOAD_TYPE_FINAL === $meta['upload_type']) {
521
            return HttpResponse::HTTP_FORBIDDEN;
522
        }
523
524
        $uploadOffset = $this->request->header('upload-offset');
525
526
        if ($uploadOffset && $uploadOffset !== (string) $meta['offset']) {
527
            return HttpResponse::HTTP_CONFLICT;
528
        }
529
530
        $contentType = $this->request->header('Content-Type');
531
532
        if ($contentType !== self::HEADER_CONTENT_TYPE) {
533
            return HTTPRESPONSE::HTTP_UNSUPPORTED_MEDIA_TYPE;
534
        }
535
536
        return HttpResponse::HTTP_OK;
537
    }
538
539
    /**
540
     * Handle GET request.
541
     *
542
     * As per RFC7231, we need to treat HEAD and GET as an identical request.
543
     * All major PHP frameworks follows the same and silently transforms each
544
     * HEAD requests to GET.
545
     *
546
     * @return BinaryFileResponse|HttpResponse
547
     */
548
    protected function handleGet()
549
    {
550
        // We will treat '/files/<key>/get' as a download request.
551
        if ('get' === $this->request->key()) {
552
            return $this->handleDownload();
553
        }
554
555
        return $this->handleHead();
556
    }
557
558
    /**
559
     * Handle Download request.
560
     *
561
     * @return BinaryFileResponse|HttpResponse
562
     */
563
    protected function handleDownload()
564
    {
565
        $path = explode('/', str_replace('/get', '', $this->request->path()));
566
        $key  = end($path);
567
568
        if ( ! $fileMeta = $this->cache->get($key)) {
569
            return $this->response->send('404 upload not found.', HttpResponse::HTTP_NOT_FOUND);
570
        }
571
572
        $resource = $fileMeta['file_path'] ?? null;
573
        $fileName = $fileMeta['name'] ?? null;
574
575
        if ( ! $resource || ! file_exists($resource)) {
576
            return $this->response->send('404 upload not found.', HttpResponse::HTTP_NOT_FOUND);
577
        }
578
579
        return $this->response->download($resource, $fileName);
580
    }
581
582
    /**
583
     * Handle DELETE request.
584
     *
585
     * @return HttpResponse
586
     */
587
    protected function handleDelete() : HttpResponse
588
    {
589
        $key      = $this->request->key();
590
        $fileMeta = $this->cache->get($key);
591
        $resource = $fileMeta['file_path'] ?? null;
592
593
        if ( ! $resource) {
594
            return $this->response->send(null, HttpResponse::HTTP_NOT_FOUND);
595
        }
596
597
        $isDeleted = $this->cache->delete($key);
598
599
        if ( ! $isDeleted || ! file_exists($resource)) {
600
            return $this->response->send(null, HttpResponse::HTTP_GONE);
601
        }
602
603
        unlink($resource);
604
605
        return $this->response->send(null, HttpResponse::HTTP_NO_CONTENT, [
606
            'Tus-Extension' => self::TUS_EXTENSION_TERMINATION,
607
        ]);
608
    }
609
610
    /**
611
     * Get required headers for head request.
612
     *
613
     * @param array $fileMeta
614
     *
615
     * @return array
616
     */
617 3
    protected function getHeadersForHeadRequest(array $fileMeta) : array
618
    {
619
        $headers = [
620 3
            'Upload-Length' => (int) $fileMeta['size'],
621 3
            'Upload-Offset' => (int) $fileMeta['offset'],
622 3
            'Cache-Control' => 'no-store',
623
        ];
624
625 3
        if (self::UPLOAD_TYPE_FINAL === $fileMeta['upload_type'] && $fileMeta['size'] !== $fileMeta['offset']) {
626 1
            unset($headers['Upload-Offset']);
627
        }
628
629 3
        if (self::UPLOAD_TYPE_NORMAL !== $fileMeta['upload_type']) {
630 2
            $headers += ['Upload-Concat' => $fileMeta['upload_type']];
631
        }
632
633 3
        return $headers;
634
    }
635
636
    /**
637
     * Build file object.
638
     *
639
     * @param array $meta
640
     *
641
     * @return File
642
     */
643
    protected function buildFile(array $meta) : File
644
    {
645
        $file = new File($meta['name'], $this->cache);
646
647
        if (array_key_exists('offset', $meta)) {
648
            $file->setMeta($meta['offset'], $meta['size'], $meta['file_path'], $meta['location']);
649
        }
650
651
        $metaInfo = array_filter($meta, function ($key) {
652
            return false === in_array($key, ['offset', 'size', 'file_path', 'location', 'name'], true);
653
        }, ARRAY_FILTER_USE_KEY);
654
        $file->setMetaInfo($metaInfo);
655
656
        return $file;
657
    }
658
659
    /**
660
     * Get list of supported hash algorithms.
661
     *
662
     * @return string
663
     */
664
    protected function getSupportedHashAlgorithms() : string
665
    {
666
        $supportedAlgorithms = hash_algos();
667
668
        $algorithms = [];
669
        foreach ($supportedAlgorithms as $hashAlgo) {
670
            if (false !== strpos($hashAlgo, ',')) {
671
                $algorithms[] = "'{$hashAlgo}'";
672
            } else {
673
                $algorithms[] = $hashAlgo;
674
            }
675
        }
676
677
        return implode(',', $algorithms);
678
    }
679
680
    /**
681
     * Verify and get upload checksum from header.
682
     *
683
     * @return string|HttpResponse
684
     */
685
    protected function getClientChecksum()
686
    {
687
        $checksumHeader = $this->getRequest()->header('Upload-Checksum');
688
689
        if (empty($checksumHeader)) {
690
            return '';
691
        }
692
693
        list($checksumAlgorithm, $checksum) = explode(' ', $checksumHeader);
694
695
        $checksum = base64_decode($checksum);
696
697
        if ( ! in_array($checksumAlgorithm, hash_algos()) || false === $checksum) {
698
            return $this->response->send(null, HttpResponse::HTTP_BAD_REQUEST);
699
        }
700
701
        return $checksum;
702
    }
703
704
    /**
705
     * Get expired but incomplete uploads.
706
     *
707
     * @param array|null $contents
708
     *
709
     * @return bool
710
     */
711
    protected function isExpired($contents) : bool
712
    {
713
        $isExpired = empty($contents['expires_at']) || Carbon::parse($contents['expires_at'])->lt(Carbon::now());
714
715
        if ($isExpired && $contents['offset'] !== $contents['size']) {
716
            return true;
717
        }
718
719
        return false;
720
    }
721
722
    /**
723
     * Get path for partial upload.
724
     *
725
     * @param string $key
726
     *
727
     * @return string
728
     */
729
    protected function getPathForPartialUpload(string $key) : string
730
    {
731
        list($actualKey, /* $partialUploadKey */) = explode(self::PARTIAL_UPLOAD_NAME_SEPARATOR, $key);
732
733
        $path = $this->uploadDir . DIRECTORY_SEPARATOR . $actualKey . DIRECTORY_SEPARATOR;
734
735
        if ( ! file_exists($path)) {
736
            mkdir($path);
737
        }
738
739
        return $path;
740
    }
741
742
    /**
743
     * Get metadata of partials.
744
     *
745
     * @param array $partials
746
     *
747
     * @return array
748
     */
749
    protected function getPartialsMeta(array $partials) : array
750
    {
751
        $files = [];
752
753
        foreach ($partials as $partial) {
754
            $fileMeta = $this->getCache()->get($partial);
755
756
            $files[] = $fileMeta;
757
        }
758
759
        return $files;
760
    }
761
762
    /**
763
     * Delete expired resources.
764
     *
765
     * @return array
766
     */
767
    public function handleExpiration() : array
768
    {
769
        $deleted   = [];
770
        $cacheKeys = $this->cache->keys();
771
772
        foreach ($cacheKeys as $key) {
773
            $fileMeta = $this->cache->get($key, true);
774
775
            if ( ! $this->isExpired($fileMeta)) {
776
                continue;
777
            }
778
779
            if ( ! $this->cache->delete($key)) {
780
                continue;
781
            }
782
783
            if (is_writable($fileMeta['file_path'])) {
784
                unlink($fileMeta['file_path']);
785
            }
786
787
            $deleted[] = $fileMeta;
788
        }
789
790
        return $deleted;
791
    }
792
793
    /**
794
     * Verify max upload size.
795
     *
796
     * @return bool
797
     */
798
    protected function verifyUploadSize() : bool
799
    {
800
        $maxUploadSize = $this->getMaxUploadSize();
801
802
        if ($maxUploadSize > 0 && $this->getRequest()->header('Upload-Length') > $maxUploadSize) {
803
            return false;
804
        }
805
806
        return true;
807
    }
808
809
    /**
810
     * Verify checksum if available.
811
     *
812
     * @param string $checksum
813
     * @param string $filePath
814
     *
815
     * @return bool
816
     */
817
    protected function verifyChecksum(string $checksum, string $filePath) : bool
818
    {
819
        // Skip if checksum is empty.
820
        if (empty($checksum)) {
821
            return true;
822
        }
823
824
        return $checksum === $this->getServerChecksum($filePath);
825
    }
826
827
    /**
828
     * No other methods are allowed.
829
     *
830
     * @param string $method
831
     * @param array  $params
832
     *
833
     * @return HttpResponse
834
     */
835 1
    public function __call(string $method, array $params)
836
    {
837 1
        return $this->response->send(null, HttpResponse::HTTP_BAD_REQUEST);
838
    }
839
}
840