Subversion Repositories oidplus

Rev

Rev 1148 | Rev 1168 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1148 Rev 1156
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
                // Creates an OIDplus-Hash-OID
66
                // Creates an OIDplus-Hash-OID
67
                if ($this->ns() != 'oid') {
67
                if ($this->ns() != 'oid') {
68
                        $sid = OIDplus::getSystemId(true);
68
                        $sid = OIDplus::getSystemId(true);
69
                        if (!empty($sid)) {
69
                        if (!empty($sid)) {
70
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
70
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
71
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
71
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
72
                                        // Official ViaThinkSoft object type plugins
72
                                        // Official ViaThinkSoft object type plugins
73
                                        // For backwards compatibility with existing IDs,
73
                                        // For backwards compatibility with existing IDs,
74
                                        // set the hash_payload as '<namespace>:<id>'
74
                                        // set the hash_payload as '<namespace>:<id>'
75
                                        $hash_payload = $this->nodeId(true);
75
                                        $hash_payload = $this->nodeId(true);
76
                                } else {
76
                                } else {
77
                                        // Third-party object type plugins
77
                                        // Third-party object type plugins
78
                                        // Set the hash_payload as '<plugin oid>:<id>'
78
                                        // Set the hash_payload as '<plugin oid>:<id>'
79
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
79
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
80
                                }
80
                                }
81
                                $oid = $sid . '.' . smallhash($hash_payload);
81
                                $oid = $sid . '.' . smallhash($hash_payload);
82
                                $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
82
                                $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object OID'));
83
                        }
83
                        }
84
                }
84
                }
85
 
85
 
86
                // Make a namebased UUID, but...
86
                // Make a namebased UUID, but...
87
                // ... exclude GUID, because a GUID is already a GUID
87
                // ... exclude GUID, because a GUID is already a GUID
88
                // ... exclude OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
88
                // ... exclude OID, because an OID already has a record UUID_NAMEBASED_NS_OID (defined by IETF) set by class OIDplusOid
89
                if (($this->ns() != 'guid') && ($this->ns() != 'oid')) {
89
                if (($this->ns() != 'guid') && ($this->ns() != 'oid')) {
90
                        $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'));
90
                        $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'));
91
                        $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'));
91
                        $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'));
92
                }
92
                }
93
 
93
 
94
                // Make a AID based on ViaThinkSoft schema
94
                // Make a AID based on ViaThinkSoft schema
95
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AIDs (which will be decoded in the OID object type plugin)
95
                // ... but not for OIDs below oid:1.3.6.1.4.1.37476.30.9, because these are the definition of these Information Object AIDs (which will be decoded in the OID object type plugin)
96
                if (($this->ns() != 'aid') && !str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
96
                if (($this->ns() != 'aid') && !str_starts_with($this->nodeId(true), 'oid:1.3.6.1.4.1.37476.30.9.')) {
97
                        $sid = OIDplus::getSystemId(false);
97
                        $sid = OIDplus::getSystemId(false);
98
                        if ($sid !== false) {
98
                        if ($sid !== false) {
99
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
99
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
100
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
100
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
101
                                        // Official ViaThinkSoft object type plugins
101
                                        // Official ViaThinkSoft object type plugins
102
                                        // For backwards compatibility with existing IDs,
102
                                        // For backwards compatibility with existing IDs,
103
                                        // set the hash_payload as '<namespace>:<id>'
103
                                        // set the hash_payload as '<namespace>:<id>'
104
                                        $hash_payload = $this->nodeId(true);
104
                                        $hash_payload = $this->nodeId(true);
105
                                } else {
105
                                } else {
106
                                        // Third-party object type plugins
106
                                        // Third-party object type plugins
107
                                        // Set the hash_payload as '<plugin oid>:<id>'
107
                                        // Set the hash_payload as '<plugin oid>:<id>'
108
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
108
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
109
                                }
109
                                }
110
 
110
 
111
                                $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
111
                                $sid_hex = strtoupper(str_pad(dechex((int)$sid),8,'0',STR_PAD_LEFT));
112
                                $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
112
                                $obj_hex = strtoupper(str_pad(dechex(smallhash($hash_payload)),8,'0',STR_PAD_LEFT));
113
                                $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
113
                                $aid = 'D276000186B20005'.$sid_hex.$obj_hex;
114
                                $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
114
                                $ids[] = new OIDplusAltId('aid', $aid, _L('OIDplus Information Object Application Identifier (ISO/IEC 7816)'), ' ('._L('No PIX allowed').')');
115
                        }
115
                        }
116
                }
116
                }
117
 
117
 
118
                return $ids;
118
                return $ids;
119
        }
119
        }
120
 
120
 
121
        /**
121
        /**
122
         * @return string
122
         * @return string
123
         */
123
         */
124
        public abstract static function objectTypeTitle(): string;
124
        public abstract static function objectTypeTitle(): string;
125
 
125
 
126
        /**
126
        /**
127
         * @return string
127
         * @return string
128
         */
128
         */
129
        public abstract static function objectTypeTitleShort(): string;
129
        public abstract static function objectTypeTitleShort(): string;
130
 
130
 
131
        /**
131
        /**
132
         * @return OIDplusObjectTypePlugin|null
132
         * @return OIDplusObjectTypePlugin|null
133
         */
133
         */
134
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
134
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
135
                $plugins = OIDplus::getObjectTypePlugins();
135
                $plugins = OIDplus::getObjectTypePlugins();
136
                foreach ($plugins as $plugin) {
136
                foreach ($plugins as $plugin) {
137
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
137
                        if (get_class($this) == $plugin::getObjectTypeClassName()) {
138
                                return $plugin;
138
                                return $plugin;
139
                        }
139
                        }
140
                }
