Subversion Repositories oidplus

Rev

Rev 635 | Rev 686 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/**
4
 * WEID<=>OID Converter
5
 * (c) Webfan.de, ViaThinkSoft
683 daniel-mar 6
 * Revision 2021-12-08
635 daniel-mar 7
 **/
8
 
683 daniel-mar 9
// What is a WEID?
10
//     A WEID (WEhowski IDentifier) is an alternative representation of an
11
//     OID (Object IDentifier) defined by Till Wehowski.
12
//     In OIDs, arcs are in decimal base 10. In WEIDs, the arcs are in base 36.
13
//     Also, each WEID has a check digit at the end (called WeLohn Check Digit).
14
//
15
// Changes in the December 2021 definition by Daniel Marschall:
16
//     - There are several classes of WEIDs which have different OID bases:
17
//           "Class C" WEID:  weid:EXAMPLE-3      (base .1.3.6.1.4.1.37553.8.)
18
//                            oid:1.3.6.1.4.1.37553.8.32488192274
19
//           "Class B" WEID:  weid:pen:SX0-7PR-6  (base .1.3.6.1.4.1.)
20
//                            oid:1.3.6.1.4.1.37476.9999
21
//           "Class A" WEID:  weid:root:2-RR-2    (base .)
22
//                            oid:2.999
23
//     - The namespace (weid:, weid:pen:, weid:root:) is now case insensitive.
24
//     - Padding with '0' characters is valid (e.g. weid:000EXAMPLE-3)
25
//       The paddings do not count into the WeLuhn check-digit.
26
 
