Subversion Repositories oidplus

Rev

Rev 1454 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1454 Rev 1461
1
<?php
1
<?php
2
 
2
 
3
/*
3
/*
4
 * OIDplus 2.0
4
 * OIDplus 2.0
5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
6
 *
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with 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
9
 * You may obtain a copy of the License at
10
 *
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
17
 * limitations under the License.
18
 */
18
 */
19
 
19
 
20
namespace ViaThinkSoft\OIDplus;
20
namespace ViaThinkSoft\OIDplus;
21
 
21
 
22
// phpcs:disable PSR1.Files.SideEffects
22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
24
// phpcs:enable PSR1.Files.SideEffects
25
 
25
 
26
abstract class OIDplusObject extends OIDplusBaseClass {
26
abstract class OIDplusObject extends OIDplusBaseClass {
27
 
27
 
28
        /**
28
        /**
29
         *
29
         *
30
         */
30
         */
31
        //const UUID_NAMEBASED_NS_OidPlusMisc = 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22';
31
        //const UUID_NAMEBASED_NS_OidPlusMisc = 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22';
32
 
32
 
33
        /**
33
        /**
34
         * Please overwrite this function!
34
         * Please overwrite this function!
35
         * @param string $node_id
35
         * @param string $node_id
36
         * @return OIDplusObject|null
36
         * @return OIDplusObject|null
37
         */
37
         */
38
        public static function parse(string $node_id)/*: ?OIDplusObject*/ {
38
        public static function parse(string $node_id)/*: ?OIDplusObject*/ {
39
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
39
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
40
                        try {
40
                        try {
41
                                $good = false;
41
                                $good = false;
42
                                if (get_parent_class($ot) == OIDplusObject::class) {
42
                                if (get_parent_class($ot) == OIDplusObject::class) {
43
                                        $reflector = new \ReflectionMethod($ot, 'parse');
43
                                        $reflector = new \ReflectionMethod($ot, 'parse');
44
                                        $isImplemented = ($reflector->getDeclaringClass()->getName() === $ot);
44
                                        $isImplemented = ($reflector->getDeclaringClass()->getName() === $ot);
45
                                        if ($isImplemented) { // avoid endless loop if parse is not overriden
45
                                        if ($isImplemented) { // avoid endless loop if parse is not overriden
46
                                                $good = true;
46
                                                $good = true;
47
                                        }
47
                                        }
48
                                }
48
                                }
49
                                // We need to do the workaround with "$good", otherwise PHPstan shows
49
                                // We need to do the workaround with "$good", otherwise PHPstan shows
50
                                // "Call to an undefined static method object::parse()"
50
                                // "Call to an undefined static method object::parse()"
51
                                if ($good && $obj = $ot::parse($node_id)) return $obj;
51
                                if ($good && $obj = $ot::parse($node_id)) return $obj;
52
                        } catch (\Exception $e) {}
52
                        } catch (\Exception $e) {}
53
                }
53
                }
54
                return null;
54
                return null;
55
        }
55
        }
56
 
56
 
57
        /**
57
        /**
58
         * @return OIDplusAltId[]
58
         * @return OIDplusAltId[]
59
         * @throws OIDplusException
59
         * @throws OIDplusException
60
         */
60
         */
