Completed
Push — master ( 9d4be0...988869 )
by Lorenzo
04:20
created

validation.php ➔ isIPv4Compatibility()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 5
nc 4
nop 1
dl 0
loc 8
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 greater than zero or equals to zero..
29
 * Only number >=0 and <=PHP_INT_MAX
30
 * or if $acceptIntegerFloatingPoints==true a floating point that match an positive integer).
31
 * @param $value
32
 * @param bool $acceptIntegerFloatingPoints
33
 * @return bool
34
 */
35
function isIntegerPositiveOrZero($value, $acceptIntegerFloatingPoints = false) : bool
36
{
37
    return isInteger($value, true, $acceptIntegerFloatingPoints) && $value >= 0;
38
}
39
40
/**
41
 * Check if the value (int, float or string) is a integer.
42
 * Only number <=PHP_INT_MAX (and >=PHP_INT_MIN if unsigned=true)
43
 * or if $acceptIntegerFloatingPoints==true a floating point that match an integer).
44
 * @param $value
45
 * @param bool $unsigned
46
 * @param bool $acceptIntegerFloatingPoints
47
 * @return bool
48
 */
49
function isInteger($value, $unsigned = true, $acceptIntegerFloatingPoints = false) : bool
50
{
51
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
52
        return false;
53
    }
54
55
    //accept only integer number and if $acceptIntegerFloatingPoints is true accept integer floating point too.
56
    return ((preg_match('/^' . ($unsigned ? '' : '-{0,1}') . '[0-9]{1,}$/', $value) === 1
57
            && ($value <= PHP_INT_MAX && $value >= PHP_INT_MIN && (((int)$value) == $value))
58
        )
59
        || ($acceptIntegerFloatingPoints && isIntegerFloatingPoint($value, $unsigned)));
60
}
61
62
/**
63
 * Check if string is a valid floating point that
64
 * match an integer (<=PHP_INT_MAX and >=PHP_INT_MIN if unsigned=true)
65
 * or is an integer
66
 * Ex.: 1, 1e2, 1E2, 1e+2, 1e-2, 1.4e+2, -1.2e+2, -1.231e-2 etc...
67
 * @param $value
68
 * @param bool $unsigned
69
 * @return bool
70
 */
71
function isIntegerFloatingPoint($value, $unsigned = true) : bool
72
{
73
    return isFloatingPoint($value, $unsigned)
74
    && $value <= PHP_INT_MAX && $value >= PHP_INT_MIN
75
    //big number rouned to int aproximately!
76
    //big number change into exp format
77
    && ((int)((double)$value) == $value || (int)$value == $value || strpos(strtoupper((string)$value), 'E') === false);
78
}
79
80
/**
81
 * Check if string is a valid floating point.
82
 * Ex.: [+-]1, [+-]1e2, [+-]1E2, [+-]1e+2, [+-]1e-2, [+-]1.43234e+2, -1.231e+2, -1.231e-2 etc...
83
 * @param $value
84
 * @param $unsigned
85
 * @return bool
86
 */
87
function isFloatingPoint($value, $unsigned) : bool
88
{
89
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
90
        return false;
91
    }
92
93
    return preg_match('/^' . ($unsigned ? '[+]{0,1}' : '[-+]{0,1}') . '[0-9]{1,}(\.[0-9]{1,}){0,1}([Ee][+,-]{0,1}[0-9]{1,}){0,}$/',
94
        $value) === 1;
95
}
96
97
/**
98
 * Check if the value are a double (integer or float in the form 1, 1.11...1.
99
 * @param $value
100
 * @param int $dec
101
 * @param bool $unsigned
102
 * @param bool $exactDec if set to true aspect number of dec exact to $dec,
103
 * otherwise $dec is max decimals accepted (0 decimals are also ok in this case).
104
 * if $dec is an empty string, accept 0 to infinite decimals.
105
 * @return bool
106
 */
107
function isDouble($value, $dec = 2, $unsigned = true, $exactDec = false) : bool
108
{
109
    if (isStringNumberStartsWithMoreThanOneZero($value)) {
110
        return false;
111
    }
112
    $regEx = '/^' . ($unsigned ? '' : '-{0,1}') . '[0-9]{1,}(\.{1}[0-9]{' . ($exactDec ? '' : '1,') . $dec . '})' . ($exactDec ? '{1}' : '{0,1}') . '$/';
113
    return preg_match($regEx, $value) === 1;
114
}
115
116
/**
117
 * Check if a string is a percent 0%-100%
118
 * @param $value
119
 * @param bool $withDecimal if set to true accept decimal values.
120
 * @param bool $withPercentChar if set to true require % char, otherwise if find a % char return false.
121
 * @return bool
122
 */
