Completed
Push — master ( ec6ab3...598217 )
by Lorenzo
03:27
created

validation.php ➔ isIntBool()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 2
nc 4
nop 1
dl 0
loc 4
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Check if a string number starts with one ore more zero
5
 * i.e.: 00...000 or 000...0Xxxx.x  with X an int
6
 * @param $value
7
 * @return bool
8
 */
9
function isStringNumberStartsWithMoreThanOneZero($value)
10
{
11
    return preg_match('/^[0]{2,}$/', $value) === 1 || preg_match('/^0{1,}[1-9]{1,}$/', $value) === 1;
12
}
13
14
/**
15
 * Check if the value (int, float or string) is a integer and greater than zero..
16
 * Only number >0 and <=PHP_INT_MAX
17
 * or if $acceptIntegerFloatingPoints==true a floating point that match an positive integer).
18
 * @param $value
19
 * @param bool $acceptIntegerFloatingPoints
20
 * @return bool
21
 */
22
function isIntegerPositive($value, $acceptIntegerFloatingPoints = false): bool
23
{
24
    return isInteger($value, true, $acceptIntegerFloatingPoints) && $value > 0;
25
}
26
27
/**
28
 * Check if the value (int, float or string) is a integer and less than zero..
29
 * Only number <0 and >=PHP_INT_MIN
30
 * or if $acceptIntegerFloatingPoints==true a floating point that match an negative integer).
31
 * @param $value
32
 * @param bool $acceptIntegerFloatingPoints
33
 * @return bool
34
 */
35
function isIntegerNegative($value, $acceptIntegerFloatingPoints = false): bool
36
{
37
    return isInteger($value, false, $acceptIntegerFloatingPoints) && $value < 0;
38
}
39
40
/**
41
 * Check if the value (int, float or string) is a integer and greater than zero or equals to zero.
42
 * Only number >=0 and <=PHP_INT_MAX
43
 * or if $acceptIntegerFloatingPoints==true a floating point that match an positive integer).
44
 * @param $value
45
 * @param bool $acceptIntegerFloatingPoints
46
 * @return bool
47
 */
48
function isIntegerPositiveOrZero($value, $acceptIntegerFloatingPoints = false): bool
49
{
50
    return isInteger($value, true, $acceptIntegerFloatingPoints) && $value >= 0;
51
}
52
53
/**
54
 * Check if the value (int, float or string) is a integer and less than zero or equals to zero.
55
 * Only number <=0 and >=PHP_INT_MIN
56
 * or if $acceptIntegerFloatingPoints==true a floating point that match an negative integer).
57
 * @param $value
58
 * @param bool $acceptIntegerFloatingPoints
59
 * @return bool
60
 */
61
function isIntegerNegativeOrZero($value, $acceptIntegerFloatingPoints = false): bool
62
{
63
    return isInteger($value, false, $acceptIntegerFloatingPoints) && $value <= 0;
64
}
65
66
/**
67
 * Check if the value (int, float or string) is a integer and equals to zero.
68
 * If $acceptIntegerFloatingPoints==true a floating point that match an zero integer).
69
 * @param $value
70
 * @param bool $acceptIntegerFloatingPoints default false
71
 * @param bool $acceptSign default false if set to true accept -0 and +0 otherwise accept 0.
72
 * @return bool
73
 */
74
function isIntegerZero($value, $acceptIntegerFloatingPoints = false, $acceptSign = false): bool
75
{
76
    if(isNullOrEmpty($value)){
77
        return false;
78
    }
79
    if(!$acceptSign){
80
        return $value == 0 && isNumericWithoutSign($value) && !isStringNumberStartsWithMoreThanOneZero($value);
81
    }else{
82
        return abs($value) == 0 && isInteger(abs($value), !$acceptSign, $acceptIntegerFloatingPoints);
83
    }
84
}
85
86
/**
87
 * Check if the value (int, float or string) is a integer.
88
 * Only number <=PHP_INT_MAX (and >=PHP_INT_MIN if unsigned=true)
89
 * or if $acceptIntegerFloatingPoints==true a floating point that match an integer).
90
 * @param $value
91
 * @param bool $unsigned
92
 * @param bool $acceptIntegerFloatingPoints
93
 * @return bool
94
 */
95
function isInteger($value, $unsigned = true, $acceptIntegerFloatingPoints = false): bool
96
{
97
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
98
        return false;
99
    }
100
101
    //accept only integer number and if $acceptIntegerFloatingPoints is true accept integer floating point too.
102
    return ((preg_match('/^' . ($unsigned ? '' : '-{0,1}') . '[0-9]{1,}$/', $value) === 1
103
            && ($value <= PHP_INT_MAX && $value >= PHP_INT_MIN && (((int)$value) == $value))
104
        )
105
        || ($acceptIntegerFloatingPoints && isIntegerFloatingPoint($value, $unsigned)));
106
}
107
108
/**
109
 * Check if string is a valid floating point that
110
 * match an integer (<=PHP_INT_MAX and >=PHP_INT_MIN if unsigned=true)
111
 * or is an integer
112
 * Ex.: 1, 1e2, 1E2, 1e+2, 1e-2, 1.4e+2, -1.2e+2, -1.231e-2 etc...
113
 * @param $value
114
 * @param bool $unsigned
115
 * @return bool
116
 */
