Completed
Push — master ( 1e6b86...6b7615 )
by Lorenzo
02:54
created

validation.php ➔ isEuVatNumber()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

Loading history...
333
{
334
    if (isNullOrEmpty($value) || strlen($value) != 10 || strpos($value, '-') === false) {
335
        return false;
336
    }
337
    list($yyyy, $mm, $dd) = explode('-', $value);
338
    try {
339
        return checkdate($mm, $dd, $yyyy);
340
    } catch (Exception $e) {
341
        return false;
342
    }
343
}
344
345
/**
346
 * Check if string is YYYY-mm-dd HH:ii:ss
347
 * @param $value
348
 * @return bool
349
 */
350
function isDateTimeIso($value): bool
351
{
352
    if (!isDateIso(substr($value, 0, 10))) {
353
        return false;
354
    }
355
    return isTimeIso(substr($value, 11));
356
}
357
358
/**
359
 * Check if string is dd/mm/YYYY HH:ii:ss
360
 * @param $value
361
 * @return bool
362
 */
363
function isDateTimeIta($value): bool
364
{
365
    if (!isDateIta(substr($value, 0, 10))) {
366
        return false;
367
    }
368
    return isTimeIso(substr($value, 11));
369
}
370
371
/**
372
 * Check if string is HH:ii:ss
373
 * @param $value
374
 * @return bool
375
 */
376
function isTimeIso($value): bool
377
{
378
    $strRegExp = '/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/';
379
    if (!(preg_match($strRegExp, $value) === 1)) {
380
        return false;
381
    }
382
    list($HH, $ii, $ss) = explode(':', $value);
383
    return isInRange((int)$HH, 0, 23) && isInRange((int)$ii, 0, 59) && isInRange((int)$ss, 0, 59);
384
}
385
386
/**
387
 * An alias of isTimeIso.
388
 * @param $value
389
 * @return bool
390
 */
391
function isTimeIta($value)
392
{
393
    return isTimeIso($value);
394
}
395
396
/**
397
 * Check if year ia a leap year in jewish calendar.
398
 * @param int $year
399
 * @return bool
400
 */
401
function isJewishLeapYear(int $year): bool
402
{
403
    if ($year % 19 == 0 || $year % 19 == 3 || $year % 19 == 6 ||
404
        $year % 19 == 8 || $year % 19 == 11 || $year % 19 == 14 ||
405
        $year % 19 == 17
406
    ) {
407
        return true;
408
    } else {
409
        return false;
410
    }
411
}
412
413
/**
414
 * Check if a number is a valid month.
415
 * More params you passed (year, calendar), more accurate is the check.
416
 * If passed a not valid year return false.
417
 * @param int $value
418
 * @param int $year
419
 * @param int $calendar
420
 * @return bool
421
 */
422
function isMonth(int $value, int $year, int $calendar = CAL_GREGORIAN): bool
423
{
424
    if (!isInRange($year, 0, PHP_INT_MAX)) {
425
        return false;
426
    }
427
428
    $maxMonths = 12;
429
430
    if ($calendar == 3
431
        || ($year > 0 && $calendar == 2 && isJewishLeapYear($year))
432
    ) {
433
        $maxMonths = 13;
434
    }
435
436
    return isInRange($value, 1, $maxMonths);
437
}
438
439
/**
440
 * Check if a number is a valid day.
441
 * More params you passed (month, year, calendar), more accurate is the check.
442
 * If passed a not valid year or month return false.
443
 * @param int $value
444
 * @param int $month
445
 * @param int $year
446
 * @param int $calendar
447
 * @return bool
448
 */
449
function isDay(int $value, int $month = 0, int $year = 0, int $calendar = CAL_GREGORIAN): bool
450
{
451
    if ($month != 0 && !isMonth($month, $year, $calendar)) {
452
        return false;
453
    }
454
    if (!isInRange($year, 0, PHP_INT_MAX)) {
455
        return false;
456
    }
457
458
    $maxDays = 31;
459
460
    if ($year > 0 && $month > 0) {
461
        $maxDays = cal_days_in_month($calendar, $month, $year);
462
    } elseif (in_array($month, [11, 4, 6, 9])) {
463
        $maxDays = 30;
464
    } elseif ($month == 2) {
465
        $maxDays = 28;
466
    }
467
468
    return isInRange($value, 1, $maxDays);
469
}
470
471
/**
472
 * Determine if the provided input meets age requirement (ISO 8601).
473
 *
474
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
475
 * @param int $age
476
 *
477
 * @return bool
478
 */