123
function isPercent($value, bool $withDecimal = true, bool $withPercentChar = false) : bool
124
{
125
    if (isNullOrEmpty($value)) {
126
        return false;
127
    }
128
    $contains_perc = str_contains($value, '%');
129
    if (($withPercentChar && !$contains_perc)
130
        || (!$withPercentChar && $contains_perc)
131
        || (substr_count($value, '%') > 1) //only one %
132
    ) {
133
        return false;
134
    }
135
    $value = trim(str_replace('%', '', $value));
136
137
    return $withDecimal ? isDouble($value, '', true) : isInteger($value, true);
138
}
139
140
/**
141
 * @param float $value
142
 * @param float $leftRange
143
 * @param float $rightRange
144
 * @return bool
145
 */
146
function isInRange(float $value, float $leftRange = 0, float $rightRange = 0) : bool
147
{
148
    return ($value <= $rightRange && $value >= $leftRange);
149
}
150
151
/**
152
 * Check if string is dd/mm/YYYY
153
 * @param $value
154
 * @return bool
155
 */
156 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...
157
{
158
    if (isNullOrEmpty($value) || strlen($value) != 10 || strpos($value, '/') === false) {
159
        return false;
160
    }
161
    list($dd, $mm, $yyyy) = explode('/', $value);
162
    try {
163
        return checkdate($mm, $dd, $yyyy);
164
    } catch (Exception $e) {
165
        return false;
166
    }
167
}
168
169
/**
170
 * Check if string is 0000-00-00
171
 * @param $value
172
 * @return bool
173
 */
174
function isDateZeroIso($value) : bool
175
{
176
    return $value == '0000-00-00';
177
}
178
179
/**
180
 * Check if string is 00:00:00
181
 * @param $value
182
 * @return bool
183
 */
184
function isTimeZeroIso($value) : bool
185
{
186
    return $value == '00:00:00';
187
}
188
189
/**
190
 * Check if string is '0000-00-00 00:00:00'
191
 * @param $value
192
 * @return bool
193
 */
194
function isDateTimeZeroIso($value) : bool
195
{
196
    return $value == '0000-00-00 00:00:00';
197
}
198
199
/**
200
 * Check if string is YYYY-mm-dd and valid date or 0000-00-00
201
 * @param $value
202
 * @return bool
203
 */
204
function isDateOrDateZeroIso($value) : bool
205
{
206
    return isDateIso($value) || isDateZeroIso($value);
207
}
208
209
/**
210
 * Check if string is 'YYYY-mm-dd HH:ii:ss' and valid date or '0000-00-00 00:00:00'
211
 * @param $value
212
 * @return bool
213
 */
214
function isDateTimeOrDateTimeZeroIso($value) : bool
215
{
216
    return isDateTimeIso($value) || isDateTimeZeroIso($value);
217
}
218
219
/**
220
 * Check if string is YYYY-mm-dd
221
 * @param $value
222
 * @return bool
223
 */
224 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...
225
{
226
    if (isNullOrEmpty($value) || strlen($value) != 10 || strpos($value, '-') === false) {
227
        return false;
228
    }
229
    list($yyyy, $mm, $dd) = explode('-', $value);
230
    try {
231
        return checkdate($mm, $dd, $yyyy);
232
    } catch (Exception $e) {
233
        return false;
234
    }
235
}
236
237
/**
238
 * Check if string is YYYY-mm-dd HH:ii:ss
239
 * @param $value
240
 * @return bool
241
 */
242
function isDateTimeIso($value) : bool
243
{
244
    if (!isDateIso(substr($value, 0, 10))) {
245
        return false;
246
    }
247
    return isTimeIso(substr($value, 11));
248
}
249
250
/**
251
 * Check if string is dd/mm/YYYY HH:ii:ss
252
 * @param $value
253
 * @return bool
254
 */
255
function isDateTimeIta($value) : bool
256
{
257
    if (!isDateIta(substr($value, 0, 10))) {
258
        return false;
259
    }
260
    return isTimeIso(substr($value, 11));
261
}
262
263
/**
264
 * Check if string is HH:ii:ss
265
 * @param $value
266
 * @return bool
267
 */
268
function isTimeIso($value) : bool
269
{
270
    $strRegExp = '/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/';
271
    if (!(preg_match($strRegExp, $value) === 1)) {
272
        return false;
273
    }
274
    list($HH, $ii, $ss) = explode(':', $value);
275
    return isInRange((int)$HH, 0, 23) && isInRange((int)$ii, 0, 59) && isInRange((int)$ss, 0, 59);
276
}
277
278
/**
279
 * An alias of isTimeIso.
280
 * @param $value
281
 * @return bool
282
 */
