Subversion Repositories oidplus

Rev

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

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
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
 
227 daniel-mar 20
class OIDplusOid extends OIDplusObject {
21
        private $oid;
22
 
2 daniel-mar 23
        public function __construct($oid) {
12 daniel-mar 24
                $bak_oid = $oid;
25
 
26
                $oid = sanitizeOID($oid, 'auto');
27
                if ($oid === false) {
250 daniel-mar 28
                        throw new OIDplusException("Invalid OID '$bak_oid'");
12 daniel-mar 29
                }
30
 
31
                if (($oid != '') && (!oid_valid_dotnotation($oid, false, true, 0))) {
32
                        // avoid OIDs like 3.0
250 daniel-mar 33
                        throw new OIDplusException("Invalid OID '$bak_oid'");
12 daniel-mar 34
                }
35
 
2 daniel-mar 36
                $this->oid = $oid;
37
        }
38
 
39
        public static function parse($node_id) {
40
                @list($namespace, $oid) = explode(':', $node_id, 2);
41
                if ($namespace !== 'oid') return false;
42
                return new self($oid);
43
        }
44
 
45
        public static function objectTypeTitle() {
46
                return "Object Identifier (OID)";
47
        }
48
 
49
        public static function objectTypeTitleShort() {
50
                return "OID";
51
        }
52
 
53
        public static function ns() {
54
                return 'oid';
55
        }
56
 
57
        public static function root() {
58
                return 'oid:';
59
        }
60
 
61
        public function isRoot() {
62
                return $this->oid == '';
63
        }
64
 
247 daniel-mar 65
        public function nodeId($with_ns=true) {
66
                return $with_ns ? 'oid:'.$this->oid : $this->oid;
2 daniel-mar 67
        }
68
 
69
        public function addString($str) {
70
                if (!$this->isRoot()) {
250 daniel-mar 71
                        if (strpos($str,'.') !== false) throw new OIDplusException("Please only submit one arc (not an absolute OID or multiple arcs).");
2 daniel-mar 72
                }
196 daniel-mar 73
 
199 daniel-mar 74
                return $this->appendArcs($str)->nodeId();
2 daniel-mar 75
        }
76
 
77
        public function crudShowId(OIDplusObject $parent) {
78
                return $this->deltaDotNotation($parent);
79
        }
80
 
81
        public function crudInsertPrefix() {
82
                return '';
83
        }
84
 
85
        public function jsTreeNodeName(OIDplusObject $parent = null) {
86
                if ($parent == null) return $this->objectTypeTitle();
87
                return $this->viewGetArcAsn1s($parent);
88
        }
89
 
90
        public function defaultTitle() {
91
                return 'OID ' . $this->oid;
92
        }
93
 
16 daniel-mar 94
        public function isLeafNode() {
95
                return false;
96
        }
97
 
34 daniel-mar 98
        public function getContentPage(&$title, &$content, &$icon) {
55 daniel-mar 99
                $icon = file_exists(__DIR__.'/icon_big.png') ? 'plugins/objectTypes/'.basename(__DIR__).'/icon_big.png' : '';
100
 
2 daniel-mar 101
                if ($this->isRoot()) {
102
                        $title = OIDplusOid::objectTypeTitle();
103
 
261 daniel-mar 104
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array(self::root()));
236 daniel-mar 105
                        if ($res->num_rows() > 0) {
2 daniel-mar 106
                                $content = 'Please select an OID in the tree view at the left to show its contents.';
107
                        } else {
108
                                $content = 'Currently, no OID is registered in the system.';
109
                        }
110
 
16 daniel-mar 111
                        if (!$this->isLeafNode()) {
112
                                if (OIDplus::authUtils()::isAdminLoggedIn()) {
113
                                        $content .= '<h2>Manage your root OIDs</h2>';
114
                                } else {
115
                                        $content .= '<h2>Root OIDs</h2>';
116
                                }
117
                                $content .= '%%CRUD%%';
2 daniel-mar 118
                        }
119
                } else {
192 daniel-mar 120
                        $title = $this->getTitle();
121
 
103 daniel-mar 122
                        $content = "<h2>Technical information</h2>".$this->oidInformation().
11 daniel-mar 123
                                   "<h2>Description</h2>%%DESC%%".
6 daniel-mar 124
                                   "<h2>Registration Authority</h2>%%RA_INFO%%";
2 daniel-mar 125
 
16 daniel-mar 126
                        if (!$this->isLeafNode()) {
127
                                if ($this->userHasWriteRights()) {
128
                                        $content .= '<h2>Create or change subsequent objects</h2>';
129
                                } else {
130
                                        $content .= '<h2>Subsequent objects</h2>';
131
                                }
132
                                $content .= '%%CRUD%%';
2 daniel-mar 133
                        }
134
                }
135
        }
