Yii2 framework backup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

664 lines
24 KiB

<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\validators;
use Yii;
use yii\helpers\FileHelper;
use yii\validators\FileValidator;
use yii\web\UploadedFile;
use yiiunit\data\validators\models\FakedValidationModel;
use yiiunit\TestCase;
/**
* @group validators
*/
class FileValidatorTest extends TestCase
{
protected function setUp()
{
parent::setUp();
$this->mockApplication();
}
public function testAssureMessagesSetOnInit()
{
$val = new FileValidator();
foreach (['message', 'uploadRequired', 'tooMany', 'wrongExtension', 'tooBig', 'tooSmall', 'wrongMimeType'] as $attr) {
$this->assertInternalType('string', $val->$attr);
}
}
public function testTypeSplitOnInit()
{
$val = new FileValidator(['extensions' => 'jpeg, jpg, gif']);
$this->assertEquals(['jpeg', 'jpg', 'gif'], $val->extensions);
$val = new FileValidator(['extensions' => 'jpeg']);
$this->assertEquals(['jpeg'], $val->extensions);
$val = new FileValidator(['extensions' => '']);
$this->assertEquals([], $val->extensions);
$val = new FileValidator(['extensions' => []]);
$this->assertEquals([], $val->extensions);
$val = new FileValidator();
$this->assertEquals([], $val->extensions);
$val = new FileValidator(['extensions' => ['jpeg', 'exe']]);
$this->assertEquals(['jpeg', 'exe'], $val->extensions);
}
public function testMimeTypeSplitOnInit()
{
$val = new FileValidator(['mimeTypes' => 'text/plain, image/png']);
$this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes);
$val = new FileValidator(['mimeTypes' => 'text/plain']);
$this->assertEquals(['text/plain'], $val->mimeTypes);
$val = new FileValidator(['mimeTypes' => '']);
$this->assertEquals([], $val->mimeTypes);
$val = new FileValidator(['mimeTypes' => []]);
$this->assertEquals([], $val->mimeTypes);
$val = new FileValidator();
$this->assertEquals([], $val->mimeTypes);
$val = new FileValidator(['mimeTypes' => ['text/plain', 'image/png']]);
$this->assertEquals(['text/plain', 'image/png'], $val->mimeTypes);
}
public function testGetSizeLimit()
{
$size = min($this->sizeToBytes(ini_get('upload_max_filesize')), $this->sizeToBytes(ini_get('post_max_size')));
$val = new FileValidator();
$this->assertEquals($size, $val->getSizeLimit());
$val->maxSize = $size + 1; // set and test if value is overridden
$this->assertEquals($size, $val->getSizeLimit());
$val->maxSize = abs($size - 1);
$this->assertEquals($size - 1, $val->getSizeLimit());
$_POST['MAX_FILE_SIZE'] = $size + 1;
$this->assertEquals($size - 1, $val->getSizeLimit());
$_POST['MAX_FILE_SIZE'] = abs($size - 2);
$this->assertSame($_POST['MAX_FILE_SIZE'], $val->getSizeLimit());
}
protected function sizeToBytes($sizeStr)
{
switch (substr($sizeStr, -1)) {
case 'M':
case 'm':
return (int) $sizeStr * 1048576;
case 'K':
case 'k':
return (int) $sizeStr * 1024;
case 'G':
case 'g':
return (int) $sizeStr * 1073741824;
default:
return (int) $sizeStr;
}
}
public function testValidateAttributeMultiple()
{
$val = new FileValidator([
'maxFiles' => 2,
]);
$m = FakedValidationModel::createWithAttributes(['attr_files' => 'path']);
$val->validateAttribute($m, 'attr_files');
$this->assertTrue($m->hasErrors('attr_files'));
$m = FakedValidationModel::createWithAttributes(['attr_files' => []]);
$val->validateAttribute($m, 'attr_files');
$this->assertTrue($m->hasErrors('attr_files'));
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files')));
$m = FakedValidationModel::createWithAttributes(
[
'attr_files' => $this->createTestFiles(
[
[
'name' => 'test_up_1.txt',
'size' => 1024,
],
[
'error' => UPLOAD_ERR_NO_FILE,
],
]
),
]
);
$val->validateAttribute($m, 'attr_files');
$this->assertFalse($m->hasErrors('attr_files'));
$m = FakedValidationModel::createWithAttributes([
'attr_files' => $this->createTestFiles([
[''], [''], [''],
]),
]);
$val->validateAttribute($m, 'attr_files');
$this->assertTrue($m->hasErrors());
$this->assertNotFalse(stripos(current($m->getErrors('attr_files')), 'you can upload at most'));
$files = [
'file_1' => [
'name' => 'test_up_1.txt',
'size' => 1024,
],
'file_2' => [
'name' => 'test_up_2.txt',
'size' => 1024,
]
];
$m = FakedValidationModel::createWithAttributes(
[
'attr_files' => $this->createTestFiles(
$files
),
]
);
$val->validateAttribute($m, 'attr_files');
$this->assertFalse($m->hasErrors());
$this->assertEquals(array_keys($m->attr_files), array_keys($files));
$val->maxFiles = 0;
$m->clearErrors();
$val->validateAttribute($m, 'attr_files');
$this->assertFalse($m->hasErrors());
$m = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'text.txt',
'size' => 1024,
],
]
),
]
);
$m->setScenario('validateMultipleFiles');
$this->assertFalse($m->validate());
$this->assertNotFalse(stripos(current($m->getErrors('attr_images')),
'Only files with these extensions are allowed'));
$m = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
),
]
);
$m->setScenario('validateMultipleFiles');
$this->assertTrue($m->validate());
$m = FakedValidationModel::createWithAttributes(
[
'attr_image' => $this->createTestFiles(
[
[
'name' => 'text.txt',
'size' => 1024,
],
]
),
]
);
$m->setScenario('validateFile');
$this->assertFalse($m->validate());
}
public function testValidateAttribute_minFilesGreaterThanOneMaxFilesUnlimited_notError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertFalse($model->hasErrors('attr_images'));
}
public function testValidateAttribute_minFilesTwoMaxFilesFour_notError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 4]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertFalse($model->hasErrors('attr_images'));
}
public function testValidateAttribute_minFilesTwoMaxFilesUnlimited_hasError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'error' => UPLOAD_ERR_NO_FILE,
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertTrue($model->hasErrors('attr_images'));
}
/**
* @param array $params
* @return UploadedFile[]
*/
protected function createTestFiles($params = [])
{
$rndString = function ($len = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < $len; $i++) {
$randomString .= $characters[random_int(0, strlen($characters) - 1)];
}
return $randomString;
};
$files = [];
foreach ($params as $key => $param) {
if (empty($param) && count($params) != 1) {
$files[$key] = ['no instance of UploadedFile'];
continue;
}
$name = isset($param['name']) ? $param['name'] : $rndString();
$tempName = \Yii::getAlias('@yiiunit/runtime/validators/file/tmp/') . $name;
if (is_readable($tempName)) {
$size = filesize($tempName);
} else {
$size = isset($param['size']) ? $param['size'] : random_int(
1,
$this->sizeToBytes(ini_get('upload_max_filesize'))
);
}
$type = isset($param['type']) ? $param['type'] : 'text/plain';
$error = isset($param['error']) ? $param['error'] : UPLOAD_ERR_OK;
if (count($params) == 1) {
$error = empty($param) ? UPLOAD_ERR_NO_FILE : $error;
return new UploadedFile([
'name' => $name,
'tempName' => $tempName,
'type' => $type,
'size' => $size,
'error' => $error,
]);
}
$files[$key] = new UploadedFile([
'name' => $name,
'tempName' => $tempName,
'type' => $type,
'size' => $size,
'error' => $error,
]);
}
return $files;
}
/**
* @param $fileName
* @return UploadedFile
*/
protected function getRealTestFile($fileName)
{
$filePath = \Yii::getAlias('@yiiunit/framework/validators/data/mimeType/') . $fileName;
return new UploadedFile([
'name' => $fileName,
'tempName' => $filePath,
'type' => FileHelper::getMimeType($filePath),
'size' => filesize($filePath),
'error' => UPLOAD_ERR_OK,
]);
}
public function testValidateAttribute()
{
// single File
$val = new FileValidator();
$m = $this->createModelForAttributeTest();
$val->validateAttribute($m, 'attr_files');
$this->assertFalse($m->hasErrors());
$val->validateAttribute($m, 'attr_files_empty');
$this->assertTrue($m->hasErrors('attr_files_empty'));
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty')));
// single File with skipOnEmpty = false
$val = new FileValidator(['skipOnEmpty' => false]);
$m = $this->createModelForAttributeTest();
$val->validateAttribute($m, 'attr_files');
$this->assertFalse($m->hasErrors());
$val->validateAttribute($m, 'attr_files_empty');
$this->assertTrue($m->hasErrors('attr_files_empty'));
$this->assertSame($val->uploadRequired, current($m->getErrors('attr_files_empty')));
$m = $this->createModelForAttributeTest();
// too big
$val = new FileValidator(['maxSize' => 128]);
$val->validateAttribute($m, 'attr_files');
$this->assertTrue($m->hasErrors('attr_files'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_files')), 'too big'));
// to Small
$m = $this->createModelForAttributeTest();
$val = new FileValidator(['minSize' => 2048]);
$val->validateAttribute($m, 'attr_files');
$this->assertTrue($m->hasErrors('attr_files'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_files')), 'too small'));
// UPLOAD_ERR_INI_SIZE/UPLOAD_ERR_FORM_SIZE
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_ini');
$this->assertTrue($m->hasErrors('attr_err_ini'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_err_ini')), 'too big'));
// UPLOAD_ERR_PARTIAL
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_part');
$this->assertTrue($m->hasErrors('attr_err_part'));
$this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part')));
}
public function testValidateAttributeType()
{
$val = new FileValidator([
'extensions' => 'jpeg, jpg',
'checkExtensionByMimeType' => false,
]);
$m = FakedValidationModel::createWithAttributes(
[
'attr_jpg' => $this->createTestFiles([['name' => 'one.jpeg']]),
'attr_exe' => $this->createTestFiles([['name' => 'bad.exe']]),
]
);
$val->validateAttribute($m, 'attr_jpg');
$this->assertFalse($m->hasErrors('attr_jpg'));
$val->validateAttribute($m, 'attr_exe');
$this->assertTrue($m->hasErrors('attr_exe'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_exe')), 'Only files with these extensions '));
}
public function testValidateEmptyExtension()
{
$val = new FileValidator([
'extensions' => ['txt', ''],
'checkExtensionByMimeType' => false,
]);
$m = FakedValidationModel::createWithAttributes(
[
'attr_txt' => $this->createTestFiles([['name' => 'one.txt']]),
'attr_empty' => $this->createTestFiles([['name' => 'bad.']]),
'attr_empty2' => $this->createTestFiles([['name' => 'bad']]),
]
);
$val->validateAttribute($m, 'attr_txt');
$this->assertFalse($m->hasErrors('attr_txt'));
$val->validateAttribute($m, 'attr_empty');
$this->assertFalse($m->hasErrors('attr_empty'));
$val->validateAttribute($m, 'attr_empty2');
$this->assertFalse($m->hasErrors('attr_empty2'));
}
public function testValidateAttributeDoubleType()
{
$val = new FileValidator([
'extensions' => 'tar.gz, tar.xz',
'checkExtensionByMimeType' => false,
]);
$m = FakedValidationModel::createWithAttributes(
[
'attr_tar' => $this->createTestFiles([['name' => 'one.tar.gz']]),
'attr_bar' => $this->createTestFiles([['name' => 'bad.bar.xz']]),
'attr_badtar' => $this->createTestFiles([['name' => 'badtar.xz']]),
]
);
$val->validateAttribute($m, 'attr_tar');
$this->assertFalse($m->hasErrors('attr_tar'));
$val->validateAttribute($m, 'attr_bar');
$this->assertTrue($m->hasErrors('attr_bar'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_bar')), 'Only files with these extensions '));
$val->validateAttribute($m, 'attr_badtar');
$this->assertTrue($m->hasErrors('attr_badtar'));
$this->assertNotFalse(stripos(current($m->getErrors('attr_badtar')), 'Only files with these extensions '));
}
public function testIssue11012()
{
$baseName = '飛兒樂團光茫';
/** @var UploadedFile $file */
$file = $this->createTestFiles([
['name' => $baseName . '.txt'],
]);
$this->assertEquals($baseName, $file->getBaseName());
}
/**
* @param string $fileName
* @param string $mask
* @dataProvider validMimeTypes
*/
public function testValidateMimeTypeMaskValid($fileName, $mask)
{
$validator = new FileValidator(['mimeTypes' => $mask]);
$file = $this->getRealTestFile($fileName);
$this->assertTrue($validator->validate($file));
}
/**
* @param string $fileName
* @param string $mask
* @dataProvider invalidMimeTypes
*/
public function testValidateMimeTypeMaskInvalid($fileName, $mask)
{
$validator = new FileValidator(['mimeTypes' => $mask]);
$file = $this->getRealTestFile($fileName);
$this->assertFalse($validator->validate($file));
}
public function validMimeTypes()
{
return array_filter([
['test.svg', 'image/*', 'svg'],
['test.jpg', 'image/*', 'jpg'],
['test.png', 'image/*', 'png'],
['test.png', 'IMAGE/*', 'png'],
['test.txt', 'text/*', 'txt'],
['test.xml', '*/xml', 'xml'],
['test.odt', 'application/vnd*', 'odt'],
['test.tar.xz', 'application/x-xz', 'tar.xz'],
]);
}
public function invalidMimeTypes()
{
return [
['test.txt', 'image/*', 'png, jpg'],
['test.odt', 'text/*', 'txt'],
['test.xml', '*/svg+xml', 'svg'],
['test.png', 'image/x-iso9660-image', 'bmp'],
['test.svg', 'application/*', 'jpg'],
];
}
/**
* @param string $fileName
* @param mixed $_
* @param string|array $allowedExtensions
* @dataProvider validMimeTypes
*/
public function testValidateFileByExtensionUsingMimeType($fileName, $_, $allowedExtensions)
{
$validator = new FileValidator(['extensions' => (array) $allowedExtensions]);
$file = $this->getRealTestFile($fileName);
$detectedMimeType = FileHelper::getMimeType($file->tempName, null, false);
$this->assertTrue($validator->validate($file), "Mime type detected was \"$detectedMimeType\". Consider adding it to MimeTypeController::\$aliases.");
}
/**
* @param string $fileName
* @param mixed $_
* @param string|array $allowedExtensions
* @dataProvider invalidMimeTypes
*/
public function testValidateFileByExtensionUsingMimeTypeInvalid($fileName, $_, $allowedExtensions)
{
$validator = new FileValidator(['extensions' => (array) $allowedExtensions]);
$file = $this->getRealTestFile($fileName);
$this->assertFalse($validator->validate($file));
}
protected function createModelForAttributeTest()
{
return FakedValidationModel::createWithAttributes(
[
'attr_files' => $this->createTestFiles([
['name' => 'abc.jpg', 'size' => 1024, 'type' => 'image/jpeg'],
]),
'attr_files_empty' => $this->createTestFiles([[]]),
'attr_err_ini' => $this->createTestFiles([['error' => UPLOAD_ERR_INI_SIZE]]),
'attr_err_part' => $this->createTestFiles([['error' => UPLOAD_ERR_PARTIAL]]),
'attr_err_tmp' => $this->createTestFiles([['error' => UPLOAD_ERR_NO_TMP_DIR]]),
'attr_err_write' => $this->createTestFiles([['error' => UPLOAD_ERR_CANT_WRITE]]),
'attr_err_ext' => $this->createTestFiles([['error' => UPLOAD_ERR_EXTENSION]]),
]
);
}
public function testValidateAttributeErrPartial()
{
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_part');
$this->assertTrue($m->hasErrors('attr_err_part'));
$this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_part')));
}
public function testValidateAttributeErrCantWrite()
{
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_write');
$this->assertTrue($m->hasErrors('attr_err_write'));
$this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_write')));
}
public function testValidateAttributeErrExtension()
{
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_ext');
$this->assertTrue($m->hasErrors('attr_err_ext'));
$this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_ext')));
}
public function testValidateAttributeErrNoTmpDir()
{
$m = $this->createModelForAttributeTest();
$val = new FileValidator();
$val->validateAttribute($m, 'attr_err_tmp');
$this->assertTrue($m->hasErrors('attr_err_tmp'));
$this->assertSame(Yii::t('yii', 'File upload failed.'), current($m->getErrors('attr_err_tmp')));
}
/**
* @param string $mask
* @param string $fileMimeType
* @param bool $expected
* @dataProvider mimeTypeCaseInsensitive
*/
public function testValidateMimeTypeCaseInsensitive($mask, $fileMimeType, $expected) {
$validator = $this->getMock('\yii\validators\FileValidator', ['getMimeTypeByFile']);
$validator->method('getMimeTypeByFile')->willReturn($fileMimeType);
$validator->mimeTypes = [$mask];
$file = $this->getRealTestFile('test.txt');
$this->assertEquals($expected, $validator->validate($file), sprintf('Mime type validate fail: "%s" / "%s"', $mask, $fileMimeType));
}
public function mimeTypeCaseInsensitive() {
return [
['Image/*', 'image/jp2', true],
['image/*', 'Image/jp2', true],
['application/vnd.ms-word.document.macroEnabled.12', 'application/vnd.ms-word.document.macroenabled.12', true],
['image/jxra', 'image/jxrA', true],
];
}
}