UploadGuard   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 82
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 82
ccs 0
cts 50
cp 0
rs 10
c 0
b 0
f 0
wmc 22
lcom 1
cbo 4

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C getUploadedFiles() 0 28 14
B getMimeType() 0 18 7
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Minotaur
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7
 * use this file except in compliance with the License. You may obtain a copy of
8
 * the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
 * License for the specific language governing permissions and limitations under
16
 * the License.
17
 *
18
 * @copyright 2015-2017 Appertly
19
 * @license   Apache-2.0
20
 */
21
namespace Minotaur\Http;
22
23
use Psr\Http\Message\ServerRequestInterface as Request;
24
use Psr\Http\Message\UploadedFileInterface;
25
26
/**
27
 * A helper for dealing with file upload validation.
28
 */
29
class UploadGuard
30
{
31
    /**
32
     * @var \finfo $finfo
33
     */
34
    private $finfo;
35
36
    /**
37
     * Creates a new UploadGuard.
38
     *
39
     * @param \finfo $finfo The MIME detector
40
     */
41
    public function __construct(\finfo $finfo)
42
    {
43
        $this->finfo = $finfo;
44
    }
45
46
    /**
47
     * Gets the list of uploaded files, validating file size.
48
     *
49
     * @param Request $request The PSR HTTP Request
50
     * @param string $field The request field containing the files
51
     * @param int $maxSize The maximum allowed file size, or `null`
52
     * @return array<\Psr\Http\Message\UploadedFileInterface> The uploaded files
53
     * @throws \Caridea\Validate\Exception\Invalid if any files aren't valid
54
     */
55
    public function getUploadedFiles(Request $request, string $field, ?int $maxSize = null): array
56
    {
57
        $allFiles = $request->getUploadedFiles();
58
        if (!array_key_exists($field, $allFiles)) {
59
            throw new \Caridea\Validate\Exception\Invalid([$field => 'REQUIRED']);
60
        }
61
        $files = $allFiles[$field];
62
        $files = is_iterable($files) ? $files : [$files];
63
        foreach ($files as $file) {
64
            $error = $file->getError();
65
            if (UPLOAD_ERR_INI_SIZE === $error || UPLOAD_ERR_FORM_SIZE === $error) {
66
                throw new \Caridea\Validate\Exception\Invalid([$field => 'TOO_LONG']);
67
            } elseif (UPLOAD_ERR_PARTIAL === $error) {
68
                throw new \Caridea\Validate\Exception\Invalid([$field => 'TOO_SHORT']);
69
            } elseif (UPLOAD_ERR_NO_FILE === $error) {
70
                throw new \Caridea\Validate\Exception\Invalid([$field => 'CANNOT_BE_EMPTY']);
71
            } elseif (UPLOAD_ERR_NO_TMP_DIR === $error || UPLOAD_ERR_CANT_WRITE === $error) {
72
                throw new \RuntimeException("Cannot write uploaded file to disk");
73
            }
74
            if ($maxSize !== null && $maxSize > 0) {
75
                $size = $file->getSize();
76
                if ($size > $maxSize) {
77
                    throw new \Caridea\Validate\Exception\Invalid([$field => 'TOO_LONG']);
78
                }
79
            }
80
        }
81
        return is_array($files) ? $files : iterator_to_array($files, false);
82
    }
83
84
    /**
85
     * Validates the uploaded files in a request.
86
     *
87
     * @param \Psr\Http\Message\UploadedFileInterface $file The uploaded file
88
     * @param array<string> $mimeTypes A set of allowed MIME types (e.g. `image/svg+xml`, 'video/*')
89
     * @return string The MIME type
90
     * @throws \Caridea\Validate\Exception\Invalid if the file isn't valid
91
     */
92
    public function getMimeType(UploadedFileInterface $file, string $field, array $mimeTypes = []): string
93
    {
94
        $mime = $this->finfo->file($file->getStream()->getMetadata('uri'), FILEINFO_MIME_TYPE);
95
        if (!empty($mimeTypes) && !in_array($mime, $mimeTypes)) {
96
            $match = false;
97
            foreach ($mimeTypes as $t) {
98
                if (substr($t, -2, 2) === '/*' &&
99
                        substr_compare($mime, strstr($t, '/', true), 0, strlen($t) - 2) === 0) {
100
                    $match = true;
101
                    break;
102
                }
103
            }
104
            if (!$match) {
105
                throw new \Caridea\Validate\Exception\Invalid([$field => 'WRONG_FORMAT']);
106
            }
107
        }
108
        return $mime;
109
    }
110
}
111