Rev 1417 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
707 | daniel-mar | 1 | <?php |
2 | |||
3 | /* |
||
4 | * OIDplus 2.0 |
||
1086 | daniel-mar | 5 | * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft |
707 | daniel-mar | 6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
8 | * you may not use this file except in compliance with the License. |
||
9 | * You may obtain a copy of the License at |
||
10 | * |
||
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
12 | * |
||
13 | * Unless required by applicable law or agreed to in writing, software |
||
14 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
16 | * See the License for the specific language governing permissions and |
||
17 | * limitations under the License. |
||
18 | */ |
||
19 | |||
1050 | daniel-mar | 20 | namespace ViaThinkSoft\OIDplus; |
707 | daniel-mar | 21 | |
1417 | daniel-mar | 22 | use SpomkyLabs\Punycode; |
23 | |||
1086 | daniel-mar | 24 | // phpcs:disable PSR1.Files.SideEffects |
25 | \defined('INSIDE_OIDPLUS') or die; |
||
26 | // phpcs:enable PSR1.Files.SideEffects |
||
27 | |||
707 | daniel-mar | 28 | class OIDplusDomain extends OIDplusObject { |
1130 | daniel-mar | 29 | /** |
30 | * @var string |
||
31 | */ |
||
707 | daniel-mar | 32 | private $domain; |
33 | |||
1116 | daniel-mar | 34 | /** |
35 | * @param string $domain |
||
36 | */ |
||
37 | public function __construct(string $domain) { |
||
707 | daniel-mar | 38 | // TODO: syntax checks |
39 | $this->domain = $domain; |
||
40 | } |
||
41 | |||
1116 | daniel-mar | 42 | /** |
43 | * @param string $node_id |
||
44 | * @return OIDplusDomain|null |
||
45 | */ |
||
46 | public static function parse(string $node_id)/*: ?OIDplusDomain*/ { |
||
707 | daniel-mar | 47 | @list($namespace, $domain) = explode(':', $node_id, 2); |
1116 | daniel-mar | 48 | if ($namespace !== self::ns()) return null; |
707 | daniel-mar | 49 | return new self($domain); |
50 | } |
||
51 | |||
1116 | daniel-mar | 52 | /** |
53 | * @return string |
||
54 | */ |
||
55 | public static function objectTypeTitle(): string { |
||
707 | daniel-mar | 56 | return _L('Domain Names'); |
57 | } |
||
58 | |||
1116 | daniel-mar | 59 | /** |
60 | * @return string |
||
61 | */ |
||
62 | public static function objectTypeTitleShort(): string { |
||
707 | daniel-mar | 63 | return _L('Domain'); |
64 | } |
||
65 | |||
1116 | daniel-mar | 66 | /** |
67 | * @return string |
||
68 | */ |
||
69 | public static function ns(): string { |
||
707 | daniel-mar | 70 | return 'domain'; |
71 | } |
||
72 | |||
1116 | daniel-mar | 73 | /** |
74 | * @return string |
||
75 | */ |
||
76 | public static function root(): string { |
||
860 | daniel-mar | 77 | return self::ns().':'; |
707 | daniel-mar | 78 | } |
79 | |||
1116 | daniel-mar | 80 | /** |
81 | * @return bool |
||
82 | */ |
||
83 | public function isRoot(): bool { |
||
707 | daniel-mar | 84 | return $this->domain == ''; |
85 | } |
||
86 | |||
1116 | daniel-mar | 87 | /** |
88 | * @param bool $with_ns |
||
89 | * @return string |
||
90 | */ |
||
91 | public function nodeId(bool $with_ns=true): string { |
||
859 | daniel-mar | 92 | return $with_ns ? self::root().$this->domain : $this->domain; |
707 | daniel-mar | 93 | } |
94 | |||
1116 | daniel-mar | 95 | /** |
96 | * @param string $str |
||
97 | * @return string |
||
98 | * @throws OIDplusException |
||
99 | */ |
||
100 | public function addString(string $str): string { |
||
707 | daniel-mar | 101 | if ($this->isRoot()) { |
859 | daniel-mar | 102 | return self::root().$str; |
707 | daniel-mar | 103 | } else { |
104 | if (strpos($str,'.') !== false) throw new OIDplusException(_L('Please only submit one arc.')); |
||
859 | daniel-mar | 105 | return self::root().$str.'.'.$this->nodeId(false); |
707 | daniel-mar | 106 | } |
107 | } |
||
108 | |||
1116 | daniel-mar | 109 | /** |
110 | * @param OIDplusObject $parent |
||
111 | * @return string |
||
112 | */ |
||
113 | public function crudShowId(OIDplusObject $parent): string { |
||
707 | daniel-mar | 114 | return $this->domain; |
115 | } |
||
116 | |||
1116 | daniel-mar | 117 | /** |
118 | * @return string |
||
119 | * @throws OIDplusException |
||
120 | */ |
||
121 | public function crudInsertSuffix(): string { |
||
707 | daniel-mar | 122 | return $this->isRoot() ? '' : substr($this->addString(''), strlen(self::ns())+1); |
123 | } |
||
124 | |||
1116 | daniel-mar | 125 | /** |
126 | * @param OIDplusObject|null $parent |
||
127 | * @return string |
||
128 | */ |
||
129 | public function jsTreeNodeName(OIDplusObject $parent = null): string { |
||
707 | daniel-mar | 130 | if ($parent == null) return $this->objectTypeTitle(); |
131 | return $this->domain; |
||
132 | } |
||
133 | |||
1116 | daniel-mar | 134 | /** |
135 | * @return string |
||
136 | */ |
||
137 | public function defaultTitle(): string { |
||
707 | daniel-mar | 138 | return $this->domain; |
139 | } |
||
140 | |||
1116 | daniel-mar | 141 | /** |
142 | * @return bool |
||
143 | */ |
||
144 | public function isLeafNode(): bool { |
||
707 | daniel-mar | 145 | return false; |
146 | } |
||
147 | |||
1116 | daniel-mar | 148 | /** |
1417 | daniel-mar | 149 | * @return string[] |
150 | * @throws OIDplusException |
||
151 | */ |
||
152 | private function getTechInfo(): array { |
||
153 | $tech_info = array(); |
||
154 | |||
155 | $dns = $this->nodeId(false); |
||
156 | $punycode = Punycode::encode($dns); |
||
157 | |||
1420 | daniel-mar | 158 | // More informatin about the three formats, see RFC 8499 |
159 | |||
160 | // - common (www.example.com) <== we have this natively |
||
1417 | daniel-mar | 161 | if ($dns != $punycode) { |
1420 | daniel-mar | 162 | $tmp = _L('Common display (IDN)'); |
1417 | daniel-mar | 163 | $tech_info[$tmp] = $dns; |
1420 | daniel-mar | 164 | $tmp = _L('Common display (Punycode)'); |
1417 | daniel-mar | 165 | $tech_info[$tmp] = $punycode; |
166 | } else { |
||
1420 | daniel-mar | 167 | $tmp = _L('Common display'); |
1417 | daniel-mar | 168 | $tech_info[$tmp] = $punycode; |
169 | } |
||
170 | |||
171 | // - presentation (www.example.com.) |
||
1420 | daniel-mar | 172 | $tmp = _L('Presentation format'); |
1417 | daniel-mar | 173 | $tech_info[$tmp] = $punycode.'.'; |
174 | |||
1420 | daniel-mar | 175 | // - wire format (3www7example3com0, but actually, the numbers are octets (binary), not decimal) |
176 | $bytes = []; |
||
1417 | daniel-mar | 177 | $ary = explode('.', $punycode.'.'); |
178 | foreach ($ary as $a) { |
||
1420 | daniel-mar | 179 | $bytes[] = strlen($a); |
180 | for ($i=0; $i<strlen($a); $i++) { |
||
181 | $bytes[] = ord($a[$i]); |
||
182 | } |
||
1417 | daniel-mar | 183 | } |
1420 | daniel-mar | 184 | $wireformat = c_literal($bytes); |
185 | # TODO: am besten farbmarkierung innerhalb c_literal_machen ? mit <abbr> und dann <abbr> irgendwie behandeln? |
||
186 | $wireformat = preg_replace('@(\\\\\\d{3})@i', '<span class="dns_wireformat_specialhexchar">\\1</span>', $wireformat); |
||
187 | $wireformat = preg_replace('@(\\\\x[0-9A-Fa-f]{2})@i', '<span class="dns_wireformat_specialhexchar">\\1</span>', $wireformat); |
||
1417 | daniel-mar | 188 | $tmp = _L('Wire format'); |
189 | $tech_info[$tmp] = $wireformat; |
||
190 | |||
191 | return $tech_info; |
||
192 | } |
||
193 | |||
194 | /** |
||
1116 | daniel-mar | 195 | * @param string $title |
196 | * @param string $content |
||
197 | * @param string $icon |
||
198 | * @return void |
||
199 | * @throws OIDplusException |
||
200 | */ |
||
201 | public function getContentPage(string &$title, string &$content, string &$icon) { |
||
801 | daniel-mar | 202 | $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : ''; |
707 | daniel-mar | 203 | |
204 | if ($this->isRoot()) { |
||
205 | $title = OIDplusDomain::objectTypeTitle(); |
||
206 | |||
207 | $res = OIDplus::db()->query("select * from ###objects where parent = ?", array(self::root())); |
||
790 | daniel-mar | 208 | if ($res->any()) { |
962 | daniel-mar | 209 | $content = '<p>'._L('Please select a Domain Name in the tree view at the left to show its contents.').'</p>'; |
707 | daniel-mar | 210 | } else { |
962 | daniel-mar | 211 | $content = '<p>'._L('Currently, no Domain Name is registered in the system.').'</p>'; |
707 | daniel-mar | 212 | } |
213 | |||
214 | if (!$this->isLeafNode()) { |
||
215 | if (OIDplus::authUtils()->isAdminLoggedIn()) { |
||
216 | $content .= '<h2>'._L('Manage root objects').'</h2>'; |
||
217 | } else { |
||
218 | $content .= '<h2>'._L('Available objects').'</h2>'; |
||
219 | } |
||
220 | $content .= '%%CRUD%%'; |
||
221 | } |
||
222 | } else { |
||
223 | $title = $this->getTitle(); |
||
224 | |||
1417 | daniel-mar | 225 | $tech_info = $this->getTechInfo(); |
226 | $tech_info_html = ''; |
||
227 | if (count($tech_info) > 0) { |
||
228 | $tech_info_html .= '<h2>'._L('Technical information').'</h2>'; |
||
229 | $tech_info_html .= '<div style="overflow:auto"><table border="0">'; |
||
230 | foreach ($tech_info as $key => $value) { |
||
231 | $tech_info_html .= '<tr><td valign="top" style="white-space: nowrap;">'.$key.': </td><td><code>'.$value.'</code></td></tr>'; |
||
232 | } |
||
233 | $tech_info_html .= '</table></div>'; |
||
234 | } |
||
707 | daniel-mar | 235 | |
1417 | daniel-mar | 236 | // $content = '<h3>'.explode(':',$this->nodeId())[1].'</h3>'; |
237 | $content = $tech_info_html; |
||
238 | |||
707 | daniel-mar | 239 | $content .= '<h2>'._L('Description').'</h2>%%DESC%%'; // TODO: add more meta information about the object type |
240 | |||
241 | if (!$this->isLeafNode()) { |
||
242 | if ($this->userHasWriteRights()) { |
||
928 | daniel-mar | 243 | $content .= '<h2>'._L('Create or change subordinate objects').'</h2>'; |
707 | daniel-mar | 244 | } else { |
928 | daniel-mar | 245 | $content .= '<h2>'._L('Subordinate objects').'</h2>'; |
707 | daniel-mar | 246 | } |
247 | $content .= '%%CRUD%%'; |
||
248 | } |
||
249 | } |
||
250 | } |
||
251 | |||
1116 | daniel-mar | 252 | /** |
253 | * @return OIDplusDomain|null |
||
254 | */ |
||
255 | public function one_up()/*: ?OIDplusDomain*/ { |
||
707 | daniel-mar | 256 | $oid = $this->domain; |
257 | |||
258 | $p = strpos($oid, '.'); |
||
713 | daniel-mar | 259 | if ($p === false) return self::parse(''); |
707 | daniel-mar | 260 | |
261 | $oid_up = substr($oid, $p+1); |
||
262 | |||
263 | return self::parse(self::ns().':'.$oid_up); |
||
264 | } |
||
265 | |||
1116 | daniel-mar | 266 | /** |
1130 | daniel-mar | 267 | * @param OIDplusObject|string $to |
1116 | daniel-mar | 268 | * @return int|null |
269 | */ |
||
707 | daniel-mar | 270 | public function distance($to) { |
271 | if (!is_object($to)) $to = OIDplusObject::parse($to); |
||
1121 | daniel-mar | 272 | if (!$to) return null; |
1116 | daniel-mar | 273 | if (!($to instanceof $this)) return null; |
707 | daniel-mar | 274 | |
275 | $a = $to->domain; |
||
276 | $b = $this->domain; |
||
277 | |||
278 | if (substr($a,-1) == '.') $a = substr($a,0,strlen($a)-1); |
||
279 | if (substr($b,-1) == '.') $b = substr($b,0,strlen($b)-1); |
||
280 | |||
281 | $ary = explode('.', $a); |
||
282 | $bry = explode('.', $b); |
||
283 | |||
284 | $ary = array_reverse($ary); |
||
285 | $bry = array_reverse($bry); |
||
286 | |||
287 | $min_len = min(count($ary), count($bry)); |
||
288 | |||
289 | for ($i=0; $i<$min_len; $i++) { |
||
1116 | daniel-mar | 290 | if ($ary[$i] != $bry[$i]) return null; |
707 | daniel-mar | 291 | } |
292 | |||
293 | return count($ary) - count($bry); |
||
294 | } |
||
295 | |||
1116 | daniel-mar | 296 | /** |
1417 | daniel-mar | 297 | * @return OIDplusAltId[] |
298 | * @throws OIDplusException |
||
299 | */ |
||
300 | public function getAltIds(): array { |
||
301 | if ($this->isRoot()) return array(); |
||
302 | $ids = parent::getAltIds(); |
||
303 | |||
304 | // Note: The payload for the namebased UUID can be any notation: |
||
1420 | daniel-mar | 305 | // - common display (www.example.com) <== we use this |
306 | // - presentation format (www.example.com.) |
||
307 | // - wire format format (3www7example3com0, actually contains octets, not decimals!) |
||
308 | // More informatin about the three formats, see RFC 8499 |
||
1417 | daniel-mar | 309 | $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_DNS, $this->nodeId(false)), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_DNS')); |
310 | $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_DNS, $this->nodeId(false)), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_DNS')); |
||
311 | |||
312 | return $ids; |
||
313 | } |
||
314 | |||
315 | /** |
||
1116 | daniel-mar | 316 | * @return string |
317 | */ |
||
318 | public function getDirectoryName(): string { |
||
707 | daniel-mar | 319 | if ($this->isRoot()) return $this->ns(); |
320 | return $this->ns().'_'.md5($this->nodeId(false)); |
||
321 | } |
||
800 | daniel-mar | 322 | |
1116 | daniel-mar | 323 | /** |
324 | * @param string $mode |
||
325 | * @return string |
||
326 | */ |
||
327 | public static function treeIconFilename(string $mode): string { |
||
800 | daniel-mar | 328 | return 'img/'.$mode.'_icon16.png'; |
329 | } |
||
707 | daniel-mar | 330 | } |