61
        public function getAltIds(): array {
61
        public function getAltIds(): array {
62
                if ($this->isRoot()) return array();
62
                if ($this->isRoot()) return array();
63
 
63
 
64
                $ids = array();
64
                $ids = array();
65
 
65
 
66
                // Create Information Object OID/AID/UUID
66
                // Create Information Object OID/AID/UUID
67
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AID/OID/UUID (which will be decoded in the OID object type plugin)
67
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AID/OID/UUID (which will be decoded in the OID object type plugin)
68
                if (!str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
68
                if (!str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
69
                        // Creates an OIDplus-Hash-OID
69
                        // Creates an OIDplus-Hash-OID
70
                        // ... exclude OIDs, because an OID is already an OID
70
                        // ... exclude OIDs, because an OID is already an OID
71
                        if ($this->ns() != 'oid') {
71
                        if ($this->ns() != 'oid') {
72
                                $sid = OIDplus::getSystemId(true);
72
                                $sid = OIDplus::getSystemId(true);
73
                                if (!empty($sid)) {
73
                                if (!empty($sid)) {
74
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
74
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
75
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
75
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
76
                                        $oid = $sid . '.' . smallhash($hash_payload);
76
                                        $oid = $sid . '.' . smallhash($hash_payload);
77
                                        $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
77
                                        $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
78
                                }
78
                                }
79
                        }
79
                        }
80
 
80
 
81
                        // Make a OIDplus-UUID, but...
81
                        // Make a OIDplus-UUID, but...
82
                        // ... exclude GUID, because a GUID is already a GUID
82
                        // ... exclude GUID, because a GUID is already a GUID
83
                        // ... exclude OIDs which are 2.25, because these are basically GUIDs (but 2nd, 3rd, 4th, ... level is OK)
83
                        // ... exclude OIDs which are 2.25, because these are basically GUIDs (but 2nd, 3rd, 4th, ... level is OK)
84
                        // Previously, we excluded OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
84
                        // Previously, we excluded OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
85
                        if (($this->ns() != 'guid') && ($this->ns() != 'oid' || $this->one_up()->nodeId(true) != 'oid:2.25') /*&& ($this->ns() != 'oid')*/) {
85
                        if (($this->ns() != 'guid') && ($this->ns() != 'oid' || $this->one_up()->nodeId(true) != 'oid:2.25') /*&& ($this->ns() != 'oid')*/) {
86
                                // Obsolete custom namespace for UUIDv3 and UUIDv5:
86
                                // Obsolete custom namespace for UUIDv3 and UUIDv5:
87
                                //$ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
87
                                //$ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
88
                                //$ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
88
                                //$ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
89
                                // New custom UUIDv8:
89
                                // New custom UUIDv8:
90
                                $sysid = OIDplus::getSystemId(false);
90
                                $sysid = OIDplus::getSystemId(false);
91
                                $sysid_int = $sysid ? $sysid : 0;
91
                                $sysid_int = $sysid ? $sysid : 0;
92
                                $unix_ts = $this->getCreatedTime() ? strtotime($this->getCreatedTime()) : 0;
92
                                $unix_ts = $this->getCreatedTime() ? strtotime($this->getCreatedTime()) : 0;
93
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
93
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
94
                                $obj_name = $this->nodeId(false);
94
                                $obj_name = $this->nodeId(false);
95
                                $ids[] = new OIDplusAltId('guid',
95
                                $ids[] = new OIDplusAltId('guid',
96
                                        gen_uuid_v8(
96
                                        gen_uuid_v8(
97
                                                dechex($sysid_int),
97
                                                dechex($sysid_int),
98
                                                dechex((int)round($unix_ts/60/60/24)),
98
                                                dechex((int)round($unix_ts/60/60/24)),
99
                                                dechex(0),
99
                                                dechex(0),
100
                                                sha1($ns_oid), // Note: No 14bit collission between 1.3.6.1.4.1.37476.2.5.2.4.8.[0-185]
100
                                                sha1($ns_oid), // Note: No 14bit collission between 1.3.6.1.4.1.37476.2.5.2.4.8.[0-185]
101
                                                sha1($obj_name)
101
                                                sha1($obj_name)
102
                                        ),
102
                                        ),
103
                                        _L('OIDplus Information Object Custom UUID (RFC4122bis)'),
103
                                        _L('OIDplus Information Object Custom UUID (RFC4122bis)'),
104
                                        '',
104
                                        '',
105
                                        'https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md'
105
                                        'https://github.com/danielmarschall/oidplus/blob/master/doc/oidplus_custom_guid.md'
106
                                        );
106
                                        );
107
                        }
107
                        }
108
 
108
 
109
                        // Make a AID based on ViaThinkSoft schema
109
                        // Make a AID based on ViaThinkSoft schema
110
                        // ... exclude AIDs, because an AID is already an AID
110
                        // ... exclude AIDs, because an AID is already an AID
111
                        if ($this->ns() != 'aid') {
111
                        if ($this->ns() != 'aid') {
112
                                $sid = OIDplus::getSystemId(false);
112
                                $sid = OIDplus::getSystemId(false);
113
                                if ($sid !== false) {
113
                                if ($sid !== false) {
114
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
114
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
115
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
115
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
116
                                        $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
116
                                        $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
117
                                        $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
117
                                        $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
118
                                        $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
118
                                        $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
119
                                        $ids[] = new OIDplusAltId('aid', $aid,
119
                                        $ids[] = new OIDplusAltId('aid', $aid,
120
                                                _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'),
120
                                                _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'),
121
                                                ' ('._L('No PIX allowed').')',
121
                                                ' ('._L('No PIX allowed').')',
122
                                                'https://hosted.oidplus.com/viathinksoft/?goto=aid%3AD276000186B20005');
122
                                                'https://hosted.oidplus.com/viathinksoft/?goto=aid%3AD276000186B20005');
123
                                }
123
                                }
124
                        }
124
                        }
125
 
125
 
126
                        // Make a MAC based on AAI (not 100% worldwide unique!)
126
                        // Make a MAC based on AAI (not 100% worldwide unique!)
127
                        // ... exclude MACs, because an MAC is already a MAC
127
                        // ... exclude MACs, because an MAC is already a MAC
128
                        if ($this->ns() != 'mac') {
128
                        if ($this->ns() != 'mac') {
129
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
129
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
130
                                $obj_name = $this->nodeId(false);
130
                                $obj_name = $this->nodeId(false);
131
                                $mac = strtoupper(substr(sha1($ns_oid.':'.$obj_name),-12));
131
                                $mac = strtoupper(substr(sha1($ns_oid.':'.$obj_name),-12));
132
                                $mac = rtrim(chunk_split($mac, 2, '-'),'-');
132
                                $mac = rtrim(chunk_split($mac, 2, '-'),'-');
133
 
133
 
134
                                $mac[1] = '2'; // 2=AAI Unicast
134
                                $mac[1] = '2'; // 2=AAI Unicast
135
                                $ids[] = new OIDplusAltId('mac', $mac, _L('OIDplus Information Object MAC address, Unicast (AAI)'));
135
                                $ids[] = new OIDplusAltId('mac', $mac, _L('OIDplus Information Object MAC address, Unicast (AAI)'));
136
 
136
 
137
                                $mac[1] = '3'; // 3=AAI Multicast
137
                                $mac[1] = '3'; // 3=AAI Multicast
138
                                $ids[] = new OIDplusAltId('mac', $mac, _L('OIDplus Information Object MAC address, Multicast (AAI)'));
138
                                $ids[] = new OIDplusAltId('mac', $mac, _L('OIDplus Information Object MAC address, Multicast (AAI)'));
139
                        }
139
                        }
140
 
140
 
141
                        // Make a DN based on DN
141
                        // Make a DN based on DN
142
                        // ... exclude DN, because an DN is already a DN
142
                        // ... exclude DN, because an DN is already a DN
143
                        if ($this->ns() != 'x500dn') {
143
                        if ($this->ns() != 'x500dn') {
144
                                $sysid = OIDplus::getSystemId(false);
144
                                $sysid = OIDplus::getSystemId(false);
145
                                if ($sysid !== false) {
145
                                if ($sysid !== false) {
146
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
146
                                        $ns_oid = $this->getPlugin()->getManifest()->getOid();
147
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
147
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
148
                                        $objhash = smallhash($hash_payload);
148
                                        $objhash = smallhash($hash_payload);
149
 
149
 
150
                                        $oid_at_sysid = '1.3.6.1.4.1.37476.2.5.2.9.4.1';
150
                                        $oid_at_sysid = '1.3.6.1.4.1.37476.2.5.2.9.4.1';
151
                                        $oid_at_objhash = '1.3.6.1.4.1.37476.2.5.2.9.4.2';
151
                                        $oid_at_objhash = '1.3.6.1.4.1.37476.2.5.2.9.4.2';
152
                                        $dn = '/dc=com/dc=example/cn=oidplus/'.$oid_at_sysid.'='.$sysid.'/'.$oid_at_objhash.'='.$objhash;
152
                                        $dn = '/dc=com/dc=example/cn=oidplus/'.$oid_at_sysid.'='.$sysid.'/'.$oid_at_objhash.'='.$objhash;
153
 
153
 
154
                                        $ids[] = new OIDplusAltId('x500dn', $dn, _L('OIDplus Information Object X.500 DN'));
154
                                        $ids[] = new OIDplusAltId('x500dn', $dn, _L('OIDplus Information Object X.500 DN'));
155
                                }
155
                                }
156
                        }
156
                        }
157
                }
157
                }
158
 
158
 
159
                return $ids;
159
                return $ids;
160
        }
160
        }
161
 
161
 
162
        /**
162
        /**
163
         * @return string
163
         * @return string
164
         */
164
         */
165
        public abstract static function objectTypeTitle(): string;
165
        public abstract static function objectTypeTitle(): string;
166
 
166
 
167
        /**
167
        /**
168
         * @return string
168
         * @return string
169
         */
169
         */
170
        public abstract static function objectTypeTitleShort(): string;
170
        public abstract static function objectTypeTitleShort(): string;
171
 
171
 
172
        /**
172
        /**
173
         * @return OIDplusObjectTypePlugin|null
173
         * @return OIDplusObjectTypePlugin|null
174
         */