117
function isIntegerFloatingPoint($value, $unsigned = true): bool
118
{
119
    return isFloatingPoint($value, $unsigned)
120
        && $value <= PHP_INT_MAX && $value >= PHP_INT_MIN
121
        //big number rouned to int aproximately!
122
        //big number change into exp format
123
        && ((int)((double)$value) == $value || (int)$value == $value || strpos(strtoupper((string)$value),
124
                'E') === false);
125
}
126
127
/**
128
 * Check if string is a valid floating point.
129
 * Ex.: [+-]1, [+-]1e2, [+-]1E2, [+-]1e+2, [+-]1e-2, [+-]1.43234e+2, -1.231e+2, -1.231e-2 etc...
130
 * @param $value
131
 * @param $unsigned
132
 * @return bool
133
 */
134
function isFloatingPoint($value, $unsigned): bool
135
{
136
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
137
        return false;
138
    }
139
140
    return preg_match('/^' . ($unsigned ? '[+]{0,1}' : '[-+]{0,1}') . '[0-9]{1,}(\.[0-9]{1,}){0,1}([Ee][+,-]{0,1}[0-9]{1,}){0,}$/',
141
            $value) === 1;
142
}
143
144
/**
145
 * Check if the value is a integer/string 0 or 1.
146
 * @param $value
147
 * @return bool
148
 */
149
function isIntBool($value): bool
150
{
151
    return $value === 1 || $value === 0 || $value === '1' || $value === '0';
152
}
153
154
/**
155
 * Check if the value are a double (integer or float in the form 1, 1.11...1.
156
 * @param $value
157
 * @param int $dec
158
 * @param bool $unsigned
159
 * @param bool $exactDec if set to true aspect number of dec exact to $dec,
160
 * otherwise $dec is max decimals accepted (0 decimals are also ok in this case).
161
 * if $dec is an empty string, accept 0 to infinite decimals.
162
 * @return bool
163
 */
164
function isDouble($value, $dec = 2, $unsigned = true, $exactDec = false): bool
165
{
166
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
167
        return false;
168
    }
169
    $regEx = '/^' . ($unsigned ? '' : '-{0,1}') . '[0-9]{1,}(\.{1}[0-9]{' . ($exactDec ? '' : '1,') . $dec . '})' . ($exactDec ? '{1}' : '{0,1}') . '$/';
170
    return preg_match($regEx, $value) === 1;
171
}
172
173
/**
174
 * Check if a string is a percent 0%-100%
175
 * @param $value
176
 * @param bool $withDecimal if set to true accept decimal values.
177
 * @param bool $withPercentChar if set to true require % char, otherwise if find a % char return false.
178
 * @return bool
179
 */
180
function isPercent($value, bool $withDecimal = true, bool $withPercentChar = false): bool
181
{
182
    if (isNullOrEmpty($value)) {
183
        return false;
184
    }
185
    $contains_perc = str_contains($value, '%');
186
    if (($withPercentChar && !$contains_perc)
187
        || (!$withPercentChar && $contains_perc)
188
        || (substr_count($value, '%') > 1) //only one %
189
    ) {
190
        return false;
191
    }
192
    $value = trim(str_replace('%', '', $value));
193
194
    return $withDecimal ? isDouble($value, '', true) : isInteger($value, true);
195
}
196
197
/**
198
 * @param float $value
199
 * @param float $leftRange
200
 * @param float $rightRange
201
 * @return bool
202
 */
203
function isInRange(float $value, float $leftRange = 0.00, float $rightRange = 0.00): bool
204
{
205
    return ($value <= $rightRange && $value >= $leftRange);
206
}
207
208
/**
209
 * Check if string is dd/mm/YYYY
210
 * @param $value
211
 * @return bool
212
 */
213 View Code Duplication
function isDateIta($value): bool
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
214
{
215
    if (isNullOrEmpty($value) || strlen($value) != 10 || strpos($value, '/') === false) {
216
        return false;
217
    }
218
    list($dd, $mm, $yyyy) = explode('/', $value);
219
    try {
220
        return checkdate($mm, $dd, $yyyy);
221
    } catch (Exception $e) {
222
        return false;
223
    }
224
}
225
226
/**
227
 * Check if string is 0000-00-00
228
 * @param $value
229
 * @return bool
230
 */
231
function isDateZeroIso($value): bool
232
{
233
    return $value == '0000-00-00';
234
}
235
236
/**
237
 * Check if string is 00:00:00
238
 * @param $value
239
 * @return bool
240
 */
241
function isTimeZeroIso($value): bool
242
{
243
    return $value == '00:00:00';
244
}
245
246
/**
247
 * Check if string is '0000-00-00 00:00:00'
248
 * @param $value
249
 * @return bool
250
 */
251
function isDateTimeZeroIso($value): bool
252
{
253
    return $value == '0000-00-00 00:00:00';
254
}
255
256
/**
257
 * Check if string is YYYY-mm-dd and valid date or 0000-00-00
258
 * @param $value
259
 * @return bool
260
 */
261
function isDateOrDateZeroIso($value): bool
262
{
263
    return isDateIso($value) || isDateZeroIso($value);
264
}
265
266
/**
267
 * Check if string is 'YYYY-mm-dd HH:ii:ss' and valid date or '0000-00-00 00:00:00'
268
 * @param $value
269
 * @return bool
270
 */