635 daniel-mar 27
class WeidOidConverter {
28
 
29
        protected static function weLuhnGetCheckDigit($str) {
683 daniel-mar 30
 
31
                // Padding zeros don't count to the check digit (December 2021)
32
                $ary = explode('-', $str);
33
                foreach ($ary as &$a) $a = ltrim($a, '0');
34
                $str = implode('-', $ary);
35
 
635 daniel-mar 36
                $wrkstr = str_replace('-', '', $str); // remove separators
37
                for ($i=0; $i<36; $i++) {
38
                        $wrkstr = str_ireplace(chr(ord('a')+$i), (string)($i+10), $wrkstr);
39
                }
40
                $nbdigits = strlen($wrkstr);
41
                $parity = $nbdigits & 1;
42
                $sum = 0;
43
                for ($n=$nbdigits-1; $n>=0; $n--) {
44
                        $digit = $wrkstr[$n];
45
                        if (($n & 1) != $parity) $digit *= 2;
46
                        if ($digit > 9) $digit -= 9;
47
                        $sum += $digit;
48
                }
49
                return ($sum%10) == 0 ? 0 : 10-($sum%10);
50
        }
51
 
683 daniel-mar 52
        // Translates a weid to an oid
53
        // "weid:EXAMPLE-3" becomes "1.3.6.1.4.1.37553.8.32488192274"
54
        // If it failed (e.g. wrong namespace, wrong checksum, etc.) then false is returned.
55
        // If the weid ends with '?', then it will be replaced with the checksum,
56
        // e.g. weid:EXAMPLE-? becomes weid:EXAMPLE-3
57
        public static function weid2oid(&$weid) {
635 daniel-mar 58
 
683 daniel-mar 59
                $p = strrpos($weid,':');
60
                $namespace = substr($weid, 0, $p+1);
61
                $rest = substr($weid, $p+1);
62
 
63
                $namespace = strtolower($namespace); // namespace is case insensitive
64
                if ($namespace == 'weid:') {
65
                        // Class C
66
                        $base = '1-3-6-1-4-1-SZ5-8';
67
                } else if ($namespace == 'weid:pen:') {
68
                        // Class B
69
                        $base = '1-3-6-1-4-1';
70
                } else if ($namespace == 'weid:root:') {
71
                        // Class A
72
                        $base = '';
73
                } else {
74
                        // Wrong namespace
75
                        return false;
76
                }
77
 
78
                $weid = $rest;
79
 
80
                $elements = array_merge(($base != '') ? explode('-', $base) : array(), explode('-', $weid));
635 daniel-mar 81
                $actual_checksum = array_pop($elements);
82
                $expected_checksum = self::weLuhnGetCheckDigit(implode('-',$elements));
83
                if ($actual_checksum != '?') {
84
                        if ($actual_checksum != $expected_checksum) return false; // wrong checksum
85
                } else {
86
                        // If checksum is '?', it will be replaced by the actual checksum,
87
                        // e.g. weid:EXAMPLE-? becomes weid:EXAMPLE-3
88
                        $weid = str_replace('?', $expected_checksum, $weid);
89
                }
90
                foreach ($elements as &$arc) {
91
                        //$arc = strtoupper(base_convert($arc, 36, 10));
92
                        $arc = strtoupper(self::base_convert_bigint($arc, 36, 10));
93
                }
94
                $oidstr = implode('.', $elements);
95
 
683 daniel-mar 96
                $weid = $namespace . $weid; // add namespace again
97
 
635 daniel-mar 98
                return $oidstr;
99
        }
100
 
683 daniel-mar 101
        // Converts an OID to WEID
102
        // "1.3.6.1.4.1.37553.8.32488192274" becomes "weid:EXAMPLE-3"
103
        public static function oid2weid($oid) {
104
                if (substr($oid,0,1) === '.') $oid = substr($oid,1); // remove leading dot
105
 
106
                if ($oid !== '') {
107
                        $elements = explode('.', $oid);
108
                        foreach ($elements as &$arc) {
109
                                //$arc = strtoupper(base_convert($arc, 10, 36));
110
                                $arc = strtoupper(self::base_convert_bigint($arc, 10, 36));
111
                        }
112
                        $weidstr = implode('-', $elements);
113
                } else {
114
                        $weidstr = '';
635 daniel-mar 115
                }
116
 
683 daniel-mar 117
                $is_class_c = (strpos($weidstr, '1-3-6-1-4-1-SZ5-8-') === 0) ||
118
                              ($weidstr === '1-3-6-1-4-1-SZ5-8');
119
                $is_class_b = ((strpos($weidstr, '1-3-6-1-4-1-') === 0) ||
120
                              ($weidstr === '1-3-6-1-4-1'))
121
                              && !$is_class_c;
122
                $is_class_a = !$is_class_b && !$is_class_c;
635 daniel-mar 123
 
683 daniel-mar 124
                $checksum = self::weLuhnGetCheckDigit($weidstr);
125
 
126
                if ($is_class_c) {
127
                        $weidstr = substr($weidstr, strlen('1-3-6-1-4-1-SZ5-8-'));
128
                        $namespace = 'weid:';
129
                } else if ($is_class_b) {
130
                        $weidstr = substr($weidstr, strlen('1-3-6-1-4-1-'));
131
                        $namespace = 'weid:pen:';
132
                } else if ($is_class_a) {
133
                        // $weidstr stays
134
                        $namespace = 'weid:root:';
135
                }
136
 
137
                return $namespace . ($weidstr == '' ? $checksum : $weidstr . '-' . $checksum);
635 daniel-mar 138
        }
139
 
140
        protected static function base_convert_bigint($numstring, $frombase, $tobase) {
141
                $frombase_str = '';
142
                for ($i=0; $i<$frombase; $i++) {
143
                        $frombase_str .= strtoupper(base_convert((string)$i, 10, 36));
144
                }
145
 
146
                $tobase_str = '';
147
                for ($i=0; $i<$tobase; $i++) {
148
                        $tobase_str .= strtoupper(base_convert((string)$i, 10, 36));
149
                }
150
 
151
                $length = strlen($numstring);
152
                $result = '';
153
                $number = array();
154
                for ($i = 0; $i < $length; $i++) {
155
                        $number[$i] = stripos($frombase_str, $numstring[$i]);
156
                }
157
                do { // Loop until whole number is converted
158
                        $divide = 0;
159
                        $newlen = 0;
160
                        for ($i = 0; $i < $length; $i++) { // Perform division manually (which is why this works with big numbers)
161
                                $divide = $divide * $frombase + $number[$i];
162
                                if ($divide >= $tobase) {
163
                                        $number[$newlen++] = (int)($divide / $tobase);
164
                                        $divide = $divide % $tobase;
165
                                } else if ($newlen > 0) {
166
                                        $number[$newlen++] = 0;
167
                                }
168
                        }
169
                        $length = $newlen;
170
                        $result = $tobase_str[$divide] . $result; // Divide is basically $numstring % $tobase (i.e. the new character)
171
                }
172
                while ($newlen != 0);
173
 
174
                return $result;
175
        }
176
}
177
 