174
         */
175
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
175
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
176
                $plugins = OIDplus::getObjectTypePlugins();
176
                $plugins = OIDplus::getObjectTypePlugins();
177
                foreach ($plugins as $plugin) {
177
                foreach ($plugins as $plugin) {
178
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
178
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
179
                                return $plugin;
179
                                return $plugin;
180
                        }
180
                        }
181
                }
181
                }
182
                return null;
182
                return null;
183
        }
183
        }
184
 
184
 
185
        /**
185
        /**
186
         * @return string
186
         * @return string
187
         */
187
         */
188
        public abstract static function ns(): string;
188
        public abstract static function ns(): string;
189
 
189
 
190
        /**
190
        /**
191
         * @return string
191
         * @return string
192
         */
192
         */
193
        public abstract static function root(): string;
193
        public abstract static function root(): string;
194
 
194
 
195
        /**
195
        /**
196
         * @return bool
196
         * @return bool
197
         */
197
         */
198
        public abstract function isRoot(): bool;
198
        public abstract function isRoot(): bool;
199
 
199
 
200
        /**
200
        /**
201
         * @param bool $with_ns
201
         * @param bool $with_ns
202
         * @return string
202
         * @return string
203
         */
203
         */
204
        public abstract function nodeId(bool $with_ns=true): string;
204
        public abstract function nodeId(bool $with_ns=true): string;
205
 
205
 
206
        /**
206
        /**
207
         * @param string $str
207
         * @param string $str
208
         * @return string mixed
208
         * @return string mixed
209
         * @throws OIDplusException
209
         * @throws OIDplusException
210
         */
210
         */
211
        public abstract function addString(string $str): string;
211
        public abstract function addString(string $str): string;
212
 
212
 
213
        /**
213
        /**
214
         * @param OIDplusObject $parent
214
         * @param OIDplusObject $parent
215
         * @return string
215
         * @return string
216
         */
216
         */
217
        public abstract function crudShowId(OIDplusObject $parent): string;
217
        public abstract function crudShowId(OIDplusObject $parent): string;
218
 
218
 
219
        /**
219
        /**
220
         * @return string
220
         * @return string
221
         */
221
         */
222
        public function crudInsertPrefix(): string {
222
        public function crudInsertPrefix(): string {
223
                return '';
223
                return '';
224
        }
224
        }
225
 
225
 
226
        /**
226
        /**
227
         * @return string
227
         * @return string
228
         */
228
         */
229
        public function crudInsertSuffix(): string {
229
        public function crudInsertSuffix(): string {
230
                return '';
230
                return '';
231
        }
231
        }
232
 
232
 
233
        /**
233
        /**
234
         * @param OIDplusObject|null $parent
234
         * @param OIDplusObject|null $parent
235
         * @return string
235
         * @return string
236
         */
236
         */
237
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
237
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
238
 
238
 
239
        /**
239
        /**
240
         * @return string
240
         * @return string
241
         */
241
         */
242
        public abstract function defaultTitle(): string;
242
        public abstract function defaultTitle(): string;
243
 
243
 
244
        /**
244
        /**
245
         * @return bool
245
         * @return bool
246
         */
246
         */
247
        public abstract function isLeafNode(): bool;
247
        public abstract function isLeafNode(): bool;
248
 
248
 
249
        /**
249
        /**
250
         * @param string $title
250
         * @param string $title
251
         * @param string $content
251
         * @param string $content
252
         * @param string $icon
252
         * @param string $icon
253
         * @return void
253
         * @return void
254
         */
254
         */
255
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
255
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
256
 
256
 
257
        /**
257
        /**
258
         * @param OIDplusRA|string|null $ra
258
         * @param OIDplusRA|string|null $ra
259
         * @return array
259
         * @return array
260
         * @throws OIDplusConfigInitializationException
260
         * @throws OIDplusConfigInitializationException
261
         * @throws OIDplusException
261
         * @throws OIDplusException
262
         */
262
         */
263
        public static function getRaRoots($ra=null) : array{
263
        public static function getRaRoots($ra=null) : array{
264
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
264
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
265
 
265
 
266
                $out = array();
266
                $out = array();
267
 
267
 
268
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
268
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
269
                        if (!$ra) {
269
                        if (!$ra) {
270
                                $res = OIDplus::db()->query("select oChild.id as child_id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
270
                                $res = OIDplus::db()->query("select oChild.id as child_id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
271
                                                            "left join ###objects as oParent on oChild.parent = oParent.id");
271
                                                            "left join ###objects as oParent on oChild.parent = oParent.id");
272
                                $res->naturalSortByField('child_id');
272
                                $res->naturalSortByField('child_id');
273
                                while ($row = $res->fetch_array()) {
273
                                while ($row = $res->fetch_array()) {
274
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
274
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
275
                                                $x = self::parse($row['child_id']); // can be NULL if namespace was disabled
275
                                                $x = self::parse($row['child_id']); // can be NULL if namespace was disabled
276
                                                if ($x) $out[] = $x;
276
                                                if ($x) $out[] = $x;
277
                                        }
277
                                        }
278
                                }
278
                                }
279
                        } else {
279
                        } else {
280
                                $res = OIDplus::db()->query("select oChild.id as child_id from ###objects as oChild ".
280
                                $res = OIDplus::db()->query("select oChild.id as child_id from ###objects as oChild ".
281
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
281
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
282
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
282
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
283
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
283
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
284
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ",
284
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ",
285
                                                            array($ra, $ra, $ra));
285
                                                            array($ra, $ra, $ra));
286
                                $res->naturalSortByField('child_id');
286
                                $res->naturalSortByField('child_id');
287
                                while ($row = $res->fetch_array()) {
287
                                while ($row = $res->fetch_array()) {
288
                                        $x = self::parse($row['child_id']); // can be NULL if namespace was disabled
288
                                        $x = self::parse($row['child_id']); // can be NULL if namespace was disabled
289
                                        if ($x) $out[] = $x;
289
                                        if ($x) $out[] = $x;
290
                                }
290
                                }
291
                        }
291
                        }