271
function isDateTimeOrDateTimeZeroIso($value): bool
272
{
273
    return isDateTimeIso($value) || isDateTimeZeroIso($value);
274
}
275
276
277
/**
278
 * Check if string is 00/00/0000
279
 * @param $value
280
 * @return bool
281
 */
282
function isDateZeroIta($value): bool
283
{
284
    return $value == '00/00/0000';
285
}
286
287
/**
288
 * Check if string is 00:00:00
289
 * @param $value
290
 * @return bool
291
 */
292
function isTimeZeroIta($value): bool
293
{
294
    return $value == '00:00:00';
295
}
296
297
/**
298
 * Check if string is '00/00/0000 00:00:00'
299
 * @param $value
300
 * @return bool
301
 */
302
function isDateTimeZeroIta($value): bool
303
{
304
    return $value == '00/00/0000 00:00:00';
305
}
306
307
/**
308
 * Check if string is dd/mm/YYYY and valid date or 00/00/0000
309
 * @param $value
310
 * @return bool
311
 */
312
function isDateOrDateZeroIta($value): bool
313
{
314
    return isDateIta($value) || isDateZeroIta($value);
315
}
316
317
/**
318
 * Check if string is 'dd/mm/YYYY HH:ii:ss' and valid date or '00/00/0000 00:00:00'
319
 * @param $value
320
 * @return bool
321
 */
322
function isDateTimeOrDateTimeZeroIta($value): bool
323
{
324
    return isDateTimeIta($value) || isDateTimeZeroIta($value);
325
}
326
327
/**
328
 * Check if string is YYYY-mm-dd
329
 * @param $value
330
 * @return bool
331
 */
332 View Code Duplication
function isDateIso($value): bool
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
333
{
334
    if (isNullOrEmpty($value) || strlen($value) != 10 || strpos($value, '-') === false) {
335
        return false;
336
    }
337
    list($yyyy, $mm, $dd) = explode('-', $value);
338
    try {
339
        return checkdate($mm, $dd, $yyyy);
340
    } catch (Exception $e) {
341
        return false;
342
    }
343
}
344
345
/**
346
 * Check if string is YYYY-mm-dd HH:ii:ss
347
 * @param $value
348
 * @return bool
349
 */
350
function isDateTimeIso($value): bool
351
{
352
    if (!isDateIso(substr($value, 0, 10))) {
353
        return false;
354
    }
355
    return isTimeIso(substr($value, 11));
356
}
357
358
/**
359
 * Check if string is dd/mm/YYYY HH:ii:ss
360
 * @param $value
361
 * @return bool
362
 */
363
function isDateTimeIta($value): bool
364
{
365
    if (!isDateIta(substr($value, 0, 10))) {
366
        return false;
367
    }
368
    return isTimeIso(substr($value, 11));
369
}
370
371
/**
372
 * Check if string is HH:ii:ss
373
 * @param $value
374
 * @return bool
375
 */
376
function isTimeIso($value): bool
377
{
378
    $strRegExp = '/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/';
379
    if (!(preg_match($strRegExp, $value) === 1)) {
380
        return false;
381
    }
382
    list($HH, $ii, $ss) = explode(':', $value);
383
    return isInRange((int)$HH, 0, 23) && isInRange((int)$ii, 0, 59) && isInRange((int)$ss, 0, 59);
384
}
385
386
/**
387
 * An alias of isTimeIso.
388
 * @param $value
389
 * @return bool
390
 */
391
function isTimeIta($value)
392
{
393
    return isTimeIso($value);
394
}
395
396
/**
397
 * Check if year ia a leap year in jewish calendar.
398
 * @param int $year
399
 * @return bool
400
 */
401
function isJewishLeapYear(int $year): bool
402
{
403
    if ($year % 19 == 0 || $year % 19 == 3 || $year % 19 == 6 ||
404
        $year % 19 == 8 || $year % 19 == 11 || $year % 19 == 14 ||
405
        $year % 19 == 17
406
    ) {
407
        return true;
408
    } else {
409
        return false;
410
    }
411
}
412
413
/**
414
 * Check if a number is a valid month.
415
 * More params you passed (year, calendar), more accurate is the check.
416
 * If passed a not valid year return false.
417
 * @param int $value
418
 * @param int $year
419
 * @param int $calendar
420
 * @return bool
421
 */
422
function isMonth(int $value, int $year, int $calendar = CAL_GREGORIAN): bool
423
{
424
    if (!isInRange($year, 0, PHP_INT_MAX)) {
425
        return false;
426
    }
427
428
    $maxMonths = 12;
429
430
    if ($calendar == 3
431
        || ($year > 0 && $calendar == 2 && isJewishLeapYear($year))
432
    ) {
433
        $maxMonths = 13;
434
    }
435
436
    return isInRange($value, 1, $maxMonths);
437
}
438
439
/**
440
 * Check if a number is a valid day.
441
 * More params you passed (month, year, calendar), more accurate is the check.
442
 * If passed a not valid year or month return false.
443
 * @param int $value
444
 * @param int $month
445
 * @param int $year
446
 * @param int $calendar
447
 * @return bool
448
 */
