PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.31
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.31
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.31, at vendor/wpfluent/framework/src/WPFluent/Validator/ValidatesAttributes.php

690 lines 17.0 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 \PackageDev\Framework\Validator\Contracts\File
500 */
501 return $value->getPath() != '' && in_array($value->guessExtension(), $parameters);
502 }
503
504 /**
505 * Validate the MIME type of a file upload attribute is in a set of MIME types.
506 *
507 * @param string $attribute
508 * @param mixed $value
509 * @param array $parameters
510 * @return bool
511 */
512 protected function validateMimetypes($attribute, $value, $parameters)
513 {
514 if (! $this->isValidFileInstance($value)) {
515 return false;
516 }
517
518 if ($this->shouldBlockPhpUpload($value, $parameters)) {
519 return false;
520 }
521
522 return $value->getPath() != '' &&
523 (
524 in_array($value->getMimeType(), $parameters) ||
525 in_array(explode('/', $value->getMimeType())[0].'/*', $parameters)
526 );
527 }
528
529 /**
530 * Check that the given value is a valid file instance.
531 *
532 * @param mixed $value
533 *
534 * @return bool
535 */
536 public function isValidFileInstance($value)
537 {
538 return $value instanceof File && $value->isValid();
539 }
540
541 /**
542 * Check if PHP uploads are explicitly allowed.
543 *
544 * @param mixed $value
545 * @param array $parameters
546 *
547 * @return bool
548 */
549 protected function shouldBlockPhpUpload($value, $parameters)
550 {
551 if (in_array('php', $parameters)) {
552 return false;
553 }
554
555 /**
556 * @var $value \PackageDev\Framework\Validator\Contracts\File
557 */
558 return strtolower($value->getClientOriginalExtension()) === 'php';
559 }
560
561 /**
562 * Validate that an attribute exists even if not filled.
563 *
564 * @param string $attribute
565 * @param mixed $value
566 *
567 * @return bool
568 */
569 protected function validatePresent($attribute, $value)
570 {
571 return Arr::has($this->data, $attribute);
572 }
573
574 /**
575 * Validate that an attribute has a given number of digits.
576 *
577 * @param string $attribute
578 * @param mixed $value
579 * @param array $parameters
580 *
581 * @return bool
582 */
583 public function validateDigits($attribute, $value, $parameters)
584 {
585 $this->requireParameterCount(1, $parameters, 'digits');
586
587 return $this->validateNumeric($attribute, $value)
588 && strlen((string) $value) == $parameters[0];
589 }
590
591 /**
592 * Validate that an attribute is an array.
593 *
594 * @param string $attribute
595 * @param mixed $value
596 * @param array $parameters
597 * @return bool
598 */
599 public function validateArray($attribute, $value, $parameters = [])
600 {
601 if (! is_array($value)) {
602 return false;
603 }
604
605 if (empty($parameters)) {
606 return true;
607 }
608
609 return empty(array_diff_key($value, array_fill_keys($parameters, '')));
610 }
611
612 /**
613 * Validate that an array has all of the given keys.
614 *
615 * @param string $attribute
616 * @param mixed $value
617 * @param array<int, int|string> $parameters
618 * @return bool
619 */
620 public function validateRequiredArrayKeys($attribute, $value, $parameters)
621 {
622 if (!is_array($value)) {
623 return false;
624 }
625
626 foreach ($parameters as $param) {
627 if (!Arr::exists($value, $param)) {
628 return false;
629 }
630 }
631
632 return true;
633 }
634
635 /**
636 * Validate that an attribute passes a regular expression check.
637 *
638 * @param string $attribute
639 * @param mixed $value
640 * @param array<int, int|string> $parameters
641 * @return bool
642 */
643 public function validateRegex($attribute, $value, $parameters)
644 {
645 if (! is_string($value) && ! is_numeric($value)) {
646 return false;
647 }
648
649 $this->requireParameterCount(1, $parameters, 'regex');
650
651 return preg_match($parameters[0], $value) > 0;
652 }
653
654 /**
655 * Validate an attribute is contained within a list of values.
656 *
657 * @param string $attribute
658 * @param mixed $value
659 * @param array $parameters
660 * @return bool
661 */
662 public function validateIn($attribute, $value, $parameters)
663 {
664 if (is_array($value) && $this->hasRule($attribute, 'Array')) {
665 foreach ($value as $element) {
666 if (is_array($element)) {
667 return false;
668 }
669 }
670
671 return count(array_diff($value, $parameters)) === 0;
672 }
673
674 return !is_array($value) && in_array((string) $value, $parameters);
675 }
676
677 /**
678 * Validate an attribute is not contained within a list of values.
679 *
680 * @param string $attribute
681 * @param mixed $value
682 * @param array $parameters
683 * @return bool
684 */
685 public function validateNotIn($attribute, $value, $parameters)
686 {
687 return !$this->validateIn($attribute, $value, $parameters);
688 }
689 }
690