Completed
Push — master ( b20047...c22284 )
by Lorenzo
07:33
created

validation.php ➔ isDateTimeZeroIso()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
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 has a URL address syntax is valid.
495
 * It require scheme to be valide (http|https|ftp|mailto|file|data)
496
 * i.e.: http://dummy.com and http://www.dummy.com is valid but www.dummy.and dummy.com return false.
497
 * @param $url
498
 * @return bool
499
 */
500
function isUrl($url) : bool
501
{
502
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
503
}
504
505
/**
506
 * Check if a string is valid hostname
507
 * (dummy.com, www.dummy.com, , www.dummy.co.uk, , www.dummy-dummy.com, etc..).
508
 * @param $value
509
 * @return bool
510
 */
511
function isHostname($value) : bool
512
{
513
    return preg_match('/(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/i', $value) === 1;
514
}
515
516
/**
517
 * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt
518
 *
519
 * The regex checks for the following component parts:
520
 *
521
 * - a valid, optional, scheme
522
 * - a valid ip address OR
523
 *   a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt
524
 *   with an optional port number
525
 * - an optional valid path
526
 * - an optional query string (get parameters)
527
 * - an optional fragment (anchor tag)
528
 *
529
 * @param string $check Value to check
530
 * @param bool $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher)
531
 * @return bool Success
532
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php#L839
533
 */
534
function urlW3c($check, bool $strict = false) : bool
535
{
536
    $_pattern = array();
537
    $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
538
    $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
539
    $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})';
540
    $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}:)';
541
    $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}))';
542
    $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}';
543
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
544
    $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
545
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
546
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
547
    $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})?)';
548
    $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
549
    $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
550
    $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})))(%.+)?';
551
    $_pattern['IPv6'] = $pattern;
552
553
    $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])';
554
    $_pattern['IPv4'] = $pattern;
555
556
    $_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,})'];
557
558
    $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9\p{L}\p{N}]|(%[0-9a-f]{2}))';
559
    $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . ($strict ? '' : '?') .
560
        '(?:' . $_pattern['IPv4'] . '|\[' . $_pattern['IPv6'] . '\]|' . $_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' .
561
        '(?:\/?|\/' . $validChars . '*)?' .
562
        '(?:\?' . $validChars . '*)?' .
563
        '(?:#' . $validChars . '*)?$/iu';
564
    return preg_match($regex, $check) === 1;
565
}
566
567
/**
568
 * Controlla partita IVA Italiana.
569
 * @author Umberto Salsi <[email protected]>
570
 * @author Lorenzo Padovani modified.
571
 * @version 2012-05-12
572
 * @param string $pi Partita IVA Italiana è costituita da 11 cifre. Non sono ammessi
573
 * caratteri di spazio, per cui i campi di input dell'utente dovrebbero
574
 * essere trimmati preventivamente. La stringa vuota e' ammessa, cioe'
575
 * il dato viene considerato opzionale.
576
 * @param bool $validateOnVIES default false. if se to true, first check algorithm then if it valid,
577
 * try to check VIES service. If VIES return false or soap exception was thrown, return false.
578
 * @return bool
579
 */
580
function isPiva(string $pi, bool $validateOnVIES = false) : bool
581
{
582
    if ($pi === null || $pi === '' || strlen($pi) != 11 || preg_match("/^[0-9]+\$/", $pi) != 1) {
583
        return false;
584
    }
585
    $s = 0;
586
    for ($i = 0; $i <= 9; $i += 2) {
587
        $s += ord($pi[$i]) - ord('0');
588
    }
589
    for ($i = 1; $i <= 9; $i += 2) {
590
        $c = 2 * (ord($pi[$i]) - ord('0'));
591
        if ($c > 9) {
592
            $c -= 9;
593
        }
594
        $s += $c;
595
    }
596
    if ((10 - $s % 10) % 10 != ord($pi[10]) - ord('0')) {
597
        return false;
598
    }
599
    if (!$validateOnVIES) {
600
        return true;
601
    }
602
    //check vies
603
    try {
604
        return isVATNumber($pi);
605
    } catch (SoapFault $e) {
606
        return false;
607
    }
608
}
609
610
/**
611
 * Validate a European VAT number using the EU commission VIES service.
612
 * If not $vatNumber starts with country code, a default $countryCodeDefault applied.
613
 * @param string $vatNumber
614
 * @param string $countryCodeDefault default 'IT'
615
 * @return bool
616
 * @throws SoapFault
617
 */