449
function isDay(int $value, int $month = 0, int $year = 0, int $calendar = CAL_GREGORIAN): bool
450
{
451
    if ($month != 0 && !isMonth($month, $year, $calendar)) {
452
        return false;
453
    }
454
    if (!isInRange($year, 0, PHP_INT_MAX)) {
455
        return false;
456
    }
457
458
    $maxDays = 31;
459
460
    if ($year > 0 && $month > 0) {
461
        $maxDays = cal_days_in_month($calendar, $month, $year);
462
    } elseif (in_array($month, [11, 4, 6, 9])) {
463
        $maxDays = 30;
464
    } elseif ($month == 2) {
465
        $maxDays = 28;
466
    }
467
468
    return isInRange($value, 1, $maxDays);
469
}
470
471
/**
472
 * Determine if the provided input meets age requirement (ISO 8601).
473
 *
474
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
475
 * @param int $age
476
 *
477
 * @return bool
478
 */
479
function hasMinAge($dateOfBirthday, int $age): bool
480
{
481
    return date_diff(date('Y-m-d'), $dateOfBirthday) >= $age;
482
}
483
484
/**
485
 * Determine if the provided input meets age requirement (ISO 8601).
486
 *
487
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
488
 * @param int $age
489
 *
490
 * @return bool
491
 */
492
function hasMaxAge($dateOfBirthday, int $age): bool
493
{
494
    return date_diff(date('Y-m-d'), $dateOfBirthday) <= $age;
495
}
496
497
/**
498
 * Determine if the provided input meets age requirement (ISO 8601).
499
 *
500
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
501
 * @param int $ageMin
502
 * @param int $ageMax
503
 *
504
 * @return bool
505
 */
506
function hasAgeInRange($dateOfBirthday, int $ageMin, int $ageMax): bool
507
{
508
    return hasMinAge($dateOfBirthday, $ageMin) && hasMaxAge($dateOfBirthday, $ageMax);
509
}
510
511
/**
512
 * Check if a date in iso format is in range
513
 * @param string $date iso format
514
 * @param string $minDate iso format
515
 * @param string $maxDate iso format
516
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
517
 * @return bool
518
 */
519
function betweenDateIso(string $date, string $minDate, string $maxDate, bool $strict = false): bool
520
{
521
    if (!isDateIso($date) || !isDateIso($minDate) || !isDateIso($maxDate)) {
522
        return false;
523
    }
524
525
    if (!$strict) {
526
        return ($date >= $minDate) && ($date <= $maxDate);
527
    }
528
    return ($date > $minDate) && ($date < $maxDate);
529
}
530
531
/**
532
 * Check if a date in ita format is in range
533
 * @param string $date ita format
534
 * @param string $minDate ita format
535
 * @param string $maxDate ita format
536
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
537
 * @return bool
538
 */
539
function betweenDateIta(string $date, string $minDate, string $maxDate, bool $strict = false): bool
540
{
541
    if (!isDateIta($date) || !isDateIta($minDate) || !isDateIta($maxDate)) {
542
        return false;
543
    }
544
545
    $date = dateItaToIso($date);
546
    $minDate = dateItaToIso($minDate);
547
    $maxDate = dateItaToIso($maxDate);
548
549
    return betweenDateIso($date, $minDate, $maxDate, $strict);
550
}
551
552
/**
553
 * @param $value
554
 * @param $checkMx
555
 * @return bool
556
 */
557
function isMail($value, bool $checkMx = false): bool
558
{
559
    if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
560
        return false;
561
    }
562
    if ($checkMx) {
563
        list(, $mailDomain) = explode('@', $value);
564
        if (!checkdnsrr($mailDomain, 'MX')) {
565
            return false;
566
        }
567
    }
568
    return true;
569
}
570
571
/**
572
 * isIPv4 check if a string is a valid IP v4
573
 * @param  string $IP2Check IP to check
574
 * @return bool
575
 */
576
function isIPv4($IP2Check): bool
577
{
578
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false);
579
}
580
581
/**
582
 * isIPv6 check if a string is a valid IP v6
583
 * @param  string $IP2Check IP to check
584
 * @return bool
585
 */
586
function isIPv6($IP2Check): bool
587
{
588
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false);
589
}
590
591
/**
592
 * Check if a string is a valid IP (v4 or v6).
593
 * @param  string $IP2Check IP to check
594
 * @return bool
595
 */
596
function isIP($IP2Check): bool
597
{
598
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP) === false);
599
}
600
601
/**
602
 * Check if a string is a valid IP v4 compatibility (ffff:ffff:ffff:ffff.192.168.0.15).
603
 * @param  string $IP2Check IP to check
604
 * @return bool
605
 */
606
function isIPv4Compatibility($IP2Check): bool
607
{
608
    return (strrpos($IP2Check, ":") > 0
609
        && strrpos($IP2Check, ".") > 0
610
        && isIPv4(substr($IP2Check, strpos($IP2Check, ".") + 1))
611
        && isIPv6(substr($IP2Check, 0, strpos($IP2Check, ".")) . ':0:0:0:0')
612
    );
613
}
614
615
/**
616
 * Check if a string has a URL address syntax is valid.
617
 * It require scheme to be valide (http|https|ftp|mailto|file|data)
618
 * i.e.: http://dummy.com and http://www.dummy.com is valid but www.dummy.and dummy.com return false.
619
 * @param $url
620
 * @return bool
621
 */
622
function isUrl($url): bool
623
{
624
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
625
}
626
627
/**
628
 * Check if a string is valid hostname
629
 * (dummy.com, www.dummy.com, , www.dummy.co.uk, , www.dummy-dummy.com, etc..).
630
 * @param $value
631
 * @return bool
632
 */
