Passed
Push — master ( 402f33...7c44c5 )
by Pol
02:04
created

BelgianNationalNumberValidator::isValid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace drupol\BelgianNationalNumberFaker\Validator;
6
7
/**
8
 * Class BelgianNationalNumberValidator.
9
 */
10
final class BelgianNationalNumberValidator
11
{
12
    /**
13
     * Validates a Belgian identification number.
14
     *
15
     * @param string $id
16
     *   The number.
17
     *
18
     * @return bool
19
     *   True if valid, false otherwise.
20
     */
21 2
    public static function isValid(string $id): bool
22
    {
23 2
        return static::isValidNationalNumber($id);
24
    }
25
26
    /**
27
     * Check if the number is a valid national number.
28
     *
29
     * @param string $national_number
30
     *   The number.
31
     *
32
     * @return bool
33
     *   True if validated, false otherwise.
34
     */
35 2
    private static function isValidNationalNumber(string $national_number): bool
36
    {
37 2
        $national_number = \filter_var($national_number, \FILTER_SANITIZE_NUMBER_INT);
38
39 2
        if (false === $national_number) {
40
            return false;
41
        }
42
43 2
        $allowedCharactersPattern = '/^[0-9\\ \\-]+$/';
44 2
        $nonNumericPattern = '/\\D/';
45
46 2
        if (1 !== \preg_match($allowedCharactersPattern, $national_number)) {
47 1
            return false;
48
        }
49
50 2
        $national_number = \preg_replace($nonNumericPattern, '', $national_number);
51
52 2
        if (null === $national_number) {
53
            return false;
54
        }
55
56 2
        if (11 !== \mb_strlen($national_number)) {
57 1
            return false;
58
        }
59
60 2
        $birthDatePart = (int) \mb_substr($national_number, 0, 6);
61 2
        $counterPart = (int) \mb_substr($national_number, 6, 3);
62 2
        $controlPart = (int) \mb_substr($national_number, 9, 2);
63
64
        // 1. CONTROL NUMBER CHECKING
65 2
        $born2kOrLater = false;
66 2
        $calculatedControl = 97 - (($birthDatePart . $counterPart) % 97);
67
68 2
        if ($calculatedControl !== $controlPart) {
69 2
            $born2kOrLater = true;
70 2
            $calculatedControl = 97 - (('2' . $birthDatePart . $counterPart) % 97);
71
72 2
            if ($calculatedControl !== $controlPart) {
73 2
                return false;
74
            }
75
        }
76
77
        // 2. BIRTHDATE CHECKING
78 2
        $birthDate = true === $born2kOrLater ?
79 2
            '20' . $birthDatePart :
80 2
            '19' . $birthDatePart;
81
82 2
        if (!\checkdate(
83 2
            (int) \mb_substr($birthDate, 4, 2),
84 2
            (int) \mb_substr($birthDate, 6, 2),
85 2
            (int) \mb_substr($birthDate, 0, 4)
86
        )
87
        ) {
88
            return false;
89
        }
90
91
        // 3. COUNTER CHECKING
92 2
        if (1 > $counterPart || 997 < $counterPart) {
93
            return false;
94
        }
95
96 2
        return true;
97
    }
98
}
99