479
function hasMinAge($dateOfBirthday, int $age): bool
480
{
481
    return date_diff(date('Y-m-d'), $dateOfBirthday) >= $age;
482
}
483
484
/**
485
 * Determine if the provided input meets age requirement (ISO 8601).
486
 *
487
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
488
 * @param int $age
489
 *
490
 * @return bool
491
 */
492
function hasMaxAge($dateOfBirthday, int $age): bool
493
{
494
    return date_diff(date('Y-m-d'), $dateOfBirthday) <= $age;
495
}
496
497
/**
498
 * Determine if the provided input meets age requirement (ISO 8601).
499
 *
500
 * @param string $dateOfBirthday date ('Y-m-d') or datetime ('Y-m-d H:i:s') Date Of Birthday
501
 * @param int $ageMin
502
 * @param int $ageMax
503
 *
504
 * @return bool
505
 */
506
function hasAgeInRange($dateOfBirthday, int $ageMin, int $ageMax): bool
507
{
508
    return hasMinAge($dateOfBirthday, $ageMin) && hasMaxAge($dateOfBirthday, $ageMax);
509
}
510
511
/**
512
 * Check if a date in iso format is in range
513
 * @param string $date iso format
514
 * @param string $minDate iso format
515
 * @param string $maxDate iso format
516
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
517
 * @return bool
518
 */
519
function betweenDateIso(string $date, string $minDate, string $maxDate, bool $strict = false): bool
520
{
521
    if (!isDateIso($date) || !isDateIso($minDate) || !isDateIso($maxDate)) {
522
        return false;
523
    }
524
525
    if (!$strict) {
526
        return ($date >= $minDate) && ($date <= $maxDate);
527
    }
528
    return ($date > $minDate) && ($date < $maxDate);
529
}
530
531
/**
532
 * Check if a date in ita format is in range
533
 * @param string $date ita format
534
 * @param string $minDate ita format
535
 * @param string $maxDate ita format
536
 * @param bool $strict if set to false (default) check >=min and <=max otherwise check >min and <max.
537
 * @return bool
538
 */
539
function betweenDateIta(string $date, string $minDate, string $maxDate, bool $strict = false): bool
540
{
541
    if (!isDateIta($date) || !isDateIta($minDate) || !isDateIta($maxDate)) {
542
        return false;
543
    }
544
545
    $date = dateItaToIso($date);
546
    $minDate = dateItaToIso($minDate);
547
    $maxDate = dateItaToIso($maxDate);
548
549
    return betweenDateIso($date, $minDate, $maxDate, $strict);
550
}
551
552
/**
553
 * @param $value
554
 * @param $checkMx
555
 * @return bool
556
 */
557
function isMail($value, bool $checkMx = false): bool
558
{
559
    if (filter_var($value, FILTER_VALIDATE_EMAIL) === false) {
560
        return false;
561
    }
562
    if ($checkMx) {
563
        list(, $mailDomain) = explode('@', $value);
564
        if (!checkdnsrr($mailDomain, 'MX')) {
565
            return false;
566
        }
567
    }
568
    return true;
569
}
570
571
/**
572
 * isIPv4 check if a string is a valid IP v4
573
 * @param  string $IP2Check IP to check
574
 * @return bool
575
 */
576
function isIPv4($IP2Check): bool
577
{
578
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false);
579
}
580
581
/**
582
 * isIPv6 check if a string is a valid IP v6
583
 * @param  string $IP2Check IP to check
584
 * @return bool
585
 */
586
function isIPv6($IP2Check): bool
587
{
588
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false);
589
}
590
591
/**
592
 * Check if a string is a valid IP (v4 or v6).
593
 * @param  string $IP2Check IP to check
594
 * @return bool
595
 */
596
function isIP($IP2Check): bool
597
{
598
    return !(filter_var($IP2Check, FILTER_VALIDATE_IP) === false);
599
}
600
601
/**
602
 * Check if a string is a valid IP v4 compatibility (ffff:ffff:ffff:ffff.192.168.0.15).
603
 * @param  string $IP2Check IP to check
604
 * @return bool
605
 */