136
 
137
        # ---
138
 
197 daniel-mar 139
        public function isWeid($allow_root) {
61 daniel-mar 140
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
197 daniel-mar 141
                if (!$allow_root && ($weid === 'weid:4')) return false;
196 daniel-mar 142
                return $weid !== false;
2 daniel-mar 143
        }
144
 
196 daniel-mar 145
        public function weidArc() {
146
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
147
                if ($weid === false) return false;
197 daniel-mar 148
                list($ns,$weid) = explode(':', $weid, 2);
196 daniel-mar 149
                $x = explode('-', $weid);
197 daniel-mar 150
                if (count($x) < 2) return ''; // WEID root arc. Has no name
196 daniel-mar 151
                return $x[count($x)-2];
152
        }
153
 
154
        public function getWeidNotation($withAbbr=true) {
155
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
156
                if ($withAbbr) {
157
                        list($ns,$weid) = explode(':', $weid);
158
                        $weid_arcs = explode('-', $weid);
159
                        foreach ($weid_arcs as $i => &$weid) {
160
                                if ($i == count($weid_arcs)-1) {
161
                                        $weid = '<abbr title="weLuhn check digit">'.$weid.'</abbr>';
162
                                } else {
163
                                        $oid_arcs = explode('.',$this->oid);
164
                                        $weid_num = $oid_arcs[(count($oid_arcs)-1)-(count($weid_arcs)-1)+($i+1)];
165
                                        if ($weid_num != $weid) {
166
                                                $weid = '<abbr title="Numeric value: '.$weid_num.'">'.$weid.'</abbr>';
167
                                        }
168
                                }
169
                        }
170
                        $weid = '<abbr title="Root arc: 1.3.6.1.4.1.37553.8">' . $ns . '</abbr>:' . implode('-',$weid_arcs);
171
                }
172
                return $weid;
173
        }
174
 
175
        private function oidInformation() {
176
                $out = array();
177
                $out[] = "Dot notation: <code>" . $this->getDotNotation() . "</code>";
178
                $out[] = "ASN.1 notation: <code>{ " . $this->getAsn1Notation() . " }</code>";
179
                $out[] = "OID-IRI notation: <code>" . $this->getIriNotation() . "</code>";
197 daniel-mar 180
                if ($this->isWeid(true)) {
196 daniel-mar 181
                        $out[] = "WEID notation: <code>" . $this->getWeidNotation() . "</code>";
182
                }
183
                return '<p>'.implode('<br>',$out).'</p>';
184
        }
185
 
2 daniel-mar 186
        public function __clone() {
187
                return new self($this->oid);
188
        }
189
 