283
function isTimeIta($value)
284
{
285
    return isTimeIso($value);
286
}
287
288
/**
289
 * Check if year ia a leap year in jewish calendar.
290
 * @param int $year
291
 * @return bool
292
 */
293
function isJewishLeapYear(int $year) : bool
294
{
295
    if ($year % 19 == 0 || $year % 19 == 3 || $year % 19 == 6 ||
296
        $year % 19 == 8 || $year % 19 == 11 || $year % 19 == 14 ||
297
        $year % 19 == 17
298
    ) {
299
        return true;
300
    } else {
301
        return false;
302
    }
303
}
304
305
/**
306
 * Check if a number is a valid month.
307
 * More params you passed (year, calendar), more accurate is the check.
308
 * If passed a not valid year return false.
309
 * @param int $value
310
 * @param int $year
311
 * @param int $calendar
312
 * @return bool
313
 */
314
function isMonth(int $value, int $year, int $calendar = CAL_GREGORIAN) : bool
315
{
316
    if (!isInRange($year, 0, PHP_INT_MAX)) {
317
        return false;
318
    }
319
320
    $maxMonths = 12;
321
322
    if ($calendar == 3
323
        || ($year > 0 && $calendar == 2 && isJewishLeapYear($year))
324
    ) {
325
        $maxMonths = 13;
326
    }
327
328
    return isInRange($value, 1, $maxMonths);
329
}
330
331
/**
332
 * Check if a number is a valid day.
333
 * More params you passed (month, year, calendar), more accurate is the check.
334
 * If passed a not valid year or month return false.
335
 * @param int $value
336
 * @param int $month
337
 * @param int $year
338
 * @param int $calendar
339
 * @return bool
340
 */
341
function isDay(int $value, int $month = 0, int $year = 0, int $calendar = CAL_GREGORIAN) : bool
342
{
343
    if ($month != 0 && !isMonth($month, $year, $calendar)) {
344
        return false;
345
    }
346
    if (!isInRange($year, 0, PHP_INT_MAX)) {
347
        return false;
348
    }
349
350
    $maxDays = 31;
351
352
    if ($year > 0 && $month > 0) {
353
        $maxDays = cal_days_in_month($calendar, $month, $year);
354
    } elseif (in_array($month, [11, 4, 6, 9])) {
355
        $maxDays = 30;
356
    } elseif ($month == 2) {
357
        $maxDays = 28;
358
    }
359
360
    return isInRange($value, 1, $maxDays);
361
}
362
363
/**
364
 * Determine if the provided input meets age requirement (ISO 8601).
365
 *
366
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
367
 * @param int $age
368
 *
369
 * @return bool
370
 */
371
function hasMinAge($dateOfBirthday, int $age) : bool
372
{
373
    return date_diff(date('Y-m-d'), $dateOfBirthday) >= $age;
374
}
375
376
/**
377
 * Determine if the provided input meets age requirement (ISO 8601).
378
 *
379
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
380
 * @param int $age
381
 *
382
 * @return bool
383
 */
384
function hasMaxAge($dateOfBirthday, int $age) : bool
385
{
386
    return date_diff(date('Y-m-d'), $dateOfBirthday) <= $age;
387
}
388
389
/**
390
 * Determine if the provided input meets age requirement (ISO 8601).
391
 *
392
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
393
 * @param int $ageMin
394
 * @param int $ageMax
395
 *
396
 * @return bool
397
 */
398
function hasAgeInRange($dateOfBirthday, int $ageMin, int $ageMax) : bool
399
{
400
    return hasMinAge($dateOfBirthday, $ageMin) && hasMaxAge($dateOfBirthday, $ageMax);
401
}
402
403
/**
404
 * Check if a date in iso format is in range
405
 * @param string $date iso format
406
 * @param string $minDate iso format
407
 * @param string $maxDate iso format
408
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
409
 * @return bool
410
 */
411
function betweenDateIso(string $date, string $minDate, string $maxDate, bool $strict = false) : bool
412
{
413
    if (!isDateIso($date) || !isDateIso($minDate) || !isDateIso($maxDate)) {
414
        return false;
415
    }
416
417
    if (!$strict) {
418
        return ($date >= $minDate) && ($date <= $maxDate);
419
    }
420
    return ($date > $minDate) && ($date < $maxDate);
421
}
422
423
/**
424
 * Check if a date in ita format is in range
425
 * @param string $date ita format
426
 * @param string $minDate ita format
427
 * @param string $maxDate ita format
428
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
429
 * @return bool
430
 */
