Subversion Repositories oidplus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
226 daniel-mar 1
<?php
2
 
3
# TODO:
4
#       <oid1>
5
#               ...
6
#                       <orphan>
7
 
8
// TODO: {...} = ein link zu einer whois query
9
 
10
// TODO !list auch ohne oidplus:
11
 
12
# todo: auch "oid:" erlauben (ohne beginning dot)
13
 
14
# TODO is_numeric() nicht verwenden bei oidutils... stattdessen [0-9]+
15
 
16
// TODO: suchen nach eigenschaften, z.b. created:2012-...
17
# todo: exceptions im frontent oder false results?
18
# todo: was ist private, was protected?
19
# todo: ismU ohne m etc
20
# todo: headless camel notation
21
# todo: distance funktion: (a,b) und (b,a) syntax nicht eindeutig... mal so mal so. (plugins/*.php und ipv?_functions.php)
22
 
23
# todo: extends ok oder ist es keine oop-erweiterung?
24
require_once __DIR__ . '/1_VolcanoDB.class.php';
25
class OIDPlus extends VolcanoDB {
26
        protected function displayLine($oid) {
27
                $described   = $this->oidDescribed($oid);
28
                $identifiers = $this->getIdentifiers($oid);
29
                $oid_attribs = $this->getOIDAttribs($oid);
30
 
31
                $out = $oid;
32
 
33
                $oidary = explode('.', $oid);
34
                $lastarc = $oidary[count($oidary)-1];
35
                if (count($identifiers) == 0) {
36
                        $out .= " $lastarc";
37
                } else {
38
                        foreach ($identifiers as $n => $i) {
39
                                if ($n != 0) $out .= " |";
40
                                $out .= " $i($lastarc)";
41
                        }
42
                }
43
                if (count($oid_attribs) > 0) {
44
                        $out .= " [".implode(',',$oid_attribs)."]";
45
                }
46
                if (!$described) $out .= " [not described]";
47
                # TODO: '...' anzeigen zwischen einer OID und einer orphan OID?
48
                return $out;
49
        }
50
 
51
        protected function rec_show($oid, &$out, $desc='', $levels=-1) {
52
                $x = $this->listAllOIDs($oid, $levels);
53
                foreach ($x as $oid) {
54
                        $out .= $desc . $this->displayLine($oid) . "\n";
55
                }
56
                unset($x);
57
        }
58
 
59
        protected function rec_listAllOIDs($oid, &$out, $levels=-1) {
60
                $children = $this->listChildren($oid, $levels);
61
                if ($children === false) {
62
                        #echo "...\n"; # TODO problem, es ist ungewiss ob noch was untergeordnet ist!
63
                        return;
64
                }
65
 
66
                foreach ($children as $num => &$data) {
67
                        $dotstop = self::appendDot($oid);
68
                        $cur_oid = $dotstop.$num;
69
                        $out[] = $cur_oid;
70
                        $this->rec_listAllOIDs($cur_oid, $out, $levels-1);
71
                }
72
                unset($data);
73
        }
74
 
75
        public function listAllOIDs($oid, $levels=-1) {
76
                $out = array();
77
                $this->rec_listAllOIDs($oid, $out, $levels);
78
                return $out;
79
        }
80
 
81
/* TODO: das wäre einfacherer, aber das geht nicht mit orphan OIDS !!!
82
public function listAllOIDs($parent_oid, $depth=-1, $check_auth=true) {
83
return $this->listOIDs($parent_oid, true, $depth=-1, $check_auth=true);
84
}
85
*/
86
 
87
        public function count_roots() {
88
                return count($this->findRoots());
89
        }
90
 
91
        public function count_oids() {
92
                $oids = $this->getAllOIDs();
93
                return count($oids);
94
        }
95
 
96
        public function count_indexes() {
97
                $cnt = 0;
98
                $oids = $this->getAllOIDs();
99
                foreach ($oids as &$oid) {
100
                        $arys = $this->getDatasets($oid, 'index');
101
                        if (count($arys) > 0) $cnt++;
102
                }
103
                return $cnt;
104
        }
105
 
106
        protected function sc_listIndexes() {
107
                $out = '';
108
                # TODO: + oid anzeigen?
109
                $oids = $this->getAllOIDs();
110
                foreach ($oids as &$oid) {
111
                        $arys = $this->getDatasets($oid, 'index');
112
                        foreach ($arys as &$ary) {
113
                                if (!isset($ary['attrib_params'][0])) {
114
                                        throw new VolcanoException('index() field without any param', $ary);
115
                                }
116
                                $nid = $ary['attrib_params'][0];
117
                                $val = $ary['value'];
118
                                # TODO: domain mit puny-decoding?
119
                                $out .= "index($nid):$val\n";
120
                        }
121
                }
122
                return $out;
123
        }
124
 
125
        protected function sc_listRoots() {
126
                $out = '';
127
                $roots = $this->findRoots();
128
                foreach ($roots as &$root) {
129
                        $out .= "oid:" . $this->displayLine($root) . "\n"; # todo "oid:" mittels maketabs alignen
130
                }
131
                return $out;
132
        }
133
 
134
        protected function sc_list($show_complete_tree = false) {
135
                $out = '';
136
                if ($show_complete_tree) {
137
                        $roots = array('.');
138
                } else {
139
                        $roots = $this->findRoots();
140
                }
141
                $first = true;
142
                foreach ($roots as &$root) {
143
                        // Auskommentiert: Abstand zwischen den OIDs von 2 Roots lassen
144
                        // if (!$first) echo "\n";
145
                        $first = false;
146
                        $out .= "oid:" . $this->displayLine($root) . "\n";
147
                        $this->rec_show($root, $out, "oid:");
148
                }
149
 
150
                $out2 = array();
151
                $max_len_oid = 0;
152
                $max_dep_oid = 0;
153
                $min_dep_oid = PHP_INT_MAX;
154
                $lines = explode("\n", trim($out));
155
                foreach ($lines as &$x) {
156
                        $m = explode(' ', $x, 2);
157
                        $oid = substr($m[0], 4);
158
                        $len = strlen($oid);
159
                        $dep = oid_len($oid);
160
                        $entry = isset($m[1]) ? $m[1] : '';
161
                        $out2[] = array($len, $dep, $oid, $entry);
162
                        if ($len > $max_len_oid) $max_len_oid = $len;
163
                        if ($dep > $max_dep_oid) $max_dep_oid = $dep;
164
                        if ($dep < $min_dep_oid) $min_dep_oid = $dep;
165
                }
166
 
167
                $out = '';
168
                foreach ($out2 as &$data) {
169
                        $len = $data[0];
170
                        $dep = $data[1];
171
                        $oid = $data[2];
172
                        $entry = $data[3];
173
 
174
                        if (empty($entry)) $entry = '<no identifier>';
175
 
176
                        $oid = str_pad($oid, $max_len_oid);
177
                        $entry = str_repeat('.    ', $dep-$min_dep_oid).$entry;
178
 
179
                        $out .= "oid:$oid | $entry\n";
180
                }
181
 
182
                unset($root);
183
                return $out;
184
        }
185
 
186
        protected static function help() {
187
                // TODO syntax for searching
188
                echo "System commands:\n";
189
                echo "\thelp\n";
190
                echo "\toidplus:!list [#<authtoken>[,<authtoken>[,...]]]\n";
191
                echo "\toidplus:!listRoots [#<authtoken>[,<authtoken>[,...]]]\n";
192
                echo "\toidplus:!listIndexes [#<authtoken>[,<authtoken>[,...]]]\n";
193
# todo: listAll
194
                echo "\toidplus:!help\n";
195
                echo "\n";
196
                echo "Seaching for indexed items (index attribute):\n";
197
                echo "\toidplus:<index> [#<authtoken>[,<authtoken>[,...]]]\n";
198
                echo "\n";
199
                echo "Lookup a single OID:\n";
200
                echo "\toidplus:.2.999 [#<authtoken>[,<authtoken>[,...]]]\n";
201
                echo "\toidplus:.2.example [#<authtoken>[,<authtoken>[,...]]]\n";
202
        }
203
 
204
        # todo: kein echo sondern string return?
205
        public function query($q) {
206
                $q = trim($q);
207
 
208
#               echo "Process query '$q'\n\n";
209
 
210
                $this->clearAuthTokens();
211
 
212
                if ($q == 'help') {
213
                        return self::help();
214
                }
215
 
216
                if (!preg_match('@^oidplus:([^#]+)(#([^#]*)){0,1}$@ismU', $q, $m)) {
217
                        # return false;
218
 
219
                        # TODO: eigentlich sollte die syntax nicht willkürlich sein
220
                        # lieber "oid:(non-dotted-oid without authToken and no indexes)
221
                #       $q = preg_replace('@^oidplus:@isU', '', $q);
222
                #       $q = preg_replace('@^(urn:){0,1}oid:@isU', '.', $q);
223
                        $q = preg_replace('@^(urn:){0,1}oid:@isU', '', $q);
224
                        if (oid_valid_dotnotation($q, true, false) && ($q[0] != '.')) $q = ".$q";
225
 
226
                        $q = "oidplus:$q";
227
                        return $this->query($q);
228
                } else {
229
                        $q    = trim($m[1]);
230
                        $pins = (isset($m[3])) ? trim($m[3]) : null;
231
 
232
                        if (oid_valid_dotnotation($q, true, false) && ($q[0] != '.')) $q = ".$q";
233
                }
234
 
235
                if (!is_null($pins)) {
236
                        $pins = explode(',', $pins);
237
                        foreach ($pins as &$pin) {
238
                                $this->addAuthToken($pin);
239
                        }
240
                        unset($pin);
241
                }
242
 
243
                if ($q[0] == '!') {
244
                        $syscommand = trim(substr($q, 1));
245
                        if ($syscommand == 'help') {
246
                                return self::help();
247
                        } else if ($syscommand == 'list') {
248
                                $out = self::sc_list();
249
                                echo self::make_tabs($out);
250
                                return;
251
                        } else if ($syscommand == 'listRoots') {
252
                                $out = self::sc_listRoots();
253
                                echo self::make_tabs($out);
254
                                return;
255
                        } else if ($syscommand == 'listIndexes') {
256
                                $out = self::sc_listIndexes();
257
                                echo self::make_tabs($out);
258
                                return;
259
                        } else {
260
                                // TODO error
261
                                return false;
262
                        }
263
                } else if ($q[0] == '.') {
264
                        // Single OID
265
                        // TODO auch ohne leading dot?
266
 
267
                        echo self::make_tabs($this->showSingleOID($q));
268
                        return;
269
                } else {
270
                        // Indexed name (string, ipv4, ipv6, domain, doi, guid, ...)
271
 
272
                        $prefix  = '';
273
                        $ary     = $this->findOID($q);
274
                        if ($ary) {
275
                                $oid  = $ary[0];
276
                                $dist = $ary[1];
277
                                $nid  = $ary[2];
278
 
279
                                if ($dist > 0) {
280
                                        $prefix .= "searchterm:$q\n";
281
                                        $prefix .= "search-result:Did not find an exact match for the given searchterm, but found a superior node\n";
282
                                        $prefix .= "distance($nid):$dist\n";
283
                                        $prefix .= "\n";
284
                                }
285
 
286
                                echo self::make_tabs($this->showSingleOID($oid, $prefix));
287
                                return;
288
                        } else {
289
                                $prefix .= "searchterm:$q\n";
290
                                # $prefix .= "search-result:Not found\n";
291
                                $prefix .= "search-result:No exact match and no superior node was found\n";
292
                                echo self::make_tabs($prefix);
293
                        }
294
                }
295
        }
296
 
297
        public static function filterOutput($output, $name, $preg=false, $including_name=true) {
298
                $out = '';
299
 
300
                $lines = explode("\n", $output);
301
                foreach ($lines as $line) {
302
                        $line = trim($line);
303
                        if ($line == '') continue;
304
                        $name_val = explode(':', $line, 2);
305
                        if (count($name_val) != 2) continue;
306
                        if ($preg) {
307
                                $ok = preg_match($name, $name_val[0], $m);
308
                        } else {
309
                                $ok = $name == trim($name_val[0]);
310
                        }
311
                        if ($ok) {
312
                                if ($including_name) {
313
                                        $out .= $line."\n";
314
                                } else {
315
                                        $out .= $name_val[1]."\n";
316
                                }
317
                        }
318
 
319
                }
320
 
321
                return $out;
322
        }
323
 
324
        const SEG_OIDINFO = 2;
325
        const SEG_OIDDATA = 4;
326
        const SEG_IDX_BROWSER = 8;
327
        const SEG_OID_BROWSER = 16;
328
        /*protected*/ public function showSingleOID($oid, $prefix='', $segments = self::SEG_OIDINFO+self::SEG_OIDDATA+self::SEG_IDX_BROWSER+self::SEG_OID_BROWSER, $make_tabs=true) {
329
                if (!oid_valid_dotnotation($oid, true, substr($oid,0,1) == '.')) {
330
                        throw new VolcanoException("OID '$oid' is invalid");
331
                }
332
 
333
                $out_segs = array();
334
 
335
                $oid = sanitizeOID($oid, substr($oid,0,1) == '.');
336
                if ($oid === false) return false;
337
 
338
                // --- Segment 1 ---
339
 
340
                if (($segments & self::SEG_OIDINFO) == self::SEG_OIDINFO) {
341
                        $out = "oid:$oid\n"; # TODO: soll das "searchterm" heißen, wenn nur superior node gefunden wurde?
342
 
343
                        # TODO: nach search-result: verschieben?
344
                        foreach (self::$fieldExtenders as $fe) {
345
                                $x = array();
346
                                $fe->processOID($oid, $x, $this);
347
                                if (count($x) > 0) {
348
                                        $out .= implode("\n", $x)."\n";
349
                                }
350
                        }
351
 
352
                        if ($this->oidDescribed($oid)) {
353
                                $out .= "search-result:Found\n";
354
                        } else {
355
                                # TODO: wenn der user eine ungültige oid eingibt, dann keinen "internal error" werfen
356
                                $out .= "search-result:Not found\n";
357
                        }
358
 
359
                        $out_segs[] = $out;
360
                }
361
 
362
                // --- Segment 2 ---
363
 
364
                if (($segments & self::SEG_OIDDATA) == self::SEG_OIDDATA) {
365
                        $out = '';
366
                        $x = $this->getDatasets($oid);
367
                        foreach ($x as &$y) {
368
                                if ($this->isSpecialInvisibleField($y)) continue; // system fields, like '*read-auth' are invisible
369
                                $out .= $y['attrib_name'];
370
                                if (count($y['attrib_params']) > 0) $out .= '('.implode(',', $y['attrib_params']).')';
371
                                $out .= ':'.$y['value']."\n"; # todo: +params? TEST.
372
                        }
373
 
374
                        $out_segs[] = $out;
375
                }
376
 
377
                # --- Segment 3: Index-Navigation ---
378
 
379
                if (($segments & self::SEG_IDX_BROWSER) == self::SEG_IDX_BROWSER) {
380
                        $index_browser_ns = '';
381
                        $index_browser_val = '';
382
                        $index_browser_found = false;
383
                        if (isset($this->oid_data[$oid])) {
384
                                foreach ($this->oid_data[$oid] as $tmp) {
385
                                        if ($tmp['attrib_name'] == 'index') {
386
                                                if (!isset($tmp['attrib_params'][0])) continue; # TODO: exception?
387
                                                $index_browser_ns = $tmp['attrib_params'][0];
388
 
389
#                                               $index_browser_val = $tmp['value'];
390
                                                if (($tmp['flag_confidential']) && (!$this->isAuthentificated($oid))) {
391
                                                        if (!$this->isRedactedMessageEnabled()) {
392
                                                                continue; // hide complete line
393
                                                        } else {
394
                                                                $index_browser_val = $this->redactedMessage;
395
                                                        }
396
                                                } else {
397
                                                        $index_browser_val = $tmp['value'];
398
                                                }
399
 
400
                                                $index_browser_found = true;
401
                                                break;
402
                                        }
403
                                }
404
                        }
405
 
406
                        if (($index_browser_found) && ($found_prov = self::findSearchProvider($index_browser_ns))) {
407
                                $out = '';
408
 
409
                                $nearest_father = array(false, PHP_INT_MAX, '');
410
                                $subs = array();
411
 
412
                                $index_ns_root = oid_up($oid);
413
 
414
                                $cry = $this->listChildren($index_ns_root, 1);
415
                                foreach ($cry as $num => $c) {
416
                                        $oid_2 = $index_ns_root.'.'.$num;
417
 
418
                                        $index_browser_ns_2 = '';
419
                                        $index_browser_val_2 = '';
420
                                        $index_browser_found_2 = false;
421
                                        foreach ($this->oid_data[$oid_2] as $tmp_2) {
422
                                                if ($tmp_2['attrib_name'] == 'index') {
423
                                                        if (!isset($tmp_2['attrib_params'][0])) continue; # TODO: exception?
424
                                                        $index_browser_ns_2 = $tmp_2['attrib_params'][0];
425
 
426
#                                                       $index_browser_val_2 = $tmp_2['value'];
427
                                                        if (($tmp_2['flag_confidential']) && (!$this->isAuthentificated($oid_2))) {
428
                                                                if (!$this->isRedactedMessageEnabled()) {
429
                                                                        continue; // hide complete line
430
                                                                } else {
431
                                                                        $index_browser_val_2 = $this->redactedMessage;
432
                                                                }
433
                                                        } else {
434
                                                                $index_browser_val_2 = $tmp_2['value'];
435
                                                        }
436
 
437
                                                        $index_browser_found_2 = true;
438
                                                        break;
439
                                                }
440
                                        }
441
 
442
                                        if ($index_browser_found_2) {
443
                                                $cur_distance = $found_prov->calcDistance($index_browser_val, $index_browser_val_2);
444
 
445
                                                if ($index_browser_val == $index_browser_val_2) continue;
446
 
447
                                                if ($cur_distance === false) continue;
448
 
449
                                                if ($cur_distance < 0) {
450
                                                        if (abs($cur_distance) < $nearest_father[1]) {
451
                                                                $nearest_father[0] = true;
452
                                                                $nearest_father[1] = abs($cur_distance);
453
                                                                $nearest_father[2] = array($index_browser_val_2);
454
                                                        } else if (abs($cur_distance) == $nearest_father[1]) {
455
                                                                $nearest_father[2][] = $index_browser_val_2;
456
                                                        }
457
                                                } else if ($cur_distance > 0) {
458
                                                        $subs[] = $index_browser_val_2;
459
                                                }
460
                                        }
461
                                }
462
 
463
                                # TODO FUT: brothers (selbe dist zum vater)
464
 
465
                                // Nur die untergeordneten Knoten anzeigen, zwischen denen kein weiterer Knoten zu unserem Knoten besteht.
466
                                // K  <-- a <-- a' <-- a''
467
                                //    <-- b <-- b'
468
                                //          <-- c
469
                                // => Wähle a, b, c
470
                                foreach ($subs as &$sub1) {
471
                                        foreach ($subs as &$sub2) {
472
                                                if ($sub1 == $sub2) continue;
473
 
474
                                                $dist = ($found_prov->calcDistance($sub1, $sub2));
475
                                                if ($dist === false) continue;
476
                                                if ($dist > 0) $sub2 = null;
477
                                        }
478
                                }
479
 
480
                                if ($nearest_father[0]) {
481
                                        foreach ($nearest_father[2] as $tmp) {
482
                                                $out .= "father-index($index_browser_ns):$tmp\n";
483
                                        }
484
                                }
485
                                $out .= "self-index($index_browser_ns):$index_browser_val\n";
486
                                foreach ($subs as $tmp) {
487
                                        if (is_null($tmp)) continue;
488
                                        $out .= "son-index($index_browser_ns):$tmp\n";
489
                                }
490
 
491
                                $out_segs[] = $out;
492
                        }
493
                }
494
 
495
                # --- Segment 4: OID Navigation ---
496
 
497
                if (($segments & self::SEG_OID_BROWSER) == self::SEG_OID_BROWSER) {
498
                        $out = '';
499
 
500
                        // Show father
501
                        if ($oid != '.') {
502
                                // $out .= "father:" . $this->displayLine(oid_up($oid)) . "\n";
503
                                $i=0;
504
                                $cur_oid = $oid;
505
                                $father_out = '';
506
 
507
                                $tmp_table = array();
508
 
509
                                while ($cur_oid != '.') {
510
                                        $i++;
511
                                        $cur_oid = oid_up($cur_oid);
512
                                        $tmp_table[] = array($this->oidDescribed($cur_oid), "superior-node($i):" . $this->displayLine($cur_oid));
513
                                }
514
 
515
                                $described_once = false;
516
                                for ($i=count($tmp_table)-1; $i>=0; $i--) {
517
                                        $t = $tmp_table[$i];
518
 
519
                                        $is_desc = $t[0];
520
                                        $line    = $t[1];
521
 
522
                                        if ($is_desc) $described_once  = true;
523
 
524
                                        if ($is_desc || $described_once ) {
525
                                                $father_out .= "$line\n";
526
                                        }
527
                                }
528
 
529
                                $out .= $father_out;
530
                        }
531
 
532
                        // Show current OID
533
                        $out .= "current-node:" . $this->displayLine($oid) . "\n";
534
 
535
                        // Show first level children (also undescribed ones)
536
                        $x = $this->listChildren($oid, 1);
537
                        foreach ($x as $num => &$data) {
538
                                $dotstop = self::appendDot($oid);
539
                                $cur_oid = $dotstop.$num;
540
                                $out .= "child-node:" . $this->displayLine($cur_oid) . "\n";
541
                        }
542
 
543
                        $out_segs[] = $out;
544
 
545
                        // Brothers
546
 
547
                        $out = '';
548
 
549
                        $x = $this->listChildren(oid_up($oid), 1);
550
                        foreach ($x as $num => &$data) {
551
                                $dotstop = self::appendDot(oid_up($oid));
552
                                $cur_oid = $dotstop.$num;
553
                                if ($cur_oid != $oid) $out .= "brother:" . $this->displayLine($cur_oid) . "\n";
554
                        }
555
 
556
                        $out_segs[] = $out;
557
                }
558
 
559
                // --- Output ---
560
 
561
                $out = $prefix;
562
                $first = true;
563
                foreach ($out_segs as $seg) {
564
                        if (!$first) {
565
                                $out .= ":----------------------\n"; # TODO: max len of output
566
                        }
567
                        $out .= $seg;
568
                        $first = false;
569
                }
570
 
571
                if ($make_tabs) {
572
                        $out = self::make_tabs($out);
573
                }
574
 
575
                return $out;
576
        }
577
 
578
        # http://whois.viathinksoft.de/gwhois_fork/showcode/?fn=package%2Fshare%2Fsubprograms%2Ffunctions.inc.php
579
        # Changed: $abstand default 4->2, oop, +$mindestbreite
580
        protected static function make_tabs($text, $abstand = 2, $mindestbreite = 0) {
581
                $ary = explode("\n", $text);
582
                $longest = 0;
583
                foreach ($ary as &$a) {
584
                        $bry = explode(':', $a, 2);
585
                        if (count($bry) < 2) continue;
586
                        $c = strlen($bry[0]);
587
                        if ($c > $longest) $longest = $c;
588
                }
589
                if ($longest < $mindestbreite) $longest = $mindestbreite;
590
                foreach ($ary as $n => &$a) {
591
                        $bry = explode(':', $a, 2);
592
                        if (count($bry) < 2) continue;
593
                        $rep = $longest-strlen($bry[0]) + $abstand;
594
                        if ($rep < 1) {
595
                                $wh = '';
596
                        } else {
597
                                $wh = str_repeat(' ', $rep);
598
                        }
599
                        $ary[$n] = ($bry[0] != '' ? $bry[0].':' : ' ').$wh.trim($bry[1]);
600
                }
601
                $x = implode("\n", $ary);
602
                return $x;
603
        }
604
 
605
 
606
        protected static $fieldExtenders = array();
607
 
608
        public static function registerFieldExtender($prov) {
609
                self::$fieldExtenders[] = $prov;
610
        }
611
 
612
}