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