mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Merge pull request #3866 from Ragazzo/file_validator_type_check_against_mime_type
type validation adjusted
This commit is contained in:
@ -85,6 +85,7 @@ Yii Framework 2 Change Log
|
||||
- Enh #3636: Hide menu container tag with empty items in `yii\widgets\Menu` (arturf)
|
||||
- Enh #3643: Improved Mime-Type detection by using the `mime.types` file from apache http project to dected mime types by file extension (cebe, pavel-voronin, trejder)
|
||||
- Enh #3773: Added `FileValidator::mimeTypes` to support validating MIME types of files (Ragazzo)
|
||||
- Enh #3774: Added `FileValidator::checkExtensionByMimeType` to support validating file types against file mime-types (Ragazzo)
|
||||
- Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue)
|
||||
- Enh: Supported adding a new response formatter without the need to reconfigure existing formatters (qiangxue)
|
||||
- Enh: Added `yii\web\UrlManager::addRules()` to simplify adding new URL rules (qiangxue)
|
||||
@ -109,6 +110,7 @@ Yii Framework 2 Change Log
|
||||
- Chg #3640: All cookies are now httpOnly by default in order to increase overall security (samdark)
|
||||
- Chg #3687: Default `sourceLanguage` and `language` are now `en-US` in order for i18n formatter to work correctly (samdark)
|
||||
- Chg #3804: Added `fileinfo` PHP extension to the basic requirement of Yii (Ragazzo)
|
||||
- Chg #3866: `FileValidator::types` attribute changed to `FileValidator::extensions` (Ragazzo)
|
||||
- Chg: Replaced `clearAll()` and `clearAllAssignments()` in `yii\rbac\ManagerInterface` with `removeAll()`, `removeAllRoles()`, `removeAllPermissions()`, `removeAllRules()` and `removeAllAssignments()` (qiangxue)
|
||||
- Chg: Added `$user` as the first parameter of `yii\rbac\Rule::execute()` (qiangxue)
|
||||
- Chg: `yii\grid\DataColumn::getDataCellValue()` visibility is now `public` to allow accessing the value from a GridView directly (cebe)
|
||||
|
@ -53,3 +53,6 @@ Upgrade from Yii 2.0 Beta
|
||||
|
||||
* Please update your main layout file by adding this line in the `<head>` section: `<?= Html::csrfMetaTags() ?>`.
|
||||
This change is needed because `yii\web\View` no longer automatically generates CSRF meta tags due to issue #3358.
|
||||
|
||||
* `FileValidator::types` attribute was changed to `FileValidator::extensions` for consistency. If you use this attribute in your code you
|
||||
should consider this replacement.
|
||||
|
@ -161,6 +161,26 @@ class BaseFileHelper
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the extensions by given mime-type.
|
||||
* This method will use a local map between extension names and MIME types.
|
||||
* @param string $mimeType file mime-type.
|
||||
* @param string $magicFile the path of the file that contains all available MIME type information.
|
||||
* If this is not set, the default file aliased by `@yii/util/mimeTypes.php` will be used.
|
||||
* @return array.
|
||||
*/
|
||||
public static function getExtensionsByMimeType($mimeType, $magicFile = null)
|
||||
{
|
||||
static $mimeTypes = [];
|
||||
|
||||
if (!count($mimeTypes)) {
|
||||
$magicFile = __DIR__ . '/mimeTypes.php';
|
||||
$mimeTypes = require($magicFile);
|
||||
}
|
||||
|
||||
return array_keys($mimeTypes, mb_strtolower($mimeType, 'utf-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a whole directory as another one.
|
||||
* The files and sub-directories will also be copied over.
|
||||
|
@ -29,7 +29,13 @@ class FileValidator extends Validator
|
||||
* extensions are allowed.
|
||||
* @see wrongType
|
||||
*/
|
||||
public $types;
|
||||
public $extensions;
|
||||
/**
|
||||
*
|
||||
* @var boolean whether to check file type (extension) with mime-type. If extension produced by
|
||||
* file mime-type check differs from uploaded file extension, file will be counted as not valid.
|
||||
*/
|
||||
public $checkExtensionByMimeType = true;
|
||||
/**
|
||||
* @var array|string a list of file MIME types that are allowed to be uploaded.
|
||||
* This can be either an array or a string consisting of file MIME types
|
||||
@ -88,13 +94,13 @@ class FileValidator extends Validator
|
||||
public $tooSmall;
|
||||
/**
|
||||
* @var string the error message used when the uploaded file has an extension name
|
||||
* that is not listed in [[types]]. You may use the following tokens in the message:
|
||||
* that is not listed in [[extensions]]. You may use the following tokens in the message:
|
||||
*
|
||||
* - {attribute}: the attribute name
|
||||
* - {file}: the uploaded file name
|
||||
* - {extensions}: the list of the allowed extensions.
|
||||
*/
|
||||
public $wrongType;
|
||||
public $wrongExtension;
|
||||
/**
|
||||
* @var string the error message used if the count of multiple uploads exceeds limit.
|
||||
* You may use the following tokens in the message:
|
||||
@ -130,8 +136,8 @@ class FileValidator extends Validator
|
||||
if ($this->tooMany === null) {
|
||||
$this->tooMany = Yii::t('yii', 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.');
|
||||
}
|
||||
if ($this->wrongType === null) {
|
||||
$this->wrongType = Yii::t('yii', 'Only files with these extensions are allowed: {extensions}.');
|
||||
if ($this->wrongExtension === null) {
|
||||
$this->wrongExtension = Yii::t('yii', 'Only files with these extensions are allowed: {extensions}.');
|
||||
}
|
||||
if ($this->tooBig === null) {
|
||||
$this->tooBig = Yii::t('yii', 'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.');
|
||||
@ -139,8 +145,8 @@ class FileValidator extends Validator
|
||||
if ($this->tooSmall === null) {
|
||||
$this->tooSmall = Yii::t('yii', 'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.');
|
||||
}
|
||||
if (!is_array($this->types)) {
|
||||
$this->types = preg_split('/[\s,]+/', strtolower($this->types), -1, PREG_SPLIT_NO_EMPTY);
|
||||
if (!is_array($this->extensions)) {
|
||||
$this->extensions = preg_split('/[\s,]+/', strtolower($this->extensions), -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
if ($this->wrongMimeType === null) {
|
||||
$this->wrongMimeType = Yii::t('yii', 'Only files with these MIME types are allowed: {mimeTypes}.');
|
||||
@ -197,15 +203,16 @@ class FileValidator extends Validator
|
||||
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
|
||||
return [$this->uploadRequired, []];
|
||||
}
|
||||
|
||||
switch ($file->error) {
|
||||
case UPLOAD_ERR_OK:
|
||||
if ($this->maxSize !== null && $file->size > $this->maxSize) {
|
||||
return [$this->tooBig, ['file' => $file->name, 'limit' => $this->getSizeLimit()]];
|
||||
} elseif ($this->minSize !== null && $file->size < $this->minSize) {
|
||||
return [$this->tooSmall, ['file' => $file->name, 'limit' => $this->minSize]];
|
||||
} elseif (!empty($this->types) && !in_array(strtolower(pathinfo($file->name, PATHINFO_EXTENSION)), $this->types, true)) {
|
||||
return [$this->wrongType, ['file' => $file->name, 'extensions' => implode(', ', $this->types)]];
|
||||
} elseif (!empty($this->mimeTypes) && !in_array(FileHelper::getMimeType($file->tempName), $this->mimeTypes, true)) {
|
||||
} elseif (!empty($this->extensions) && !$this->validateExtension($file)) {
|
||||
return [$this->wrongExtension, ['file' => $file->name, 'extensions' => implode(', ', $this->extensions)]];
|
||||
} elseif (!empty($this->mimeTypes) && !in_array(FileHelper::getMimeType($file->tempName), $this->mimeTypes, true)) {
|
||||
return [$this->wrongMimeType, ['file' => $file->name, 'mimeTypes' => implode(', ', $this->mimeTypes)]];
|
||||
} else {
|
||||
return null;
|
||||
@ -244,8 +251,7 @@ class FileValidator extends Validator
|
||||
*/
|
||||
public function getSizeLimit()
|
||||
{
|
||||
$limit = ini_get('upload_max_filesize');
|
||||
$limit = $this->sizeToBytes($limit);
|
||||
$limit = $this->sizeToBytes(ini_get('upload_max_filesize'));
|
||||
if ($this->maxSize !== null && $limit > 0 && $this->maxSize < $limit) {
|
||||
$limit = $this->maxSize;
|
||||
}
|
||||
@ -287,4 +293,30 @@ class FileValidator extends Validator
|
||||
return (int) $sizeStr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given uploaded file have correct type (extension) according current validator settings.
|
||||
* @param \yii\web\UploadedFile $file
|
||||
* @return boolean
|
||||
*/
|
||||
public function validateExtension($file)
|
||||
{
|
||||
$fileExtension = mb_strtolower($file->extension, 'utf-8');
|
||||
|
||||
if ($this->checkExtensionByMimeType) {
|
||||
|
||||
$extensionsByMimeType = FileHelper::getExtensionsByMimeType(FileHelper::getMimeType($file->tempName));
|
||||
|
||||
if (!in_array($fileExtension, $extensionsByMimeType, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array($fileExtension, $this->extensions, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ class FakedValidationModel extends Model
|
||||
return [
|
||||
[['val_attr_a', 'val_attr_b'], 'required', 'on' => 'reqTest'],
|
||||
['val_attr_c', 'integer'],
|
||||
['attr_images', 'file', 'maxFiles' => 3, 'types' => ['png'], 'on' => 'validateMultipleFiles'],
|
||||
['attr_image', 'file', 'types' => ['png'], 'on' => 'validateFile']
|
||||
['attr_images', 'file', 'maxFiles' => 3, 'extensions' => ['png'], 'on' => 'validateMultipleFiles', 'checkExtensionByMimeType' => false],
|
||||
['attr_image', 'file', 'extensions' => ['png'], 'on' => 'validateFile', 'checkExtensionByMimeType' => false]
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -21,30 +21,30 @@ class FileValidatorTest extends TestCase
|
||||
public function testAssureMessagesSetOnInit()
|
||||
{
|
||||
$val = new FileValidator();
|
||||
foreach (['message', 'uploadRequired', 'tooMany', 'wrongType', 'tooBig', 'tooSmall', 'wrongMimeType'] as $attr) {
|
||||
foreach (['message', 'uploadRequired', 'tooMany', 'wrongExtension', 'tooBig', 'tooSmall', 'wrongMimeType'] as $attr) {
|
||||
$this->assertTrue(is_string($val->$attr));
|
||||
}
|
||||
}
|
||||
|
||||
public function testTypeSplitOnInit()
|
||||
{
|
||||
$val = new FileValidator(['types' => 'jpeg, jpg, gif']);
|
||||
$this->assertEquals(['jpeg', 'jpg', 'gif'], $val->types);
|
||||
$val = new FileValidator(['extensions' => 'jpeg, jpg, gif']);
|
||||
$this->assertEquals(['jpeg', 'jpg', 'gif'], $val->extensions);
|
||||
|
||||
$val = new FileValidator(['types' => 'jpeg']);
|
||||
$this->assertEquals(['jpeg'], $val->types);
|
||||
$val = new FileValidator(['extensions' => 'jpeg']);
|
||||
$this->assertEquals(['jpeg'], $val->extensions);
|
||||
|
||||
$val = new FileValidator(['types' => '']);
|
||||
$this->assertEquals([], $val->types);
|
||||
$val = new FileValidator(['extensions' => '']);
|
||||
$this->assertEquals([], $val->extensions);
|
||||
|
||||
$val = new FileValidator(['types' => []]);
|
||||
$this->assertEquals([], $val->types);
|
||||
$val = new FileValidator(['extensions' => []]);
|
||||
$this->assertEquals([], $val->extensions);
|
||||
|
||||
$val = new FileValidator();
|
||||
$this->assertEquals([], $val->types);
|
||||
$this->assertEquals([], $val->extensions);
|
||||
|
||||
$val = new FileValidator(['types' => ['jpeg', 'exe']]);
|
||||
$this->assertEquals(['jpeg', 'exe'], $val->types);
|
||||
$val = new FileValidator(['extensions' => ['jpeg', 'exe']]);
|
||||
$this->assertEquals(['jpeg', 'exe'], $val->extensions);
|
||||
}
|
||||
|
||||
public function testMimeTypeSplitOnInit()
|
||||
@ -102,7 +102,9 @@ class FileValidatorTest extends TestCase
|
||||
|
||||
public function testValidateAttributeMultiple()
|
||||
{
|
||||
$val = new FileValidator(['maxFiles' => 2]);
|
||||
$val = new FileValidator([
|
||||
'maxFiles' => 2,
|
||||
]);
|
||||
$m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']);
|
||||
$val->validateAttribute($m, 'attr_files');
|
||||
$this->assertTrue($m->hasErrors('attr_files'));
|
||||
@ -221,7 +223,7 @@ class FileValidatorTest extends TestCase
|
||||
continue;
|
||||
}
|
||||
$name = isset($param['name']) ? $param['name'] : $rndString();
|
||||
$tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp') . $name;
|
||||
$tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp/') . $name;
|
||||
if (is_readable($tempName)) {
|
||||
$size = filesize($tempName);
|
||||
} else {
|
||||
@ -303,7 +305,10 @@ class FileValidatorTest extends TestCase
|
||||
|
||||
public function testValidateAttributeType()
|
||||
{
|
||||
$val = new FileValidator(['types' => 'jpeg, jpg']);
|
||||
$val = new FileValidator([
|
||||
'extensions' => 'jpeg, jpg',
|
||||
'checkExtensionByMimeType' => false,
|
||||
]);
|
||||
$m = FakedValidationModel::createWithAttributes(
|
||||
[
|
||||
'attr_jpg' => $this->createTestFiles([['name' => 'one.jpeg']]),
|
||||
|
Reference in New Issue
Block a user