Completed
Push — master ( d76c96...324acd )
by Mohamed
15s queued 12s
created

UniqueUid::CodePointFromCharacter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Lsf\UniqueUid;
4
5
class UniqueUid
6
{
7
    static $charSet;
8
    static $maxCharLen;
9
10
    public function __construct()
11
    {
12
        self::$charSet = '2346789BCDFGHJKMPQRTVWXY';
13
        self::$maxCharLen = strlen(self::$charSet);
14
    }
15
16
    /**
17
     * set custom charset for the Unique ID
18
     *
19
     * @param string $characters
20
     * @return void
21
     */
22
    public function setCharSet($characters)
23
    {
24
        self::$charSet = $characters;
25
        $this->setCharLen($characters);
26
    }
27
28
    /**
29
     * Set charset Len
30
     *
31
     * @param string $characters
32
     * @return void
33
     */
34
    public function setCharLen($characters)
35
    {
36
        self::$maxCharLen = strlen($characters);
37
    }
38
39
    /**
40
     * TO the the Code Point form the Character set
41
     *
42
     * @param string $character
43
     * @return integer
44
     */
45
    public static function CodePointFromCharacter($character)
46
    {
47
        $characters = array_flip(str_split(self::$charSet));
48
        return $characters[$character];
49
    }
50
51
    /**
52
     * Get the Character set form the Code Point
53
     *
54
     * @param integer $codePoint
55
     * @return string
56
     */
57
    public static function CharacterFromCodePoint($codePoint)
58
    {
59
        $characters = str_split(self::$charSet);
60
        return $characters[$codePoint];
61
    }
62
63
    /**
64
     * Get the number of Valid characters for Check digit
65
     *
66
     * @return void
67
     */
68
    public static function NumberOfValidCharacters()
69
    {
70
        return strlen(self::$charSet);
71
    }
72
73
    /**
74
     * This function will pass values to random generator.
75
     * Our function has 1 digit to 25 options
76
     * @length integer - length of expected 
77
     * @split integer - split range
78
     * @return string
79
     **/
80
    public static function getUniqueAlphanumeric(int $length = 9, int $split = 3)
81
    {
82
        $token = "";
83
84
        // adjust the check digit place
85
        $length = $length - 1;
86
87
        for ($i = 0; $i < $length; $i++) {
88
            $token .= self::$charSet[random_int(0, self::$maxCharLen - 1)];
89
        }
90
91
        $checkChar = self::GenerateCheckCharacter($token);
92
        $token .= $checkChar;
93
        $token  = self::format($token, $split);
94
        return $token;
95
    }
96
97
    /**
98
     * Format the ID with given split range
99
     *
100
     * @param string $token
101
     * @return integer
102
     */
103
    public  static function format(string $token, int $split)
104
    {
105
        $partitions = str_split($token, $split);
106
        $length = count($partitions);
107
        $newToken = '';
108
        for ($i = 0; $i < $length; $i++) {
109
            $newToken .= '-' . $partitions[$i];
110
        }
111
        return ltrim(rtrim(substr($newToken, 1, strlen($newToken)), '-'));
112
    }
113
114
    /**
115
     * Check the valid ID
116
     *
117
     * @param string $token
118
     * @return boolean
119
     */
120
    public static function isValidUniqueId(string $token, $validLength = 9, $split = 3)
121
    {
122
        $actualLength = strlen($token);
123
124
        $equalSplit = ($validLength % $split) ==  0 ? true : false;
125
126
        //calculate valid string length
127
        $validActualLength =  $equalSplit ? (($validLength + ($split - 1))) : (($validLength + $split));
128
129
        //remove - form the token
130
        $token = str_replace("-", "", $token);
131
132
        // get the length of the token
133
        $length = strlen($token);
134
135
        // validate the character set
136
        $valid = preg_match("/^[" . self::$charSet . "]+$/", $token);
137
138
        //validate formatted length
139
        if ($actualLength != $validActualLength) {
140
            return false;
141
        //validate un formatted length
142
        } elseif ($validLength != $length) {
143
            return false;
144
        //validate charset
145
        } elseif (!$valid) {
146
            return false;
147
        //validate 100 % numeric NSID    
148
        } elseif (is_numeric($token)) {
149
            return false;
150
        //validate check digit    
151
        } else {
152
            //get the check character from the token
153
            $checkChar = str_split($token)[$length - 1];
154
155
            // remove the check digit from the token
156
            $token = substr($token, 0, -1);
157
158
            // get the valid check character
159
            $ValidCheckChar = self::GenerateCheckCharacter($token);
160
            return $checkChar == $ValidCheckChar;
161
        }
162
    }
163
164
    /**
165
     * Luhn mod N algorithm
166
     * @input string $token
167
     * @return string
168
     **/
169
    public static function GenerateCheckCharacter(string $token)
170
    {
171
        $length = strlen($token) - 1;
172
        $factor = 2;
173
        $total_sum = 0;
174
        $n = self::NumberOfValidCharacters();
175
176
        // Starting from the right and working leftwards is easier since
177
        // the initial "factor" will always be "2".
178
        for ($i = ($length); $i >= 0; --$i) {
179
            $codePoint = self::codePointFromCharacter($token[$i]);
180
            $added = $factor * $codePoint;
181
182
            // Alternate the "factor" that each "codePoint" is multiplied by
183
            $factor = ($factor == 2) ? 1 : 2;
184
185
            // Sum the digits of the "addend" as expressed in base "n"
186
            $added = ($added / $n) + ($added % $n);
187
            $total_sum += $added;
188
        }
189
190
        // Calculate the number that must be added to the "sum"
191
        // to make it divisible by "n".
192
        $reminder = $total_sum % $n;
193
        $checkCodePoint  = ($n - $reminder) % $n;
194
        return  self::CharacterFromCodePoint($checkCodePoint);
195
    }
196
}
197