Rev 1445 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
990 | daniel-mar | 1 | <?php |
2 | |||
3 | /* |
||
4 | * OIDplus 2.0 |
||
1086 | daniel-mar | 5 | * Copyright 2022 - 2023 Daniel Marschall, ViaThinkSoft / Till Wehowski, Frdlweb |
990 | daniel-mar | 6 | * |
7 | * Licensed under the MIT License. |
||
8 | */ |
||
9 | |||
1050 | daniel-mar | 10 | namespace Frdlweb\OIDplus; |
990 | daniel-mar | 11 | |
1131 | daniel-mar | 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; |
||
1050 | daniel-mar | 14 | use ViaThinkSoft\OIDplus\OIDplus; |
15 | use ViaThinkSoft\OIDplus\OIDplusObject; |
||
16 | use ViaThinkSoft\OIDplus\OIDplusPagePluginPublic; |
||
17 | |||
1086 | daniel-mar | 18 | // phpcs:disable PSR1.Files.SideEffects |
19 | \defined('INSIDE_OIDPLUS') or die; |
||
20 | // phpcs:enable PSR1.Files.SideEffects |
||
21 | |||
1131 | daniel-mar | 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 | { |
||
990 | daniel-mar | 26 | |
1116 | daniel-mar | 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); |
||
990 | daniel-mar | 35 | } |
36 | |||
1116 | daniel-mar | 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) { |
||
990 | daniel-mar | 44 | |
45 | } |
||
46 | |||
1116 | daniel-mar | 47 | /** |
48 | * @param array $out |
||
49 | * @return void |
||
50 | */ |
||
51 | public function publicSitemap(array &$out) { |
||
990 | daniel-mar | 52 | |
53 | } |
||
54 | |||
1116 | daniel-mar | 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 { |
||
990 | daniel-mar | 63 | return false; |
64 | } |
||
65 | |||
1116 | daniel-mar | 66 | /** |
67 | * @return string|null |
||
68 | * @throws \ViaThinkSoft\OIDplus\OIDplusException |
||
69 | */ |
||
990 | daniel-mar | 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 | |||
1116 | daniel-mar | 85 | /** |
1130 | daniel-mar | 86 | * @param bool $noCache |
1116 | daniel-mar | 87 | * @return array[]|mixed|null |
88 | * @throws \ViaThinkSoft\OIDplus\OIDplusException |
||
89 | */ |
||
1130 | daniel-mar | 90 | public function readAll(bool $noCache = false) { |
990 | daniel-mar | 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 | |||
1445 | daniel-mar | 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!!! |
||
990 | daniel-mar | 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 | |||
1116 | daniel-mar | 141 | /** |
1449 | daniel-mar | 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 | /** |
||
1130 | daniel-mar | 160 | * @param string $id |
1131 | daniel-mar | 161 | * @return string[] |
1116 | daniel-mar | 162 | * @throws \ViaThinkSoft\OIDplus\OIDplusException |
163 | */ |
||
1131 | daniel-mar | 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 { |
990 | daniel-mar | 165 | |
166 | static $caches = array(); |
||
167 | |||
168 | if(/*$noCache === false && */isset($caches[$id]) ){ |
||
169 | return $caches[$id]; |
||
170 | } |
||
171 | |||
1008 | daniel-mar | 172 | if (strpos($id,':') !== false) { |
173 | list($ns, $altIdRaw) = explode(':', $id, 2); |
||
174 | if($ns === 'weid'){ |
||
1050 | daniel-mar | 175 | $id='oid:'.\Frdl\Weid\WeidOidConverter::weid2oid($id); |
1008 | daniel-mar | 176 | } |
990 | daniel-mar | 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){ |
||
1449 | daniel-mar | 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) ){ |
||
990 | daniel-mar | 196 | $res = array_merge($res, $altIds); |
197 | $res = array_merge($res, [$original]); |
||
198 | } |
||
199 | } |
||
200 | |||
201 | $weid = false; |
||
202 | foreach($res as $alt){ |
||
1008 | daniel-mar | 203 | if (strpos($alt,':') !== false) { |
204 | list($ns, $altIdRaw) = explode(':', $alt, 2); |
||
205 | if($ns === 'oid'){ |
||
1050 | daniel-mar | 206 | $weid=\Frdl\Weid\WeidOidConverter::oid2weid($altIdRaw); |
1008 | daniel-mar | 207 | break; |
208 | } |
||
990 | daniel-mar | 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 | |||
1116 | daniel-mar | 222 | /** |
223 | * @param string $request |
||
224 | * @return array|false |
||
225 | */ |
||
226 | public function tree_search(string $request) { |
||
990 | daniel-mar | 227 | return false; |
228 | } |
||
229 | |||
1116 | daniel-mar | 230 | /** |
1130 | daniel-mar | 231 | * @param string $id |
1116 | daniel-mar | 232 | * @return false|mixed|string |
233 | * @throws \ViaThinkSoft\OIDplus\OIDplusException |
||
234 | */ |
||
1130 | daniel-mar | 235 | public function getCanonical(string $id){ |
990 | daniel-mar | 236 | foreach($this->getAlternativesForQuery($id) as $alt){ |
1008 | daniel-mar | 237 | if (strpos($alt,':') !== false) { |
238 | list($ns, $altIdRaw) = explode(':', $alt, 2); |
||
239 | if($ns === 'oid'){ |
||
240 | return $alt; |
||
241 | } |
||
990 | daniel-mar | 242 | } |
243 | } |
||
244 | |||
245 | return false; |
||
246 | } |
||
247 | |||
1116 | daniel-mar | 248 | /** |
1131 | daniel-mar | 249 | * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4 |
1130 | daniel-mar | 250 | * @param string $id |
251 | * @param array $out |
||
1116 | daniel-mar | 252 | * @return void |
253 | * @throws \ViaThinkSoft\OIDplus\OIDplusException |
||
254 | */ |
||
1130 | daniel-mar | 255 | public function whoisObjectAttributes(string $id, array &$out) { |
990 | daniel-mar | 256 | $xmlns = 'oidplus-frdlweb-altids-plugin'; |
257 | $xmlschema = 'urn:oid:1.3.6.1.4.1.37553.8.1.8.8.53354196964.641310544.1714020422'; |
||
1375 | daniel-mar | 258 | $xmlschemauri = OIDplus::webpath(__DIR__.'/altids.xsd',OIDplus::PATH_ABSOLUTE_CANONICAL); |
990 | daniel-mar | 259 | |
260 | $handleShown = false; |
||
261 | $canonicalShown = false; |
||
262 | |||
1135 | daniel-mar | 263 | $out1 = array(); |
264 | $out2 = array(); |
||
990 | daniel-mar | 265 | |
1135 | daniel-mar | 266 | $tmp = $this->getAlternativesForQuery($id); |
267 | sort($tmp); // DM 26.03.2023 : Added sorting (intended to sort "alternate-identifier") |
||
1445 | daniel-mar | 268 | |
1135 | daniel-mar | 269 | foreach($tmp as $alt) { |
1040 | daniel-mar | 270 | if (strpos($alt,':') === false) continue; |
1008 | daniel-mar | 271 | |
990 | daniel-mar | 272 | list($ns, $altIdRaw) = explode(':', $alt, 2); |
273 | |||
1445 | daniel-mar | 274 | if (($canonicalShown === false) && ($ns === 'oid')) { |
990 | daniel-mar | 275 | $canonicalShown=true; |
276 | |||
1135 | daniel-mar | 277 | $out1[] = [ |
990 | daniel-mar | 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 | |||
1135 | daniel-mar | 290 | $out1[] = [ |
990 | daniel-mar | 291 | 'xmlns' => $xmlns, |
292 | 'xmlschema' => $xmlschema, |
||
293 | 'xmlschemauri' => $xmlschemauri, |
||
294 | 'name' => 'handle-identifier', |
||
295 | 'value' => $alt, |
||
296 | ]; |
||
297 | |||
298 | } |
||
299 | |||
1135 | daniel-mar | 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 | } |
||
990 | daniel-mar | 309 | |
310 | } |
||
1135 | daniel-mar | 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 | |||
990 | daniel-mar | 316 | } |
317 | |||
1116 | daniel-mar | 318 | /** |
1131 | daniel-mar | 319 | * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_4 |
1130 | daniel-mar | 320 | * @param string $email |
321 | * @param array $out |
||
1116 | daniel-mar | 322 | * @return void |
323 | */ |
||
1130 | daniel-mar | 324 | public function whoisRaAttributes(string $email, array &$out) { |
1116 | daniel-mar | 325 | |
990 | daniel-mar | 326 | } |
327 | |||
328 | } |