431
function betweenDateIta(string $date, string $minDate, string $maxDate, bool $strict = false) : bool
432
{
433
    if (!isDateIta($date) || !isDateIta($minDate) || !isDateIta($maxDate)) {
434
        return false;
435
    }
436
437
    $date = dateItaToIso($date);
438
    $minDate = dateItaToIso($minDate);
439
    $maxDate = dateItaToIso($maxDate);
440
441
    return betweenDateIso($date, $minDate, $maxDate, $strict);
442
}
443
444
/**
445
 * @param $value
446
 * @param $checkMx
447
 * @return bool
448
 */
449
function isMail($value, bool $checkMx = false) : bool
450
{
451
    if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
452
        return false;
453
    }
454
    if ($checkMx) {
455
        list(, $mailDomain) = explode('@', $value);
456
        if (!checkdnsrr($mailDomain, 'MX')) {
457
            return false;
458
        }
459
    }
460
    return true;
461
}
462
463
/**
464
 * isIPv4 check if a string is a valid IP v4
465
 * @param  string $IP2Check IP to check
466
 * @return bool
467
 */
468
function isIPv4($IP2Check) : bool
469
{
470
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false);
471
}
472
473
/**
474
 * isIPv6 check if a string is a valid IP v6
475
 * @param  string $IP2Check IP to check
476
 * @return bool
477
 */
478
function isIPv6($IP2Check) : bool
479
{
480
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false);
481
}
482
483
/**
484
 * Check if a string is a valid IP (v4 or v6).
485
 * @param  string $IP2Check IP to check
486
 * @return bool
487
 */
488
function isIP($IP2Check) : bool
489
{
490
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP) === false);
491
}
492
493
/**
494
 * Check if a string is a valid IP v4 compatibility (ffff:ffff:ffff:ffff.192.168.0.15).
495
 * @param  string $IP2Check IP to check
496
 * @return bool
497
 */
498
function isIPv4Compatibility($IP2Check) : bool
499
{
500
    return (strrpos($IP2Check, ":") > 0
501
        && strrpos($IP2Check, ".") > 0
502
        && isIPv4(substr($IP2Check, strpos($IP2Check, ".") + 1))
503
        && isIPv6(substr($IP2Check, 0, strpos($IP2Check, ".")).':0:0:0:0')
504
    );
505
}
506
507
/**
508
 * Check if a string has a URL address syntax is valid.
509
 * It require scheme to be valide (http|https|ftp|mailto|file|data)
510
 * i.e.: http://dummy.com and http://www.dummy.com is valid but www.dummy.and dummy.com return false.
511
 * @param $url
512
 * @return bool
513
 */
514
function isUrl($url) : bool
515
{
516
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
517
}
518
519
/**
520
 * Check if a string is valid hostname
521
 * (dummy.com, www.dummy.com, , www.dummy.co.uk, , www.dummy-dummy.com, etc..).
522
 * @param $value
523
 * @return bool
524
 */
525
function isHostname($value) : bool
526
{
527
    return preg_match('/(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/i', $value) === 1;
528
}
529
530
/**
531
 * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt
532
 *
533
 * The regex checks for the following component parts:
534
 *
535
 * - a valid, optional, scheme
536
 * - a valid ip address OR
537
 *   a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt
538
 *   with an optional port number
539
 * - an optional valid path
540
 * - an optional query string (get parameters)
541
 * - an optional fragment (anchor tag)
542
 *
543
 * @param string $check Value to check
544
 * @param bool $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher)
545
 * @return bool Success
546
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php#L839
547
 */
548
function urlW3c($check, bool $strict = false) : bool
549
{
550
    $_pattern = array();
551
    $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
552
    $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
553
    $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})';
554
    $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}:)';
555
    $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}))';
556
    $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}';
557
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
558
    $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
559
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
560
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
561
    $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})?)';
562
    $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
563
    $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
564
    $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})))(%.+)?';
565
    $_pattern['IPv6'] = $pattern;
566
567
    $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])';
568
    $_pattern['IPv4'] = $pattern;
569
570
    $_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,})'];
571
572
    $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9\p{L}\p{N}]|(%[0-9a-f]{2}))';
573
    $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . ($strict ? '' : '?') .
574
        '(?:' . $_pattern['IPv4'] . '|\[' . $_pattern['IPv6'] . '\]|' . $_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' .
575
        '(?:\/?|\/' . $validChars . '*)?' .
576
        '(?:\?' . $validChars . '*)?' .