606
function isIPv4Compatibility($IP2Check): bool
607
{
608
    return (strrpos($IP2Check, ":") > 0
609
        && strrpos($IP2Check, ".") > 0
610
        && isIPv4(substr($IP2Check, strpos($IP2Check, ".") + 1))
611
        && isIPv6(substr($IP2Check, 0, strpos($IP2Check, ".")) . ':0:0:0:0')
612
    );
613
}
614
615
/**
616
 * Check if a string has a URL address syntax is valid.
617
 * It require scheme to be valide (http|https|ftp|mailto|file|data)
618
 * i.e.: http://dummy.com and http://www.dummy.com is valid but www.dummy.and dummy.com return false.
619
 * @param $url
620
 * @return bool
621
 */
622
function isUrl($url): bool
623
{
624
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
625
}
626
627
/**
628
 * Check if a string is valid hostname
629
 * (dummy.com, www.dummy.com, , www.dummy.co.uk, , www.dummy-dummy.com, etc..).
630
 * @param $value
631
 * @return bool
632
 */
633
function isHostname($value): bool
634
{
635
    return preg_match('/(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/i', $value) === 1;
636
}
637
638
/**
639
 * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt
640
 *
641
 * The regex checks for the following component parts:
642
 *
643
 * - a valid, optional, scheme
644
 * - a valid ip address OR
645
 *   a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt
646
 *   with an optional port number
647
 * - an optional valid path
648
 * - an optional query string (get parameters)
649
 * - an optional fragment (anchor tag)
650
 *
651
 * @param string $check Value to check
652
 * @param bool $strict Require URL to be prefixed by a valid scheme (one of http(s)/ftp(s)/file/news/gopher)
653
 * @return bool Success
654
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php#L839
655
 */
656
function urlW3c($check, bool $strict = false): bool
657
{
658
    $_pattern = array();
659
    $pattern = '((([0-9A-Fa-f]{1,4}:){7}(([0-9A-Fa-f]{1,4})|:))|(([0-9A-Fa-f]{1,4}:){6}';
660
    $pattern .= '(:|((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})';
661
    $pattern .= '|(:[0-9A-Fa-f]{1,4})))|(([0-9A-Fa-f]{1,4}:){5}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})';
662
    $pattern .= '(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)';
663
    $pattern .= '{4}(:[0-9A-Fa-f]{1,4}){0,1}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
664
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}';
665
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|';
666
    $pattern .= '((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}';
667
    $pattern .= '((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2}))';
668
    $pattern .= '{3})?)|((:[0-9A-Fa-f]{1,4}){1,2})))|(([0-9A-Fa-f]{1,4}:)(:[0-9A-Fa-f]{1,4})';
669
    $pattern .= '{0,4}((:((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)';
670
    $pattern .= '|((:[0-9A-Fa-f]{1,4}){1,2})))|(:(:[0-9A-Fa-f]{1,4}){0,5}((:((25[0-5]|2[0-4]';
671
    $pattern .= '\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|((:[0-9A-Fa-f]{1,4})';
672
    $pattern .= '{1,2})))|(((25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))(%.+)?';
673
    $_pattern['IPv6'] = $pattern;
674
675
    $pattern = '(?:(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|(?:(?:1[0-9])?|[1-9]?)[0-9])';
676
    $_pattern['IPv4'] = $pattern;
677
678
    $_pattern = ['hostname' => '(?:[_\p{L}0-9][-_\p{L}0-9]*\.)*(?:[\p{L}0-9][-\p{L}0-9]{0,62})\.(?:(?:[a-z]{2}\.)?[a-z]{2,})'];
679
680
    $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=~[]') . '\/0-9\p{L}\p{N}]|(%[0-9a-f]{2}))';
681
    $regex = '/^(?:(?:https?|ftps?|sftp|file|news|gopher):\/\/)' . ($strict ? '' : '?') .
682
        '(?:' . $_pattern['IPv4'] . '|\[' . $_pattern['IPv6'] . '\]|' . $_pattern['hostname'] . ')(?::[1-9][0-9]{0,4})?' .
683
        '(?:\/?|\/' . $validChars . '*)?' .
684
        '(?:\?' . $validChars . '*)?' .
685
        '(?:#' . $validChars . '*)?$/iu';
686
    return preg_match($regex, $check) === 1;
687
}
688
689
/**
690
 * Check if a valid EU vat given.
691
 * @param string $pi required eu vat number with or without country code prefix.
692
 * If you don't pass country code prefix, 'IT' will be assumed.
693
 * @param bool $validateOnVIES default false. if se to true, first check formal EU country algorithm,
694
 * then if it valid and country code isn't 'IT' try to check by API VIES service.
695
 * If VIES return false or soap exception was thrown, return false.
696
 * @return bool
697
 */