633
function isHostname($value): bool
634
{
635
    return preg_match('/(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/i', $value) === 1;
636
}
637
638
/**
639
 * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt
640
 *
641
 * The regex checks for the following component parts:
642
 *
643
 * - a valid, optional, scheme
644
 * - a valid ip address OR
645
 *   a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt
646
 *   with an optional port number
647
 * - an optional valid path
648
 * - an optional query string (get parameters)
649
 * - an optional fragment (anchor tag)
650
 *
651
 * @param string $check Value to check
652
 * @param bool $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher)
653
 * @return bool Success
654
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php#L839
655
 */
656
function urlW3c($check, bool $strict = false): bool
657
{
658
    $_pattern = array();
659
    $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
660
    $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
661
    $pattern .= '|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})';
662
    $pattern .= '(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)';
663
    $pattern .= '{4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
664
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}';
665
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
666
    $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
667
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
668
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
669
    $pattern .= '{0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)';
670
    $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
671
    $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
672
    $pattern .= '{1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?';
673
    $_pattern['IPv6'] = $pattern;
674
675
    $pattern = '(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])';
676
    $_pattern['IPv4'] = $pattern;
677
678
    $_pattern = ['hostname' => '(?:[_\p{L}0-9][-_\p{L}0-9]*\.)*(?:[\p{L}0-9][-\p{L}0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})'];
679
680
    $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9\p{L}\p{N}]|(%[0-9a-f]{2}))';
681
    $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . ($strict ? '' : '?') .
682
        '(?:' . $_pattern['IPv4'] . '|\[' . $_pattern['IPv6'] . '\]|' . $_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' .
683
        '(?:\/?|\/' . $validChars . '*)?' .
684
        '(?:\?' . $validChars . '*)?' .
685
        '(?:#' . $validChars . '*)?$/iu';
686
    return preg_match($regex, $check) === 1;
687
}
688
689
/**
690
 * Controlla partita IVA Italiana.
691
 * @author Umberto Salsi <[email protected]>
692
 * @author Lorenzo Padovani modified.
693
 * @version 2012-05-12
694
 * @param string $pi Partita IVA Italiana è costituita da 11 cifre. Non sono ammessi
695
 * caratteri di spazio, per cui i campi di input dell'utente dovrebbero
696
 * essere trimmati preventivamente. La stringa vuota e' ammessa, cioe'
697
 * il dato viene considerato opzionale.
698
 * @param bool $validateOnVIES default false. if se to true, first check algorithm then if it valid,
699
 * try to check VIES service. If VIES return false or soap exception was thrown, return false.
700
 * @return bool
701
 */
702
function isPiva(string $pi, bool $validateOnVIES = false): bool
703
{
704
    if ($pi === null || $pi === '' || strlen($pi) != 11 || preg_match("/^[0-9]+\$/", $pi) != 1) {
705
        return false;
706
    }
707
    $s = 0;
708
    for ($i = 0; $i <= 9; $i += 2) {
709
        $s += ord($pi[$i]) - ord('0');
710
    }
711
    for ($i = 1; $i <= 9; $i += 2) {
712
        $c = 2 * (ord($pi[$i]) - ord('0'));
713
        if ($c > 9) {
714
            $c -= 9;
715
        }
716
        $s += $c;
717
    }
718
    if ((10 - $s % 10) % 10 != ord($pi[10]) - ord('0')) {
719
        return false;
720
    }
721
    if (!$validateOnVIES) {
722
        return true;
723
    }
724
    //check vies
725
    try {
726
        return isVATNumber($pi);
727
    } catch (SoapFault $e) {
728
        return false;
729
    }
730
}
731
732
/**
733
 * Validate a European VAT number using the EU commission VIES service.
734
 * If not $vatNumber starts with country code, a default $countryCodeDefault applied.
735
 * @param string $vatNumber
736
 * @param string $countryCodeDefault default 'IT'
737
 * @return bool
738
 * @throws SoapFault
739
 */
740
function isVATNumber(string $vatNumber, string $countryCodeDefault = 'IT'): bool
741
{
742
    if (!isAlphaNumericWhiteSpaces($vatNumber) || strlen(trim($vatNumber)) < 3) {
743
        return false;
744
    }
745
746
    $vatNumber = str_replace([' ', '-', '.', ','], '', strtoupper(trim($vatNumber)));
747
    $countryCode = strtoupper(substr($vatNumber, 0, 2));
748
749
    if (preg_match('/^[A-Za-z]{2}$/', $countryCode) === 1) {
750
        $vatNumber = substr($vatNumber, 2);
751
    } else {
752
        $countryCode = $countryCodeDefault != '' ? strtoupper($countryCodeDefault) : 'IT';
753
    }
754
    try {
755
        $serviceUrl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
756
        $client = new SoapClient($serviceUrl);
757
        $response = $client->checkVat([
758
            'countryCode' => $countryCode,
759
            'vatNumber' => $vatNumber,
760
        ]);
761
        return $response->valid;
762
    } catch (SoapFault $e) {
763
        throw $e;
764
    }
765
}
766
767
/**
768
 * Controlla codice fiscale.
769
 * @author Umberto Salsi <[email protected]>
770
 * @version 2012-05-12
771
 * @param string $cf Codice fiscale costituito da 16 caratteri. Non
772
 * sono ammessi caratteri di spazio, per cui i campi di input dell'utente
773
 * dovrebbero essere trimmati preventivamente. La stringa vuota e' ammessa,
774
 * cioe' il dato viene considerato opzionale.
775
 * @return bool
776
 */