178
 
683 daniel-mar 179
# --- Usage Example ---
180
 
635 daniel-mar 181
/*
683 daniel-mar 182
echo "Class C tests:\n\n";
635 daniel-mar 183
 
683 daniel-mar 184
var_dump($oid = '1.3.6.1.4.1.37553.8')."\n";
185
var_dump(WeidOidConverter::oid2weid($oid))."\n";
186
$weid = 'weid:?';
187
var_dump(WeidOidConverter::weid2oid($weid))."\n";
188
var_dump($weid)."\n";
189
echo "\n";
635 daniel-mar 190
 
683 daniel-mar 191
var_dump($oid = '1.3.6.1.4.1.37553.8.32488192274')."\n";
192
var_dump(WeidOidConverter::oid2weid($oid))."\n";
193
$weid = 'weid:EXAMPLE-?';
194
var_dump(WeidOidConverter::weid2oid($weid))."\n";
195
var_dump($weid)."\n";
196
$weid = 'weid:00000example-?';
197
var_dump(WeidOidConverter::weid2oid($weid))."\n";
198
var_dump($weid)."\n";
199
echo "\n";
635 daniel-mar 200
 
683 daniel-mar 201
echo "Class B tests:\n\n";
635 daniel-mar 202
 
683 daniel-mar 203
var_dump($oid = '1.3.6.1.4.1')."\n";
204
var_dump(WeidOidConverter::oid2weid($oid))."\n";
205
$weid = 'weid:pen:?';
206
var_dump(WeidOidConverter::weid2oid($weid))."\n";
207
var_dump($weid)."\n";
208
echo "\n";
635 daniel-mar 209
 
683 daniel-mar 210
var_dump($oid = '1.3.6.1.4.1.37553.7.99.99.99')."\n";
211
var_dump(WeidOidConverter::oid2weid($oid))."\n";
212
$weid = 'weid:pen:SZ5-7-2R-2R-2R-?';
213
var_dump(WeidOidConverter::weid2oid($weid))."\n";
214
var_dump($weid)."\n";
215
$weid = 'weid:pen:000SZ5-7-02R-00002R-002r-?';
216
var_dump(WeidOidConverter::weid2oid($weid))."\n";
217
var_dump($weid)."\n";
218
echo "\n";
219
 
220
var_dump($oid = '1.3.6.1.4.1.37476.9999')."\n";
221
var_dump(WeidOidConverter::oid2weid($oid))."\n";
222
$weid = 'weid:pen:SX0-7PR-?';
223
var_dump(WeidOidConverter::weid2oid($weid))."\n";
224
var_dump($weid)."\n";
225
echo "\n";
226
 
227
echo "Class A tests:\n\n";
228
 
229
var_dump($oid = '')."\n";
230
var_dump(WeidOidConverter::oid2weid($oid))."\n";
231
$weid = 'weid:root:?';
232
var_dump(WeidOidConverter::weid2oid($weid))."\n";
233
var_dump($weid)."\n";
234
echo "\n";
235
 
236
var_dump($oid = '.2.999')."\n";
237
var_dump(WeidOidConverter::oid2weid($oid))."\n";
238
$weid = 'weid:root:2-RR-?';
239
var_dump(WeidOidConverter::weid2oid($weid))."\n";
240
var_dump($weid)."\n";
241
echo "\n";
242
 
243
var_dump($oid = '2.999')."\n";
244
var_dump(WeidOidConverter::oid2weid($oid))."\n";
245
$weid = 'weid:root:2-RR-?';
246
var_dump(WeidOidConverter::weid2oid($weid))."\n";
247
var_dump($weid)."\n";
248
echo "\n";
635 daniel-mar 249
*/