698
function isEuVatNumber(string $pi, bool $validateOnVIES = false): bool
699
{
700
    $countryCode = getCoutryCodeByVatNumber($pi, 'IT');
701
702
    $result = true;
703
    if (function_exists('is'.$countryCode.'Vat')){
704
        $funcname = 'is'.$countryCode.'Vat';
705
        $result = $funcname($pi);
706
    }
707
    if(!$result){
708
        return false;
709
    }
710
    if($countryCode=='IT' || !$validateOnVIES){
711
        return $result;
712
    }
713
714
    //check vies
715
    try {
716
        return isVATRegisteredInVies($pi);
717
    } catch (SoapFault $e) {
718
        return false;
719
    }
720
}
721
722
/**
723
 * Try to extract EU country code in Vat number
724
 * return $fallback if it fails.
725
 *
726
 * @param string $pi
727
 * @param string $fallback
728
 * @return string
729
 */
730
function getCoutryCodeByVatNumber(string $pi, string $fallback  ='IT'): string
731
{
732
    if ($pi === null || $pi === '' || strlen($pi) < 2) {
733
        return $fallback;
734
    }
735
736
    //try to find country code
737
    $countryCode = strtoupper(substr($pi, 0, 2));
738
    if (preg_match('/^[A-Za-z]{2}$/', $countryCode) === 1) {
739
        $pi = substr($pi, 2);
0 ignored issues
show
Unused Code introduced by
$pi is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
740
    } else {
741
        $countryCode = $fallback;
742
    }
743
    return $countryCode;
744
}
745
746
/**
747
 * Check Italian Vat Number (Partita IVA).
748
 * @author Umberto Salsi <[email protected]>
749
 * @author Lorenzo Padovani modified.
750
 * @version 2012-05-12
751
 * @param string $pi Partita IVA Italiana è costituita da 11 cifre o 13 caratteri (prefisso 2 lettere IT).
752
 * Non sono ammessi caratteri di spazio, per cui i campi di input dell'utente dovrebbero
753
 * essere trimmati preventivamente.
754
 * @return bool
755
 */
756
function isITVat(string $pi): bool
757
{
758
    $countryCode = getCoutryCodeByVatNumber($pi, '');
759
    if($countryCode!='IT' && $countryCode!=''){
760
        return false;
761
    }
762
    if($countryCode!=''){
763
        $pi = substr($pi, 2);
764
    }
765
766
    if ($pi === null || $pi === '' || strlen($pi) != 11 || preg_match("/^[0-9]+\$/", $pi) != 1) {
767
        return false;
768
    }
769
    $s = 0;
770
    for ($i = 0; $i <= 9; $i += 2) {
771
        $s += ord($pi[$i]) - ord('0');
772
    }
773
    for ($i = 1; $i <= 9; $i += 2) {
774
        $c = 2 * (ord($pi[$i]) - ord('0'));
775
        if ($c > 9) {
776
            $c -= 9;
777
        }
778
        $s += $c;
779
    }
780
    if ((10 - $s % 10) % 10 != ord($pi[10]) - ord('0')) {
781
        return false;
782
    }
783
784
    return true;
785
}
786
787
/**
788
 * Validate a European VAT number using the EU commission VIES service.
789
 * To verify if VAT number is authorized to carry out intra-Community operations must use the service
790
 * If not $vatNumber starts with country code, a default $countryCodeDefault applied.
791
 * @param string $vatNumber
792
 * @param string $countryCodeDefault default 'IT'
793
 * @return bool
794
 * @throws SoapFault
795
 */