777
function isCf(string $cf): bool
778
{
779
    if ($cf === null || $cf === '' || strlen($cf) != 16) {
780
        return false;
781
    }
782
    $cf = strtoupper($cf);
783
    if (preg_match("/^[A-Z0-9]+\$/", $cf) != 1) {
784
        return false;
785
    }
786
    $s = 0;
787
    for ($i = 1; $i <= 13; $i += 2) {
788
        $c = $cf[$i];
789
        if (strcmp($c, "0") >= 0 && strcmp($c, "9") <= 0) {
790
            $s += ord($c) - ord('0');
791
        } else {
792
            $s += ord($c) - ord('A');
793
        }
794
    }
795
    for ($i = 0; $i <= 14; $i += 2) {
796
        $c = $cf[$i];
797
        switch ($c) {
798
            case '0':
799
                $s += 1;
800
                break;
801
            case '1':
802
                $s += 0;
803
                break;
804
            case '2':
805
                $s += 5;
806
                break;
807
            case '3':
808
                $s += 7;
809
                break;
810
            case '4':
811
                $s += 9;
812
                break;
813
            case '5':
814
                $s += 13;
815
                break;
816
            case '6':
817
                $s += 15;
818
                break;
819
            case '7':
820
                $s += 17;
821
                break;
822
            case '8':
823
                $s += 19;
824
                break;
825
            case '9':
826
                $s += 21;
827
                break;
828
            case 'A':
829
                $s += 1;
830
                break;
831
            case 'B':
832
                $s += 0;
833
                break;
834
            case 'C':
835
                $s += 5;
836
                break;
837
            case 'D':
838
                $s += 7;
839
                break;
840
            case 'E':
841
                $s += 9;
842
                break;
843
            case 'F':
844
                $s += 13;
845
                break;
846
            case 'G':
847
                $s += 15;
848
                break;
849
            case 'H':
850
                $s += 17;
851
                break;
852
            case 'I':
853
                $s += 19;
854
                break;
855
            case 'J':
856
                $s += 21;
857
                break;
858
            case 'K':
859
                $s += 2;
860
                break;
861
            case 'L':
862
                $s += 4;
863
                break;
864
            case 'M':
865
                $s += 18;
866
                break;
867
            case 'N':
868
                $s += 20;
869
                break;
870
            case 'O':
871
                $s += 11;
872
                break;
873
            case 'P':
874
                $s += 3;
875
                break;
876
            case 'Q':
877
                $s += 6;
878
                break;
879
            case 'R':
880
                $s += 8;
881
                break;
882
            case 'S':
883
                $s += 12;
884
                break;
885
            case 'T':
886
                $s += 14;
887
                break;
888
            case 'U':
889
                $s += 16;
890
                break;
891
            case 'V':
892
                $s += 10;
893
                break;
894
            case 'W':
895
                $s += 22;
896
                break;
897
            case 'X':
898
                $s += 25;
899
                break;
900
            case 'Y':
901
                $s += 24;
902
                break;
903
            case 'Z':
904
                $s += 23;
905
                break;
906
            /*. missing_default: .*/
907
        }
908
    }
909
    return !(chr($s % 26 + ord('A')) != $cf[15]);
910
}
911
912
/**
913
 * Determine if the provided value contains only alpha characters.
914
 *
915
 * @param string $field
916
 *
917
 * @return mixed
918
 *
919
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
920
 */
921
function isAlpha(string $field): bool
922
{
923
    return isNotNullOrEmpty($field)
924
        && preg_match('/^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
925
}
926
927
/**
928
 * Determine if the provided value contains only alpha characters.
929
 *
930
 * @param string $field
931
 *
932
 * @return mixed
933
 *
934
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
935
 */
936
function isAlphaNumeric(string $field): bool
937
{
938
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
939
}
940
941
/**
942
 * Determine if the provided value contains only numeric characters with or without(default) sign.
943
 *
944
 * @param string $field
945
 * @param bool $acceptSign default false if true accept string that starts with +/- oterwise only [0-9] chars.
946
 *
947
 * @return mixed
948
 */
949
function isNumeric(string $field, bool $acceptSign = false): bool
950
{
951
    return preg_match('/^(' . ($acceptSign ? '[+-]{0,1}' : '') . '[0-9])+$/i', $field) === 1;
952
}
953
954
/**
955
 * Determine if the provided value contains only numeric characters with sign.
956
 *
957
 * @param string $field
958
 *
959
 * @return mixed
960
 */
961
function isNumericWithSign(string $field): bool
962
{
963
    return isNumeric($field, true);
964
}
965
966
/**
967
 * Determine if the provided value contains only numeric characters without sign.
968
 *
969
 * @param string $field
970
 *
971
 * @return mixed
972
 */
973
function isNumericWithoutSign(string $field): bool
974
{
975
    return isNumeric($field, false);
976
}
977
978
/**
979
 * Determine if the provided value contains only alpha characters with dashed and underscores.
980
 *
981
 * @param string $field
982
 *
983
 * @return mixed
984
 */
985
function isAlphaNumericDash($field): bool
986
{
987
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_])+$/i', $field) === 1;
988
}
989
990
/**
991
 * Determine if the provided value contains only alpha numeric characters with spaces.
992
 *
993
 * @param string $field
994
 *
995
 * @return mixed
996
 */
