From 5a691228e2a4288a33e46f5c9ca3118efbafa955 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 31 Aug 2016 01:16:36 +0200 Subject: [PATCH] Handle validating failed file uploads --- src/Illuminate/Validation/Validator.php | 20 ++++++++++ tests/Validation/ValidationValidatorTest.php | 42 +++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index e17bacaf2390..1767470ce6ed 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -149,6 +149,13 @@ class Validator implements ValidatorContract */ protected $sizeRules = ['Size', 'Between', 'Min', 'Max']; + /** + * The validation rules that work with files. + * + * @var array + */ + protected $fileRules = ['File', 'Image', 'Mimes', 'Mimetypes', 'Min', 'Max', 'Size', 'Between', 'Dimensions']; + /** * The numeric related validation rules. * @@ -518,6 +525,15 @@ protected function validateAttribute($attribute, $rule) // that the attribute is required, rules are not run for missing values. $value = $this->getValue($attribute); + if ( + $value instanceof UploadedFile && + ! $value->isValid() && + $this->hasRule($attribute, array_merge($this->fileRules, $this->implicitRules)) + ) { + return $this->addFailure($attribute, 'file_uploaded', []); + } + + $validatable = $this->isValidatable($rule, $attribute, $value); $method = "validate{$rule}"; @@ -762,6 +778,10 @@ protected function shouldStopValidating($attribute) return $this->messages->has($attribute); } + if (isset($this->failedRules[$attribute]) && in_array('file_uploaded', array_keys($this->failedRules[$attribute]))) { + return true; + } + // In case the attribute has any rule that indicates that the field is required // and that rule already failed then we should stop validation at this point // as now there is no point in calling other rules with this field empty. diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 0fb74e8cba5c..bc92b4474cab 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -769,6 +769,46 @@ public function testRequiredUnless() $this->assertEquals('The last field is required unless first is in taylor, sven.', $v->messages()->first('last')); } + public function testFailedFileUploads() + { + $trans = $this->getRealTranslator(); + + // If file is not successfully uploaded validation should fail with a + // 'file_uploaded' error message instead of the original rule. + $file = m::mock('Symfony\Component\HttpFoundation\File\UploadedFile'); + $file->shouldReceive('isValid')->andReturn(false); + $file->shouldNotReceive('getSize'); + $v = new Validator($trans, [], ['photo' => 'Max:10']); + $v->setFiles(['photo' => $file]); + $this->assertTrue($v->fails()); + $this->assertEquals(['validation.file_uploaded'], $v->errors()->get('photo')); + + // Even "required" will not run if the file failed to upload. + $file = m::mock('Symfony\Component\HttpFoundation\File\UploadedFile'); + $file->shouldReceive('isValid')->once()->andReturn(false); + $v = new Validator($trans, [], ['photo' => 'required']); + $v->setFiles(['photo' => $file]); + $this->assertTrue($v->fails()); + $this->assertEquals(['validation.file_uploaded'], $v->errors()->get('photo')); + + // It should only fail with that rule if a validation rule implies it's + // a file. Otherwise it should fail with the regular rule. + $file = m::mock('Symfony\Component\HttpFoundation\File\UploadedFile'); + $file->shouldReceive('isValid')->andReturn(false); + $v = new Validator($trans, [], ['photo' => 'string']); + $v->setFiles(['photo' => $file]); + $this->assertTrue($v->fails()); + $this->assertEquals(['validation.string'], $v->errors()->get('photo')); + + // Validation shouldn't continue if a file failed to upload. + $file = m::mock('Symfony\Component\HttpFoundation\File\UploadedFile'); + $file->shouldReceive('isValid')->once()->andReturn(false); + $v = new Validator($trans, [], ['photo' => 'file|mimes:pdf|min:10']); + $v->setFiles(['photo' => $file]); + $this->assertTrue($v->fails()); + $this->assertEquals(['validation.file_uploaded'], $v->errors()->get('photo')); + } + public function testValidateInArray() { $trans = $this->getRealTranslator(); @@ -1187,7 +1227,7 @@ public function testValidateMax() $this->assertFalse($v->passes()); $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['isValid', 'getSize'])->setConstructorArgs([__FILE__, basename(__FILE__)])->getMock(); - $file->expects($this->at(0))->method('isValid')->will($this->returnValue(true)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); $file->expects($this->at(1))->method('getSize')->will($this->returnValue(3072)); $v = new Validator($trans, [], ['photo' => 'Max:10']); $v->setFiles(['photo' => $file]);