796
function isVATRegisteredInVies(string $vatNumber, string $countryCodeDefault = 'IT'): bool
797
{
798
    if (!isAlphaNumericWhiteSpaces($vatNumber) || strlen(trim($vatNumber)) < 3) {
799
        return false;
800
    }
801
802
    $vatNumber = str_replace([' ', '-', '.', ','], '', strtoupper(trim($vatNumber)));
803
    $countryCode = strtoupper(substr($vatNumber, 0, 2));
804
805
    if (preg_match('/^[A-Za-z]{2}$/', $countryCode) === 1) {
806
        $vatNumber = substr($vatNumber, 2);
807
    } else {
808
        $countryCode = $countryCodeDefault != '' ? strtoupper($countryCodeDefault) : 'IT';
809
    }
810
    try {
811
        $serviceUrl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
812
        $client = new SoapClient($serviceUrl);
813
        $response = $client->checkVat([
814
            'countryCode' => $countryCode,
815
            'vatNumber' => $vatNumber,
816
        ]);
817
        return $response->valid;
818
    } catch (SoapFault $e) {
819
        throw $e;
820
    }
821
}
822
823
/**
824
 * Controlla codice fiscale.
825
 * @author Umberto Salsi <[email protected]>
826
 * @version 2012-05-12
827
 * @param string $cf Codice fiscale costituito da 16 caratteri. Non
828
 * sono ammessi caratteri di spazio, per cui i campi di input dell'utente
829
 * dovrebbero essere trimmati preventivamente. La stringa vuota e' ammessa,
830
 * cioe' il dato viene considerato opzionale.
831
 * @return bool
832
 */
833
function isCf(string $cf): bool
834
{
835
    if ($cf === null || $cf === '' || strlen($cf) != 16) {
836
        return false;
837
    }
838
    $cf = strtoupper($cf);
839
    if (preg_match("/^[A-Z0-9]+\$/", $cf) != 1) {
840
        return false;
841
    }
842
    $s = 0;
843
    for ($i = 1; $i <= 13; $i += 2) {
844
        $c = $cf[$i];
845
        if (strcmp($c, "0") >= 0 && strcmp($c, "9") <= 0) {
846
            $s += ord($c) - ord('0');
847
        } else {
848
            $s += ord($c) - ord('A');
849
        }
850
    }
851
    for ($i = 0; $i <= 14; $i += 2) {
852
        $c = $cf[$i];
853
        switch ($c) {
854
            case '0':
855
                $s += 1;
856
                break;
857
            case '1':
858
                $s += 0;
859
                break;
860
            case '2':
861
                $s += 5;
862
                break;
863
            case '3':
864
                $s += 7;
865
                break;
866
            case '4':
867
                $s += 9;
868
                break;
869
            case '5':
870
                $s += 13;
871
                break;
872
            case '6':
873
                $s += 15;
874
                break;
875
            case '7':
876
                $s += 17;
877
                break;
878
            case '8':
879
                $s += 19;
880
                break;
881
            case '9':
882
                $s += 21;
883
                break;
884
            case 'A':
885
                $s += 1;
886
                break;
887
            case 'B':
888
                $s += 0;
889
                break;
890
            case 'C':
891
                $s += 5;
892
                break;
893
            case 'D':
894
                $s += 7;
895
                break;
896
            case 'E':
897
                $s += 9;
898
                break;
899
            case 'F':
900
                $s += 13;
901
                break;
902
            case 'G':
903
                $s += 15;
904
                break;
905
            case 'H':
906
                $s += 17;
907
                break;
908
            case 'I':
909
                $s += 19;
910
                break;
911
            case 'J':
912
                $s += 21;
913
                break;
914
            case 'K':
915
                $s += 2;
916
                break;
917
            case 'L':
918
                $s += 4;
919
                break;
920
            case 'M':
921
                $s += 18;
922
                break;
923
            case 'N':
924
                $s += 20;
925
                break;
926
            case 'O':
927
                $s += 11;
928
                break;
929
            case 'P':
930
                $s += 3;
931
                break;
932
            case 'Q':
933
                $s += 6;
934
                break;
935
            case 'R':
936
                $s += 8;
937
                break;
938
            case 'S':
939
                $s += 12;
940
                break;
941
            case 'T':
942
                $s += 14;
943
                break;
944
            case 'U':
945
                $s += 16;
946
                break;
947
            case 'V':
948
                $s += 10;
949
                break;
950
            case 'W':
951
                $s += 22;
952
                break;
953
            case 'X':
954
                $s += 25;
955
                break;
956
            case 'Y':
957
                $s += 24;
958
                break;
959
            case 'Z':
960
                $s += 23;
961
                break;
962
            /*. missing_default: .*/
963
        }
964
    }
965
    return !(chr($s % 26 + ord('A')) != $cf[15]);
966
}
967
968
/**
969
 * Determine if the provided value contains only alpha characters.
970
 *
971
 * @param string $field
972
 *
973
 * @return mixed
974
 *
975
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
976
 */