292
                } else {
292
                } else {
293
                        if (!$ra) {
293
                        if (!$ra) {
294
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
294
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
295
                                if (count($ra_mails_to_check) == 0) return $out;
295
                                if (count($ra_mails_to_check) == 0) return $out;
296
                        } else {
296
                        } else {
297
                                $ra_mails_to_check = array($ra);
297
                                $ra_mails_to_check = array($ra);
298
                        }
298
                        }
299
 
299
 
300
                        self::buildObjectInformationCache();
300
                        self::buildObjectInformationCache();
301
 
301
 
302
                        foreach ($ra_mails_to_check as $check_ra_mail) {
302
                        foreach ($ra_mails_to_check as $check_ra_mail) {
303
                                $out_part = array();
303
                                $out_part = array();
304
 
304
 
305
                                foreach (self::$object_info_cache as $id => $cacheitem) {
305
                                foreach (self::$object_info_cache as $id => $cacheitem) {
306
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
306
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
307
                                                $parent = $cacheitem[self::CACHE_PARENT];
307
                                                $parent = $cacheitem[self::CACHE_PARENT];
308
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
308
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
309
                                                        $out_part[] = $id;
309
                                                        $out_part[] = $id;
310
                                                }
310
                                                }
311
                                        }
311
                                        }
312
                                }
312
                                }
313
 
313
 
314
                                natsort($out_part);
314
                                natsort($out_part);
315
 
315
 
316
                                foreach ($out_part as $id) {
316
                                foreach ($out_part as $id) {
317
                                        $obj = self::parse($id);
317
                                        $obj = self::parse($id);
318
                                        if ($obj) $out[] = $obj;
318
                                        if ($obj) $out[] = $obj;
319
                                }
319
                                }
320
                        }
320
                        }
321
                }
321
                }
322
 
322
 
323
                return $out;
323
                return $out;
324
        }
324
        }
325
 
325
 
326
        /**
326
        /**
327
         * @return array
327
         * @return array
328
         * @throws OIDplusException
328
         * @throws OIDplusException
329
         */
329
         */
330
        public static function getAllNonConfidential(): array {
330
        public static function getAllNonConfidential(): array {
331
                $out = array();
331
                $out = array();
332
 
332
 
333
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
333
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
334
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ?", array(false));
334
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ?", array(false));
335
                        $res->naturalSortByField('id');
335
                        $res->naturalSortByField('id');
336
                        while ($row = $res->fetch_array()) {
336
                        while ($row = $res->fetch_array()) {
337
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
337
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
338
                                if ($obj && (!$obj->isConfidential())) {
338
                                if ($obj && (!$obj->isConfidential())) {
339
                                        $out[] = $row['id'];
339
                                        $out[] = $row['id'];
340
                                }
340
                                }
341
                        }
341
                        }
342
                } else {
342
                } else {
343
                        self::buildObjectInformationCache();
343
                        self::buildObjectInformationCache();
344
 
344
 
345
                        foreach (self::$object_info_cache as $id => $cacheitem) {
345
                        foreach (self::$object_info_cache as $id => $cacheitem) {
346
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
346
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
347
                                if (!$confidential) {
347
                                if (!$confidential) {
348
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
348
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
349
                                        if ($obj && (!$obj->isConfidential())) {
349
                                        if ($obj && (!$obj->isConfidential())) {
350
                                                $out[] = $id;
350
                                                $out[] = $id;
351
                                        }
351
                                        }
352
                                }
352
                                }
353
                        }
353
                        }
354
                }
354
                }
355
 
355
 
356
                return $out;
356
                return $out;
357
        }
357
        }
358
 
358
 
359
        /**
359
        /**
360
         * @return bool
360
         * @return bool
361
         * @throws OIDplusException
361
         * @throws OIDplusException
362
         */
362
         */
363
        public function isConfidential(): bool {
363
        public function isConfidential(): bool {
364
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
364
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
365
                        //static $confidential_cache = array();
365
                        //static $confidential_cache = array();
366
                        $curid = $this->nodeId();
366
                        $curid = $this->nodeId();
367
                        //$orig_curid = $curid;
367
                        //$orig_curid = $curid;
368
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
368
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
369
                        // Recursively search for the confidential flag in the parents
369
                        // Recursively search for the confidential flag in the parents
370
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
370
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
371
                                $row = $res->fetch_array();
371
                                $row = $res->fetch_array();
372
                                if ($row['confidential']) {
372
                                if ($row['confidential']) {
373
                                        //$confidential_cache[$curid] = true;
373
                                        //$confidential_cache[$curid] = true;
374
                                        //$confidential_cache[$orig_curid] = true;
374
                                        //$confidential_cache[$orig_curid] = true;
375
                                        return true;
375
                                        return true;
376
                                } else {
376
                                } else {
377
                                        //$confidential_cache[$curid] = false;
377
                                        //$confidential_cache[$curid] = false;
378
                                }
378
                                }
379
                                $curid = $row['parent'];
379
                                $curid = $row['parent'];
380
                                //if (isset($confidential_cache[$curid])) {
380
                                //if (isset($confidential_cache[$curid])) {
381
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
381
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
382
                                        //return $confidential_cache[$curid];
382
                                        //return $confidential_cache[$curid];
383
                                //}
383
                                //}
384
                        }
384
                        }
385
 
385
 
386
                        //$confidential_cache[$orig_curid] = false;
386
                        //$confidential_cache[$orig_curid] = false;
387
                        return false;
387
                        return false;
388
                } else {
388
                } else {
389
                        self::buildObjectInformationCache();
389
                        self::buildObjectInformationCache();
390
 
390
 
391
                        $curid = $this->nodeId();
391
                        $curid = $this->nodeId();
392
                        // Recursively search for the confidential flag in the parents
392
                        // Recursively search for the confidential flag in the parents
393
                        while (isset(self::$object_info_cache[$curid])) {
393
                        while (isset(self::$object_info_cache[$curid])) {
394
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
394
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
395
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
395
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
396
                        }
396
                        }
397
                        return false;
397
                        return false;
398
                }
398
                }
399
        }
399
        }
400
 
400
 
401
        /**
401
        /**
402
         * @param OIDplusObject $obj
402
         * @param OIDplusObject $obj
403
         * @return bool
403
         * @return bool
404
         * @throws OIDplusException
404
         * @throws OIDplusException
405
         */
405
         */
406
        public function isChildOf(OIDplusObject $obj): bool {
406
        public function isChildOf(OIDplusObject $obj): bool {
407
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
407
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
408
                        $curid = $this->nodeId();
408
                        $curid = $this->nodeId();
409
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
409
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
410
                                $row = $res->fetch_array();
410
                                $row = $res->fetch_array();
411
                                if ($curid == $obj->nodeId()) return true;
411
                                if ($curid == $obj->nodeId()) return true;
412
                                $curid = $row['parent'];
412
                                $curid = $row['parent'];
413
                        }
413
                        }
414
                        return false;
414
                        return false;
415
                } else {
415
                } else {
416
                        self::buildObjectInformationCache();
416
                        self::buildObjectInformationCache();
417
 
417
 
418
                        $curid = $this->nodeId();
418
                        $curid = $this->nodeId();
419
                        while (isset(self::$object_info_cache[$curid])) {
419
                        while (isset(self::$object_info_cache[$curid])) {
420
                                if ($curid == $obj->nodeId()) return true;
420
                                if ($curid == $obj->nodeId()) return true;
421
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
421
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
422
                        }
422
                        }
423
                        return false;
423
                        return false;
424
                }