577
        '(?:#' . $validChars . '*)?$/iu';
578
    return preg_match($regex, $check) === 1;
579
}
580
581
/**
582
 * Controlla partita IVA Italiana.
583
 * @author Umberto Salsi <[email protected]>
584
 * @author Lorenzo Padovani modified.
585
 * @version 2012-05-12
586
 * @param string $pi Partita IVA Italiana è costituita da 11 cifre. Non sono ammessi
587
 * caratteri di spazio, per cui i campi di input dell'utente dovrebbero
588
 * essere trimmati preventivamente. La stringa vuota e' ammessa, cioe'
589
 * il dato viene considerato opzionale.
590
 * @param bool $validateOnVIES default false. if se to true, first check algorithm then if it valid,
591
 * try to check VIES service. If VIES return false or soap exception was thrown, return false.
592
 * @return bool
593
 */
594
function isPiva(string $pi, bool $validateOnVIES = false) : bool
595
{
596
    if ($pi === null || $pi === '' || strlen($pi) != 11 || preg_match("/^[0-9]+\$/", $pi) != 1) {
597
        return false;
598
    }
599
    $s = 0;
600
    for ($i = 0; $i <= 9; $i += 2) {
601
        $s += ord($pi[$i]) - ord('0');
602
    }
603
    for ($i = 1; $i <= 9; $i += 2) {
604
        $c = 2 * (ord($pi[$i]) - ord('0'));
605
        if ($c > 9) {
606
            $c -= 9;
607
        }
608
        $s += $c;
609
    }
610
    if ((10 - $s % 10) % 10 != ord($pi[10]) - ord('0')) {
611
        return false;
612
    }
613
    if (!$validateOnVIES) {
614
        return true;
615
    }
616
    //check vies
617
    try {
618
        return isVATNumber($pi);
619
    } catch (SoapFault $e) {
620
        return false;
621
    }
622
}
623
624
/**
625
 * Validate a European VAT number using the EU commission VIES service.
626
 * If not $vatNumber starts with country code, a default $countryCodeDefault applied.
627
 * @param string $vatNumber
628
 * @param string $countryCodeDefault default 'IT'
629
 * @return bool
630
 * @throws SoapFault
631
 */
632
function isVATNumber(string $vatNumber, string $countryCodeDefault = 'IT') : bool
633
{
634
    if (!isAlphaNumericWhiteSpaces($vatNumber) || strlen(trim($vatNumber)) < 3) {
635
        return false;
636
    }
637
638
    $vatNumber = str_replace([' ', '-', '.', ','], '', strtoupper(trim($vatNumber)));
639
    $countryCode = strtoupper(substr($vatNumber, 0, 2));
640
641
    if (preg_match('/^[A-Za-z]{2}$/', $countryCode) === 1) {
642
        $vatNumber = substr($vatNumber, 2);
643
    } else {
644
        $countryCode = $countryCodeDefault != '' ? strtoupper($countryCodeDefault) : 'IT';
645
    }
646
    try {
647
        $serviceUrl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
648
        $client = new SoapClient($serviceUrl);
649
        $response = $client->checkVat([
650
            'countryCode' => $countryCode,
651
            'vatNumber' => $vatNumber,
652
        ]);
653
        return $response->valid;
654
    } catch (SoapFault $e) {
655
        throw $e;
656
    }
657
}
658
659
/**
660
 * Controlla codice fiscale.
661
 * @author Umberto Salsi <[email protected]>
662
 * @version 2012-05-12
663
 * @param string $cf Codice fiscale costituito da 16 caratteri. Non
664
 * sono ammessi caratteri di spazio, per cui i campi di input dell'utente
665
 * dovrebbero essere trimmati preventivamente. La stringa vuota e' ammessa,
666
 * cioe' il dato viene considerato opzionale.
667
 * @return bool
668
 */
