Passed
Push — master ( f53c15...e7ac2a )
by Bruno
09:12
created

File::validate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 3
nop 4
dl 0
loc 15
rs 10
1
<?php declare(strict_types=1);
2
3
namespace Formularium\Validator;
4
5
use Formularium\Datatype;
6
use Formularium\Exception\ValidatorException;
7
use Formularium\Model;
8
use Formularium\ValidatorArgs;
9
use Formularium\ValidatorInterface;
10
use Formularium\ValidatorMetadata;
11
12
/**
13
 * File validation
14
 */
15
class File implements ValidatorInterface
16
{
17
    const MAX_SIZE = 'maxSize';
18
19
    /**
20
     * Key for extension. Value can be array or string.
21
     */
22
    const ACCEPT = 'accept';
23
    const ACCEPT_AUDIO = 'audio/*';
24
    const ACCEPT_IMAGE = 'image/*';
25
    const ACCEPT_VIDEO = 'video/*';
26
27
    protected static function size(string $value, array $options = []): void
28
    {
29
        $max_size = $options[self::MAX_SIZE] ?? 0;
30
        if ($max_size > 0 && filesize($value) > $max_size) {
31
            throw new ValidatorException(
32
                'File too big. Maximum size: ' . $max_size
33
            );
34
        }
35
    }
36
37
    protected static function accept(string $value, array $options = []): void
38
    {
39
        $accept = $options[self::ACCEPT];
40
        if (!is_array($accept)) {
41
            $accept = [$accept];
42
        }
43
44
        /**
45
         * @var array $accept
46
         */
47
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
48
        if ($finfo === false) {
49
            throw new ValidatorException(
50
                'Cannot load fileinfo'
51
            );
52
        }
53
        $mime = finfo_file($finfo, $value);
54
55
        $valid = false;
56
        foreach ($accept as $a) {
57
            switch ($a) {
58
                case self::ACCEPT_AUDIO:
59
                    $validMimes = [
60
                        'audio/aac',
61
                        'audio/mpeg',
62
                        'audio/ogg',
63
                        'audio/wav',
64
                        'audio/webm',
65
                    ];
66
                    if (in_array($mime, $validMimes)) {
67
                        $valid = true;
68
                        break;
69
                    }
70
                break;
71
                case self::ACCEPT_IMAGE:
72
                    $validMimes = [
73
                        'image/jpg',
74
                        'image/jpeg',
75
                        'image/gif',
76
                        'image/png',
77
                        'image/webp'
78
                    ];
79
                    if (in_array($mime, $validMimes)) {
80
                        $valid = true;
81
                        break;
82
                    }
83
                break;
84
                case self::ACCEPT_VIDEO:
85
                    $validMimes = [
86
                        'video/x-flv',
87
                        'video/mp4',
88
                        'video/mpeg',
89
                        'application/x-mpegURL',
90
                        'video/MP2T',
91
                        'video/3gpp',
92
                        'video/ogg',
93
                        'video/quicktime',
94
                        'video/x-msvideo',
95
                        'video/x-ms-wmv',
96
                        'video/webm',
97
                    ];
98
                    if (in_array($mime, $validMimes)) {
99
                        $valid = true;
100
                        break;
101
                    }
102
                break;
103
            }
104
        }
105
106
        // TODO: 'accept' extensions
107
108
        if (!$valid) {
109
            throw new ValidatorException(
110
                'Not an accepted file'
111
            );
112
        }
113
    }
114
115
    public static function validate($value, array $options = [], Datatype $datatype, ?Model $model = null)
116
    {
117
        if ($datatype->getBasetype() !== 'file') {
118
            throw new ValidatorException(
119
                'Not a file'
120
            );
121
        }
122
123
        self::size($value, $options);
124
125
        if ($options[self::ACCEPT] ?? false) {
126
            self::accept($value, $options);
127
        }
128
129
        return $value;
130
    }
131
132
    public static function getMetadata(): ValidatorMetadata
133
    {
134
        return new ValidatorMetadata(
135
            'File',
136
            "File validations.",
137
            [
138
                new ValidatorArgs(
139
                    self::MAX_SIZE,
140
                    'Int',
141
                    'Maximum file size in bytes'
142
                ),
143
                new ValidatorArgs(
144
                    self::ACCEPT,
145
                    '[String]',
146
                    'Acceptable types'
147
                )
148
            ]
149
        );
150
    }
151
}
152