Completed
Push — master ( 0d1453...1e6b86 )
by Lorenzo
06:29
created

validation.php ➔ isEuVatNumber()   D

Complexity

Conditions 10
Paths 17

Size

Total Lines 33
Code Lines 20

Duplication

Lines 8
Ratio 24.24 %

Importance

Changes 0
Metric Value
cc 10
eloc 20
nc 17
nop 2
dl 8
loc 33
rs 4.8196
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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