prisma-client-php 2.0.12 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,738 +0,0 @@
1
- <?php
2
-
3
- declare(strict_types=1);
4
-
5
- namespace Lib;
6
-
7
- use HTMLPurifier;
8
- use HTMLPurifier_Config;
9
- use DateTime;
10
- use Exception;
11
- use Symfony\Component\Uid\Uuid;
12
- use Symfony\Component\Uid\Ulid;
13
- use Brick\Math\BigDecimal;
14
- use Brick\Math\BigInteger;
15
- use Brick\Math\Exception\MathException;
16
- use Brick\Math\RoundingMode;
17
- use InvalidArgumentException;
18
- use BackedEnum;
19
-
20
- final class Validator
21
- {
22
- // String Validation
23
-
24
- /**
25
- * Validate and sanitize a string.
26
- *
27
- * This function converts the input to a string, trims any leading or trailing
28
- * whitespace, and optionally converts special characters to HTML entities to
29
- * prevent XSS attacks. If the input is null, an empty string is returned.
30
- *
31
- * @param mixed $value The value to validate and sanitize. This can be of any type.
32
- * @param bool $escapeHtml Whether to escape special characters as HTML entities.
33
- * Defaults to true. Set to false when handling database
34
- * queries or other non-HTML contexts.
35
- * @return string The sanitized string. If the input is not a string or null,
36
- * it is converted to its string representation before sanitization.
37
- * If the input is null, an empty string is returned.
38
- */
39
- public static function string($value, bool $escapeHtml = true): string
40
- {
41
- // Convert the value to a string if it's not null
42
- $stringValue = $value !== null ? (string)$value : '';
43
-
44
- // If escaping is enabled, apply htmlspecialchars; otherwise, just trim
45
- return $escapeHtml ? htmlspecialchars(trim($stringValue), ENT_QUOTES, 'UTF-8') : trim($stringValue);
46
- }
47
-
48
- /**
49
- * Validate an email address.
50
- *
51
- * @param mixed $value The value to validate.
52
- * @return string|null The valid email address or null if invalid.
53
- */
54
- public static function email($value): ?string
55
- {
56
- return filter_var($value, FILTER_VALIDATE_EMAIL) !== false ? $value : null;
57
- }
58
-
59
- /**
60
- * Validate a URL.
61
- *
62
- * @param mixed $value The value to validate.
63
- * @return string|null The valid URL or null if invalid.
64
- */
65
- public static function url($value): ?string
66
- {
67
- return filter_var($value, FILTER_VALIDATE_URL) !== false ? $value : null;
68
- }
69
-
70
- /**
71
- * Validate an IP address.
72
- *
73
- * @param mixed $value The value to validate.
74
- * @return string|null The valid IP address or null if invalid.
75
- */
76
- public static function ip($value): ?string
77
- {
78
- return filter_var($value, FILTER_VALIDATE_IP) !== false ? $value : null;
79
- }
80
-
81
- /**
82
- * Validate a UUID.
83
- *
84
- * @param mixed $value The value to validate.
85
- * @return string|null The valid UUID or null if invalid.
86
- */
87
- public static function uuid($value): ?string
88
- {
89
- return Uuid::isValid($value) ? $value : null;
90
- }
91
-
92
- /**
93
- * Validates if the given value is a valid ULID (Universally Unique Lexicographically Sortable Identifier).
94
- *
95
- * @param string $value The value to be validated.
96
- * @return string|null Returns the value if it is a valid ULID, otherwise returns null.
97
- */
98
- public static function ulid($value): ?string
99
- {
100
- return Ulid::isValid($value) ? $value : null;
101
- }
102
-
103
- /**
104
- * Validate a CUID.
105
- *
106
- * @param mixed $value The value to validate.
107
- * @return string|null The valid CUID or null if invalid.
108
- */
109
- public static function cuid($value): ?string
110
- {
111
- // Ensure the value is a string
112
- if (!is_string($value)) {
113
- return null;
114
- }
115
-
116
- // Perform the CUID validation
117
- return preg_match('/^c[0-9a-z]{24}$/', $value) ? $value : null;
118
- }
119
-
120
- /**
121
- * Validate a CUID2.
122
- *
123
- * @param mixed $value The value to validate.
124
- * @return string|null The valid CUID2 or null if invalid.
125
- */
126
- public static function cuid2($value): ?string
127
- {
128
- // Ensure the value is a string
129
- if (!is_string($value)) {
130
- return null;
131
- }
132
-
133
- // Perform the CUID2 validation
134
- return preg_match('/^[0-9a-zA-Z_-]{21,}$/', $value) ? $value : null;
135
- }
136
-
137
- /**
138
- * Validate a size string (e.g., "10MB").
139
- *
140
- * @param mixed $value The value to validate.
141
- * @return string|null The valid size string or null if invalid.
142
- */
143
- public static function bytes($value): ?string
144
- {
145
- return preg_match('/^[0-9]+[kKmMgGtT]?[bB]?$/', $value) ? $value : null;
146
- }
147
-
148
- /**
149
- * Validate an XML string.
150
- *
151
- * @param mixed $value The value to validate.
152
- * @return string|null The valid XML string or null if invalid.
153
- */
154
- public static function xml($value): ?string
155
- {
156
- return preg_match('/^<\?xml/', $value) ? $value : null;
157
- }
158
-
159
- // Number Validation
160
-
161
- /**
162
- * Validate an integer value.
163
- *
164
- * @param mixed $value The value to validate.
165
- * @return int|null The integer value or null if invalid.
166
- */
167
- public static function int($value): ?int
168
- {
169
- return filter_var($value, FILTER_VALIDATE_INT) !== false ? (int)$value : null;
170
- }
171
-
172
- /**
173
- * Validate a big integer value.
174
- *
175
- * @param mixed $value The value to validate.
176
- * @return BigInteger|null The big integer value or null if invalid.
177
- */
178
- public static function bigInt($value): ?BigInteger
179
- {
180
- try {
181
- return BigInteger::of($value);
182
- } catch (MathException) {
183
- return null;
184
- }
185
- }
186
-
187
- /**
188
- * Validate a float value.
189
- *
190
- * @param mixed $value The value to validate.
191
- * @return float|null The float value or null if invalid.
192
- */
193
- public static function float($value): ?float
194
- {
195
- return filter_var($value, FILTER_VALIDATE_FLOAT) !== false ? (float)$value : null;
196
- }
197
-
198
- /**
199
- * Validate a decimal value.
200
- *
201
- * @param mixed $value The value to validate.
202
- * @param int $scale The number of decimal places (default is 30).
203
- * @return BigDecimal|null The decimal value or null if invalid.
204
- */
205
- public static function decimal($value, int $scale = 30): ?BigDecimal
206
- {
207
- try {
208
- return BigDecimal::of($value)->toScale($scale, RoundingMode::HALF_UP);
209
- } catch (MathException) {
210
- return null;
211
- }
212
- }
213
-
214
- // Date Validation
215
-
216
- /**
217
- * Validate and format a date in a given format.
218
- *
219
- * This function attempts to parse the input value as a date according to the specified format.
220
- * If the value is valid, it returns the formatted date string. Otherwise, it returns null.
221
- *
222
- * @param mixed $value The value to validate. It can be a string or a DateTime object.
223
- * @param string $format The expected date format (default is 'Y-m-d').
224
- * @return string|null The formatted date string if valid, or null if invalid.
225
- */
226
- public static function date($value, string $format = 'Y-m-d'): ?string
227
- {
228
- try {
229
- if ($value instanceof DateTime) {
230
- $date = $value;
231
- } else {
232
- $date = DateTime::createFromFormat($format, (string)$value);
233
- }
234
-
235
- if ($date && $date->format($format) === (string)$value) {
236
- return $date->format($format);
237
- }
238
- } catch (Exception) {
239
- return null;
240
- }
241
-
242
- return null;
243
- }
244
-
245
- /**
246
- * Validates and formats a date-time value.
247
- *
248
- * This method attempts to create a DateTime object from the given value and formats it
249
- * according to the specified format. If the value is already a DateTime object, it uses
250
- * it directly. If the value cannot be parsed into a DateTime object, the method returns null.
251
- *
252
- * @param mixed $value The value to be validated and formatted. It can be a string or a DateTime object.
253
- * @param string $format The format to use for the output date-time string. Default is 'Y-m-d H:i:s.u'.
254
- * @return string|null The formatted date-time string, or null if the value could not be parsed.
255
- */
256
- public static function dateTime($value, string $format = 'Y-m-d H:i:s'): ?string
257
- {
258
- try {
259
- if ($value instanceof DateTime) {
260
- $date = $value;
261
- } else {
262
- $date = new DateTime($value);
263
- }
264
- } catch (Exception) {
265
- return null;
266
- }
267
-
268
- return $date->format($format);
269
- }
270
-
271
- // Boolean Validation
272
-
273
- /**
274
- * Validate a boolean value.
275
- *
276
- * @param mixed $value The value to validate.
277
- * @return bool|null The boolean value or null if invalid.
278
- */
279
- public static function boolean($value): ?bool
280
- {
281
- return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
282
- }
283
-
284
- // Other Validation
285
-
286
- /**
287
- * Validate a JSON string.
288
- *
289
- * @param mixed $value The value to validate.
290
- * @return bool True if valid JSON, false otherwise.
291
- */
292
- public static function json($value): bool
293
- {
294
- json_decode($value);
295
- return json_last_error() === JSON_ERROR_NONE;
296
- }
297
-
298
- /**
299
- * Validate an enum value against allowed values.
300
- *
301
- * @param mixed $value The value to validate.
302
- * @param array $allowedValues The allowed values.
303
- * @return bool True if value is allowed, false otherwise.
304
- */
305
- public static function enum($value, array $allowedValues): bool
306
- {
307
- return in_array($value, $allowedValues, true);
308
- }
309
-
310
- /**
311
- * Validates and casts a value (or array of values) of a native enum.
312
- *
313
- * @template T of BackedEnum
314
- * @param string|int|T|array<string|int|T> $value String, integer, instance, or array.
315
- * @param class-string<T> $enumClass Enum class name.
316
- * @return string|int|array<string|int>|null Backed value(s) or null if any is invalid.
317
- * @throws InvalidArgumentException If the class is not an enum.
318
- */
319
- public static function enumClass(mixed $value, string $enumClass): string|int|array|null
320
- {
321
- if (!enum_exists($enumClass)) {
322
- throw new InvalidArgumentException("Enum '$enumClass' not found.");
323
- }
324
-
325
- $cast = static function ($v) use ($enumClass) {
326
- if (is_object($v) && $v instanceof $enumClass && property_exists($v, 'value')) {
327
- return $v->value;
328
- }
329
- $inst = $enumClass::tryFrom($v);
330
- return $inst?->value;
331
- };
332
-
333
- if (is_array($value)) {
334
- $out = [];
335
- foreach ($value as $item) {
336
- $val = $cast($item);
337
- if ($val === null) {
338
- return null;
339
- }
340
- $out[] = $val;
341
- }
342
- return $out;
343
- }
344
-
345
- return $cast($value);
346
- }
347
-
348
- /**
349
- * Purify and sanitize HTML content.
350
- *
351
- * @param string $html The HTML content to purify.
352
- * @return string The purified HTML content.
353
- */
354
- public static function html(string $html): string
355
- {
356
- $config = HTMLPurifier_Config::createDefault();
357
- $purifier = new HTMLPurifier($config);
358
- return $purifier->purify($html);
359
- }
360
-
361
- /**
362
- * Converts emojis or special characters in the message content to appropriate HTML entities or format.
363
- *
364
- * @param string $content The content to process.
365
- * @return string The processed content.
366
- */
367
- public static function emojis($content): string
368
- {
369
- static $emojiMap = [
370
- ':)' => '😊',
371
- ':-)' => '😊',
372
- ':(' => '☹️',
373
- ':-(' => '☹️',
374
- ':D' => '😄',
375
- ':-D' => '😄',
376
- ':P' => '😛',
377
- ':-P' => '😛',
378
- ';)' => '😉',
379
- ';-)' => '😉',
380
- ':o' => '😮',
381
- ':-o' => '😮',
382
- ':O' => '😮',
383
- ':-O' => '😮',
384
- 'B)' => '😎',
385
- 'B-)' => '😎',
386
- ':|' => '😐',
387
- ':-|' => '😐',
388
- ':/' => '😕',
389
- ':-/' => '😕',
390
- ':\\' => '😕',
391
- ':-\\' => '😕',
392
- ':*' => '😘',
393
- ':-*' => '😘',
394
- '<3' => '❤️',
395
- '</3' => '💔',
396
- ':@' => '😡',
397
- ':-@' => '😡',
398
- ':S' => '😖',
399
- ':-S' => '😖',
400
- ':$' => '😳',
401
- ':-$' => '😳',
402
- ':X' => '🤐',
403
- ':-X' => '🤐',
404
- ':#' => '🤐',
405
- ':-#' => '🤐',
406
- ':^)' => '😊',
407
- ':v' => '😋',
408
- ':3' => '😺',
409
- 'O:)' => '😇',
410
- 'O:-)' => '😇',
411
- '>:)' => '😈',
412
- '>:-)' => '😈',
413
- 'D:' => '😧',
414
- 'D-:' => '😧',
415
- ':-o' => '😯',
416
- ':p' => '😋',
417
- ':-p' => '😋',
418
- ':b' => '😋',
419
- ':-b' => '😋',
420
- ':^/' => '😕',
421
- ':-^/' => '😕',
422
- '>_<' => '😣',
423
- '-_-' => '😑',
424
- '^_^' => '😊',
425
- 'T_T' => '😢',
426
- 'TT_TT' => '😭',
427
- 'xD' => '😆',
428
- 'XD' => '😆',
429
- 'xP' => '😝',
430
- 'XP' => '😝',
431
- ':wave:' => '👋',
432
- ':thumbsup:' => '👍',
433
- ':thumbsdown:' => '👎',
434
- ':clap:' => '👏',
435
- ':fire:' => '🔥',
436
- ':100:' => '💯',
437
- ':poop:' => '💩',
438
- ':smile:' => '😄',
439
- ':smirk:' => '😏',
440
- ':sob:' => '😭',
441
- ':heart:' => '❤️',
442
- ':broken_heart:' => '💔',
443
- ':grin:' => '😁',
444
- ':joy:' => '😂',
445
- ':cry:' => '😢',
446
- ':angry:' => '😠',
447
- ':sunglasses:' => '😎',
448
- ':kiss:' => '😘',
449
- ':thinking:' => '🤔',
450
- ':shocked:' => '😲',
451
- ':shhh:' => '🤫',
452
- ':nerd:' => '🤓',
453
- ':cool:' => '😎',
454
- ':scream:' => '😱',
455
- ':zzz:' => '💤',
456
- ':celebrate:' => '🎉',
457
- ':ok_hand:' => '👌',
458
- ':pray:' => '🙏',
459
- ':muscle:' => '💪',
460
- ':tada:' => '🎉',
461
- ':eyes:' => '👀',
462
- ':star:' => '⭐',
463
- ':bulb:' => '💡',
464
- ':chicken:' => '🐔',
465
- ':cow:' => '🐮',
466
- ':dog:' => '🐶',
467
- ':cat:' => '🐱',
468
- ':fox:' => '🦊',
469
- ':lion:' => '🦁',
470
- ':penguin:' => '🐧',
471
- ':pig:' => '🐷',
472
- ':rabbit:' => '🐰',
473
- ':tiger:' => '🐯',
474
- ':unicorn:' => '🦄',
475
- ':bear:' => '🐻',
476
- ':elephant:' => '🐘',
477
- ':monkey:' => '🐒',
478
- ':panda:' => '🐼',
479
- ];
480
-
481
- return strtr($content, $emojiMap);
482
- }
483
-
484
- /**
485
- * Validate a value against a set of rules.
486
- *
487
- * @param mixed $value The value to validate.
488
- * @param string $rules A pipe-separated string of rules (e.g., 'required|min:2|max:50').
489
- * @param mixed $confirmationValue The value to confirm against, if applicable.
490
- * @return bool|string|null True if validation passes, string with error message if fails, or null for optional field.
491
- */
492
- public static function withRules($value, string $rules, $confirmationValue = null)
493
- {
494
- $rulesArray = explode('|', $rules);
495
- foreach ($rulesArray as $rule) {
496
- // Handle parameters in rules, e.g., 'min:10'
497
- if (strpos($rule, ':') !== false) {
498
- [$ruleName, $parameter] = explode(':', $rule);
499
- $result = self::applyRule($ruleName, $parameter, $value, $confirmationValue);
500
- } else {
501
- $result = self::applyRule($rule, null, $value, $confirmationValue);
502
- }
503
-
504
- // If a validation rule fails, return the error message
505
- if ($result !== true) {
506
- return $result;
507
- }
508
- }
509
- return true;
510
- }
511
-
512
- /**
513
- * Apply an individual rule to a value.
514
- *
515
- * @param string $rule The rule to apply.
516
- * @param mixed $parameter The parameter for the rule, if applicable.
517
- * @param mixed $value The value to validate.
518
- * @return bool|string True if the rule passes, or a string with an error message if it fails.
519
- */
520
- private static function applyRule(string $rule, $parameter, $value, $confirmationValue = null)
521
- {
522
- switch ($rule) {
523
- case 'required':
524
- if (empty($value) && $value !== '0') {
525
- return "This field is required.";
526
- } else {
527
- return true;
528
- }
529
- break;
530
- case 'min':
531
- if (strlen($value) < (int)$parameter) {
532
- return "This field must be at least $parameter characters long.";
533
- } else {
534
- return true;
535
- }
536
- break;
537
- case 'max':
538
- if (strlen($value) > (int)$parameter) {
539
- return "This field must not exceed $parameter characters.";
540
- } else {
541
- return true;
542
- }
543
- break;
544
- case 'startsWith':
545
- if (strpos($value, $parameter) !== 0) {
546
- return "This field must start with $parameter.";
547
- } else {
548
- return true;
549
- }
550
- break;
551
- case 'endsWith':
552
- if (substr($value, -strlen($parameter)) !== $parameter) {
553
- return "This field must end with $parameter.";
554
- } else {
555
- return true;
556
- }
557
- break;
558
- case 'confirmed':
559
- if ($confirmationValue !== $value) {
560
- return "The $rule confirmation does not match.";
561
- } else {
562
- return true;
563
- }
564
- break;
565
- case 'email':
566
- return self::email($value) ? true : "This field must be a valid email address.";
567
- case 'url':
568
- return self::url($value) ? true : "This field must be a valid URL.";
569
- case 'ip':
570
- return self::ip($value) ? true : "This field must be a valid IP address.";
571
- case 'uuid':
572
- return self::uuid($value) ? true : "This field must be a valid UUID.";
573
- case 'ulid':
574
- return self::ulid($value) ? true : "This field must be a valid ULID.";
575
- case 'cuid':
576
- return self::cuid($value) ? true : "This field must be a valid CUID.";
577
- case 'int':
578
- return self::int($value) !== null ? true : "This field must be an integer.";
579
- case 'float':
580
- return self::float($value) !== null ? true : "This field must be a float.";
581
- case 'boolean':
582
- return self::boolean($value) !== null ? true : "This field must be a boolean.";
583
- case 'in':
584
- if (!in_array($value, explode(',', $parameter), true)) {
585
- return "The selected value is invalid.";
586
- } else {
587
- return true;
588
- }
589
- break;
590
- case 'notIn':
591
- if (in_array($value, explode(',', $parameter), true)) {
592
- return "The selected value is invalid.";
593
- } else {
594
- return true;
595
- }
596
- break;
597
- case 'size':
598
- if (strlen($value) !== (int)$parameter) {
599
- return "This field must be exactly $parameter characters long.";
600
- } else {
601
- return true;
602
- }
603
- break;
604
- case 'between':
605
- [$min, $max] = explode(',', $parameter);
606
- if (strlen($value) < (int)$min || strlen($value) > (int)$max) {
607
- return "This field must be between $min and $max characters long.";
608
- } else {
609
- return true;
610
- }
611
- break;
612
- case 'date':
613
- return self::date($value, $parameter ?: 'Y-m-d') ? true : "This field must be a valid date.";
614
- case 'dateFormat':
615
- if (!DateTime::createFromFormat($parameter, $value)) {
616
- return "This field must match the format $parameter.";
617
- } else {
618
- return true;
619
- }
620
- break;
621
- case 'before':
622
- if (strtotime($value) >= strtotime($parameter)) {
623
- return "This field must be a date before $parameter.";
624
- } else {
625
- return true;
626
- }
627
- break;
628
- case 'after':
629
- if (strtotime($value) <= strtotime($parameter)) {
630
- return "This field must be a date after $parameter.";
631
- } else {
632
- return true;
633
- }
634
- break;
635
- case 'json':
636
- return self::json($value) ? true : "This field must be a valid JSON string.";
637
- break;
638
- case 'timezone':
639
- if (!in_array($value, timezone_identifiers_list())) {
640
- return "This field must be a valid timezone.";
641
- } else {
642
- return true;
643
- }
644
- break;
645
- case 'regex':
646
- if (!preg_match($parameter, $value)) {
647
- return "This field format is invalid.";
648
- } else {
649
- return true;
650
- }
651
- break;
652
- case 'digits':
653
- if (!ctype_digit($value) || strlen($value) != $parameter) {
654
- return "This field must be $parameter digits.";
655
- } else {
656
- return true;
657
- }
658
- break;
659
- case 'digitsBetween':
660
- [$min, $max] = explode(',', $parameter);
661
- if (!ctype_digit($value) || strlen($value) < (int)$min || strlen($value) > (int)$max) {
662
- return "This field must be between $min and $max digits.";
663
- } else {
664
- return true;
665
- }
666
- break;
667
- case 'extensions':
668
- $extensions = explode(',', $parameter);
669
- if (!self::isExtensionAllowed($value, $extensions)) {
670
- return "The file must have one of the following extensions: " . implode(', ', $extensions) . ".";
671
- } else {
672
- return true;
673
- }
674
- break;
675
- case 'mimes':
676
- $mimeTypes = explode(',', $parameter);
677
- if (!self::isMimeTypeAllowed($value, $mimeTypes)) {
678
- return "The file must be of type: " . implode(', ', $mimeTypes) . ".";
679
- } else {
680
- return true;
681
- }
682
- break;
683
- case 'file':
684
- if (!is_uploaded_file($value)) {
685
- return "This field must be a valid file.";
686
- } else {
687
- return true;
688
- }
689
- break;
690
- // Add additional rules as needed...
691
- default:
692
- return true;
693
- }
694
- }
695
-
696
- /**
697
- * Check if a file's extension is in the list of allowed extensions.
698
- *
699
- * @param string $file The path or filename of the file.
700
- * @param array $allowedExtensions The list of allowed extensions.
701
- * @return bool True if the extension is allowed, false otherwise.
702
- */
703
- private static function isExtensionAllowed($file, array $allowedExtensions): bool
704
- {
705
- // Extract the file extension
706
- $fileExtension = pathinfo($file, PATHINFO_EXTENSION);
707
-
708
- // Check if the extension is in the allowed list
709
- return in_array(strtolower($fileExtension), array_map('strtolower', $allowedExtensions), true);
710
- }
711
-
712
- /**
713
- * Check if a file's MIME type is in the list of allowed MIME types.
714
- *
715
- * @param string $file The path or filename of the file.
716
- * @param array $allowedMimeTypes The list of allowed MIME types.
717
- * @return bool True if the MIME type is allowed, false otherwise.
718
- */
719
- private static function isMimeTypeAllowed($file, array $allowedMimeTypes)
720
- {
721
- // Check if the file is a valid uploaded file
722
- if (!is_uploaded_file($file)) {
723
- return false;
724
- }
725
-
726
- // Get the MIME type of the file using PHP's finfo_file function
727
- $finfo = finfo_open(FILEINFO_MIME_TYPE);
728
- $mimeType = finfo_file($finfo, $file);
729
- finfo_close($finfo);
730
-
731
- // Check if the MIME type is in the list of allowed MIME types
732
- if (in_array($mimeType, $allowedMimeTypes, true)) {
733
- return true;
734
- }
735
-
736
- return false;
737
- }
738
- }