Completed
Push — master ( d0cfcf...43547c )
by Lorenzo
02:02
created

validation.php ➔ isPercent()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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