Skip to content

Commit 2779afc

Browse files
authored
Fix #591: Add File validator
1 parent 379ec2e commit 2779afc

20 files changed

Lines changed: 1529 additions & 27 deletions

.github/workflows/bc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ jobs:
3131
['ubuntu-latest']
3232
php: >-
3333
['8.1']
34+
install-development-dependencies: true

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Enh #787: Explicitly import classes, functions, and constants in "use" section (@mspirkov)
66
- Bug #793: Fix translations, broken link in contributing guide, incorrect imports and grammar in documentation (@evilkarter)
77
- Chg #795: Update Polish translations (@rbrzezinski)
8+
- New #591: Add `File` validator (@samdark)
89
- New #798: Add `SplFileInfo` value support to `Image` validator (@samdark)
910
- Bug #798: Fix `Image` validator when unable to read from stream (@samdark)
1011

docs/guide/en/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Compare](built-in-rules-compare.md)
1515
- [Composite](built-in-rules-composite.md)
1616
- [Each](built-in-rules-each.md)
17+
- [File](built-in-rules-file.md)
1718
- [Nested](built-in-rules-nested.md)
1819
- [Required](built-in-rules-required.md)
1920
- [StopOnError](built-in-rules-stop-on-error.md)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# File
2+
3+
`File` checks that a value is a file and can validate its extension, MIME type, and size.
4+
5+
Supported values:
6+
7+
- string file paths;
8+
- `SplFileInfo` instances;
9+
- [PSR-7] `UploadedFileInterface` instances.
10+
11+
Use `Each` for multiple files:
12+
13+
```php
14+
use Yiisoft\Validator\Rule\Each;
15+
use Yiisoft\Validator\Rule\File;
16+
17+
$rules = [
18+
'attachments' => new Each(new File(extensions: ['pdf', 'txt'])),
19+
];
20+
```
21+
22+
For example, with a PSR-7 request:
23+
24+
```php
25+
use Yiisoft\Validator\Rule\Each;
26+
use Yiisoft\Validator\Rule\File;
27+
use Yiisoft\Validator\Validator;
28+
29+
$uploadedFiles = $request->getUploadedFiles()['attachments'] ?? [];
30+
31+
$result = (new Validator())->validate(
32+
['attachments' => $uploadedFiles],
33+
['attachments' => new Each(new File(maxSize: 5_000_000))],
34+
);
35+
```
36+
37+
If your application works with native PHP `$_FILES` data directly, convert it to supported values such as PSR-7 uploaded
38+
file objects before passing it to the validator.
39+
40+
## Uploaded Files
41+
42+
`File` handles PSR-7 upload error codes. `UPLOAD_ERR_NO_FILE` is treated as a missing value, so optional upload fields
43+
can use `skipOnEmpty`:
44+
45+
```php
46+
use Yiisoft\Validator\Rule\File;
47+
48+
$rule = new File(skipOnEmpty: true);
49+
```
50+
51+
Other upload error codes fail validation with `uploadFailedMessage`.
52+
53+
The rule does not prove that arbitrary string paths or `SplFileInfo` values came from PHP's HTTP upload mechanism. Do
54+
not pass user-submitted paths directly. Use PSR-7 uploaded file objects from a trusted request implementation, or perform
55+
[upload provenance checks] before validating filesystem paths.
56+
57+
## MIME Types
58+
59+
For filesystem-backed files, MIME type validation uses PHP's file information facilities through
60+
`mime_content_type()`. If the MIME type can't be determined, MIME validation fails.
61+
62+
For pathless PSR-7 uploads backed only by an in-memory stream, `File` doesn't trust client-provided media type by
63+
default. If your application has already decided that the client metadata is acceptable for this field, enable it
64+
explicitly:
65+
66+
```php
67+
use Yiisoft\Validator\Rule\File;
68+
69+
$rule = new File(
70+
mimeTypes: ['text/plain'],
71+
trustClientMediaType: true,
72+
);
73+
```
74+
75+
This option should be used with care because the client can send any media type value.
76+
77+
## Size
78+
79+
For filesystem-backed uploads, size checks use the actual file size on disk. For pathless streams, size checks use the
80+
PSR-7 upload size when available. If a size constraint is configured and the size can't be determined, validation fails.
81+
82+
`size` is mutually exclusive with `minSize` and `maxSize`. When both `minSize` and `maxSize` are set, `minSize` must be
83+
less than or equal to `maxSize`.
84+
85+
## Request Body Streams
86+
87+
`File` doesn't validate generic request body streams such as data read from `php://input` for PUT requests. Convert such
88+
input to a supported value first, or write a custom rule that validates your stream format and storage flow.
89+
90+
[PSR-7]: https://www.php-fig.org/psr/psr-7/
91+
[upload provenance checks]: https://www.php.net/manual/en/features.file-upload.post-method.php