140
                }
141
                return null;
141
                return null;
142
        }
142
        }
143
 
143
 
144
        /**
144
        /**
145
         * @return string
145
         * @return string
146
         */
146
         */
147
        public abstract static function ns(): string;
147
        public abstract static function ns(): string;
148
 
148
 
149
        /**
149
        /**
150
         * @return string
150
         * @return string
151
         */
151
         */
152
        public abstract static function root(): string;
152
        public abstract static function root(): string;
153
 
153
 
154
        /**
154
        /**
155
         * @return bool
155
         * @return bool
156
         */
156
         */
157
        public abstract function isRoot(): bool;
157
        public abstract function isRoot(): bool;
158
 
158
 
159
        /**
159
        /**
160
         * @param bool $with_ns
160
         * @param bool $with_ns
161
         * @return string
161
         * @return string
162
         */
162
         */
163
        public abstract function nodeId(bool $with_ns=true): string;
163
        public abstract function nodeId(bool $with_ns=true): string;
164
 
164
 
165
        /**
165
        /**
166
         * @param string $str
166
         * @param string $str
167
         * @return string mixed
167
         * @return string mixed
168
         * @throws OIDplusException
168
         * @throws OIDplusException
169
         */
169
         */
170
        public abstract function addString(string $str): string;
170
        public abstract function addString(string $str): string;
171
 
171
 
172
        /**
172
        /**
173
         * @param OIDplusObject $parent
173
         * @param OIDplusObject $parent
174
         * @return string
174
         * @return string
175
         */
175
         */
176
        public abstract function crudShowId(OIDplusObject $parent): string;
176
        public abstract function crudShowId(OIDplusObject $parent): string;
177
 
177
 
178
        /**
178
        /**
179
         * @return string
179
         * @return string
180
         */
180
         */
181
        public function crudInsertPrefix(): string {
181
        public function crudInsertPrefix(): string {
182
                return '';
182
                return '';
183
        }
183
        }
184
 
184
 
185
        /**
185
        /**
186
         * @return string
186
         * @return string
187
         */
187
         */
188
        public function crudInsertSuffix(): string {
188
        public function crudInsertSuffix(): string {
189
                return '';
189
                return '';
190
        }
190
        }
191
 
191
 
192
        /**
192
        /**
193
         * @param OIDplusObject|null $parent
193
         * @param OIDplusObject|null $parent
194
         * @return string
194
         * @return string
195
         */
195
         */
196
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
196
        public abstract function jsTreeNodeName(OIDplusObject $parent = null): string;
197
 
197
 
198
        /**
198
        /**
199
         * @return string
199
         * @return string
200
         */
200
         */
201
        public abstract function defaultTitle(): string;
201
        public abstract function defaultTitle(): string;
202
 
202
 
203
        /**
203
        /**
204
         * @return bool
204
         * @return bool
205
         */
205
         */
206
        public abstract function isLeafNode(): bool;
206
        public abstract function isLeafNode(): bool;
207
 
207
 
208
        /**
208
        /**
209
         * @param string $title
209
         * @param string $title
210
         * @param string $content
210
         * @param string $content
211
         * @param string $icon
211
         * @param string $icon
212
         * @return void
212
         * @return void
213
         */
213
         */
214
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
214
        public abstract function getContentPage(string &$title, string &$content, string &$icon);
215
 
215
 
216
        /**
216
        /**
217
         * @param OIDplusRA|string|null $ra
217
         * @param OIDplusRA|string|null $ra
218
         * @return array
218
         * @return array
219
         * @throws OIDplusConfigInitializationException
219
         * @throws OIDplusConfigInitializationException
220
         * @throws OIDplusException
220
         * @throws OIDplusException
221
         */
221
         */
222
        public static function getRaRoots($ra=null) : array{
222
        public static function getRaRoots($ra=null) : array{
223
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
223
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
224
 
224
 
225
                $out = array();
225
                $out = array();
226
 
226
 
227
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
227
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
228
                        if (!$ra) {
228
                        if (!$ra) {
229
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
229
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
230
                                                            "left join ###objects as oParent on oChild.parent = oParent.id");
230
                                                            "left join ###objects as oParent on oChild.parent = oParent.id");
231
                                $res = new OIDplusNaturalSortedQueryResult($res, 'oChild.id');
231
                                $res->naturalSortByField('oChild.id');
232
                                while ($row = $res->fetch_array()) {
232
                                while ($row = $res->fetch_array()) {
233
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
233
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
234
                                                $x = self::parse($row['id']); // can be NULL if namespace was disabled
234
                                                $x = self::parse($row['id']); // can be NULL if namespace was disabled
235
                                                if ($x) $out[] = $x;
235
                                                if ($x) $out[] = $x;
236
                                        }
236
                                        }
237
                                }
237
                                }
238
                        } else {
238
                        } else {
239
                                $res = OIDplus::db()->query("select oChild.id as id from ###objects as oChild ".
239
                                $res = OIDplus::db()->query("select oChild.id as id from ###objects as oChild ".
240
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
240
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
241
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
241
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
242
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
242
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
243
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ",
243
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ",
244
                                                            array($ra, $ra, $ra));
244
                                                            array($ra, $ra, $ra));
245
                                $res = new OIDplusNaturalSortedQueryResult($res, 'oChild.id');
245
                                $res->naturalSortByField('oChild.id');
246
                                while ($row = $res->fetch_array()) {
246
                                while ($row = $res->fetch_array()) {
247
                                        $x = self::parse($row['id']); // can be NULL if namespace was disabled
247
                                        $x = self::parse($row['id']); // can be NULL if namespace was disabled
248
                                        if ($x) $out[] = $x;
248
                                        if ($x) $out[] = $x;
249
                                }
249
                                }
250
                        }
