PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.99
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.99
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / vendor / wpfluent / framework / src / WPFluent / Validator / ValidatesAttributes.php

ValidatesAttributes.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 1.0.99, at vendor/wpfluent/framework/src/WPFluent/Validator/ValidatesAttributes.php

691 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 FluentCommunity\Framework\Validator;
4
5 use Countable;
6 use Exception;
7 use ValueError;
8 use DateTimeInterface;
9 use InvalidArgumentException;
10 use FluentCommunity\Framework\Support\Str;
11 use FluentCommunity\Framework\Support\Arr;
12 use FluentCommunity\Framework\Support\Helper;
13 use FluentCommunity\Framework\Support\DateTime;
14 use FluentCommunity\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 \FluentCommunity\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 \FluentCommunity\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 return Arr::has($this->data, $attribute);
573 }
574
575 /**
576 * Validate that an attribute has a given number of digits.
577 *
578 * @param string $attribute
579 * @param mixed $value
580 * @param array $parameters
581 *
582 * @return bool
583 */
584 public function validateDigits($attribute, $value, $parameters)
585 {
586 $this->requireParameterCount(1, $parameters, 'digits');
587
588 return $this->validateNumeric($attribute, $value)
589 && strlen((string) $value) == $parameters[0];
590 }
591
592 /**
593 * Validate that an attribute is an array.
594 *
595 * @param string $attribute
596 * @param mixed $value
597 * @param array $parameters
598 * @return bool
599 */
600 public function validateArray($attribute, $value, $parameters = [])
601 {
602 if (! is_array($value)) {
603 return false;
604 }
605
606 if (empty($parameters)) {
607 return true;
608 }
609
610 return empty(array_diff_key($value, array_fill_keys($parameters, '')));
611 }
612
613 /**
614 * Validate that an array has all of the given keys.
615 *
616 * @param string $attribute
617 * @param mixed $value
618 * @param array<int, int|string> $parameters
619 * @return bool
620 */
621 public function validateRequiredArrayKeys($attribute, $value, $parameters)
622 {
623 if (!is_array($value)) {
624 return false;
625 }
626
627 foreach ($parameters as $param) {
628 if (!Arr::exists($value, $param)) {
629 return false;
630 }
631 }
632
633 return true;
634 }
635
636 /**
637 * Validate that an attribute passes a regular expression check.
638 *
639 * @param string $attribute
640 * @param mixed $value
641 * @param array<int, int|string> $parameters
642 * @return bool
643 */
644 public function validateRegex($attribute, $value, $parameters)
645 {
646 if (! is_string($value) && ! is_numeric($value)) {
647 return false;
648 }
649
650 $this->requireParameterCount(1, $parameters, 'regex');
651
652 return preg_match($parameters[0], $value) > 0;
653 }
654
655 /**
656 * Validate an attribute is contained within a list of values.
657 *
658 * @param string $attribute
659 * @param mixed $value
660 * @param array $parameters
661 * @return bool
662 */
663 public function validateIn($attribute, $value, $parameters)
664 {
665 if (is_array($value) && $this->hasRule($attribute, 'Array')) {
666 foreach ($value as $element) {
667 if (is_array($element)) {
668 return false;
669 }
670 }
671
672 return count(array_diff($value, $parameters)) === 0;
673 }
674
675 return !is_array($value) && in_array((string) $value, $parameters);
676 }
677
678 /**
679 * Validate an attribute is not contained within a list of values.
680 *
681 * @param string $attribute
682 * @param mixed $value
683 * @param array $parameters
684 * @return bool
685 */
686 public function validateNotIn($attribute, $value, $parameters)
687 {
688 return !$this->validateIn($attribute, $value, $parameters);
689 }
690 }
691