669
function isCf(string $cf) : bool
670
{
671
    if ($cf === null || $cf === '' || strlen($cf) != 16) {
672
        return false;
673
    }
674
    $cf = strtoupper($cf);
675
    if (preg_match("/^[A-Z0-9]+\$/", $cf) != 1) {
676
        return false;
677
    }
678
    $s = 0;
679
    for ($i = 1; $i <= 13; $i += 2) {
680
        $c = $cf[$i];
681
        if (strcmp($c, "0") >= 0 && strcmp($c, "9") <= 0) {
682
            $s += ord($c) - ord('0');
683
        } else {
684
            $s += ord($c) - ord('A');
685
        }
686
    }
687
    for ($i = 0; $i <= 14; $i += 2) {
688
        $c = $cf[$i];
689
        switch ($c) {
690
            case '0':
691
                $s += 1;
692
                break;
693
            case '1':
694
                $s += 0;
695
                break;
696
            case '2':
697
                $s += 5;
698
                break;
699
            case '3':
700
                $s += 7;
701
                break;
702
            case '4':
703
                $s += 9;
704
                break;
705
            case '5':
706
                $s += 13;
707
                break;
708
            case '6':
709
                $s += 15;
710
                break;
711
            case '7':
712
                $s += 17;
713
                break;
714
            case '8':
715
                $s += 19;
716
                break;
717
            case '9':
718
                $s += 21;
719
                break;
720
            case 'A':
721
                $s += 1;
722
                break;
723
            case 'B':
724
                $s += 0;
725
                break;
726
            case 'C':
727
                $s += 5;
728
                break;
729
            case 'D':
730
                $s += 7;
731
                break;
732
            case 'E':
733
                $s += 9;
734
                break;
735
            case 'F':
736
                $s += 13;
737
                break;
738
            case 'G':
739
                $s += 15;
740
                break;
741
            case 'H':
742
                $s += 17;
743
                break;
744
            case 'I':
745
                $s += 19;
746
                break;
747
            case 'J':
748
                $s += 21;
749
                break;
750
            case 'K':
751
                $s += 2;
752
                break;
753
            case 'L':
754
                $s += 4;
755
                break;
756
            case 'M':
757
                $s += 18;
758
                break;
759
            case 'N':
760
                $s += 20;
761
                break;
762
            case 'O':
763
                $s += 11;
764
                break;
765
            case 'P':
766
                $s += 3;
767
                break;
768
            case 'Q':
769
                $s += 6;
770
                break;
771
            case 'R':
772
                $s += 8;
773
                break;
774
            case 'S':
775
                $s += 12;
776
                break;
777
            case 'T':
778
                $s += 14;
779
                break;
780
            case 'U':
781
                $s += 16;
782
                break;
783
            case 'V':
784
                $s += 10;
785
                break;
786
            case 'W':
787
                $s += 22;
788
                break;
789
            case 'X':
790
                $s += 25;
791
                break;
792
            case 'Y':
793
                $s += 24;
794
                break;
795
            case 'Z':
796
                $s += 23;
797
                break;
798
            /*. missing_default: .*/
799
        }
800
    }
801
    return !(chr($s % 26 + ord('A')) != $cf[15]);
802
}
803
804
/**
805
 * Determine if the provided value contains only alpha characters.
806
 *
807
 * @param string $field
808
 *
809
 * @return mixed
810
 *
811
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
812
 */
813
function isAlpha(string $field) : bool
814
{
815
    return isNotNullOrEmpty($field)
816
    && preg_match('/^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
817
}
818
819
/**
820
 * Determine if the provided value contains only alpha characters.
821
 *
822
 * @param string $field
823
 *
824
 * @return mixed
825
 *
826
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
827
 */
828
function isAlphaNumeric(string $field) : bool
829
{
830
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
831
}
832
833
/**
834
 * Determine if the provided value contains only alpha characters with dashed and underscores.
835
 *
836
 * @param string $field
837
 *
838
 * @return mixed
839
 */
840
function isAlphaNumericDash($field) : bool
841
{
842
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_])+$/i', $field) === 1;
843
}
844
845
/**
846
 * Determine if the provided value contains only alpha numeric characters with spaces.
847
 *
848
 * @param string $field
849
 *
850
 * @return mixed
851
 */
852
function isAlphaNumericWhiteSpaces($field) : bool
853
{
854
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_\s])+$/i', $field) === 1;
855
}
856
857
/**
858
 * Determine if the provided value is a boolean.
859
 *
860
 * @param string $field
861
 *
862
 * @return mixed
863
 */
864
function isBool($field) : bool
865
{
866
    return $field === true || $field === false;
867
}
868
869
/**
870
 * Determine if the provided value is a boolean or 1,0,'1','0'.
871
 *
872
 * @param string $field
873
 *
874
 * @return bool
875
 */
876
function isBoolOrIntBool($field) : bool
877
{
878
    return in_array($field, [0, 1, '0', '1', true, false], true);
879
}
880
881
/**
882
 * Determine if the input is a valid credit card number.
883
 *
884
 * See: http://stackoverflow.com/questions/174730/what-is-the-best-way-to-validate-a-credit-card-in-php
885
 *
886
 * @param string $field
887
 *
888
 * @return mixed
889
 */
