Rev 24 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 24 | Rev 86 | ||
---|---|---|---|
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * OID-Utilities for PHP |
4 | * OID-Utilities for PHP |
5 | * Copyright 2011-2022 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2011 - 2023 Daniel Marschall, ViaThinkSoft |
6 | * Version 2022-01-07 |
6 | * Version 2023-08-25 |
7 | * |
7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | * you may not use this file except in compliance with the License. |
9 | * you may not use this file except in compliance with the License. |
10 | * You may obtain a copy of the License at |
10 | * You may obtain a copy of the License at |
11 | * |
11 | * |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | * |
13 | * |
14 | * Unless required by applicable law or agreed to in writing, software |
14 | * Unless required by applicable law or agreed to in writing, software |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | * See the License for the specific language governing permissions and |
17 | * See the License for the specific language governing permissions and |
18 | * limitations under the License. |
18 | * limitations under the License. |
19 | */ |
19 | */ |
20 | 20 | ||
21 | // All functions in this library are compatible with leading zeroes (not recommended) and leading dots |
21 | // All functions in this library are compatible with leading zeroes (not recommended) and leading dots |
22 | 22 | ||
23 | // TODO: change some function names, so that they have a uniform naming schema, and rename "oid identifier" into "ASN.1 alphanumeric identifier" |
23 | // TODO: change some function names, so that they have a uniform naming schema, and rename "oid identifier" into "ASN.1 alphanumeric identifier" |
24 | // oid_id_is_valid() => asn1_alpha_id_valid() |
24 | // oid_id_is_valid() => asn1_alpha_id_valid() |
25 | 25 | ||
26 | define('OID_DOT_FORBIDDEN', 0); |
26 | define('OID_DOT_FORBIDDEN', 0); |
27 | define('OID_DOT_OPTIONAL', 1); |
27 | define('OID_DOT_OPTIONAL', 1); |
28 | define('OID_DOT_REQUIRED', 2); |
28 | define('OID_DOT_REQUIRED', 2); |
29 | 29 | ||
30 | /** |
30 | /** |
31 | * Checks if an OID has a valid dot notation. |
31 | * Checks if an OID has a valid dot notation. |
32 | * @author Daniel Marschall, ViaThinkSoft |
32 | * @author Daniel Marschall, ViaThinkSoft |
33 | * @version 2014-12-09 |
33 | * @version 2014-12-09 |
34 | * @param string $oid<br/> |
34 | * @param string $oid<br/> |
35 | * An OID in dot notation. |
35 | * An OID in dot notation. |
36 | * @param boolean $allow_leading_zeroes<br/> |
36 | * @param boolean $allow_leading_zeroes<br/> |
37 | * true of leading zeroes are allowed or not. |
37 | * true of leading zeroes are allowed or not. |
38 | * @param boolean $allow_leading_dot<br/> |
38 | * @param boolean $allow_leading_dot<br/> |
39 | * true of leading dots are allowed or not. |
39 | * true of leading dots are allowed or not. |
40 | * @return boolean true if the dot notation is valid. |
40 | * @return boolean true if the dot notation is valid. |
41 | **/ |
41 | **/ |
42 | function oid_valid_dotnotation($oid, $allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
42 | function oid_valid_dotnotation($oid, $allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
43 | $regex = oid_validation_regex($allow_leading_zeroes, $allow_leading_dot, $min_len); |
43 | $regex = oid_validation_regex($allow_leading_zeroes, $allow_leading_dot, $min_len); |
44 | 44 | ||
45 | $m = array(); |
45 | $m = array(); |
46 | return preg_match($regex, $oid, $m) ? true : false; |
46 | return preg_match($regex, $oid, $m) ? true : false; |
47 | } |
47 | } |
48 | 48 | ||
49 | /** |
49 | /** |
50 | * Returns a full regular expression to validate an OID in dot-notation |
50 | * Returns a full regular expression to validate an OID in dot-notation |
51 | * @author Daniel Marschall, ViaThinkSoft |
51 | * @author Daniel Marschall, ViaThinkSoft |
52 | * @version 2014-12-09 |
52 | * @version 2014-12-09 |
53 | * @param boolean $allow_leading_zeroes<br/> |
53 | * @param boolean $allow_leading_zeroes<br/> |
54 | * true of leading zeroes are allowed or not. |
54 | * true of leading zeroes are allowed or not. |
55 | * @param boolean $allow_leading_dot<br/> |
55 | * @param boolean $allow_leading_dot<br/> |
56 | * true of leading dots are allowed or not. |
56 | * true of leading dots are allowed or not. |
57 | * @return string The regular expression |
57 | * @return string The regular expression |
58 | **/ |
58 | **/ |
59 | function oid_validation_regex($allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
59 | function oid_validation_regex($allow_leading_zeroes=true, $allow_leading_dot=false, $min_len=0) { |
60 | $leading_dot_policy = $allow_leading_dot ? OID_DOT_OPTIONAL : OID_DOT_FORBIDDEN; |
60 | $leading_dot_policy = $allow_leading_dot ? OID_DOT_OPTIONAL : OID_DOT_FORBIDDEN; |
61 | 61 | ||
62 | $part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
62 | $part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
63 | 63 | ||
64 | return '@^'.$part_regex.'$@'; |
64 | return '@^'.$part_regex.'$@'; |
65 | } |
65 | } |
66 | 66 | ||
67 | /** |
67 | /** |
68 | * Returns a partial regular expression which matches valid OIDs in dot notation. |
68 | * Returns a partial regular expression which matches valid OIDs in dot notation. |
69 | * It can be inserted into regular expressions. |
69 | * It can be inserted into regular expressions. |
70 | * @author Daniel Marschall, ViaThinkSoft |
70 | * @author Daniel Marschall, ViaThinkSoft |
71 | * @version 2014-12-09 |
71 | * @version 2014-12-09 |
72 | * @param int $min_len<br/> |
72 | * @param int $min_len<br/> |
73 | * 0="." and greater will be recognized, but not ""<br/> |
73 | * 0="." and greater will be recognized, but not ""<br/> |
74 | * 1=".2" and greater will be recognized<br/> |
74 | * 1=".2" and greater will be recognized<br/> |
75 | * 2=".2.999" and greater will be recognized (default)<br/> |
75 | * 2=".2.999" and greater will be recognized (default)<br/> |
76 | * etc. |
76 | * etc. |
77 | * @param boolean $allow_leading_zeroes<br/> |
77 | * @param boolean $allow_leading_zeroes<br/> |
78 | * true: ".2.0999" will be recognized<br/> |
78 | * true: ".2.0999" will be recognized<br/> |
79 | * false: ".2.0999" won't be recognized (default) |
79 | * false: ".2.0999" won't be recognized (default) |
80 | * @param int $leading_dot_policy<br/> |
80 | * @param int $leading_dot_policy<br/> |
81 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
81 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
82 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
82 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
83 | * 2 (OID_DOT_REQUIRED) : enforced |
83 | * 2 (OID_DOT_REQUIRED) : enforced |
84 | * @return string|false A regular expression which matches OIDs in dot notation |
84 | * @return string|false A regular expression which matches OIDs in dot notation |
85 | **/ |
85 | **/ |
86 | function oid_part_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL) { |
86 | function oid_part_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL) { |
87 | switch ($leading_dot_policy) { |
87 | switch ($leading_dot_policy) { |
88 | case 0: // forbidden |
88 | case 0: // forbidden |
89 | $lead_dot = ''; |
89 | $lead_dot = ''; |
90 | break; |
90 | break; |
91 | case 1: // optional |
91 | case 1: // optional |
92 | $lead_dot = '\\.{0,1}'; |
92 | $lead_dot = '\\.{0,1}'; |
93 | break; |
93 | break; |
94 | case 2: // enforced |
94 | case 2: // enforced |
95 | $lead_dot = '\\.'; |
95 | $lead_dot = '\\.'; |
96 | break; |
96 | break; |
97 | default: |
97 | default: |
98 | assert(false); |
98 | assert(false); |
99 | return false; |
99 | return false; |
100 | } |
100 | } |
101 | 101 | ||
102 | $lead_zero = $allow_leading_zeroes ? '0*' : ''; |
102 | $lead_zero = $allow_leading_zeroes ? '0*' : ''; |
103 | $zero_till_thirtynine = '(([0-9])|([1-3][0-9]))'; // second arc is limited to 0..39 if root arc is 0..1 |
103 | $zero_till_thirtynine = '(([0-9])|([1-3][0-9]))'; // second arc is limited to 0..39 if root arc is 0..1 |
104 | $singledot_option = ($min_len == 0) && ($leading_dot_policy != OID_DOT_FORBIDDEN) ? '|\\.' : ''; |
104 | $singledot_option = ($min_len == 0) && ($leading_dot_policy != OID_DOT_FORBIDDEN) ? '|\\.' : ''; |
105 | $only_root_option = ($min_len <= 1) ? '|('.$lead_dot.$lead_zero.'[0-2])' : ''; |
105 | $only_root_option = ($min_len <= 1) ? '|('.$lead_dot.$lead_zero.'[0-2])' : ''; |
106 | 106 | ||
107 | $regex = ' |
107 | $regex = ' |
108 | ( |
108 | ( |
109 | ( |
109 | ( |
110 | ( |
110 | ( |
111 | ('.$lead_dot.$lead_zero.'[0-1]) |
111 | ('.$lead_dot.$lead_zero.'[0-1]) |
112 | \\.'.$lead_zero.$zero_till_thirtynine.' |
112 | \\.'.$lead_zero.$zero_till_thirtynine.' |
113 | (\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-2).',} |
113 | (\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-2).',} |
114 | )|( |
114 | )|( |
115 | ('.$lead_dot.$lead_zero.'[2]) |
115 | ('.$lead_dot.$lead_zero.'[2]) |
116 | (\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-1).',} |
116 | (\\.'.$lead_zero.'(0|[1-9][0-9]*)){'.max(0, $min_len-1).',} |
117 | ) |
117 | ) |
118 | '.$only_root_option.' |
118 | '.$only_root_option.' |
119 | '.$singledot_option.' |
119 | '.$singledot_option.' |
120 | ) |
120 | ) |
121 | )'; |
121 | )'; |
122 | 122 | ||
123 | // Remove the indentations which are used to maintain this large regular expression in a human friendly way |
123 | // Remove the indentations which are used to maintain this large regular expression in a human friendly way |
124 | $regex = str_replace("\n", '', $regex); |
124 | $regex = str_replace("\n", '', $regex); |
125 | $regex = str_replace("\r", '', $regex); |
125 | $regex = str_replace("\r", '', $regex); |
126 | $regex = str_replace("\t", '', $regex); |
126 | $regex = str_replace("\t", '', $regex); |
127 | $regex = str_replace(' ', '', $regex); |
127 | $regex = str_replace(' ', '', $regex); |
128 | 128 | ||
129 | return $regex; |
129 | return $regex; |
130 | } |
130 | } |
131 | 131 | ||
132 | /** |
132 | /** |
133 | * Searches all OIDs in $text and outputs them as array. |
133 | * Searches all OIDs in $text and outputs them as array. |
134 | * @author Daniel Marschall, ViaThinkSoft |
134 | * @author Daniel Marschall, ViaThinkSoft |
135 | * @version 2014-12-09 |
135 | * @version 2014-12-09 |
136 | * @param string $text<br/> |
136 | * @param string $text<br/> |
137 | * The text to be parsed |
137 | * The text to be parsed |
138 | * @param int $min_len<br/> |
138 | * @param int $min_len<br/> |
139 | * 0="." and greater will be recognized, but not ""<br/> |
139 | * 0="." and greater will be recognized, but not ""<br/> |
140 | * 1=".2" and greater will be recognized<br/> |
140 | * 1=".2" and greater will be recognized<br/> |
141 | * 2=".2.999" and greater will be recognized (default)<br/> |
141 | * 2=".2.999" and greater will be recognized (default)<br/> |
142 | * etc. |
142 | * etc. |
143 | * @param boolean $allow_leading_zeroes<br/> |
143 | * @param boolean $allow_leading_zeroes<br/> |
144 | * true: ".2.0999" will be recognized<br/> |
144 | * true: ".2.0999" will be recognized<br/> |
145 | * false: ".2.0999" won't be recognized (default) |
145 | * false: ".2.0999" won't be recognized (default) |
146 | * @param int $leading_dot_policy<br/> |
146 | * @param int $leading_dot_policy<br/> |
147 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
147 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
148 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
148 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
149 | * 2 (OID_DOT_REQUIRED) : enforced |
149 | * 2 (OID_DOT_REQUIRED) : enforced |
150 | * @param boolean $requires_whitespace_delimiters<br/> |
150 | * @param boolean $requires_whitespace_delimiters<br/> |
151 | * true: "2.999" will be recognized, as well as " 2.999 " (default)<br/> |
151 | * true: "2.999" will be recognized, as well as " 2.999 " (default)<br/> |
152 | * false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
152 | * false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
153 | * @return string[] An array of OIDs in dot notation |
153 | * @return string[] An array of OIDs in dot notation |
154 | **/ |
154 | **/ |
155 | function parse_oids($text, $min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
155 | function parse_oids($text, $min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
156 | $regex = oid_detection_regex($min_len, $allow_leading_zeroes, $leading_dot_policy, $requires_whitespace_delimiters); |
156 | $regex = oid_detection_regex($min_len, $allow_leading_zeroes, $leading_dot_policy, $requires_whitespace_delimiters); |
157 | 157 | ||
158 | $matches = array(); |
158 | $matches = array(); |
159 | preg_match_all($regex, $text, $matches); |
159 | preg_match_all($regex, $text, $matches); |
160 | return $matches[1]; |
160 | return $matches[1]; |
161 | } |
161 | } |
162 | 162 | ||
163 | /** |
163 | /** |
164 | * Returns a full regular expression for detecting OIDs in dot notation inside a text. |
164 | * Returns a full regular expression for detecting OIDs in dot notation inside a text. |
165 | * @author Daniel Marschall, ViaThinkSoft |
165 | * @author Daniel Marschall, ViaThinkSoft |
166 | * @version 2014-12-09 |
166 | * @version 2014-12-09 |
167 | * @param int $min_len<br/> |
167 | * @param int $min_len<br/> |
168 | * 0="." and greater will be recognized, but not ""<br/> |
168 | * 0="." and greater will be recognized, but not ""<br/> |
169 | * 1=".2" and greater will be recognized<br/> |
169 | * 1=".2" and greater will be recognized<br/> |
170 | * 2=".2.999" and greater will be recognized (default)<br/> |
170 | * 2=".2.999" and greater will be recognized (default)<br/> |
171 | * etc. |
171 | * etc. |
172 | * @param boolean $allow_leading_zeroes<br/> |
172 | * @param boolean $allow_leading_zeroes<br/> |
173 | * true: ".2.0999" will be recognized<br/> |
173 | * true: ".2.0999" will be recognized<br/> |
174 | * false: ".2.0999" won't be recognized (default) |
174 | * false: ".2.0999" won't be recognized (default) |
175 | * @param int $leading_dot_policy<br/> |
175 | * @param int $leading_dot_policy<br/> |
176 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
176 | * 0 (OID_DOT_FORBIDDEN): forbidden<br/> |
177 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
177 | * 1 (OID_DOT_OPTIONAL) : optional (default)<br/> |
178 | * 2 (OID_DOT_REQUIRED) : enforced |
178 | * 2 (OID_DOT_REQUIRED) : enforced |
179 | * @param boolean $requires_whitespace_delimiters<br/> |
179 | * @param boolean $requires_whitespace_delimiters<br/> |
180 | * true: "2.999" will be recognized, as well as " 2.999 " (default)<br/> |
180 | * true: "2.999" will be recognized, as well as " 2.999 " (default)<br/> |
181 | * false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
181 | * false: "2.999!" will be reconigzed, as well as "2.999.c" (this might be used in in documentations with templates) |
182 | * @return string The regular expression |
182 | * @return string The regular expression |
183 | **/ |
183 | **/ |
184 | function oid_detection_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
184 | function oid_detection_regex($min_len=2, $allow_leading_zeroes=false, $leading_dot_policy=OID_DOT_OPTIONAL, $requires_whitespace_delimiters=true) { |
185 | if ($requires_whitespace_delimiters) { |
185 | if ($requires_whitespace_delimiters) { |
186 | // A fully qualified regular expression which can be used by preg_match() |
186 | // A fully qualified regular expression which can be used by preg_match() |
187 | $begin_condition = '(?<=^|\\s)'; |
187 | $begin_condition = '(?<=^|\\s)'; |
188 | $end_condition = '(?=\\s|$)'; |
188 | $end_condition = '(?=\\s|$)'; |
189 | } else { |
189 | } else { |
190 | // A partial expression which can be used inside another regular expression |
190 | // A partial expression which can be used inside another regular expression |
191 | $begin_condition = '(?<![\d])'; |
191 | $begin_condition = '(?<![\d])'; |
192 | $end_condition = '(?![\d])'; |
192 | $end_condition = '(?![\d])'; |
193 | } |
193 | } |
194 | 194 | ||
195 | $part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
195 | $part_regex = oid_part_regex($min_len, $allow_leading_zeroes, $leading_dot_policy); |
196 | 196 | ||
197 | return '@'.$begin_condition.$part_regex.$end_condition.'@'; |
197 | return '@'.$begin_condition.$part_regex.$end_condition.'@'; |
198 | } |
198 | } |
199 | 199 | ||
200 | /** |
200 | /** |
201 | * Returns the parent of an OID in dot notation or the OID itself, if it is the root.<br/> |
201 | * Returns the parent of an OID in dot notation or the OID itself, if it is the root.<br/> |
202 | * Leading dots and leading zeroes are tolerated. |
202 | * Leading dots and leading zeroes are tolerated. |
203 | * @author Daniel Marschall, ViaThinkSoft |
203 | * @author Daniel Marschall, ViaThinkSoft |
204 | * @version 2014-12-16 |
204 | * @version 2014-12-16 |
205 | * @param string $oid<br/> |
205 | * @param string $oid<br/> |
206 | * An OID in dot notation. |
206 | * An OID in dot notation. |
207 | * @return string|false The parent OID in dot notation. |
207 | * @return string|false The parent OID in dot notation. |
208 | **/ |
208 | **/ |
209 | function oid_up($oid) { |
209 | function oid_up($oid) { |
210 | $oid = sanitizeOID($oid, 'auto'); |
210 | $oid = sanitizeOID($oid, 'auto'); |
211 | if ($oid === false) return false; |
211 | if ($oid === false) return false; |
212 | 212 | ||
213 | $p = strrpos($oid, '.'); |
213 | $p = strrpos($oid, '.'); |
214 | if ($p === false) return $oid; |
214 | if ($p === false) return $oid; |
215 | if ($p == 0) return '.'; |
215 | if ($p == 0) return '.'; |
216 | 216 | ||
217 | return substr($oid, 0, $p); |
217 | return substr($oid, 0, $p); |
218 | } |
218 | } |
219 | 219 | ||
220 | /** |
220 | /** |
221 | * Outputs the depth of an OID. |
221 | * Outputs the depth of an OID. |
222 | * @author Daniel Marschall, ViaThinkSoft |
222 | * @author Daniel Marschall, ViaThinkSoft |
223 | * @version 2014-12-09 |
223 | * @version 2014-12-09 |
224 | * @param string $oid An OID in dot notation (with or without leading dot) |
224 | * @param string $oid An OID in dot notation (with or without leading dot) |
225 | * @return int The depth of the OID, e.g. 2.999 and .2.999 has the length 2. |
225 | * @return int The depth of the OID, e.g. 2.999 and .2.999 has the length 2. |
226 | **/ |
226 | **/ |
227 | function oid_len($oid) { |
227 | function oid_len($oid) { |
228 | if ($oid == '') return 0; |
228 | if ($oid == '') return 0; |
229 | if ($oid[0] == '.') $oid = substr($oid, 1); |
229 | if (substr($oid,0,1) == '.') $oid = substr($oid, 1); |
230 | return substr_count($oid, '.')+1; |
230 | return substr_count($oid, '.')+1; |
231 | } |
231 | } |
232 | function oid_depth($oid) { |
232 | function oid_depth($oid) { |
233 | return oid_len($oid); |
233 | return oid_len($oid); |
234 | } |
234 | } |
235 | 235 | ||
236 | /** |
236 | /** |
237 | * Lists all parents of an OID. |
237 | * Lists all parents of an OID. |
238 | * This function tolerates leading dots. The parent of '.' stays '.'. |
238 | * This function tolerates leading dots. The parent of '.' stays '.'. |
239 | * The OID will not be checked for validity! |
239 | * The OID will not be checked for validity! |
240 | * @author Daniel Marschall, ViaThinkSoft |
240 | * @author Daniel Marschall, ViaThinkSoft |
241 | * @version 2014-12-17 |
241 | * @version 2014-12-17 |
242 | * @param string $oid<br/> |
242 | * @param string $oid<br/> |
243 | * An OID in dot notation. |
243 | * An OID in dot notation. |
244 | * @return string[] An array with all parent OIDs. |
244 | * @return string[] An array with all parent OIDs. |
245 | **/ |
245 | **/ |
246 | function oid_parents($oid) { |
246 | function oid_parents($oid) { |
247 | $parents = array(); |
247 | $parents = array(); |
248 | 248 | ||
249 | while (oid_len($oid) > 1) { |
249 | while (oid_len($oid) > 1) { |
250 | $oid = oid_up($oid); |
250 | $oid = oid_up($oid); |
251 | $parents[] = $oid; |
251 | $parents[] = $oid; |
252 | } |
252 | } |
253 | 253 | ||
254 | if (substr($oid, 0, 1) == '.') $parents[] = '.'; |
254 | if (substr($oid, 0, 1) == '.') $parents[] = '.'; |
255 | 255 | ||
256 | return $parents; |
256 | return $parents; |
257 | } |
257 | } |
258 | 258 | ||
259 | /* |
259 | /* |
260 | assert(oid_parents('.1.2.999') == array('.1.2', '.1', '.')); |
260 | assert(oid_parents('.1.2.999') == array('.1.2', '.1', '.')); |
261 | assert(oid_parents('1.2.999') == array('1.2', '1')); |
261 | assert(oid_parents('1.2.999') == array('1.2', '1')); |
262 | assert(oid_parents('.') == array('.')); |
262 | assert(oid_parents('.') == array('.')); |
263 | assert(oid_parents('') == array()); |
263 | assert(oid_parents('') == array()); |
264 | */ |
264 | */ |
265 | 265 | ||
266 | /** |
266 | /** |
267 | * Sorts an array containing OIDs in dot notation. |
267 | * Sorts an array containing OIDs in dot notation. |
268 | * @author Daniel Marschall, ViaThinkSoft |
268 | * @author Daniel Marschall, ViaThinkSoft |
269 | * @version 2014-12-09 |
269 | * @version 2014-12-09 |
270 | * @param string[] $ary<br/> |
270 | * @param string[] $ary<br/> |
271 | * An array of OIDs in dot notation.<br/> |
271 | * An array of OIDs in dot notation.<br/> |
272 | * This array will be changed by this method. |
272 | * This array will be changed by this method. |
273 | * @param boolean $output_with_leading_dot<br/> |
273 | * @param boolean $output_with_leading_dot<br/> |
274 | * true: The array will be normalized to OIDs with a leading dot. |
274 | * true: The array will be normalized to OIDs with a leading dot. |
275 | * false: The array will be normalized to OIDs without a leading dot. (default) |
275 | * false: The array will be normalized to OIDs without a leading dot. (default) |
276 | **/ |
276 | **/ |
277 | function oidSort(&$ary, $output_with_leading_dot=false) { |
277 | function oidSort(&$ary, $output_with_leading_dot=false) { |
278 | $out = array(); |
278 | $out = array(); |
279 | 279 | ||
280 | $none = $output_with_leading_dot ? '.' : ''; |
280 | $none = $output_with_leading_dot ? '.' : ''; |
281 | 281 | ||
282 | $d = array(); |
282 | $d = array(); |
283 | $oid = null; |
283 | $oid = null; |
284 | foreach ($ary as &$oid) { |
284 | foreach ($ary as &$oid) { |
285 | if (($oid == '') || ($oid == '.')) { |
285 | if (($oid == '') || ($oid == '.')) { |
286 | $out[] = $none; |
286 | $out[] = $none; |
287 | } else { |
287 | } else { |
288 | $oid = sanitizeOID($oid, 'auto'); // strike leading zeroes |
288 | $oid = sanitizeOID($oid, 'auto'); // strike leading zeroes |
289 | $bry = explode('.', $oid, 2); |
289 | $bry = explode('.', $oid, 2); |
290 | $firstarc = $bry[0]; |
290 | $firstarc = $bry[0]; |
291 | $rest = (isset($bry[1])) ? $bry[1] : ''; |
291 | $rest = (isset($bry[1])) ? $bry[1] : ''; |
292 | $d[$firstarc][] = $rest; |
292 | $d[$firstarc][] = $rest; |
293 | } |
293 | } |
294 | } |
294 | } |
295 | unset($oid); |
295 | unset($oid); |
296 | ksort($d); |
296 | ksort($d); |
297 | 297 | ||
298 | $data = null; |
298 | $data = null; |
299 | foreach ($d as $firstarc => &$data) { |
299 | foreach ($d as $firstarc => &$data) { |
300 | oidSort($data); |
300 | oidSort($data); |
301 | foreach ($data as &$rest) { |
301 | foreach ($data as &$rest) { |
302 | $out[] = ($output_with_leading_dot ? '.' : '')."$firstarc" . (($rest != $none) ? ".$rest" : ''); |
302 | $out[] = ($output_with_leading_dot ? '.' : '')."$firstarc" . (($rest != $none) ? ".$rest" : ''); |
303 | } |
303 | } |
304 | } |
304 | } |
305 | unset($data); |
305 | unset($data); |
306 | 306 | ||
307 | $ary = $out; |
307 | $ary = $out; |
308 | } |
308 | } |
309 | 309 | ||
310 | /** |
310 | /** |
311 | * Checks if two OIDs in dot-notation are equal |
311 | * Checks if two OIDs in dot-notation are equal |
312 | * @author Daniel Marschall, ViaThinkSoft |
312 | * @author Daniel Marschall, ViaThinkSoft |
313 | * @version 2020-05-27 |
313 | * @version 2020-05-27 |
314 | * @param string $oidA<br/> |
314 | * @param string $oidA<br/> |
315 | * First OID |
315 | * First OID |
316 | * @param string $oidB<br/> |
316 | * @param string $oidB<br/> |
317 | * Second OID |
317 | * Second OID |
318 | * @return boolean|null True if the OIDs are equal, null if one of the OIDs are invalid |
318 | * @return boolean|null True if the OIDs are equal, null if one of the OIDs are invalid |
319 | **/ |
319 | **/ |
320 | function oid_dotnotation_equal($oidA, $oidB) { |
320 | function oid_dotnotation_equal($oidA, $oidB) { |
321 | $oidA = sanitizeOID($oidA, false); |
321 | $oidA = sanitizeOID($oidA, false); |
322 | if ($oidA === false) return null; |
322 | if ($oidA === false) return null; |
323 | 323 | ||
324 | $oidB = sanitizeOID($oidB, false); |
324 | $oidB = sanitizeOID($oidB, false); |
325 | if ($oidB === false) return null; |
325 | if ($oidB === false) return null; |
326 | 326 | ||
327 | return $oidA === $oidB; |
327 | return $oidA === $oidB; |
328 | } |
328 | } |
329 | 329 | ||
330 | /** |
330 | /** |
331 | * Removes leading zeroes from an OID in dot notation. |
331 | * Removes leading zeroes from an OID in dot notation. |
332 | * @author Daniel Marschall, ViaThinkSoft |
332 | * @author Daniel Marschall, ViaThinkSoft |
333 | * @version 2015-08-17 |
333 | * @version 2015-08-17 |
334 | * @param string $oid<br/> |
334 | * @param string $oid<br/> |
335 | * An OID in dot notation. |
335 | * An OID in dot notation. |
336 | * @param mixed $leading_dot<br/> |
336 | * @param mixed $leading_dot<br/> |
337 | * true: The OID is valid, if it contains a leading dot.<br/> |
337 | * true: The OID is valid, if it contains a leading dot.<br/> |
338 | * false (default): The OID is valid, if it does not contain a leading dot. |
338 | * false (default): The OID is valid, if it does not contain a leading dot. |
339 | * 'auto: Allow both |
339 | * 'auto: Allow both |
340 | * @return string|false The OID without leading dots, or <code>false</code> if the OID is syntactically wrong. |
340 | * @return string|false The OID without leading dots, or <code>false</code> if the OID is syntactically wrong. |
341 | **/ |
341 | **/ |
342 | function sanitizeOID($oid, $leading_dot=false) { |
342 | function sanitizeOID($oid, $leading_dot=false) { |
343 | static $oid_sanitize_cache = array(); |
343 | static $oid_sanitize_cache = array(); |
344 | 344 | ||
345 | if ($leading_dot) $leading_dot = substr($oid,0,1) == '.'; |
345 | if ($leading_dot) $leading_dot = substr($oid,0,1) == '.'; |
346 | 346 | ||
347 | // We are using a cache, since this function is used very often by OIDplus |
347 | // We are using a cache, since this function is used very often by OIDplus |
348 | global $oid_sanitize_cache; |
348 | global $oid_sanitize_cache; |
349 | $v = ($leading_dot ? 'T' : 'F').$oid; |
349 | $v = ($leading_dot ? 'T' : 'F').$oid; |
350 | if (isset($oid_sanitize_cache[$v])) return $oid_sanitize_cache[$v]; |
350 | if (isset($oid_sanitize_cache[$v])) return $oid_sanitize_cache[$v]; |
351 | 351 | ||
352 | if ($leading_dot) { |
352 | if ($leading_dot) { |
353 | if ($oid == '.') return ''; |
353 | if ($oid == '.') return ''; |
354 | } else { |
354 | } else { |
355 | if ($oid == '') return ''; |
355 | if ($oid == '') return ''; |
356 | } |
356 | } |
357 | 357 | ||
358 | $out = ''; |
358 | $out = ''; |
359 | $ary = explode('.', $oid); |
359 | $ary = explode('.', $oid); |
360 | foreach ($ary as $n => &$a) { |
360 | foreach ($ary as $n => &$a) { |
361 | if (($leading_dot) && ($n == 0)) { |
361 | if (($leading_dot) && ($n == 0)) { |
362 | if ($a != '') return false; |
362 | if ($a != '') return false; |
363 | continue; |
363 | continue; |
364 | } |
364 | } |
365 | 365 | ||
366 | if (!preg_match('@^(\\d+)$@', $a, $m)) return false; // does contain something other than digits |
366 | if (!preg_match('@^(\\d+)$@', $a, $m)) return false; // does contain something other than digits |
367 | 367 | ||
368 | // strike leading zeroes |
368 | // strike leading zeroes |
369 | $a = preg_replace("@^0+@", '', $a); |
369 | $a = preg_replace("@^0+@", '', $a); |
370 | if ($a == '') $a = 0; |
370 | if ($a == '') $a = 0; |
371 | 371 | ||
372 | if (($leading_dot) || ($n != 0)) $out .= '.'; |
372 | if (($leading_dot) || ($n != 0)) $out .= '.'; |
373 | $out .= $a; |
373 | $out .= $a; |
374 | } |
374 | } |
375 | unset($a); |
375 | unset($a); |
376 | unset($ary); |
376 | unset($ary); |
377 | 377 | ||
378 | $oid_sanitize_cache[$v] = $out; |
378 | $oid_sanitize_cache[$v] = $out; |
379 | return $out; |
379 | return $out; |
380 | } |
380 | } |
381 | 381 | ||
382 | /** |
382 | /** |
383 | * Shows the top arc of an OID. |
383 | * Shows the top arc of an OID. |
384 | * This function tolerates leading dots. |
384 | * This function tolerates leading dots. |
385 | * @author Daniel Marschall, ViaThinkSoft |
385 | * @author Daniel Marschall, ViaThinkSoft |
386 | * @version 2014-12-16 |
386 | * @version 2014-12-16 |
387 | * @param string $oid<br/> |
387 | * @param string $oid<br/> |
388 | * An OID in dot notation. |
388 | * An OID in dot notation. |
389 | * @return string|false The top arc of the OID or empty string if it is already the root ('.') |
389 | * @return string|false The top arc of the OID or empty string if it is already the root ('.') |
390 | **/ |
390 | **/ |
391 | function oid_toparc($oid) { |
391 | function oid_toparc($oid) { |
392 | $leadingdot = substr($oid,0,1) == '.'; |
392 | $leadingdot = substr($oid,0,1) == '.'; |
393 | 393 | ||
394 | $oid = sanitizeOID($oid, $leadingdot); |
394 | $oid = sanitizeOID($oid, $leadingdot); |
395 | if ($oid === false) return false; |
395 | if ($oid === false) return false; |
396 | 396 | ||
397 | if (!$leadingdot) $oid = '.'.$oid; |
397 | if (!$leadingdot) $oid = '.'.$oid; |
398 | 398 | ||
399 | $p = strrpos($oid, '.'); |
399 | $p = strrpos($oid, '.'); |
400 | if ($p === false) return false; |
400 | if ($p === false) return false; |
401 | $r = substr($oid, $p+1); |
401 | $r = substr($oid, $p+1); |
402 | 402 | ||
403 | if ($leadingdot) { |
403 | if ($leadingdot) { |
404 | # if ($r == '') return '.'; |
404 | # if ($r == '') return '.'; |
405 | return $r; |
405 | return $r; |
406 | } else { |
406 | } else { |
407 | return substr($r, 1); |
407 | return substr($r, 1); |
408 | } |
408 | } |
409 | } |
409 | } |
410 | 410 | ||
411 | /** |
411 | /** |
412 | * Calculates the distance between two OIDs. |
412 | * Calculates the distance between two OIDs. |
413 | * This function tolerates leading dots and leading zeroes. |
413 | * This function tolerates leading dots and leading zeroes. |
414 | * @author Daniel Marschall, ViaThinkSoft |
414 | * @author Daniel Marschall, ViaThinkSoft |
415 | * @version 2014-12-20 |
415 | * @version 2014-12-20 |
416 | * @param string $a<br/> |
416 | * @param string $a<br/> |
417 | * An OID. |
417 | * An OID. |
418 | * @param string $b<br/> |
418 | * @param string $b<br/> |
419 | * An OID. |
419 | * An OID. |
420 | * @return int|false false if both OIDs do not have a child-parent or parent-child relation, e.g. oid_distance('2.999.1.2.3', '2.999.4.5') = false, or if one of the OIDs is syntactially invalid<br/> |
420 | * @return int|false false if both OIDs do not have a child-parent or parent-child relation, e.g. oid_distance('2.999.1.2.3', '2.999.4.5') = false, or if one of the OIDs is syntactially invalid<br/> |
421 | * >0 if $a is more specific than $b , e.g. oid_distance('2.999.1.2', '2.999') = 2<br/> |
421 | * >0 if $a is more specific than $b , e.g. oid_distance('2.999.1.2', '2.999') = 2<br/> |
422 | * <0 if $a is more common than $b , e.g. oid_distance('2.999', '2.999.1.2') = -2 |
422 | * <0 if $a is more common than $b , e.g. oid_distance('2.999', '2.999.1.2') = -2 |
423 | **/ |
423 | **/ |
424 | function oid_distance($a, $b) { |
424 | function oid_distance($a, $b) { |
425 | if (substr($a,0,1) == '.') $a = substr($a,1); |
425 | if (substr($a,0,1) == '.') $a = substr($a,1); |
426 | if (substr($b,0,1) == '.') $b = substr($b,1); |
426 | if (substr($b,0,1) == '.') $b = substr($b,1); |
427 | 427 | ||
428 | $a = sanitizeOID($a, false); |
428 | $a = sanitizeOID($a, false); |
429 | if ($a === false) return false; |
429 | if ($a === false) return false; |
430 | $b = sanitizeOID($b, false); |
430 | $b = sanitizeOID($b, false); |
431 | if ($b === false) return false; |
431 | if ($b === false) return false; |
432 | 432 | ||
433 | $ary = explode('.', $a); |
433 | $ary = explode('.', $a); |
434 | $bry = explode('.', $b); |
434 | $bry = explode('.', $b); |
435 | 435 | ||
436 | $min_len = min(count($ary), count($bry)); |
436 | $min_len = min(count($ary), count($bry)); |
437 | 437 | ||
438 | for ($i=0; $i<$min_len; $i++) { |
438 | for ($i=0; $i<$min_len; $i++) { |
439 | if ($ary[$i] != $bry[$i]) return false; |
439 | if ($ary[$i] != $bry[$i]) return false; |
440 | } |
440 | } |
441 | 441 | ||
442 | return count($ary) - count($bry); |
442 | return count($ary) - count($bry); |
443 | } |
443 | } |
444 | /* |
444 | /* |
445 | assert(oid_distance('2.999.1.2.3', '2.999.4.5') === false); |
445 | assert(oid_distance('2.999.1.2.3', '2.999.4.5') === false); |
446 | assert(oid_distance('2.999.1.2', '2.999') === 2); |
446 | assert(oid_distance('2.999.1.2', '2.999') === 2); |
447 | assert(oid_distance('2.999', '2.999.1.2') === -2); |
447 | assert(oid_distance('2.999', '2.999.1.2') === -2); |
448 | */ |
448 | */ |
449 | 449 | ||
450 | /** |
450 | /** |
451 | * Adds a leading dot to an OID. |
451 | * Adds a leading dot to an OID. |
452 | * Leading zeroes are tolerated. |
452 | * Leading zeroes are tolerated. |
453 | * @author Daniel Marschall, ViaThinkSoft |
453 | * @author Daniel Marschall, ViaThinkSoft |
454 | * @version 2014-12-20 |
454 | * @version 2014-12-20 |
455 | * @param string $oid<br/> |
455 | * @param string $oid<br/> |
456 | * An OID. |
456 | * An OID. |
457 | * @return string|false The OID with a leading dot or false if the OID is syntactially wrong. |
457 | * @return string|false The OID with a leading dot or false if the OID is syntactially wrong. |
458 | **/ |
458 | **/ |
459 | function oid_add_leading_dot($oid) { |
459 | function oid_add_leading_dot($oid) { |
460 | $oid = sanitizeOID($oid, 'auto'); |
460 | $oid = sanitizeOID($oid, 'auto'); |
461 | if ($oid === false) return false; |
461 | if ($oid === false) return false; |
462 | 462 | ||
463 | if ($oid[0] != '.') $oid = '.'.$oid; |
463 | if (substr($oid,0,1) != '.') $oid = '.'.$oid; |
464 | return $oid; |
464 | return $oid; |
465 | } |
465 | } |
466 | 466 | ||
467 | /** |
467 | /** |
468 | * Removes a leading dot to an OID. |
468 | * Removes a leading dot to an OID. |
469 | * Leading zeroes are tolerated. |
469 | * Leading zeroes are tolerated. |
470 | * @author Daniel Marschall, ViaThinkSoft |
470 | * @author Daniel Marschall, ViaThinkSoft |
471 | * @version 2014-12-20 |
471 | * @version 2014-12-20 |
472 | * @param string $oid<br/> |
472 | * @param string $oid<br/> |
473 | * An OID. |
473 | * An OID. |
474 | * @return string|false The OID without a leading dot or false if the OID is syntactially wrong. |
474 | * @return string|false The OID without a leading dot or false if the OID is syntactially wrong. |
475 | **/ |
475 | **/ |
476 | function oid_remove_leading_dot($oid) { |
476 | function oid_remove_leading_dot($oid) { |
477 | $oid = sanitizeOID($oid, 'auto'); |
477 | $oid = sanitizeOID($oid, 'auto'); |
478 | if ($oid === false) return false; |
478 | if ($oid === false) return false; |
479 | 479 | ||
480 | if (substr($oid,0,1) == '.') $oid = substr($oid, 1); |
480 | if (substr($oid,0,1) == '.') $oid = substr($oid, 1); |
481 | return $oid; |
481 | return $oid; |
482 | } |
482 | } |
483 | 483 | ||
484 | /** |
484 | /** |
485 | * Find the common ancestor of two or more OIDs |
485 | * Find the common ancestor of two or more OIDs |
486 | * @author Daniel Marschall, ViaThinkSoft |
486 | * @author Daniel Marschall, ViaThinkSoft |
487 | * @version 2020-05-27 |
487 | * @version 2020-05-27 |
488 | * @param string[] $oids<br/> |
488 | * @param string[] $oids<br/> |
489 | * An array of multiple OIDs, e.g. 2.999.1 and 2.999.2.3.4 |
489 | * An array of multiple OIDs, e.g. 2.999.1 and 2.999.2.3.4 |
490 | * @return string|false The common ancestor, e.g. 2.999, or false if there is no common ancestor. |
490 | * @return string|false The common ancestor, e.g. 2.999, or false if there is no common ancestor. |
491 | **/ |
491 | **/ |
492 | function oid_common_ancestor(array $oids) { |
492 | function oid_common_ancestor(array $oids) { |
493 | $shared = array(); |
493 | $shared = array(); |
494 | 494 | ||
495 | if (!is_array($oids)) return false; |
495 | if (!is_array($oids)) return false; |
496 | if (count($oids) === 0) return false; |
496 | if (count($oids) === 0) return false; |
497 | 497 | ||
498 | foreach ($oids as &$oid) { |
498 | foreach ($oids as &$oid) { |
499 | $oid = sanitizeOID($oid, false); |
499 | $oid = sanitizeOID($oid, false); |
500 | if ($oid === false) return false; |
500 | if ($oid === false) return false; |
501 | $oid = explode('.', $oid); |
501 | $oid = explode('.', $oid); |
502 | } |
502 | } |
503 | 503 | ||
504 | $max_ok = strlen($oids[0]); |
504 | $max_ok = strlen($oids[0]); |
505 | for ($i=1; $i<count($oids); $i++) { |
505 | for ($i=1; $i<count($oids); $i++) { |
506 | for ($j=0; $j<min(strlen($oids[$i]),strlen($oids[0])); $j++) { |
506 | for ($j=0; $j<min(strlen($oids[$i]),strlen($oids[0])); $j++) { |
507 | if ($oids[$i][$j] != $oids[0][$j]) { |
507 | if ($oids[$i][$j] != $oids[0][$j]) { |
508 | if ($j < $max_ok) $max_ok = $j; |
508 | if ($j < $max_ok) $max_ok = $j; |
509 | break; |
509 | break; |
510 | } |
510 | } |
511 | } |
511 | } |
512 | if ($j < $max_ok) $max_ok = $j; |
512 | if ($j < $max_ok) $max_ok = $j; |
513 | } |
513 | } |
514 | 514 | ||
515 | $out = array(); |
515 | $out = array(); |
516 | for ($i=0; $i<$max_ok; $i++) { |
516 | for ($i=0; $i<$max_ok; $i++) { |
517 | $out[] = $oids[0][$i]; |
517 | $out[] = $oids[0][$i]; |
518 | } |
518 | } |
519 | return implode('.', $out); |
519 | return implode('.', $out); |
520 | } |
520 | } |
521 | /* |
521 | /* |
522 | assert(oid_shared_ancestor(array('2.999.4.5.3', '2.999.4.5')) === "2.999.4.5"); |
522 | assert(oid_shared_ancestor(array('2.999.4.5.3', '2.999.4.5')) === "2.999.4.5"); |
523 | assert(oid_shared_ancestor(array('2.999.4.5', '2.999.4.5.3')) === "2.999.4.5"); |
523 | assert(oid_shared_ancestor(array('2.999.4.5', '2.999.4.5.3')) === "2.999.4.5"); |
524 | assert(oid_shared_ancestor(array('2.999.1.2.3', '2.999.4.5')) === "2.999"); |
524 | assert(oid_shared_ancestor(array('2.999.1.2.3', '2.999.4.5')) === "2.999"); |
525 | */ |
525 | */ |
526 | 526 | ||
527 | 527 | ||
528 | # === OID-IRI NOTATION FUNCTIONS === |
528 | # === OID-IRI NOTATION FUNCTIONS === |
529 | 529 | ||
530 | if (!function_exists('mb_ord')) { |
530 | if (!function_exists('mb_ord')) { |
531 | # http://stackoverflow.com/a/24755772/3544341 |
531 | # http://stackoverflow.com/a/24755772/3544341 |
532 | function mb_ord($char, $encoding = 'UTF-8') { |
532 | function mb_ord($char, $encoding = 'UTF-8') { |
533 | if ($encoding === 'UCS-4BE') { |
533 | if ($encoding === 'UCS-4BE') { |
534 | list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char); |
534 | list(, $ord) = (strlen($char) === 4) ? @unpack('N', $char) : @unpack('n', $char); |
535 | return $ord; |
535 | return $ord; |
536 | } else { |
536 | } else { |
537 | return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE'); |
537 | return mb_ord(mb_convert_encoding($char, 'UCS-4BE', $encoding), 'UCS-4BE'); |
538 | } |
538 | } |
539 | } |
539 | } |
540 | } |
540 | } |
541 | 541 | ||
542 | function iri_char_valid($c, $firstchar, $lastchar) { |
542 | function iri_char_valid($c, $firstchar, $lastchar) { |
543 | // see Rec. ITU-T X.660, clause 7.5 |
543 | // see Rec. ITU-T X.660, clause 7.5 |
544 | 544 | ||
545 | if (($firstchar || $lastchar) && ($c == '-')) return false; |
545 | if (($firstchar || $lastchar) && ($c == '-')) return false; |
546 | 546 | ||
547 | if ($c == '-') return true; |
547 | if ($c == '-') return true; |
548 | if ($c == '.') return true; |
548 | if ($c == '.') return true; |
549 | if ($c == '_') return true; |
549 | if ($c == '_') return true; |
550 | if ($c == '~') return true; |
550 | if ($c == '~') return true; |
551 | if (($c >= '0') && ($c <= '9') && (!$firstchar)) return true; |
551 | if (($c >= '0') && ($c <= '9') && (!$firstchar)) return true; |
552 | if (($c >= 'A') && ($c <= 'Z')) return true; |
552 | if (($c >= 'A') && ($c <= 'Z')) return true; |
553 | if (($c >= 'a') && ($c <= 'z')) return true; |
553 | if (($c >= 'a') && ($c <= 'z')) return true; |
554 | 554 | ||
555 | $v = mb_ord($c); |
555 | $v = mb_ord($c); |
556 | 556 | ||
557 | if (($v >= 0x000000A0) && ($v <= 0x0000DFFE)) return true; |
557 | if (($v >= 0x000000A0) && ($v <= 0x0000DFFE)) return true; |
558 | if (($v >= 0x0000F900) && ($v <= 0x0000FDCF)) return true; |
558 | if (($v >= 0x0000F900) && ($v <= 0x0000FDCF)) return true; |
559 | if (($v >= 0x0000FDF0) && ($v <= 0x0000FFEF)) return true; |
559 | if (($v >= 0x0000FDF0) && ($v <= 0x0000FFEF)) return true; |
560 | if (($v >= 0x00010000) && ($v <= 0x0001FFFD)) return true; |
560 | if (($v >= 0x00010000) && ($v <= 0x0001FFFD)) return true; |
561 | if (($v >= 0x00020000) && ($v <= 0x0002FFFD)) return true; |
561 | if (($v >= 0x00020000) && ($v <= 0x0002FFFD)) return true; |
562 | if (($v >= 0x00030000) && ($v <= 0x0003FFFD)) return true; |
562 | if (($v >= 0x00030000) && ($v <= 0x0003FFFD)) return true; |
563 | if (($v >= 0x00040000) && ($v <= 0x0004FFFD)) return true; |
563 | if (($v >= 0x00040000) && ($v <= 0x0004FFFD)) return true; |
564 | if (($v >= 0x00050000) && ($v <= 0x0005FFFD)) return true; |
564 | if (($v >= 0x00050000) && ($v <= 0x0005FFFD)) return true; |
565 | if (($v >= 0x00060000) && ($v <= 0x0006FFFD)) return true; |
565 | if (($v >= 0x00060000) && ($v <= 0x0006FFFD)) return true; |
566 | if (($v >= 0x00070000) && ($v <= 0x0007FFFD)) return true; |
566 | if (($v >= 0x00070000) && ($v <= 0x0007FFFD)) return true; |
567 | if (($v >= 0x00080000) && ($v <= 0x0008FFFD)) return true; |
567 | if (($v >= 0x00080000) && ($v <= 0x0008FFFD)) return true; |
568 | if (($v >= 0x00090000) && ($v <= 0x0009FFFD)) return true; |
568 | if (($v >= 0x00090000) && ($v <= 0x0009FFFD)) return true; |
569 | if (($v >= 0x000A0000) && ($v <= 0x000AFFFD)) return true; |
569 | if (($v >= 0x000A0000) && ($v <= 0x000AFFFD)) return true; |
570 | if (($v >= 0x000B0000) && ($v <= 0x000BFFFD)) return true; |
570 | if (($v >= 0x000B0000) && ($v <= 0x000BFFFD)) return true; |
571 | if (($v >= 0x000C0000) && ($v <= 0x000CFFFD)) return true; |
571 | if (($v >= 0x000C0000) && ($v <= 0x000CFFFD)) return true; |
572 | if (($v >= 0x000D0000) && ($v <= 0x000DFFFD)) return true; |
572 | if (($v >= 0x000D0000) && ($v <= 0x000DFFFD)) return true; |
573 | if (($v >= 0x000E1000) && ($v <= 0x000EFFFD)) return true; |
573 | if (($v >= 0x000E1000) && ($v <= 0x000EFFFD)) return true; |
574 | 574 | ||
575 | // Note: Rec. ITU-T X.660, clause 7.5.3 would also forbid ranges which are marked in ISO/IEC 10646 as "(This position shall not be used)" |
575 | // Note: Rec. ITU-T X.660, clause 7.5.3 would also forbid ranges which are marked in ISO/IEC 10646 as "(This position shall not be used)" |
576 | // But tool implementers should be tolerate them, since these limitations can be removed in future. |
576 | // But tool implementers should be tolerate them, since these limitations can be removed in future. |
577 | 577 | ||
578 | return false; |
578 | return false; |
579 | } |
579 | } |
580 | 580 | ||
581 | function iri_arc_valid($arc, $allow_numeric=true) { |
581 | function iri_arc_valid($arc, $allow_numeric=true) { |
582 | if ($arc == '') return false; |
582 | if ($arc == '') return false; |
583 | 583 | ||
584 | $m = array(); |
584 | $m = array(); |
585 | if ($allow_numeric && preg_match('@^(\\d+)$@', $arc, $m)) return true; # numeric arc |
585 | if ($allow_numeric && preg_match('@^(\\d+)$@', $arc, $m)) return true; # numeric arc |
586 | 586 | ||
587 | // Question: Should we strip RTL/LTR characters? |
587 | // Question: Should we strip RTL/LTR characters? |
588 | 588 | ||
589 | if (mb_substr($arc, 2, 2) == '--') return false; // see Rec. ITU-T X.660, clause 7.5.4 |
589 | if (mb_substr($arc, 2, 2) == '--') return false; // see Rec. ITU-T X.660, clause 7.5.4 |
590 | 590 | ||
591 | $array = array(); |
591 | $array = array(); |
592 | preg_match_all('/./u', $arc, $array, PREG_SET_ORDER); |
592 | preg_match_all('/./u', $arc, $array, PREG_SET_ORDER); |
593 | $len = count($array); |
593 | $len = count($array); |
594 | foreach ($array as $i => $char) { |
594 | foreach ($array as $i => $char) { |
595 | if (!iri_char_valid($char[0], $i==0, $i==$len-1)) return false; |
595 | if (!iri_char_valid($char[0], $i==0, $i==$len-1)) return false; |
596 | } |
596 | } |
597 | 597 | ||
598 | return true; |
598 | return true; |
599 | } |
599 | } |
600 | 600 | ||
601 | /** |
601 | /** |
602 | * Checks if an IRI identifier is valid or not. |
602 | * Checks if an IRI identifier is valid or not. |
603 | * @author Daniel Marschall, ViaThinkSoft |
603 | * @author Daniel Marschall, ViaThinkSoft |
604 | * @version 2014-12-17 |
604 | * @version 2014-12-17 |
605 | * @param string $iri<br/> |
605 | * @param string $iri<br/> |
606 | * An OID in OID-IRI notation, e.g. /Example/test |
606 | * An OID in OID-IRI notation, e.g. /Example/test |
607 | * @return boolean true if the IRI identifier is valid. |
607 | * @return boolean true if the IRI identifier is valid. |
608 | **/ |
608 | **/ |
609 | function iri_valid($iri) { |
609 | function iri_valid($iri) { |
610 | if ($iri == '/') return true; // OK? |
610 | if ($iri == '/') return true; // OK? |
611 | 611 | ||
612 | if (substr($iri, 0, 1) != '/') return false; |
612 | if (substr($iri, 0, 1) != '/') return false; |
613 | 613 | ||
614 | $ary = explode('/', $iri); |
614 | $ary = explode('/', $iri); |
615 | array_shift($ary); |
615 | array_shift($ary); |
616 | foreach ($ary as $a) { |
616 | foreach ($ary as $a) { |
617 | if (!iri_arc_valid($a)) return false; |
617 | if (!iri_arc_valid($a)) return false; |
618 | } |
618 | } |
619 | 619 | ||
620 | return true; |
620 | return true; |
621 | } |
621 | } |
622 | 622 | ||
623 | /* |
623 | /* |
624 | assert(iri_arc_valid('ABCDEF')); |
624 | assert(iri_arc_valid('ABCDEF')); |
625 | assert(!iri_arc_valid('-ABCDEF')); |
625 | assert(!iri_arc_valid('-ABCDEF')); |
626 | assert(!iri_arc_valid('ABCDEF-')); |
626 | assert(!iri_arc_valid('ABCDEF-')); |
627 | assert(!iri_arc_valid(' ABCDEF')); |
627 | assert(!iri_arc_valid(' ABCDEF')); |
628 | assert(!iri_arc_valid('2 ABCDEF')); |
628 | assert(!iri_arc_valid('2 ABCDEF')); |
629 | assert(!iri_arc_valid('')); |
629 | assert(!iri_arc_valid('')); |
630 | 630 | ||
631 | assert(!iri_valid('')); |
631 | assert(!iri_valid('')); |
632 | assert(iri_valid('/')); |
632 | assert(iri_valid('/')); |
633 | assert(iri_valid('/hello/world')); |
633 | assert(iri_valid('/hello/world')); |
634 | assert(iri_valid('/123/world')); |
634 | assert(iri_valid('/123/world')); |
635 | assert(!iri_valid('/hello/0world')); |
635 | assert(!iri_valid('/hello/0world')); |
636 | assert(!iri_valid('/hello/xo--test')); |
636 | assert(!iri_valid('/hello/xo--test')); |
637 | assert(!iri_valid('/hello/-super-/sd')); |
637 | assert(!iri_valid('/hello/-super-/sd')); |
638 | */ |
638 | */ |
639 | 639 | ||
640 | /** |
640 | /** |
641 | * Returns an associative array in the form 'ASN.1' => '/2/1' . |
641 | * Returns an associative array in the form 'ASN.1' => '/2/1' . |
642 | * @author Daniel Marschall, ViaThinkSoft |
642 | * @author Daniel Marschall, ViaThinkSoft |
643 | * @version 2018-01-05 |
643 | * @version 2018-01-05 |
644 | * @see http://itu.int/go/X660 |
644 | * @see http://itu.int/go/X660 |
645 | * @return array<string,string> An associative array in the form 'ASN.1' => '/2/1' . |
645 | * @return array<string,string> An associative array in the form 'ASN.1' => '/2/1' . |
646 | **/ |
646 | **/ |
647 | function iri_get_long_arcs() { |
647 | function iri_get_long_arcs() { |
648 | $iri_long_arcs = array(); |
648 | $iri_long_arcs = array(); |
649 | $iri_long_arcs['ASN.1'] = '/2/1'; |
649 | $iri_long_arcs['ASN.1'] = '/2/1'; |
650 | $iri_long_arcs['Country'] = '/2/16'; |
650 | $iri_long_arcs['Country'] = '/2/16'; |
651 | $iri_long_arcs['International-Organizations'] = '/2/23'; |
651 | $iri_long_arcs['International-Organizations'] = '/2/23'; |
652 | $iri_long_arcs['UUID'] = '/2/25'; |
652 | $iri_long_arcs['UUID'] = '/2/25'; |
653 | $iri_long_arcs['Tag-Based'] = '/2/27'; |
653 | $iri_long_arcs['Tag-Based'] = '/2/27'; |
654 | $iri_long_arcs['BIP'] = '/2/41'; |
654 | $iri_long_arcs['BIP'] = '/2/41'; |
655 | $iri_long_arcs['Telebiometrics'] = '/2/42'; |
655 | $iri_long_arcs['Telebiometrics'] = '/2/42'; |
656 | $iri_long_arcs['Cybersecurity'] = '/2/48'; |
656 | $iri_long_arcs['Cybersecurity'] = '/2/48'; |
657 | $iri_long_arcs['Alerting'] = '/2/49'; |
657 | $iri_long_arcs['Alerting'] = '/2/49'; |
658 | $iri_long_arcs['OIDResolutionSystem'] = '/2/50'; |
658 | $iri_long_arcs['OIDResolutionSystem'] = '/2/50'; |
659 | $iri_long_arcs['GS1'] = '/2/51'; |
659 | $iri_long_arcs['GS1'] = '/2/51'; |
660 | $iri_long_arcs['Example'] = '/2/999'; // English |
660 | $iri_long_arcs['Example'] = '/2/999'; // English |
661 | $iri_long_arcs['Exemple'] = '/2/999'; // French |
661 | $iri_long_arcs['Exemple'] = '/2/999'; // French |
662 | $iri_long_arcs['Ejemplo'] = '/2/999'; // Spanish |
662 | $iri_long_arcs['Ejemplo'] = '/2/999'; // Spanish |
663 | $iri_long_arcs["\u{0627}\u{0644}\u{0645}\u{062B}\u{0627}\u{0644}"] = '/2/999'; // Arabic |
663 | $iri_long_arcs["\u{0627}\u{0644}\u{0645}\u{062B}\u{0627}\u{0644}"] = '/2/999'; // Arabic |
664 | $iri_long_arcs["\u{8303}\u{4F8B}"] = '/2/999'; // Chinese |
664 | $iri_long_arcs["\u{8303}\u{4F8B}"] = '/2/999'; // Chinese |
665 | $iri_long_arcs["\u{041F}\u{0440}\u{0438}\u{043C}\u{0435}\u{0440}"] = '/2/999'; // Russian |
665 | $iri_long_arcs["\u{041F}\u{0440}\u{0438}\u{043C}\u{0435}\u{0440}"] = '/2/999'; // Russian |
666 | $iri_long_arcs["\u{C608}\u{C81C}"] = '/2/999'; // Korean |
666 | $iri_long_arcs["\u{C608}\u{C81C}"] = '/2/999'; // Korean |
667 | $iri_long_arcs["\u{4F8B}"] = '/2/999'; // Japanese |
667 | $iri_long_arcs["\u{4F8B}"] = '/2/999'; // Japanese |
668 | $iri_long_arcs['Beispiel'] = '/2/999'; // German |
668 | $iri_long_arcs['Beispiel'] = '/2/999'; // German |
669 | return $iri_long_arcs; |
669 | return $iri_long_arcs; |
670 | } |
670 | } |
671 | 671 | ||
672 | /** |
672 | /** |
673 | * Tries to shorten/simplify an IRI by applying "long arcs", e.g. /2/999/123 -> /Example/123 . |
673 | * Tries to shorten/simplify an IRI by applying "long arcs", e.g. /2/999/123 -> /Example/123 . |
674 | * @author Daniel Marschall, ViaThinkSoft |
674 | * @author Daniel Marschall, ViaThinkSoft |
675 | * @version 2020-05-22 |
675 | * @version 2020-05-22 |
676 | * @param string $iri<br/> |
676 | * @param string $iri<br/> |
677 | * An OID in OID-IRI notation, e.g. /Example/test |
677 | * An OID in OID-IRI notation, e.g. /Example/test |
678 | * @return string|false The modified IRI. |
678 | * @return string|false The modified IRI. |
679 | **/ |
679 | **/ |
680 | function iri_add_longarcs($iri) { |
680 | function iri_add_longarcs($iri) { |
681 | $iri_long_arcs = iri_get_long_arcs(); |
681 | $iri_long_arcs = iri_get_long_arcs(); |
682 | 682 | ||
683 | if (!iri_valid($iri)) return false; |
683 | if (!iri_valid($iri)) return false; |
684 | 684 | ||
685 | $ary = explode('/', $iri); |
685 | $ary = explode('/', $iri); |
686 | 686 | ||
687 | $ary_number_iri = $ary; |
687 | $ary_number_iri = $ary; |
688 | if ($ary_number_iri[1] == 'Joint-ISO-ITU-T') $ary_number_iri[1] = '2'; |
688 | if ($ary_number_iri[1] == 'Joint-ISO-ITU-T') $ary_number_iri[1] = '2'; |
689 | 689 | ||
690 | $number_iri = implode('/', $ary_number_iri); |
690 | $number_iri = implode('/', $ary_number_iri); |
691 | 691 | ||
692 | foreach ($iri_long_arcs as $cur_longarc => $cur_iri) { |
692 | foreach ($iri_long_arcs as $cur_longarc => $cur_iri) { |
693 | assert(iri_valid($cur_iri)); |
693 | assert(iri_valid($cur_iri)); |
694 | if (strpos($number_iri.'/', $cur_iri.'/') === 0) { |
694 | if (strpos($number_iri.'/', $cur_iri.'/') === 0) { |
695 | $cnt = substr_count($cur_iri, '/'); |
695 | $cnt = substr_count($cur_iri, '/'); |
696 | for ($i=1; $i<$cnt; $i++) { |
696 | for ($i=1; $i<$cnt; $i++) { |
697 | array_shift($ary); |
697 | array_shift($ary); |
698 | } |
698 | } |
699 | $ary[0] = ''; |
699 | $ary[0] = ''; |
700 | $ary[1] = $cur_longarc; |
700 | $ary[1] = $cur_longarc; |
701 | $iri = implode('/', $ary); |
701 | $iri = implode('/', $ary); |
702 | break; |
702 | break; |
703 | } |
703 | } |
704 | } |
704 | } |
705 | 705 | ||
706 | return $iri; |
706 | return $iri; |
707 | } |
707 | } |
708 | /* |
708 | /* |
709 | assert(iri_add_longarcs('/2/999/123') === '/Example/123'); |
709 | assert(iri_add_longarcs('/2/999/123') === '/Example/123'); |
710 | */ |
710 | */ |
711 | 711 | ||
712 | # === FUNCTIONS FOR OIDS IN ASN.1 NOTATION === |
712 | # === FUNCTIONS FOR OIDS IN ASN.1 NOTATION === |
713 | 713 | ||
714 | /** |
714 | /** |
715 | * Checks if an ASN.1 identifier is valid. |
715 | * Checks if an ASN.1 identifier is valid. |
716 | * @author Daniel Marschall, ViaThinkSoft |
716 | * @author Daniel Marschall, ViaThinkSoft |
717 | * @version 2020-05-22 |
717 | * @version 2020-05-22 |
718 | * @param string $id<br/> |
718 | * @param string $id<br/> |
719 | * An ASN.1 identifier, e.g. "example". Not "example(99)" or "99" and not a path like "{ 2 999 }" |
719 | * An ASN.1 identifier, e.g. "example". Not "example(99)" or "99" and not a path like "{ 2 999 }" |
720 | * Note: Use asn1_path_valid() for validating a whole ASN.1 notation path. |
720 | * Note: Use asn1_path_valid() for validating a whole ASN.1 notation path. |
721 | * @return boolean true, if the identifier is valid: It begins with an lowercase letter and contains only 0-9, a-z, A-Z and "-" |
721 | * @return boolean true, if the identifier is valid: It begins with an lowercase letter and contains only 0-9, a-z, A-Z and "-" |
722 | **/ |
722 | **/ |
723 | function oid_id_is_valid($id) { |
723 | function oid_id_is_valid($id) { |
724 | // see Rec. ITU-T X.660 | ISO/IEC 9834-1, clause 7.7 |
724 | // see Rec. ITU-T X.660 | ISO/IEC 9834-1, clause 7.7 |
725 | // and Rec. ITU-T X.680 | ISO/IEC 8824-1, clause 12.3 |
725 | // and Rec. ITU-T X.680 | ISO/IEC 8824-1, clause 12.3 |
726 | if (substr($id,-1,1) == '-') return false; |
726 | if (substr($id,-1,1) == '-') return false; |
727 | if (strstr($id,'--')) return false; |
727 | if (strstr($id,'--')) return false; |
728 | return preg_match('/^([a-z][a-zA-Z0-9-]*)$/', $id) != 0; |
728 | return preg_match('/^([a-z][a-zA-Z0-9-]*)$/', $id) != 0; |
729 | } |
729 | } |
730 | 730 | ||
731 | /** |
731 | /** |
732 | * Checks if the ASN.1 notation of an OID is valid. |
732 | * Checks if the ASN.1 notation of an OID is valid. |
733 | * This function does not tolerate leading zeros. |
733 | * This function does not tolerate leading zeros. |
734 | * This function will fail (return false) if there are unresolved symbols, e.g. {iso test} is not valid while { iso 123 } is valid. |
734 | * This function will fail (return false) if there are unresolved symbols, e.g. {iso test} is not valid while { iso 123 } is valid. |
735 | * @author Daniel Marschall, ViaThinkSoft |
735 | * @author Daniel Marschall, ViaThinkSoft |
736 | * @version 2014-12-17 |
736 | * @version 2014-12-17 |
737 | * @param string $asn1<br/> |
737 | * @param string $asn1<br/> |
738 | * An OID in ASN.1 notation. |
738 | * An OID in ASN.1 notation. |
739 | * @return boolean true if the identifier is valid. |
739 | * @return boolean true if the identifier is valid. |
740 | **/ |
740 | **/ |
741 | function asn1_path_valid($asn1) { |
741 | function asn1_path_valid($asn1) { |
742 | return asn1_to_dot($asn1) != false; |
742 | return asn1_to_dot($asn1) != false; |
743 | } |
743 | } |
744 | 744 | ||
745 | /** |
745 | /** |
746 | * Returns an array of standardized ASN.1 alphanumeric identifiers which do not require a numeric identifier, e.g. { 2 example } |
746 | * Returns an array of standardized ASN.1 alphanumeric identifiers which do not require a numeric identifier, e.g. { 2 example } |
747 | * The array has the form '0.0.a' -> '0.0.1' |
747 | * The array has the form '0.0.a' -> '0.0.1' |
748 | * @author Daniel Marschall, ViaThinkSoft |
748 | * @author Daniel Marschall, ViaThinkSoft |
749 | * @version 2019-03-25 |
749 | * @version 2019-03-25 |
750 | * @see http://www.oid-info.com/name-forms.htm |
750 | * @see http://www.oid-info.com/name-forms.htm |
751 | * @return array<string,string> Associative array of standardized ASN.1 alphanumeric identifiers |
751 | * @return array<string,string> Associative array of standardized ASN.1 alphanumeric identifiers |
752 | **/ |
752 | **/ |
753 | function asn1_get_standardized_array() { |
753 | function asn1_get_standardized_array() { |
754 | 754 | ||
755 | // Taken from oid-info.com |
755 | // Taken from oid-info.com |
756 | // http://www.oid-info.com/name-forms.htm |
756 | // http://www.oid-info.com/name-forms.htm |
757 | $standardized = array(); |
757 | $standardized = array(); |
758 | $standardized['itu-t'] = '0'; |
758 | $standardized['itu-t'] = '0'; |
759 | $standardized['ccitt'] = '0'; |
759 | $standardized['ccitt'] = '0'; |
760 | $standardized['iso'] = '1'; |
760 | $standardized['iso'] = '1'; |
761 | $standardized['joint-iso-itu-t'] = '2'; |
761 | $standardized['joint-iso-itu-t'] = '2'; |
762 | $standardized['joint-iso-ccitt'] = '2'; |
762 | $standardized['joint-iso-ccitt'] = '2'; |
763 | $standardized['0.recommendation'] = '0.0'; |
763 | $standardized['0.recommendation'] = '0.0'; |
764 | $standardized['0.0.a'] = '0.0.1'; |
764 | $standardized['0.0.a'] = '0.0.1'; |
765 | $standardized['0.0.b'] = '0.0.2'; |
765 | $standardized['0.0.b'] = '0.0.2'; |
766 | $standardized['0.0.c'] = '0.0.3'; |
766 | $standardized['0.0.c'] = '0.0.3'; |
767 | $standardized['0.0.d'] = '0.0.4'; |
767 | $standardized['0.0.d'] = '0.0.4'; |
768 | $standardized['0.0.e'] = '0.0.5'; |
768 | $standardized['0.0.e'] = '0.0.5'; |
769 | $standardized['0.0.f'] = '0.0.6'; |
769 | $standardized['0.0.f'] = '0.0.6'; |
770 | $standardized['0.0.g'] = '0.0.7'; |
770 | $standardized['0.0.g'] = '0.0.7'; |
771 | $standardized['0.0.h'] = '0.0.8'; |
771 | $standardized['0.0.h'] = '0.0.8'; |
772 | $standardized['0.0.i'] = '0.0.9'; |
772 | $standardized['0.0.i'] = '0.0.9'; |
773 | $standardized['0.0.j'] = '0.0.10'; |
773 | $standardized['0.0.j'] = '0.0.10'; |
774 | $standardized['0.0.k'] = '0.0.11'; |
774 | $standardized['0.0.k'] = '0.0.11'; |
775 | $standardized['0.0.l'] = '0.0.12'; |
775 | $standardized['0.0.l'] = '0.0.12'; |
776 | $standardized['0.0.m'] = '0.0.13'; |
776 | $standardized['0.0.m'] = '0.0.13'; |
777 | $standardized['0.0.n'] = '0.0.14'; |
777 | $standardized['0.0.n'] = '0.0.14'; |
778 | $standardized['0.0.o'] = '0.0.15'; |
778 | $standardized['0.0.o'] = '0.0.15'; |
779 | $standardized['0.0.p'] = '0.0.16'; |
779 | $standardized['0.0.p'] = '0.0.16'; |
780 | $standardized['0.0.q'] = '0.0.17'; |
780 | $standardized['0.0.q'] = '0.0.17'; |
781 | $standardized['0.0.r'] = '0.0.18'; |
781 | $standardized['0.0.r'] = '0.0.18'; |
782 | $standardized['0.0.s'] = '0.0.19'; |
782 | $standardized['0.0.s'] = '0.0.19'; |
783 | $standardized['0.0.t'] = '0.0.20'; |
783 | $standardized['0.0.t'] = '0.0.20'; |
784 | $standardized['0.0.u'] = '0.0.21'; |
784 | $standardized['0.0.u'] = '0.0.21'; |
785 | $standardized['0.0.v'] = '0.0.22'; |
785 | $standardized['0.0.v'] = '0.0.22'; |
786 | $standardized['0.0.w'] = '0.0.23'; // actually, this OID does not exist |
786 | $standardized['0.0.w'] = '0.0.23'; // actually, this OID does not exist |
787 | $standardized['0.0.x'] = '0.0.24'; |
787 | $standardized['0.0.x'] = '0.0.24'; |
788 | $standardized['0.0.y'] = '0.0.25'; |
788 | $standardized['0.0.y'] = '0.0.25'; |
789 | $standardized['0.0.z'] = '0.0.26'; |
789 | $standardized['0.0.z'] = '0.0.26'; |
790 | $standardized['0.question'] = '0.1'; |
790 | $standardized['0.question'] = '0.1'; |
791 | $standardized['0.administration'] = '0.2'; |
791 | $standardized['0.administration'] = '0.2'; |
792 | $standardized['0.network-operator'] = '0.3'; |
792 | $standardized['0.network-operator'] = '0.3'; |
793 | $standardized['0.identified-organization'] = '0.4'; |
793 | $standardized['0.identified-organization'] = '0.4'; |
794 | $standardized['1.standard'] = '1.0'; |
794 | $standardized['1.standard'] = '1.0'; |
795 | $standardized['1.registration-authority'] = '1.1'; |
795 | $standardized['1.registration-authority'] = '1.1'; |
796 | $standardized['1.member-body'] = '1.2'; |
796 | $standardized['1.member-body'] = '1.2'; |
797 | $standardized['1.identified-organization'] = '1.3'; |
797 | $standardized['1.identified-organization'] = '1.3'; |
798 | return $standardized; |
798 | return $standardized; |
799 | } |
799 | } |
800 | 800 | ||
801 | /** |
801 | /** |
802 | * Converts an OID in ASN.1 notation into an OID in dot notation and tries to resolve well-known identifiers.<br/> |
802 | * Converts an OID in ASN.1 notation into an OID in dot notation and tries to resolve well-known identifiers.<br/> |
803 | * e.g. {joint-iso-itu-t(2) example(999) 1 2 3} --> 2.999.1.2.3<br/> |
803 | * e.g. {joint-iso-itu-t(2) example(999) 1 2 3} --> 2.999.1.2.3<br/> |
804 | * e.g. {iso 3} --> 1.3 |
804 | * e.g. {iso 3} --> 1.3 |
805 | * This function does not tolerate leading zeros. |
805 | * This function does not tolerate leading zeros. |
806 | * This function will fail (return false) if there are unresolved symbols, e.g. {iso test} will not be resolved to 1.test |
806 | * This function will fail (return false) if there are unresolved symbols, e.g. {iso test} will not be resolved to 1.test |
807 | * @author Daniel Marschall, ViaThinkSoft |
807 | * @author Daniel Marschall, ViaThinkSoft |
808 | * @version 2014-12-17 |
808 | * @version 2014-12-17 |
809 | * @param string $asn<br/> |
809 | * @param string $asn<br/> |
810 | * An OID in ASN.1 notation. |
810 | * An OID in ASN.1 notation. |
811 | * @return string|false An OID in dot notation without leading dot or false if the path is invalid. |
811 | * @return string|false An OID in dot notation without leading dot or false if the path is invalid. |
812 | **/ |
812 | **/ |
813 | function asn1_to_dot($asn) { |
813 | function asn1_to_dot($asn) { |
814 | $standardized = asn1_get_standardized_array(); |
814 | $standardized = asn1_get_standardized_array(); |
815 | 815 | ||
816 | // Clean up |
816 | // Clean up |
817 | $count = -1; |
817 | $count = -1; |
818 | $asn = preg_replace('@^\\{(.+)\\}$@', '\\1', $asn, -1, $count); |
818 | $asn = preg_replace('@^\\{(.+)\\}$@', '\\1', $asn, -1, $count); |
819 | if ($count == 0) return false; // { and } are required. The ASN.1 path will NOT be trimmed by this function |
819 | if ($count == 0) return false; // { and } are required. The ASN.1 path will NOT be trimmed by this function |
820 | 820 | ||
821 | // If identifier is set, apply it (no check if it overrides a standardized identifier) |
821 | // If identifier is set, apply it (no check if it overrides a standardized identifier) |
822 | $asn = preg_replace('|\s*([a-z][a-zA-Z0-9-]*)\s*\((\d+)\)|', ' \\2', $asn); |
822 | $asn = preg_replace('|\s*([a-z][a-zA-Z0-9-]*)\s*\((\d+)\)|', ' \\2', $asn); |
823 | $asn = trim($asn); |
823 | $asn = trim($asn); |
824 | 824 | ||
825 | // Set dots |
825 | // Set dots |
826 | $asn = preg_replace('|\s+|', '.', $asn); |
826 | $asn = preg_replace('|\s+|', '.', $asn); |
827 | 827 | ||
828 | // Apply standardized identifiers (case sensitive) |
828 | // Apply standardized identifiers (case sensitive) |
829 | $asn .= '.'; |
829 | $asn .= '.'; |
830 | foreach ($standardized as $s => $r) { |
830 | foreach ($standardized as $s => $r) { |
831 | $asn = preg_replace("@^".preg_quote($s,"@")."@", $r, $asn); |
831 | $asn = preg_replace("@^".preg_quote($s,"@")."@", $r, $asn); |
832 | } |
832 | } |
833 | $asn = substr($asn, 0, strlen($asn)-1); |
833 | $asn = substr($asn, 0, strlen($asn)-1); |
834 | 834 | ||
835 | // Check if all numbers are OK |
835 | // Check if all numbers are OK |
836 | // -> every arc must be resolved |
836 | // -> every arc must be resolved |
837 | // -> numeric arcs must not have a leading zero |
837 | // -> numeric arcs must not have a leading zero |
838 | // -> invalid stuff will be recognized, e.g. a "(1)" without an identifier in front of it |
838 | // -> invalid stuff will be recognized, e.g. a "(1)" without an identifier in front of it |
839 | $ary = explode('.', $asn); |
839 | $ary = explode('.', $asn); |
840 | foreach ($ary as $a) { |
840 | foreach ($ary as $a) { |
841 | $m = array(); |
841 | $m = array(); |
842 | if (!preg_match('@^(0|([1-9]\\d*))$@', $a, $m)) return false; |
842 | if (!preg_match('@^(0|([1-9]\\d*))$@', $a, $m)) return false; |
843 | } |
843 | } |
844 | 844 | ||
845 | return $asn; |
845 | return $asn; |
846 | } |
846 | } |
847 | 847 | ||
848 | /* |
848 | /* |
849 | assert(asn1_to_dot('{2 999 (1)}') == false); |
849 | assert(asn1_to_dot('{2 999 (1)}') == false); |
850 | assert(asn1_to_dot('{2 999 test}') == false); |
850 | assert(asn1_to_dot('{2 999 test}') == false); |
851 | assert(asn1_to_dot('{2 999 1}') == '2.999.1'); |
851 | assert(asn1_to_dot('{2 999 1}') == '2.999.1'); |
852 | assert(asn1_to_dot(' {2 999 1} ') == false); |
852 | assert(asn1_to_dot(' {2 999 1} ') == false); |
853 | assert(asn1_to_dot('2 999 1') == false); |
853 | assert(asn1_to_dot('2 999 1') == false); |
854 | assert(asn1_to_dot('{2 999 01}') == false); |
854 | assert(asn1_to_dot('{2 999 01}') == false); |
855 | assert(asn1_to_dot('{ 0 question 123 }') == '0.1.123'); |
855 | assert(asn1_to_dot('{ 0 question 123 }') == '0.1.123'); |
856 | assert(asn1_to_dot('{ iso }') == '1'); |
856 | assert(asn1_to_dot('{ iso }') == '1'); |
857 | assert(asn1_to_dot('{ iso(1) }') == '1'); |
857 | assert(asn1_to_dot('{ iso(1) }') == '1'); |
858 | assert(asn1_to_dot('{ iso(2) }') == '2'); |
858 | assert(asn1_to_dot('{ iso(2) }') == '2'); |
859 | assert(asn1_to_dot('{ iso 3 }') == '1.3'); |
859 | assert(asn1_to_dot('{ iso 3 }') == '1.3'); |
860 | */ |
860 | */ |
861 | 861 | ||
862 | /** |
862 | /** |
863 | * Gets the last numeric identifier of an ASN.1 notation OID. |
863 | * Gets the last numeric identifier of an ASN.1 notation OID. |
864 | * @author Daniel Marschall, ViaThinkSoft |
864 | * @author Daniel Marschall, ViaThinkSoft |
865 | * @version 2020-06-11 |
865 | * @version 2020-06-11 |
866 | * @param string $asn1id<br/> |
866 | * @param string $asn1id<br/> |
867 | * An ASN.1 identifier string, e.g. { 2 example(999) test(1) } |
867 | * An ASN.1 identifier string, e.g. { 2 example(999) test(1) } |
868 | * @return int|false The last numeric identifier arc, e.g. "1" or false if the ID is invalid |
868 | * @return int|false The last numeric identifier arc, e.g. "1" or false if the ID is invalid |
869 | **/ |
869 | **/ |
870 | function asn1_last_identifier($asn1id) { |
870 | function asn1_last_identifier($asn1id) { |
871 | $asn1id = preg_replace('@\(\s*\d+\s*\)@', '', $asn1id); |
871 | $asn1id = preg_replace('@\(\s*\d+\s*\)@', '', $asn1id); |
872 | $asn1id = trim(str_replace(array('{', '}', "\t"), ' ', $asn1id)); |
872 | $asn1id = trim(str_replace(array('{', '}', "\t"), ' ', $asn1id)); |
873 | $ary = explode(' ', $asn1id); |
873 | $ary = explode(' ', $asn1id); |
874 | $asn1id = $ary[count($ary)-1]; |
874 | $asn1id = $ary[count($ary)-1]; |
875 | return preg_match('#[^0-9]#',$asn1id) ? (int)$asn1id : false; |
875 | return preg_match('#[^0-9]#',$asn1id) ? (int)$asn1id : false; |
876 | } |
876 | } |
877 | 877 | ||
878 | /** |
878 | /** |
879 | * "Soft corrects" an invalid ASN.1 identifier.<br/> |
879 | * "Soft corrects" an invalid ASN.1 identifier.<br/> |
880 | * Attention, by "soft correcting" the ID, it is not authoritative anymore, and might not be able to be resolved by ORS. |
880 | * Attention, by "soft correcting" the ID, it is not authoritative anymore, and might not be able to be resolved by ORS. |
881 | * @author Daniel Marschall, ViaThinkSoft |
881 | * @author Daniel Marschall, ViaThinkSoft |
882 | * @version 2020-05-22 |
882 | * @version 2020-05-22 |
883 | * @param string $id<br/> |
883 | * @param string $id<br/> |
884 | * An ASN.1 identifier. |
884 | * An ASN.1 identifier. |
885 | * @param boolean $append_id_prefix<br/> |
885 | * @param boolean $append_id_prefix<br/> |
886 | * true (default): If the identifier doesn't start with a-Z, the problem will be solved by prepending "id-" to the identifier.<br/> |
886 | * true (default): If the identifier doesn't start with a-Z, the problem will be solved by prepending "id-" to the identifier.<br/> |
887 | * false: If the identifier doesn't start with a-Z, then the problem cannot be solved (method returns empty string). |
887 | * false: If the identifier doesn't start with a-Z, then the problem cannot be solved (method returns empty string). |
888 | * @return string The "soft corrected" ASN.1 identifier.<br/> |
888 | * @return string The "soft corrected" ASN.1 identifier.<br/> |
889 | * Invalid characters will be removed.<br/> |
889 | * Invalid characters will be removed.<br/> |
890 | * Uncorrectable start elements (0-9 or "-") will be either removed or solved by prepending "id-" (see <code>$append_id_prefix</code>)<br/> |
890 | * Uncorrectable start elements (0-9 or "-") will be either removed or solved by prepending "id-" (see <code>$append_id_prefix</code>)<br/> |
891 | * If the identifier begins with an upper case letter, the letter will be converted into lower case. |
891 | * If the identifier begins with an upper case letter, the letter will be converted into lower case. |
892 | **/ |
892 | **/ |
893 | function oid_soft_correct_id($id, $append_id_prefix = true) { |
893 | function oid_soft_correct_id($id, $append_id_prefix = true) { |
894 | // Convert "_" to "-" |
894 | // Convert "_" to "-" |
895 | $id = str_replace('_', '-', $id); |
895 | $id = str_replace('_', '-', $id); |
896 | 896 | ||
897 | // Convert "--" to "-" |
897 | // Convert "--" to "-" |
898 | $id = str_replace('--', '-', $id); |
898 | $id = str_replace('--', '-', $id); |
899 | 899 | ||
900 | // Remove invalid characters |
900 | // Remove invalid characters |
901 | $id = preg_replace('/[^a-zA-Z0-9-]+/', '', $id); |
901 | $id = preg_replace('/[^a-zA-Z0-9-]+/', '', $id); |
902 | 902 | ||
903 | // Remove uncorrectable start elements (0-9 or "-") |
903 | // Remove uncorrectable start elements (0-9 or "-") |
904 | if ($append_id_prefix) { |
904 | if ($append_id_prefix) { |
905 | $id = preg_replace('/^([^a-zA-Z]+)/', 'id-$1', $id); |
905 | $id = preg_replace('/^([^a-zA-Z]+)/', 'id-$1', $id); |
906 | } else { |
906 | } else { |
907 | $id = preg_replace('/^([^a-zA-Z]+)/', '', $id); |
907 | $id = preg_replace('/^([^a-zA-Z]+)/', '', $id); |
908 | } |
908 | } |
909 | 909 | ||
910 | // "Correct" upper case beginning letter by converting it to lower case |
910 | // "Correct" upper case beginning letter by converting it to lower case |
911 | if (preg_match('/^[A-Z]/', $id)) { |
911 | if (preg_match('/^[A-Z]/', $id)) { |
912 | $id = strtolower($id[0]) . substr($id, 1); |
912 | $id = strtolower($id[0]) . substr($id, 1); |
913 | } |
913 | } |
914 | 914 | ||
915 | return $id; |
915 | return $id; |
916 | } |
916 | } |
917 | 917 |