250
                        }
251
                } else {
251
                } else {
252
                        if (!$ra) {
252
                        if (!$ra) {
253
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
253
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
254
                                if (count($ra_mails_to_check) == 0) return $out;
254
                                if (count($ra_mails_to_check) == 0) return $out;
255
                        } else {
255
                        } else {
256
                                $ra_mails_to_check = array($ra);
256
                                $ra_mails_to_check = array($ra);
257
                        }
257
                        }
258
 
258
 
259
                        self::buildObjectInformationCache();
259
                        self::buildObjectInformationCache();
260
 
260
 
261
                        foreach ($ra_mails_to_check as $check_ra_mail) {
261
                        foreach ($ra_mails_to_check as $check_ra_mail) {
262
                                $out_part = array();
262
                                $out_part = array();
263
 
263
 
264
                                foreach (self::$object_info_cache as $id => $cacheitem) {
264
                                foreach (self::$object_info_cache as $id => $cacheitem) {
265
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
265
                                        if ($cacheitem[self::CACHE_RA_EMAIL] == $check_ra_mail) {
266
                                                $parent = $cacheitem[self::CACHE_PARENT];
266
                                                $parent = $cacheitem[self::CACHE_PARENT];
267
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
267
                                                if (!isset(self::$object_info_cache[$parent]) || (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] != $check_ra_mail)) {
268
                                                        $out_part[] = $id;
268
                                                        $out_part[] = $id;
269
                                                }
269
                                                }
270
                                        }
270
                                        }
271
                                }
271
                                }
272
 
272
 
273
                                natsort($out_part);
273
                                natsort($out_part);
274
 
274
 
275
                                foreach ($out_part as $id) {
275
                                foreach ($out_part as $id) {
276
                                        $obj = self::parse($id);
276
                                        $obj = self::parse($id);
277
                                        if ($obj) $out[] = $obj;
277
                                        if ($obj) $out[] = $obj;
278
                                }
278
                                }
279
                        }
279
                        }
280
                }
280
                }
281
 
281
 
282
                return $out;
282
                return $out;
283
        }
283
        }
284
 
284
 
285
        /**
285
        /**
286
         * @return array
286
         * @return array
287
         * @throws OIDplusException
287
         * @throws OIDplusException
288
         */
288
         */
289
        public static function getAllNonConfidential(): array {
289
        public static function getAllNonConfidential(): array {
290
                $out = array();
290
                $out = array();
291
 
291
 
292
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
292
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
293
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ?", array(false));
293
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ?", array(false));
294
                        $res = new OIDplusNaturalSortedQueryResult($res, 'id');
294
                        $res->naturalSortByField('id');
295
                        while ($row = $res->fetch_array()) {
295
                        while ($row = $res->fetch_array()) {
296
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
296
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
297
                                if ($obj && (!$obj->isConfidential())) {
297
                                if ($obj && (!$obj->isConfidential())) {
298
                                        $out[] = $row['id'];
298
                                        $out[] = $row['id'];
299
                                }
299
                                }
300
                        }
300
                        }
301
                } else {
301
                } else {
302
                        self::buildObjectInformationCache();
302
                        self::buildObjectInformationCache();
303
 
303
 
304
                        foreach (self::$object_info_cache as $id => $cacheitem) {
304
                        foreach (self::$object_info_cache as $id => $cacheitem) {
305
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
305
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
306
                                if (!$confidential) {
306
                                if (!$confidential) {
307
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
307
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
308
                                        if ($obj && (!$obj->isConfidential())) {
308
                                        if ($obj && (!$obj->isConfidential())) {
309
                                                $out[] = $id;
309
                                                $out[] = $id;
310
                                        }
310
                                        }
311
                                }
311
                                }
312
                        }
312
                        }
313
                }
313
                }
314
 
314
 
315
                return $out;
315
                return $out;
316
        }
316
        }
317
 
317
 
318
        /**
318
        /**
319
         * @return bool
319
         * @return bool
320
         * @throws OIDplusException
320
         * @throws OIDplusException
321
         */
321
         */
322
        public function isConfidential(): bool {
322
        public function isConfidential(): bool {
323
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
323
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
324
                        //static $confidential_cache = array();
324
                        //static $confidential_cache = array();
325
                        $curid = $this->nodeId();
325
                        $curid = $this->nodeId();
326
                        //$orig_curid = $curid;
326
                        //$orig_curid = $curid;
327
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
327
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
328
                        // Recursively search for the confidential flag in the parents
328
                        // Recursively search for the confidential flag in the parents
329
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
329
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
330
                                $row = $res->fetch_array();
330
                                $row = $res->fetch_array();
331
                                if ($row['confidential']) {
331
                                if ($row['confidential']) {
332
                                        //$confidential_cache[$curid] = true;
332
                                        //$confidential_cache[$curid] = true;
333
                                        //$confidential_cache[$orig_curid] = true;
333
                                        //$confidential_cache[$orig_curid] = true;
334
                                        return true;
334
                                        return true;
335
                                } else {
335
                                } else {
336
                                        //$confidential_cache[$curid] = false;
336
                                        //$confidential_cache[$curid] = false;
337
                                }
337
                                }
338
                                $curid = $row['parent'];
338
                                $curid = $row['parent'];
339
                                //if (isset($confidential_cache[$curid])) {
339
                                //if (isset($confidential_cache[$curid])) {
340
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
340
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
341
                                        //return $confidential_cache[$curid];
341
                                        //return $confidential_cache[$curid];
342
                                //}
342
                                //}
343
                        }
343
                        }
344
 
344
 
345
                        //$confidential_cache[$orig_curid] = false;
345
                        //$confidential_cache[$orig_curid] = false;
346
                        return false;
