Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
226 | daniel-mar | 1 | <?php |
2 | |||
3 | # todo: "recursive" functions private machen, damit params nicht manipuliert werden können... |
||
4 | # todo: return false -> exception |
||
5 | |||
6 | # TODO false vs null ausgaben |
||
7 | # TODO signed openssl output |
||
8 | |||
9 | # TODO: oid definieren für name based |
||
10 | # QUE: geht extention von macros? |
||
11 | |||
12 | # TODO: "server time" am ende von Âquery() anzeigen? |
||
13 | |||
14 | require_once __DIR__ . '/../includes/uuid_utils.inc.php'; |
||
15 | require_once __DIR__ . '/../includes/oid_utils.inc.php'; |
||
16 | |||
17 | define('UUID_NAMEBASED_NS_OidPlusMisc', 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22'); |
||
18 | define('UUID_NAMEBASED_NS_OidPlusNSOnly', '0943e3ce-4b79-11e5-b742-78e3b5fc7f22'); |
||
19 | |||
20 | define('GENERATION_ROOT_DEFAULT', '.2.25.<SYSID>'); |
||
21 | |||
22 | class VolcanoDB { |
||
23 | protected $macro_data = array(); // TODO: use with caution! |
||
24 | protected $oid_data = array(); // TODO: use with caution! |
||
25 | protected $authTokens = array(); |
||
26 | protected $configuration = array(); |
||
27 | protected $configuration_file = null; |
||
28 | protected $configuration_may_create = false; |
||
29 | |||
30 | protected $redactedMessage = '# Information redacted. Please append a correct auth token with your request.'; |
||
31 | # protected $redactedMessage = null; |
||
32 | |||
33 | public function filterRedactedEntries($output) { |
||
34 | $out = ''; |
||
35 | |||
36 | $lines = explode("\n", $output); |
||
37 | foreach ($lines as $line) { |
||
38 | $line = trim($line); |
||
39 | if ($line == '') continue; |
||
40 | $name_val = explode(':', $line, 2); |
||
41 | if (count($name_val) != 2) continue; |
||
42 | if (trim($name_val[1]) != trim($this->redactedMessage)) { |
||
43 | $out .= $line."\n"; |
||
44 | } |
||
45 | |||
46 | } |
||
47 | |||
48 | return $out; |
||
49 | } |
||
50 | |||
51 | public function getOIDData() { |
||
52 | return $this->oid_data; |
||
53 | } |
||
54 | |||
55 | public function getMacroData() { |
||
56 | return $this->macro_data; |
||
57 | } |
||
58 | |||
59 | public function __construct($conf_file, $may_create) { |
||
60 | $this->configuration_file = $conf_file; |
||
61 | $this->configuration_may_create = $may_create; |
||
62 | $this->readConfiguration(); |
||
63 | } |
||
64 | |||
65 | public function getConfigValue($name) { |
||
66 | if (!isset($this->configuration[$name])) return false; |
||
67 | return $this->configuration[$name]; |
||
68 | } |
||
69 | |||
70 | public function setConfigValue($name, $value) { |
||
71 | $this->configuration[$name] = $value; |
||
72 | $this->saveConfiguration(); |
||
73 | } |
||
74 | |||
75 | protected function readConfiguration() { |
||
76 | if (is_null($this->configuration_file)) return; |
||
77 | $this->configuration = array(); |
||
78 | if (!file_exists($this->configuration_file)) { |
||
79 | if (!$this->configuration_may_create) { |
||
80 | $metadata = array(); |
||
81 | throw new VolcanoException("Configuration file '$conf_file' not found", $metadata); |
||
82 | } |
||
83 | } else { |
||
84 | $lines = file($this->configuration_file); |
||
85 | foreach ($lines as &$line) { |
||
86 | $line = trim($line); |
||
87 | if (empty($line)) continue; |
||
88 | if ($line[0] == '#') continue; |
||
89 | $ary = explode('=', $line, 2); |
||
90 | if (count($ary) < 2) continue; |
||
91 | $this->configuration[$ary[0]] = $ary[1]; |
||
92 | } |
||
93 | } |
||
94 | |||
95 | if ($this->getConfigValue('system_unique_id') === false) { |
||
96 | $this->setConfigValue('system_unique_id', gen_uuid()); |
||
97 | } |
||
98 | } |
||
99 | |||
100 | public function getSystemID() { |
||
101 | return $this->getConfigValue('system_unique_id'); |
||
102 | } |
||
103 | |||
104 | public function getSystemIDInteger() { |
||
105 | $val = uuid_numeric_value($this->getSystemID()); |
||
106 | if (!$val) { |
||
107 | $metadata = array(); |
||
108 | throw new VolcanoException("system_unique_id is not a valid UUID. Please check db/local.conf", $metadata); |
||
109 | } |
||
110 | return $val; |
||
111 | } |
||
112 | |||
113 | protected function saveConfiguration() { |
||
114 | if (is_null($this->configuration_file)) return; |
||
115 | file_put_contents($this->configuration_file, ''); |
||
116 | foreach ($this->configuration as $name => $val) { |
||
117 | file_put_contents($this->configuration_file, $name.'='.$val."\n", FILE_APPEND); |
||
118 | } |
||
119 | } |
||
120 | |||
121 | public function setRedactedMessage($msg) { |
||
122 | $this->redactedMessage = $msg; |
||
123 | } |
||
124 | |||
125 | public function getRedactedMessage() { |
||
126 | return $this->redactedMessage; |
||
127 | } |
||
128 | |||
129 | public function disableRedactedMessage() { |
||
130 | $this->redactedMessage = null; |
||
131 | } |
||
132 | |||
133 | public function isRedactedMessageEnabled() { |
||
134 | return !is_null($this->redactedMessage); |
||
135 | } |
||
136 | |||
137 | public function addAuthToken($token) { |
||
138 | if (!in_array($token, $this->authTokens)) { |
||
139 | $this->authTokens[] = $token; |
||
140 | $this->clearCaches(); |
||
141 | } |
||
142 | } |
||
143 | |||
144 | public function clearAuthTokens() { |
||
145 | $this->authTokens = array(); |
||
146 | $this->clearCaches(); |
||
147 | } |
||
148 | |||
149 | public function addDir($dir, $recursive=true) { |
||
150 | if (!is_dir($dir)) { |
||
151 | throw new VolcanoException("Directory not found: $dir"); |
||
152 | } |
||
153 | $ary = glob($dir . '/*'); |
||
154 | if (count($ary) == 0) return; |
||
155 | if ($ary === false) return; |
||
156 | sort($ary); |
||
157 | foreach ($ary as &$a) { |
||
158 | if ($a[0] == '.') continue; // e.g. '.', '..', or '.htaccess' |
||
159 | if (self::endsWith($a, '~')) continue; // recycled files |
||
160 | if (($recursive) && (is_dir($a))) { |
||
161 | $this->addDir($a, $recursive); |
||
162 | continue; |
||
163 | } |
||
164 | if (!is_file($a)) continue; |
||
165 | if (!self::endsWith($a, '.db')) continue; |
||
166 | $this->addFile($a); |
||
167 | } |
||
168 | unset($a); |
||
169 | |||
170 | #echo '<!--'; |
||
171 | #print_r($this->oid_data); |
||
172 | #print_r($this->macro_data); |
||
173 | #echo '-->'; |
||
174 | |||
175 | } |
||
176 | |||
177 | public function addFile($file) { |
||
178 | $h = fopen($file, 'r'); |
||
179 | |||
180 | $lineno = 1; |
||
181 | $header = fgets($h); |
||
182 | if (trim($header) != '['.$this->getFileformatIdentifier().']') { |
||
183 | $metadata = array(); |
||
184 | $metadata['source'] = "$file:0"; |
||
185 | throw new VolcanoException("Header of file is invalid", $metadata); |
||
186 | } |
||
187 | |||
188 | while (!feof($h)) { // TODO OK? |
||
189 | $line = fgets($h); |
||
190 | $lineno++; |
||
191 | $this->addLine($line, $file.':'.$lineno); |
||
192 | } |
||
193 | fclose($h); |
||
194 | } |
||
195 | |||
196 | # todo: wie das problem bzgl allowed field-override lösen? (superior RA verbietet "identifier" change) |
||
197 | |||
198 | protected function isSpecialInvisibleField($data) { |
||
199 | assert(isset($data['attrib_name'])); |
||
200 | |||
201 | $field_name = $data['attrib_name']; |
||
202 | |||
203 | if (empty($field_name)) return false; |
||
204 | |||
205 | if ($field_name == '*read-auth') return true; |
||
206 | # if ($field_name == '*write-auth') return true; |
||
207 | if ($field_name == '*invisible') return true; |
||
208 | |||
209 | if ($field_name[0] == '*') { |
||
210 | throw new VolcanoException("Invalid system command '$field_name'", $data); |
||
211 | } |
||
212 | |||
213 | return false; |
||
214 | } |
||
215 | |||
216 | public function isAuthentificated($oid) { |
||
217 | $readAuths = $this->getDatasets($oid, '*read-auth', false); # todo: [co] erzwingen? |
||
218 | foreach ($readAuths as &$ra) { |
||
219 | $nid = isset($ra['attrib_params'][0]) ? $ra['attrib_params'][0] : ''; |
||
220 | $found_valid_authprovider = false; |
||
221 | foreach (self::$authProvs as &$ap) { |
||
222 | if ($ap->checkId($nid)) { |
||
223 | $found_valid_authprovider = true; |
||
224 | if ($ap->checkAuth($ra['value'], null)) return true; // first, check with empty/null authToken, e.g. for IP-Authentification |
||
225 | foreach ($this->authTokens as &$token) { |
||
226 | if ($ap->checkAuth($ra['value'], $token)) return true; |
||
227 | } |
||
228 | unset($token); |
||
229 | } |
||
230 | } |
||
231 | if (!$found_valid_authprovider) { |
||
232 | # return false; |
||
233 | throw new VolcanoException("No authentification provider found", $ra); |
||
234 | } |
||
235 | unset($ap); |
||
236 | } |
||
237 | unset($ra); |
||
238 | return false; |
||
239 | } |
||
240 | |||
241 | protected static function showSource($source) { |
||
242 | if (strpos($source, ':') === false) return $source; |
||
243 | preg_match('@^(.+):(\\d+)$@', $source, $m); |
||
244 | $file = $m[1]; |
||
245 | $line = $m[2]; |
||
246 | return "$file at line $line"; |
||
247 | } |
||
248 | |||
249 | protected function clearCaches() { # TODO: aufsplitten in caches, die die auth betreffen und die, die es nicht tun? |
||
250 | $this->all_cache = null; |
||
251 | $this->cache_recdatasets = array(); |
||
252 | $this->cache_listOIDs = array(); |
||
253 | } |
||
254 | |||
255 | protected function getIndexGenerationRoot() { |
||
256 | $val = $this->getConfigValue('local_index_generation_root'); |
||
257 | if (!$val) { |
||
258 | $val = GENERATION_ROOT_DEFAULT; |
||
259 | $this->setConfigValue('local_index_generation_root', $val); |
||
260 | } |
||
261 | |||
262 | return $this->extendOID($val, true); |
||
263 | } |
||
264 | |||
265 | public function extendOID($identifier, $no_gen_root_replacement=false) { |
||
266 | $identifier = str_replace('<SYSID>', $this->getSystemIDInteger(), $identifier); |
||
267 | if (!$no_gen_root_replacement) { |
||
268 | // Avoids an endless recursion with getIndexGenerationRoot |
||
269 | $identifier = str_replace('<GENROOT>', $this->getIndexGenerationRoot(), $identifier); |
||
270 | } |
||
271 | $identifier = sanitizeOID($identifier, true); |
||
272 | return $identifier; |
||
273 | } |
||
274 | |||
275 | public function addLine($line, $source='(Direct Input):0') { |
||
276 | $line = trim($line); |
||
277 | $line = str_replace("\t", ' ', $line); |
||
278 | $line = str_replace(array("\n", "\r"), '', $line); |
||
279 | |||
280 | $line_expl = explode(' ', $line, 2); |
||
281 | |||
282 | if (empty($line) || ($line[0] == '#')) { |
||
283 | return; |
||
284 | } else if (strpos($line_expl[0], ':') !== false) { |
||
285 | $this->clearCaches(); |
||
286 | |||
287 | $expl2 = explode(':', $line_expl[0], 2); |
||
288 | $namespace = trim(strtolower($expl2[0])); |
||
289 | $identifier = trim($expl2[1]); |
||
290 | |||
291 | if (empty($namespace)) { |
||
292 | $metadata = array(); |
||
293 | $metadata['source'] = $source; |
||
294 | throw new VolcanoException("The namespace may not be empty", $metadata); |
||
295 | } |
||
296 | |||
297 | if (empty($identifier)) { |
||
298 | $metadata = array(); |
||
299 | $metadata['source'] = $source; |
||
300 | throw new VolcanoException("The identifier may not be empty", $metadata); |
||
301 | } |
||
302 | |||
303 | $is_oid = $namespace == 'oid'; |
||
304 | $is_macro = $namespace == '*macro'; |
||
305 | $is_external = $namespace == '*external'; |
||
306 | $is_other = (!$is_oid) && (!$is_macro) && (!$is_external); |
||
307 | |||
308 | # TODO: isSpecialNamespace($namespace, $source) ? |
||
309 | if (($namespace[0] == '*') && (!$is_macro) && (!$is_external)) { |
||
310 | $metadata = array(); |
||
311 | $metadata['source'] = $source; |
||
312 | throw new VolcanoException("Invalid system namespace '$namepsace'", $metadata); |
||
313 | } |
||
314 | |||
315 | if ($is_external) { |
||
316 | # TODO: wenn lokal und mit .php endend, dann eval() |
||
317 | $url = $identifier; |
||
318 | $this->addFile($url); |
||
319 | return; |
||
320 | } |
||
321 | |||
322 | if ($is_macro) { |
||
323 | $identifier = strtoupper($identifier); |
||
324 | } |
||
325 | |||
326 | if ($is_other) { |
||
327 | # TODO!!! diese handlers als plugins auslagern! |
||
328 | # QUE: sollte sowas nicht OID+ und nicht Volcano sein? |
||
329 | |||
330 | $flags = ''; |
||
331 | if (strpos($identifier, '[co]') !== false) { |
||
332 | $identifier = str_replace('[co]', '', $identifier); |
||
333 | $flags .= '[co]'; |
||
334 | } |
||
335 | $original_identifier = $identifier; |
||
336 | # TODO: check for unknown attrib flags |
||
337 | |||
338 | /* |
||
339 | if (($namespace == 'guid') || ($namespace == 'uuid')) { |
||
340 | $guid = $identifier; |
||
341 | } else { |
||
342 | $guid = gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OidPlusMisc, $namespace.':'.$identifier); |
||
343 | } |
||
344 | $identifier = '.'.uuid_to_oid($guid); # TODO: parameter, ob mit leading dot oder nicht |
||
345 | */ |
||
346 | |||
347 | $is_guid_ns = ($namespace == 'guid') || ($namespace == 'uuid'); |
||
348 | |||
349 | if ($is_guid_ns && (!$this->getConfigValue('uuid_indexes_in_genroot'))) { |
||
350 | # uuid_indexes_in_genroot wird verwendet, sonst würde bei einer sammlung von MS COM clsids würde sonst die root zone platzen |
||
351 | $guid = $identifier; |
||
352 | $identifier = '.'.uuid_to_oid($guid); # TODO: parameter, ob mit leading dot oder nicht |
||
353 | } else { |
||
354 | # Es wird ein weltweit einzigartiger Root angelegt, anstelle 2.25 für jeden einzelnen index zu verwenden. |
||
355 | # Grund: Indexes sollen (alleine schon aus Performancegründen bei der Root-Anzeige im Webinterface) |
||
356 | # in einer Wurzel zusammengefasst werden. Diese Wurzel sollte aber unter der legalen Kontrolle des |
||
357 | # Eigentümers stehen. "2.25" kann nicht als Wurzel definiert werden, da der Benutzer kein Recht hat, |
||
358 | # "2.25" sein Eigen zu nennen. |
||
359 | # PROBLEM: aber dann kann man von den einzelnen items nicht das "uuid" feld ablesen, um an die |
||
360 | # per UUID_NAMEBASED_NS_OidPlusMisc erstellte UUID ranzukommen, da das "uuid" feld nur kindsknoten von 2.25 |
||
361 | # konvertiert. |
||
362 | $gen_root = $this->getIndexGenerationRoot(); |
||
363 | |||
364 | if ($namespace == 'doi') { |
||
365 | if (!self::beginswith($identifier, '10.')) { |
||
366 | $metadata = array(); |
||
367 | $metadata['source'] = $source; |
||
368 | throw new VolcanoException("Invalid DOI '$identifier'. Must start with '10.'", $metadata); |
||
369 | } |
||
370 | $x = substr($identifier, 3/* strlen('10.') */); |
||
371 | $orgid = explode('/', $x, 2)[0]; |
||
372 | |||
373 | # doi(10) <orgid> <doi:identifier> |
||
374 | $identifier_ns = $gen_root.'.10.'.$orgid; |
||
375 | |||
376 | if (!$this->oidDescribed($identifier_ns, false)) { |
||
377 | $this->addLine("oid:$identifier_ns description: Organisation $orgid", $source); |
||
378 | } |
||
379 | |||
380 | $guid_item = gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OidPlusMisc, 'doi:'.$identifier); |
||
381 | } else if ($is_guid_ns) { |
||
382 | # uuid(25) <numeric_uuid> |
||
383 | $identifier_ns = $gen_root.'.25'; |
||
384 | |||
385 | # TODO: im web frontend trotzdem die originale index uuid zum klicken abieten (action=uuid_info, nicht nur action=show_index!) |
||
386 | $guid_item = $identifier; |
||
387 | } else { |
||
388 | $guid_ns = gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OidPlusNSOnly, $namespace); |
||
389 | |||
390 | # ns(0) <ns> <ns:identifier> |
||
391 | $identifier_ns = $gen_root.'.0.'.uuid_numeric_value($guid_ns); |
||
392 | |||
393 | if (!$this->oidDescribed($identifier_ns, false)) { |
||
394 | $this->addLine("oid:$identifier_ns description: Automatically generated arc for namespace \"$namespace\"", $source); |
||
395 | if (oid_id_is_valid($namespace)) { |
||
396 | $this->addLine("oid:$identifier_ns identifier:$namespace", $source); |
||
397 | } |
||
398 | } |
||
399 | |||
400 | $guid_item = gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OidPlusMisc, $namespace.':'.$identifier); |
||
401 | } |
||
402 | |||
403 | $identifier = $identifier_ns.'.'.uuid_numeric_value($guid_item); |
||
404 | } |
||
405 | if (!$this->oidDescribed($identifier, false)) { # TODO: WARUM? man kann den index doch auch so anlegen??? !! |
||
406 | $this->addLine('oid:'.$identifier." ${flags}index($namespace):$original_identifier", $source); |
||
407 | } |
||
408 | $is_other = false; |
||
409 | $is_oid = true; |
||
410 | } |
||
411 | |||
412 | # Muss als letztes stehen, da $is_other zu $is_oid konvertiert werden kann |
||
413 | if ($is_oid) { |
||
414 | $bak_oid = $identifier; |
||
415 | $identifier = $this->extendOID($identifier); |
||
416 | |||
417 | if ($identifier === false) { |
||
418 | $metadata = array(); |
||
419 | $metadata['source'] = $source; |
||
420 | $metadata['oid'] = $bak_oid; |
||
421 | throw new VolcanoException("Illegal OID or dot notation with leading dot not recognized", $metadata); |
||
422 | } |
||
423 | } |
||
424 | |||
425 | if (!isset($line_expl[1])) { |
||
426 | $metadata = array(); |
||
427 | $metadata['source'] = $source; |
||
428 | throw new VolcanoException("Syntax error in DB: line contains no data", $metadata); |
||
429 | } |
||
430 | |||
431 | $data = isset($line_expl[1]) ? $line_expl[1] : ''; |
||
432 | |||
433 | $bry = explode(':', $data, 2); |
||
434 | $attrib_name = (isset($bry[0])) ? $bry[0] : ''; |
||
435 | $value = (isset($bry[1])) ? $bry[1] : ''; |
||
436 | |||
437 | // <attrib_name>(<attrib_params>) |
||
438 | if (preg_match("@^(.*)\((.+)\)(.*)$@isU", $attrib_name, $m)) { |
||
439 | $attrib_name = $m[1].$m[3]; |
||
440 | $attrib_params = explode(',', $m[2]); |
||
441 | } else { |
||
442 | $attrib_params = array(); |
||
443 | } |
||
444 | |||
445 | // Process params |
||
446 | // [co]<attrib_name> marks the line as confidential (read-auth necessary) |
||
447 | $attrib_name = str_replace('[co]', '', $attrib_name, $cnt); |
||
448 | $flag_confidential = $cnt > 0; |
||
449 | |||
450 | $attrib_name = str_replace('[xt]', '', $attrib_name, $cnt); |
||
451 | $flag_extend = $cnt > 0; |
||
452 | |||
453 | $attrib_name = str_replace('[add]', '', $attrib_name, $cnt); |
||
454 | $flag_add = $cnt > 0; |
||
455 | |||
456 | $attrib_name = str_replace('[del]', '', $attrib_name, $cnt); |
||
457 | $flag_del = $cnt > 0; |
||
458 | |||
459 | $attrib_name = str_replace('[in]', '', $attrib_name, $cnt); |
||
460 | ## $flag_inherit = $cnt > 0; |
||
461 | # Wir speichern hier keinen boolean, sondern den $attrib_name . |
||
462 | # Dadurch wird sichergestellt, dass ein [xt]-Block im ganzen überschrieben wird, und nicht jede Zeile einzeln. |
||
463 | # Jede Zeile enthält also im flag_inherit den Namen ihres [xt]-Blocks. |
||
464 | $flag_inherit = ($cnt > 0) ? $attrib_name : false; // attrib_name muss ohne restliche flags sein, deswegen [in] zuletzt parsen |
||
465 | |||
466 | # No! We just leave inherited so we can use it later |
||
467 | /* |
||
468 | if (($flag_inherit) && ($is_macro)) { |
||
469 | $metadata = array(); |
||
470 | $metadata['source'] = $source; |
||
471 | throw new VolcanoException("Macro attributes cannot be inherited", $metadata); |
||
472 | } |
||
473 | */ |
||
474 | |||
475 | if (preg_match('@\[(.*)\]@isU', $attrib_name, $m)) { |
||
476 | $metadata = array(); |
||
477 | $unkn_flag = $m[1]; |
||
478 | $metadata['source'] = $source; |
||
479 | throw new VolcanoException("Flag [$unkn_flag] unknown", $metadata); |
||
480 | } |
||
481 | |||
482 | $attrib_name = trim($attrib_name); |
||
483 | |||
484 | // Add data |
||
485 | if ($flag_extend) { |
||
486 | $value = trim($value); |
||
487 | |||
488 | // Allow multiple whitespaces as separator for macro params |
||
489 | $value = preg_replace('@(\s+)@', ' ', $value); |
||
490 | |||
491 | # $macro_params = explode(' ', $value); // <macroname> <macroparam_1> <...> |
||
492 | $macro_params = str_getcsv($value, ' '); // requires PHP 5.3, see http://stackoverflow.com/questions/2202435/php-explode-the-string-but-treat-words-in-quotes-as-a-single-word for alternatives |
||
493 | $macroname = $macro_params[0]; |
||
494 | if (!isset($this->macro_data[strtoupper($macroname)])) { |
||
495 | $metadata = array(); |
||
496 | $metadata['source'] = $source; |
||
497 | |||
498 | # TODO: zuerst alle anderen *.db files durchprobieren ob es auftaucht? |
||
499 | throw new VolcanoException("Macro '$macroname' not found", $metadata); |
||
500 | } |
||
501 | |||
502 | $x = $this->macro_data[strtoupper($macroname)]; |
||
503 | |||
504 | foreach ($x as $y) { // no &$y |
||
505 | # $y['source'] bleibt erhalten |
||
506 | |||
507 | // Replace macro params in value, attrib_name and attrib_params |
||
508 | foreach ($macro_params as $mp_n => &$mp_x) { |
||
509 | $y['value'] = str_replace('__'.$mp_n.'__', $mp_x, $y['value']); |
||
510 | $y['attrib_name'] = str_replace('__'.$mp_n.'__', $mp_x, $y['attrib_name']); |
||
511 | foreach ($y['attrib_params'] as &$ap_val) { |
||
512 | $ap_val = str_replace('__'.$mp_n.'__', $mp_x, $ap_val); |
||
513 | } |
||
514 | } |
||
515 | // Remove unused macro param place holders |
||
516 | // NO! Otherwise we cannot use parametrized macros which are using parametrized macros itself |
||
517 | /* |
||
518 | $y['value'] = preg_replace('@__(\\d+)__@sU', '', $y['value']); |
||
519 | $y['attrib_name'] = preg_replace('@__(\\d+)__@sU', '', $y['attrib_name']); |
||
520 | foreach ($y['attrib_params'] as &$ap_val) { |
||
521 | $ap_val = preg_replace('@__(\\d+)__@sU', '', $ap_val); |
||
522 | } |
||
523 | */ |
||
524 | |||
525 | // $y['attrib_params'] = $attrib_params; |
||
526 | // Nein, attrib_params lieber direkt nach ?? einfügen: |
||
527 | if (count($attrib_params) > 0) { |
||
528 | $attr_ext = '('.implode(',', $attrib_params).')'; |
||
529 | } else { |
||
530 | $attr_ext = ''; |
||
531 | } |
||
532 | # NG: '??' auch ersetzen in attrib_param, value ? |
||
533 | $y['attrib_name'] = str_replace('??', $attrib_name.$attr_ext, $y['attrib_name']); |
||
534 | // QUE: wie verhalten sich die params im falle einer vererbung? kann man params missbrauchen um z.B. ra(1), ra(2) etc zu kennzeichnen? |
||
535 | |||
536 | $y['flag_confidential'] = $flag_confidential || $y['flag_confidential']; |
||
537 | # todo: read-auth im macro-bereich? |
||
538 | # $y['flag_extend'] = true; // TODO? |
||
539 | $y['flag_inherit'] = trim($flag_inherit); # dieser flag_inherit geht von der ursprungs-oid über alle stufen der macros und submacros hinweg |
||
540 | $y['flag_add'] = $flag_add; |
||
541 | |||
542 | if ($is_macro) { |
||
543 | $y['macro'] = $identifier; |
||
544 | } else { |
||
545 | $y['oid'] = $identifier; |
||
546 | } |
||
547 | |||
548 | // Check if the identifier is valid to the ASN.1 standards |
||
549 | $flag_extend = strpos($y['attrib_name'], '[xt]') !== false; |
||
550 | if ((!$flag_extend) && (!$is_macro) && (strtolower($y['attrib_name']) == 'identifier') && (!oid_id_is_valid($y['value']))) { |
||
551 | throw new VolcanoException("Identifier '".$y['value']."' is not a valid ASN.1 identifier", $y); |
||
552 | } |
||
553 | |||
554 | if ((!$flag_extend) && (!$is_macro) && (strtolower($y['attrib_name']) == 'iri') && (!iri_valid($y['value']))) { |
||
555 | throw new VolcanoException("Identifier '".$y['value']."' is not a valid IRI identifier", $y); |
||
556 | } |
||
557 | |||
558 | if ($is_macro) { |
||
559 | $this->macro_data[$identifier][] = $y; |
||
560 | } else { |
||
561 | $this->oid_data[$identifier][] = $y; |
||
562 | } |
||
563 | } |
||
564 | } else { |
||
565 | // $value = trim($value); // TODO: oder doch lieber? z.b. descriptions einrücken? |
||
566 | |||
567 | # NG: '??' auch ersetzen in attrib_param, value ? |
||
568 | if ((!$is_macro) && (strpos($attrib_name, '??') !== false)) { |
||
569 | $metadata = array(); |
||
570 | $metadata['source'] = $source; |
||
571 | throw new VolcanoException("'??' is only allowed inside a macro", $metadata); |
||
572 | } |
||
573 | |||
574 | $y = array( |
||
575 | 'source' => $source, |
||
576 | 'attrib_name' => $attrib_name, |
||
577 | 'attrib_params' => $attrib_params, |
||
578 | 'value' => $value, |
||
579 | 'flag_confidential' => $flag_confidential, |
||
580 | # 'flag_extend' => $flag_extend, |
||
581 | 'flag_inherit' => trim($flag_inherit), |
||
582 | 'flag_add' => $flag_add, |
||
583 | 'flag_del' => $flag_del |
||
584 | ); |
||
585 | |||
586 | if ($is_macro) { |
||
587 | $y['macro'] = $identifier; |
||
588 | } else { |
||
589 | $y['oid'] = $identifier; |
||
590 | } |
||
591 | |||
592 | // Check if the identifier is valid to the ASN.1 standards |
||
593 | if ((!$flag_extend) && (!$is_macro) && (strtolower($y['attrib_name']) == 'identifier') && (!oid_id_is_valid($y['value']))) { |
||
594 | throw new VolcanoException("Identifier '".$y['value']."' is not a valid ASN.1 identifier", $y); |
||
595 | } |
||
596 | |||
597 | if ($is_macro) { |
||
598 | $this->macro_data[$identifier][] = $y; |
||
599 | } else { |
||
600 | $this->oid_data[$identifier][] = $y; |
||
601 | } |
||
602 | } |
||
603 | } else { |
||
604 | $metadata = array(); |
||
605 | $metadata['source'] = $source; |
||
606 | throw new VolcanoException("Syntax error in database (not beginning with 'oid:' or '*macro:' or a valid identifier like 'guid:<uuid>')", $metadata); |
||
607 | } |
||
608 | } |
||
609 | |||
610 | private $all_cache = array(); |
||
611 | # TODO: auch $parent_oid parameter |
||
612 | public function getAllOIDs($check_auth=true) { |
||
613 | $vvv = $check_auth; |
||
614 | if (isset($this->all_cache[$vvv])) return $this->all_cache[$vvv]; |
||
615 | |||
616 | // TODO: $with_macros per default false. ausblenden. xxx |
||
617 | |||
618 | $ary = array(); |
||
619 | foreach ($this->oid_data as $b => &$data) { |
||
620 | if ($check_auth) { |
||
621 | if ($this->oidDescribed($b, $check_auth)) $ary[] = $b; |
||
622 | } else { |
||
623 | $ary[] = $b; |
||
624 | } |
||
625 | } |
||
626 | |||
627 | $this->all_cache[$vvv] = $ary; |
||
628 | return $ary; |
||
629 | } |
||
630 | |||
631 | // TODO: -> functions.inc.php |
||
632 | protected static function getShortestString(&$ary) { |
||
633 | $minlen = PHP_INT_MAX; |
||
634 | $out = false; |
||
635 | foreach ($ary as &$a) { |
||
636 | if ($a === null) continue; |
||
637 | $len = strlen($a); |
||
638 | if ($len < $minlen) { |
||
639 | $out = $a; |
||
640 | $minlen = $len; |
||
641 | } |
||
642 | } |
||
643 | unset($a); |
||
644 | return $out; |
||
645 | } |
||
646 | |||
647 | // TODO: -> oid_utils.inc.php ? |
||
648 | protected static function strikeRoot(&$ary, $oid) { |
||
649 | $oid = sanitizeOID($oid, substr($oid,0,1) == '.'); |
||
650 | if ($oid === false) return false; |
||
651 | |||
652 | $dotstop = self::appendDot($oid); |
||
653 | foreach ($ary as &$a) { |
||
654 | if (($a == $oid) || (self::beginsWith($a, $dotstop))) { |
||
655 | $a = null; |
||
656 | } |
||
657 | } |
||
658 | unset($a); |
||
659 | } |
||
660 | |||
661 | public function findRoots($check_auth=true) { |
||
662 | $out = array(); |
||
663 | |||
664 | $ary = $this->getAllOIDs($check_auth); |
||
665 | |||
666 | while (($oid = $this->getShortestString($ary)) !== false) { |
||
667 | $out[] = $oid; |
||
668 | $this->strikeRoot($ary, $oid); |
||
669 | } |
||
670 | |||
671 | oidSort($out); |
||
672 | |||
673 | return $out; |
||
674 | } |
||
675 | |||
676 | public static function findSearchProvider($nid) { |
||
677 | $found_prov = null; |
||
678 | foreach (self::$searchProvs as &$searchprov) { |
||
679 | if ($searchprov->checkId($nid)) { |
||
680 | $found_prov = $searchprov; |
||
681 | break; |
||
682 | } |
||
683 | } |
||
684 | unset($searchprov); |
||
685 | |||
686 | return $found_prov; |
||
687 | } |
||
688 | |||
689 | public function findOID(&$indexname, $check_auth=true) { |
||
690 | $lowest_oid = null; |
||
691 | $lowest_dist = PHP_INT_MAX; |
||
692 | $lowest_nid = null; |
||
693 | $oids = $this->getAllOIDs($check_auth); |
||
694 | |||
695 | $ary = explode(':', $indexname, 2); |
||
696 | if (count($ary) == 2) { |
||
697 | $suggested_nid = $ary[0]; // This does not neccessarily be a searchprovider NID, since it could also be a part of an IPv6 address |
||
698 | $found_prov = self::findSearchProvider($suggested_nid); |
||
699 | if (!is_null($found_prov)) { |
||
700 | $indexname = $ary[1]; |
||
701 | } else { |
||
702 | // No search provider was found. We don't strip the text before ':', because it |
||
703 | // could be actually a part of the index name, e.g. for an IPv6 |
||
704 | # $indexname = $ary[1]; |
||
705 | } |
||
706 | } else { |
||
707 | $suggested_nid = ''; |
||
708 | $found_prov = null; |
||
709 | } |
||
710 | |||
711 | $has_preferred_prov = !is_null($found_prov); |
||
712 | |||
713 | foreach ($oids as &$oid) { |
||
714 | $search_data = $this->getDatasets($oid, 'index'); # todo: wird [co] beachtet? |
||
715 | foreach ($search_data as &$data) { |
||
716 | $nid = $data['attrib_params'][0]; |
||
717 | $value = $data['value']; |
||
718 | |||
719 | |||
720 | if (!$has_preferred_prov) $found_prov = self::findSearchProvider($nid); |
||
721 | |||
722 | if (!is_null($found_prov)) { |
||
723 | $cur_distance = $found_prov->calcDistance($value, $indexname); |
||
724 | if ($cur_distance === false) continue; |
||
725 | if ($cur_distance < 0) continue; // item is too specific for the request |
||
726 | // else if ($cur_distance == 0) return array($oid, 0, $nid); |
||
727 | else if ($cur_distance < $lowest_dist) { |
||
728 | $lowest_dist = $cur_distance; |
||
729 | $lowest_oid = $oid; |
||
730 | $lowest_nid = $nid; |
||
731 | if ($cur_distance == 0) break 2; |
||
732 | } |
||
733 | } else { |
||
734 | // We don't have a Searchprovider, but we can look for an index which matches exactly |
||
735 | if ($suggested_nid == $nid) { |
||
736 | $indexname = isset($ary[1]) ? $ary[1] : ''; |
||
737 | } |
||
738 | if ($value == $indexname) { |
||
739 | $lowest_dist = 0; |
||
740 | $lowest_oid = $oid; |
||
741 | $lowest_nid = $nid; |
||
742 | break 2; |
||
743 | } |
||
744 | } |
||
745 | } |
||
746 | unset($data); |
||
747 | } |
||
748 | unset($oid); |
||
749 | |||
750 | if (is_null($lowest_oid)) return null; |
||
751 | return array($lowest_oid, $lowest_dist, $lowest_nid); |
||
752 | } |
||
753 | |||
754 | private $cache_listOIDs = array(); |
||
755 | public function listOIDs($parent_oid, $absolute=true, $depth=-1, $check_auth=true) { |
||
756 | $parent_oid = sanitizeOID($parent_oid, substr($parent_oid,0,1) == '.'); |
||
757 | if ($parent_oid === false) return false; |
||
758 | |||
759 | $vvv = ($absolute ? 'T' : 'F').($check_auth ? 'T' : 'F').$depth.'/'.$parent_oid; |
||
760 | if (isset($this->cache_listOIDs[$vvv])) return $this->cache_listOIDs[$vvv]; |
||
761 | |||
762 | $dotstop = self::appendDot($parent_oid); |
||
763 | |||
764 | $oids = $this->getAllOIDs($check_auth); |
||
765 | |||
766 | $out = array(); |
||
767 | foreach ($oids as &$oid) { |
||
768 | if (self::beginsWith($oid, $dotstop)) { |
||
769 | if ($depth >= 0) { |
||
770 | if (substr_count($oid, '.')-substr_count($dotstop, '.') > $depth-1) continue; |
||
771 | } |
||
772 | if ($absolute) { |
||
773 | $out[] = $oid; |
||
774 | } else { |
||
775 | $out[] = substr($oid, strlen($dotstop)); |
||
776 | } |
||
777 | } |
||
778 | } |
||
779 | unset($oid); |
||
780 | |||
781 | $this->cache_listOIDs[$vvv] = $out; |
||
782 | return $out; |
||
783 | } |
||
784 | |||
785 | public function listChildren($parent_oid, $levels=-1, $check_auth=true) { |
||
786 | if ($levels == 0) return false; |
||
787 | |||
788 | $parent_oid = sanitizeOID($parent_oid, substr($parent_oid,0,1) == '.'); |
||
789 | if ($parent_oid === false) return false; |
||
790 | |||
791 | $deepChildrenSearch = $this->listOIDs($parent_oid, false, -1, $check_auth); |
||
792 | if (count($deepChildrenSearch) == 0) return array(); |
||
793 | |||
794 | $firstarcs = array(); |
||
795 | foreach ($deepChildrenSearch as &$child) { |
||
796 | $ary = explode('.', $child, 2); |
||
797 | $firstarc = $ary[0]; |
||
798 | if ($firstarc == '') continue; # Achtung: Darf nicht empty() sein, da empty(0)===true |
||
799 | |||
800 | # if (!in_array($firstarc, $firstarcs)) $firstarcs[] = $firstarc; # slow |
||
801 | if (!isset($firstarcs[$firstarc])) $firstarcs[$firstarc] = true; |
||
802 | } |
||
803 | unset($child); |
||
804 | # sort($firstarcs); |
||
805 | ksort($firstarcs); |
||
806 | |||
807 | $dotstop = self::appendDot($parent_oid); |
||
808 | |||
809 | $out = array(); |
||
810 | # foreach ($firstarcs as &$firstarc) { |
||
811 | foreach ($firstarcs as $firstarc => &$dummy) { |
||
812 | |||
813 | |||
814 | /* This doesn't work with orphan OIDs |
||
815 | $firstarcs = $this->listOIDs($parent_oid, false, 1, $check_auth); |
||
816 | if (count($firstarcs) == 0) return array(); |
||
817 | |||
818 | sort($firstarcs); |
||
819 | |||
820 | $dotstop = self::appendDot($parent_oid); |
||
821 | |||
822 | $out = array(); |
||
823 | foreach ($firstarcs as &$firstarc) { |
||
824 | */ |
||
825 | $cur_oid = $dotstop.$firstarc; |
||
826 | |||
827 | $out[$firstarc] = array( |
||
828 | 'children' => $this->listChildren($cur_oid, $levels-1, $check_auth), |
||
829 | 'described' => $this->oidDescribed($cur_oid, $check_auth), |
||
830 | 'identifiers' => $this->getIdentifiers($cur_oid, $check_auth), |
||
831 | 'unicodelabels' => $this->getUnicodeLabels($cur_oid, $check_auth), |
||
832 | 'attributes' => $this->getOIDAttribs($cur_oid, $check_auth) |
||
833 | ); |
||
834 | } |
||
835 | |||
836 | return $out; |
||
837 | } |
||
838 | |||
839 | /* protected */ public function getIdentifiers($oid, $check_auth=true) { |
||
840 | // TODO: value sanity check |
||
841 | return $this->getValuesOf($oid, 'identifier', $check_auth); |
||
842 | } |
||
843 | |||
844 | /* protected */ public function getUnicodeLabels($oid, $check_auth=true) { |
||
845 | // TODO: value sanity check |
||
846 | return $this->getValuesOf($oid, 'unicodelabel', $check_auth); |
||
847 | } |
||
848 | |||
849 | /* protected */ public function getOIDAttribs($oid, $check_auth=true) { |
||
850 | return $this->getValuesOf($oid, 'attribute', $check_auth, 1); |
||
851 | } |
||
852 | |||
853 | // case 0 = preserve TODO: als konstanten auslagern |
||
854 | // case 1 = upper case |
||
855 | // case 2 = lower case |
||
856 | /* protected */ public function getValuesOf($oid, $attrib_name, $unique=true, $case=0) { |
||
857 | $oid = sanitizeOID($oid, substr($oid,0,1) == '.'); |
||
858 | if ($oid === false) return false; |
||
859 | |||
860 | $identifiers = array(); |
||
861 | $identifiers_raw = $this->getDatasets($oid, $attrib_name); |
||
862 | foreach ($identifiers_raw as &$idd) { |
||
863 | $val = $idd['value']; |
||
864 | if ($case == 1) $val = strtoupper($val); |
||
865 | elseif ($case == 2) $val = strtolower($val); |
||
866 | $identifiers[] = $val; |
||
867 | } |
||
868 | unset($idd); |
||
869 | |||
870 | if ($unique) $identifiers = array_unique($identifiers); |
||
871 | |||
872 | return $identifiers; |
||
873 | } |
||
874 | |||
875 | /* protected */ public function getValues($oid, $attribute_name) { |
||
876 | $oid = sanitizeOID($oid, substr($oid,0,1) == '.'); |
||
877 | if ($oid === false) return false; |
||
878 | |||
879 | $values = array(); |
||
880 | $values_raw = $this->getDatasets($oid, $attribute_name); |
||
881 | foreach ($values_raw as &$idd) { |
||
882 | $values[] = $idd['value']; |
||
883 | } |
||
884 | unset($idd); |
||
885 | return $values; |
||
886 | } |
||
887 | |||
888 | public function oidDescribed($oid, $check_auth=true) { |
||
889 | $oid = sanitizeOID($oid, substr($oid,0,1) == '.'); |
||
890 | if ($oid === false) return false; |
||
891 | |||
892 | if ($check_auth) { |
||
893 | $m = $this->getDatasets($oid, '', $check_auth); |
||
894 | $c = 0; |
||
895 | foreach ($m as &$data) { |
||
896 | if ($this->isSpecialInvisibleField($data)) continue; |
||
897 | $c++; |
||
898 | } |
||
899 | if ($c == 0) return false; // secret OID or not available OID |
||
900 | } |
||
901 | |||
902 | return isset($this->oid_data[$oid]); # TODO: was ist wenn OID secret? |
||
903 | } |
||
904 | |||
905 | public function getDatasets($oid, $attrib_name='', $check_auth=true) { // TODO filter nach params, value? |
||
906 | $out = array(); |
||
907 | $ary = $this->rec_getDatasets($oid, $attrib_name, $check_auth); |
||
908 | foreach ($ary as &$d) { |
||
909 | if ((!empty($attrib_name)) && ($d['attrib_name'] != $attrib_name)) continue; |
||
910 | $out[] = $d; |
||
911 | } |
||
912 | return $out; |
||
913 | } |
||
914 | |||
915 | public function stripAttribs($oid, $attrib_name, $limit=-1) { |
||
916 | $count = 0; |
||
917 | foreach ($this->oid_data[$oid] as $n => $data) { // no &$data |
||
918 | if (empty($attrib_name) || ($data['attrib_name'] == $attrib_name)) { |
||
919 | $count++; |
||
920 | if (($limit >= 0) && ($count > $limit)) break; |
||
921 | unset($this->oid_data[$oid][$n]); |
||
922 | } |
||
923 | } |
||
924 | } |
||
925 | |||
926 | private $cache_recdatasets = array(); |
||
927 | |||
928 | # FUT QUE: return by reference? |
||
929 | protected function rec_getDatasets($oid, $attrib_name='', $check_auth=true) { // TODO filter nach params, value? |
||
930 | $oid = sanitizeOID($oid, substr($oid,0,1) == '.'); |
||
931 | if ($oid === false) { |
||
932 | throw new VolcanoException("'$oid' is not a valid OID."); # TODO: exception source ("stacktrace") metadata -- idee: global $source variable? |
||
933 | } |
||
934 | |||
935 | $vvv = $oid.'/'.$attrib_name.'/'.($check_auth ? 'T' : 'F'); |
||
936 | if (isset($this->cache_recdatasets[$vvv])) return $this->cache_recdatasets[$vvv]; |
||
937 | |||
938 | if (!$this->oidDescribed($oid, false)) return array(); |
||
939 | |||
940 | $out = array(); |
||
941 | foreach ($this->oid_data[$oid] as $data) { // no &$data |
||
942 | if ($check_auth) { |
||
943 | # Anstelle *invisible lieber ein "attribute:" ? ist leider schwieriger zu bedienen , z.b. wenn man es wieder weghaben möchte |
||
944 | if (($data['attrib_name'] == '*invisible') && ($data['value'] == '1')) { |
||
945 | if ($this->isAuthentificated($oid)) { # TODO: parameter, für was man sich authentifizieren möchte (read,write, etc). |
||
946 | $dd = $data; // TODO: OK? |
||
947 | $dd['attrib_name'] = 'attribute'; |
||
948 | $dd['value'] = 'INVISIBLE'; |
||
949 | $dd['flag_inherit'] = $data['flag_inherit']; |
||
950 | $dd['flag_add'] = $data['flag_add']; # TODO: ok? |
||
951 | $dd['attrib_params'] = array(); |
||
952 | $dd['source'] = $data['source']; |
||
953 | # TODO: weitere dinge in $dd notwendig? |
||
954 | $out[] = $dd; |
||
955 | } else { |
||
956 | $this->cache_recdatasets[$vvv] = array($data); |
||
957 | return array($data); |
||
958 | } |
||
959 | } |
||
960 | |||
961 | if (($data['flag_confidential']) && (!$this->isAuthentificated($oid))) { |
||
962 | if (!$this->isRedactedMessageEnabled()) { |
||
963 | continue; // hide complete line |
||
964 | } else { |
||
965 | $data['value'] = $this->redactedMessage; |
||
966 | } |
||
967 | } |
||
968 | } |
||
969 | |||
970 | if ((!empty($attrib_name)) && ($data['attrib_name'] != $attrib_name)) continue; |
||
971 | |||
972 | // Add it to output |
||
973 | if (!$data['flag_del']) $out[] = $data; |
||
974 | } |
||
975 | unset($data); |
||
976 | |||
977 | // Get the inherited fields |
||
978 | if ($oid != '.') { |
||
979 | $ori_oid = $oid; |
||
980 | while ($oid != '.') { |
||
981 | $oid = oid_up($oid); |
||
982 | if ($this->oidDescribed($oid, false)) break; |
||
983 | } |
||
984 | $ds = $this->rec_getDatasets($oid, $attrib_name, $check_auth); |
||
985 | foreach ($ds as &$d) { |
||
986 | if ($d['flag_inherit']) { |
||
987 | // Only inherit if it isn't overwritten |
||
988 | $is_overwritten = false; |
||
989 | |||
990 | foreach ($this->oid_data[$ori_oid] as &$x) { // $d = diese oid ; $x = vater oid |
||
991 | #/* |
||
992 | // compare single fields to each other (may also include fields that were extended from a macro) |
||
993 | if ($x['attrib_name'] == $d['attrib_name']) { # todo: case sensitive? |
||
994 | $is_overwritten = true; |
||
995 | break; |
||
996 | } |
||
997 | #*/ |
||
998 | |||
999 | if ($x['attrib_name'] == $d['flag_inherit']) { # todo: case sensitive? |
||
1000 | $is_overwritten = true; |
||
1001 | break; |
||
1002 | } |
||
1003 | |||
1004 | // ein ganzer [xt] block wird inherited, z.B. "ra". nicht die einzelnen felder einzeln behandeln. |
||
1005 | if ($x['flag_inherit'] == $d['flag_inherit']) { # todo: case sensitive? |
||
1006 | $is_overwritten = true; |
||
1007 | break; |
||
1008 | } |
||
1009 | } |
||
1010 | |||
1011 | if ($x['flag_add']) { |
||
1012 | $is_overwritten = false; |
||
1013 | } |
||
1014 | |||
1015 | if ($is_overwritten) continue; |
||
1016 | |||
1017 | if ($check_auth) { |
||
1018 | if (($d['attrib_name'] == '*invisible') && ($d['value'] == '1')) { |
||
1019 | if ($this->isAuthentificated($oid)) { |
||
1020 | $dd['attrib_name'] = 'attribute'; |
||
1021 | $dd['value'] = 'INVISIBLE'; |
||
1022 | $dd['flag_inherit'] = $d['flag_inherit']; |
||
1023 | $dd['flag_add'] = $d['flag_add']; # TODO: ok? |
||
1024 | $dd['attrib_params'] = array(); |
||
1025 | # $out[] = $dd; |
||
1026 | } else { |
||
1027 | $this->cache_recdatasets[$vvv] = array($d); |
||
1028 | return array($d); |
||
1029 | } |
||
1030 | } |
||
1031 | } |
||
1032 | |||
1033 | // Add to output |
||
1034 | if (!$d['flag_del']) $out[] = $d; |
||
1035 | } |
||
1036 | } |
||
1037 | } |
||
1038 | |||
1039 | $this->cache_recdatasets[$vvv] = $out; |
||
1040 | return $out; |
||
1041 | } |
||
1042 | |||
1043 | // TODO: iso.org auch aufloesen und standardized |
||
1044 | public function resolveIdentifiers($term) { |
||
1045 | $ary = explode('.', $term); |
||
1046 | $cd = $this->listChildren('.'); |
||
1047 | |||
1048 | foreach ($ary as $n => &$a) { |
||
1049 | if ($n == 0) continue; |
||
1050 | if (!is_numeric($a[0])) { |
||
1051 | if (is_null($cd)) return false; // TODO FUT: loessen durch referenzierende whois server (forward)? |
||
1052 | $found = false; |
||
1053 | foreach ($cd as $arc => &$data) { |
||
1054 | foreach ($data['identifiers'] as &$idc) { |
||
1055 | if ($idc == $a) { |
||
1056 | $a = $arc; |
||
1057 | $found = true; |
||
1058 | break 2; |
||
1059 | } |
||
1060 | } |
||
1061 | } |
||
1062 | unset($data); |
||
1063 | if (!$found) return false; |
||
1064 | } |
||
1065 | $cd = (!isset($cd[$a]['children'])) ? null : $cd[$a]['children']; |
||
1066 | } |
||
1067 | unset($a); |
||
1068 | |||
1069 | return implode('.', $ary); |
||
1070 | } |
||
1071 | |||
1072 | // --------- STATIC |
||
1073 | |||
1074 | protected static $searchProvs = array(); |
||
1075 | protected static $authProvs = array(); |
||
1076 | |||
1077 | public static function getFileformatIdentifier() { |
||
1078 | return '1.3.6.1.4.1.37476.2.5.1.1.2'; |
||
1079 | } |
||
1080 | |||
1081 | public static function registerSearchProvider($prov) { |
||
1082 | self::$searchProvs[] = $prov; |
||
1083 | } |
||
1084 | |||
1085 | public static function registerAuthProvider($prov) { |
||
1086 | self::$authProvs[] = $prov; |
||
1087 | } |
||
1088 | |||
1089 | protected static function appendDot($oid) { |
||
1090 | return ($oid == '.') ? '.' : $oid . '.'; |
||
1091 | } |
||
1092 | |||
1093 | // TODO: functions.inc.php |
||
1094 | protected static function beginsWith($haystack, $needle) { |
||
1095 | # http://maettig.com/code/php/php-performance-benchmarks.php |
||
1096 | return strpos($haystack, $needle) === 0; |
||
1097 | } |
||
1098 | |||
1099 | // TODO: functions.inc.php |
||
1100 | protected static function endsWith($haystack, $needle) { |
||
1101 | # $length = strlen($needle); |
||
1102 | # if ($length == 0) return true; |
||
1103 | # return (substr($haystack, -$length) === $needle); |
||
1104 | return substr($haystack, -strlen($needle)) === $needle; |
||
1105 | } |
||
1106 | } |