977
function isAlpha(string $field): bool
978
{
979
    return isNotNullOrEmpty($field)
980
        && preg_match('/^([a-zÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
981
}
982
983
/**
984
 * Determine if the provided value contains only alpha characters.
985
 *
986
 * @param string $field
987
 *
988
 * @return mixed
989
 *
990
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
991
 */
992
function isAlphaNumeric(string $field): bool
993
{
994
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ])+$/i', $field) === 1;
995
}
996
997
/**
998
 * Determine if the provided value contains only numeric characters with or without(default) sign.
999
 *
1000
 * @param string $field
1001
 * @param bool $acceptSign default false if true accept string that starts with +/- oterwise only [0-9] chars.
1002
 *
1003
 * @return mixed
1004
 */
1005
function isNumeric(string $field, bool $acceptSign = false): bool
1006
{
1007
    return preg_match('/^(' . ($acceptSign ? '[+-]{0,1}' : '') . '[0-9])+$/i', $field) === 1;
1008
}
1009
1010
/**
1011
 * Determine if the provided value contains only numeric characters with sign.
1012
 *
1013
 * @param string $field
1014
 *
1015
 * @return mixed
1016
 */
1017
function isNumericWithSign(string $field): bool
1018
{
1019
    return isNumeric($field, true);
1020
}
1021
1022
/**
1023
 * Determine if the provided value contains only numeric characters without sign.
1024
 *
1025
 * @param string $field
1026
 *
1027
 * @return mixed
1028
 */
1029
function isNumericWithoutSign(string $field): bool
1030
{
1031
    return isNumeric($field, false);
1032
}
1033
1034
/**
1035
 * Determine if the provided value contains only alpha characters with dashed and underscores.
1036
 *
1037
 * @param string $field
1038
 *
1039
 * @return mixed
1040
 */
1041
function isAlphaNumericDash($field): bool
1042
{
1043
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_])+$/i', $field) === 1;
1044
}
1045
1046
/**
1047
 * Determine if the provided value contains only alpha numeric characters with spaces.
1048
 *
1049
 * @param string $field
1050
 *
1051
 * @return mixed
1052
 */
1053
function isAlphaNumericWhiteSpaces($field): bool
1054
{
1055
    return preg_match('/^([a-z0-9ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÒÓÔÕÖßÙÚÛÜÝàáâãäåçèéêëìíîïñðòóôõöùúûüýÿ\-_\s])+$/i', $field) === 1;
1056
}
1057
1058
/**
1059
 * Determine if the provided value is a boolean.
1060
 *
1061
 * @param string $field
1062
 *
1063
 * @return mixed
1064
 */
1065
function isBool($field): bool
1066
{
1067
    return $field === true || $field === false;
1068
}
1069
1070
/**
1071
 * Determine if the provided value is a boolean or 1,0,'1','0'.
1072
 *
1073
 * @param string $field
1074
 *
1075
 * @return bool
1076
 */
1077
function isBoolOrIntBool($field): bool
1078
{
1079
    return in_array($field, [0, 1, '0', '1', true, false], true);
1080
}
1081
1082
/**
1083
 * Determine if the input is a valid credit card number.
1084
 *
1085
 * See: http://stackoverflow.com/questions/174730/what-is-the-best-way-to-validate-a-credit-card-in-php
1086
 *
1087
 * @param string $field
1088
 *
1089
 * @return mixed
1090
 */
1091
function isCrediCard(string $field): bool
1092
{
1093
    if (isNullOrEmpty($field)) {
1094
        return false;
1095
    }
1096
    $number = preg_replace('/\D/', '', $field);
1097
    if (function_exists('mb_strlen')) {
1098
        $number_length = mb_strlen($number);
1099
    } else {
1100
        $number_length = strlen($number);
1101
    }
1102
    $parity = $number_length % 2;
1103
    $total = 0;
1104
    for ($i = 0; $i < $number_length; ++$i) {
1105
        $digit = $number[$i];
1106
        if ($i % 2 == $parity) {
1107
            $digit *= 2;
1108
            if ($digit > 9) {
1109
                $digit -= 9;
1110
            }
1111
        }
1112
        $total += $digit;
1113
    }
1114
    return ($total % 10 == 0);
1115
}
1116
1117
/**
1118
 * Determine if the input is a valid human name.
1119
 *
1120
 * @param string $field
1121
 *
1122
 * @return mixed
1123
 *
1124
 * @See: https://github.com/Wixel/GUMP/issues/5
1125
 */