346
                        return false;
347
                } else {
347
                } else {
348
                        self::buildObjectInformationCache();
348
                        self::buildObjectInformationCache();
349
 
349
 
350
                        $curid = $this->nodeId();
350
                        $curid = $this->nodeId();
351
                        // Recursively search for the confidential flag in the parents
351
                        // Recursively search for the confidential flag in the parents
352
                        while (isset(self::$object_info_cache[$curid])) {
352
                        while (isset(self::$object_info_cache[$curid])) {
353
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
353
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
354
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
354
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
355
                        }
355
                        }
356
                        return false;
356
                        return false;
357
                }
357
                }
358
        }
358
        }
359
 
359
 
360
        /**
360
        /**
361
         * @param OIDplusObject $obj
361
         * @param OIDplusObject $obj
362
         * @return bool
362
         * @return bool
363
         * @throws OIDplusException
363
         * @throws OIDplusException
364
         */
364
         */
365
        public function isChildOf(OIDplusObject $obj): bool {
365
        public function isChildOf(OIDplusObject $obj): bool {
366
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
366
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
367
                        $curid = $this->nodeId();
367
                        $curid = $this->nodeId();
368
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
368
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
369
                                $row = $res->fetch_array();
369
                                $row = $res->fetch_array();
370
                                if ($curid == $obj->nodeId()) return true;
370
                                if ($curid == $obj->nodeId()) return true;
371
                                $curid = $row['parent'];
371
                                $curid = $row['parent'];
372
                        }
372
                        }
373
                        return false;
373
                        return false;
374
                } else {
374
                } else {
375
                        self::buildObjectInformationCache();
375
                        self::buildObjectInformationCache();
376
 
376
 
377
                        $curid = $this->nodeId();
377
                        $curid = $this->nodeId();
378
                        while (isset(self::$object_info_cache[$curid])) {
378
                        while (isset(self::$object_info_cache[$curid])) {
379
                                if ($curid == $obj->nodeId()) return true;
379
                                if ($curid == $obj->nodeId()) return true;
380
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
380
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
381
                        }
381
                        }
382
                        return false;
382
                        return false;
383
                }
383
                }
384
        }
384
        }
385
 
385
 
386
        /**
386
        /**
387
         * @return array
387
         * @return array
388
         * @throws OIDplusException
388
         * @throws OIDplusException
389
         */
389
         */
390
        public function getChildren(): array {
390
        public function getChildren(): array {
391
                $out = array();
391
                $out = array();
392
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
392
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
393
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
393
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
394
                        while ($row = $res->fetch_array()) {
394
                        while ($row = $res->fetch_array()) {
395
                                $obj = self::parse($row['id']);
395
                                $obj = self::parse($row['id']);
396
                                if (!$obj) continue;
396
                                if (!$obj) continue;
397
                                $out[] = $obj;
397
                                $out[] = $obj;
398
                        }
398
                        }
399
                } else {
399
                } else {
400
                        self::buildObjectInformationCache();
400
                        self::buildObjectInformationCache();
401
 
401
 
402
                        foreach (self::$object_info_cache as $id => $cacheitem) {
402
                        foreach (self::$object_info_cache as $id => $cacheitem) {
403
                                $parent = $cacheitem[self::CACHE_PARENT];
403
                                $parent = $cacheitem[self::CACHE_PARENT];
404
                                if ($parent == $this->nodeId()) {
404
                                if ($parent == $this->nodeId()) {
405
                                        $obj = self::parse($id);
405
                                        $obj = self::parse($id);
406
                                        if (!$obj) continue;
406
                                        if (!$obj) continue;
407
                                        $out[] = $obj;
407
                                        $out[] = $obj;
408
                                }
408
                                }
409
                        }
409
                        }
410
                }
410
                }
411
                return $out;
411
                return $out;
412
        }
412
        }
413
 
413
 
414
        /**
414
        /**
415
         * @return OIDplusRA|null
415
         * @return OIDplusRA|null
416
         * @throws OIDplusException
416
         * @throws OIDplusException
417
         */
417
         */
418
        public function getRa()/*: ?OIDplusRA*/ {
418
        public function getRa()/*: ?OIDplusRA*/ {
419
                $ra = $this->getRaMail();
419
                $ra = $this->getRaMail();
420
                return $ra ? new OIDplusRA($ra) : null;
420
                return $ra ? new OIDplusRA($ra) : null;
421
        }
421
        }
422
 
422
 
423
        /**
423
        /**
424
         * @param OIDplusRA|string|null $ra
424
         * @param OIDplusRA|string|null $ra
425
         * @return bool
425
         * @return bool
426
         * @throws OIDplusConfigInitializationException
426
         * @throws OIDplusConfigInitializationException
427
         * @throws OIDplusException
427
         * @throws OIDplusException
428
         */
428
         */
429
        public function userHasReadRights($ra=null): bool {
429
        public function userHasReadRights($ra=null): bool {
430
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
430
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
431
 
431
 
432
                // If it is not confidential, everybody can read/see it.
432
                // If it is not confidential, everybody can read/see it.
433
                // Note: This also checks if superior OIDs are confidential.
433
                // Note: This also checks if superior OIDs are confidential.
434
                if (!$this->isConfidential()) return true;
434
                if (!$this->isConfidential()) return true;
435
 
435
 
436
                if (!$ra) {
436
                if (!$ra) {
437
                        // Admin may do everything
437
                        // Admin may do everything
438
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
438
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
439
 
439
 
440
                        // If the RA is logged in, then they can see the OID.
440
                        // If the RA is logged in, then they can see the OID.
441
                        $ownRa = $this->getRaMail();
441
                        $ownRa = $this->getRaMail();
442
                        if ($ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa)) return true;
442
                        if ($ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa)) return true;
443
                } else {
443
                } else {
444
                        // If this OID belongs to the requested RA, then they may see it.
444
                        // If this OID belongs to the requested RA, then they may see it.
445
                        if ($this->getRaMail() == $ra) return true;
445
                        if ($this->getRaMail() == $ra) return true;
446
                }
446
                }