890
function isCrediCard(string $field) : bool
891
{
892
    if (isNullOrEmpty($field)) {
893
        return false;
894
    }
895
    $number = preg_replace('/\D/', '', $field);
896
    if (function_exists('mb_strlen')) {
897
        $number_length = mb_strlen($number);
898
    } else {
899
        $number_length = strlen($number);
900
    }
901
    $parity = $number_length % 2;
902
    $total = 0;
903
    for ($i = 0; $i < $number_length; ++$i) {
904
        $digit = $number[$i];
905
        if ($i % 2 == $parity) {
906
            $digit *= 2;
907
            if ($digit > 9) {
908
                $digit -= 9;
909
            }
910
        }
911
        $total += $digit;
912
    }
913
    return ($total % 10 == 0);
914
}
915
916
/**
917
 * Determine if the input is a valid human name.
918
 *
919
 * @param string $field
920
 *
921
 * @return mixed
922
 *
923
 * @See: https://github.com/Wixel/GUMP/issues/5
924
 */
925
function isValidHumanName(string $field) : bool
926
{
927
    if (isNullOrEmpty($field)) {
928
        return false;
929
    }
930
    return isAlpha($field) && preg_match("/^([ '-])+$/", $field) === 1;
931
}
932
933
/**
934
 * Determine if the provided value is a valid IBAN.
935
 *
936
 * @param string $field
937
 *
938
 * @return bool
939
 *
940
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
941
 */
942
function isIban($field) : bool
943
{
944
    if (isNullOrEmpty($field)) {
945
        return false;
946
    }
947
    static $character = array(
948
        'A' => 10,
949
        'C' => 12,
950
        'D' => 13,
951
        'E' => 14,
952
        'F' => 15,
953
        'G' => 16,
954
        'H' => 17,
955
        'I' => 18,
956
        'J' => 19,
957
        'K' => 20,
958
        'L' => 21,
959
        'M' => 22,
960
        'N' => 23,
961
        'O' => 24,
962
        'P' => 25,
963
        'Q' => 26,
964
        'R' => 27,
965
        'S' => 28,
966
        'T' => 29,
967
        'U' => 30,
968
        'V' => 31,
969
        'W' => 32,
970
        'X' => 33,
971
        'Y' => 34,
972
        'Z' => 35,
973
        'B' => 11
974
    );
975
    if (preg_match('/\A[A-Z]{2}\d{2} ?[A-Z\d]{4}( ?\d{4}){1,} ?\d{1,4}\z/', $field) != 1) {
976
        return false;
977
    }
978
    $iban = str_replace(' ', '', $field);
979
    $iban = substr($iban, 4) . substr($iban, 0, 4);
980
    $iban = strtr($iban, $character);
981
    return (bcmod($iban, 97) != 1);
982
}
983
984
/**
985
 * check the file extension
986
 * for now checks onlt the ext should add mime type check.
987
 *
988
 * @param string $filePath
989
 * @param array $allowed_extensions array of extension to match
990
 *
991
 * @return bool
992
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php
993
 */
994
function hasFileExtension($filePath, array $allowed_extensions) : bool
995
{
996
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
997
    $allowed_extensions = (array)array_map('mb_strtolower', $allowed_extensions);
998
    return in_array($extension, $allowed_extensions);
999
}
1000
1001
/**
1002
 * Determine if the provided value is a valid phone number.
1003
 *
1004
 * @param string $field
1005
 *
1006
 * @return bool
1007
 *
1008
 * Examples:
1009
 *
1010
 *  555-555-5555: valid
1011
 *    5555425555: valid
1012
 *    555 555 5555: valid
1013
 *    1(519) 555-4444: valid
1014
 *    1 (519) 555-4422: valid
1015
 *    1-555-555-5555: valid
1016
 *    1-(555)-555-5555: valid
1017
 *    +1(519) 555-4444: valid
1018
 *    +1 (519) 555-4422: valid
1019
 *    +1-555-555-5555: valid
1020
 *    +1-(555)-555-5555: valid
1021
 *
1022
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1023
 */
1024
function isphoneNumber($field) : bool
1025
{
1026
    if (isNullOrEmpty($field) || strlen(trim($field)) < 2) {
1027
        return false;
1028
    }
1029
    $field = trim($field);
1030
    if (starts_with($field, '+')) {
1031
        $field = trim(substr($field, 1));
1032
    }
1033
    $regex = '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i';
1034
    return preg_match($regex, $field) === 1;
1035
}
1036
1037
/**
1038
 * check is string is a Json string.
1039
 *
1040
 * @param string $field
1041
 *
1042
 * @return bool
1043
 */