1126
function isValidHumanName(string $field): bool
1127
{
1128
    if (isNullOrEmpty($field)) {
1129
        return false;
1130
    }
1131
    return isAlpha($field) && preg_match("/^([ '-])+$/", $field) === 1;
1132
}
1133
1134
/**
1135
 * Determine if the provided value is a valid IBAN.
1136
 *
1137
 * @param string $field
1138
 *
1139
 * @return bool
1140
 *
1141
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1142
 */
1143
function isIban($field): bool
1144
{
1145
    if (isNullOrEmpty($field)) {
1146
        return false;
1147
    }
1148
    static $character = array(
1149
        'A' => 10,
1150
        'C' => 12,
1151
        'D' => 13,
1152
        'E' => 14,
1153
        'F' => 15,
1154
        'G' => 16,
1155
        'H' => 17,
1156
        'I' => 18,
1157
        'J' => 19,
1158
        'K' => 20,
1159
        'L' => 21,
1160
        'M' => 22,
1161
        'N' => 23,
1162
        'O' => 24,
1163
        'P' => 25,
1164
        'Q' => 26,
1165
        'R' => 27,
1166
        'S' => 28,
1167
        'T' => 29,
1168
        'U' => 30,
1169
        'V' => 31,
1170
        'W' => 32,
1171
        'X' => 33,
1172
        'Y' => 34,
1173
        'Z' => 35,
1174
        'B' => 11
1175
    );
1176
    if (preg_match('/\A[A-Z]{2}\d{2} ?[A-Z\d]{4}( ?\d{4}){1,} ?\d{1,4}\z/', $field) != 1) {
1177
        return false;
1178
    }
1179
    $iban = str_replace(' ', '', $field);
1180
    $iban = substr($iban, 4) . substr($iban, 0, 4);
1181
    $iban = strtr($iban, $character);
1182
    return (bcmod($iban, 97) != 1);
1183
}
1184
1185
/**
1186
 * check the file extension
1187
 * for now checks onlt the ext should add mime type check.
1188
 *
1189
 * @param string $filePath
1190
 * @param array $allowed_extensions array of extension to match
1191
 *
1192
 * @return bool
1193
 * @see https://github.com/cakephp/cakephp/blob/master/src/Validation/Validation.php
1194
 */
1195
function hasFileExtension($filePath, array $allowed_extensions): bool
1196
{
1197
    $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
1198
    $allowed_extensions = (array)array_map('mb_strtolower', $allowed_extensions);
1199
    return in_array($extension, $allowed_extensions);
1200
}
1201
1202
/**
1203
 * Determine if the provided value is a valid phone number.
1204
 *
1205
 * @param string $field
1206
 *
1207
 * @return bool
1208
 *
1209
 * Examples:
1210
 *
1211
 *    555-555-5555: valid
1212
 *    5555425555: valid
1213
 *    555 555 5555: valid
1214
 *    1(519) 555-4444: valid
1215
 *    1 (519) 555-4422: valid
1216
 *    1-555-555-5555: valid
1217
 *    1-(555)-555-5555: valid
1218
 *    +1(519) 555-4444: valid
1219
 *    +1 (519) 555-4422: valid
1220
 *    +1-555-555-5555: valid
1221
 *    +1-(555)-555-5555: valid
1222
 *
1223
 * @see https://github.com/Wixel/GUMP/blob/master/gump.class.php
1224
 */
1225
function isphoneNumber($field): bool
1226
{
1227
    if (isNullOrEmpty($field) || strlen(trim($field)) < 2) {
1228
        return false;
1229
    }
1230
    $field = trim($field);
1231
    if (starts_with($field, '+')) {
1232
        $field = trim(substr($field, 1));
1233
    }
1234
    $regex = '/^(\d[\s-]?)?[\(\[\s-]{0,2}?\d{3}[\)\]\s-]{0,2}?\d{3}[\s-]?\d{4}$/i';
1235
    return preg_match($regex, $field) === 1;
1236
}
1237
1238
/**
1239
 * check is string is a Json string.
1240
 *
1241
 * @param string $field
1242
 *
1243
 * @return bool
1244
 */
1245
function isJsonString($field): bool
1246
{
1247
    if (isNullOrEmpty($field)) {
1248
        return false;
1249
    }
1250
    return is_string($field) && is_object(json_decode($field));
1251
}
1252
1253
1254
/**
1255
 * Checks that a value is a valid UUID - http://tools.ietf.org/html/rfc4122
1256
 *
1257
 * @param string $check Value to check
1258
 * @return bool Success
1259
 */