447
 
447
 
448
                // If someone has rights to an object below our confidential node,
448
                // If someone has rights to an object below our confidential node,
449
                // we let him see the confidential node,
449
                // we let him see the confidential node,
450
                // Otherwise he could not browse through to his own node.
450
                // Otherwise he could not browse through to his own node.
451
                $roots = $this->getRaRoots($ra);
451
                $roots = $this->getRaRoots($ra);
452
                foreach ($roots as $root) {
452
                foreach ($roots as $root) {
453
                        if ($root->isChildOf($this)) return true;
453
                        if ($root->isChildOf($this)) return true;
454
                }
454
                }
455
 
455
 
456
                return false;
456
                return false;
457
        }
457
        }
458
 
458
 
459
        /**
459
        /**
460
         * @param array|null $row
460
         * @param array|null $row
461
         * @return string|null
461
         * @return string|null
462
         * @throws OIDplusException
462
         * @throws OIDplusException
463
         */
463
         */
464
        public function getIcon(array $row=null) {
464
        public function getIcon(array $row=null) {
465
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
465
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
466
 
466
 
467
                if (is_null($row)) {
467
                if (is_null($row)) {
468
                        $ra_email = $this->getRaMail();
468
                        $ra_email = $this->getRaMail();
469
                } else {
469
                } else {
470
                        $ra_email = $row['ra_email'];
470
                        $ra_email = $row['ra_email'];
471
                }
471
                }
472
 
472
 
473
                // $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
473
                // $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
474
                // if (count($dirs) == 0) return null; // default icon (folder)
474
                // if (count($dirs) == 0) return null; // default icon (folder)
475
                // $dir = substr($dirs[0], strlen(OIDplus::localpath()));
475
                // $dir = substr($dirs[0], strlen(OIDplus::localpath()));
476
                $reflection = new \ReflectionClass($this);
476
                $reflection = new \ReflectionClass($this);
477
                $dir = dirname($reflection->getFilename());
477
                $dir = dirname($reflection->getFilename());
478
                $dir = substr($dir, strlen(OIDplus::localpath()));
478
                $dir = substr($dir, strlen(OIDplus::localpath()));
479
                $dir = str_replace('\\', '/', $dir);
479
                $dir = str_replace('\\', '/', $dir);
480
 
480
 
481
                if ($this->isRoot()) {
481
                if ($this->isRoot()) {
482
                        $icon = $dir . '/' . $this::treeIconFilename('root');
482
                        $icon = $dir . '/' . $this::treeIconFilename('root');
483
                } else {
483
                } else {
484
                        // We use $this:: instead of self:: , because we want to call the overridden methods
484
                        // We use $this:: instead of self:: , because we want to call the overridden methods
485
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
485
                        if ($ra_email && OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
486
                                if ($this->isLeafNode()) {
486
                                if ($this->isLeafNode()) {
487
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
487
                                        $icon = $dir . '/' . $this::treeIconFilename('own_leaf');
488
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
488
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('own');
489
                                } else {
489
                                } else {
490
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
490
                                        $icon = $dir . '/' . $this::treeIconFilename('own');
491
                                }
491
                                }
492
                        } else {
492
                        } else {
493
                                if ($this->isLeafNode()) {
493
                                if ($this->isLeafNode()) {
494
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
494
                                        $icon = $dir . '/' . $this::treeIconFilename('general_leaf');
495
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
495
                                        if (!file_exists($icon)) $icon = $dir . '/' . $this::treeIconFilename('general');
496
                                } else {
496
                                } else {
497
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
497
                                        $icon = $dir . '/' . $this::treeIconFilename('general');
498
                                }
498
                                }
499
                        }
499
                        }
500
                }
500
                }
501
 
501
 
502
                if (!file_exists($icon)) return null; // default icon (folder)
502
                if (!file_exists($icon)) return null; // default icon (folder)
503
 
503
 
504
                return $icon;
504
                return $icon;
505
        }
505
        }
506
 
506
 
507
        /**
507
        /**
508
         * @param string $id
508
         * @param string $id
509
         * @return bool
509
         * @return bool
510
         * @throws OIDplusException
510
         * @throws OIDplusException
511
         */
511
         */
512
        public static function exists(string $id): bool {
512
        public static function exists(string $id): bool {
513
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
513
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
514
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
514
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
515
                        return $res->any();
515
                        return $res->any();
516
                } else {
516
                } else {
517
                        self::buildObjectInformationCache();
517
                        self::buildObjectInformationCache();
518
                        return isset(self::$object_info_cache[$id]);
518
                        return isset(self::$object_info_cache[$id]);
519
                }
519
                }
520
        }
520
        }
521
 
521
 
522
        /**
522
        /**
523
         * Get parent gives the next possible parent which is EXISTING in OIDplus
523
         * Get parent gives the next possible parent which is EXISTING in OIDplus
524
         * It does not give the immediate parent
524
         * It does not give the immediate parent
525
         * @return OIDplusObject|null
525
         * @return OIDplusObject|null
526
         * @throws OIDplusException
526
         * @throws OIDplusException
527
         */
527
         */