618
function isVATNumber(string $vatNumber, string $countryCodeDefault = 'IT') : bool
619
{
620
    if (!isAlphaNumericWhiteSpaces($vatNumber) || strlen(trim($vatNumber)) < 3) {
621
        return false;
622
    }
623
624
    $vatNumber = str_replace([' ', '-', '.', ','], '', strtoupper(trim($vatNumber)));
625
    $countryCode = strtoupper(substr($vatNumber, 0, 2));
626
627
    if (preg_match('/^[A-Za-z]{2}$/', $countryCode) === 1) {
628
        $vatNumber = substr($vatNumber, 2);
629
    } else {
630
        $countryCode = $countryCodeDefault != '' ? strtoupper($countryCodeDefault) : 'IT';
631
    }
632
    try {
633
        $serviceUrl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
634
        $client = new SoapClient($serviceUrl);
635
        $response = $client->checkVat([
636
            'countryCode' => $countryCode,
637
            'vatNumber' => $vatNumber,
638
        ]);
639
        return $response->valid;
640
    } catch (SoapFault $e) {
641
        throw $e;
642
    }
643
}
644
645
/**
646
 * Controlla codice fiscale.
647
 * @author Umberto Salsi <[email protected]>
648
 * @version 2012-05-12
649
 * @param string $cf Codice fiscale costituito da 16 caratteri. Non
650
 * sono ammessi caratteri di spazio, per cui i campi di input dell'utente
651
 * dovrebbero essere trimmati preventivamente. La stringa vuota e' ammessa,
652
 * cioe' il dato viene considerato opzionale.
653
 * @return bool
654
 */
655
function isCf(string $cf) : bool
656
{
657
    if ($cf === null || $cf === '' || strlen($cf) != 16) {
658
        return false;
659
    }
660
    $cf = strtoupper($cf);
661
    if (preg_match("/^[A-Z0-9]+\$/", $cf) != 1) {
662
        return false;
663
    }
664
    $s = 0;
665
    for ($i = 1; $i <= 13; $i += 2) {
666
        $c = $cf[$i];
667
        if (strcmp($c, "0") >= 0 && strcmp($c, "9") <= 0) {
668
            $s += ord($c) - ord('0');
669
        } else {
670
            $s += ord($c) - ord('A');
671
        }
672
    }
673
    for ($i = 0; $i <= 14; $i += 2) {
674
        $c = $cf[$i];
675
        switch ($c) {
676
            case '0':
677
                $s += 1;
678
                break;
679
            case '1':
680
                $s += 0;
681
                break;
682
            case '2':
683
                $s += 5;
684
                break;
685
            case '3':
686
                $s += 7;
687
                break;
688
            case '4':
689
                $s += 9;
690
                break;
691
            case '5':
692
                $s += 13;
693
                break;
694
            case '6':
695
                $s += 15;
696
                break;
697
            case '7':
698
                $s += 17;
699
                break;
700
            case '8':
701
                $s += 19;
702
                break;
703
            case '9':
704
                $s += 21;
705
                break;
706
            case 'A':
707
                $s += 1;
708
                break;
709
            case 'B':
710
                $s += 0;
711
                break;
712
            case 'C':
713
                $s += 5;
714
                break;
715
            case 'D':
716
                $s += 7;
717
                break;
718
            case 'E':
719
                $s += 9;
720
                break;
721
            case 'F':
722
                $s += 13;
723
                break;
724
            case 'G':
725
                $s += 15;
726
                break;
727
            case 'H':
728
                $s += 17;
729
                break;
730
            case 'I':
731
                $s += 19;
732
                break;
733
            case 'J':
734
                $s += 21;
735
                break;
736
            case 'K':
737
                $s += 2;
738
                break;
739
            case 'L':
740
                $s += 4;
741
                break;
742
            case 'M':
743
                $s += 18;
744
                break;
745
            case 'N':
746
                $s += 20;
747
                break;
748
            case 'O':
749
                $s += 11;
750
                break;
751
            case 'P':
752
                $s += 3;
753
                break;
754
            case 'Q':
755
                $s += 6;
756
                break;
757
            case 'R':
758
                $s += 8;
759
                break;
760
            case 'S':
761
                $s += 12;
762
                break;
763
            case 'T':
764
                $s += 14;
765
                break;
766
            case 'U':
767
                $s += 16;
768
                break;
769
            case 'V':
770
                $s += 10;
771
                break;
772
            case 'W':
773
                $s += 22;
774
                break;
775
            case 'X':
776
                $s += 25;
777
                break;
778
            case 'Y':
779
                $s += 24;
780
                break;
781
            case 'Z':
782
                $s += 23;
783
                break;
784
            /*. missing_default: .*/
785
        }
786
    }
787
    return !(chr($s % 26 + ord('A')) != $cf[15]);
788
}
789
790
/**
791
 * Determine if the provided value contains only alpha characters.
792
 *
793
 * @param string $field
794
 *
795
 * @return mixed
796
 *
797
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
798
 */
