1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.yiiframework.com/ |
4
|
|
|
* @copyright Copyright (c) 2008 Yii Software LLC |
5
|
|
|
* @license http://www.yiiframework.com/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace yii\validators; |
9
|
|
|
|
10
|
|
|
use Yii; |
11
|
|
|
use yii\helpers\FileHelper; |
12
|
|
|
use yii\helpers\Html; |
13
|
|
|
use yii\helpers\Json; |
14
|
|
|
use yii\helpers\StringHelper; |
15
|
|
|
use yii\web\JsExpression; |
16
|
|
|
use yii\web\UploadedFile; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* FileValidator verifies if an attribute is receiving a valid uploaded file. |
20
|
|
|
* |
21
|
|
|
* Note that you should enable `fileinfo` PHP extension. |
22
|
|
|
* |
23
|
|
|
* @property int $sizeLimit The size limit for uploaded files. This property is read-only. |
24
|
|
|
* |
25
|
|
|
* @author Qiang Xue <[email protected]> |
26
|
|
|
* @since 2.0 |
27
|
|
|
*/ |
28
|
|
|
class FileValidator extends Validator |
29
|
|
|
{ |
30
|
|
|
/** |
31
|
|
|
* @var array|string a list of file name extensions that are allowed to be uploaded. |
32
|
|
|
* This can be either an array or a string consisting of file extension names |
33
|
|
|
* separated by space or comma (e.g. "gif, jpg"). |
34
|
|
|
* Extension names are case-insensitive. Defaults to null, meaning all file name |
35
|
|
|
* extensions are allowed. |
36
|
|
|
* @see wrongExtension for the customized message for wrong file type. |
37
|
|
|
*/ |
38
|
|
|
public $extensions; |
39
|
|
|
/** |
40
|
|
|
* @var bool whether to check file type (extension) with mime-type. If extension produced by |
41
|
|
|
* file mime-type check differs from uploaded file extension, the file will be considered as invalid. |
42
|
|
|
*/ |
43
|
|
|
public $checkExtensionByMimeType = true; |
44
|
|
|
/** |
45
|
|
|
* @var array|string a list of file MIME types that are allowed to be uploaded. |
46
|
|
|
* This can be either an array or a string consisting of file MIME types |
47
|
|
|
* separated by space or comma (e.g. "text/plain, image/png"). |
48
|
|
|
* The mask with the special character `*` can be used to match groups of mime types. |
49
|
|
|
* For example `image/*` will pass all mime types, that begin with `image/` (e.g. `image/jpeg`, `image/png`). |
50
|
|
|
* Mime type names are case-insensitive. Defaults to null, meaning all MIME types are allowed. |
51
|
|
|
* @see wrongMimeType for the customized message for wrong MIME type. |
52
|
|
|
*/ |
53
|
|
|
public $mimeTypes; |
54
|
|
|
/** |
55
|
|
|
* @var int the minimum number of bytes required for the uploaded file. |
56
|
|
|
* Defaults to null, meaning no limit. |
57
|
|
|
* @see tooSmall for the customized message for a file that is too small. |
58
|
|
|
*/ |
59
|
|
|
public $minSize; |
60
|
|
|
/** |
61
|
|
|
* @var int the maximum number of bytes required for the uploaded file. |
62
|
|
|
* Defaults to null, meaning no limit. |
63
|
|
|
* Note, the size limit is also affected by `upload_max_filesize` and `post_max_size` INI setting |
64
|
|
|
* and the 'MAX_FILE_SIZE' hidden field value. See [[getSizeLimit()]] for details. |
65
|
|
|
* @see https://secure.php.net/manual/en/ini.core.php#ini.upload-max-filesize |
66
|
|
|
* @see https://secure.php.net/post-max-size |
67
|
|
|
* @see getSizeLimit |
68
|
|
|
* @see tooBig for the customized message for a file that is too big. |
69
|
|
|
*/ |
70
|
|
|
public $maxSize; |
71
|
|
|
/** |
72
|
|
|
* @var int the maximum file count the given attribute can hold. |
73
|
|
|
* Defaults to 1, meaning single file upload. By defining a higher number, |
74
|
|
|
* multiple uploads become possible. Setting it to `0` means there is no limit on |
75
|
|
|
* the number of files that can be uploaded simultaneously. |
76
|
|
|
* |
77
|
|
|
* > Note: The maximum number of files allowed to be uploaded simultaneously is |
78
|
|
|
* also limited with PHP directive `max_file_uploads`, which defaults to 20. |
79
|
|
|
* |
80
|
|
|
* @see https://secure.php.net/manual/en/ini.core.php#ini.max-file-uploads |
81
|
|
|
* @see tooMany for the customized message when too many files are uploaded. |
82
|
|
|
*/ |
83
|
|
|
public $maxFiles = 1; |
84
|
|
|
/** |
85
|
|
|
* @var int the minimum file count the given attribute can hold. |
86
|
|
|
* Defaults to 0. Higher value means at least that number of files should be uploaded. |
87
|
|
|
* |
88
|
|
|
* @see tooFew for the customized message when too few files are uploaded. |
89
|
|
|
* @since 2.0.14 |
90
|
|
|
*/ |
91
|
|
|
public $minFiles = 0; |
92
|
|
|
/** |
93
|
|
|
* @var string the error message used when a file is not uploaded correctly. |
94
|
|
|
*/ |
95
|
|
|
public $message; |
96
|
|
|
/** |
97
|
|
|
* @var string the error message used when no file is uploaded. |
98
|
|
|
* Note that this is the text of the validation error message. To make uploading files required, |
99
|
|
|
* you have to set [[skipOnEmpty]] to `false`. |
100
|
|
|
*/ |
101
|
|
|
public $uploadRequired; |
102
|
|
|
/** |
103
|
|
|
* @var string the error message used when the uploaded file is too large. |
104
|
|
|
* You may use the following tokens in the message: |
105
|
|
|
* |
106
|
|
|
* - {attribute}: the attribute name |
107
|
|
|
* - {file}: the uploaded file name |
108
|
|
|
* - {limit}: the maximum size allowed (see [[getSizeLimit()]]) |
109
|
|
|
* - {formattedLimit}: the maximum size formatted |
110
|
|
|
* with [[\yii\i18n\Formatter::asShortSize()|Formatter::asShortSize()]] |
111
|
|
|
*/ |
112
|
|
|
public $tooBig; |
113
|
|
|
/** |
114
|
|
|
* @var string the error message used when the uploaded file is too small. |
115
|
|
|
* You may use the following tokens in the message: |
116
|
|
|
* |
117
|
|
|
* - {attribute}: the attribute name |
118
|
|
|
* - {file}: the uploaded file name |
119
|
|
|
* - {limit}: the value of [[minSize]] |
120
|
|
|
* - {formattedLimit}: the value of [[minSize]] formatted |
121
|
|
|
* with [[\yii\i18n\Formatter::asShortSize()|Formatter::asShortSize()] |
122
|
|
|
*/ |
123
|
|
|
public $tooSmall; |
124
|
|
|
/** |
125
|
|
|
* @var string the error message used if the count of multiple uploads exceeds limit. |
126
|
|
|
* You may use the following tokens in the message: |
127
|
|
|
* |
128
|
|
|
* - {attribute}: the attribute name |
129
|
|
|
* - {limit}: the value of [[maxFiles]] |
130
|
|
|
*/ |
131
|
|
|
public $tooMany; |
132
|
|
|
/** |
133
|
|
|
* @var string the error message used if the count of multiple uploads less that minFiles. |
134
|
|
|
* You may use the following tokens in the message: |
135
|
|
|
* |
136
|
|
|
* - {attribute}: the attribute name |
137
|
|
|
* - {limit}: the value of [[minFiles]] |
138
|
|
|
* |
139
|
|
|
* @since 2.0.14 |
140
|
|
|
*/ |
141
|
|
|
public $tooFew; |
142
|
|
|
/** |
143
|
|
|
* @var string the error message used when the uploaded file has an extension name |
144
|
|
|
* that is not listed in [[extensions]]. You may use the following tokens in the message: |
145
|
|
|
* |
146
|
|
|
* - {attribute}: the attribute name |
147
|
|
|
* - {file}: the uploaded file name |
148
|
|
|
* - {extensions}: the list of the allowed extensions. |
149
|
|
|
*/ |
150
|
|
|
public $wrongExtension; |
151
|
|
|
/** |
152
|
|
|
* @var string the error message used when the file has an mime type |
153
|
|
|
* that is not allowed by [[mimeTypes]] property. |
154
|
|
|
* You may use the following tokens in the message: |
155
|
|
|
* |
156
|
|
|
* - {attribute}: the attribute name |
157
|
|
|
* - {file}: the uploaded file name |
158
|
|
|
* - {mimeTypes}: the value of [[mimeTypes]] |
159
|
|
|
*/ |
160
|
|
|
public $wrongMimeType; |
161
|
|
|
|
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* {@inheritdoc} |
165
|
|
|
*/ |
166
|
46 |
|
public function init() |
167
|
|
|
{ |
168
|
46 |
|
parent::init(); |
169
|
46 |
|
if ($this->message === null) { |
170
|
46 |
|
$this->message = Yii::t('yii', 'File upload failed.'); |
171
|
|
|
} |
172
|
46 |
|
if ($this->uploadRequired === null) { |
173
|
46 |
|
$this->uploadRequired = Yii::t('yii', 'Please upload a file.'); |
174
|
|
|
} |
175
|
46 |
|
if ($this->tooMany === null) { |
176
|
46 |
|
$this->tooMany = Yii::t('yii', 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.'); |
177
|
|
|
} |
178
|
46 |
|
if ($this->tooFew === null) { |
179
|
46 |
|
$this->tooFew = Yii::t('yii', 'You should upload at least {limit, number} {limit, plural, one{file} other{files}}.'); |
180
|
|
|
} |
181
|
46 |
|
if ($this->wrongExtension === null) { |
182
|
46 |
|
$this->wrongExtension = Yii::t('yii', 'Only files with these extensions are allowed: {extensions}.'); |
183
|
|
|
} |
184
|
46 |
|
if ($this->tooBig === null) { |
185
|
46 |
|
$this->tooBig = Yii::t('yii', 'The file "{file}" is too big. Its size cannot exceed {formattedLimit}.'); |
186
|
|
|
} |
187
|
46 |
|
if ($this->tooSmall === null) { |
188
|
46 |
|
$this->tooSmall = Yii::t('yii', 'The file "{file}" is too small. Its size cannot be smaller than {formattedLimit}.'); |
189
|
|
|
} |
190
|
46 |
|
if (!is_array($this->extensions)) { |
191
|
32 |
|
$this->extensions = preg_split('/[\s,]+/', strtolower($this->extensions), -1, PREG_SPLIT_NO_EMPTY); |
|
|
|
|
192
|
|
|
} else { |
193
|
16 |
|
$this->extensions = array_map('strtolower', $this->extensions); |
194
|
|
|
} |
195
|
46 |
|
if ($this->wrongMimeType === null) { |
196
|
46 |
|
$this->wrongMimeType = Yii::t('yii', 'Only files with these MIME types are allowed: {mimeTypes}.'); |
197
|
|
|
} |
198
|
46 |
|
if (!is_array($this->mimeTypes)) { |
199
|
46 |
|
$this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY); |
|
|
|
|
200
|
|
|
} else { |
201
|
1 |
|
$this->mimeTypes = array_map('strtolower', $this->mimeTypes); |
202
|
|
|
} |
203
|
46 |
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* {@inheritdoc} |
207
|
|
|
*/ |
208
|
11 |
|
public function validateAttribute($model, $attribute) |
209
|
|
|
{ |
210
|
11 |
|
if ($this->maxFiles != 1 || $this->minFiles > 1) { |
211
|
4 |
|
$rawFiles = $model->$attribute; |
212
|
4 |
|
if (!is_array($rawFiles)) { |
213
|
1 |
|
$this->addError($model, $attribute, $this->uploadRequired); |
214
|
|
|
|
215
|
1 |
|
return; |
216
|
|
|
} |
217
|
|
|
|
218
|
4 |
|
$files = $this->filterFiles($rawFiles); |
219
|
4 |
|
$model->$attribute = $files; |
220
|
|
|
|
221
|
4 |
|
if (empty($files)) { |
222
|
1 |
|
$this->addError($model, $attribute, $this->uploadRequired); |
223
|
|
|
|
224
|
1 |
|
return; |
225
|
|
|
} |
226
|
|
|
|
227
|
4 |
|
$filesCount = count($files); |
228
|
4 |
|
if ($this->maxFiles && $filesCount > $this->maxFiles) { |
229
|
1 |
|
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]); |
230
|
|
|
} |
231
|
|
|
|
232
|
4 |
|
if ($this->minFiles && $this->minFiles > $filesCount) { |
233
|
1 |
|
$this->addError($model, $attribute, $this->tooFew, ['limit' => $this->minFiles]); |
234
|
|
|
} |
235
|
|
|
|
236
|
4 |
|
foreach ($files as $file) { |
237
|
4 |
|
$result = $this->validateValue($file); |
238
|
4 |
|
if (!empty($result)) { |
239
|
4 |
|
$this->addError($model, $attribute, $result[0], $result[1]); |
240
|
|
|
} |
241
|
|
|
} |
242
|
|
|
} else { |
243
|
8 |
|
$result = $this->validateValue($model->$attribute); |
244
|
8 |
|
if (!empty($result)) { |
245
|
8 |
|
$this->addError($model, $attribute, $result[0], $result[1]); |
246
|
|
|
} |
247
|
|
|
} |
248
|
11 |
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Files filter. |
252
|
|
|
* @param array $files |
253
|
|
|
* @return UploadedFile[] |
254
|
|
|
*/ |
255
|
4 |
|
private function filterFiles(array $files) |
256
|
|
|
{ |
257
|
4 |
|
$result = []; |
258
|
|
|
|
259
|
4 |
|
foreach ($files as $fileName => $file) { |
260
|
4 |
|
if ($file instanceof UploadedFile && $file->error !== UPLOAD_ERR_NO_FILE) { |
261
|
4 |
|
$result[$fileName] = $file; |
262
|
|
|
} |
263
|
|
|
} |
264
|
|
|
|
265
|
4 |
|
return $result; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* {@inheritdoc} |
270
|
|
|
*/ |
271
|
41 |
|
protected function validateValue($value) |
272
|
|
|
{ |
273
|
41 |
|
if (!$value instanceof UploadedFile || $value->error == UPLOAD_ERR_NO_FILE) { |
274
|
1 |
|
return [$this->uploadRequired, []]; |
275
|
|
|
} |
276
|
|
|
|
277
|
41 |
|
switch ($value->error) { |
278
|
41 |
|
case UPLOAD_ERR_OK: |
279
|
37 |
|
if ($this->maxSize !== null && $value->size > $this->getSizeLimit()) { |
280
|
|
|
return [ |
281
|
1 |
|
$this->tooBig, |
282
|
|
|
[ |
283
|
1 |
|
'file' => $value->name, |
284
|
1 |
|
'limit' => $this->getSizeLimit(), |
285
|
1 |
|
'formattedLimit' => Yii::$app->formatter->asShortSize($this->getSizeLimit()), |
286
|
|
|
], |
287
|
|
|
]; |
288
|
37 |
|
} elseif ($this->minSize !== null && $value->size < $this->minSize) { |
289
|
|
|
return [ |
290
|
1 |
|
$this->tooSmall, |
291
|
|
|
[ |
292
|
1 |
|
'file' => $value->name, |
293
|
1 |
|
'limit' => $this->minSize, |
294
|
1 |
|
'formattedLimit' => Yii::$app->formatter->asShortSize($this->minSize), |
295
|
|
|
], |
296
|
|
|
]; |
297
|
37 |
|
} elseif (!empty($this->extensions) && !$this->validateExtension($value)) { |
298
|
8 |
|
return [$this->wrongExtension, ['file' => $value->name, 'extensions' => implode(', ', $this->extensions)]]; |
299
|
32 |
|
} elseif (!empty($this->mimeTypes) && !$this->validateMimeType($value)) { |
300
|
5 |
|
return [$this->wrongMimeType, ['file' => $value->name, 'mimeTypes' => implode(', ', $this->mimeTypes)]]; |
|
|
|
|
301
|
|
|
} |
302
|
|
|
|
303
|
27 |
|
return null; |
304
|
5 |
|
case UPLOAD_ERR_INI_SIZE: |
305
|
5 |
|
case UPLOAD_ERR_FORM_SIZE: |
306
|
1 |
|
return [$this->tooBig, [ |
307
|
1 |
|
'file' => $value->name, |
308
|
1 |
|
'limit' => $this->getSizeLimit(), |
309
|
1 |
|
'formattedLimit' => Yii::$app->formatter->asShortSize($this->getSizeLimit()), |
310
|
|
|
]]; |
311
|
5 |
|
case UPLOAD_ERR_PARTIAL: |
312
|
2 |
|
Yii::warning('File was only partially uploaded: ' . $value->name, __METHOD__); |
313
|
2 |
|
break; |
314
|
3 |
|
case UPLOAD_ERR_NO_TMP_DIR: |
315
|
1 |
|
Yii::warning('Missing the temporary folder to store the uploaded file: ' . $value->name, __METHOD__); |
316
|
1 |
|
break; |
317
|
2 |
|
case UPLOAD_ERR_CANT_WRITE: |
318
|
1 |
|
Yii::warning('Failed to write the uploaded file to disk: ' . $value->name, __METHOD__); |
319
|
1 |
|
break; |
320
|
1 |
|
case UPLOAD_ERR_EXTENSION: |
321
|
1 |
|
Yii::warning('File upload was stopped by some PHP extension: ' . $value->name, __METHOD__); |
322
|
1 |
|
break; |
323
|
|
|
default: |
324
|
|
|
break; |
325
|
|
|
} |
326
|
|
|
|
327
|
5 |
|
return [$this->message, []]; |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Returns the maximum size allowed for uploaded files. |
332
|
|
|
* |
333
|
|
|
* This is determined based on four factors: |
334
|
|
|
* |
335
|
|
|
* - 'upload_max_filesize' in php.ini |
336
|
|
|
* - 'post_max_size' in php.ini |
337
|
|
|
* - 'MAX_FILE_SIZE' hidden field |
338
|
|
|
* - [[maxSize]] |
339
|
|
|
* |
340
|
|
|
* @return int the size limit for uploaded files. |
341
|
|
|
*/ |
342
|
2 |
|
public function getSizeLimit() |
343
|
|
|
{ |
344
|
|
|
// Get the lowest between post_max_size and upload_max_filesize, log a warning if the first is < than the latter |
345
|
2 |
|
$limit = $this->sizeToBytes(ini_get('upload_max_filesize')); |
346
|
2 |
|
$postLimit = $this->sizeToBytes(ini_get('post_max_size')); |
347
|
2 |
|
if ($postLimit > 0 && $postLimit < $limit) { |
348
|
|
|
Yii::warning('PHP.ini\'s \'post_max_size\' is less than \'upload_max_filesize\'.', __METHOD__); |
349
|
|
|
$limit = $postLimit; |
350
|
|
|
} |
351
|
2 |
|
if ($this->maxSize !== null && $limit > 0 && $this->maxSize < $limit) { |
352
|
2 |
|
$limit = $this->maxSize; |
353
|
|
|
} |
354
|
2 |
|
if (isset($_POST['MAX_FILE_SIZE']) && $_POST['MAX_FILE_SIZE'] > 0 && $_POST['MAX_FILE_SIZE'] < $limit) { |
355
|
1 |
|
$limit = (int) $_POST['MAX_FILE_SIZE']; |
356
|
|
|
} |
357
|
|
|
|
358
|
2 |
|
return $limit; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* {@inheritdoc} |
363
|
|
|
* @param bool $trim |
364
|
|
|
*/ |
365
|
1 |
|
public function isEmpty($value, $trim = false) |
|
|
|
|
366
|
|
|
{ |
367
|
1 |
|
$value = is_array($value) ? reset($value) : $value; |
368
|
1 |
|
return !($value instanceof UploadedFile) || $value->error == UPLOAD_ERR_NO_FILE; |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* Converts php.ini style size to bytes. |
373
|
|
|
* |
374
|
|
|
* @param string $sizeStr $sizeStr |
375
|
|
|
* @return int |
376
|
|
|
*/ |
377
|
2 |
|
private function sizeToBytes($sizeStr) |
378
|
|
|
{ |
379
|
2 |
|
switch (substr($sizeStr, -1)) { |
380
|
2 |
|
case 'M': |
381
|
|
|
case 'm': |
382
|
2 |
|
return (int) $sizeStr * 1048576; |
383
|
|
|
case 'K': |
384
|
|
|
case 'k': |
385
|
|
|
return (int) $sizeStr * 1024; |
386
|
|
|
case 'G': |
387
|
|
|
case 'g': |
388
|
|
|
return (int) $sizeStr * 1073741824; |
389
|
|
|
default: |
390
|
|
|
return (int) $sizeStr; |
391
|
|
|
} |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
/** |
395
|
|
|
* Checks if given uploaded file have correct type (extension) according current validator settings. |
396
|
|
|
* @param UploadedFile $file |
397
|
|
|
* @return bool |
398
|
|
|
*/ |
399
|
16 |
|
protected function validateExtension($file) |
400
|
|
|
{ |
401
|
16 |
|
$extension = mb_strtolower($file->extension, 'UTF-8'); |
402
|
|
|
|
403
|
16 |
|
if ($this->checkExtensionByMimeType) { |
404
|
13 |
|
$mimeType = FileHelper::getMimeType($file->tempName, null, false); |
405
|
13 |
|
if ($mimeType === null) { |
|
|
|
|
406
|
|
|
return false; |
407
|
|
|
} |
408
|
|
|
|
409
|
13 |
|
$extensionsByMimeType = FileHelper::getExtensionsByMimeType($mimeType); |
410
|
|
|
|
411
|
13 |
|
if (!in_array($extension, $extensionsByMimeType, true)) { |
412
|
|
|
return false; |
413
|
|
|
} |
414
|
|
|
} |
415
|
|
|
|
416
|
16 |
|
if (!empty($this->extensions)) { |
417
|
16 |
|
foreach ((array) $this->extensions as $ext) { |
418
|
16 |
|
if (StringHelper::endsWith($file->name, ".$ext", false)) { |
419
|
16 |
|
return true; |
420
|
|
|
} |
421
|
|
|
} |
422
|
8 |
|
return false; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
return true; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* {@inheritdoc} |
430
|
|
|
*/ |
431
|
|
|
public function clientValidateAttribute($model, $attribute, $view) |
432
|
|
|
{ |
433
|
|
|
ValidationAsset::register($view); |
434
|
|
|
$options = $this->getClientOptions($model, $attribute); |
435
|
|
|
return 'yii.validation.file(attribute, messages, ' . Json::encode($options) . ');'; |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
/** |
439
|
|
|
* {@inheritdoc} |
440
|
|
|
*/ |
441
|
|
|
public function getClientOptions($model, $attribute) |
442
|
|
|
{ |
443
|
|
|
$label = $model->getAttributeLabel($attribute); |
444
|
|
|
|
445
|
|
|
$options = []; |
446
|
|
|
if ($this->message !== null) { |
447
|
|
|
$options['message'] = $this->formatMessage($this->message, [ |
448
|
|
|
'attribute' => $label, |
449
|
|
|
]); |
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
$options['skipOnEmpty'] = $this->skipOnEmpty; |
453
|
|
|
|
454
|
|
|
if (!$this->skipOnEmpty) { |
455
|
|
|
$options['uploadRequired'] = $this->formatMessage($this->uploadRequired, [ |
456
|
|
|
'attribute' => $label, |
457
|
|
|
]); |
458
|
|
|
} |
459
|
|
|
|
460
|
|
|
if ($this->mimeTypes !== null) { |
461
|
|
|
$mimeTypes = []; |
462
|
|
|
foreach ($this->mimeTypes as $mimeType) { |
463
|
|
|
$mimeTypes[] = new JsExpression(Html::escapeJsRegularExpression($this->buildMimeTypeRegexp($mimeType))); |
464
|
|
|
} |
465
|
|
|
$options['mimeTypes'] = $mimeTypes; |
466
|
|
|
$options['wrongMimeType'] = $this->formatMessage($this->wrongMimeType, [ |
467
|
|
|
'attribute' => $label, |
468
|
|
|
'mimeTypes' => implode(', ', $this->mimeTypes), |
|
|
|
|
469
|
|
|
]); |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
if ($this->extensions !== null) { |
473
|
|
|
$options['extensions'] = $this->extensions; |
474
|
|
|
$options['wrongExtension'] = $this->formatMessage($this->wrongExtension, [ |
475
|
|
|
'attribute' => $label, |
476
|
|
|
'extensions' => implode(', ', $this->extensions), |
477
|
|
|
]); |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
if ($this->minSize !== null) { |
481
|
|
|
$options['minSize'] = $this->minSize; |
482
|
|
|
$options['tooSmall'] = $this->formatMessage($this->tooSmall, [ |
483
|
|
|
'attribute' => $label, |
484
|
|
|
'limit' => $this->minSize, |
485
|
|
|
'formattedLimit' => Yii::$app->formatter->asShortSize($this->minSize), |
486
|
|
|
]); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
if ($this->maxSize !== null) { |
490
|
|
|
$options['maxSize'] = $this->maxSize; |
491
|
|
|
$options['tooBig'] = $this->formatMessage($this->tooBig, [ |
492
|
|
|
'attribute' => $label, |
493
|
|
|
'limit' => $this->getSizeLimit(), |
494
|
|
|
'formattedLimit' => Yii::$app->formatter->asShortSize($this->getSizeLimit()), |
495
|
|
|
]); |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
if ($this->maxFiles !== null) { |
499
|
|
|
$options['maxFiles'] = $this->maxFiles; |
500
|
|
|
$options['tooMany'] = $this->formatMessage($this->tooMany, [ |
501
|
|
|
'attribute' => $label, |
502
|
|
|
'limit' => $this->maxFiles, |
503
|
|
|
]); |
504
|
|
|
} |
505
|
|
|
|
506
|
|
|
return $options; |
507
|
|
|
} |
508
|
|
|
|
509
|
|
|
/** |
510
|
|
|
* Builds the RegExp from the $mask. |
511
|
|
|
* |
512
|
|
|
* @param string $mask |
513
|
|
|
* @return string the regular expression |
514
|
|
|
* @see mimeTypes |
515
|
|
|
*/ |
516
|
13 |
|
private function buildMimeTypeRegexp($mask) |
517
|
|
|
{ |
518
|
13 |
|
return '/^' . str_replace('\*', '.*', preg_quote($mask, '/')) . '$/i'; |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
/** |
522
|
|
|
* Checks the mimeType of the $file against the list in the [[mimeTypes]] property. |
523
|
|
|
* |
524
|
|
|
* @param UploadedFile $file |
525
|
|
|
* @return bool whether the $file mimeType is allowed |
526
|
|
|
* @throws \yii\base\InvalidConfigException |
527
|
|
|
* @see mimeTypes |
528
|
|
|
* @since 2.0.8 |
529
|
|
|
*/ |
530
|
17 |
|
protected function validateMimeType($file) |
531
|
|
|
{ |
532
|
17 |
|
$fileMimeType = $this->getMimeTypeByFile($file->tempName); |
533
|
|
|
|
534
|
17 |
|
foreach ($this->mimeTypes as $mimeType) { |
535
|
17 |
|
if (strcasecmp($mimeType, $fileMimeType) === 0) { |
536
|
3 |
|
return true; |
537
|
|
|
} |
538
|
|
|
|
539
|
14 |
|
if (strpos($mimeType, '*') !== false && preg_match($this->buildMimeTypeRegexp($mimeType), $fileMimeType)) { |
540
|
14 |
|
return true; |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
544
|
5 |
|
return false; |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Get MIME type by file path |
549
|
|
|
* |
550
|
|
|
* @param string $filePath |
551
|
|
|
* @return string |
552
|
|
|
* @throws \yii\base\InvalidConfigException |
553
|
|
|
* @since 2.0.26 |
554
|
|
|
*/ |
555
|
13 |
|
protected function getMimeTypeByFile($filePath) { |
556
|
13 |
|
return FileHelper::getMimeType($filePath); |
557
|
|
|
} |
558
|
|
|
} |
559
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.