528
        public function getParent()/*: ?OIDplusObject*/ {
528
        public function getParent()/*: ?OIDplusObject*/ {
529
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
529
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
530
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
530
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
531
                        if (!$res->any()) return null;
531
                        if (!$res->any()) return null;
532
                        $row = $res->fetch_array();
532
                        $row = $res->fetch_array();
533
                        $parent = $row['parent'];
533
                        $parent = $row['parent'];
534
                        $obj = OIDplusObject::parse($parent);
534
                        $obj = OIDplusObject::parse($parent);
535
                        if ($obj) return $obj;
535
                        if ($obj) return $obj;
536
                        // TODO: Also implement one_up() like below
536
                        // TODO: Also implement one_up() like below
537
                } else {
537
                } else {
538
                        self::buildObjectInformationCache();
538
                        self::buildObjectInformationCache();
539
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
539
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
540
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
540
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
541
                                $obj = OIDplusObject::parse($parent);
541
                                $obj = OIDplusObject::parse($parent);
542
                                if ($obj) return $obj;
542
                                if ($obj) return $obj;
543
                        }
543
                        }
544
 
544
 
545
                        // 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()
545
                        // 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()
546
                        $cur = $this->one_up();
546
                        $cur = $this->one_up();
547
                        if (!$cur) return null;
547
                        if (!$cur) return null;
548
                        do {
548
                        do {
549
                                // findFitting() checks if that OID exists
549
                                // findFitting() checks if that OID exists
550
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
550
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
551
 
551
 
552
                                $prev = $cur;
552
                                $prev = $cur;
553
                                $cur = $cur->one_up();
553
                                $cur = $cur->one_up();
554
                                if (!$cur) return null;
554
                                if (!$cur) return null;
555
                        } while ($prev !== $cur);
555
                        } while ($prev !== $cur);
556
                }
556
                }
557
                return null;
557
                return null;
558
        }
558
        }
559
 
559
 
560
        /**
560
        /**
561
         * @return string|null
561
         * @return string|null
562
         * @throws OIDplusException
562
         * @throws OIDplusException
563
         */
563
         */
564
        public function getRaMail() {
564
        public function getRaMail() {
565
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
565
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
566
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
566
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
567
                        if (!$res->any()) return null;
567
                        if (!$res->any()) return null;
568
                        $row = $res->fetch_array();
568
                        $row = $res->fetch_array();
569
                        return $row['ra_email'];
569
                        return $row['ra_email'];
570
                } else {
570
                } else {
571
                        self::buildObjectInformationCache();
571
                        self::buildObjectInformationCache();
572
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
572
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
573
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
573
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
574
                        }
574
                        }
575
                        return null;
575
                        return null;
576
                }
576
                }
577
        }
577
        }
578
 
578
 
579
        /**
579
        /**
580
         * @return string|null
580
         * @return string|null
581
         * @throws OIDplusException
581
         * @throws OIDplusException
582
         */
582
         */
583
        public function getTitle() {
583
        public function getTitle() {
584
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
584
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
585
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
585
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
586
                        if (!$res->any()) return null;
586
                        if (!$res->any()) return null;
587
                        $row = $res->fetch_array();
587
                        $row = $res->fetch_array();
588
                        return $row['title'];
588
                        return $row['title'];
589
                } else {
589
                } else {
590
                        self::buildObjectInformationCache();
590
                        self::buildObjectInformationCache();
591
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
591
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
592
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
592
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
593
                        }
593
                        }
594
                        return null;
594
                        return null;
595
                }
595
                }
596
        }
596
        }
597
 
597
 
598
        /**
598
        /**
599
         * @return string|null
599
         * @return string|null
600
         * @throws OIDplusException
600
         * @throws OIDplusException
601
         */
601
         */
602
        public function getDescription() {
602
        public function getDescription() {
603
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
603
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
604
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
604
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
605
                        if (!$res->any()) return null;
605
                        if (!$res->any()) return null;
606
                        $row = $res->fetch_array();
606
                        $row = $res->fetch_array();
607
                        return $row['description'];
607
                        return $row['description'];
608
                } else {
608
                } else {
609
                        self::buildObjectInformationCache();
609
                        self::buildObjectInformationCache();
610
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
610
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
611
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
611
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
612
                        }
612
                        }
613
                        return null;
613
                        return null;
614
                }
614
                }
615
        }
615
        }
616
 
616
 
617
        /**
617
        /**
618
         * @return string|null
618
         * @return string|null
619
         * @throws OIDplusException
619
         * @throws OIDplusException
620
         */
620
         */
621
        public function getComment() {
621
        public function getComment() {
622
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
622
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
623
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
623
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
624
                        if (!$res->any()) return null;
624
                        if (!$res->any()) return null;
625
                        $row = $res->fetch_array();
625
                        $row = $res->fetch_array();
626
                        return $row['comment'];
626
                        return $row['comment'];
627
                } else {
627
                } else {
628
                        self::buildObjectInformationCache();
628
                        self::buildObjectInformationCache();
629
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
629
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
630
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
630
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
631
                        }
631
                        }
632
                        return null;
632
                        return null;
633
                }
633
                }
634
        }
634
        }
635
 
635
 
636
        /**
636
        /**
637
         * @return string|null
637
         * @return string|null
638
         * @throws OIDplusException
638
         * @throws OIDplusException
639
         */
639
         */
640
        public function getCreatedTime() {
640
        public function getCreatedTime() {
641
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
641
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
642
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
642
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
643
                        if (!$res->any()) return null;
643
                        if (!$res->any()) return null;
644
                        $row = $res->fetch_array();
644
                        $row = $res->fetch_array();
645
                        return $row['created'];
645
                        return $row['created'];
646
                } else {
646
                } else {
647
                        self::buildObjectInformationCache();
647
                        self::buildObjectInformationCache();
648
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
648
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
649
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
649
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
650
                        }
650
                        }
651
                        return null;
651
                        return null;
652
                }
652
                }
653
        }
653
        }
654
 
654
 
