Rev 26 | Rev 28 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | daniel-mar | 1 | <?php |
2 | |||
8 | daniel-mar | 3 | /* |
4 | * OID-Info.com API for PHP |
||
16 | daniel-mar | 5 | * Copyright 2019-2021 Daniel Marschall, ViaThinkSoft |
26 | daniel-mar | 6 | * Version 2021-12-08 |
8 | daniel-mar | 7 | * |
8 | * Licensed under the Apache License, Version 2.0 (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 |
||
11 | * |
||
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | * |
||
14 | * Unless required by applicable law or agreed to in writing, software |
||
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
17 | * See the License for the specific language governing permissions and |
||
18 | * limitations under the License. |
||
2 | daniel-mar | 19 | */ |
20 | |||
14 | daniel-mar | 21 | // error_reporting(E_ALL | E_NOTICE | E_STRICT | E_DEPRECATED); |
2 | daniel-mar | 22 | |
9 | daniel-mar | 23 | if(!defined('STDIN')) define('STDIN', fopen('php://stdin', 'rb')); |
24 | if(!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'wb')); |
||
25 | if(!defined('STDERR')) define('STDERR', fopen('php://stderr', 'wb')); |
||
26 | |||
2 | daniel-mar | 27 | if (file_exists(__DIR__ . '/oid_utils.inc.phps')) require_once __DIR__ . '/oid_utils.inc.phps'; |
28 | if (file_exists(__DIR__ . '/oid_utils.inc.php')) require_once __DIR__ . '/oid_utils.inc.php'; |
||
29 | if (file_exists(__DIR__ . '/xml_utils.inc.phps')) require_once __DIR__ . '/xml_utils.inc.phps'; |
||
30 | if (file_exists(__DIR__ . '/xml_utils.inc.php')) require_once __DIR__ . '/xml_utils.inc.php'; |
||
4 | daniel-mar | 31 | if (file_exists(__DIR__ . '/../includes/oid_utils.inc.php')) require_once __DIR__ . '/../includes/oid_utils.inc.php'; |
32 | if (file_exists(__DIR__ . '/../includes/xml_utils.inc.php')) require_once __DIR__ . '/../includes/xml_utils.inc.php'; |
||
33 | if (file_exists(__DIR__ . '/../../includes/oid_utils.inc.php')) require_once __DIR__ . '/../../includes/oid_utils.inc.php'; |
||
34 | if (file_exists(__DIR__ . '/../../includes/xml_utils.inc.php')) require_once __DIR__ . '/../../includes/xml_utils.inc.php'; |
||
35 | if (file_exists(__DIR__ . '/../../../includes/oid_utils.inc.php')) require_once __DIR__ . '/../../../includes/oid_utils.inc.php'; |
||
36 | if (file_exists(__DIR__ . '/../../../includes/xml_utils.inc.php')) require_once __DIR__ . '/../../../includes/xml_utils.inc.php'; |
||
2 | daniel-mar | 37 | |
38 | class OIDInfoException extends Exception { |
||
39 | } |
||
40 | |||
41 | class OIDInfoAPI { |
||
42 | |||
43 | # --- PART 0: Constants |
||
44 | |||
45 | // First digit of the ping result |
||
46 | // "-" = error |
||
47 | // "0" = OID does not exist |
||
48 | // "1" = OID does exist, but is not approved yet |
||
49 | // "2" = OID does exist and is accessible |
||
50 | /*private*/ const PING_IDX_EXISTS = 0; |
||
51 | |||
52 | // Second digit of the ping result |
||
53 | // "-" = error |
||
54 | // "0" = The OID may not be created |
||
55 | // "1" = OID is not an illegal OID, and none of its ascendant is a leaf and its parent OID is not frozen |
||
56 | /*private*/ const PING_IDX_MAY_CREATE = 1; |
||
57 | |||
58 | /*private*/ const SOFT_CORRECT_BEHAVIOR_NONE = 0; |
||
59 | /*private*/ const SOFT_CORRECT_BEHAVIOR_LOWERCASE_BEGINNING = 1; |
||
60 | /*private*/ const SOFT_CORRECT_BEHAVIOR_ALL_POSSIBLE = 2; |
||
61 | |||
62 | /*public*/ const DEFAULT_ILLEGALITY_RULE_FILE = __DIR__ . '/oid_illegality_rules'; |
||
63 | |||
64 | # --- Part 1: "Ping API" for checking if OIDs are available or allowed to create |
||
65 | |||
66 | public $verbosePingProviders = array('https://misc.daniel-marschall.de/oid-repository/ping_oid.php?oid={OID}'); |
||
67 | |||
68 | private $pingCache = array(); |
||
69 | |||
70 | public $pingCacheMaxAge = 3600; |
||
71 | |||
72 | public function clearPingCache() { |
||
73 | $this->pingCache = array(); |
||
74 | } |
||
75 | |||
76 | public function checkOnlineExists($oid) { |
||
77 | if (!self::strictCheckSyntax($oid)) return false; |
||
78 | |||
79 | $pingResult = $this->pingOID($oid); |
||
80 | $ret = $pingResult[self::PING_IDX_EXISTS] >= 1; |
||
81 | return $ret; |
||
82 | } |
||
83 | |||
84 | public function checkOnlineAvailable($oid) { |
||
85 | if (!self::strictCheckSyntax($oid)) return false; |
||
86 | |||
87 | $pingResult = $this->pingOID($oid); |
||
88 | $ret = $pingResult[self::PING_IDX_EXISTS] == 2; |
||
89 | return $ret; |
||
90 | } |
||
91 | |||
92 | public function checkOnlineAllowed($oid) { |
||
93 | if (!self::strictCheckSyntax($oid)) return false; |
||
94 | |||
95 | $pingResult = $this->pingOID($oid); |
||
96 | return $pingResult[self::PING_IDX_MAY_CREATE] == 1; |
||
97 | } |
||
98 | |||
99 | public function checkOnlineMayCreate($oid) { |
||
100 | if (!self::strictCheckSyntax($oid)) return false; |
||
101 | |||
102 | $pingResult = $this->pingOID($oid); |
||
103 | |||
104 | // OID is either illegal, or one of their parents are leaf or frozen |
||
105 | # if (!checkOnlineAllowed($oid)) return false; |
||
106 | if ($pingResult[self::PING_IDX_MAY_CREATE] == 0) return false; |
||
107 | |||
108 | // The OID exists already, so we don't need to create it again |
||
109 | # if ($this->checkOnlineExists($oid)) return false; |
||
110 | if ($pingResult[self::PING_IDX_EXISTS] >= 1) return false; |
||
111 | |||
112 | return true; |
||
113 | } |
||
114 | |||
115 | protected function pingOID($oid) { |
||
116 | if (isset($this->pingCache[$oid])) { |
||
117 | $cacheAge = $this->pingCache[$oid][0] - time(); |
||
118 | if ($cacheAge <= $this->pingCacheMaxAge) { |
||
119 | return $this->pingCache[$oid][1]; |
||
120 | } |
||
121 | } |
||
122 | |||
123 | if (count($this->verbosePingProviders) == 0) { |
||
124 | throw new OIDInfoException("No verbose ping provider available!"); |
||
125 | } |
||
126 | |||
127 | $res = false; |
||
128 | foreach ($this->verbosePingProviders as $url) { |
||
129 | $url = str_replace('{OID}', $oid, $url); |
||
130 | $cn = @file_get_contents($url); |
||
131 | if ($cn === false) continue; |
||
132 | $loc_res = trim($cn); |
||
133 | if (strpos($loc_res, '-') === false) { |
||
134 | $res = $loc_res; |
||
135 | break; |
||
136 | } |
||
137 | } |
||
138 | if ($res === false) { |
||
139 | throw new OIDInfoException("Could not ping OID $oid status!"); |
||
140 | } |
||
141 | |||
142 | // if ($this->pingCacheMaxAge >= 0) { |
||
143 | $this->pingCache[$oid] = array(time(), $res); |
||
144 | //} |
||
145 | |||
146 | return $res; |
||
147 | } |
||
148 | |||
149 | # --- PART 2: Syntax checking |
||
150 | |||
151 | public static function strictCheckSyntax($oid) { |
||
152 | return oid_valid_dotnotation($oid, false, false, 1); |
||
153 | } |
||
154 | |||
155 | // Returns false if $oid has wrong syntax |
||
156 | // Return an OID without leading dot or zeroes, if the syntax is acceptable |
||
157 | public static function trySanitizeOID($oid) { |
||
158 | // Allow leading dots and leading zeroes, but remove then afterwards |
||
159 | $ok = oid_valid_dotnotation($oid, true, true, 1); |
||
160 | if ($ok === false) return false; |
||
161 | |||
162 | return sanitizeOID($oid, $oid[0] == '.'); |
||
163 | } |
||
164 | |||
165 | # --- PART 3: XML file creation |
||
166 | |||
167 | protected static function eMailValid($email) { |
||
168 | # TODO: use isemail project |
||
169 | |||
170 | if (empty($email)) return false; |
||
171 | |||
172 | if (strpos($email, '@') === false) return false; |
||
173 | |||
174 | $ary = explode('@', $email, 2); |
||
175 | if (!isset($ary[1])) return false; |
||
176 | if (strpos($ary[1], '.') === false) return false; |
||
177 | |||
178 | return true; |
||
179 | } |
||
180 | |||
181 | public function softCorrectEMail($email, $params) { |
||
24 | daniel-mar | 182 | $params = $this->init_params($params); |
183 | |||
2 | daniel-mar | 184 | $email = str_replace(' ', '', $email); |
185 | $email = str_replace('&', '@', $email); |
||
186 | $email = str_replace('(at)', '@', $email); |
||
187 | $email = str_replace('[at]', '@', $email); |
||
188 | $email = str_replace('(dot)', '.', $email); |
||
189 | $email = str_replace('[dot]', '.', $email); |
||
190 | $email = trim($email); |
||
191 | |||
192 | if (!$params['allow_illegal_email'] && !self::eMailValid($email)) { |
||
193 | return ''; |
||
194 | } |
||
195 | |||
196 | return $email; |
||
197 | } |
||
198 | |||
199 | public function softCorrectPhone($phone, $params) { |
||
24 | daniel-mar | 200 | $params = $this->init_params($params); |
201 | |||
2 | daniel-mar | 202 | // TODO: if no "+", add "+1" , but only if address is in USA |
203 | // TODO: or use param to fixate country if it is not known |
||
204 | /* |
||
205 | NOTE: with german phone numbers, this will cause trouble, even if we assume "+49" |
||
206 | 06223 / 1234 |
||
207 | shall be |
||
208 | +49 6223 1234 |
||
209 | and not |
||
210 | +49 06223 1234 |
||
211 | */ |
||
212 | |||
213 | $phone = str_replace('-', ' ', $phone); |
||
214 | $phone = str_replace('.', ' ', $phone); |
||
215 | $phone = str_replace('/', ' ', $phone); |
||
216 | $phone = str_replace('(', ' ', $phone); |
||
217 | $phone = str_replace(')', ' ', $phone); |
||
218 | |||
219 | // HL7 registry has included this accidently |
||
220 | $phone = str_replace('"', '', $phone); |
||
221 | |||
222 | $phone = trim($phone); |
||
223 | |||
224 | return $phone; |
||
225 | } |
||
226 | |||
5 | daniel-mar | 227 | private static function strip_to_xhtml_light($str, $allow_strong_text=false) { |
228 | // <strong> is allowed in the XSD, but not <b> |
||
2 | daniel-mar | 229 | $str = str_ireplace('<b>', '<strong>', $str); |
230 | $str = str_ireplace('</b>', '</strong>', $str); |
||
231 | |||
5 | daniel-mar | 232 | if (!$allow_strong_text) { |
233 | // <strong> is only used for very important things like the word "deprecated". It should therefore not used for anything else |
||
234 | $str = str_ireplace('<strong>', '', $str); |
||
235 | $str = str_ireplace('</strong>', '', $str); |
||
236 | } |
||
237 | |||
2 | daniel-mar | 238 | $str = preg_replace('@<\s*script.+<\s*/script.*>@isU', '', $str); |
239 | $str = preg_replace('@<\s*style.+<\s*/style.*>@isU', '', $str); |
||
240 | |||
241 | $str = preg_replace_callback( |
||
242 | '@<(\s*/{0,1}\d*)([^\s/>]+)(\s*[^>]*)>@i', |
||
243 | function ($treffer) { |
||
244 | // see http://oid-info.com/xhtml-light.xsd |
||
245 | $whitelist = array('a', 'br', 'code', 'em', 'font', 'img', 'li', 'strong', 'sub', 'sup', 'ul'); |
||
246 | |||
247 | $pre = $treffer[1]; |
||
248 | $tag = $treffer[2]; |
||
249 | $attrib = $treffer[3]; |
||
250 | if (in_array($tag, $whitelist)) { |
||
251 | return '<'.$pre.$tag.$attrib.'>'; |
||
252 | } else { |
||
253 | return ''; |
||
254 | } |
||
255 | }, $str); |
||
256 | |||
257 | return $str; |
||
258 | } |
||
259 | |||
260 | const OIDINFO_CORRECT_DESC_OPTIONAL_ENDING_DOT = 0; |
||
261 | const OIDINFO_CORRECT_DESC_ENFORCE_ENDING_DOT = 1; |
||
262 | const OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT = 2; |
||
263 | |||
264 | public function correctDesc($desc, $params, $ending_dot_policy=self::OIDINFO_CORRECT_DESC_OPTIONAL_ENDING_DOT, $enforce_xhtml_light=false) { |
||
24 | daniel-mar | 265 | $params = $this->init_params($params); |
266 | |||
2 | daniel-mar | 267 | $desc = trim($desc); |
268 | |||
269 | $desc = preg_replace('@<!\\[CDATA\\[(.+)\\]\\]>@ismU', '\\1', $desc); |
||
270 | |||
271 | if (substr_count($desc, '>') != substr_count($desc, '<')) { |
||
272 | $params['allow_html'] = false; |
||
273 | } |
||
274 | |||
275 | $desc = str_replace("\r", '', $desc); |
||
276 | |||
277 | if (!$params['allow_html']) { |
||
278 | // htmlentities_numeric() does this for us |
||
279 | /* |
||
280 | $desc = str_replace('&', '&', $desc); |
||
281 | $desc = str_replace('<', '<', $desc); |
||
282 | $desc = str_replace('>', '>', $desc); |
||
283 | $desc = str_replace('"', '"', $desc); |
||
284 | $desc = str_replace("'", ''', $desc); // ' is not HTML. It is XML |
||
285 | */ |
||
286 | |||
287 | $desc = str_replace("\n", '<br />', $desc); |
||
288 | } else { |
||
289 | // Some problems we had with HL7 registry |
||
290 | $desc = preg_replace('@<(/{0,1}(p|i|b|u|ul|li))>@ismU', '<\\1>', $desc); |
||
291 | # preg_match_all('@<[^ :\\@]+>@ismU', $desc, $m); |
||
292 | # if (count($m[0]) > 0) print_r($m); |
||
293 | |||
294 | $desc = preg_replace('@<i>(.+)<i/>@ismU', '<i>\\1</i>', $desc); |
||
295 | $desc = str_replace('<p><p>', '</p><p>', $desc); |
||
296 | |||
297 | // <p> are not supported by oid-info.com |
||
298 | $desc = str_replace('<p>', '<br /><br />', $desc); |
||
299 | $desc = str_replace('</p>', '', $desc); |
||
300 | } |
||
301 | |||
302 | // Escape unicode characters as numeric &#...; |
||
303 | // The XML 1.0 standard does only has a few entities, but nothing like e.g. € , so we prefer numeric |
||
304 | |||
305 | //$desc = htmlentities_numeric($desc, $params['allow_html']); |
||
306 | if (!$params['allow_html']) $desc = htmlentities($desc); |
||
307 | $desc = html_named_to_numeric_entities($desc); |
||
308 | |||
309 | // Remove HTML tags which are not allowed |
||
310 | if ($params['allow_html'] && (!$params['ignore_xhtml_light']) && $enforce_xhtml_light) { |
||
311 | // oid-info.com does only allow a few HTML tags |
||
312 | // see http://oid-info.com/xhtml-light.xsd |
||
313 | $desc = self::strip_to_xhtml_light($desc); |
||
314 | } |
||
315 | |||
316 | // Solve some XML problems... |
||
317 | $desc = preg_replace('@<\s*br\s*>@ismU', '<br/>', $desc); // auto close <br> |
||
318 | $desc = preg_replace('@(href\s*=\s*)(["\'])(.*)&([^#].*)(\2)@ismU', '\1\2\3&\4\5', $desc); // fix "&" inside href-URLs to & |
||
319 | // TODO: what do we do if there are more XHTML errors (e.g. additional open tags) which would make the XML invalid? |
||
320 | |||
321 | // "Trim" <br/> |
||
13 | daniel-mar | 322 | $count = 0; |
2 | daniel-mar | 323 | do { $desc = preg_replace('@^\s*<\s*br\s*/{0,1}\s*>@isU', '', $desc, -1, $count); } while ($count > 0); // left trim |
324 | do { $desc = preg_replace('@<\s*br\s*/{0,1}\s*>\s*$@isU', '', $desc, -1, $count); } while ($count > 0); // right trim |
||
325 | |||
326 | // Correct double-encoded stuff |
||
327 | if (!isset($params['tolerant_htmlentities']) || $params['tolerant_htmlentities']) { |
||
328 | do { |
||
329 | $old_desc = $desc; |
||
330 | # Full list of entities: https://www.freeformatter.com/html-entities.html |
||
331 | # Max: 8 chars ( ϑ ) |
||
332 | # Min: 2 chars ( lt,gt,ni,or,ne,le,ge,Mu,Nu,Xi,Pi,mu,nu,xi,pi ) |
||
333 | $desc = preg_replace('@(&|&)(#|#)(\d+);@ismU', '&#\3;', $desc); |
||
334 | $desc = preg_replace('@(&|&)([a-zA-Z0-9]{2,8});@ismU', '&\2;', $desc); |
||
335 | } while ($old_desc != $desc); |
||
336 | } |
||
337 | |||
338 | // TODO: use the complete list of oid-info.com |
||
339 | // TODO: Make this step optional using $params |
||
340 | /* |
||
341 | Array |
||
342 | ( |
||
343 | [0] => Root OID for |
||
344 | [1] => OID for |
||
345 | [2] => OID identifying |
||
346 | [3] => Top arc for |
||
347 | [4] => Arc for |
||
348 | [5] => arc root |
||
349 | [6] => Node for |
||
350 | [7] => Leaf node for |
||
351 | [8] => This OID describes |
||
352 | [9] => [tT]his oid |
||
353 | [10] => This arc describes |
||
354 | [11] => This identifies |
||
355 | [12] => Identifies a |
||
356 | [13] => [Oo]bject [Ii]dentifier |
||
357 | [14] => Identifier for |
||
358 | [15] => This [Ii]dentifier is for |
||
359 | [16] => Identifiers used by |
||
360 | [17] => identifier$ |
||
361 | [18] => This branch |
||
362 | [19] => Branch for |
||
363 | [20] => Child tree for |
||
364 | [21] => Child for |
||
365 | [22] => Subtree for |
||
366 | [23] => Sub-OID |
||
367 | [24] => Tree for |
||
368 | [25] => Child object |
||
369 | [26] => Parent OID |
||
370 | [27] => root for |
||
371 | [28] => Assigned for |
||
372 | [29] => Used to identify |
||
373 | [30] => Used in |
||
374 | [31] => Used for |
||
375 | [32] => For use by |
||
376 | [33] => Entry for |
||
377 | [34] => This is for |
||
378 | [35] => ["]?OID["]? |
||
379 | [36] => ^OID |
||
380 | [37] => OID$ |
||
381 | [38] => oid |
||
382 | [39] => oid$ |
||
383 | [40] => OIDs |
||
384 | ) |
||
385 | $x = 'Root OID for ; OID for ; OID identifying ; Top arc for ; Arc for ; arc root; Node for ; Leaf node for ; This OID describes ; [tT]his oid ; This arc describes ; This identifies ; Identifies a ; [Oo]bject [Ii]dentifier; Identifier for ; This [Ii]dentifier is for ; Identifiers used by ; identifier$; This branch ; Branch for ; Child tree for ; Child for ; Subtree for ; Sub-OID; Tree for ; Child object; Parent OID; root for ; Assigned for ; Used to identify ; Used in ; Used for ; For use by ; Entry for ; This is for ; ["]?OID["]? ; ^OID ; OID$; oid ; oid$; OIDs'; |
||
386 | $ary = explode('; ', $x); |
||
387 | print_r($ary); |
||
388 | */ |
||
389 | $desc = preg_replace("@^Root OID for the @i", '', $desc); |
||
390 | $desc = preg_replace("@^Root OID for @i", '', $desc); |
||
391 | $desc = preg_replace("@^OID root for the @i", '', $desc); |
||
392 | $desc = preg_replace("@^OID root for @i", '', $desc); |
||
393 | $desc = preg_replace("@^This OID will be used for @i", '', $desc); |
||
394 | $desc = preg_replace("@^This will be a generic OID for the @i", '', $desc); |
||
395 | $desc = preg_replace("@^OID for @i", '', $desc); |
||
396 | $desc = preg_replace("@ Root OID$@i", '', $desc); |
||
397 | $desc = preg_replace("@ OID$@i", '', $desc); |
||
398 | $desc = preg_replace("@ OID Namespace$@i", '', $desc); |
||
399 | $desc = preg_replace("@^OID for @i", '', $desc); |
||
27 | daniel-mar | 400 | $desc = preg_replace("@OID root$@i", '', $desc); |
401 | $desc = preg_replace("@Object Identifier$@i", '', $desc); |
||
402 | $desc = preg_replace("@^The @i", '', $desc); |
||
2 | daniel-mar | 403 | |
404 | $desc = rtrim($desc); |
||
405 | if ($ending_dot_policy == self::OIDINFO_CORRECT_DESC_ENFORCE_ENDING_DOT) { |
||
406 | if (($desc != '') && (substr($desc, -1)) != '.') $desc .= '.'; |
||
407 | } else if ($ending_dot_policy == self::OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT) { |
||
408 | $desc = preg_replace('@\\.$@', '', $desc); |
||
409 | } |
||
410 | |||
27 | daniel-mar | 411 | // Required for XML importer of oid-info.com (E-Mail 09.12.2021) |
412 | $desc = str_replace('&', '&amp;', $desc); |
||
413 | |||
2 | daniel-mar | 414 | return $desc; |
415 | } |
||
416 | |||
417 | public function xmlAddHeader($firstName, $lastName, $email) { |
||
418 | // TODO: encode |
||
419 | |||
420 | $firstName = htmlentities_numeric($firstName); |
||
421 | if (empty($firstName)) { |
||
422 | throw new OIDInfoException("Please supply a first name"); |
||
423 | } |
||
424 | |||
425 | $lastName = htmlentities_numeric($lastName); |
||
426 | if (empty($lastName)) { |
||
427 | throw new OIDInfoException("Please supply a last name"); |
||
428 | } |
||
429 | |||
430 | $email = htmlentities_numeric($email); |
||
431 | if (empty($email)) { |
||
432 | throw new OIDInfoException("Please supply an email address"); |
||
433 | } |
||
434 | |||
435 | // $out = "<!DOCTYPE oid-database>\n\n"; |
||
436 | $out = '<?xml version="1.0" encoding="UTF-8" ?>'."\n"; |
||
437 | $out .= '<oid-database xmlns="http://oid-info.com"'."\n"; |
||
438 | $out .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'."\n"; |
||
439 | $out .= ' xsi:schemaLocation="http://oid-info.com '."\n"; |
||
440 | $out .= ' http://oid-info.com/oid.xsd">'."\n"; |
||
441 | $out .= "\t<submitter>\n"; |
||
442 | $out .= "\t\t<first-name>$firstName</first-name>\n"; |
||
443 | $out .= "\t\t<last-name>$lastName</last-name>\n"; |
||
444 | $out .= "\t\t<email>$email</email>\n"; |
||
445 | $out .= "\t</submitter>\n"; |
||
446 | |||
447 | if (!self::eMailValid($email)) { |
||
448 | throw new OIDInfoException("eMail address '$email' is invalid"); |
||
449 | } |
||
450 | |||
451 | return $out; |
||
452 | } |
||
453 | |||
454 | public function xmlAddFooter() { |
||
455 | return "</oid-database>\n"; |
||
456 | } |
||
457 | |||
458 | /* |
||
459 | -- CODE TEMPLATE -- |
||
460 | |||
461 | $params['allow_html'] = false; // Allow HTML in <description> and <information> |
||
462 | $params['allow_illegal_email'] = true; // We should allow it, because we don't know if the user has some kind of human-readable anti-spam technique |
||
463 | $params['soft_correct_behavior'] = OIDInfoAPI::SOFT_CORRECT_BEHAVIOR_NONE; |
||
464 | $params['do_online_check'] = false; // Flag to disable this online check, because it generates a lot of traffic and runtime. |
||
465 | $params['do_illegality_check'] = true; |
||
466 | $params['do_simpleping_check'] = true; |
||
467 | $params['auto_extract_name'] = ''; |
||
468 | $params['auto_extract_url'] = ''; |
||
469 | $params['always_output_comment'] = false; // Also output comment if there was an error (e.g. OID already existing) |
||
470 | $params['creation_allowed_check'] = true; |
||
471 | $params['tolerant_htmlentities'] = true; |
||
472 | $params['ignore_xhtml_light'] = false; |
||
473 | |||
474 | $elements['synonymous-identifier'] = ''; // string or array |
||
475 | $elements['description'] = ''; |
||
476 | $elements['information'] = ''; |
||
477 | |||
478 | $elements['first-registrant']['first-name'] = ''; |
||
479 | $elements['first-registrant']['last-name'] = ''; |
||
480 | $elements['first-registrant']['address'] = ''; |
||
481 | $elements['first-registrant']['email'] = ''; |
||
482 | $elements['first-registrant']['phone'] = ''; |
||
483 | $elements['first-registrant']['fax'] = ''; |
||
484 | $elements['first-registrant']['creation-date'] = ''; |
||
485 | |||
486 | $elements['current-registrant']['first-name'] = ''; |
||
487 | $elements['current-registrant']['last-name'] = ''; |
||
488 | $elements['current-registrant']['address'] = ''; |
||
489 | $elements['current-registrant']['email'] = ''; |
||
490 | $elements['current-registrant']['phone'] = ''; |
||
491 | $elements['current-registrant']['fax'] = ''; |
||
492 | $elements['current-registrant']['modification-date'] = ''; |
||
493 | |||
494 | $oid = '1.2.3'; |
||
495 | |||
496 | $comment = 'test'; |
||
497 | |||
498 | echo $oa->createXMLEntry($oid, $elements, $params, $comment); |
||
499 | */ |
||
24 | daniel-mar | 500 | private function init_params($params) { |
2 | daniel-mar | 501 | // Backward compatibility |
502 | if (!isset($params['do_csv_check'])) $params['do_simpleping_check'] = true; |
||
503 | |||
504 | // Set default behavior |
||
505 | if (!isset($params['allow_html'])) $params['allow_html'] = false; // Allow HTML in <description> and <information> |
||
506 | if (!isset($params['allow_illegal_email'])) $params['allow_illegal_email'] = true; // We should allow it, because we don't know if the user has some kind of human-readable anti-spam technique |
||
507 | if (!isset($params['soft_correct_behavior'])) $params['soft_correct_behavior'] = self::SOFT_CORRECT_BEHAVIOR_NONE; |
||
508 | if (!isset($params['do_online_check'])) $params['do_online_check'] = false; // Flag to disable this online check, because it generates a lot of traffic and runtime. |
||
509 | if (!isset($params['do_illegality_check'])) $params['do_illegality_check'] = true; |
||
510 | if (!isset($params['do_simpleping_check'])) $params['do_simpleping_check'] = true; |
||
511 | if (!isset($params['auto_extract_name'])) $params['auto_extract_name'] = ''; |
||
512 | if (!isset($params['auto_extract_url'])) $params['auto_extract_url'] = ''; |
||
513 | if (!isset($params['always_output_comment'])) $params['always_output_comment'] = false; // Also output comment if there was an error (e.g. OID already existing) |
||
514 | if (!isset($params['creation_allowed_check'])) $params['creation_allowed_check'] = true; |
||
515 | if (!isset($params['tolerant_htmlentities'])) $params['tolerant_htmlentities'] = true; |
||
516 | if (!isset($params['ignore_xhtml_light'])) $params['ignore_xhtml_light'] = false; |
||
26 | daniel-mar | 517 | if (!isset($params['show_errors'])) $params['show_errors'] = true; |
2 | daniel-mar | 518 | |
24 | daniel-mar | 519 | return $params; |
520 | } |
||
521 | public function createXMLEntry($oid, $elements, $params, $comment='') { |
||
522 | $params = $this->init_params($params); |
||
523 | |||
2 | daniel-mar | 524 | $out = ''; |
525 | if (!empty($comment)) $out .= "\t\t<!-- $comment -->\n"; |
||
526 | |||
527 | if ($params['always_output_comment']) { |
||
528 | $err = $out; |
||
529 | } else { |
||
530 | $err = false; |
||
531 | } |
||
532 | |||
533 | if (isset($elements['dotted_oid'])) { |
||
534 | throw new OIDInfoException("'dotted_oid' in the \$elements array is not supported. Please use the \$oid argument."); |
||
535 | } |
||
536 | if (isset($elements['value'])) { |
||
537 | // TODO: WHAT SHOULD WE DO WITH THAT? |
||
538 | throw new OIDInfoException("'value' in the \$elements array is currently not supported."); |
||
539 | } |
||
540 | |||
541 | $bak_oid = $oid; |
||
542 | $oid = self::trySanitizeOID($oid); |
||
543 | if ($oid === false) { |
||
26 | daniel-mar | 544 | if ($params['show_errors']) fwrite(STDOUT/*STDERR*/,"<!-- ERROR: Ignored '$bak_oid', because it is not a valid OID -->\n"); |
6 | daniel-mar | 545 | return $err; |
2 | daniel-mar | 546 | } |
547 | |||
548 | if ($params['creation_allowed_check']) { |
||
6 | daniel-mar | 549 | if (!$this->oidMayCreate($oid, $params['do_online_check'], $params['do_simpleping_check'], $params['do_illegality_check'])) { |
26 | daniel-mar | 550 | if ($params['show_errors']) fwrite(STDOUT/*STDERR*/,"<!-- ERROR: Creation of $oid disallowed -->\n"); |
6 | daniel-mar | 551 | return $err; |
552 | } |
||
7 | daniel-mar | 553 | } else { |
554 | if ($params['do_illegality_check'] && ($this->illegalOid($oid))) { |
||
26 | daniel-mar | 555 | if ($params['show_errors']) fwrite(STDOUT/*STDERR*/,"<!-- ERROR: Creation of $oid disallowed -->\n"); |
7 | daniel-mar | 556 | return $err; |
557 | } |
||
2 | daniel-mar | 558 | } |
559 | |||
26 | daniel-mar | 560 | if (!isset($elements['description'])) $elements['description'] = ''; |
561 | if (!isset($elements['information'])) $elements['information'] = ''; |
||
562 | |||
2 | daniel-mar | 563 | $elements['description'] = $this->correctDesc($elements['description'], $params, self::OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT, true); |
564 | $elements['information'] = $this->correctDesc($elements['information'], $params, self::OIDINFO_CORRECT_DESC_ENFORCE_ENDING_DOT, true); |
||
565 | |||
5 | daniel-mar | 566 | // Request by O.D. 26 August 2019 |
567 | $elements['description'] = trim($elements['description']); |
||
13 | daniel-mar | 568 | $m = array(); |
5 | daniel-mar | 569 | if (preg_match('@^[a-z]@', $elements['description'], $m)) { |
6 | daniel-mar | 570 | $ending_dot_policy = self::OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT; // for description |
5 | daniel-mar | 571 | if (($ending_dot_policy != self::OIDINFO_CORRECT_DESC_ENFORCE_ENDING_DOT) && (strpos($elements['description'], ' ') === false)) { // <-- added by DM |
572 | $elements['description'] = '"' . $elements['description'] . '"'; |
||
573 | } |
||
574 | } |
||
575 | // End request by O.D. 26. August 2019 |
||
576 | |||
2 | daniel-mar | 577 | if ($params['auto_extract_name'] || $params['auto_extract_url']) { |
578 | if (!empty($elements['information'])) $elements['information'] .= '<br /><br />'; |
||
579 | if ($params['auto_extract_name'] || $params['auto_extract_url']) { |
||
580 | $elements['information'] .= 'Automatically extracted from <a href="'.$params['auto_extract_url'].'">'.$params['auto_extract_name'].'</a>.'; |
||
581 | } else if ($params['auto_extract_name']) { |
||
582 | $elements['information'] .= 'Automatically extracted from '.$params['auto_extract_name']; |
||
583 | } else if ($params['auto_extract_url']) { |
||
584 | $hr_url = $params['auto_extract_url']; |
||
585 | // $hr_url = preg_replace('@^https{0,1}://@ismU', '', $hr_url); |
||
586 | $hr_url = preg_replace('@^http://@ismU', '', $hr_url); |
||
587 | $elements['information'] .= 'Automatically extracted from <a href="'.$params['auto_extract_url'].'">'.$hr_url.'</a>.'; |
||
588 | } |
||
589 | } |
||
590 | |||
591 | // Validate ASN.1 ID |
||
592 | if (isset($elements['synonymous-identifier'])) { |
||
593 | if (!is_array($elements['synonymous-identifier'])) { |
||
594 | $elements['synonymous-identifier'] = array($elements['synonymous-identifier']); |
||
595 | } |
||
596 | foreach ($elements['synonymous-identifier'] as &$synid) { |
||
597 | if ($synid == '') { |
||
598 | $synid = null; |
||
599 | continue; |
||
600 | } |
||
601 | |||
602 | $behavior = $params['soft_correct_behavior']; |
||
603 | |||
604 | if ($behavior == self::SOFT_CORRECT_BEHAVIOR_NONE) { |
||
605 | if (!oid_id_is_valid($synid)) $synid = null; |
||
606 | } else if ($behavior == self::SOFT_CORRECT_BEHAVIOR_LOWERCASE_BEGINNING) { |
||
607 | $synid[0] = strtolower($synid[0]); |
||
608 | if (!oid_id_is_valid($synid)) $synid = null; |
||
609 | } else if ($behavior == self::SOFT_CORRECT_BEHAVIOR_ALL_POSSIBLE) { |
||
610 | $synid = oid_soft_correct_id($synid); |
||
611 | // if (!oid_id_is_valid($synid)) $synid = null; |
||
612 | } else { |
||
613 | throw new OIDInfoException("Unexpected soft-correction behavior for ASN.1 IDs"); |
||
614 | } |
||
615 | } |
||
616 | } |
||
617 | |||
618 | // ATTENTION: the XML-generator will always add <dotted-oid> , but what will happen if additionally an |
||
619 | // asn1-path (<value>) is given? (the resulting OIDs might be inconsistent/mismatch) |
||
620 | if (isset($elements['value']) && (!asn1_path_valid($elements['value']))) { |
||
621 | unset($elements['value']); |
||
622 | } |
||
623 | |||
624 | // Validate IRI (currently not supported by oid-info.com, but the tag name is reserved) |
||
625 | if (isset($elements['iri'])) { |
||
626 | if (!is_array($elements['iri'])) { |
||
627 | $elements['iri'] = array($elements['iri']); |
||
628 | } |
||
629 | foreach ($elements['iri'] as &$iri) { |
||
15 | daniel-mar | 630 | // Do not allow Numeric-only. It would only be valid in an IRI path, but not in a single identifier |
2 | daniel-mar | 631 | if (!iri_arc_valid($iri, false)) $iri = null; |
632 | } |
||
633 | } |
||
634 | |||
635 | if (isset($elements['first-registrant']['phone'])) |
||
636 | $elements['first-registrant']['phone'] = $this->softCorrectPhone($elements['first-registrant']['phone'], $params); |
||
637 | |||
638 | if (isset($elements['current-registrant']['phone'])) |
||
639 | $elements['current-registrant']['phone'] = $this->softCorrectPhone($elements['current-registrant']['phone'], $params); |
||
640 | |||
641 | if (isset($elements['first-registrant']['fax'])) |
||
642 | $elements['first-registrant']['fax'] = $this->softCorrectPhone($elements['first-registrant']['fax'], $params); |
||
643 | |||
644 | if (isset($elements['current-registrant']['fax'])) |
||
645 | $elements['current-registrant']['fax'] = $this->softCorrectPhone($elements['current-registrant']['fax'], $params); |
||
646 | |||
647 | if (isset($elements['first-registrant']['email'])) |
||
648 | $elements['first-registrant']['email'] = $this->softCorrectEMail($elements['first-registrant']['email'], $params); |
||
649 | |||
650 | if (isset($elements['current-registrant']['email'])) |
||
651 | $elements['current-registrant']['email'] = $this->softCorrectEMail($elements['current-registrant']['email'], $params); |
||
652 | |||
653 | // TODO: if name is empty, but address has 1 line, take it as firstname (but remove hyperlink) |
||
654 | |||
655 | $out_loc = ''; |
||
656 | foreach ($elements as $name => $val) { |
||
657 | if (($name == 'first-registrant') || ($name == 'current-registrant')) { |
||
658 | $out_loc2 = ''; |
||
659 | foreach ($val as $name2 => $val2) { |
||
660 | if (is_null($val2)) continue; |
||
661 | if (empty($val2)) continue; |
||
662 | |||
663 | if (!is_array($val2)) $val2 = array($val2); |
||
664 | |||
665 | foreach ($val2 as $val3) { |
||
666 | // if (is_null($val3)) continue; |
||
667 | if (empty($val3)) continue; |
||
668 | |||
669 | if ($name2 == 'address') { |
||
670 | // $val3 = htmlentities_numeric($val3); |
||
671 | $val3 = $this->correctDesc($val3, $params, self::OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT, true); |
||
672 | } else { |
||
673 | // $val3 = htmlentities_numeric($val3); |
||
674 | $val3 = $this->correctDesc($val3, $params, self::OIDINFO_CORRECT_DESC_DISALLOW_ENDING_DOT, false); |
||
675 | } |
||
676 | $out_loc2 .= "\t\t\t<$name2>".$val3."</$name2>\n"; |
||
677 | } |
||
678 | } |
||
679 | |||
680 | if (!empty($out_loc2)) { |
||
681 | $out_loc .= "\t\t<$name>\n"; |
||
682 | $out_loc .= $out_loc2; |
||
683 | $out_loc .= "\t\t</$name>\n"; |
||
684 | } |
||
685 | } else { |
||
686 | // if (is_null($val)) continue; |
||
687 | if (empty($val) && ($name != 'description')) continue; // description is mandatory, according to http://oid-info.com/oid.xsd |
||
688 | |||
689 | if (!is_array($val)) $val = array($val); |
||
690 | |||
691 | foreach ($val as $val2) { |
||
692 | // if (is_null($val2)) continue; |
||
693 | if (empty($val2) && ($name != 'description')) continue; // description is mandatory, according to http://oid-info.com/oid.xsd |
||
694 | |||
695 | if (($name != 'description') && ($name != 'information')) { // don't correctDesc description/information, because we already did it above. |
||
696 | // $val2 = htmlentities_numeric($val2); |
||
697 | $val2 = $this->correctDesc($val2, $params, self::OIDINFO_CORRECT_DESC_OPTIONAL_ENDING_DOT, false); |
||
698 | } |
||
699 | $out_loc .= "\t\t<$name>".$val2."</$name>\n"; |
||
700 | } |
||
701 | } |
||
702 | } |
||
703 | |||
704 | if (!empty($out)) { |
||
705 | $out = "\t<oid>\n"."\t\t".trim($out)."\n"; |
||
706 | } else { |
||
707 | $out = "\t<oid>\n"; |
||
708 | } |
||
709 | $out .= "\t\t<dot-notation>$oid</dot-notation>\n"; |
||
710 | $out .= $out_loc; |
||
711 | $out .= "\t</oid>\n"; |
||
712 | |||
713 | return $out; |
||
714 | } |
||
715 | |||
716 | # --- PART 4: Offline check if OIDs are illegal |
||
717 | |||
718 | protected $illegality_rules = array(); |
||
719 | |||
720 | public function clearIllegalityRules() { |
||
721 | $this->illegality_rules = array(); |
||
722 | } |
||
723 | |||
724 | public function loadIllegalityRuleFile($file) { |
||
725 | if (!file_exists($file)) { |
||
726 | throw new OIDInfoException("Error: File '$file' does not exist"); |
||
727 | } |
||
728 | |||
729 | $lines = file($file); |
||
730 | |||
731 | if ($lines === false) { |
||
732 | throw new OIDInfoException("Error: Could not load '$file'"); |
||
733 | } |
||
734 | |||
735 | $signature = trim(array_shift($lines)); |
||
736 | if (($signature != '[1.3.6.1.4.1.37476.3.1.5.1]') && ($signature != '[1.3.6.1.4.1.37476.3.1.5.2]')) { |
||
737 | throw new OIDInfoException("'$file' does not seem to a valid illegality rule file (file format OID does not match. Signature $signature unexpected)"); |
||
738 | } |
||
739 | |||
740 | foreach ($lines as $line) { |
||
741 | // Remove comments |
||
742 | $ary = explode('--', $line); |
||
743 | $rule = trim($ary[0]); |
||
744 | |||
745 | if ($rule !== '') $this->addIllegalityRule($rule); |
||
746 | } |
||
747 | } |
||
748 | |||
749 | public function addIllegalityRule($rule) { |
||
750 | $test = $rule; |
||
751 | $test = preg_replace('@\\.\\(!\\d+\\)@ismU', '.0', $test); // added in ver 2 |
||
752 | $test = preg_replace('@\\.\\(\\d+\\+\\)@ismU', '.0', $test); |
||
753 | $test = preg_replace('@\\.\\(\\d+\\-\\)@ismU', '.0', $test); |
||
754 | $test = preg_replace('@\\.\\(\\d+\\-\\d+\\)@ismU', '.0', $test); |
||
755 | $test = preg_replace('@\\.\\*@ismU', '.0', $test); |
||
756 | |||
757 | if (!oid_valid_dotnotation($test, false, false, 1)) { |
||
758 | throw new OIDInfoException("Illegal illegality rule '$rule'."); |
||
759 | } |
||
760 | |||
761 | $this->illegality_rules[] = $rule; |
||
762 | } |
||
763 | |||
7 | daniel-mar | 764 | private static function bigint_cmp($a, $b) { |
765 | if (function_exists('bccomp')) { |
||
766 | return bccomp($a, $b); |
||
767 | } |
||
768 | |||
769 | if (function_exists('gmp_cmp')) { |
||
770 | return gmp_cmp($a, $b); |
||
771 | } |
||
772 | |||
773 | if ($a > $b) return 1; |
||
774 | if ($a < $b) return -1; |
||
775 | return 0; |
||
776 | } |
||
777 | |||
2 | daniel-mar | 778 | public function illegalOID($oid, &$illegal_root='') { |
779 | $bak = $oid; |
||
780 | $oid = self::trySanitizeOID($oid); |
||
781 | if ($oid === false) { |
||
782 | $illegal_root = $bak; |
||
783 | return true; // is illegal |
||
784 | } |
||
785 | |||
786 | $rules = $this->illegality_rules; |
||
787 | |||
788 | foreach ($rules as $rule) { |
||
789 | $rule = str_replace(array('(', ')'), '', $rule); |
||
790 | |||
791 | $oarr = explode('.', $oid); |
||
792 | $rarr = explode('.', $rule); |
||
793 | |||
794 | if (count($oarr) < count($rarr)) continue; |
||
795 | |||
796 | $rulefit = true; |
||
797 | |||
798 | $illrootary = array(); |
||
799 | |||
800 | $vararcs = 0; |
||
801 | $varsfit = 0; |
||
802 | for ($i=0; $i<count($rarr); $i++) { |
||
803 | $oelem = $oarr[$i]; |
||
804 | $relem = $rarr[$i]; |
||
805 | |||
806 | $illrootary[] = $oelem; |
||
807 | |||
808 | if ($relem == '*') $relem = '0+'; |
||
809 | |||
810 | $startchar = substr($relem, 0, 1); |
||
811 | $endchar = substr($relem, -1, 1); |
||
812 | if ($startchar == '!') { // added in ver 2 |
||
813 | $vararcs++; |
||
814 | $relem = substr($relem, 1, strlen($relem)-1); // cut away first char |
||
7 | daniel-mar | 815 | $cmp = self::bigint_cmp($oelem, $relem) != 0; |
816 | if ($cmp) $varsfit++; |
||
2 | daniel-mar | 817 | } else if ($endchar == '+') { |
818 | $vararcs++; |
||
819 | $relem = substr($relem, 0, strlen($relem)-1); // cut away last char |
||
7 | daniel-mar | 820 | $cmp = self::bigint_cmp($oelem, $relem) >= 0; |
821 | if ($cmp) $varsfit++; |
||
2 | daniel-mar | 822 | } else if ($endchar == '-') { |
823 | $vararcs++; |
||
824 | $relem = substr($relem, 0, strlen($relem)-1); // cut away last char |
||
7 | daniel-mar | 825 | $cmp = self::bigint_cmp($oelem, $relem) <= 0; |
826 | if ($cmp) $varsfit++; |
||
2 | daniel-mar | 827 | } else if (strpos($relem, '-') !== false) { |
828 | $vararcs++; |
||
829 | $limarr = explode('-', $relem); |
||
830 | $limmin = $limarr[0]; |
||
831 | $limmax = $limarr[1]; |
||
7 | daniel-mar | 832 | $cmp_min = self::bigint_cmp($oelem, $limmin) >= 0; |
833 | $cmp_max = self::bigint_cmp($oelem, $limmax) <= 0; |
||
834 | if ($cmp_min && $cmp_max) $varsfit++; |
||
2 | daniel-mar | 835 | } else { |
836 | if ($relem != $oelem) { |
||
837 | $rulefit = false; |
||
838 | break; |
||
839 | } |
||
840 | } |
||
841 | } |
||
842 | |||
843 | if ($rulefit && ($vararcs == $varsfit)) { |
||
844 | $illegal_root = implode('.', $illrootary); |
||
845 | return true; // is illegal |
||
846 | } |
||
847 | } |
||
848 | |||
849 | $illegal_root = ''; |
||
850 | return false; // not illegal |
||
851 | } |
||
852 | |||
853 | # --- PART 5: Misc functions |
||
854 | |||
855 | function __construct() { |
||
856 | if (file_exists(self::DEFAULT_ILLEGALITY_RULE_FILE)) { |
||
857 | $this->loadIllegalityRuleFile(self::DEFAULT_ILLEGALITY_RULE_FILE); |
||
858 | } |
||
859 | } |
||
860 | |||
861 | public static function getPublicURL($oid) { |
||
862 | return "http://oid-info.com/get/$oid"; |
||
863 | } |
||
864 | |||
865 | public function oidExisting($oid, $onlineCheck=true, $useSimplePingProvider=true) { |
||
866 | $bak_oid = $oid; |
||
867 | $oid = self::trySanitizeOID($oid); |
||
868 | if ($oid === false) { |
||
869 | throw new OIDInfoException("'$bak_oid' is not a valid OID"); |
||
870 | } |
||
871 | |||
872 | $canuseSimplePingProvider = $useSimplePingProvider && $this->simplePingProviderAvailable(); |
||
873 | if ($canuseSimplePingProvider) { |
||
874 | if ($this->simplePingProviderCheckOID($oid)) return true; |
||
875 | } |
||
876 | if ($onlineCheck) { |
||
877 | return $this->checkOnlineExists($oid); |
||
878 | } |
||
879 | if ((!$canuseSimplePingProvider) && (!$onlineCheck)) { |
||
880 | throw new OIDInfoException("No simple or verbose checking method chosen/available"); |
||
881 | } |
||
882 | return false; |
||
883 | } |
||
884 | |||
885 | public function oidMayCreate($oid, $onlineCheck=true, $useSimplePingProvider=true, $illegalityCheck=true) { |
||
886 | $bak_oid = $oid; |
||
887 | $oid = self::trySanitizeOID($oid); |
||
888 | if ($oid === false) { |
||
889 | throw new OIDInfoException("'$bak_oid' is not a valid OID"); |
||
890 | } |
||
891 | |||
892 | if ($illegalityCheck && $this->illegalOID($oid)) return false; |
||
893 | |||
894 | $canuseSimplePingProvider = $useSimplePingProvider && $this->simplePingProviderAvailable(); |
||
895 | if ($canuseSimplePingProvider) { |
||
896 | if ($this->simplePingProviderCheckOID($oid)) return false; |
||
897 | } |
||
898 | if ($onlineCheck) { |
||
899 | return $this->checkOnlineMayCreate($oid); |
||
900 | } |
||
901 | if ((!$canuseSimplePingProvider) && (!$onlineCheck)) { |
||
902 | throw new OIDInfoException("No simple or verbose checking method chosen/available"); |
||
903 | } |
||
904 | return true; |
||
905 | } |
||
906 | |||
907 | # --- PART 6: Simple Ping Providers |
||
908 | # TODO: Question ... can't these provider concepts (SPP and VPP) not somehow be combined? |
||
909 | |||
910 | protected $simplePingProviders = array(); |
||
911 | |||
912 | public function addSimplePingProvider($addr) { |
||
913 | if (!isset($this->simplePingProviders[$addr])) { |
||
914 | if (strtolower(substr($addr, -4, 4)) == '.csv') { |
||
915 | $this->simplePingProviders[$addr] = new CSVSimplePingProvider($addr); |
||
916 | } else { |
||
917 | $this->simplePingProviders[$addr] = new OIDSimplePingProvider($addr); |
||
918 | // $this->simplePingProviders[$addr]->connect(); |
||
919 | } |
||
920 | } |
||
921 | return $this->simplePingProviders[$addr]; |
||
922 | } |
||
923 | |||
924 | public function removeSimplePingProvider($addr) { |
||
925 | $this->simplePingProviders[$addr]->disconnect(); |
||
926 | unset($this->simplePingProviders[$addr]); |
||
927 | } |
||
928 | |||
929 | public function removeAllSimplePingProviders() { |
||
930 | foreach ($this->simplePingProviders as $addr => $obj) { |
||
931 | $this->removeSimplePingProvider($addr); |
||
932 | } |
||
933 | } |
||
934 | |||
935 | public function listSimplePingProviders() { |
||
936 | $out = array(); |
||
937 | foreach ($this->simplePingProviders as $addr => $obj) { |
||
938 | $out[] = $addr; |
||
939 | } |
||
940 | return $out; |
||
941 | } |
||
942 | |||
943 | public function simplePingProviderCheckOID($oid) { |
||
944 | if (!$this->simplePingProviderAvailable()) { |
||
945 | throw new OIDInfoException("No simple ping providers available."); |
||
946 | } |
||
947 | |||
948 | $one_null = false; |
||
13 | daniel-mar | 949 | foreach ($this->simplePingProviders as /*$addr =>*/ $obj) { |
2 | daniel-mar | 950 | $res = $obj->queryOID($oid); |
951 | if ($res) return true; |
||
952 | if ($res !== false) $one_null = true; |
||
953 | } |
||
954 | |||
955 | return $one_null ? null : false; |
||
956 | } |
||
957 | |||
958 | public function simplePingProviderAvailable() { |
||
959 | return count($this->simplePingProviders) >= 1; |
||
960 | } |
||
961 | |||
962 | } |
||
963 | |||
964 | interface IOIDSimplePingProvider { |
||
965 | public function queryOID($oid); |
||
966 | public function disconnect(); |
||
967 | public function connect(); |
||
968 | } |
||
969 | |||
970 | class CSVSimplePingProvider implements IOIDSimplePingProvider { |
||
971 | protected $csvfile = ''; |
||
972 | protected $lines = array(); |
||
973 | protected $filemtime = 0; |
||
974 | |||
975 | public function queryOID($oid) { |
||
976 | $this->reloadCSV(); |
||
977 | return in_array($oid, $this->lines); |
||
978 | } |
||
979 | |||
980 | public function disconnect() { |
||
981 | // Nothing |
||
982 | } |
||
983 | |||
984 | public function connect() { |
||
985 | // Nothing |
||
986 | } |
||
987 | |||
988 | // TODO: This cannot handle big CSVs. We need to introduce the old code of "2016-09-02_old_oidinfo_api_with_csv_reader.zip" here. |
||
989 | protected function reloadCSV() { |
||
990 | if (!file_exists($this->csvfile)) { |
||
991 | throw new OIDInfoException("File '".$this->csvfile."' does not exist"); |
||
992 | } |
||
993 | $filemtime = filemtime($this->csvfile); |
||
994 | if ($filemtime != $this->filemtime) { |
||
13 | daniel-mar | 995 | $this->lines = file($this->csvfile); |
2 | daniel-mar | 996 | $this->filemtime = $filemtime; |
997 | } |
||
998 | } |
||
999 | |||
1000 | function __construct($csvfile) { |
||
1001 | $this->csvfile = $csvfile; |
||
1002 | $this->reloadCSV(); |
||
1003 | } |
||
1004 | } |
||
1005 | |||
1006 | |||
1007 | class OIDSimplePingProvider implements IOIDSimplePingProvider { |
||
1008 | protected $addr = ''; |
||
1009 | protected $connected = false; |
||
1010 | protected $socket = null; |
||
1011 | |||
15 | daniel-mar | 1012 | const SPP_MAX_CONNECTION_ATTEMPTS = 3; // TODO: Put into an OIDInfoAPI class...? |
2 | daniel-mar | 1013 | |
1014 | const DEFAULT_PORT = 49500; |
||
1015 | |||
1016 | protected function spp_reader_init() { |
||
1017 | $this->spp_reader_uninit(); |
||
1018 | |||
16 | daniel-mar | 1019 | $ary = explode(':', $this->addr); // TODO: does not work with an IPv6 address |
2 | daniel-mar | 1020 | $host = $ary[0]; |
1021 | $service_port = isset($ary[1]) ? $ary[1] : self::DEFAULT_PORT; |
||
16 | daniel-mar | 1022 | |
1023 | $is_ip = filter_var($host, FILTER_VALIDATE_IP) !== false; |
||
1024 | if (!$is_ip) { |
||
1025 | $address = @gethostbyname($host); |
||
1026 | if ($address === $host) { |
||
21 | daniel-mar | 1027 | $msg = "gethostbyname() failed.\n"; // TODO: exceptions? (also all "echos" below) |
1028 | throw new Exception($msg); |
||
1029 | // echo $msg; |
||
1030 | // return false; |
||
16 | daniel-mar | 1031 | } |
1032 | } else { |
||
1033 | $address = $host; |
||
2 | daniel-mar | 1034 | } |
16 | daniel-mar | 1035 | |
2 | daniel-mar | 1036 | $this->socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); |
1037 | if ($this->socket === false) { |
||
21 | daniel-mar | 1038 | $msg = "socket_create() failed: " . socket_strerror(socket_last_error()) . "\n"; |
1039 | throw new Exception($msg); |
||
1040 | // echo $msg; |
||
1041 | // return false; |
||
2 | daniel-mar | 1042 | } |
1043 | $result = @socket_connect($this->socket, $address, $service_port); |
||
1044 | if ($result === false) { |
||
21 | daniel-mar | 1045 | $msg = "socket_connect() failed: " . socket_strerror(socket_last_error($this->socket)) . "\n"; |
1046 | throw new Exception($msg); |
||
1047 | // echo $msg; |
||
1048 | // return false; |
||
2 | daniel-mar | 1049 | } |
1050 | |||
1051 | $this->connected = true; |
||
1052 | } |
||
1053 | |||
1054 | protected function spp_reader_avail($oid, $failcount=0) { |
||
1055 | $in = "${oid}\n\0"; // PHP's socket_send() does not send a trailing \n . There needs to be something after the \n ... :( |
||
1056 | |||
1057 | if ($failcount >= self::SPP_MAX_CONNECTION_ATTEMPTS) { |
||
21 | daniel-mar | 1058 | $msg = "Query $oid: CONNECTION TO SIMPLE PING PROVIDER FAILED!\n"; |
1059 | throw new Exception($msg); |
||
1060 | // echo $msg; |
||
1061 | // return null; |
||
2 | daniel-mar | 1062 | } |
1063 | |||
1064 | if (!$this->connected) { |
||
1065 | $this->spp_reader_init(); |
||
1066 | } |
||
1067 | |||
1068 | $s = @socket_send($this->socket, $in, strlen($in), 0); |
||
1069 | if ($s != strlen($in)) { |
||
1070 | // echo "Query $oid: Sending failed\n"; |
||
1071 | $this->spp_reader_init(); |
||
1072 | if (!$this->socket) return null; |
||
1073 | return $this->spp_reader_avail($oid, $failcount+1); |
||
1074 | } |
||
1075 | |||
1076 | $out = @socket_read($this->socket, 2048); |
||
1077 | if (trim($out) == '1') { |
||
1078 | return true; |
||
1079 | } else if (trim($out) == '0') { |
||
1080 | return false; |
||
1081 | } else { |
||
1082 | // echo "Query $oid: Receiving failed\n"; |
||
1083 | $this->spp_reader_init(); |
||
1084 | if (!$this->socket) return null; |
||
1085 | return $this->spp_reader_avail($oid, $failcount+1); |
||
1086 | } |
||
1087 | } |
||
1088 | |||
1089 | protected function spp_reader_uninit() { |
||
1090 | if (!$this->connected) return; |
||
1091 | @socket_close($this->socket); |
||
1092 | $this->connected = false; |
||
1093 | } |
||
1094 | |||
1095 | public function queryOID($oid) { |
||
1096 | if (trim($oid) === 'bye') return null; |
||
1097 | return $this->spp_reader_avail($oid); |
||
1098 | } |
||
1099 | |||
1100 | public function disconnect() { |
||
1101 | return $this->spp_reader_uninit(); |
||
1102 | } |
||
1103 | |||
1104 | public function connect() { |
||
1105 | return $this->spp_reader_init(); |
||
1106 | } |
||
1107 | |||
1108 | function __construct($addr='localhost:49500') { |
||
1109 | $this->addr = $addr; |
||
1110 | } |
||
1111 | |||
1112 | } |