799
function isAlpha(string $field) : bool
800
{
801
    return isNotNullOrEmpty($field)
802
    && preg_match('/^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
803
}
804
805
/**
806
 * Determine if the provided value contains only alpha characters.
807
 *
808
 * @param string $field
809
 *
810
 * @return mixed
811
 *
812
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
813
 */
814
function isAlphaNumeric(string $field) : bool
815
{
816
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
817
}
818
819
/**
820
 * Determine if the provided value contains only alpha characters with dashed and underscores.
821
 *
822
 * @param string $field
823
 *
824
 * @return mixed
825
 */
826
function isAlphaNumericDash($field) : bool
827
{
828
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_])+$/i', $field) === 1;
829
}
830
831
/**
832
 * Determine if the provided value contains only alpha numeric characters with spaces.
833
 *
834
 * @param string $field
835
 *
836
 * @return mixed
837
 */
838
function isAlphaNumericWhiteSpaces($field) : bool
839
{
840
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_\s])+$/i', $field) === 1;
841
}
842
843
/**
844
 * Determine if the provided value is a boolean.
845
 *
846
 * @param string $field
847
 *
848
 * @return mixed
849
 */
850
function isBool($field) : bool
851
{
852
    return $field === true || $field === false;
853
}
854
855
/**
856
 * Determine if the provided value is a boolean or 1,0,'1','0'.
857
 *
858
 * @param string $field
859
 *
860
 * @return bool
861
 */
862
function isBoolOrIntBool($field) : bool
863
{
864
    return in_array($field, [0, 1, '0', '1', true, false], true);
865
}
866
867
/**
868
 * Determine if the input is a valid credit card number.
869
 *
870
 * See: http://stackoverflow.com/questions/174730/what-is-the-best-way-to-validate-a-credit-card-in-php
871
 *
872
 * @param string $field
873
 *
874
 * @return mixed
875
 */
876
function isCrediCard(string $field) : bool
877
{
878
    if (isNullOrEmpty($field)) {
879
        return false;
880
    }
881
    $number = preg_replace('/\D/', '', $field);
882
    if (function_exists('mb_strlen')) {
883
        $number_length = mb_strlen($number);
884
    } else {
885
        $number_length = strlen($number);
886
    }
887
    $parity = $number_length % 2;
888
    $total = 0;
889
    for ($i = 0; $i < $number_length; ++$i) {
890
        $digit = $number[$i];
891
        if ($i % 2 == $parity) {
892
            $digit *= 2;
893
            if ($digit > 9) {
894
                $digit -= 9;
895
            }
896
        }
897
        $total += $digit;
898
    }
899
    return ($total % 10 == 0);
900
}
901
902
/**
903
 * Determine if the input is a valid human name.
904
 *
905
 * @param string $field
906
 *
907
 * @return mixed
908
 *
909
 * @See: https://github.com/Wixel/GUMP/issues/5
910
 */
