• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / forms / 15763260878

19 Jun 2025 05:19PM UTC coverage: 93.011%. Remained the same
15763260878

push

github

dg
netteForms: restructured package, includes UMD and ESM (BC break)

2076 of 2232 relevant lines covered (93.01%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.59
/src/Forms/Validator.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\Forms;
11

12
use Nette;
13
use Nette\Utils\Strings;
14
use Nette\Utils\Validators;
15
use function array_map, count, explode, in_array, is_array, is_float, is_int, is_object, is_string, preg_replace, preg_replace_callback, rtrim, str_replace, strtolower;
16
use const UPLOAD_ERR_INI_SIZE;
17

18

19
/**
20
 * Common validators.
21
 */
22
final class Validator
23
{
24
        use Nette\StaticClass;
25

26
        public static array $messages = [
27
                Controls\CsrfProtection::Protection => 'Your session has expired. Please return to the home page and try again.',
28
                Form::Equal => 'Please enter %s.',
29
                Form::NotEqual => 'This value should not be %s.',
30
                Form::Filled => 'This field is required.',
31
                Form::Blank => 'This field should be blank.',
32
                Form::MinLength => 'Please enter at least %d characters.',
33
                Form::MaxLength => 'Please enter no more than %d characters.',
34
                Form::Length => 'Please enter a value between %d and %d characters long.',
35
                Form::Email => 'Please enter a valid email address.',
36
                Form::URL => 'Please enter a valid URL.',
37
                Form::Integer => 'Please enter a valid integer.',
38
                Form::Float => 'Please enter a valid number.',
39
                Form::Min => 'Please enter a value greater than or equal to %d.',
40
                Form::Max => 'Please enter a value less than or equal to %d.',
41
                Form::Range => 'Please enter a value between %d and %d.',
42
                Form::MaxFileSize => 'The size of the uploaded file can be up to %d bytes.',
43
                Form::MaxPostSize => 'The uploaded data exceeds the limit of %d bytes.',
44
                Form::MimeType => 'The uploaded file is not in the expected format.',
45
                Form::Image => 'The uploaded file must be image in format JPEG, GIF, PNG or WebP.',
46
                Controls\SelectBox::Valid => 'Please select a valid option.',
47
                Controls\UploadControl::Valid => 'An error occurred during file upload.',
48
        ];
49

50

51
        /**
52
         * @internal
53
         */
54
        public static function formatMessage(Rule $rule, bool $withValue = true): string|Nette\HtmlStringable
1✔
55
        {
56
                $message = $rule->message;
1✔
57
                if ($message instanceof Nette\HtmlStringable) {
1✔
58
                        return $message;
×
59

60
                } elseif ($message === null && is_string($rule->validator) && isset(static::$messages[$rule->validator])) {
1✔
61
                        $message = static::$messages[$rule->validator];
1✔
62

63
                } elseif ($message == null) { // intentionally ==
1✔
64
                        trigger_error(
×
65
                                "Missing validation message for control '{$rule->control->getName()}'"
×
66
                                . (is_string($rule->validator) ? " (validator '{$rule->validator}')." : '.'),
×
67
                                E_USER_WARNING,
×
68
                        );
69
                }
70

71
                if ($translator = $rule->control->getForm()->getTranslator()) {
1✔
72
                        $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : null);
1✔
73
                }
74

75
                $message = preg_replace_callback('#%(name|label|value|\d+\$[ds]|[ds])#', function (array $m) use ($rule, $withValue, $translator) {
1✔
76
                        static $i = -1;
1✔
77
                        switch ($m[1]) {
1✔
78
                                case 'name': return $rule->control->getName();
1✔
79
                                case 'label':
80
                                        if ($rule->control instanceof Controls\BaseControl) {
1✔
81
                                                $caption = $rule->control->getCaption();
1✔
82
                                                $caption = $caption instanceof Nette\HtmlStringable
1✔
83
                                                        ? $caption->getText()
1✔
84
                                                        : ($translator ? $translator->translate($caption) : $caption);
1✔
85
                                                return rtrim((string) $caption, ':');
1✔
86
                                        }
87

88
                                        return '';
89
                                case 'value': return $withValue
1✔
90
                                                ? $rule->control->getValue()
1✔
91
                                                : $m[0];
1✔
92
                                default:
93
                                        $args = is_array($rule->arg) ? $rule->arg : [$rule->arg];
1✔
94
                                        $i = (int) $m[1] ? (int) $m[1] - 1 : $i + 1;
1✔
95
                                        $arg = $args[$i] ?? null;
1✔
96
                                        if ($arg === null) {
1✔
97
                                                return '';
1✔
98
                                        } elseif ($arg instanceof Control) {
1✔
99
                                                return $withValue ? $args[$i]->getValue() : "%$i";
1✔
100
                                        } elseif ($rule->control instanceof Controls\DateTimeControl) {
1✔
101
                                                return $rule->control->formatLocaleText($arg);
1✔
102
                                        } else {
103
                                                return $arg;
1✔
104
                                        }
105
                        }
106
                }, $message);
1✔
107
                return $message;
1✔
108
        }
109

110

111
        /********************* default validators ****************d*g**/
112

113

114
        /**
115
         * Is control's value equal with second parameter?
116
         */
117
        public static function validateEqual(Control $control, $arg): bool
1✔
118
        {
119
                $value = $control->getValue();
1✔
120
                $values = is_array($value) ? $value : [$value];
1✔
121
                $args = is_array($arg) ? $arg : [$arg];
1✔
122

123
                foreach ($values as $val) {
1✔
124
                        foreach ($args as $item) {
1✔
125
                                if ($item instanceof \BackedEnum) {
1✔
126
                                        $item = $item->value;
1✔
127
                                }
128

129
                                if ((string) $val === (string) $item) {
1✔
130
                                        continue 2;
1✔
131
                                }
132
                        }
133

134
                        return false;
1✔
135
                }
136

137
                return (bool) $values;
1✔
138
        }
139

140

141
        /**
142
         * Is control's value not equal with second parameter?
143
         */
144
        public static function validateNotEqual(Control $control, $arg): bool
1✔
145
        {
146
                return !static::validateEqual($control, $arg);
1✔
147
        }
148

149

150
        /**
151
         * Returns argument.
152
         */
153
        public static function validateStatic(Control $control, bool $arg): bool
1✔
154
        {
155
                return $arg;
1✔
156
        }
157

158

159
        /**
160
         * Is control filled?
161
         */
162
        public static function validateFilled(Controls\BaseControl $control): bool
1✔
163
        {
164
                return $control->isFilled();
1✔
165
        }
166

167

168
        /**
169
         * Is control not filled?
170
         */
171
        public static function validateBlank(Controls\BaseControl $control): bool
1✔
172
        {
173
                return !$control->isFilled();
1✔
174
        }
175

176

177
        /**
178
         * Is control valid?
179
         */
180
        public static function validateValid(Controls\BaseControl $control): bool
1✔
181
        {
182
                return $control->getRules()->validate();
1✔
183
        }
184

185

186
        /**
187
         * Is a control's value number in specified range?
188
         */
189
        public static function validateRange(Control $control, array $range): bool
1✔
190
        {
191
                if ($control instanceof Controls\DateTimeControl) {
1✔
192
                        return $control->validateMinMax($range[0] ?? null, $range[1] ?? null);
1✔
193
                }
194
                $range = array_map(fn($v) => $v === '' ? null : $v, $range);
1✔
195
                return Validators::isInRange($control->getValue(), $range);
1✔
196
        }
197

198

199
        /**
200
         * Is a control's value number greater than or equal to the specified minimum?
201
         */
202
        public static function validateMin(Control $control, $minimum): bool
1✔
203
        {
204
                return Validators::isInRange($control->getValue(), [$minimum === '' ? null : $minimum, null]);
1✔
205
        }
206

207

208
        /**
209
         * Is a control's value number less than or equal to the specified maximum?
210
         */
211
        public static function validateMax(Control $control, $maximum): bool
1✔
212
        {
213
                return Validators::isInRange($control->getValue(), [null, $maximum === '' ? null : $maximum]);
1✔
214
        }
215

216

217
        /**
218
         * Count/length validator. Range is array, min and max length pair.
219
         */
220
        public static function validateLength(Control $control, array|int $range): bool
1✔
221
        {
222
                if (!is_array($range)) {
1✔
223
                        $range = [$range, $range];
1✔
224
                }
225

226
                $value = $control->getValue();
1✔
227
                return Validators::isInRange(is_array($value) ? count($value) : Strings::length((string) $value), $range);
1✔
228
        }
229

230

231
        /**
232
         * Has control's value minimal count/length?
233
         */
234
        public static function validateMinLength(Control $control, $length): bool
1✔
235
        {
236
                return static::validateLength($control, [$length, null]);
1✔
237
        }
238

239

240
        /**
241
         * Is control's value count/length in limit?
242
         */
243
        public static function validateMaxLength(Control $control, $length): bool
1✔
244
        {
245
                return static::validateLength($control, [null, $length]);
1✔
246
        }
247

248

249
        /**
250
         * Has been button pressed?
251
         */
252
        public static function validateSubmitted(Controls\SubmitButton $control): bool
1✔
253
        {
254
                return $control->isSubmittedBy();
1✔
255
        }
256

257

258
        /**
259
         * Is control's value valid email address?
260
         */
261
        public static function validateEmail(Control $control): bool
1✔
262
        {
263
                return Validators::isEmail((string) $control->getValue());
1✔
264
        }
265

266

267
        /**
268
         * Is control's value valid URL?
269
         */
270
        public static function validateUrl(Control $control): bool
1✔
271
        {
272
                $value = (string) $control->getValue();
1✔
273
                if (Validators::isUrl($value)) {
1✔
274
                        return true;
1✔
275
                }
276

277
                $value = "https://$value";
1✔
278
                if (Validators::isUrl($value)) {
1✔
279
                        $control->setValue($value);
1✔
280
                        return true;
1✔
281
                }
282

283
                return false;
1✔
284
        }
285

286

287
        /**
288
         * Does the control's value match the regular expression?
289
         * Case-sensitive to comply with the HTML5 <input /> pattern attribute behaviour
290
         */
291
        public static function validatePattern(Control $control, string $pattern, bool $caseInsensitive = false): bool
1✔
292
        {
293
                $regexp = "\x01^(?:$pattern)$\x01Du" . ($caseInsensitive ? 'i' : '');
1✔
294
                foreach (static::toArray($control->getValue()) as $item) {
1✔
295
                        $value = $item instanceof Nette\Http\FileUpload ? $item->getUntrustedName() : $item;
1✔
296
                        if (!Strings::match((string) $value, $regexp)) {
1✔
297
                                return false;
1✔
298
                        }
299
                }
300

301
                return true;
1✔
302
        }
303

304

305
        public static function validatePatternCaseInsensitive(Control $control, string $pattern): bool
1✔
306
        {
307
                return self::validatePattern($control, $pattern, caseInsensitive: true);
1✔
308
        }
309

310

311
        /**
312
         * Is a control's value numeric?
313
         */
314
        public static function validateNumeric(Control $control): bool
1✔
315
        {
316
                $value = $control->getValue();
1✔
317
                return (is_int($value) && $value >= 0)
1✔
318
                        || (is_string($value) && Strings::match($value, '#^\d+$#D'));
1✔
319
        }
320

321

322
        /**
323
         * Is a control's value decimal number?
324
         */
325
        public static function validateInteger(Control $control): bool
1✔
326
        {
327
                if (
328
                        Validators::isNumericInt($value = $control->getValue())
1✔
329
                        && !is_float($tmp = $value * 1) // too big for int?
1✔
330
                ) {
331
                        $control->setValue($tmp);
1✔
332
                        return true;
1✔
333
                }
334

335
                return false;
1✔
336
        }
337

338

339
        /**
340
         * Is a control's value float number?
341
         */
342
        public static function validateFloat(Control $control): bool
1✔
343
        {
344
                $value = $control->getValue();
1✔
345
                if (is_string($value)) {
1✔
346
                        $value = str_replace([' ', ','], ['', '.'], $value);
1✔
347
                }
348

349
                if (Validators::isNumeric($value)) {
1✔
350
                        $control->setValue((float) $value);
1✔
351
                        return true;
1✔
352
                }
353

354
                return false;
1✔
355
        }
356

357

358
        /**
359
         * Is file size in limit?
360
         */
361
        public static function validateFileSize(Controls\UploadControl $control, $limit): bool
1✔
362
        {
363
                foreach (static::toArray($control->getValue()) as $file) {
1✔
364
                        if ($file->getSize() > $limit || $file->getError() === UPLOAD_ERR_INI_SIZE) {
1✔
365
                                return false;
1✔
366
                        }
367
                }
368

369
                return true;
1✔
370
        }
371

372

373
        /**
374
         * Has file specified mime type?
375
         * @param  string|string[]  $mimeType
376
         */
377
        public static function validateMimeType(Controls\UploadControl $control, string|array $mimeType): bool
1✔
378
        {
379
                $mimeTypes = is_array($mimeType) ? $mimeType : explode(',', $mimeType);
1✔
380
                foreach (static::toArray($control->getValue()) as $file) {
1✔
381
                        $type = strtolower($file->getContentType() ?? '');
1✔
382
                        if (!in_array($type, $mimeTypes, true) && !in_array(preg_replace('#/.*#', '/*', $type), $mimeTypes, true)) {
1✔
383
                                return false;
1✔
384
                        }
385
                }
386

387
                return true;
1✔
388
        }
389

390

391
        /**
392
         * Is file image?
393
         */
394
        public static function validateImage(Controls\UploadControl $control): bool
1✔
395
        {
396
                foreach (static::toArray($control->getValue()) as $file) {
1✔
397
                        if (!$file->isImage()) {
1✔
398
                                return false;
×
399
                        }
400
                }
401

402
                return true;
1✔
403
        }
404

405

406
        private static function toArray($value): array
407
        {
408
                return is_object($value) ? [$value] : (array) $value;
1✔
409
        }
410
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc