Skip to content

Commit 660c653

Browse files
ziadoztaylorotwell
andauthored
[12.x] Add encoding validation rule for uploaded files (#57823)
* validate file encoding * add method to file rule helper * test file rule helper * add translation and replacements * allow string or uploaded file * generic message for strings and files * handle invalid encoding parameter * test more scenarios * tidy grammar * no @ silencing * typo * lowercase encodings * doc block * ci * alpha * test multiple * generic test filenames * formatting --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 5c6fc41 commit 660c653

File tree

6 files changed

+102
-0
lines changed

6 files changed

+102
-0
lines changed

src/Illuminate/Translation/lang/en/validation.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
'doesnt_end_with' => 'The :attribute field must not end with one of the following: :values.',
5353
'doesnt_start_with' => 'The :attribute field must not start with one of the following: :values.',
5454
'email' => 'The :attribute field must be a valid email address.',
55+
'encoding' => 'The :attribute field must encoded in :encoding.',
5556
'ends_with' => 'The :attribute field must end with one of the following: :values.',
5657
'enum' => 'The selected :attribute is invalid.',
5758
'exists' => 'The selected :attribute is invalid.',

src/Illuminate/Validation/Concerns/ReplacesAttributes.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,20 @@ protected function replaceDigitsBetween($message, $attribute, $rule, $parameters
129129
return $this->replaceBetween($message, $attribute, $rule, $parameters);
130130
}
131131

132+
/**
133+
* Replace all place-holders for the encoding rule.
134+
*
135+
* @param string $message
136+
* @param string $attribute
137+
* @param string $rule
138+
* @param array<int,string> $parameters
139+
* @return string
140+
*/
141+
protected function replaceEncoding($message, $attribute, $rule, $parameters)
142+
{
143+
return str_replace(':encoding', $parameters[0], $message);
144+
}
145+
132146
/**
133147
* Replace all place-holders for the extensions rule.
134148
*

src/Illuminate/Validation/Concerns/ValidatesAttributes.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,25 @@ public function validateEmail($attribute, $value, $parameters)
959959
return $emailValidator->isValid($value, new MultipleValidationWithAnd($validations));
960960
}
961961

962+
/**
963+
* Validate the encoding of an attribute.
964+
*
965+
* @param string $attribute
966+
* @param mixed $value
967+
* @param array<int, int|string> $parameters
968+
* @return bool
969+
*/
970+
public function validateEncoding($attribute, $value, $parameters)
971+
{
972+
$this->requireParameterCount(1, $parameters, 'encoding');
973+
974+
if (! in_array(mb_strtolower($parameters[0]), array_map(mb_strtolower(...), mb_list_encodings()))) {
975+
throw new InvalidArgumentException("Validation rule encoding parameter [{$parameters[0]}] is not a valid encoding.");
976+
}
977+
978+
return mb_check_encoding($value instanceof File ? $value->getContent() : $value, $parameters[0]);
979+
}
980+
962981
/**
963982
* Validate the existence of an attribute value in a database table.
964983
*

src/Illuminate/Validation/Rules/File.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ class File implements Rule, DataAwareRule, ValidatorAwareRule
4545
*/
4646
protected $maximumFileSize = null;
4747

48+
/**
49+
* The required file encoding.
50+
*
51+
* @var string|null
52+
*/
53+
protected $encoding = null;
54+
4855
/**
4956
* An array of custom rules that will be merged into the validation rules.
5057
*
@@ -205,6 +212,19 @@ public function max($size)
205212
return $this;
206213
}
207214

215+
/**
216+
* Indicate that the uploaded file should be in the given encoding.
217+
*
218+
* @param string $encoding
219+
* @return $this
220+
*/
221+
public function encoding($encoding)
222+
{
223+
$this->encoding = $encoding;
224+
225+
return $this;
226+
}
227+
208228
/**
209229
* Convert a potentially human-friendly file size to kilobytes.
210230
*
@@ -291,6 +311,10 @@ protected function buildValidationRules()
291311
default => "size:{$this->minimumFileSize}",
292312
};
293313

314+
if ($this->encoding) {
315+
$rules[] = 'encoding:'.$this->encoding;
316+
}
317+
294318
return array_merge(array_filter($rules), $this->customRules);
295319
}
296320

src/Illuminate/Validation/Validator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class Validator implements ValidatorContract
188188
protected $fileRules = [
189189
'Between',
190190
'Dimensions',
191+
'Encoding',
191192
'Extensions',
192193
'File',
193194
'Image',

tests/Validation/ValidationFileRuleTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,49 @@ public function testMaxWithHumanReadableSizeAndMultipleValue()
357357
);
358358
}
359359

360+
public function testEncoding()
361+
{
362+
// ASCII file containing UTF-8.
363+
$this->fails(
364+
File::default()->encoding('ascii'),
365+
UploadedFile::fake()->createWithContent('foo.txt', '✌️'),
366+
['validation.encoding'],
367+
);
368+
369+
// UTF-8 file containing invalid UTF-8 byte sequence.
370+
$this->fails(
371+
File::default()->encoding('utf-8'),
372+
UploadedFile::fake()->createWithContent('foo.txt', "\xf0\x28\x8c\x28"),
373+
['validation.encoding'],
374+
);
375+
376+
$this->passes(
377+
File::default()->encoding('utf-8'),
378+
UploadedFile::fake()->createWithContent('foo.txt', '✌️'),
379+
);
380+
381+
$this->passes(
382+
File::default()->encoding('utf-8'),
383+
[
384+
UploadedFile::fake()->createWithContent('foo-1.txt', '✌️'),
385+
UploadedFile::fake()->createWithContent('foo-2.txt', '👍'),
386+
]
387+
);
388+
}
389+
390+
public function testEncodingWithInvalidParameter()
391+
{
392+
$this->expectException(\InvalidArgumentException::class);
393+
$this->expectExceptionMessage('Validation rule encoding parameter "FOOBAR" is not a valid encoding.');
394+
395+
// Invalid encoding.
396+
$this->fails(
397+
File::default()->encoding('FOOBAR'),
398+
UploadedFile::fake()->createWithContent('foo.txt', ''),
399+
['validation.encoding'],
400+
);
401+
}
402+
360403
public function testMacro()
361404
{
362405
File::macro('toDocument', function () {

0 commit comments

Comments
 (0)