1260
function isUuid($check)
1261
{
1262
    $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}$/';
1263
    return preg_match($regex, $check) === 1;
1264
}
1265
1266
1267
/**
1268
 * Validates a geographic coordinate.
1269
 *
1270
 * Supported formats:
1271
 *
1272
 * - `<latitude>, <longitude>` Example: `-25.274398, 133.775136`
1273
 *
1274
 * ### Options
1275
 *
1276
 * - `type` - A string of the coordinate format, right now only `latLong`.
1277
 * - `format` - By default `both`, can be `long` and `lat` as well to validate
1278
 *   only a part of the coordinate.
1279
 *
1280
 * @param string $value Geographic location as string
1281
 * @param array $options Options for the validation logic.
1282
 * @return bool|Exception
1283
 */
1284
function isGeoCoordinate($value, array $options = [])
1285
{
1286
    $_pattern = [
1287
        'latitude' => '[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?)',
1288
        'longitude' => '[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)',
1289
    ];
1290
1291
    $options += [
1292
        'format' => 'both',
1293
        'type' => 'latLong'
1294
    ];
1295
    if ($options['type'] !== 'latLong') {
1296
        throw new RuntimeException(sprintf(
1297
            'Unsupported coordinate type "%s". Use "latLong" instead.',
1298
            $options['type']
1299
        ));
1300
    }
1301
    $pattern = '/^' . $_pattern['latitude'] . ',\s*' . $_pattern['longitude'] . '$/';
1302
    if ($options['format'] === 'long') {
1303
        $pattern = '/^' . $_pattern['longitude'] . '$/';
1304
    }
1305
    if ($options['format'] === 'lat') {
1306
        $pattern = '/^' . $_pattern['latitude'] . '$/';
1307
    }
1308
    return (bool)preg_match($pattern, $value);
1309
}
1310
1311
/**
1312
 * Convenience method for latitude validation.
1313
 *
1314
 * @param string $value Latitude as string
1315
 * @param array $options Options for the validation logic.
1316
 * @return bool
1317
 * @link https://en.wikipedia.org/wiki/Latitude
1318
 * @see \Cake\Validation\Validation::geoCoordinate()
1319
 */
1320
function isLatitude($value, array $options = [])
1321
{
1322
    $options['format'] = 'lat';
1323
    return isGeoCoordinate($value, $options);
1324
}
1325
1326
/**
1327
 * Convenience method for longitude validation.
1328
 *
1329
 * @param string $value Latitude as string
1330
 * @param array $options Options for the validation logic.
1331
 * @return bool
1332
 * @link https://en.wikipedia.org/wiki/Longitude
1333
 * @see \Cake\Validation\Validation::geoCoordinate()
1334
 */
1335
function isLongitude($value, array $options = []): bool
1336
{
1337
    $options['format'] = 'long';
1338
    return isGeoCoordinate($value, $options);
1339
}
1340
1341
/**
1342
 * Check that the input value is within the ascii byte range.
1343
 *
1344
 * This method will reject all non-string values.
1345
 *
1346
 * @param string $value The value to check
1347
 * @return bool
1348
 */
1349
function isAscii($value)
1350
{
1351
    if (!is_string($value)) {
1352
        return false;
1353
    }
1354
    return strlen($value) <= mb_strlen($value, 'utf-8');
1355
}
1356
1357
/**
1358
 * Check that the input value is a utf8 string.
1359
 *
1360
 * This method will reject all non-string values.
1361
 *
1362
 * # Options
1363
 *
1364
 * - `extended` - Disallow bytes higher within the basic multilingual plane.
1365
 *   MySQL's older utf8 encoding type does not allow characters above
1366
 *   the basic multilingual plane. Defaults to false.
1367
 *
1368
 * @param string $value The value to check
1369
 * @param array $options An array of options. See above for the supported options.
1370
 * @return bool
1371
 */
1372
function isUtf8($value, array $options = []): bool
1373
{
1374
    if (!is_string($value)) {
1375
        return false;
1376
    }
1377
    $options += ['extended' => false];
1378
    if ($options['extended']) {
1379
        return true;
1380
    }
1381
    return preg_match('/[\x{10000}-\x{10FFFF}]/u', $value) === 0;
1382
}
1383