911
function isValidHumanName(string $field) : bool
912
{
913
    if (isNullOrEmpty($field)) {
914
        return false;
915
    }
916
    return isAlpha($field) && preg_match("/^([ '-])+$/", $field) === 1;
917
}
918
919
/**
920
 * Determine if the provided value is a valid IBAN.
921
 *
922
 * @param string $field
923
 *
924
 * @return bool
925
 *
926
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
927
 */
928
function isIban($field) : bool
929
{
930
    if (isNullOrEmpty($field)) {
931
        return false;
932
    }
933
    static $character = array(
934
        'A' => 10,
935
        'C' => 12,
936
        'D' => 13,
937
        'E' => 14,
938
        'F' => 15,
939
        'G' => 16,
940
        'H' => 17,
941
        'I' => 18,
942
        'J' => 19,
943
        'K' => 20,
944
        'L' => 21,
945
        'M' => 22,
946
        'N' => 23,
947
        'O' => 24,
948
        'P' => 25,
949
        'Q' => 26,
950
        'R' => 27,
951
        'S' => 28,
952
        'T' => 29,
953
        'U' => 30,
954
        'V' => 31,
955
        'W' => 32,
956
        'X' => 33,
957
        'Y' => 34,
958
        'Z' => 35,
959
        'B' => 11
960
    );
961
    if (preg_match('/\A[A-Z]{2}\d{2} ?[A-Z\d]{4}( ?\d{4}){1,} ?\d{1,4}\z/', $field) != 1) {
962
        return false;
963
    }
964
    $iban = str_replace(' ', '', $field);
965
    $iban = substr($iban, 4) . substr($iban, 0, 4);
966
    $iban = strtr($iban, $character);
967
    return (bcmod($iban, 97) != 1);
968
}
969
970
/**
971
 * check the file extension
972
 * for now checks onlt the ext should add mime type check.
973
 *
974
 * @param string $filePath
975
 * @param array $allowed_extensions array of extension to match
976
 *
977
 * @return bool
978
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php
979
 */
980
function hasFileExtension($filePath, array $allowed_extensions) : bool
981
{
982
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
983
    $allowed_extensions = (array)array_map('mb_strtolower', $allowed_extensions);
984
    return in_array($extension, $allowed_extensions);
985
}
986
987
/**
988
 * Determine if the provided value is a valid phone number.
989
 *
990
 * @param string $field
991
 *
992
 * @return bool
993
 *
994
 * Examples:
995
 *
996
 *  555-555-5555: valid
997
 *    5555425555: valid
998
 *    555 555 5555: valid
999
 *    1(519) 555-4444: valid
1000
 *    1 (519) 555-4422: valid
1001
 *    1-555-555-5555: valid
1002
 *    1-(555)-555-5555: valid
1003
 *    +1(519) 555-4444: valid
1004
 *    +1 (519) 555-4422: valid
1005
 *    +1-555-555-5555: valid
1006
 *    +1-(555)-555-5555: valid
1007
 *
1008
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1009
 */
1010
function isphoneNumber($field) : bool
1011
{
1012
    if (isNullOrEmpty($field) || strlen(trim($field)) < 2) {
1013
        return false;
1014
    }
1015
    $field = trim($field);
1016
    if (starts_with($field, '+')) {
1017
        $field = trim(substr($field, 1));
1018
    }
1019
    $regex = '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i';
1020
    return preg_match($regex, $field) === 1;
1021
}
1022
1023
/**
1024
 * check is string is a Json string.
1025
 *
1026
 * @param string $field
1027
 *
1028
 * @return bool
1029
 */
1030
function isJsonString($field) : bool
1031
{
1032
    if (isNullOrEmpty($field)) {
1033
        return false;
1034
    }
1035
    return is_string($field) && is_object(json_decode($field));
1036
}
1037
1038
1039
/**
1040
 * Checks that a value is a valid UUID - http://tools.ietf.org/html/rfc4122
1041
 *
1042
 * @param string $check Value to check
1043
 * @return bool Success
1044
 */
1045
function isUuid($check)
1046
{
1047
    $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}$/';
1048
    return preg_match($regex, $check) === 1;