655
        /**
655
        /**
656
         * @return string|null
656
         * @return string|null
657
         * @throws OIDplusException
657
         * @throws OIDplusException
658
         */
658
         */
659
        public function getUpdatedTime() {
659
        public function getUpdatedTime() {
660
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
660
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
661
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
661
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
662
                        if (!$res->any()) return null;
662
                        if (!$res->any()) return null;
663
                        $row = $res->fetch_array();
663
                        $row = $res->fetch_array();
664
                        return $row['updated'];
664
                        return $row['updated'];
665
                } else {
665
                } else {
666
                        self::buildObjectInformationCache();
666
                        self::buildObjectInformationCache();
667
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
667
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
668
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
668
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
669
                        }
669
                        }
670
                        return null;
670
                        return null;
671
                }
671
                }
672
        }
672
        }
673
 
673
 
674
        /**
674
        /**
675
         * @param OIDplusRA|string|null $ra
675
         * @param OIDplusRA|string|null $ra
676
         * @return bool
676
         * @return bool
677
         * @throws OIDplusException
677
         * @throws OIDplusException
678
         */
678
         */
679
        public function userHasParentalWriteRights($ra=null): bool {
679
        public function userHasParentalWriteRights($ra=null): bool {
680
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
680
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
681
 
681
 
682
                if (!$ra) {
682
                if (!$ra) {
683
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
683
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
684
                }
684
                }
685
 
685
 
686
                $objParent = $this->getParent();
686
                $objParent = $this->getParent();
687
                if (!$objParent) return false;
687
                if (!$objParent) return false;
688
                return $objParent->userHasWriteRights($ra);
688
                return $objParent->userHasWriteRights($ra);
689
        }
689
        }
690
 
690
 
691
        /**
691
        /**
692
         * @param OIDplusRA|string|null $ra
692
         * @param OIDplusRA|string|null $ra
693
         * @return bool
693
         * @return bool
694
         * @throws OIDplusException
694
         * @throws OIDplusException
695
         */
695
         */
696
        public function userHasWriteRights($ra=null): bool {
696
        public function userHasWriteRights($ra=null): bool {
697
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
697
                if ($ra instanceof OIDplusRA) $ra = $ra->raEmail();
698
 
698
 
699
                if (!$ra) {
699
                if (!$ra) {
700
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
700
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
701
                        $ownRa = $this->getRaMail();
701
                        $ownRa = $this->getRaMail();
702
                        return $ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa);
702
                        return $ownRa && OIDplus::authUtils()->isRaLoggedIn($ownRa);
703
                } else {
703
                } else {
704
                        return $this->getRaMail() == $ra;
704
                        return $this->getRaMail() == $ra;
705
                }
705
                }
706
        }
706
        }
707
 
707
 
708
        /**
708
        /**
709
         * @param string|OIDplusObject $to
709
         * @param string|OIDplusObject $to
710
         * @return int|null
710
         * @return int|null
711
         */
711
         */
712
        public function distance($to)/*: ?int*/ {
712
        public function distance($to)/*: ?int*/ {
713
                return null; // not implemented
713
                return null; // not implemented
714
        }
714
        }
715
 
715
 
716
        /**
716
        /**
717
         * @param OIDplusObject|string $obj
717
         * @param OIDplusObject|string $obj
718
         * @return bool
718
         * @return bool
719
         */
719
         */
720
        public function equals($obj): bool {
720
        public function equals($obj): bool {
721
                if (!$obj) return false;
721
                if (!$obj) return false;
722
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
722
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
723
                if (!$obj) return false;
723
                if (!$obj) return false;
724
                if (!($obj instanceof $this)) return false;
724
                if (!($obj instanceof $this)) return false;
725
 
725
 
726
                $distance = $this->distance($obj);
726
                $distance = $this->distance($obj);
727
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
727
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
728
 
728
 
729
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
729
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
730
        }
730
        }
731
 
731
 
732
        /**
732
        /**
733
         * @param string $id
733
         * @param string $id
734
         * @return OIDplusObject|false
734
         * @return OIDplusObject|false
735
         * @throws OIDplusException
735
         * @throws OIDplusException
736
         */
736
         */
737
        public static function findFitting(string $id) {
737
        public static function findFitting(string $id) {
738
                $obj = OIDplusObject::parse($id);
738
                $obj = OIDplusObject::parse($id);
739
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
739
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
740
 
740
 
741
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
741
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
742
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
742
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
743
                        while ($row = $res->fetch_object()) {
743
                        while ($row = $res->fetch_object()) {
744
                                $test = OIDplusObject::parse($row->id);
744
                                $test = OIDplusObject::parse($row->id);
745
                                if ($obj->equals($test)) return $test;
745
                                if ($obj->equals($test)) return $test;
746
                        }
746
                        }
747
                        return false;
747
                        return false;
748
                } else {
748
                } else {
749
                        self::buildObjectInformationCache();
749
                        self::buildObjectInformationCache();
750
                        foreach (self::$object_info_cache as $id => $cacheitem) {
750
                        foreach (self::$object_info_cache as $id => $cacheitem) {
751
                                if (strpos($id, $obj->ns().':') === 0) {
751
                                if (strpos($id, $obj->ns().':') === 0) {
752
                                        $test = OIDplusObject::parse($id);
752
                                        $test = OIDplusObject::parse($id);
753
                                        if ($obj->equals($test)) return $test;
753
                                        if ($obj->equals($test)) return $test;
754
                                }
754
                                }
755
                        }
755
                        }
756
                        return false;
756
                        return false;
757
                }
757
                }
758
        }
758
        }
759
 
759
 
760
        /**
760
        /**
761
         * @return OIDplusObject|null
761
         * @return OIDplusObject|null
762
         */
762
         */
