Subversion Repositories oidplus

Rev

Rev 1445 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /*
  4.  * OIDplus 2.0
  5.  * Copyright 2022 - 2023 Daniel Marschall, ViaThinkSoft / Till Wehowski, Frdlweb
  6.  *
  7.  * Licensed under the MIT License.
  8.  */
  9.  
  10. namespace Frdlweb\OIDplus;
  11.  
  12. use ViaThinkSoft\OIDplus\INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4;
  13. use ViaThinkSoft\OIDplus\INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_7;
  14. use ViaThinkSoft\OIDplus\OIDplus;
  15. use ViaThinkSoft\OIDplus\OIDplusObject;
  16. use ViaThinkSoft\OIDplus\OIDplusPagePluginPublic;
  17.  
  18. // phpcs:disable PSR1.Files.SideEffects
  19. \defined('INSIDE_OIDPLUS') or die;
  20. // phpcs:enable PSR1.Files.SideEffects
  21.  
  22. class OIDplusPagePublicAltIds extends OIDplusPagePluginPublic
  23.         implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4, /* whois*Attributes */
  24.                    INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_7  /* getAlternativesForQuery */
  25. {
  26.  
  27.         /**
  28.          * @param string $actionID
  29.          * @param array $params
  30.          * @return array
  31.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  32.          */
  33.         public function action(string $actionID, array $params): array {
  34.                 return parent::action($actionID, $params);
  35.         }
  36.  
  37.         /**
  38.          * @param string $id
  39.          * @param array $out
  40.          * @param bool $handled
  41.          * @return void
  42.          */
  43.         public function gui(string $id, array &$out, bool &$handled) {
  44.  
  45.         }
  46.  
  47.         /**
  48.          * @param array $out
  49.          * @return void
  50.          */
  51.         public function publicSitemap(array &$out) {
  52.  
  53.         }
  54.  
  55.         /**
  56.          * @param array $json
  57.          * @param string|null $ra_email
  58.          * @param bool $nonjs
  59.          * @param string $req_goto
  60.          * @return bool
  61.          */
  62.         public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
  63.                 return false;
  64.         }
  65.  
  66.         /**
  67.          * @return string|null
  68.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  69.          */
  70.         private function cache_id() {
  71.                 static $cache_id = null;
  72.                 if (!is_null($cache_id)) return $cache_id;
  73.                 $cache_id  =  'Create='.OIDplus::db()->getScalar("select max(created) as ts from ###objects where created is not null;");
  74.                 $cache_id .= '/Update='.OIDplus::db()->getScalar("select max(updated) as ts from ###objects where updated is not null;");
  75.                 $cache_id .= '/Count='.OIDplus::db()->getScalar("select count(id) as cnt from ###objects;");
  76.                 $plugin_versions = array();
  77.                 foreach (OIDplus::getObjectTypePluginsEnabled() as $otp) {
  78.                         $plugin_versions[] = '/'.$otp->getManifest()->getOid().'='.$otp->getManifest()->getVersion();
  79.                 }
  80.                 sort($plugin_versions);
  81.                 $cache_id .= implode('',$plugin_versions);
  82.                 return $cache_id;
  83.         }
  84.  
  85.         /**
  86.          * @param bool $noCache
  87.          * @return array[]|mixed|null
  88.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  89.          */
  90.         public function readAll(bool $noCache = false) {
  91.                 static $local_cache = null;
  92.  
  93.                 $cache_file = OIDplus::localpath().'/userdata/cache/frdl_alt_id.ser';
  94.                 if ($noCache === false) {
  95.                         // Local cache (to save time for multiple calls during the same HTTP request)
  96.                         if (!is_null($local_cache)) return $local_cache;
  97.  
  98.                         // File cache (to save time between HTTP requests)
  99.                         if (file_exists($cache_file)) {
  100.                                 $cache_data = unserialize(file_get_contents($cache_file));
  101.                                 $cache_id = $cache_data[0];
  102.                                 if ($cache_id == $this->cache_id()) {
  103.                                         return $cache_data[1];
  104.                                 }
  105.                         }
  106.                 }
  107.  
  108.                 $alt_ids = array();
  109.                 $rev_lookup = array();
  110.  
  111.                 $res = OIDplus::db()->query("select id from ###objects ".
  112.                                             "where parent <> 'oid:1.3.6.1.4.1.37476.1.2.3.1'");  // TODO FIXME! readAll() is TOOOOO slow if a system has more than 50.000 OIDs!!! DEADLOCK!!!
  113.                 while ($row = $res->fetch_array()) {
  114.                         $obj = OIDplusObject::parse($row['id']);
  115.                         if (!$obj) continue; // e.g. if plugin is disabled
  116.                         $ary = $obj->getAltIds();
  117.                         foreach ($ary as $a) {
  118.                                 $origin = $obj->nodeId(true);
  119.                                 $alternative = $a->getNamespace() . ':' . $a->getId();
  120.  
  121.                                 if (!isset($alt_ids[$origin])) $alt_ids[$origin] = array();
  122.                                 $alt_ids[$origin][] = $alternative;
  123.  
  124.                                 if (!isset($rev_lookup[$alternative])) $rev_lookup[$alternative] = array();
  125.                                 $rev_lookup[$alternative][] = $origin;
  126.                         }
  127.                 }
  128.  
  129.                 $data = array($alt_ids, $rev_lookup);
  130.  
  131.                 // File cache (to save time between HTTP requests)
  132.                 $cache_data = array($this->cache_id(), $data);
  133.                 @file_put_contents($cache_file, serialize($cache_data));
  134.  
  135.                 // Local cache (to save time for multiple calls during the same HTTP request)
  136.                 $local_cache = $data;
  137.  
  138.                 return $data;
  139.         }
  140.  
  141.         /**
  142.          * Acts like in_array(), but allows includes prefilterQuery, e.g. `mac:AA-BB-CC-DD-EE-FF` can be found in an array containing `mac:AABBCCDDEEFF`.
  143.          * @param string $needle
  144.          * @param array $haystack
  145.          * @return bool
  146.          */
  147.         private static function special_in_array(string $needle, array $haystack) {
  148.                 $needle_prefiltered = OIDplus::prefilterQuery($needle,false);
  149.                 foreach ($haystack as $straw) {
  150.                         $straw_prefiltered = OIDplus::prefilterQuery($straw, false);
  151.                         if ($needle == $straw) return true;
  152.                         else if ($needle == $straw_prefiltered) return true;
  153.                         else if ($needle_prefiltered == $straw) return true;
  154.                         else if ($needle_prefiltered == $straw_prefiltered) return true;
  155.                 }
  156.                 return false;
  157.         }
  158.  
  159.         /**
  160.          * @param string $id
  161.          * @return string[]
  162.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  163.          */
  164.         public function getAlternativesForQuery(string $id/* INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_7 signature takes just 1 param!? , $noCache = false*/): array {
  165.  
  166.                 static $caches = array();
  167.  
  168.                 if(/*$noCache === false && */isset($caches[$id]) ){
  169.                         return $caches[$id];
  170.                 }
  171.  
  172.                 if (strpos($id,':') !== false) {
  173.                         list($ns, $altIdRaw) = explode(':', $id, 2);
  174.                         if($ns === 'weid'){
  175.                                 $id='oid:'.\Frdl\Weid\WeidOidConverter::weid2oid($id);
  176.                         }
  177.                 }
  178.  
  179.                 list($alt_ids, $rev_lookup) = $this->readAll(false);
  180.  
  181.                 $res = [
  182.                         $id,
  183.                 ];
  184.                 if(isset($rev_lookup[$id])){
  185.                         $res = array_merge($res, $rev_lookup[$id]);
  186.                 }
  187.                 foreach($alt_ids as $original => $altIds){
  188.                         // Why self::special_in_array() instead of in_array()? Consider the following testcase:
  189.                         // "oid:1.3.6.1.4.1.37553.8.8.2" defines alt ID "mac:63-CF-E4-AE-C5-66" which is NOT canonized!
  190.                         // You must be able to enter "mac:63-CF-E4-AE-C5-66" in the search box, which gets canonized
  191.                         // to mac:63CFE4AEC566 and must be solved to "oid:1.3.6.1.4.1.37553.8.8.2" by this plugin.
  192.                         // Therefore we use self::special_in_array().
  193.                         // However, it is mandatory, that previously saveAltIdsForQuery("oid:1.3.6.1.4.1.37553.8.8.2") was called once!
  194.                         // Please also note that the "weid:" to "oid:" converting is handled by prefilterQuery(), but only if the OID plugin is installed.
  195.                         if($id === $original || self::special_in_array($id, $altIds) ){
  196.                                  $res = array_merge($res, $altIds);
  197.                                  $res = array_merge($res, [$original]);
  198.                         }
  199.                 }
  200.  
  201.                 $weid = false;
  202.                 foreach($res as $alt){
  203.                         if (strpos($alt,':') !== false) {
  204.                                 list($ns, $altIdRaw) = explode(':', $alt, 2);
  205.                                 if($ns === 'oid'){
  206.                                         $weid=\Frdl\Weid\WeidOidConverter::oid2weid($altIdRaw);
  207.                                         break;
  208.                                 }
  209.                         }
  210.                 }
  211.  
  212.                 if ($weid !== false) {
  213.                         $res[]=$weid;
  214.                 }
  215.                 $res = array_unique($res);
  216.  
  217.                 $caches[$id] = $res;
  218.  
  219.                 return $res;
  220.         }
  221.  
  222.         /**
  223.          * @param string $request
  224.          * @return array|false
  225.          */
  226.         public function tree_search(string $request) {
  227.                 return false;
  228.         }
  229.  
  230.         /**
  231.          * @param string $id
  232.          * @return false|mixed|string
  233.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  234.          */
  235.         public function getCanonical(string $id){
  236.                 foreach($this->getAlternativesForQuery($id) as $alt){
  237.                         if (strpos($alt,':') !== false) {
  238.                                 list($ns, $altIdRaw) = explode(':', $alt, 2);
  239.                                 if($ns === 'oid'){
  240.                                         return $alt;
  241.                                 }
  242.                         }
  243.                 }
  244.  
  245.                 return false;
  246.         }
  247.  
  248.         /**
  249.          * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4
  250.          * @param string $id
  251.          * @param array $out
  252.          * @return void
  253.          * @throws \ViaThinkSoft\OIDplus\OIDplusException
  254.          */
  255.         public function whoisObjectAttributes(string $id, array &$out) {
  256.                 $xmlns = 'oidplus-frdlweb-altids-plugin';
  257.                 $xmlschema = 'urn:oid:1.3.6.1.4.1.37553.8.1.8.8.53354196964.641310544.1714020422';
  258.                 $xmlschemauri = OIDplus::webpath(__DIR__.'/altids.xsd',OIDplus::PATH_ABSOLUTE_CANONICAL);
  259.  
  260.                 $handleShown = false;
  261.                 $canonicalShown = false;
  262.  
  263.                 $out1 = array();
  264.                 $out2 = array();
  265.  
  266.                 $tmp = $this->getAlternativesForQuery($id);
  267.                 sort($tmp); // DM 26.03.2023 : Added sorting (intended to sort "alternate-identifier")
  268.  
  269.                 foreach($tmp as $alt) {
  270.                         if (strpos($alt,':') === false) continue;
  271.  
  272.                         list($ns, $altIdRaw) = explode(':', $alt, 2);
  273.  
  274.                         if (($canonicalShown === false) && ($ns === 'oid')) {
  275.                                 $canonicalShown=true;
  276.  
  277.                                 $out1[] = [
  278.                                         'xmlns' => $xmlns,
  279.                                         'xmlschema' => $xmlschema,
  280.                                         'xmlschemauri' => $xmlschemauri,
  281.                                         'name' => 'canonical-identifier',
  282.                                         'value' => $ns.':'.$altIdRaw,
  283.                                 ];
  284.  
  285.                         }
  286.  
  287.                         if (($handleShown === false) && ($alt === $id)) {
  288.                                 $handleShown=true;
  289.  
  290.                                 $out1[] = [
  291.                                         'xmlns' => $xmlns,
  292.                                         'xmlschema' => $xmlschema,
  293.                                         'xmlschemauri' => $xmlschemauri,
  294.                                         'name' => 'handle-identifier',
  295.                                         'value' => $alt,
  296.                                 ];
  297.  
  298.                         }
  299.  
  300.                         if ($alt !== $id) { // DM 26.03.2023 : Added condition that alternate must not be the id itself
  301.                                 $out2[] = [
  302.                                         'xmlns' => $xmlns,
  303.                                         'xmlschema' => $xmlschema,
  304.                                         'xmlschemauri' => $xmlschemauri,
  305.                                         'name' => 'alternate-identifier',
  306.                                         'value' => $ns.':'.$altIdRaw,
  307.                                 ];
  308.                         }
  309.  
  310.                 }
  311.  
  312.                 // DM 26.03.2023 : Added this
  313.                 $out = array_merge($out, $out1); // handle-identifier and canonical-identifier
  314.                 $out = array_merge($out, $out2); // alternate-identifier
  315.  
  316.         }
  317.  
  318.         /**
  319.          * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4
  320.          * @param string $email
  321.          * @param array $out
  322.          * @return void
  323.          */
  324.         public function whoisRaAttributes(string $email, array &$out) {
  325.  
  326.         }
  327.  
  328.  }
  329.