424
                }
425
        }
425
        }
426
 
426
 
427
        /**
427
        /**
428
         * @return array
428
         * @return array
429
         * @throws OIDplusException
429
         * @throws OIDplusException
430
         */
430
         */
431
        public function getChildren(): array {
431
        public function getChildren(): array {
432
                $out = array();
432
                $out = array();
433
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
433
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
434
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
434
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
435
                        while ($row = $res->fetch_array()) {
435
                        while ($row = $res->fetch_array()) {
436
                                $obj = self::parse($row['id']);
436
                                $obj = self::parse($row['id']);
437
                                if (!$obj) continue;
437
                                if (!$obj) continue;
438
                                $out[] = $obj;
438
                                $out[] = $obj;
439
                        }
439
                        }
440
                } else {
440
                } else {
441
                        self::buildObjectInformationCache();
441
                        self::buildObjectInformationCache();
442
 
442
 
443
                        foreach (self::$object_info_cache as $id => $cacheitem) {
443
                        foreach (self::$object_info_cache as $id => $cacheitem) {
444
                                $parent = $cacheitem[self::CACHE_PARENT];
444
                                $parent = $cacheitem[self::CACHE_PARENT];
445
                                if ($parent == $this->nodeId()) {
445
                                if ($parent == $this->nodeId()) {
446
                                        $obj = self::parse($id);
446
                                        $obj = self::parse($id);
447
                                        if (!$obj) continue;
447
                                        if (!$obj) continue;
448
                                        $out[] = $obj;
448
                                        $out[] = $obj;
449
                                }
449
                                }
450
                        }
450
                        }
451
                }
451
                }
452
                return $out;
452
                return $out;
453
        }
453
        }
454
 
454
 
455
        /**
455
        /**
456
         * @return OIDplusRA|null
456
         * @return OIDplusRA|null
457
         * @throws OIDplusException
457
         * @throws OIDplusException
458
         */
458
         */
459
        public function getRa()/*: ?OIDplusRA*/ {
459
        public function getRa()/*: ?OIDplusRA*/ {
460
                $ra = $this->getRaMail();
460
                $ra = $this->getRaMail();
461
                return $ra ? new OIDplusRA($ra) : null;
461
                return $ra ? new OIDplusRA($ra) : null;
462
        }
462
        }
463
 
463
 
464
        /**
464
        /**
465
         * @param OIDplusRA|string|null $ra
465
         * @param OIDplusRA|string|null $ra
466
         * @return bool
466
         * @return bool
467
         * @throws OIDplusConfigInitializationException
467
         * @throws OIDplusConfigInitializationException
468
         * @throws OIDplusException
468
         * @throws OIDplusException
469
         */
469
         */
470
        public function userHasReadRights($ra=null): bool {
470
        public function userHasReadRights($ra=null): bool {
471
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
471
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
472
 
472
 
473
                // If it is not confidential, everybody can read/see it.
473
                // If it is not confidential, everybody can read/see it.
474
                // Note: This also checks if superior OIDs are confidential.
474
                // Note: This also checks if superior OIDs are confidential.
475
                if (!$this->isConfidential()) return true;
475
                if (!$this->isConfidential()) return true;
476
 
476
 
477
                if (!$ra) {
477
                if (!$ra) {
478
                        // Admin may do everything
478
                        // Admin may do everything
479
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
479
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
480
 
480
 
481
                        // If the RA is logged in, then they can see the OID.
481
                        // If the RA is logged in, then they can see the OID.
482
                        $ownRa = $this->getRaMail();
482
                        $ownRa = $this->getRaMail();
483
                        if ($ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa)) return true;
483
                        if ($ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa)) return true;
484
                } else {
484
                } else {
485
                        // If this OID belongs to the requested RA, then they may see it.
485
                        // If this OID belongs to the requested RA, then they may see it.
486
                        if ($this->getRaMail() == $ra) return true;
486
                        if ($this->getRaMail() == $ra) return true;
487
                }
487
                }
488
 
488
 
489
                // If someone has rights to an object below our confidential node,
489
                // If someone has rights to an object below our confidential node,
490
                // we let him see the confidential node,
490
                // we let him see the confidential node,
491
                // Otherwise he could not browse through to his own node.
491
                // Otherwise he could not browse through to his own node.
492
                $roots = $this->getRaRoots($ra);
492
                $roots = $this->getRaRoots($ra);
493
                foreach ($roots as $root) {
493
                foreach ($roots as $root) {
494
                        if ($root->isChildOf($this)) return true;
494
                        if ($root->isChildOf($this)) return true;
495
                }
495
                }
496
 
496
 
497
                return false;
497
                return false;
498
        }
498
        }
499
 
499
 
500
        /**
500
        /**
501
         * @param array|null $row
501
         * @param array|null $row
502
         * @return string|null
502
         * @return string|null
503
         * @throws OIDplusException
503
         * @throws OIDplusException
504
         */
504
         */
505
        public function getIcon(array $row=null) {
505
        public function getIcon(array $row=null) {
506
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
506
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
507
 
507
 
508
                if (is_null($row)) {
508
                if (is_null($row)) {
509
                        $ra_email = $this->getRaMail();
509
                        $ra_email = $this->getRaMail();
510
                } else {
510
                } else {
511
                        $ra_email = $row['ra_email'];
511
                        $ra_email = $row['ra_email'];
512
                }
512
                }
513
 
513
 
514
                // $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
514
                // $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
515
                // if (count($dirs) == 0) return null; // default icon (folder)
515
                // if (count($dirs) == 0) return null; // default icon (folder)
516
                // $dir = substr($dirs[0], strlen(OIDplus::localpath()));
516
                // $dir = substr($dirs[0], strlen(OIDplus::localpath()));
517
                $reflection = new \ReflectionClass($this);
517
                $reflection = new \ReflectionClass($this);
518
                $dir = dirname($reflection->getFilename());
518
                $dir = dirname($reflection->getFilename());
519
                $dir = substr($dir, strlen(OIDplus::localpath()));
519
                $dir = substr($dir, strlen(OIDplus::localpath()));
520
                $dir = str_replace('\\', '/', $dir);
520
                $dir = str_replace('\\', '/', $dir);
521
 
521
 
522
                if ($this->isRoot()) {
522
                if ($this->isRoot()) {
523
                        $icon = $dir . '/' . $this::treeIconFilename('root');
523
                        $icon = $dir . '/' . $this::treeIconFilename('root');
524
                } else {
524
                } else {
525
                        // We use $this:: instead of self:: , because we want to call the overridden methods
525
                        // We use $this:: instead of self:: , because we want to call the overridden methods
526
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
526
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
527
                                if ($this->isLeafNode()) {
527
                                if ($this->isLeafNode()) {
528
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
528
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
529
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
529
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
530
                                } else {
530
                                } else {
531
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
531
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
532
                                }
532
                                }
533
                        } else {
533
                        } else {
534
                                if ($this->isLeafNode()) {
534
                                if ($this->isLeafNode()) {
535
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
535
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
536
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
536
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
537
                                } else {
537
                                } else {
538
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
538
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
539
                                }
539
                                }
540
                        }
540
                        }
541
                }
541
                }