1044
function isJsonString($field) : bool
1045
{
1046
    if (isNullOrEmpty($field)) {
1047
        return false;
1048
    }
1049
    return is_string($field) && is_object(json_decode($field));
1050
}
1051
1052
1053
/**
1054
 * Checks that a value is a valid UUID - http://tools.ietf.org/html/rfc4122
1055
 *
1056
 * @param string $check Value to check
1057
 * @return bool Success
1058
 */
1059
function isUuid($check)
1060
{
1061
    $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}$/';
1062
    return preg_match($regex, $check) === 1;
1063
}
1064
1065
1066
/**
1067
 * Validates a geographic coordinate.
1068
 *
1069
 * Supported formats:
1070
 *
1071
 * - `<latitude>, <longitude>` Example: `-25.274398, 133.775136`
1072
 *
1073
 * ### Options
1074
 *
1075
 * - `type` - A string of the coordinate format, right now only `latLong`.
1076
 * - `format` - By default `both`, can be `long` and `lat` as well to validate
1077
 *   only a part of the coordinate.
1078
 *
1079
 * @param string $value Geographic location as string
1080
 * @param array $options Options for the validation logic.
1081
 * @return bool|Exception
1082
 */
1083
function isGeoCoordinate($value, array $options = [])
1084
{
1085
    $_pattern = [
1086
        'latitude' => '[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)',
1087
        'longitude' => '[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)',
1088
    ];
1089
1090
    $options += [
1091
        'format' => 'both',
1092
        'type' => 'latLong'
1093
    ];
1094
    if ($options['type'] !== 'latLong') {
1095
        throw new RuntimeException(sprintf(
1096
            'Unsupported coordinate type "%s". Use "latLong" instead.',
1097
            $options['type']
1098
        ));
1099
    }
1100
    $pattern = '/^' . $_pattern['latitude'] . ',\s*' . $_pattern['longitude'] . '$/';
1101
    if ($options['format'] === 'long') {
1102
        $pattern = '/^' . $_pattern['longitude'] . '$/';
1103
    }
1104
    if ($options['format'] === 'lat') {
1105
        $pattern = '/^' . $_pattern['latitude'] . '$/';
1106
    }
1107
    return (bool)preg_match($pattern, $value);
1108
}
1109
1110
/**
1111
 * Convenience method for latitude validation.
1112
 *
1113
 * @param string $value Latitude as string
1114
 * @param array $options Options for the validation logic.
1115
 * @return bool
1116
 * @link https://en.wikipedia.org/wiki/Latitude
1117
 * @see \Cake\Validation\Validation::geoCoordinate()
1118
 */
1119
function isLatitude($value, array $options = [])
1120
{
1121
    $options['format'] = 'lat';
1122
    return isGeoCoordinate($value, $options);
1123
}
1124
1125
/**
1126
 * Convenience method for longitude validation.
1127
 *
1128
 * @param string $value Latitude as string
1129
 * @param array $options Options for the validation logic.
1130
 * @return bool
1131
 * @link https://en.wikipedia.org/wiki/Longitude
1132
 * @see \Cake\Validation\Validation::geoCoordinate()
1133
 */
1134
function isLongitude($value, array $options = []) : bool
1135
{
1136
    $options['format'] = 'long';
1137
    return isGeoCoordinate($value, $options);
1138
}
1139
1140
/**
1141
 * Check that the input value is within the ascii byte range.
1142
 *
1143
 * This method will reject all non-string values.
1144
 *
1145
 * @param string $value The value to check
1146
 * @return bool
1147
 */
1148
function isAscii($value)
1149
{
1150
    if (!is_string($value)) {
1151
        return false;
1152
    }
1153
    return strlen($value) <= mb_strlen($value, 'utf-8');
1154
}
1155
1156
/**
1157
 * Check that the input value is a utf8 string.
1158
 *
1159
 * This method will reject all non-string values.
1160
 *
1161
 * # Options
1162
 *
1163
 * - `extended` - Disallow bytes higher within the basic multilingual plane.
1164
 *   MySQL's older utf8 encoding type does not allow characters above
1165
 *   the basic multilingual plane. Defaults to false.
1166
 *
1167
 * @param string $value The value to check
1168
 * @param array $options An array of options. See above for the supported options.
1169
 * @return bool
1170
 */
1171
function isUtf8($value, array $options = []) : bool
1172
{
1173
    if (!is_string($value)) {
1174
        return false;
1175
    }
1176
    $options += ['extended' => false];
1177
    if ($options['extended']) {
1178
        return true;
1179
    }
1180
    return preg_match('/[\x{10000}-\x{10FFFF}]/u', $value) === 0;
1181
}
1182