763
        public function one_up()/*: ?OIDplusObject*/ {
763
        public function one_up()/*: ?OIDplusObject*/ {
764
                return null; // not implemented
764
                return null; // not implemented
765
        }
765
        }
766
 
766
 
767
        // Caching stuff
767
        // Caching stuff
768
 
768
 
769
        protected static $object_info_cache = null;
769
        protected static $object_info_cache = null;
770
 
770
 
771
        /**
771
        /**
772
         * @return void
772
         * @return void
773
         */
773
         */
774
        public static function resetObjectInformationCache() {
774
        public static function resetObjectInformationCache() {
775
                self::$object_info_cache = null;
775
                self::$object_info_cache = null;
776
        }
776
        }
777
 
777
 
778
        const CACHE_ID = 'id';
778
        const CACHE_ID = 'id';
779
        const CACHE_PARENT = 'parent';
779
        const CACHE_PARENT = 'parent';
780
        const CACHE_TITLE = 'title';
780
        const CACHE_TITLE = 'title';
781
        const CACHE_DESCRIPTION = 'description';
781
        const CACHE_DESCRIPTION = 'description';
782
        const CACHE_RA_EMAIL = 'ra_email';
782
        const CACHE_RA_EMAIL = 'ra_email';
783
        const CACHE_CONFIDENTIAL = 'confidential';
783
        const CACHE_CONFIDENTIAL = 'confidential';
784
        const CACHE_CREATED = 'created';
784
        const CACHE_CREATED = 'created';
785
        const CACHE_UPDATED = 'updated';
785
        const CACHE_UPDATED = 'updated';
786
        const CACHE_COMMENT = 'comment';
786
        const CACHE_COMMENT = 'comment';
787
 
787
 
788
        /**
788
        /**
789
         * @return void
789
         * @return void
790
         * @throws OIDplusException
790
         * @throws OIDplusException
791
         */
791
         */
792
        private static function buildObjectInformationCache() {
792
        private static function buildObjectInformationCache() {
793
                if (is_null(self::$object_info_cache)) {
793
                if (is_null(self::$object_info_cache)) {
794
                        self::$object_info_cache = array();
794
                        self::$object_info_cache = array();
795
                        $res = OIDplus::db()->query("select * from ###objects");
795
                        $res = OIDplus::db()->query("select * from ###objects");
796
                        while ($row = $res->fetch_array()) {
796
                        while ($row = $res->fetch_array()) {
797
                                self::$object_info_cache[$row['id']] = $row;
797
                                self::$object_info_cache[$row['id']] = $row;
798
                        }
798
                        }
799
                }
799
                }
800
        }
800
        }
801
 
801
 
802
        /**
802
        /**
803
         * override this function if you want your object type to save
803
         * override this function if you want your object type to save
804
         * attachments in directories with easy names.
804
         * attachments in directories with easy names.
805
         * Take care that your custom directory name will not allow jailbreaks (../) !
805
         * Take care that your custom directory name will not allow jailbreaks (../) !
806
         * @return string
806
         * @return string
807
         * @throws OIDplusException
807
         * @throws OIDplusException
808
         */
808
         */
809
        public function getDirectoryName(): string {
809
        public function getDirectoryName(): string {
810
                if ($this->isRoot()) return $this->ns();
810
                if ($this->isRoot()) return $this->ns();
811
                return $this->getLegacyDirectoryName();
811
                return $this->getLegacyDirectoryName();
812
        }
812
        }
813
 
813
 
814
        /**
814
        /**
815
         * @return string
815
         * @return string
816
         * @throws OIDplusException
816
         * @throws OIDplusException
817
         */
817
         */
818
        public final function getLegacyDirectoryName(): string {
818
        public final function getLegacyDirectoryName(): string {
819
                if ($this::ns() == 'oid') {
819
                if ($this::ns() == 'oid') {
820
                        $oid = $this->nodeId(false);
820
                        $oid = $this->nodeId(false);
821
                } else {
821
                } else {
822
                        $oid = null;
822
                        $oid = null;
823
                        $alt_ids = $this->getAltIds();
823
                        $alt_ids = $this->getAltIds();
824
                        foreach ($alt_ids as $alt_id) {
824
                        foreach ($alt_ids as $alt_id) {
825
                                if ($alt_id->getNamespace() == 'oid') {
825
                                if ($alt_id->getNamespace() == 'oid') {
826
                                        $oid = $alt_id->getId();
826
                                        $oid = $alt_id->getId();
827
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
827
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
828
                                }
828
                                }
829
                        }
829
                        }
830
                }
830
                }
831
 
831
 
832
                if (!is_null($oid) && ($oid != '')) {
832
                if (!is_null($oid) && ($oid != '')) {
833
                        // For OIDs, it is the OID, for other identifiers
833
                        // For OIDs, it is the OID, for other identifiers
834
                        // it it the OID alt ID (generated using the SystemID)
834
                        // it it the OID alt ID (generated using the SystemID)
835
                        return str_replace('.', '_', $oid);
835
                        return str_replace('.', '_', $oid);
836
                } else {
836
                } else {
837
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
837
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
838
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
838
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
839
                }
839
                }
840
        }
840
        }
841
 
841
 
842
        /**
842
        /**
843
         * @param string $mode
843
         * @param string $mode
844
         * @return string
844
         * @return string
845
         */
845
         */
846
        public static function treeIconFilename(string $mode): string {
846
        public static function treeIconFilename(string $mode): string {
847
                // for backwards-compatibility with older plugins
847
                // for backwards-compatibility with older plugins
848
                return 'img/treeicon_'.$mode.'.png';
848
                return 'img/treeicon_'.$mode.'.png';
849
        }
849
        }
850
 
850
 
851
}
851
}
852
 
852