542
 
542
 
543
                if (!file_exists($icon)) return null; // default icon (folder)
543
                if (!file_exists($icon)) return null; // default icon (folder)
544
 
544
 
545
                return $icon;
545
                return $icon;
546
        }
546
        }
547
 
547
 
548
        /**
548
        /**
549
         * @param string $id
549
         * @param string $id
550
         * @return bool
550
         * @return bool
551
         * @throws OIDplusException
551
         * @throws OIDplusException
552
         */
552
         */
553
        public static function exists(string $id): bool {
553
        public static function exists(string $id): bool {
554
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
554
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
555
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
555
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
556
                        return $res->any();
556
                        return $res->any();
557
                } else {
557
                } else {
558
                        self::buildObjectInformationCache();
558
                        self::buildObjectInformationCache();
559
                        return isset(self::$object_info_cache[$id]);
559
                        return isset(self::$object_info_cache[$id]);
560
                }
560
                }
561
        }
561
        }
562
 
562
 
563
        /**
563
        /**
564
         * Get parent gives the next possible parent which is EXISTING in OIDplus
564
         * Get parent gives the next possible parent which is EXISTING in OIDplus
565
         * It does not give the immediate parent
565
         * It does not give the immediate parent
566
         * @return OIDplusObject|null
566
         * @return OIDplusObject|null
567
         * @throws OIDplusException
567
         * @throws OIDplusException
568
         */
568
         */
569
        public function getParent()/*: ?OIDplusObject*/ {
569
        public function getParent()/*: ?OIDplusObject*/ {
570
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
570
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
571
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
571
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
572
                        if ($res->any()) {
572
                        if ($res->any()) {
573
                                $row = $res->fetch_array();
573
                                $row = $res->fetch_array();
574
                                $parent = $row['parent'];
574
                                $parent = $row['parent'];
575
                                $obj = OIDplusObject::parse($parent);
575
                                $obj = OIDplusObject::parse($parent);
576
                                if ($obj) return $obj;
576
                                if ($obj) return $obj;
577
                        }
577
                        }
578
                } else {
578
                } else {
579
                        self::buildObjectInformationCache();
579
                        self::buildObjectInformationCache();
580
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
580
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
581
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
581
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
582
                                $obj = OIDplusObject::parse($parent);
582
                                $obj = OIDplusObject::parse($parent);
583
                                if ($obj) return $obj;
583
                                if ($obj) return $obj;
584
                        }
584
                        }
585
                }
585
                }
586
 
586
 
587
                // If this OID does not exist, the SQL query "select parent from ..." does not work. So we try to find the next possible parent using one_up()
587
                // If this OID does not exist, the SQL query "select parent from ..." does not work. So we try to find the next possible parent using one_up()
588
                $cur = $this->one_up();
588
                $cur = $this->one_up();
589
                if (!$cur) return null;
589
                if (!$cur) return null;
590
                do {
590
                do {
591
                        // findFitting() checks if that OID exists
591
                        // findFitting() checks if that OID exists
592
                        if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
592
                        if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
593
 
593
 
594
                        $prev = $cur;
594
                        $prev = $cur;
595
                        $cur = $cur->one_up();
595
                        $cur = $cur->one_up();
596
                        if (!$cur) return null;
596
                        if (!$cur) return null;
597
                } while ($prev->nodeId() !== $cur->nodeId());
597
                } while ($prev->nodeId() !== $cur->nodeId());
598
 
598
 
599
                return null;
599
                return null;
600
        }
600
        }
601
 
601
 
602
        /**
602
        /**
603
         * @return string|null
603
         * @return string|null
604
         * @throws OIDplusException
604
         * @throws OIDplusException
605
         */
605
         */
606
        public function getRaMail() {
606
        public function getRaMail() {
607
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
607
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
608
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
608
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
609
                        if (!$res->any()) return null;
609
                        if (!$res->any()) return null;
610
                        $row = $res->fetch_array();
610
                        $row = $res->fetch_array();
611
                        return $row['ra_email'];
611
                        return $row['ra_email'];
612
                } else {
612
                } else {
613
                        self::buildObjectInformationCache();
613
                        self::buildObjectInformationCache();
614
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
614
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
615
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
615
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
616
                        }
616
                        }
617
                        return null;
617
                        return null;
618
                }
618
                }
619
        }
619
        }
620
 
620
 
621
        /**
621
        /**
622
         * @return string|null
622
         * @return string|null
623
         * @throws OIDplusException
623
         * @throws OIDplusException
624
         */
624
         */
625
        public function getTitle() {
625
        public function getTitle() {
626
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
626
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
627
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
627
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
628
                        if (!$res->any()) return null;
628
                        if (!$res->any()) return null;
629
                        $row = $res->fetch_array();
629
                        $row = $res->fetch_array();
630
                        return $row['title'];
630
                        return $row['title'];
631
                } else {
631
                } else {
632
                        self::buildObjectInformationCache();
632
                        self::buildObjectInformationCache();
633
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
633
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
634
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
634
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
635
                        }
635
                        }
636
                        return null;
636
                        return null;
637
                }
637
                }
638
        }
638
        }
639
 
639
 
640
        /**
640
        /**
641
         * @return string|null
641
         * @return string|null
642
         * @throws OIDplusException
642
         * @throws OIDplusException
643
         */
643
         */
644
        public function getDescription() {
644
        public function getDescription() {
645
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
645
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
646
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
646
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
647
                        if (!$res->any()) return null;
647
                        if (!$res->any()) return null;
648
                        $row = $res->fetch_array();
648
                        $row = $res->fetch_array();
649
                        return $row['description'];
649
                        return $row['description'];
650
                } else {
650
                } else {
651
                        self::buildObjectInformationCache();
651
                        self::buildObjectInformationCache();
652
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
652
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
653
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
653
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
654
                        }
654
                        }
655
                        return null;
655
                        return null;
656
                }
656
                }
657
        }
657
        }
658
 
658
 
659
        /**
659
        /**
660
         * @return string|null
660
         * @return string|null
661
         * @throws OIDplusException
661
         * @throws OIDplusException
662
         */
662
         */
