Subversion Repositories oidplus

Rev

Blame | Last modification | View Log | RSS feed

  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. }
  613.