PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.91.6
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.91.6
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Validator / ValidatesAttributes.php

ValidatesAttributes.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.91.6, at vendor/wpfluent/framework/src/WPFluent/Validator/ValidatesAttributes.php

693 lines 17.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\Framework\Validator;
4
5 use Countable;
6 use Exception;
7 use ValueError;
8 use DateTimeInterface;
9 use InvalidArgumentException;
10 use FluentBoards\Framework\Support\Str;
11 use FluentBoards\Framework\Support\Arr;
12 use FluentBoards\Framework\Support\Helper;
13 use FluentBoards\Framework\Support\DateTime;
14 use FluentBoards\Framework\Validator\Contracts\File;
15
16 trait ValidatesAttributes
17 {
18 use ValidateDatabaseRulesTrait;
19
20 /**
21 * Require a certain number of parameters to be present.
22 *
23 * @param int $count
24 * @param array $parameters
25 * @param string $rule
26 *
27 * @return void
28 *
29 * @throws \InvalidArgumentException
30 */
31 protected function requireParameterCount($count, $parameters, $rule)
32 {
33 if (count($parameters) < $count) {
34 throw new InvalidArgumentException(
35 "Validation rule $rule requires at least $count parameters."
36 );
37 }
38 }
39
40 /**
41 * Get the size of an attribute.
42 *
43 * @param string $attribute
44 * @param mixed $value
45 *
46 * @return mixed
47 */
48 protected function getSize($attribute, $value)
49 {
50 // This method will determine if the attribute is a number, string, or file and
51 // return the proper size accordingly. If it is a number, then number itself
52 // is the size. If it is a file, we take kilobytes, and for a string the
53 // entire length of the string will be considered the attribute size.
54 $type = $this->deduceType($value, $attribute);
55
56 switch ($type) {
57 case 'numeric':
58 return $value;
59 case 'array':
60 return count($value);
61 case 'file':
62 return $value->getSize() / 1024;
63 default:
64 return mb_strlen($value);
65 }
66 }
67
68 /**
69 * Deduce the value type of an attribute.
70 *
71 * @param $value
72 *
73 * @return string
74 */
75 protected function deduceType($value, $attribute = null)
76 {
77 if (is_numeric($value)) {
78 return $this->guessType($value, $attribute);
79 } elseif (is_array($value)) {
80 return 'array';
81 } elseif ($value instanceof File) {
82 return 'file';
83 }
84
85 return 'string';
86 }
87
88 /**
89 * Guess the real type by examining rules.
90 *
91 * @param mixed $value
92 * @param string|null $attribute
93 * @return string
94 */
95 protected function guessType($value, $attribute)
96 {
97 if ($attribute && in_array('string', $this->rules[$attribute])) {
98 return 'string';
99 }
100
101 return 'numeric';
102 }
103
104 /**
105 * Check if parameter should be converted to boolean.
106 *
107 * @param string $parameter
108 * @return bool
109 */
110 protected function shouldConvertToBoolean($parameter)
111 {
112 return in_array('boolean', Arr::get($this->rules, $parameter, []));
113 }
114
115 /**
116 * Convert the given values to boolean if they are string "true" / "false".
117 *
118 * @param array $values
119 *
120 * @return array
121 */
122 protected function convertValuesToBoolean($values)
123 {
124 return array_map(function ($value) {
125 if ($value === 'true') {
126 return true;
127 } elseif ($value === 'false') {
128 return false;
129 }
130
131 return $value;
132 }, $values);
133 }
134
135 /**
136 * Convert the given values to null if they are string "null".
137 *
138 * @param array $values
139 * @return array
140 */
141 protected function convertValuesToNull($values)
142 {
143 return array_map(function ($value) {
144 return Str::lower($value) === 'null' ? null : $value;
145 }, $values);
146 }
147
148 /**
149 * Validate that a required attribute exists.
150 *
151 * @param string $attribute
152 * @param mixed $value
153 *
154 * @return bool
155 */
156 protected function validateRequired($attribute, $value)
157 {
158 if (is_null($value)) {
159 return false;
160 } elseif (is_string($value) && trim($value) === '') {
161 return false;
162 } elseif ((is_array($value) || $value instanceof Countable) && count($value) < 1) {
163 return false;
164 } elseif ($value instanceof File) {
165 return (string) $value->getPath() != '';
166 }
167
168 return true;
169 }
170
171 /**
172 * Validate that an attribute exists when another attribute has a given value.
173 *
174 * @param string $attribute
175 * @param mixed $value
176 * @param mixed $parameters
177 *
178 * @return bool
179 */
180 protected function validateRequiredIf($attribute, $value, $parameters)
181 {
182 $this->requireParameterCount(2, $parameters, 'required_if');
183
184 if (preg_match('/\.\d\./', $attribute, $matches)) {
185 $parameters[0] = str_replace(['.*.'], $matches, $parameters[0]);
186 }
187
188 $other = Arr::get($this->data, $parameters[0]);
189
190 $values = array_slice($parameters, 1);
191
192 if (is_bool($other)) {
193 $values = $this->convertValuesToBoolean($values);
194 }
195
196 if (in_array($other, $values)) {
197 return $this->validateRequired($attribute, $value);
198 }
199
200 return true;
201 }
202
203 /**
204 * Validate that an attribute is a valid e-mail address.
205 *
206 * @param string $attribute
207 * @param mixed $value
208 *
209 * @return bool
210 */
211 protected function validateEmail($attribute, $value)
212 {
213 return ! ! is_email($value);
214 }
215
216 /**
217 * Validate the size of an attribute.
218 *
219 * @param string $attribute
220 * @param mixed $value
221 * @param array $parameters
222 *
223 * @return bool
224 */
225 protected function validateSize($attribute, $value, $parameters)
226 {
227 $this->requireParameterCount(1, $parameters, 'size');
228
229 return $this->getSize($attribute, $value) == $parameters[0];
230 }
231
232 /**
233 * Validate the size of an attribute is greater than a minimum value.
234 *
235 * @param string $attribute
236 * @param mixed $value
237 * @param array $parameters
238 *
239 * @return bool
240 */
241 protected function validateMin($attribute, $value, $parameters)
242 {
243 $this->requireParameterCount(1, $parameters, 'min');
244
245 return $this->getSize($attribute, $value) >= $parameters[0];
246 }
247
248 /**
249 * Validate the size of an attribute is less than a maximum value.
250 *
251 * @param string $attribute
252 * @param mixed $value
253 * @param array $parameters
254 *
255 * @return bool
256 */
257 protected function validateMax($attribute, $value, $parameters)
258 {
259 $this->requireParameterCount(1, $parameters, 'max');
260
261 return $this->getSize($attribute, $value) <= $parameters[0];
262 }
263
264 /**
265 * Validate that two attributes match.
266 *
267 * @param string $attribute
268 * @param mixed $value
269 * @param array $parameters
270 *
271 * @return bool
272 */
273 protected function validateSame($attribute, $value, $parameters)
274 {
275 $this->requireParameterCount(1, $parameters, 'same');
276
277 $other = @$this->data[$parameters[0]];
278
279 return $value === $other;
280 }
281
282 /**
283 * Validate that an attribute is a valid URL.
284 *
285 * @param string $attribute
286 * @param mixed $value
287 *
288 * @return bool
289 */
290 protected function validateUrl($attribute, $value)
291 {
292 return (bool) Str::isUrl($value);
293 }
294
295 /**
296 * Validate that an attribute is a string.
297 *
298 * @param string $attribute
299 * @param mixed $value
300 * @return bool
301 */
302 public function validateString($attribute, $value)
303 {
304 return is_string($value);
305 }
306
307 /**
308 * Validate that an attribute is a integer.
309 *
310 * @param string $attribute
311 * @param mixed $value
312 * @return bool
313 */
314 public function validateInt($attribute, $value)
315 {
316 return $this->validateInteger($attribute, $value);
317 }
318
319 /**
320 * Validate that an attribute is a integer.
321 *
322 * @param string $attribute
323 * @param mixed $value
324 * @return bool
325 */
326 public function validateInteger($attribute, $value)
327 {
328 return is_int($value);
329 }
330
331 /**
332 * Validate that an attribute has a given number of decimal places.
333 *
334 * @param string $attribute
335 * @param mixed $value
336 * @param array<int, int|string> $parameters
337 * @return bool
338 */
339 public function validateDecimal($attribute, $value, $parameters)
340 {
341 $this->requireParameterCount(1, $parameters, 'decimal');
342
343 if (!$this->validateNumeric($attribute, $value)) {
344 return false;
345 }
346
347 $matches = [];
348
349 if (preg_match('/^[+-]?\d*\.?(\d*)$/', $value, $matches) !== 1) {
350 return false;
351 }
352
353 $decimals = strlen(end($matches));
354
355 if (!isset($parameters[1])) {
356 return $decimals == $parameters[0];
357 }
358
359 return $decimals >= $parameters[0] && $decimals <= $parameters[1];
360 }
361
362 /**
363 * Validate that an attribute is numeric.
364 *
365 * @param string $attribute
366 * @param mixed $value
367 *
368 * @return bool
369 */
370 protected function validateNumeric($attribute, $value)
371 {
372 return is_numeric($value);
373 }
374
375 /**
376 * Validate that an attribute is a valid date.
377 *
378 * @param string $attribute
379 * @param mixed $value
380 * @return bool
381 */
382 public function validateDate($attribute, $value)
383 {
384 if ($value instanceof DateTimeInterface) {
385 return true;
386 }
387
388 try {
389 if ((!is_string($value) && !is_numeric($value)) || strtotime($value) === false) {
390 return false;
391 }
392 } catch (Exception $e) {
393 return false;
394 }
395
396 $date = date_parse($value);
397
398 return checkdate($date['month'], $date['day'], $date['year']);
399 }
400
401 /**
402 * Validate that an attribute matches a date format.
403 *
404 * @param string $attribute
405 * @param mixed $value
406 * @param array<int, int|string> $parameters
407 * @return bool
408 */
409 public function validateDateFormat($attribute, $value, $parameters)
410 {
411 $this->requireParameterCount(1, $parameters, 'date_format');
412
413 if (!is_string($value) && !is_numeric($value)) {
414 return false;
415 }
416
417 foreach ($parameters as $format) {
418 try {
419 $date = DateTime::createFromFormat('!'.$format, $value);
420
421 if ($date && $date->format($format) == $value) {
422 return true;
423 }
424 } catch (ValueError $e) {
425 return false;
426 }
427 }
428
429 return false;
430 }
431
432 /**
433 * Validate that an attribute is alphabetic.
434 *
435 * @param string $attribute
436 * @param mixed $value
437 *
438 * @return bool
439 */
440 protected function validateAlpha($attribute, $value)
441 {
442 return is_string($value) && preg_match('/^[\pL\pM]+$/u', $value);
443 }
444
445 /**
446 * Validate that an attribute is alphanum.
447 *
448 * @param string $attribute
449 * @param mixed $value
450 *
451 * @return bool
452 */
453 protected function validateAlphanum($attribute, $value)
454 {
455 if (! is_string($value) && ! is_numeric($value)) {
456 return false;
457 }
458
459 return preg_match('/^[\pL\pM\pN]+$/u', $value) > 0;
460 }
461
462 /**
463 * Validate that an attribute is alphanum and -_.
464 *
465 * @param string $attribute
466 * @param mixed $value
467 *
468 * @return bool
469 */
470 protected function validateAlphadash($attribute, $value)
471 {
472 if (! is_string($value) && ! is_numeric($value)) {
473 return false;
474 }
475
476 return preg_match('/^[\pL\pM\pN_-]+$/u', $value) > 0;
477 }
478
479 /**
480 * Validate the guessed extension of a file upload is in a set of file extensions.
481 *
482 * @param string $attribute
483 * @param mixed $value
484 * @param array $parameters
485 *
486 * @return bool
487 */
488 protected function validateMimes($attribute, $value, $parameters)
489 {
490 if (! $this->isValidFileInstance($value)) {
491 return false;
492 }
493
494 if ($this->shouldBlockPhpUpload($value, $parameters)) {
495 return false;
496 }
497
498 /**
499 * @var $value \FluentBoards\Framework\Validator\Contracts\File
500 */
501 return $value->getPath() != '' && in_array(
502 $value->guessExtension(), $parameters
503 );
504 }
505
506 /**
507 * Validate the MIME type of a file upload attribute is in a set of MIME types.
508 *
509 * @param string $attribute
510 * @param mixed $value
511 * @param array $parameters
512 * @return bool
513 */
514 protected function validateMimetypes($attribute, $value, $parameters)
515 {
516 if (! $this->isValidFileInstance($value)) {
517 return false;
518 }
519
520 if ($this->shouldBlockPhpUpload($value, $parameters)) {
521 return false;
522 }
523
524 return $value->getPath() != '' && (
525 in_array($value->getMimeType(), $parameters) ||
526 in_array(explode('/', $value->getMimeType())[0].'/*', $parameters)
527 );
528 }
529
530 /**
531 * Check that the given value is a valid file instance.
532 *
533 * @param mixed $value
534 *
535 * @return bool
536 */
537 public function isValidFileInstance($value)
538 {
539 return $value instanceof File && $value->isValid();
540 }
541
542 /**
543 * Check if PHP uploads are explicitly allowed.
544 *
545 * @param mixed $value
546 * @param array $parameters
547 *
548 * @return bool
549 */
550 protected function shouldBlockPhpUpload($value, $parameters)
551 {
552 if (in_array('php', $parameters)) {
553 return false;
554 }
555
556 /**
557 * @var $value \FluentBoards\Framework\Validator\Contracts\File
558 */
559 return strtolower($value->getClientOriginalExtension()) === 'php';
560 }
561
562 /**
563 * Validate that an attribute exists even if not filled.
564 *
565 * @param string $attribute
566 * @param mixed $value
567 *
568 * @return bool
569 */
570 protected function validatePresent($attribute, $value)
571 {
572 $attribute = str_replace(['[', ']'], ['.', ''], $attribute);
573
574 return Arr::has($this->data, $attribute);
575 }
576
577 /**
578 * Validate that an attribute has a given number of digits.
579 *
580 * @param string $attribute
581 * @param mixed $value
582 * @param array $parameters
583 *
584 * @return bool
585 */
586 public function validateDigits($attribute, $value, $parameters)
587 {
588 $this->requireParameterCount(1, $parameters, 'digits');
589
590 return $this->validateNumeric($attribute, $value)
591 && strlen((string) $value) == $parameters[0];
592 }
593
594 /**
595 * Validate that an attribute is an array.
596 *
597 * @param string $attribute
598 * @param mixed $value
599 * @param array $parameters
600 * @return bool
601 */
602 public function validateArray($attribute, $value, $parameters = [])
603 {
604 if (! is_array($value)) {
605 return false;
606 }
607
608 if (empty($parameters)) {
609 return true;
610 }
611
612 return empty(array_diff_key($value, array_fill_keys($parameters, '')));
613 }
614
615 /**
616 * Validate that an array has all of the given keys.
617 *
618 * @param string $attribute
619 * @param mixed $value
620 * @param array<int, int|string> $parameters
621 * @return bool
622 */
623 public function validateRequiredArrayKeys($attribute, $value, $parameters)
624 {
625 if (!is_array($value)) {
626 return false;
627 }
628
629 foreach ($parameters as $param) {
630 if (!Arr::exists($value, $param)) {
631 return false;
632 }
633 }
634
635 return true;
636 }
637
638 /**
639 * Validate that an attribute passes a regular expression check.
640 *
641 * @param string $attribute
642 * @param mixed $value
643 * @param array<int, int|string> $parameters
644 * @return bool
645 */
646 public function validateRegex($attribute, $value, $parameters)
647 {
648 if (! is_string($value) && ! is_numeric($value)) {
649 return false;
650 }
651
652 $this->requireParameterCount(1, $parameters, 'regex');
653
654 return preg_match($parameters[0], $value) > 0;
655 }
656
657 /**
658 * Validate an attribute is contained within a list of values.
659 *
660 * @param string $attribute
661 * @param mixed $value
662 * @param array $parameters
663 * @return bool
664 */
665 public function validateIn($attribute, $value, $parameters)
666 {
667 if (is_array($value) && $this->hasRule($attribute, 'Array')) {
668 foreach ($value as $element) {
669 if (is_array($element)) {
670 return false;
671 }
672 }
673
674 return count(array_diff($value, $parameters)) === 0;
675 }
676
677 return !is_array($value) && in_array((string) $value, $parameters);
678 }
679
680 /**
681 * Validate an attribute is not contained within a list of values.
682 *
683 * @param string $attribute
684 * @param mixed $value
685 * @param array $parameters
686 * @return bool
687 */
688 public function validateNotIn($attribute, $value, $parameters)
689 {
690 return !$this->validateIn($attribute, $value, $parameters);
691 }
692 }
693