663
        public function getComment() {
663
        public function getComment() {
664
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
664
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
665
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
665
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
666
                        if (!$res->any()) return null;
666
                        if (!$res->any()) return null;
667
                        $row = $res->fetch_array();
667
                        $row = $res->fetch_array();
668
                        return $row['comment'];
668
                        return $row['comment'];
669
                } else {
669
                } else {
670
                        self::buildObjectInformationCache();
670
                        self::buildObjectInformationCache();
671
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
671
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
672
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
672
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
673
                        }
673
                        }
674
                        return null;
674
                        return null;
675
                }
675
                }
676
        }
676
        }
677
 
677
 
678
        /**
678
        /**
679
         * @return string|null
679
         * @return string|null
680
         * @throws OIDplusException
680
         * @throws OIDplusException
681
         */
681
         */
682
        public function getCreatedTime() {
682
        public function getCreatedTime() {
683
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
683
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
684
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
684
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
685
                        if (!$res->any()) return null;
685
                        if (!$res->any()) return null;
686
                        $row = $res->fetch_array();
686
                        $row = $res->fetch_array();
687
                        return $row['created'];
687
                        return $row['created'];
688
                } else {
688
                } else {
689
                        self::buildObjectInformationCache();
689
                        self::buildObjectInformationCache();
690
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
690
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
691
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
691
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
692
                        }
692
                        }
693
                        return null;
693
                        return null;
694
                }
694
                }
695
        }
695
        }
696
 
696
 
697
        /**
697
        /**
698
         * @return string|null
698
         * @return string|null
699
         * @throws OIDplusException
699
         * @throws OIDplusException
700
         */
700
         */
701
        public function getUpdatedTime() {
701
        public function getUpdatedTime() {
702
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
702
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
703
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
703
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
704
                        if (!$res->any()) return null;
704
                        if (!$res->any()) return null;
705
                        $row = $res->fetch_array();
705
                        $row = $res->fetch_array();
706
                        return $row['updated'];
706
                        return $row['updated'];
707
                } else {
707
                } else {
708
                        self::buildObjectInformationCache();
708
                        self::buildObjectInformationCache();
709
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
709
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
710
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
710
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
711
                        }
711
                        }
712
                        return null;
712
                        return null;
713
                }
713
                }
714
        }
714
        }
715
 
715
 
716
        /**
716
        /**
717
         * @param OIDplusRA|string|null $ra
717
         * @param OIDplusRA|string|null $ra
718
         * @return bool
718
         * @return bool
719
         * @throws OIDplusException
719
         * @throws OIDplusException
720
         */
720
         */
721
        public function userHasParentalWriteRights($ra=null): bool {
721
        public function userHasParentalWriteRights($ra=null): bool {
722
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
722
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
723
 
723
 
724
                if (!$ra) {
724
                if (!$ra) {
725
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
725
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
726
                }
726
                }
727
 
727
 
728
                $objParent = $this->getParent();
728
                $objParent = $this->getParent();
729
                if (!$objParent) return false;
729
                if (!$objParent) return false;
730
                return $objParent->userHasWriteRights($ra);
730
                return $objParent->userHasWriteRights($ra);
731
        }
731
        }
732
 
732
 
733
        /**
733
        /**
734
         * @param OIDplusRA|string|null $ra
734
         * @param OIDplusRA|string|null $ra
735
         * @return bool
735
         * @return bool
736
         * @throws OIDplusException
736
         * @throws OIDplusException
737
         */
737
         */
738
        public function userHasWriteRights($ra=null): bool {
738
        public function userHasWriteRights($ra=null): bool {
739
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
739
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
740
 
740
 
741
                if (!$ra) {
741
                if (!$ra) {
742
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
742
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
743
                        // TODO: should we allow that the parent RA also may update title/description about this OID (since they delegated it?)
743
                        // TODO: should we allow that the parent RA also may update title/description about this OID (since they delegated it?)
744
                        $ownRa = $this->getRaMail();
744
                        $ownRa = $this->getRaMail();
745
                        return $ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa);
745
                        return $ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa);
746
                } else {
746
                } else {
747
                        return $this->getRaMail() == $ra;
747
                        return $this->getRaMail() == $ra;
748
                }
748
                }
749
        }
749
        }
750
 
750
 
751
        /**
751
        /**
752
         * @param string|OIDplusObject $to
752
         * @param string|OIDplusObject $to
753
         * @return int|null
753
         * @return int|null
754
         */
754
         */
755
        public function distance($to)/*: ?int*/ {
755
        public function distance($to)/*: ?int*/ {
756
                return null; // not implemented
756
                return null; // not implemented
757
        }
757
        }
758
 
758
 
759
        /**
759
        /**
760
         * @param OIDplusObject|string $obj
760
         * @param OIDplusObject|string $obj
761
         * @return bool
761
         * @return bool
762
         */
762
         */
763
        public function equals($obj): bool {
763
        public function equals($obj): bool {
764
                if (!$obj) return false;
764
                if (!$obj) return false;
-
 
765
                if (!is_object($obj)) {
-
 
766
                        if ($this->nodeId(true) === $obj) return true; // simplest case
765
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
767
                        $obj = OIDplusObject::parse($obj);
766
                if (!$obj) return false;
768
                        if (!$obj) return false;
-
 
769
                } else {
-
 
770
                        if ($this->nodeId(true) === $obj->nodeId(true)) return true; // simplest case
-
 
771
                }
767
                if (!($obj instanceof $this)) return false;
772
                if (!($obj instanceof $this)) return false;
768
 
773
 
769
                $distance = $this->distance($obj);
774
                $distance = $this->distance($obj);
770
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
775
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
771
 
776
 
772
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
777
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
773
        }
778
        }
774
 
779
 
775
        /**
780
        /**
776
         * @param string $search_id
781
         * @param string $search_id
777
         * @return OIDplusObject|false
782
         * @return OIDplusObject|false
778
         * @throws OIDplusException
783
         * @throws OIDplusException
779
         */
784
         */