997
function isAlphaNumericWhiteSpaces($field): bool
998
{
999
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_\s])+$/i', $field) === 1;
1000
}
1001
1002
/**
1003
 * Determine if the provided value is a boolean.
1004
 *
1005
 * @param string $field
1006
 *
1007
 * @return mixed
1008
 */
1009
function isBool($field): bool
1010
{
1011
    return $field === true || $field === false;
1012
}
1013
1014
/**
1015
 * Determine if the provided value is a boolean or 1,0,'1','0'.
1016
 *
1017
 * @param string $field
1018
 *
1019
 * @return bool
1020
 */
1021
function isBoolOrIntBool($field): bool
1022
{
1023
    return in_array($field, [0, 1, '0', '1', true, false], true);
1024
}
1025
1026
/**
1027
 * Determine if the input is a valid credit card number.
1028
 *
1029
 * See: http://stackoverflow.com/questions/174730/what-is-the-best-way-to-validate-a-credit-card-in-php
1030
 *
1031
 * @param string $field
1032
 *
1033
 * @return mixed
1034
 */
1035
function isCrediCard(string $field): bool
1036
{
1037
    if (isNullOrEmpty($field)) {
1038
        return false;
1039
    }
1040
    $number = preg_replace('/\D/', '', $field);
1041
    if (function_exists('mb_strlen')) {
1042
        $number_length = mb_strlen($number);
1043
    } else {
1044
        $number_length = strlen($number);
1045
    }
1046
    $parity = $number_length % 2;
1047
    $total = 0;
1048
    for ($i = 0; $i < $number_length; ++$i) {
1049
        $digit = $number[$i];
1050
        if ($i % 2 == $parity) {
1051
            $digit *= 2;
1052
            if ($digit > 9) {
1053
                $digit -= 9;
1054
            }
1055
        }
1056
        $total += $digit;
1057
    }
1058
    return ($total % 10 == 0);
1059
}
1060
1061
/**
1062
 * Determine if the input is a valid human name.
1063
 *
1064
 * @param string $field
1065
 *
1066
 * @return mixed
1067
 *
1068
 * @See: https://github.com/Wixel/GUMP/issues/5
1069
 */
1070
function isValidHumanName(string $field): bool
1071
{
1072
    if (isNullOrEmpty($field)) {
1073
        return false;
1074
    }
1075
    return isAlpha($field) && preg_match("/^([ '-])+$/", $field) === 1;
1076
}
1077
1078
/**
1079
 * Determine if the provided value is a valid IBAN.
1080
 *
1081
 * @param string $field
1082
 *
1083
 * @return bool
1084
 *
1085
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1086
 */
1087
function isIban($field): bool
1088
{
1089
    if (isNullOrEmpty($field)) {
1090
        return false;
1091
    }
1092
    static $character = array(
1093
        'A' => 10,
1094
        'C' => 12,
1095
        'D' => 13,
1096
        'E' => 14,
1097
        'F' => 15,
1098
        'G' => 16,
1099
        'H' => 17,
1100
        'I' => 18,
1101
        'J' => 19,
1102
        'K' => 20,
1103
        'L' => 21,
1104
        'M' => 22,
1105
        'N' => 23,
1106
        'O' => 24,
1107
        'P' => 25,
1108
        'Q' => 26,
1109
        'R' => 27,
1110
        'S' => 28,
1111
        'T' => 29,
1112
        'U' => 30,
1113
        'V' => 31,
1114
        'W' => 32,
1115
        'X' => 33,
1116
        'Y' => 34,
1117
        'Z' => 35,
1118
        'B' => 11
1119
    );
1120
    if (preg_match('/\A[A-Z]{2}\d{2} ?[A-Z\d]{4}( ?\d{4}){1,} ?\d{1,4}\z/', $field) != 1) {
1121
        return false;
1122
    }
1123
    $iban = str_replace(' ', '', $field);
1124
    $iban = substr($iban, 4) . substr($iban, 0, 4);
1125
    $iban = strtr($iban, $character);
1126
    return (bcmod($iban, 97) != 1);
1127
}
1128
1129
/**
1130
 * check the file extension
1131
 * for now checks onlt the ext should add mime type check.
1132
 *
1133
 * @param string $filePath
1134
 * @param array $allowed_extensions array of extension to match
1135
 *
1136
 * @return bool
1137
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php
1138
 */
1139
function hasFileExtension($filePath, array $allowed_extensions): bool
1140
{
1141
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
1142
    $allowed_extensions = (array)array_map('mb_strtolower', $allowed_extensions);
1143
    return in_array($extension, $allowed_extensions);
1144
}
1145
1146
/**
1147
 * Determine if the provided value is a valid phone number.
1148
 *
1149
 * @param string $field
1150
 *
1151
 * @return bool
1152
 *
1153
 * Examples:
1154
 *
1155
 *  555-555-5555: valid
1156
 *    5555425555: valid
1157
 *    555 555 5555: valid
1158
 *    1(519) 555-4444: valid
1159
 *    1 (519) 555-4422: valid
1160
 *    1-555-555-5555: valid
1161
 *    1-(555)-555-5555: valid
1162
 *    +1(519) 555-4444: valid
1163
 *    +1 (519) 555-4422: valid
1164
 *    +1-555-555-5555: valid
1165
 *    +1-(555)-555-5555: valid
1166
 *
1167
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1168
 */
