Completed
Pull Request — 2.x (#118)
by jake
02:48
created

UploadedFile::required()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\Filter\Rule\Validate;
10
11
use Psr\Http\Message\UploadedFileInterface;
12
13
/**
14
 *
15
 * Validates that the value is a PSR7 UploadedFile with various properties
16
 *
17
 * @package Aura.Filter
18
 *
19
 */
20
class UploadedFile
21
{
22
23
    const REQUIRED       = 'required';
24
    const FILE_EXTENSION = 'fileExtension';
25
    const FILE_MEDIA     = 'fileMedia';
26
    const SIZE_MAX       = 'sizeMax';
27
    const SIZE_MIN       = 'sizeMin';
28
29
    protected $rules = array(
30
        self::REQUIRED,
31
        self::FILE_EXTENSION,
32
        self::FILE_MEDIA,
33
        self::SIZE_MAX,
34
        self::SIZE_MIN,
35
    );
36
37
38
    /**
39
     *
40
     * Validates the presenece and properites if a PSR7 FileUploadInterface
41
     *
42
     * valid options:
43
     *  - required      : bool require file is uploaded
44
     *  - fileExtension : array or strign of acceptable file extensions
45
     *  - fileMedia     : array or strign of acceptable file media types
46
     *  - sizeMax       : bytes or human readable string
47
     *  - sizeMin       : bytes or human readable string
48
     *
49
     * @param object $subject The subject to be filtered.
50
     *
51
     * @param string $field The subject field name.
52
     *
53
     * @return bool True if valid, false if not.
54
     *
55
     */
56 25
    public function __invoke($subject, $field, array $options)
57
    {
58 25
        $value = $subject->$field;
59
60 25
        if (! $this->isRequired($options)
61 25
            && ! $this->fileWasUploaded($value)
62 25
        ) {
63 5
            return true;
64
        }
65
66 20
        foreach ($this->rules as $rule) {
67 20
            if (array_key_exists($rule, $options)) {
68 20
                if (! $this->$rule($value, $options[$rule])) {
69 10
                    return false;
70
                }
71 10
            }
72 18
        }
73
        // looks like we're ok!
74 10
        return true;
75
    }
76
77
    /**
78
     * If the file required to be uploaded?
79
     *
80
     * @param array $options the options passed tot the filter
81
     *
82
     * @return bool
83
     *
84
     * @access protected
85
     */
86 25
    protected function isRequired(array $options)
87
    {
88
        return (
89 25
            isset($options[self::REQUIRED])
90 25
            && $options[self::REQUIRED] == true
91 25
        );
92
    }
93
94
    /**
95
     * Is value an instance of a PSR7 UploadedFileInterface?
96
     *
97
     * @param mixed $value value being validated
98
     *
99
     * @return bool
100
     *
101
     * @access protected
102
     */
103 25
    protected function isUploadedFile($value)
104
    {
105 25
        return ($value instanceof UploadedFileInterface);
106
    }
107
108
    /**
109
     * Was a file uploaded ?
110
     *
111
     * @param mixed $value value being validated
112
     *
113
     * @return bool
114
     *
115
     * @access protected
116
     */
117 25
    protected function fileWasUploaded($value)
118
    {
119 25
        if (! $this->isUploadedFile($value)) {
120 1
            return false;
121
        }
122
123 24
        if ($value->getError() !==  UPLOAD_ERR_OK) {
124 6
            return false;
125
        }
126
127 18
        return true;
128
    }
129
130
    /**
131
     * Required Rule Test
132
     *
133
     * @param mixed $value  value being validated
134
     * @param bool  $option if the file is required
135
     *
136
     * @return bool
137
     *
138
     * @access protected
139
     */
140 4
    protected function required($value, $option)
141
    {
142 4
        if ($option === false) {
143 1
            return true;
144
        }
145
146 3
        return $this->fileWasUploaded($value);
147
    }
148
149
    /**
150
     * FileExtension Rule Test
151
     *
152
     * @param mixed        $value value being validated
153
     * @param string|array $exts  array or string of valid extensions
154
     *
155
     * @return bool
156
     *
157
     * @access protected
158
     */
159 4
    protected function fileExtension($value, $exts)
160
    {
161 4
        $filename = $value->getClientFilename();
162 4
        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
163 4
        return in_array($ext, array_map('strtolower', (array) $exts));
164
    }
165
166
    /**
167
     * FileMedia Rule Test
168
     *
169
     * @param mixed        $value  value being validated
170
     * @param string|array $medias array or string of valid media types
171
     *
172
     * @return bool
173
     *
174
     * @access protected
175
     */
176 4
    protected function fileMedia($value, $medias)
177
    {
178 4
        $media = $value->getClientMediaType();
179 4
        return in_array($media, (array) $medias);
180
    }
181
182
    /**
183
     * SizeMax Rule Test
184
     *
185
     * @param mixed $value value being validated
186
     * @param mixed $max   maximum file size
187
     *
188
     * @return bool
189
     *
190
     * @access protected
191
     */
192 4
    protected function sizeMax($value, $max)
193
    {
194 4
        $size = $value->getSize();
195 4
        return $size < $this->parseHumanSize($max);
196
    }
197
198
    /**
199
     * SizeMin
200
     *
201
     * @param mixed $value value being validated
202
     * @param mixed $min   minimum file size
203
     *
204
     * @return mixed
205
     *
206
     * @access protected
207
     */
208 4
    protected function sizeMin($value, $min)
209
    {
210 4
        $size = $value->getSize();
211 4
        return $size > $this->parseHumanSize($min);
212
    }
213
214
    /**
215
     * Parse human readable size to bytes
216
     *
217
     * @param mixed $size size indicator
218
     *
219
     * @return double|int
220
     *
221
     * @access public
222
     */
223 9
    public function parseHumanSize($size)
224
    {
225 9
        $number = substr($size, 0, -2);
226 9
        switch(strtoupper(substr($size, -2))){
227 9
        case "KB":
228 4
            return $number * 1024;
229 6
        case "MB":
230 2
            return $number * pow(1024, 2);
231 5
        case "GB":
232 1
            return $number * pow(1024, 3);
233 5
        case "TB":
234 1
            return $number * pow(1024, 4);
235 5
        case "PB":
236 1
            return $number * pow(1024, 5);
237 4
        default:
238 4
            return $size;
239 4
        }
240
    }
241
}
242