780
        public static function findFitting(string $search_id) {
785
        public static function findFitting(string $search_id) {
781
                $obj = OIDplusObject::parse($search_id);
786
                $obj = OIDplusObject::parse($search_id);
782
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
787
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
783
 
788
 
-
 
789
                if ($obj->nodeId(false) == '') return false; // speed optimization. "oid:" is not equal to any object in the database
-
 
790
 
784
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
791
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
785
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
792
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
786
                        while ($row = $res->fetch_object()) {
793
                        while ($row = $res->fetch_object()) {
787
                                $test = OIDplusObject::parse($row->id);
794
                                $test = OIDplusObject::parse($row->id);
788
                                if ($obj->equals($test)) return $test;
795
                                if ($test && $obj->equals($test)) return $test;
789
                        }
796
                        }
790
                        return false;
797
                        return false;
791
                } else {
798
                } else {
792
                        self::buildObjectInformationCache();
799
                        self::buildObjectInformationCache();
793
                        foreach (self::$object_info_cache as $id => $cacheitem) {
800
                        foreach (self::$object_info_cache as $id => $cacheitem) {
794
                                if (strpos($id, $obj->ns().':') === 0) {
801
                                if (strpos($id, $obj->ns().':') === 0) {
795
                                        $test = OIDplusObject::parse($id);
802
                                        $test = OIDplusObject::parse($id);
796
                                        if ($obj->equals($test)) return $test;
803
                                        if ($test && $obj->equals($test)) return $test;
797
                                }
804
                                }
798
                        }
805
                        }
799
                        return false;
806
                        return false;
800
                }
807
                }
801
        }
808
        }
802
 
809
 
803
        /**
810
        /**
804
         * @return OIDplusObject|null
811
         * @return OIDplusObject|null
805
         */
812
         */
806
        public function one_up()/*: ?OIDplusObject*/ {
813
        public function one_up()/*: ?OIDplusObject*/ {
807
                return null; // not implemented
814
                return null; // not implemented
808
        }
815
        }
809
 
816
 
810
        // Caching stuff
817
        // Caching stuff
811
 
818
 
812
        protected static $object_info_cache = null;
819
        protected static $object_info_cache = null;
813
 
820
 
814
        /**
821
        /**
815
         * @return void
822
         * @return void
816
         */
823
         */
817
        public static function resetObjectInformationCache() {
824
        public static function resetObjectInformationCache() {
818
                self::$object_info_cache = null;
825
                self::$object_info_cache = null;
819
        }
826
        }
820
 
827
 
821
        const CACHE_ID = 'id';
828
        const CACHE_ID = 'id';
822
        const CACHE_PARENT = 'parent';
829
        const CACHE_PARENT = 'parent';
823
        const CACHE_TITLE = 'title';
830
        const CACHE_TITLE = 'title';
824
        const CACHE_DESCRIPTION = 'description';
831
        const CACHE_DESCRIPTION = 'description';
825
        const CACHE_RA_EMAIL = 'ra_email';
832
        const CACHE_RA_EMAIL = 'ra_email';
826
        const CACHE_CONFIDENTIAL = 'confidential';
833
        const CACHE_CONFIDENTIAL = 'confidential';
827
        const CACHE_CREATED = 'created';
834
        const CACHE_CREATED = 'created';
828
        const CACHE_UPDATED = 'updated';
835
        const CACHE_UPDATED = 'updated';
829
        const CACHE_COMMENT = 'comment';
836
        const CACHE_COMMENT = 'comment';
830
 
837
 
831
        /**
838
        /**
832
         * @return void
839
         * @return void
833
         * @throws OIDplusException
840
         * @throws OIDplusException
834
         */
841
         */
835
        private static function buildObjectInformationCache() {
842
        private static function buildObjectInformationCache() {
836
                if (is_null(self::$object_info_cache)) {
843
                if (is_null(self::$object_info_cache)) {
837
                        self::$object_info_cache = array();
844
                        self::$object_info_cache = array();
838
                        $res = OIDplus::db()->query("select * from ###objects");
845
                        $res = OIDplus::db()->query("select * from ###objects");
839
                        while ($row = $res->fetch_array()) {
846
                        while ($row = $res->fetch_array()) {
840
                                self::$object_info_cache[$row['id']] = $row;
847
                                self::$object_info_cache[$row['id']] = $row;
841
                        }
848
                        }
842
                }
849
                }
843
        }
850
        }
844
 
851
 
845
        /**
852
        /**
846
         * override this function if you want your object type to save
853
         * override this function if you want your object type to save
847
         * attachments in directories with easy names.
854
         * attachments in directories with easy names.
848
         * Take care that your custom directory name will not allow jailbreaks (../) !
855
         * Take care that your custom directory name will not allow jailbreaks (../) !
849
         * @return string
856
         * @return string
850
         * @throws OIDplusException
857
         * @throws OIDplusException
851
         */
858
         */
852
        public function getDirectoryName(): string {
859
        public function getDirectoryName(): string {
853
                if ($this->isRoot()) return $this->ns();
860
                if ($this->isRoot()) return $this->ns();
854
                return $this->getLegacyDirectoryName();
861
                return $this->getLegacyDirectoryName();
855
        }
862
        }
856
 
863
 
857
        /**
864
        /**
858
         * @return string
865
         * @return string
859
         * @throws OIDplusException
866
         * @throws OIDplusException
860
         */
867
         */
861
        public final function getLegacyDirectoryName(): string {
868
        public final function getLegacyDirectoryName(): string {
862
                if ($this::ns() == 'oid') {
869
                if ($this::ns() == 'oid') {
863
                        $oid = $this->nodeId(false);
870
                        $oid = $this->nodeId(false);
864
                } else {
871
                } else {
865
                        $oid = null;
872
                        $oid = null;
866
                        $alt_ids = $this->getAltIds();
873
                        $alt_ids = $this->getAltIds();
867
                        foreach ($alt_ids as $alt_id) {
874
                        foreach ($alt_ids as $alt_id) {
868
                                if ($alt_id->getNamespace() == 'oid') {
875
                                if ($alt_id->getNamespace() == 'oid') {
869
                                        $oid = $alt_id->getId();
876
                                        $oid = $alt_id->getId();
870
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
877
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
871
                                }
878
                                }
872
                        }
879
                        }
873
                }
880
                }
874
 
881
 
875
                if (!is_null($oid) && ($oid != '')) {
882
                if (!is_null($oid) && ($oid != '')) {
876
                        // For OIDs, it is the OID, for other identifiers
883
                        // For OIDs, it is the OID, for other identifiers
877
                        // it it the OID alt ID (generated using the SystemID)
884
                        // it it the OID alt ID (generated using the SystemID)
878
                        return str_replace('.', '_', $oid);
885
                        return str_replace('.', '_', $oid);
879
                } else {
886
                } else {
880
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
887
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
881
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
888
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
882
                }
889
                }
883
        }
890
        }
884
 
891
 
885
        /**
892
        /**
886
         * @param string $mode
893
         * @param string $mode
887
         * @return string
894
         * @return string
888
         */
895
         */
889
        public static function treeIconFilename(string $mode): string {
896
        public static function treeIconFilename(string $mode): string {
890
                // for backwards-compatibility with older plugins
897
                // for backwards-compatibility with older plugins
891
                return 'img/treeicon_'.$mode.'.png';
898
                return 'img/treeicon_'.$mode.'.png';
892
        }
899
        }
893
 
900
 
894
}
901
}
895
 
902