1169
function isphoneNumber($field): bool
1170
{
1171
    if (isNullOrEmpty($field) || strlen(trim($field)) < 2) {
1172
        return false;
1173
    }
1174
    $field = trim($field);
1175
    if (starts_with($field, '+')) {
1176
        $field = trim(substr($field, 1));
1177
    }
1178
    $regex = '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i';
1179
    return preg_match($regex, $field) === 1;
1180
}
1181
1182
/**
1183
 * check is string is a Json string.
1184
 *
1185
 * @param string $field
1186
 *
1187
 * @return bool
1188
 */
1189
function isJsonString($field): bool
1190
{
1191
    if (isNullOrEmpty($field)) {
1192
        return false;
1193
    }
1194
    return is_string($field) && is_object(json_decode($field));
1195
}
1196
1197
1198
/**
1199
 * Checks that a value is a valid UUID - http://tools.ietf.org/html/rfc4122
1200
 *
1201
 * @param string $check Value to check
1202
 * @return bool Success
1203
 */
1204
function isUuid($check)
1205
{
1206
    $regex = '/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[0-5][a-fA-F0-9]{3}-[089aAbB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$/';
1207
    return preg_match($regex, $check) === 1;
1208
}
1209
1210
1211
/**
1212
 * Validates a geographic coordinate.
1213
 *
1214
 * Supported formats:
1215
 *
1216
 * - `<latitude>, <longitude>` Example: `-25.274398, 133.775136`
1217
 *
1218
 * ### Options
1219
 *
1220
 * - `type` - A string of the coordinate format, right now only `latLong`.
1221
 * - `format` - By default `both`, can be `long` and `lat` as well to validate
1222
 *   only a part of the coordinate.
1223
 *
1224
 * @param string $value Geographic location as string
1225
 * @param array $options Options for the validation logic.
1226
 * @return bool|Exception
1227
 */
1228
function isGeoCoordinate($value, array $options = [])
1229
{
1230
    $_pattern = [
1231
        'latitude' => '[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)',
1232
        'longitude' => '[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)',
1233
    ];
1234
1235
    $options += [
1236
        'format' => 'both',
1237
        'type' => 'latLong'
1238
    ];
1239
    if ($options['type'] !== 'latLong') {
1240
        throw new RuntimeException(sprintf(
1241
            'Unsupported coordinate type "%s". Use "latLong" instead.',
1242
            $options['type']
1243
        ));
1244
    }
1245
    $pattern = '/^' . $_pattern['latitude'] . ',\s*' . $_pattern['longitude'] . '$/';
1246
    if ($options['format'] === 'long') {
1247
        $pattern = '/^' . $_pattern['longitude'] . '$/';
1248
    }
1249
    if ($options['format'] === 'lat') {
1250
        $pattern = '/^' . $_pattern['latitude'] . '$/';
1251
    }
1252
    return (bool)preg_match($pattern, $value);
1253
}
1254
1255
/**
1256
 * Convenience method for latitude validation.
1257
 *
1258
 * @param string $value Latitude as string
1259
 * @param array $options Options for the validation logic.
1260
 * @return bool
1261
 * @link https://en.wikipedia.org/wiki/Latitude
1262
 * @see \Cake\Validation\Validation::geoCoordinate()
1263
 */
1264
function isLatitude($value, array $options = [])
1265
{
1266
    $options['format'] = 'lat';
1267
    return isGeoCoordinate($value, $options);
1268
}
1269
1270
/**
1271
 * Convenience method for longitude validation.
1272
 *
1273
 * @param string $value Latitude as string
1274
 * @param array $options Options for the validation logic.
1275
 * @return bool
1276
 * @link https://en.wikipedia.org/wiki/Longitude
1277
 * @see \Cake\Validation\Validation::geoCoordinate()
1278
 */
1279
function isLongitude($value, array $options = []): bool
1280
{
1281
    $options['format'] = 'long';
1282
    return isGeoCoordinate($value, $options);
1283
}
1284
1285
/**
1286
 * Check that the input value is within the ascii byte range.
1287
 *
1288
 * This method will reject all non-string values.
1289
 *
1290
 * @param string $value The value to check
1291
 * @return bool
1292
 */
1293
function isAscii($value)
1294
{
1295
    if (!is_string($value)) {
1296
        return false;
1297
    }
1298
    return strlen($value) <= mb_strlen($value, 'utf-8');
1299
}
1300
1301
/**
1302
 * Check that the input value is a utf8 string.
1303
 *
1304
 * This method will reject all non-string values.
1305
 *
1306
 * # Options
1307
 *
1308
 * - `extended` - Disallow bytes higher within the basic multilingual plane.
1309
 *   MySQL's older utf8 encoding type does not allow characters above
1310
 *   the basic multilingual plane. Defaults to false.
1311
 *
1312
 * @param string $value The value to check
1313
 * @param array $options An array of options. See above for the supported options.
1314
 * @return bool
1315
 */
1316
function isUtf8($value, array $options = []): bool
1317
{
1318
    if (!is_string($value)) {
1319
        return false;
1320
    }
1321
    $options += ['extended' => false];
1322
    if ($options['extended']) {
1323
        return true;
1324
    }
1325
    return preg_match('/[\x{10000}-\x{10FFFF}]/u', $value) === 0;
1326
}
1327