1049
}
1050
1051
1052
/**
1053
 * Validates a geographic coordinate.
1054
 *
1055
 * Supported formats:
1056
 *
1057
 * - `<latitude>, <longitude>` Example: `-25.274398, 133.775136`
1058
 *
1059
 * ### Options
1060
 *
1061
 * - `type` - A string of the coordinate format, right now only `latLong`.
1062
 * - `format` - By default `both`, can be `long` and `lat` as well to validate
1063
 *   only a part of the coordinate.
1064
 *
1065
 * @param string $value Geographic location as string
1066
 * @param array $options Options for the validation logic.
1067
 * @return bool|Exception
1068
 */
1069
function isGeoCoordinate($value, array $options = [])
1070
{
1071
    $_pattern = [
1072
        'latitude' => '[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)',
1073
        'longitude' => '[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)',
1074
    ];
1075
1076
    $options += [
1077
        'format' => 'both',
1078
        'type' => 'latLong'
1079
    ];
1080
    if ($options['type'] !== 'latLong') {
1081
        throw new RuntimeException(sprintf(
1082
            'Unsupported coordinate type "%s". Use "latLong" instead.',
1083
            $options['type']
1084
        ));
1085
    }
1086
    $pattern = '/^' . $_pattern['latitude'] . ',\s*' . $_pattern['longitude'] . '$/';
1087
    if ($options['format'] === 'long') {
1088
        $pattern = '/^' . $_pattern['longitude'] . '$/';
1089
    }
1090
    if ($options['format'] === 'lat') {
1091
        $pattern = '/^' . $_pattern['latitude'] . '$/';
1092
    }
1093
    return (bool)preg_match($pattern, $value);
1094
}
1095
1096
/**
1097
 * Convenience method for latitude validation.
1098
 *
1099
 * @param string $value Latitude as string
1100
 * @param array $options Options for the validation logic.
1101
 * @return bool
1102
 * @link https://en.wikipedia.org/wiki/Latitude
1103
 * @see \Cake\Validation\Validation::geoCoordinate()
1104
 */
1105
function isLatitude($value, array $options = [])
1106
{
1107
    $options['format'] = 'lat';
1108
    return isGeoCoordinate($value, $options);
1109
}
1110
1111
/**
1112
 * Convenience method for longitude validation.
1113
 *
1114
 * @param string $value Latitude as string
1115
 * @param array $options Options for the validation logic.
1116
 * @return bool
1117
 * @link https://en.wikipedia.org/wiki/Longitude
1118
 * @see \Cake\Validation\Validation::geoCoordinate()
1119
 */
1120
function isLongitude($value, array $options = []) : bool
1121
{
1122
    $options['format'] = 'long';
1123
    return isGeoCoordinate($value, $options);
1124
}
1125
1126
/**
1127
 * Check that the input value is within the ascii byte range.
1128
 *
1129
 * This method will reject all non-string values.
1130
 *
1131
 * @param string $value The value to check
1132
 * @return bool
1133
 */
1134
function isAscii($value)
1135
{
1136
    if (!is_string($value)) {
1137
        return false;
1138
    }
1139
    return strlen($value) <= mb_strlen($value, 'utf-8');
1140
}
1141
1142
/**
1143
 * Check that the input value is a utf8 string.
1144
 *
1145
 * This method will reject all non-string values.
1146
 *
1147
 * # Options
1148
 *
1149
 * - `extended` - Disallow bytes higher within the basic multilingual plane.
1150
 *   MySQL's older utf8 encoding type does not allow characters above
1151
 *   the basic multilingual plane. Defaults to false.
1152
 *
1153
 * @param string $value The value to check
1154
 * @param array $options An array of options. See above for the supported options.
1155
 * @return bool
1156
 */
1157
function isUtf8($value, array $options = []) : bool
1158
{
1159
    if (!is_string($value)) {
1160
        return false;
1161
    }
1162
    $options += ['extended' => false];
1163
    if ($options['extended']) {
1164
        return true;
1165
    }
1166
    return preg_match('/[\x{10000}-\x{10FFFF}]/u', $value) === 0;
1167
}
1168