docs/guide/en/built-in-rules.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Here is a list of all available built-in rules, divided by category.
5757

5858
### File rules
5959

60+
- [File](../../../src/Rule/File.php)
6061
- [Image](../../../src/Rule/Image/Image.php)
6162

6263
### Date rules
@@ -86,6 +87,7 @@ Some rules also have guides in addition to PHPDoc:
8687
- [Compare](built-in-rules-compare.md)
8788
- [Composite](built-in-rules-composite.md)
8889
- [Each](built-in-rules-each.md)
90+
- [File](built-in-rules-file.md)
8991
- [Nested](built-in-rules-nested.md)
9092
- [Required](built-in-rules-required.md)
9193
- [StopOnError](built-in-rules-stop-on-error.md)

messages/de/yii-validator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@
182182
* @see \Yiisoft\Validator\Rule\Date\DateTime
183183
* @see \Yiisoft\Validator\Rule\Date\Time
184184
*/
185+
'{Property} must be no early than {limit}.' => '{Property} darf nicht früher als {limit} sein.',
186+
'{Property} must be no late than {limit}.' => '{Property} darf nicht später als {limit} sein.',
185187
'{Property} must be no earlier than {limit}.' => '{Property} darf nicht früher als {limit} sein.',
186188
'{Property} must be no later than {limit}.' => '{Property} darf nicht später als {limit} sein.',
187189

messages/pt-BR/yii-validator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@
159159
* @see \Yiisoft\Validator\Rule\Date\DateTime
160160
* @see \Yiisoft\Validator\Rule\Date\Time
161161
*/
162+
'{Property} must be no early than {limit}.' => '{Property} não deve ser anterior a {limit}.',
163+
'{Property} must be no late than {limit}.' => '{Property} não deve ser posterior a {limit}.',
162164
'{Property} must be no earlier than {limit}.' => '{Property} não deve ser anterior a {limit}.',
163165
'{Property} must be no later than {limit}.' => '{Property} não deve ser posterior a {limit}.',
164166

messages/ru/yii-validator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@
167167
* @see \Yiisoft\Validator\Rule\Date\DateTime
168168
* @see \Yiisoft\Validator\Rule\Date\Time
169169
*/
170+
'{Property} must be no early than {limit}.' => '{Property} должно быть не ранее {limit}.',
171+
'{Property} must be no late than {limit}.' => '{Property} должно быть не позднее {limit}.',
170172
'{Property} must be no earlier than {limit}.' => '{Property} должно быть не ранее {limit}.',
171173
'{Property} must be no later than {limit}.' => '{Property} должно быть не позднее {limit}.',
172174

messages/uz/yii-validator.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@
159159
* @see \Yiisoft\Validator\Rule\Date\DateTime
160160
* @see \Yiisoft\Validator\Rule\Date\Time
161161
*/
162+
'{Property} must be no early than {limit}.' => '{Property} {limit} dan oldin boʻlmasligi kerak.',
163+
'{Property} must be no late than {limit}.' => '{Property} {limit} dan keyin boʻlmasligi kerak.',
162164
'{Property} must be no earlier than {limit}.' => '{Property} {limit} dan oldin boʻlmasligi kerak.',
163165
'{Property} must be no later than {limit}.' => '{Property} {limit} dan keyin boʻlmasligi kerak.',
164166

src/Rule/Date/DateHandler.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public function __construct(
2222
?string $messageFormat = null,
2323
?int $messageDateType = IntlDateFormatter::SHORT,
2424
string $incorrectInputMessage = '{Property} must be a date.',
25-
string $tooEarlyMessage = '{Property} must be no earlier than {limit}.',
26-
string $tooLateMessage = '{Property} must be no later than {limit}.',
25+
string $tooEarlyMessage = '{Property} must be no early than {limit}.',
26+
string $tooLateMessage = '{Property} must be no late than {limit}.',
2727
) {
2828
parent::__construct(
2929
$dateType,

0 commit comments

Comments
 (0)