mirror of
https://github.com/yiisoft/yii2.git
synced 2025-10-30 01:56:35 +08:00
Fix #19855: Fixed yii\validators\FileValidator to not limit some of its rules only to array attribute
This commit is contained in:
@ -29,6 +29,7 @@ Yii Framework 2 Change Log
|
|||||||
- Bug #20141: Update `ezyang/htmlpurifier` dependency to version `4.17` (@terabytesoftw)
|
- Bug #20141: Update `ezyang/htmlpurifier` dependency to version `4.17` (@terabytesoftw)
|
||||||
- Bug #19817: Add MySQL Query `addCheck()` and `dropCheck()` (@bobonov)
|
- Bug #19817: Add MySQL Query `addCheck()` and `dropCheck()` (@bobonov)
|
||||||
- Bug #20165: Adjust pretty name of closures for PHP 8.4 compatibility (@staabm)
|
- Bug #20165: Adjust pretty name of closures for PHP 8.4 compatibility (@staabm)
|
||||||
|
- Bug #19855: Fixed `yii\validators\FileValidator` to not limit some of its rules only to array attribute (bizley)
|
||||||
- Enh: #20171: Support JSON columns for MariaDB 10.4 or higher (@terabytesoftw)
|
- Enh: #20171: Support JSON columns for MariaDB 10.4 or higher (@terabytesoftw)
|
||||||
|
|
||||||
2.0.49.2 October 12, 2023
|
2.0.49.2 October 12, 2023
|
||||||
|
|||||||
@ -208,40 +208,23 @@ class FileValidator extends Validator
|
|||||||
*/
|
*/
|
||||||
public function validateAttribute($model, $attribute)
|
public function validateAttribute($model, $attribute)
|
||||||
{
|
{
|
||||||
if ($this->maxFiles != 1 || $this->minFiles > 1) {
|
$files = $this->filterFiles(is_array($model->$attribute) ? $model->$attribute : [$model->$attribute]);
|
||||||
$rawFiles = $model->$attribute;
|
$filesCount = count($files);
|
||||||
if (!is_array($rawFiles)) {
|
if ($filesCount === 0 && $this->minFiles > 0) {
|
||||||
$this->addError($model, $attribute, $this->uploadRequired);
|
$this->addError($model, $attribute, $this->uploadRequired);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$files = $this->filterFiles($rawFiles);
|
if ($this->maxFiles > 0 && $filesCount > $this->maxFiles) {
|
||||||
$model->$attribute = $files;
|
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]);
|
||||||
|
}
|
||||||
|
if ($this->minFiles > 0 && $this->minFiles > $filesCount) {
|
||||||
|
$this->addError($model, $attribute, $this->tooFew, ['limit' => $this->minFiles]);
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($files)) {
|
foreach ($files as $file) {
|
||||||
$this->addError($model, $attribute, $this->uploadRequired);
|
$result = $this->validateValue($file);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$filesCount = count($files);
|
|
||||||
if ($this->maxFiles && $filesCount > $this->maxFiles) {
|
|
||||||
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->minFiles && $this->minFiles > $filesCount) {
|
|
||||||
$this->addError($model, $attribute, $this->tooFew, ['limit' => $this->minFiles]);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($files as $file) {
|
|
||||||
$result = $this->validateValue($file);
|
|
||||||
if (!empty($result)) {
|
|
||||||
$this->addError($model, $attribute, $result[0], $result[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$result = $this->validateValue($model->$attribute);
|
|
||||||
if (!empty($result)) {
|
if (!empty($result)) {
|
||||||
$this->addError($model, $attribute, $result[0], $result[1]);
|
$this->addError($model, $attribute, $result[0], $result[1]);
|
||||||
}
|
}
|
||||||
|
|||||||
18
tests/data/validators/models/FakedValidationTypedModel.php
Normal file
18
tests/data/validators/models/FakedValidationTypedModel.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @link https://www.yiiframework.com/
|
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||||
|
* @license https://www.yiiframework.com/license/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace yiiunit\data\validators\models;
|
||||||
|
|
||||||
|
use yii\base\Model;
|
||||||
|
use yii\web\UploadedFile;
|
||||||
|
|
||||||
|
class FakedValidationTypedModel extends Model
|
||||||
|
{
|
||||||
|
public ?UploadedFile $single = null;
|
||||||
|
|
||||||
|
public array $multiple = [];
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ use yii\helpers\FileHelper;
|
|||||||
use yii\validators\FileValidator;
|
use yii\validators\FileValidator;
|
||||||
use yii\web\UploadedFile;
|
use yii\web\UploadedFile;
|
||||||
use yiiunit\data\validators\models\FakedValidationModel;
|
use yiiunit\data\validators\models\FakedValidationModel;
|
||||||
|
use yiiunit\data\validators\models\FakedValidationTypedModel;
|
||||||
use yiiunit\TestCase;
|
use yiiunit\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,11 +115,11 @@ class FileValidatorTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
$m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']);
|
$m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']);
|
||||||
$val->validateAttribute($m, 'attr_files');
|
$val->validateAttribute($m, 'attr_files');
|
||||||
$this->assertTrue($m->hasErrors('attr_files'));
|
$this->assertFalse($m->hasErrors('attr_files'));
|
||||||
$m = FakedValidationModel::createWithAttributes(['attr_files' => []]);
|
$m = FakedValidationModel::createWithAttributes(['attr_files' => []]);
|
||||||
$val->validateAttribute($m, 'attr_files');
|
$val->validateAttribute($m, 'attr_files');
|
||||||
$this->assertTrue($m->hasErrors('attr_files'));
|
$this->assertFalse($m->hasErrors('attr_files'));
|
||||||
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files')));
|
|
||||||
$m = FakedValidationModel::createWithAttributes(
|
$m = FakedValidationModel::createWithAttributes(
|
||||||
[
|
[
|
||||||
'attr_files' => $this->createTestFiles(
|
'attr_files' => $this->createTestFiles(
|
||||||
@ -314,6 +315,32 @@ class FileValidatorTest extends TestCase
|
|||||||
$this->assertTrue($model->hasErrors('attr_images'));
|
$this->assertTrue($model->hasErrors('attr_images'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/yiisoft/yii2/issues/19855
|
||||||
|
*/
|
||||||
|
public function testValidateArrayAttributeWithMinMaxOneAndOneFile()
|
||||||
|
{
|
||||||
|
$validator = new FileValidator(['maxFiles' => 1, 'minFiles' => 0]);
|
||||||
|
$files = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
)[0];
|
||||||
|
$model = FakedValidationModel::createWithAttributes(['attr_images' => [$files]]);
|
||||||
|
|
||||||
|
$validator->validateAttribute($model, 'attr_images');
|
||||||
|
$this->assertFalse($model->hasErrors('attr_images'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $params
|
* @param array $params
|
||||||
* @return UploadedFile[]
|
* @return UploadedFile[]
|
||||||
@ -395,8 +422,7 @@ class FileValidatorTest extends TestCase
|
|||||||
$val->validateAttribute($m, 'attr_files');
|
$val->validateAttribute($m, 'attr_files');
|
||||||
$this->assertFalse($m->hasErrors());
|
$this->assertFalse($m->hasErrors());
|
||||||
$val->validateAttribute($m, 'attr_files_empty');
|
$val->validateAttribute($m, 'attr_files_empty');
|
||||||
$this->assertTrue($m->hasErrors('attr_files_empty'));
|
$this->assertFalse($m->hasErrors('attr_files_empty'));
|
||||||
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty')));
|
|
||||||
|
|
||||||
// single File with skipOnEmpty = false
|
// single File with skipOnEmpty = false
|
||||||
$val = new FileValidator(['skipOnEmpty' => false]);
|
$val = new FileValidator(['skipOnEmpty' => false]);
|
||||||
@ -404,8 +430,7 @@ class FileValidatorTest extends TestCase
|
|||||||
$val->validateAttribute($m, 'attr_files');
|
$val->validateAttribute($m, 'attr_files');
|
||||||
$this->assertFalse($m->hasErrors());
|
$this->assertFalse($m->hasErrors());
|
||||||
$val->validateAttribute($m, 'attr_files_empty');
|
$val->validateAttribute($m, 'attr_files_empty');
|
||||||
$this->assertTrue($m->hasErrors('attr_files_empty'));
|
$this->assertFalse($m->hasErrors('attr_files_empty'));
|
||||||
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty')));
|
|
||||||
$m = $this->createModelForAttributeTest();
|
$m = $this->createModelForAttributeTest();
|
||||||
|
|
||||||
// too big
|
// too big
|
||||||
@ -672,4 +697,132 @@ class FileValidatorTest extends TestCase
|
|||||||
['image/jxra', 'image/jxrA', true],
|
['image/jxra', 'image/jxrA', true],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValidateTypedAttributeNoErrors()
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '<')) {
|
||||||
|
$this->markTestSkipped('Requires typed properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = new FileValidator(['minFiles' => 0, 'maxFiles' => 2]);
|
||||||
|
$file = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$model = new FakedValidationTypedModel();
|
||||||
|
$model->single = $file;
|
||||||
|
$model->multiple = [$file];
|
||||||
|
$validator->validateAttribute($model, 'single');
|
||||||
|
$this->assertFalse($model->hasErrors('single'));
|
||||||
|
$validator->validateAttribute($model, 'multiple');
|
||||||
|
$this->assertFalse($model->hasErrors('multiple'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateTypedAttributeExactMinNoErrors()
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '<')) {
|
||||||
|
$this->markTestSkipped('Requires typed properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = new FileValidator(['minFiles' => 1]);
|
||||||
|
$file = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$model = new FakedValidationTypedModel();
|
||||||
|
$model->single = $file;
|
||||||
|
$model->multiple = [$file];
|
||||||
|
$validator->validateAttribute($model, 'single');
|
||||||
|
$this->assertFalse($model->hasErrors('single'));
|
||||||
|
$validator->validateAttribute($model, 'multiple');
|
||||||
|
$this->assertFalse($model->hasErrors('multiple'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateTypedAttributeExactMaxNoErrors()
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '<')) {
|
||||||
|
$this->markTestSkipped('Requires typed properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = new FileValidator(['maxFiles' => 1]);
|
||||||
|
$file = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$model = new FakedValidationTypedModel();
|
||||||
|
$model->single = $file;
|
||||||
|
$model->multiple = [$file];
|
||||||
|
$validator->validateAttribute($model, 'single');
|
||||||
|
$this->assertFalse($model->hasErrors('single'));
|
||||||
|
$validator->validateAttribute($model, 'multiple');
|
||||||
|
$this->assertFalse($model->hasErrors('multiple'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateTypedAttributeMinError()
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '<')) {
|
||||||
|
$this->markTestSkipped('Requires typed properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = new FileValidator(['minFiles' => 2]);
|
||||||
|
$file = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$model = new FakedValidationTypedModel();
|
||||||
|
$model->single = $file;
|
||||||
|
$model->multiple = [$file];
|
||||||
|
$validator->validateAttribute($model, 'single');
|
||||||
|
$this->assertTrue($model->hasErrors('single'));
|
||||||
|
$validator->validateAttribute($model, 'multiple');
|
||||||
|
$this->assertTrue($model->hasErrors('multiple'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateTypedAttributeMaxError()
|
||||||
|
{
|
||||||
|
if (version_compare(PHP_VERSION, '7.4', '<')) {
|
||||||
|
$this->markTestSkipped('Requires typed properties');
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = new FileValidator(['maxFiles' => 1]);
|
||||||
|
$files = $this->createTestFiles(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'image.png',
|
||||||
|
'size' => 1024,
|
||||||
|
'type' => 'image/png',
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$model = new FakedValidationTypedModel();
|
||||||
|
// single attribute cannot be checked because maxFiles = 0 === no limits
|
||||||
|
$model->multiple = $files;
|
||||||
|
$validator->validateAttribute($model, 'multiple');
|
||||||
|
$this->assertTrue($model->hasErrors('multiple'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user