190
        public function appendArcs(String $arcs) {
191
                $out = clone $this;
5 daniel-mar 192
 
2 daniel-mar 193
                if ($out->isRoot()) {
194
                        $out->oid .= $arcs;
195
                } else {
196
                        $out->oid .= '.' . $arcs;
197
                }
5 daniel-mar 198
 
13 daniel-mar 199
                $bak_oid = $out->oid;
5 daniel-mar 200
                $out->oid = sanitizeOID($out->oid);
250 daniel-mar 201
                if ($out->oid === false) throw new OIDplusException("$bak_oid is not a valid OID!");
277 daniel-mar 202
 
261 daniel-mar 203
                if (strlen($out->oid) > OIDplus::baseConfig()->getValue('LIMITS_MAX_ID_LENGTH')-strlen('oid:')) {
204
                        throw new OIDplusException("The resulting OID '".$out->oid."' is too long (max allowed: ".(OIDplus::baseConfig()->getValue('LIMITS_MAX_ID_LENGTH')-strlen('oid:')).").");
247 daniel-mar 205
                }
277 daniel-mar 206
 
247 daniel-mar 207
                $depth = 0;
208
                foreach (explode('.',$out->oid) as $arc) {
261 daniel-mar 209
                        if (strlen($arc) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE')) {
210
                                throw new OIDplusException("Arc '$arc' is too long and therefore cannot be appended to the OID '".$this->oid."' (max allowed arc size is ".OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE').")");
247 daniel-mar 211
                        }
212
                        $depth++;
213
                }
261 daniel-mar 214
                if ($depth > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH')) {
215
                        throw new OIDplusException("OID '".$out->oid."' has too many arcs (current depth $depth, max depth ".OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH').")");
247 daniel-mar 216
                }
5 daniel-mar 217
 
2 daniel-mar 218
                return $out;
219
        }
220
 
221
        public function deltaDotNotation(OIDplusOid $parent) {
222
                if (!$parent->isRoot()) {
223
                        if (substr($this->oid, 0, strlen($parent->oid)+1) == $parent->oid.'.') {
224
                                return substr($this->oid, strlen($parent->oid)+1);
225
                        } else {
226
                                return false;
227
                        }
228
                } else {
229
                        return $this->oid;
230
                }
231
        }
232
 
233
        public function viewGetArcAsn1s(OIDplusOid $parent=null, $separator = ' | ') {
234
                $asn_ids = array();
235
 
236
                if (is_null($parent)) $parent = OIDplusOid::parse('oid:');
237
 
238
                $part = $this->deltaDotNotation($parent);
239
 
240
                if (strpos($part, '.') === false) {
261 daniel-mar 241
                        $res2 = OIDplus::db()->query("select name from ###asn1id where oid = ? order by lfd", array("oid:".$this->oid));
236 daniel-mar 242
                        while ($row2 = $res2->fetch_array()) {
2 daniel-mar 243
                                $asn_ids[] = $row2['name'].'('.$part.')';
244
                        }
245
                }
246
 
247
                if (count($asn_ids) == 0) $asn_ids = array($part);
239 daniel-mar 248
                return implode($separator, $asn_ids);
2 daniel-mar 249
        }
250
 
251
        public function getAsn1Notation($withAbbr=true) {
252
                $asn1_notation = '';
253
                $arcs = explode('.', $this->oid);
254
 
255
                foreach ($arcs as $arc) {
261 daniel-mar 256
                        $res = OIDplus::db()->query("select name, standardized from ###asn1id where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
2 daniel-mar 257
 
258
                        $names = array();
236 daniel-mar 259
                        while ($row = $res->fetch_array()) {
51 daniel-mar 260
                                $names[] = $row['name']."(".end($arcs).")";
261
                                if ($row['standardized']) {
262
                                        $names[] = $row['name'];
263
                                }
2 daniel-mar 264
                        }
265
 
52 daniel-mar 266
                        $numeric = array_pop($arcs);
2 daniel-mar 267
                        if (count($names) > 1) {
268
                                $first_name = array_shift($names);
52 daniel-mar 269
                                $abbr = 'Other identifiers:&#10;      '.implode('&#10;      ',$names);
2 daniel-mar 270
                                if ($withAbbr) {
51 daniel-mar 271
                                        $asn1_notation = '<abbr title="'.$abbr.'">'.$first_name.'</abbr> '.$asn1_notation;
2 daniel-mar 272
                                } else {
51 daniel-mar 273
                                        $asn1_notation = $first_name.' '.$asn1_notation;
2 daniel-mar 274
                                }
275
                        } else if (count($names) == 1) {
51 daniel-mar 276
                                $asn1_notation = array_shift($names).' '.$asn1_notation;
2 daniel-mar 277
                        } else {
52 daniel-mar 278
                                $asn1_notation = $numeric.' '.$asn1_notation;
2 daniel-mar 279
                        }
280
                }
281
 
282
                return $asn1_notation;
283
        }
284
 
285
        public function getIriNotation($withAbbr=true) {
286
                $iri_notation = '';
287
                $arcs = explode('.', $this->oid);
288
 
289
                foreach ($arcs as $arc) {
261 daniel-mar 290
                        $res = OIDplus::db()->query("select name, longarc from ###iri where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
2 daniel-mar 291
 
292
                        $is_longarc = false;
293
                        $names = array();
236 daniel-mar 294
                        while ($row = $res->fetch_array()) {
2 daniel-mar 295
                                $is_longarc = $row['longarc'];
296
                                $names[] = $row['name'];
51 daniel-mar 297
 
298
                                if ($is_longarc) {
299
                                        $names[] = 'Joint-ISO-ITU-T/'.$row['name']; // Long arcs can only be inside root OID 2
300
                                }
2 daniel-mar 301
                        }
302
 
303
                        $names[] = array_pop($arcs);
304
                        if (count($names) > 2) {
305
                                $first_name = array_shift($names);
52 daniel-mar 306
                                $numeric = array_pop($names);
307
                                $abbr = 'Other identifiers:&#10;      '.implode('&#10;      ',$names).'&#10;Numeric value: '.$numeric;
2 daniel-mar 308
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
309
                        } else if (count($names) > 1) {
310
                                $first_name = array_shift($names);
311
                                $abbr = 'Numeric value: '.array_shift($names);
312
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
313
                        } else if (count($names) == 1) {
314
                                $iri_notation = array_shift($names) . '/' . $iri_notation;
315
                        }
316
 
51 daniel-mar 317
                        if ($is_longarc) break; // we don't write /ITU-T/ at the beginning, when /ITU-T/xxx is a long arc
2 daniel-mar 318
                }
319
                $iri_notation = '/' . substr($iri_notation, 0, strlen($iri_notation)-1);
320
 
321
                return $iri_notation;
322
        }
323
 
324
        public function getDotNotation() {
325
                return $this->oid;
326
        }
327
 
13 daniel-mar 328
        public function isWellKnown() {
261 daniel-mar 329
                $res = OIDplus::db()->query("select oid from ###asn1id where oid = ? and well_known = ?", array("oid:".$this->oid,true));
236 daniel-mar 330
                if ($res->num_rows() > 0) return true;
13 daniel-mar 331
 
261 daniel-mar 332
                $res = OIDplus::db()->query("select oid from ###iri where oid = ? and well_known = ?", array("oid:".$this->oid,true));
236 daniel-mar 333
                if ($res->num_rows() > 0) return true;
13 daniel-mar 334
 
335
                return false;
336
        }
337
 
147 daniel-mar 338
        public function replaceAsn1Ids($demandedASN1s=array(), $simulate=false) {
13 daniel-mar 339
                if ($this->isWellKnown()) {
250 daniel-mar 340
                        throw new OIDplusException("OID ".$this->oid." is a 'well-known' OID. Its identifiers cannot be changed.");
13 daniel-mar 341
                }
342
 
2 daniel-mar 343
                // First do a few checks
344
                foreach ($demandedASN1s as &$asn1) {
345
                        $asn1 = trim($asn1);
346
 
261 daniel-mar 347
                        if (strlen($asn1) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN')) {
348
                                throw new OIDplusException("ASN.1 alphanumeric identifier '$asn1' is too long (max allowed length ".OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN').")");
247 daniel-mar 349
                        }
350
 
13 daniel-mar 351
                        // Validate identifier
250 daniel-mar 352
                        if (!oid_id_is_valid($asn1)) throw new OIDplusException("'$asn1' is not a valid ASN.1 identifier!");
13 daniel-mar 353
 
2 daniel-mar 354
                        // Check if the (real) parent has any conflict
201 daniel-mar 355
                        // Unlike IRI identifiers, ASN.1 identifiers may be used multiple times (not recommended), except if one of them is standardized
261 daniel-mar 356
                        $res = OIDplus::db()->query("select oid from ###asn1id where name = ? and standardized = ?", array($asn1,true));
236 daniel-mar 357
                        while ($row = $res->fetch_array()) {
2 daniel-mar 358
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
359
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
360
                                   ($check_oid !== $this->oid))                    // different OID
361
                                {
250 daniel-mar 362
                                        throw new OIDplusException("ASN.1 identifier '$asn1' is a standardized identifier belonging to OID ($check_oid)");
2 daniel-mar 363
                                }
364
                        }
365
                }
366
 
367
                // Now do the real replacement
147 daniel-mar 368
                if (!$simulate) {
261 daniel-mar 369
                        OIDplus::db()->query("delete from ###asn1id where oid = ?", array("oid:".$this->oid));
147 daniel-mar 370
                        foreach ($demandedASN1s as &$asn1) {
261 daniel-mar 371
                                OIDplus::db()->query("insert into ###asn1id (oid, name) values (?, ?)", array("oid:".$this->oid, $asn1));
2 daniel-mar 372
                        }
373
                }
374
        }
375
 
147 daniel-mar 376
        public function replaceIris($demandedIris=array(), $simulate=false) {
13 daniel-mar 377
                if ($this->isWellKnown()) {
250 daniel-mar 378
                        throw new OIDplusException("OID ".$this->oid." is a 'well-known' OID. Its identifiers cannot be changed.");
13 daniel-mar 379
                }
380
 
2 daniel-mar 381
                // First do a few checks
382
                foreach ($demandedIris as &$iri) {
383
                        $iri = trim($iri);
384
 
261 daniel-mar 385
                        if (strlen($iri) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN')) {
386
                                throw new OIDplusException("Unicode label '$iri' is too long (max allowed length ".OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN').")");
247 daniel-mar 387
                        }
388
 
13 daniel-mar 389
                        // Validate identifier
250 daniel-mar 390
                        if (!iri_arc_valid($iri, false)) throw new OIDplusException("'$iri' is not a valid IRI!");
13 daniel-mar 391
 
2 daniel-mar 392
                        // Check if the (real) parent has any conflict
261 daniel-mar 393
                        $res = OIDplus::db()->query("select oid from ###iri where name = ?", array($iri));
236 daniel-mar 394
                        while ($row = $res->fetch_array()) {
2 daniel-mar 395
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
396
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
397
                                   ($check_oid !== $this->oid))                    // different OID
398
                                {
250 daniel-mar 399
                                        throw new OIDplusException("IRI '$iri' is already used by another OID ($check_oid)");
2 daniel-mar 400
                                }
401
                        }
402
                }
403
 
404
                // Now do the real replacement
147 daniel-mar 405
                if (!$simulate) {
261 daniel-mar 406
                        OIDplus::db()->query("delete from ###iri where oid = ?", array("oid:".$this->oid));
147 daniel-mar 407
                        foreach ($demandedIris as &$iri) {
261 daniel-mar 408
                                OIDplus::db()->query("insert into ###iri (oid, name) values (?, ?)", array("oid:".$this->oid, $iri));
2 daniel-mar 409
                        }
410
                }
411
        }
12 daniel-mar 412
 
20 daniel-mar 413
        public function one_up() {
414
                return self::parse(self::ns().':'.oid_up($this->oid));
12 daniel-mar 415
        }
416
 
417
        public function distance($to) {
418
                if (!is_object($to)) $to = OIDplusObject::parse($to);
28 daniel-mar 419
                if (!($to instanceof $this)) return false;
12 daniel-mar 420
                return oid_distance($to->oid, $this->oid);
421
        }
192 daniel-mar 422
 
193 daniel-mar 423
        public function getAltIds() {
424
                if ($this->isRoot()) return array();
425
                $ids = parent::getAltIds();
426
                if ($uuid = oid_to_uuid($this->oid)) {
228 daniel-mar 427
                        $ids[] = new OIDplusAltId('guid', $uuid, 'GUID representation of this OID');
193 daniel-mar 428
                }
228 daniel-mar 429
                $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_OID, $this->oid), 'Namebased version 3 / MD5 UUID with namespace UUID_NAMEBASED_NS_OID');
430
                $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OID, $this->oid), 'Namebased version 5 / SHA1 UUID with namespace UUID_NAMEBASED_NS_OID');
193 daniel-mar 431
                return $ids;
192 daniel-mar 432
        }
2 daniel-mar 433
}