Subversion Repositories oidplus

Rev

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

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
635 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
635 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
1131 daniel-mar 26
class OIDplusPageAdminOIDInfoExport extends OIDplusPagePluginAdmin
27
        implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8 /* getNotifications */
28
{
635 daniel-mar 29
 
1130 daniel-mar 30
        /**
31
         *
32
         */
635 daniel-mar 33
        /*private*/ const QUERY_LIST_OIDINFO_OIDS_V1 = '1.3.6.1.4.1.37476.2.5.2.1.5.1';
1130 daniel-mar 34
 
35
        /**
36
         *
37
         */
635 daniel-mar 38
        /*private*/ const QUERY_GET_OIDINFO_DATA_V1  = '1.3.6.1.4.1.37476.2.5.2.1.6.1';
39
 
1116 daniel-mar 40
        /**
41
         * @param array $params
1143 daniel-mar 42
         * @return array
1116 daniel-mar 43
         * @throws OIDplusException
44
         */
1293 daniel-mar 45
        private function action_ImportXml(array $params): array {
46
                if (!OIDplus::authUtils()->isAdminLoggedIn()) {
47
                        throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), null,401);
48
                }
635 daniel-mar 49
 
1293 daniel-mar 50
                if (!isset($_FILES['userfile'])) {
51
                        throw new OIDplusException(_L('Please choose a file.'));
52
                }
635 daniel-mar 53
 
1363 daniel-mar 54
                if ($_FILES['userfile']['error']) {
55
                        throw new OIDplusException(_L('Could not receive file (probably it is too large?)'));
56
                }
57
 
1293 daniel-mar 58
                $xml_contents = file_get_contents($_FILES['userfile']['tmp_name']);
635 daniel-mar 59
 
1293 daniel-mar 60
                $errors = array();
61
                list($count_imported_oids, $count_already_existing, $count_errors, $count_warnings) = $this->oidinfoImportXML($xml_contents, $errors, $replaceExistingOIDs=false, $orphan_mode=self::ORPHAN_AUTO_DEORPHAN);
62
                if (count($errors) > 0) {
63
                        // Note: These "errors" can also be warnings (partial success)
64
                        // TODO: since the output can be very long, should we really show it in a JavaScript alert() ?!
65
                        return array(
66
                                "status" => -1,
67
                                "count_imported_oids" => $count_imported_oids,
68
                                "count_already_existing" => $count_already_existing,
69
                                "count_errors" => $count_errors,
70
                                "count_warnings" => $count_warnings,
71
                                "error" => implode("\n",$errors)
72
                        );
73
                } else {
74
                        return array(
75
                                "status" => 0,
76
                                "count_imported_oids" => $count_imported_oids,
77
                                "count_already_existing" => $count_already_existing,
78
                                "count_errors" => $count_errors,
79
                                "count_warnings" => $count_warnings
80
                        );
81
                }
82
        }
635 daniel-mar 83
 
1293 daniel-mar 84
        /**
85
         * @param array $params
86
         * @return array
87
         * @throws OIDplusException
88
         */
89
        private function action_ImportOidInfo(array $params): array {
90
                if (!OIDplus::authUtils()->isAdminLoggedIn()) {
91
                        throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), null, 401);
92
                }
635 daniel-mar 93
 
1293 daniel-mar 94
                _CheckParamExists($params, 'oid');
635 daniel-mar 95
 
1293 daniel-mar 96
                $oid = $params['oid'];
635 daniel-mar 97
 
1293 daniel-mar 98
                $query = self::QUERY_GET_OIDINFO_DATA_V1;
635 daniel-mar 99
 
1293 daniel-mar 100
                $payload = array(
101
                        "query" => $query, // we must repeat the query because we want to sign it
102
                        "system_id" => OIDplus::getSystemId(false),
103
                        "oid" => $oid
104
                );
635 daniel-mar 105
 
1293 daniel-mar 106
                $signature = '';
107
                if (!OIDplus::getPkiStatus() || !@openssl_sign(json_encode($payload), $signature, OIDplus::getSystemPrivateKey())) {
108
                        if (!OIDplus::getPkiStatus()) {
109
                                throw new OIDplusException(_L('Error: Your system could not generate a private/public key pair. (OpenSSL is probably missing on your system). Therefore, you cannot register/unregister your OIDplus instance.'));
110
                        } else {
111
                                throw new OIDplusException(_L('Signature failed'));
635 daniel-mar 112
                        }
1293 daniel-mar 113
                }
635 daniel-mar 114
 
1293 daniel-mar 115
                $data = array(
116
                        "payload" => $payload,
117
                        "signature" => base64_encode($signature)
118
                );
635 daniel-mar 119
 
1293 daniel-mar 120
                if (OIDplus::getEditionInfo()['vendor'] != 'ViaThinkSoft') {
121
                        // The oid-info.com import functionality is a confidential API between ViaThinkSoft and oid-info.com and cannot be used in forks of OIDplus
122
                        throw new OIDplusException(_L('This feature is only available in the ViaThinkSoft edition of OIDplus'));
123
                }
699 daniel-mar 124
 
1293 daniel-mar 125
                if (function_exists('gzdeflate')) {
126
                        $compressed = "1";
127
                        $data2 = gzdeflate(json_encode($data));
128
                } else {
129
                        $compressed = "0";
130
                        $data2 = json_encode($data);
131
                }
1149 daniel-mar 132
 
1293 daniel-mar 133
                $res_curl = url_post_contents(
134
                        'https://oidplus.viathinksoft.com/reg2/query.php',
135
                        array(
136
                                "query"      => $query,
137
                                "compressed" => $compressed,
138
                                "data"       => base64_encode($data2)
139
                        )
140
                );
1149 daniel-mar 141
 
1293 daniel-mar 142
                if ($res_curl === false) {
143
                        throw new OIDplusException(_L('Communication with %1 server failed', 'ViaThinkSoft'));
144
                }
635 daniel-mar 145
 
1293 daniel-mar 146
                $json = @json_decode($res_curl, true);
635 daniel-mar 147
 
1293 daniel-mar 148
                if (!$json) {
149
                        return array(
150
                                "status" => -1,
151
                                "error" => _L('JSON reply from ViaThinkSoft decoding error: %1',$res_curl)
152
                        );
153
                }
635 daniel-mar 154
 
1293 daniel-mar 155
                if (isset($json['error']) || ($json['status'] < 0)) {
156
                        return array(
157
                                "status" => -1,
158
                                "error" => $json['error'] ?? _L('Received error status code: %1', $json['status'])
159
                        );
160
                }
635 daniel-mar 161
 
1293 daniel-mar 162
                $errors = array();
163
                list($count_imported_oids, $count_already_existing, $count_errors, $count_warnings) = $this->oidinfoImportXML('<oid-database>'.$json['xml'].'</oid-database>', $errors, $replaceExistingOIDs=false, $orphan_mode=self::ORPHAN_DISALLOW_ORPHANS);
164
                if (count($errors) > 0) {
165
                        return array("status" => -1, "error" => implode("\n",$errors));
166
                } else if ($count_imported_oids <> 1) {
167
                        return array("status" => -1, "error" => _L('Imported %1, but expected to import 1',$count_imported_oids));
635 daniel-mar 168
                } else {
1293 daniel-mar 169
                        return array("status" => 0);
170
                }
171
        }
172
 
173
        /**
174
         * @param string $actionID
175
         * @param array $params
176
         * @return array
177
         * @throws OIDplusException
178
         */
179
        public function action(string $actionID, array $params): array {
180
                if ($actionID == 'import_xml_file') {
181
                        return $this->action_ImportXml($params);
182
                } else if ($actionID == 'import_oidinfo_oid') {
183
                        return $this->action_ImportOidInfo($params);
184
                } else {
1116 daniel-mar 185
                        return parent::action($actionID, $params);
635 daniel-mar 186
                }
187
        }
188
 
1116 daniel-mar 189
        /**
190
         * @param bool $html
191
         * @return void
192
         */
193
        public function init(bool $html=true) {
635 daniel-mar 194
                // Nothing
195
        }
196
 
1116 daniel-mar 197
        /**
198
         * @param string $id
199
         * @param array $out
200
         * @param bool $handled
201
         * @return void
202
         * @throws OIDplusException
203
         */
204
        public function gui(string $id, array &$out, bool &$handled) {
635 daniel-mar 205
                $ary = explode('$', $id);
206
                if (isset($ary[1])) {
207
                        $id = $ary[0];
208
                        $tab = $ary[1];
209
                } else {
210
                        $tab = 'export';
211
                }
212
                if ($id === 'oidplus:oidinfo_compare_export') {
213
                        $handled = true;
214
                        $out['title'] = _L('List OIDs in your system which are missing at oid-info.com');
801 daniel-mar 215
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
635 daniel-mar 216
 
217
                        if (!OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 218
                                throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401);
635 daniel-mar 219
                        }
220
 
221
                        $query = self::QUERY_LIST_OIDINFO_OIDS_V1;
222
 
223
                        $payload = array(
224
                                "query" => $query, // we must repeat the query because we want to sign it
225
                                "system_id" => OIDplus::getSystemId(false),
226
                                "show_all" => 1 // this is required so that the VTS OIDRA gets no false notifications for adding the systems in the directory 1.3.6.1.4.1.37476.30.9
227
                        );
228
 
229
                        $signature = '';
830 daniel-mar 230
                        if (!OIDplus::getPkiStatus() || !@openssl_sign(json_encode($payload), $signature, OIDplus::getSystemPrivateKey())) {
635 daniel-mar 231
                                if (!OIDplus::getPkiStatus()) {
232
                                        throw new OIDplusException(_L('Error: Your system could not generate a private/public key pair. (OpenSSL is probably missing on your system). Therefore, you cannot register/unregister your OIDplus instance.'));
233
                                } else {
234
                                        throw new OIDplusException(_L('Signature failed'));
235
                                }
236
                        }
237
 
238
                        $data = array(
239
                                "payload" => $payload,
240
                                "signature" => base64_encode($signature)
241
                        );
242
 
699 daniel-mar 243
                        if (OIDplus::getEditionInfo()['vendor'] != 'ViaThinkSoft') {
244
                                // The oid-info.com import functionality is a confidential API between ViaThinkSoft and oid-info.com and cannot be used in forks of OIDplus
245
                                throw new OIDplusException(_L('This feature is only available in the ViaThinkSoft edition of OIDplus'));
246
                        }
247
 
635 daniel-mar 248
                        if (function_exists('gzdeflate')) {
249
                                $compressed = "1";
250
                                $data2 = gzdeflate(json_encode($data));
251
                        } else {
252
                                $compressed = "0";
253
                                $data2 = json_encode($data);
254
                        }
1149 daniel-mar 255
 
256
                        $res_curl = url_post_contents(
257
                                'https://oidplus.viathinksoft.com/reg2/query.php',
258
                                array(
259
                                        "query"      => $query,
260
                                        "compressed" => $compressed,
261
                                        "data"       => base64_encode($data2)
262
                                )
263
                        );
264
 
265
                        if ($res_curl === false) {
266
                                throw new OIDplusException(_L('Communication with %1 server failed', 'ViaThinkSoft'));
635 daniel-mar 267
                        }
268
 
269
                        $out['text'] = '<p><a '.OIDplus::gui()->link('oidplus:datatransfer$export').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Go back to data transfer main page').'</a></p>';
270
 
977 daniel-mar 271
                        $json = @json_decode($res_curl, true);
635 daniel-mar 272
 
273
                        if (!$json) {
1206 daniel-mar 274
                                throw new OIDplusException($out['text']._L('JSON reply from ViaThinkSoft decoding error: %1',$res_curl), $out['title']);
635 daniel-mar 275
                        }
276
 
277
                        if (isset($json['error']) || ($json['status'] < 0)) {
278
                                if (isset($json['error'])) {
1206 daniel-mar 279
                                        throw new OIDplusException($out['text']._L('Received error: %1',$json['error']), $out['title']);
635 daniel-mar 280
                                } else {
1206 daniel-mar 281
                                        throw new OIDplusException($out['text']._L('Received error status code: %1',$json['status']), $out['title']);
635 daniel-mar 282
                                }
283
                        }
284
 
285
                        if (isset($json['error']) || ($json['status'] < 0)) {
286
                                $out['text'] .= '<p>'._L('Error: %1',htmlentities($json['error'])).'</p>';
287
                        } else {
288
                                // TODO: If roots were created or deleted recently, we must do a re-query of the registration, so that the "roots" information at the directory service gets refreshed
289
                                if (count($json['roots']) == 0) $out['text'] .= '<p>'._L('In order to use this feature, you need to have at least one (root) OID added in your system, and the system needs to report the newly added root to the directory service (the reporting interval is 1 hour).').'</p>';
290
                                foreach ($json['roots'] as $root) {
291
                                        $oid = $root['oid'];
292
                                        $out['text'] .= '<h2>'._L('Root OID %1',$oid).'</h2>';
293
                                        if ($root['verified']) {
294
                                                $count = 0;
295
                                                $out['text'] .= '<div class="container box"><div id="suboid_table" class="table-responsive">';
296
                                                $out['text'] .= '<table class="table table-bordered table-striped">';
1138 daniel-mar 297
                                                $out['text'] .= '<thead>';
635 daniel-mar 298
                                                $out['text'] .= '<tr><th colspan="3">'._L('Actions').'</th><th>'._L('OID').'</th></tr>';
1138 daniel-mar 299
                                                $out['text'] .= '</thead>';
300
                                                $out['text'] .= '<tbody>';
635 daniel-mar 301
 
302
                                                $lookup_nonoid = array();
303
                                                $row_lookup = array();
304
 
305
                                                $all_local_oids_of_root = array();
306
                                                $res = OIDplus::db()->query("select * from ###objects where confidential <> 1");
307
                                                while ($row = $res->fetch_object()) {
308
                                                        $obj = OIDplusObject::parse($row->id);
309
                                                        if (!$obj) continue; // can happen when object type is not enabled
310
                                                        if ($obj->isConfidential()) continue; // This will also exclude OIDs which are descendants of confidential OIDs
311
                                                        if (strpos($row->id, 'oid:') === 0) {
312
                                                                $oid = substr($row->id,strlen('oid:'));
313
                                                                if (strpos($oid.'.', $root['oid']) === 0) {
314
                                                                        $row_lookup[$oid] = $row;
315
                                                                        $all_local_oids_of_root[] = $oid;
316
                                                                }
317
                                                        } else {
318
                                                                $aids = $obj->getAltIds();
319
                                                                foreach ($aids as $aid) {
1052 daniel-mar 320
                                                                        // TODO: Let Object Type plugins decide if they want that their OID representations get published or not (via a Feature OID implementation)
635 daniel-mar 321
                                                                        if ($aid->getNamespace() == 'oid') {
322
                                                                                $oid = $aid->getId();
323
                                                                                if (strpos($oid.'.', $root['oid']) === 0) {
324
                                                                                        $row_lookup[$oid] = $row;
325
                                                                                        $all_local_oids_of_root[] = $oid;
326
                                                                                        $lookup_nonoid[$oid] = $row->id;
327
                                                                                }
328
                                                                        }
329
                                                                }
330
                                                        }
331
                                                }
332
 
333
                                                natsort($all_local_oids_of_root);
334
                                                foreach ($all_local_oids_of_root as $local_oid) {
335
                                                        if (!in_array($local_oid, $root['children'])) {
336
                                                                $count++;
337
 
338
                                                                // Start: Build oid-info.com create URL
339
 
340
                                                                $row = $row_lookup[$local_oid];
341
 
1371 daniel-mar 342
                                                                $url = "http://oid-info.com/cgi-bin/manage?f=".oid_up($local_oid)."&a=create";
635 daniel-mar 343
 
344
                                                                $tmp = explode('.',$local_oid);
345
                                                                $url .= "&nb=".urlencode(array_pop($tmp));
346
 
347
                                                                $asn1_ids = array();
977 daniel-mar 348
                                                                $res_asn = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($row->id));
349
                                                                while ($row_asn = $res_asn->fetch_object()) {
350
                                                                        $asn1_ids[] = $row_asn->name; // 'unicode-label' is currently not in the standard format (oid.xsd)
635 daniel-mar 351
                                                                }
352
                                                                $url .= "&id=".array_shift($asn1_ids); // urlencode() is already done (see above)
353
                                                                $url .= "&syn_id=".implode('%0A', $asn1_ids); // urlencode() is already done (see above)
354
 
355
                                                                $iri_ids = array();
977 daniel-mar 356
                                                                $res_iri = OIDplus::db()->query("select * from ###iri where oid = ?", array($row->id));
357
                                                                while ($row_iri = $res_iri->fetch_object()) {
358
                                                                        $iri_ids[] = $row_iri->name;
635 daniel-mar 359
                                                                }
360
                                                                $url .= "&unicode_label_list=".implode('%0A', $iri_ids); // urlencode() is already done (see above)
361
 
362
                                                                if (!empty($row->title)) {
363
                                                                        $tmp_description = $row->title;
364
                                                                        $tmp_information = $row->description;/** @phpstan-ignore-line */
365
                                                                        if (trim($row->title) == trim(strip_tags($row->description))) {/** @phpstan-ignore-line */
366
                                                                                $tmp_information = '';
367
                                                                        }
368
                                                                } else if (isset($asn1_ids[0])) {
369
                                                                        $tmp_description = '"'.$asn1_ids[0].'"';
370
                                                                        $tmp_information = $row->description;
371
                                                                } else if (isset($iri_ids[0])) {
372
                                                                        $tmp_description = '"'.$iri_ids[0].'"';
373
                                                                        $tmp_information = $row->description;
374
                                                                } else if (!empty($row->description)) {
375
                                                                        $tmp_description = $row->description;
376
                                                                        $tmp_information = '';
377
                                                                } else if (!empty($row->comment)) {
378
                                                                        $tmp_description = $row->comment;
379
                                                                        $tmp_information = '';
380
                                                                } else {
381
                                                                        $tmp_description = '<i>No description available</i>'; // do not translate
382
                                                                        $tmp_information = '';
383
                                                                }
384
 
385
                                                                if ($tmp_information != '') {
386
                                                                        $tmp_information .= '<br/><br/>';
387
                                                                }
388
 
801 daniel-mar 389
                                                                $tmp_information .= 'See <a href="'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL).'?goto='.urlencode($id).'">more information</a>.'; // do not translate
635 daniel-mar 390
 
391
                                                                if (explode(':',$id,2)[0] != 'oid') {
392
                                                                        $tmp_information = "Object: $id\n\n" . $tmp_information; // do not translate
393
                                                                }
394
 
395
                                                                $url .= "&description=".urlencode(self::repair_relative_links($tmp_description));
396
                                                                $url .= "&info=".urlencode(self::repair_relative_links($tmp_information));
397
 
398
                                                                $url .= "&current_registrant_email=".urlencode($row->ra_email);
399
 
977 daniel-mar 400
                                                                $res_ra = OIDplus::db()->query("select * from ###ra where email = ?", array($row->ra_email));
401
                                                                if ($res_ra->any()) {
402
                                                                        $row_ra = $res_ra->fetch_object();
635 daniel-mar 403
 
404
                                                                        $tmp = array();
977 daniel-mar 405
                                                                        if (!empty($row_ra->personal_name)) {
406
                                                                                $name_ary = split_firstname_lastname($row_ra->personal_name);
635 daniel-mar 407
                                                                                $tmp_first_name = $name_ary[0];
408
                                                                                $tmp_last_name  = $name_ary[1];
977 daniel-mar 409
                                                                                if (!empty($row_ra->ra_name)       ) $tmp[] = $row_ra->ra_name;
410
                                                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
411
                                                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 412
                                                                        } else {
977 daniel-mar 413
                                                                                $tmp_first_name = $row_ra->ra_name;
635 daniel-mar 414
                                                                                $tmp_last_name  = '';
977 daniel-mar 415
                                                                                if (!empty($row_ra->personal_name) ) $tmp[] = $row_ra->personal_name;
416
                                                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
417
                                                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 418
                                                                        }
419
 
420
                                                                        if (empty($tmp_first_name) || empty($tmp_last_name)) {
421
                                                                                $name = self::split_name($tmp_first_name.' '.$tmp_last_name);
422
                                                                                $tmp_first_name = $name[0];
423
                                                                                $tmp_last_name = $name[1];
424
                                                                        }
425
                                                                        $url .= "&current_registrant_first_name=".urlencode($tmp_first_name);
426
                                                                        $url .= "&current_registrant_last_name=".urlencode($tmp_last_name);
427
 
977 daniel-mar 428
                                                                        if ((count($tmp) > 0) && ($tmp[0] == $row_ra->ra_name)) array_shift($tmp);
635 daniel-mar 429
                                                                        $tmp = array_unique($tmp);
430
 
977 daniel-mar 431
                                                                        if (!$row_ra->privacy) {
432
                                                                                if (!empty($row_ra->street))   $tmp[] = $row_ra->street;
433
                                                                                if (!empty($row_ra->zip_town)) $tmp[] = $row_ra->zip_town;
434
                                                                                if (!empty($row_ra->country))  $tmp[] = $row_ra->country;
435
                                                                                $url .= "&current_registrant_tel=".urlencode(!empty($row_ra->phone) ? $row_ra->phone : $row_ra->mobile);
436
                                                                                $url .= "&current_registrant_fax=".urlencode($row_ra->fax);
635 daniel-mar 437
                                                                        }
977 daniel-mar 438
                                                                        if (empty($row_ra->zip_town) && empty($row_ra->country)) {
635 daniel-mar 439
                                                                                // The address is useless if we do neither know city nor country
440
                                                                                // Ignore it
441
                                                                        } else {
442
                                                                                $tmp = self::split_address_country(implode("<br/>", $tmp));
443
                                                                                $url .= "&current_registrant_address=".urlencode($tmp[0]);
444
                                                                                $url .= "&current_registrant_country=".urlencode($tmp[1]);
445
                                                                        }
446
                                                                }
447
                                                                if (!empty($row->updated)) {
448
                                                                        $tmp = explode('-', self::_formatdate($row->updated));
449
                                                                        $url .= "&modification_year=".urlencode($tmp[0]);
450
                                                                        $url .= "&modification_month=".urlencode($tmp[1]);
451
                                                                        $url .= "&modification_day=".urlencode($tmp[2]);
452
                                                                }
453
 
454
                                                                //$url .= "&submitter_last_name=".urlencode($xml->{'submitter'}->{'last-name'});
455
                                                                //$url .= "&submitter_first_name=".urlencode($xml->{'submitter'}->{'first-name'});
456
                                                                //$url .= "&submitter_email=".urlencode($xml->{'submitter'}->{'email'});
457
 
458
                                                                // End: Build oid-info.com create URL
459
 
460
                                                                // Note: "Actions" is at the left, because it has a fixed width, so the user can continue clicking without the links moving if the OID length changes between lines
461
                                                                $out['text'] .= '<tr id="missing_oid_'.str_replace('.','_',$local_oid).'">'.
1130 daniel-mar 462
                                                                '<td><a '.OIDplus::gui()->link($lookup_nonoid[$local_oid] ?? 'oid:' . $local_oid, true).'>'._L('View local OID').'</a></td>'.
635 daniel-mar 463
                                                                '<td><a href="javascript:OIDplusPageAdminOIDInfoExport.removeMissingOid(\''.$local_oid.'\');">'._L('Ignore for now').'</a></td>'.
464
                                                                '<td><a target="_blank" href="'.$url.'">'._L('Add to oid-info.com manually').'</a></td>'.
465
                                                                '<td>'.$local_oid.'</td>'.
466
                                                                '</tr>';
467
                                                        }
468
                                                }
1138 daniel-mar 469
                                                $out['text'] .= '</tbody>';
635 daniel-mar 470
                                                if ($count == 0) {
1138 daniel-mar 471
                                                        $out['text'] .= '<tfoot>';
635 daniel-mar 472
                                                        $out['text'] .= '<tr><td colspan="4">'._L('No missing OIDs found').'</td></tr>';
1138 daniel-mar 473
                                                        $out['text'] .= '</tfoot>';
635 daniel-mar 474
                                                }
475
                                                $out['text'] .= '</table></div></div>';
476
                                        } else {
477
                                                $out['text'] .= '<p>'._L('This root is not validated. Please send an email to %1 in order to request ownership verification of this root OID.',$json['vts_verification_email']).'</p>';
478
                                        }
479
                                }
480
                        }
481
                }
482
 
483
                if ($id === 'oidplus:oidinfo_compare_import') {
484
                        $handled = true;
485
                        $out['title'] = _L('List OIDs at oid-info.com which are missing in your system');
801 daniel-mar 486
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
635 daniel-mar 487
 
488
                        if (!OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 489
                                throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401);
635 daniel-mar 490
                        }
491
 
492
                        $query = self::QUERY_LIST_OIDINFO_OIDS_V1;
493
 
494
                        $payload = array(
495
                                "query" => $query, // we must repeat the query because we want to sign it
496
                                "system_id" => OIDplus::getSystemId(false),
497
                                "show_all" => 0
498
                        );
499
 
500
                        $signature = '';
830 daniel-mar 501
                        if (!OIDplus::getPkiStatus() || !@openssl_sign(json_encode($payload), $signature, OIDplus::getSystemPrivateKey())) {
635 daniel-mar 502
                                if (!OIDplus::getPkiStatus()) {
503
                                        throw new OIDplusException(_L('Error: Your system could not generate a private/public key pair. (OpenSSL is probably missing on your system). Therefore, you cannot register/unregister your OIDplus instance.'));
504
                                } else {
505
                                        throw new OIDplusException(_L('Signature failed'));
506
                                }
507
                        }
508
 
509
                        $data = array(
510
                                "payload" => $payload,
511
                                "signature" => base64_encode($signature)
512
                        );
513
 
699 daniel-mar 514
                        if (OIDplus::getEditionInfo()['vendor'] != 'ViaThinkSoft') {
515
                                // The oid-info.com import functionality is a confidential API between ViaThinkSoft and oid-info.com and cannot be used in forks of OIDplus
516
                                throw new OIDplusException(_L('This feature is only available in the ViaThinkSoft edition of OIDplus'));
517
                        }
518
 
635 daniel-mar 519
                        if (function_exists('gzdeflate')) {
520
                                $compressed = "1";
521
                                $data2 = gzdeflate(json_encode($data));
522
                        } else {
523
                                $compressed = "0";
524
                                $data2 = json_encode($data);
525
                        }
1149 daniel-mar 526
 
527
                        $res = url_post_contents(
528
                                'https://oidplus.viathinksoft.com/reg2/query.php',
529
                                array(
530
                                        "query"      => $query,
531
                                        "compressed" => $compressed,
532
                                        "data"       => base64_encode($data2)
533
                                )
534
                        );
535
 
536
                        if ($res === false) {
537
                                throw new OIDplusException(_L('Communication with %1 server failed', 'ViaThinkSoft'));
635 daniel-mar 538
                        }
539
 
540
                        $out['text'] = '<p><a '.OIDplus::gui()->link('oidplus:datatransfer$import').'><img src="img/arrow_back.png" width="16" alt="'._L('Go back').'"> '._L('Go back to data transfer main page').'</a></p>';
541
 
542
                        $json = @json_decode($res, true);
543
 
544
                        if (!$json) {
1206 daniel-mar 545
                                throw new OIDplusException($out['text']._L('JSON reply from ViaThinkSoft decoding error: %1',$res), $out['title']);
635 daniel-mar 546
                        }
547
 
548
                        if (isset($json['error']) || ($json['status'] < 0)) {
549
                                if (isset($json['error'])) {
1206 daniel-mar 550
                                        throw new OIDplusException($out['text']._L('Received error: %1',$json['error']), $out['title']);
635 daniel-mar 551
                                } else {
1206 daniel-mar 552
                                        throw new OIDplusException($out['text']._L('Received error status code: %1',$json['status']), $out['title']);
635 daniel-mar 553
                                }
554
                        }
555
 
556
                        $all_local_oids = array();
557
                        $res = OIDplus::db()->query("select id from ###objects");
558
                        while ($row = $res->fetch_array()) {
559
                                if (strpos($row['id'], 'oid:') === 0) {
560
                                        $all_local_oids[] = substr($row['id'],strlen('oid:'));
561
                                } else {
562
                                        $obj = OIDplusObject::parse($row['id']);
563
                                        if (!$obj) continue; // can happen when object type is not enabled
564
                                        $aids = $obj->getAltIds();
565
                                        foreach ($aids as $aid) {
1052 daniel-mar 566
                                                // TODO: Let Object Type plugins decide if they want that their OID representations get published or not (via a Feature OID implementation)
635 daniel-mar 567
                                                if ($aid->getNamespace() == 'oid') {
568
                                                        $all_local_oids[] = $aid->getId();
569
                                                }
570
                                        }
571
                                }
572
                        }
573
 
574
                        if (isset($json['error']) || ($json['status'] < 0)) {
575
                                $out['text'] .= '<p>'._L('Error: %1',htmlentities($json['error'])).'</p>';
576
                        } else {
577
                                // TODO: If roots were created or deleted recently, we must do a re-query of the registration, so that the "roots" information at the directory service gets refreshed
578
                                if (count($json['roots']) == 0) $out['text'] .= '<p>'._L('In order to use this feature, you need to have at least one (root) OID added in your system, and the system needs to report the newly added root to the directory service (the reporting interval is 1 hour).').'</p>';
579
                                foreach ($json['roots'] as $root) {
580
                                        $oid = $root['oid'];
581
                                        $out['text'] .= '<h2>'._L('Root OID %1',$oid).'</h2>';
582
                                        // TODO: "Import all" button
583
                                        if ($root['verified']) {
584
                                                $count = 0;
585
                                                $out['text'] .= '<div class="container box"><div id="suboid_table" class="table-responsive">';
586
                                                $out['text'] .= '<table class="table table-bordered table-striped">';
1138 daniel-mar 587
                                                $out['text'] .= '<thead>';
635 daniel-mar 588
                                                $out['text'] .= '<tr><th colspan="4">'._L('Actions').'</th><th>'._L('OID').'</th></tr>';
1138 daniel-mar 589
                                                $out['text'] .= '</thead>';
590
                                                $out['text'] .= '<tbody>';
635 daniel-mar 591
                                                natsort($root['children']);
592
                                                foreach ($root['children'] as $child_oid) {
593
                                                        if (!in_array($child_oid, $all_local_oids)) {
594
                                                                $count++;
595
                                                                // Note: "Actions" is at the left, because it has a fixed width, so the user can continue clicking without the links moving if the OID length changes between lines
596
                                                                $out['text'] .= '<tr id="missing_oid_'.str_replace('.','_',$child_oid).'">'.
1371 daniel-mar 597
                                                                '<td><a target="_blank" href="http://oid-info.com/get/'.$child_oid.'">'._L('View OID at oid-info.com').'</a></td>'.
635 daniel-mar 598
                                                                '<td><a href="javascript:OIDplusPageAdminOIDInfoExport.removeMissingOid(\''.$child_oid.'\');">'._L('Ignore for now').'</a></td>'.
599
                                                                '<td><a href="mailto:admin@oid-info.com">'._L('Report illegal OID').'</a></td>'.
600
                                                                (strpos($child_oid,'1.3.6.1.4.1.37476.30.9.') === 0 ? '<td>&nbsp;</td>' : '<td><a href="javascript:OIDplusPageAdminOIDInfoExport.importMissingOid(\''.$child_oid.'\');">'._L('Import OID').'</a></td>').
601
                                                                '<td>'.$child_oid.'</td>'.
602
                                                                '</tr>';
603
                                                        }
604
                                                }
1138 daniel-mar 605
                                                $out['text'] .= '</tbody>';
635 daniel-mar 606
                                                if ($count == 0) {
1138 daniel-mar 607
                                                        $out['text'] .= '<tfoot>';
635 daniel-mar 608
                                                        $out['text'] .= '<tr><td colspan="5">'._L('No extra OIDs found').'</td></tr>';
1138 daniel-mar 609
                                                        $out['text'] .= '</tfoot>';
635 daniel-mar 610
                                                }
611
                                                $out['text'] .= '</table></div></div>';
612
                                        } else {
613
                                                $out['text'] .= '<p>'._L('This root is not validated. Please send an email to %1 in order to request ownership verification of this root OID.',$json['vts_verification_email']).'</p>';
614
                                        }
615
                                }
616
                        }
617
                }
618
 
619
                if ($id === 'oidplus:datatransfer') {
620
                        $handled = true;
1359 daniel-mar 621
                        $out['title'] = _L('Data Exchange (oid-info.com)');
801 daniel-mar 622
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
635 daniel-mar 623
 
624
                        if (!OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 625
                                throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401);
635 daniel-mar 626
                        }
627
 
890 daniel-mar 628
                        $out['text'] = '<noscript>';
1359 daniel-mar 629
                        $out['text'] .= '<p><font color="red">'._L('You need to enable JavaScript to use this feature.').'</font></p>';
890 daniel-mar 630
                        $out['text'] .= '</noscript>';
635 daniel-mar 631
 
890 daniel-mar 632
                        $out['text'] .= '<br><div id="dataTransferArea" style="visibility: hidden"><div id="dataTransferTab" class="container" style="width:100%;">';
633
 
635 daniel-mar 634
                        // ---------------- Tab control
635
                        $out['text'] .= OIDplus::gui()->tabBarStart();
636
                        $out['text'] .= OIDplus::gui()->tabBarElement('export', _L('Export'), $tab === 'export');
637
                        $out['text'] .= OIDplus::gui()->tabBarElement('import', _L('Import'), $tab === 'import');
638
                        $out['text'] .= OIDplus::gui()->tabBarEnd();
639
                        $out['text'] .= OIDplus::gui()->tabContentStart();
640
                        // ---------------- "Export" tab
641
                        $tabcont  = '<h2>'._L('Generate XML file containing all OIDs').'</h2>';
1371 daniel-mar 642
                        $tabcont .= '<p>'._L('These XML files are following the <a %1>XML schema</a> of <b>oid-info.com</b>. They can be used for various purposes though.','href="http://oid-info.com/oid.xsd" target="_blank"').'</p>';
801 daniel-mar 643
                        $tabcont .= '<p><input type="button" onclick="window.open(\''.OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'oidinfo_export.php\',\'_blank\')" value="'._L('Generate XML (all OIDs)').'"></p>';
644
                        $tabcont .= '<p><input type="button" onclick="window.open(\''.OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'oidinfo_export.php?online=1\',\'_blank\')" value="'._L('Generate XML (only OIDs which do not exist at oid-info.com)').'"></p>';
1371 daniel-mar 645
                        $tabcont .= '<p><a href="http://oid-info.com/submit.htm" target="_blank">'._L('Upload XML files manually to oid-info.com').'</a></p>';
635 daniel-mar 646
                        $tabcont .= '<br><p>'._L('Attention: Do not use this XML Export/Import to exchange, backup or restore data between OIDplus systems!<br>It will cause various loss of information, e.g. because Non-OIDs like GUIDs are converted in OIDs and can\'t be converted back.').'</p>';
1436 daniel-mar 647
                        if (OIDplus::getEditionInfo()['vendor'] == 'ViaThinkSoft') {
648
                                $tabcont .= '<h2>'._L('Automatic export to oid-info.com').'</h2>';
649
                                $privacy_level = OIDplus::config()->getValue('reg_privacy');
650
                                if ($privacy_level == 0) {
651
                                        $tabcont .= '<p>'._L('All your OIDs will automatically submitted to oid-info.com through the remote directory service in regular intervals.').' (<a '.OIDplus::gui()->link('oidplus:srv_registration').'>'._L('Change preference').'</a>)</p>';
652
                                } else {
653
                                        $tabcont .= '<p>'._L('If you set the privacy option to "0" (your system is registered), then all your OIDs will be automatically exported to oid-info.com.').' (<a '.OIDplus::gui()->link('oidplus:srv_registration').'>'._L('Change preference').'</a>)</p>';
654
                                }
635 daniel-mar 655
                        }
656
                        $tabcont .= '<h2>'._L('Comparison with oid-info.com').'</h2>';
657
                        $tabcont .= '<p><a '.OIDplus::gui()->link('oidplus:oidinfo_compare_export').'>'._L('List OIDs in your system which are missing at oid-info.com').'</a></p>';
658
                        $out['text'] .= OIDplus::gui()->tabContentPage('export', $tabcont, $tab === 'export');
659
                        // ---------------- "Import" tab
660
                        $tabcont  = '<h2>'._L('Import XML file').'</h2>';
1371 daniel-mar 661
                        $tabcont .= '<p>'._L('These XML files are following the <a %1>XML schema</a> of <b>oid-info.com</b>.','href="http://oid-info.com/oid.xsd" target="_blank"').'</p>';
635 daniel-mar 662
                        // TODO: we need a waiting animation!
663
                        $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPageAdminOIDInfoExport.uploadXmlFileOnSubmit(this);" enctype="multipart/form-data" id="uploadXmlFileForm">';
1359 daniel-mar 664
                        $tabcont .= '<div>'._L('Choose XML file here').':<br><input type="file" name="userfile" value="" id="userfile">';
635 daniel-mar 665
                        $tabcont .= '<br><input type="submit" value="'._L('Import XML').'"></div>';
666
                        $tabcont .= '</form>';
667
                        $tabcont .= '<br><p>'._L('Attention: Do not use this XML Export/Import to exchange, backup or restore data between OIDplus systems!<br>It will cause various loss of information, e.g. because Non-OIDs like GUIDs are converted in OIDs and can\'t be converted back.').'</p>';
668
                        $tabcont .= '<h2>'._L('Comparison with oid-info.com').'</h2>';
669
                        $tabcont .= '<p><a '.OIDplus::gui()->link('oidplus:oidinfo_compare_import').'>'._L('List OIDs at oid-info.com which are missing in your system').'</a></p>';
670
                        $out['text'] .= OIDplus::gui()->tabContentPage('import', $tabcont, $tab === 'import');
671
                        $out['text'] .= OIDplus::gui()->tabContentEnd();
672
                        // ---------------- Tab control END
673
 
674
                        $out['text'] .= '</div></div><script>$("#dataTransferArea")[0].style.visibility = "visible";</script>';
675
                }
676
        }
677
 
1116 daniel-mar 678
        /**
679
         * @param array $json
680
         * @param string|null $ra_email
681
         * @param bool $nonjs
682
         * @param string $req_goto
683
         * @return bool
684
         * @throws OIDplusException
685
         */
686
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
635 daniel-mar 687
                if (!OIDplus::authUtils()->isAdminLoggedIn()) return false;
688
 
800 daniel-mar 689
                if (file_exists(__DIR__.'/img/main_icon16.png')) {
801 daniel-mar 690
                        $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png';
635 daniel-mar 691
                } else {
692
                        $tree_icon = null; // default icon (folder)
693
                }
694
 
695
                $json[] = array(
696
                        'id' => 'oidplus:datatransfer',
697
                        'icon' => $tree_icon,
1359 daniel-mar 698
                        'text' => _L('Data Exchange (oid-info.com)')
635 daniel-mar 699
                );
700
 
701
                return true;
702
        }
703
 
1116 daniel-mar 704
        /**
705
         * @param string $request
706
         * @return array|false
707
         */
708
        public function tree_search(string $request) {
635 daniel-mar 709
                return false;
710
        }
711
 
1116 daniel-mar 712
        /**
1130 daniel-mar 713
         * @param bool $only_non_existing
1116 daniel-mar 714
         * @return string[]
715
         * @throws OIDplusException
716
         * @throws \OIDInfoException
717
         */
1130 daniel-mar 718
        public static function outputXML(bool $only_non_existing): array {
940 daniel-mar 719
                $out_type = null;
720
                $out_content = '';
721
 
1050 daniel-mar 722
                // This file contains class \OIDInfoAPI.
635 daniel-mar 723
                // We cannot include this in init(), because the init
724
                // of the registration plugin (OIDplusPageAdminRegistration) uses
725
                // OIDplusPageAdminOIDInfoExport::outputXML() before
726
                // OIDplusPageAdminOIDInfoExport::init() ,
727
                // because OIDplusPageAdminRegistration::init() comes first sometimes.
728
                require_once __DIR__ . '/oidinfo_api.inc.php';
729
 
1050 daniel-mar 730
                $oa = new \OIDInfoAPI();
724 daniel-mar 731
                if ($only_non_existing) {
732
                        if (!function_exists('socket_create')) {
733
                                throw new OIDplusException(_L('You must install the PHP "sockets" in order to check for non-existing OIDs.'));
734
                        }
735
                        $oa->addSimplePingProvider('viathinksoft.de:49500');
736
                }
635 daniel-mar 737
 
738
                $email = OIDplus::config()->getValue('admin_email');
739
                if (empty($email)) $email = 'unknown@example.com';
740
 
724 daniel-mar 741
                $sys_title = OIDplus::config()->getValue('system_title');
742
                $name1 = !empty($sys_title) ? $sys_title : 'OIDplus 2.0';
1130 daniel-mar 743
                $name2 = $_SERVER['SERVER_NAME'] ?? 'Export interface';
940 daniel-mar 744
                $out_content .= $oa->xmlAddHeader($name1, $name2, $email); // do not translate
635 daniel-mar 745
 
746
                $params['allow_html'] = true;
747
                $params['allow_illegal_email'] = true; // It should be enabled, because the creator could have used some kind of human-readable anti-spam technique
1050 daniel-mar 748
                $params['soft_correct_behavior'] = \OIDInfoAPI::SOFT_CORRECT_BEHAVIOR_NONE;
635 daniel-mar 749
                $params['do_online_check'] = false; // Flag to disable this online check, because it generates a lot of traffic and runtime.
750
                $params['do_illegality_check'] = true;
751
                $params['do_simpleping_check'] = $only_non_existing;
752
                $params['auto_extract_name'] = '';
753
                $params['auto_extract_url'] = '';
754
                $params['always_output_comment'] = false;
755
                $params['creation_allowed_check'] = $only_non_existing;
756
                $params['tolerant_htmlentities'] = true;
757
                $params['ignore_xhtml_light'] = false;
758
 
759
                $nonConfidential = OIDplusObject::getAllNonConfidential();
760
                natsort($nonConfidential);
761
 
762
                foreach ($nonConfidential as $id) {
977 daniel-mar 763
                        $obj = OIDplusObject::parse($id);
764
                        if ($obj) {
635 daniel-mar 765
                                $elements['identifier'] = array();
977 daniel-mar 766
                                $res_asn = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($id));
767
                                while ($row_asn = $res_asn->fetch_object()) {
768
                                        $elements['identifier'][] = $row_asn->name; // 'unicode-label' is currently not in the standard format (oid.xsd)
635 daniel-mar 769
                                }
770
 
771
                                $elements['unicode-label'] = array();
977 daniel-mar 772
                                $res_iri = OIDplus::db()->query("select * from ###iri where oid = ?", array($id));
773
                                while ($row_iri = $res_iri->fetch_object()) {
774
                                        $elements['unicode-label'][] = $row_iri->name;
635 daniel-mar 775
                                }
776
 
977 daniel-mar 777
                                $title = $obj->getTitle();
778
                                $description = $obj->getDescription();
779
                                $comment = $obj->getComment();
780
                                if (!empty($title)) {
781
                                        $elements['description'] = $title;
782
                                        $elements['information'] = $description;
783
                                        if (trim($title) == trim(strip_tags($description))) {
635 daniel-mar 784
                                                $elements['information'] = '';
785
                                        }
786
                                } else if (isset($elements['identifier'][0])) {
787
                                        $elements['description'] = '"'.$elements['identifier'][0].'"';
977 daniel-mar 788
                                        $elements['information'] = $description;
635 daniel-mar 789
                                } else if (isset($elements['unicode-label'][0])) {
790
                                        $elements['description'] = '"'.$elements['unicode-label'][0].'"';
977 daniel-mar 791
                                        $elements['information'] = $description;
792
                                } else if (!empty($description)) {
793
                                        $elements['description'] = $description;
635 daniel-mar 794
                                        $elements['information'] = '';
977 daniel-mar 795
                                } else if (!empty($comment)) {
796
                                        $elements['description'] = $comment;
635 daniel-mar 797
                                        $elements['information'] = '';
798
                                } else {
799
                                        $elements['description'] = '<i>No description available</i>'; // do not translate
800
                                        $elements['information'] = '';
801
                                }
802
 
803
                                if ($elements['information'] != '') {
804
                                        $elements['information'] .= '<br/><br/>';
805
                                }
806
 
801 daniel-mar 807
                                $elements['information'] .= 'See <a href="'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL).'?goto='.urlencode($id).'">more information</a>.'; // do not translate
635 daniel-mar 808
 
809
                                if (explode(':',$id,2)[0] != 'oid') {
810
                                        $elements['information'] = "Object: $id\n\n" . $elements['information']; // do not translate
811
                                }
812
 
813
                                $elements['description'] = self::repair_relative_links($elements['description']);
814
                                $elements['information'] = self::repair_relative_links($elements['information']);
815
 
816
                                $elements['first-registrant']['first-name'] = '';
817
                                $elements['first-registrant']['last-name'] = '';
818
                                $elements['first-registrant']['address'] = '';
819
                                $elements['first-registrant']['email'] = '';
820
                                $elements['first-registrant']['phone'] = '';
821
                                $elements['first-registrant']['fax'] = '';
1142 daniel-mar 822
                                $create_ts = $obj->getCreatedTime();
823
                                $elements['first-registrant']['creation-date'] = $create_ts ? self::_formatdate($create_ts) : '';
635 daniel-mar 824
 
825
                                $elements['current-registrant']['first-name'] = '';
826
                                $elements['current-registrant']['last-name'] = '';
977 daniel-mar 827
                                $elements['current-registrant']['email'] = $obj->getRaMail();
635 daniel-mar 828
                                $elements['current-registrant']['phone'] = '';
829
                                $elements['current-registrant']['fax'] = '';
830
                                $elements['current-registrant']['address'] = '';
831
 
977 daniel-mar 832
                                $res_ra = OIDplus::db()->query("select * from ###ra where email = ?", array($obj->getRaMail()));
833
                                if ($res_ra->any()) {
834
                                        $row_ra = $res_ra->fetch_object();
635 daniel-mar 835
 
836
                                        $tmp = array();
977 daniel-mar 837
                                        if (!empty($row_ra->personal_name)) {
838
                                                $name_ary = split_firstname_lastname($row_ra->personal_name);
635 daniel-mar 839
                                                $elements['current-registrant']['first-name'] = $name_ary[0];
840
                                                $elements['current-registrant']['last-name']  = $name_ary[1];
977 daniel-mar 841
                                                if (!empty($row_ra->ra_name)       ) $tmp[] = $row_ra->ra_name;
842
                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
843
                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 844
                                        } else {
977 daniel-mar 845
                                                $elements['current-registrant']['first-name'] = $row_ra->ra_name;
635 daniel-mar 846
                                                $elements['current-registrant']['last-name']  = '';
977 daniel-mar 847
                                                if (!empty($row_ra->personal_name) ) $tmp[] = $row_ra->personal_name;
848
                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
849
                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 850
                                        }
851
 
977 daniel-mar 852
                                        if ((count($tmp) > 0) && ($tmp[0] == $row_ra->ra_name)) array_shift($tmp);
635 daniel-mar 853
                                        $tmp = array_unique($tmp);
854
 
977 daniel-mar 855
                                        if (!$row_ra->privacy) {
856
                                                if (!empty($row_ra->street))   $tmp[] = $row_ra->street;
857
                                                if (!empty($row_ra->zip_town)) $tmp[] = $row_ra->zip_town;
858
                                                if (!empty($row_ra->country))  $tmp[] = $row_ra->country;
859
                                                $elements['current-registrant']['phone'] = !empty($row_ra->phone) ? $row_ra->phone : $row_ra->mobile;
860
                                                $elements['current-registrant']['fax'] = $row_ra->fax;
635 daniel-mar 861
                                        }
977 daniel-mar 862
                                        if (empty($row_ra->zip_town) && empty($row_ra->country)) {
635 daniel-mar 863
                                                // The address is useless if we do neither know city nor country
864
                                                // Ignore it
865
                                                $elements['current-registrant']['address'] = '';
866
                                        } else {
867
                                                $elements['current-registrant']['address'] = implode("<br/>", $tmp);
868
                                        }
869
                                }
1142 daniel-mar 870
                                $update_ts = $obj->getUpdatedTime();
871
                                $elements['current-registrant']['modification-date'] = $update_ts ? self::_formatdate($update_ts) : '';
635 daniel-mar 872
 
873
                                // Request from O.D. 20 May 2019: First registrant should not be empty (especially for cases where Creation and Modify Dates are the same)
874
                                // Actually, this is a problem because we don't know the first registrant.
875
                                // However, since oidinfo gets their XML very fast (if using registration), it is likely that the reported RA is still the same...
876
                                // ... and changes at the RA are not reported to oid-info.com anyways - the XML is only for creation
877
 
878
                                $elements['first-registrant']['first-name'] = $elements['current-registrant']['first-name'];
879
                                $elements['first-registrant']['last-name']  = $elements['current-registrant']['last-name'];
880
                                $elements['first-registrant']['address']    = $elements['current-registrant']['address'];
881
                                $elements['first-registrant']['email']      = $elements['current-registrant']['email'];
882
                                $elements['first-registrant']['phone']      = $elements['current-registrant']['phone'];
883
                                $elements['first-registrant']['fax']        = $elements['current-registrant']['fax'];
884
 
885
                                $elements['current-registrant']['first-name'] = '';
886
                                $elements['current-registrant']['last-name'] = '';
887
                                $elements['current-registrant']['address'] = '';
888
                                $elements['current-registrant']['email'] = '';
889
                                $elements['current-registrant']['phone'] = '';
890
                                $elements['current-registrant']['fax'] = '';
891
                                $elements['current-registrant']['modification-date'] = '';
892
 
893
                                // End request O.D. 20 May 2019
894
 
895
                                list($ns,$id) = explode(':',$obj->nodeId());
896
                                if ($ns == 'oid') {
940 daniel-mar 897
                                        $out_content .= $oa->createXMLEntry($id, $elements, $params, $comment=$obj->nodeId());
635 daniel-mar 898
                                } else {
899
                                        $alt_ids = $obj->getAltIds(); // TODO: slow!
900
                                        foreach ($alt_ids as $alt_id) {
901
                                                $ns = $alt_id->getNamespace();
902
                                                $id = $alt_id->getId();
903
                                                $desc = $alt_id->getDescription();
904
                                                if ($ns == 'oid') {
1052 daniel-mar 905
                                                        // TODO: Let Object Type plugins decide if they want that their OID representations get published or not (via a Feature OID implementation)
635 daniel-mar 906
                                                        if (strpos($id, '2.25.') === 0) continue; // don't spam the uuid arc with GUID objects
1432 daniel-mar 907
                                                        if (strpos($id, '1.2.840.113556.1.8000.2554.') === 0) continue; // don't spam the uuid arc with GUID objects
908
                                                        if (strpos($id, '1.3.6.1.4.1.54392.1.') === 0) continue; // don't spam the uuid arc with GUID objects
909
                                                        if (strpos($id, '1.3.6.1.4.1.54392.2.') === 0) continue; // don't spam the uuid arc with GUID objects
910
                                                        if (strpos($id, '1.3.6.1.4.1.54392.3.') === 0) continue; // don't spam the uuid arc with GUID objects
940 daniel-mar 911
                                                        $out_content .= $oa->createXMLEntry($id, $elements, $params, $comment=$obj->nodeId());
635 daniel-mar 912
                                                }
913
                                        }
914
                                }
915
                        }
916
                }
917
 
940 daniel-mar 918
                $out_content .= $oa->xmlAddFooter();
919
 
920
                $out_type = 'text/xml';
921
                return array($out_content, $out_type);
635 daniel-mar 922
        }
923
 
1116 daniel-mar 924
        /**
1125 daniel-mar 925
         * @param string $str
926
         * @return string
1116 daniel-mar 927
         */
1125 daniel-mar 928
        private static function _formatdate(string $str): string {
635 daniel-mar 929
                $str = explode(' ',$str)[0];
930
                if ($str == '0000-00-00') $str = '';
931
                return $str;
932
        }
933
 
1116 daniel-mar 934
        /**
1130 daniel-mar 935
         * @param string $str
936
         * @return string
1116 daniel-mar 937
         * @throws OIDplusException
938
         */
1130 daniel-mar 939
        private static function repair_relative_links(string $str): string {
940
                return preg_replace_callback('@(href\s*=\s*([\'"]))(.+)(\\2)@ismU', function($treffer) {
635 daniel-mar 941
                        $url = $treffer[3];
942
                        if ((stripos($url,'http:') !== 0) && (stripos($url,'https:') !== 0) && (stripos($url,'ftp:') !== 0)) {
943
                                if (stripos($url,'www.') === 0) {
944
                                        $url .= 'http://' . $url;
945
                                } else {
1381 daniel-mar 946
                                        $url = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL) . $url;
635 daniel-mar 947
                                }
948
                        }
949
                        return $treffer[1].$url.$treffer[4];
950
                }, $str);
951
        }
952
 
1116 daniel-mar 953
        /**
1125 daniel-mar 954
         * @param string $address
955
         * @return string[]
1116 daniel-mar 956
         */
1125 daniel-mar 957
        private static function split_address_country(string $address): array {
635 daniel-mar 958
                global $oidinfo_countries;
959
                $ary = explode("\n", $address);
960
                $last_line = array_pop($ary);
961
                $rest = implode("\n", $ary);
962
                if (isset($oidinfo_countries[$last_line])) {
963
                        return array($rest, $oidinfo_countries[$last_line]);
964
                } else {
965
                        return array($rest."\n".$last_line, '');
966
                }
967
        }
968
 
1116 daniel-mar 969
        /**
1130 daniel-mar 970
         * @param string $name
1116 daniel-mar 971
         * @return array
972
         */
1130 daniel-mar 973
        private static function split_name(string $name): array {
635 daniel-mar 974
                // uses regex that accepts any word character or hyphen in last name
975
                // https://stackoverflow.com/questions/13637145/split-text-string-into-first-and-last-name-in-php
976
                $name = trim($name);
977
                $last_name = (strpos($name, ' ') === false) ? '' : preg_replace('#.*\s([\w-]*)$#', '$1', $name);
978
                $first_name = trim( preg_replace('#'.preg_quote($last_name,'#').'#', '', $name ) );
979
                return array($first_name, $last_name);
980
        }
981
 
982
        /*protected*/ const ORPHAN_IGNORE = 0;
983
        /*protected*/ const ORPHAN_AUTO_DEORPHAN = 1;
984
        /*protected*/ const ORPHAN_DISALLOW_ORPHANS = 2;
985
 
1116 daniel-mar 986
        /**
1130 daniel-mar 987
         * @param string $xml_contents
988
         * @param array $errors
989
         * @param bool $replaceExistingOIDs
990
         * @param int $orphan_mode
1125 daniel-mar 991
         * @return int[]
1116 daniel-mar 992
         * @throws OIDplusException
993
         */
1130 daniel-mar 994
        protected function oidinfoImportXML(string $xml_contents, array &$errors, bool $replaceExistingOIDs=false, int $orphan_mode=self::ORPHAN_AUTO_DEORPHAN): array {
635 daniel-mar 995
                // TODO: Implement RA import (let the user decide)
996
                // TODO: Let the user decide about $replaceExistingOIDs
997
                // TODO: Let the user decide if "created=now" should be set (this is good when the XML files is created by the user itself to do bulk-inserts)
998
 
999
                $xml_contents = str_replace('<description>', '<description><![CDATA[', $xml_contents);
1000
                $xml_contents = str_replace('</description>', ']]></description>', $xml_contents);
1001
 
1002
                $xml_contents = str_replace('<information>', '<information><![CDATA[', $xml_contents);
1003
                $xml_contents = str_replace('</information>', ']]></information>', $xml_contents);
1004
 
1005
                $xml = @simplexml_load_string($xml_contents);
1006
 
1007
                $count_already_existing = 0;
1008
                $count_errors = 0;
1009
                $count_warnings = 0;
1010
 
1011
                if (!$xml) {
1012
                        $errors[] = _L('Cannot read XML data. The XML file is probably invalid.');
1013
                        $count_errors++;
1014
                        return array(0, 0, 1, 0);
1015
                }
1016
 
1017
                $ok_oids = array();
1018
 
1019
                foreach ($xml->oid as $xoid) {
1020
 
1021
                        if (isset($xoid->{'dot-notation'})) {
1022
                                $dot_notation = $xoid->{'dot-notation'}->__toString();
1023
                        } else if (isset($xoid->{'asn1-notation'})) {
1024
                                $dot_notation = asn1_to_dot($xoid->{'asn1-notation'}->__toString());
1025
                        } else {
1026
                                $errors[] = _L('Cannot find dot notation because fields asn1-notation and dot-notation are both not existing');
1027
                                $count_errors++;
1028
                                continue;
1029
                        }
1030
 
1031
                        $id = "oid:$dot_notation";
1433 daniel-mar 1032
                        $title = isset($xoid->{'description'}) ? html_entity_decode(strip_tags($xoid->{'description'}->__toString())) : '';
635 daniel-mar 1033
                        $info = isset($xoid->{'description'}) ? $xoid->{'information'}->__toString() : '';
1034
 
991 daniel-mar 1035
                        // For ASN.1 definitions, "Description" is filled with the definition and "Information" is usually empty
1036
                        if (strpos($title,'<br') !== false) {
1037
                                $info = $title . $info;
1038
                                $title = explode(' ',$title)[0];
1039
                        }
1040
 
635 daniel-mar 1041
                        if (isset($xoid->{'current-registrant'}->email)) {
1042
                                $ra = $xoid->{'current-registrant'}->email->__toString();
1043
                        } else if (isset($xoid->{'first-registrant'}->email)) {
1044
                                $ra = $xoid->{'first-registrant'}->email->__toString();
1045
                        } else {
1046
                                $ra = '';
1047
                        }
1048
 
1049
                        if (!oid_valid_dotnotation($dot_notation, false, false)) {
1050
                                $errors[] = _L('Ignored OID %1 because its dot notation is illegal or was not found',$dot_notation);
1051
                                $count_errors++;
1052
                                continue;
1053
                        }
1054
 
1055
                        $parent = 'oid:'.oid_up($dot_notation);
1056
 
1057
                        if ($orphan_mode === self::ORPHAN_DISALLOW_ORPHANS) {
977 daniel-mar 1058
                                if (!OIDplusObject::exists($parent)) {
635 daniel-mar 1059
                                        $errors[] = _L('Cannot import %1, because its parent is not in the database.',$dot_notation);
1060
                                        $count_errors++;
1061
                                        continue;
1062
                                }
1063
                        }
1064
 
1433 daniel-mar 1065
                        $obj_test = OIDplusObject::findFitting($id);
1066
                        if ($obj_test) {
1067
                                if ($replaceExistingOIDs) {
1068
                                        OIDplus::db()->query("delete from ###objects where id = ?", array($id));
1069
                                        OIDplus::db()->query("delete from ###asn1id where oid = ?", array($id));
1070
                                        OIDplus::db()->query("delete from ###iri where oid = ?", array($id));
1071
                                } else {
1072
                                        //$errors[] = "Ignore OID '$dot_notation' because it already exists";
1073
                                        //$count_errors++;
1074
                                        $count_already_existing++;
1075
                                        continue;
1231 daniel-mar 1076
                                }
1433 daniel-mar 1077
                        }
978 daniel-mar 1078
 
1433 daniel-mar 1079
                        // TODO: we can probably get the created and modified timestamp from oid-info.com XML
1080
                        OIDplus::db()->query("insert into ###objects (id, parent, title, description, confidential, ra_email) values (?, ?, ?, ?, ?, ?)", array($id, $parent, $title, $info, false, $ra));
1231 daniel-mar 1081
 
978 daniel-mar 1082
                        OIDplusObject::resetObjectInformationCache();
1083
 
635 daniel-mar 1084
                        $this_oid_has_warnings = false;
1085
 
1086
                        // ---------------------------------------------------------------------
1087
 
1088
                        $asn1ids = array();
1089
                        if (isset($xoid->{'identifier'})) {
1090
                                $asn1ids[] = $xoid->{'identifier'}->__toString();
1091
                        }
1092
                        if (isset($xoid->{'asn1-notation'})) {
1093
                                $last_id = asn1_last_identifier($xoid->{'asn1-notation'}->__toString());
1094
                                if ($last_id) {
1095
                                        $asn1ids[] = $last_id;
1096
                                }
1097
                        }
1098
                        if (isset($xoid->{'synonymous-identifier'})) {
1099
                                foreach ($xoid->{'synonymous-identifier'} as $synid) {
1100
                                        $asn1ids[] = $synid->__toString();
1101
                                }
1102
                        }
1103
                        $asn1ids = array_unique($asn1ids);
1104
                        foreach ($asn1ids as $asn1id) {
1105
                                if (!oid_id_is_valid($asn1id)) {
1106
                                        $errors[] = _L('Warning').' ['._L('OID %1',$dot_notation).']: '._L('Ignored alphanumeric identifier %1, because it is invalid',$asn1id);
1107
                                        $this_oid_has_warnings = true;
1108
                                } else {
1302 daniel-mar 1109
                                        OIDplus::db()->query("delete from ###asn1id where oid = ? and name = ?", array($id, $asn1id)); // Attention: Requires case-SENSITIVE database collation!!
635 daniel-mar 1110
                                        OIDplus::db()->query("insert into ###asn1id (oid, name) values (?, ?)", array($id, $asn1id));
1111
                                }
1112
                        }
1113
 
1114
                        // ---------------------------------------------------------------------
1115
 
1116
                        if (isset($xoid->{'unicode-label'})) {
1117
                                $iris = array();
1118
                                foreach ($xoid->{'unicode-label'} as $iri) {
1119
                                        $iris[] = $iri->__toString();
1120
                                }
1121
                                $iris = array_unique($iris);
1122
                                foreach ($iris as $iri) {
1123
                                        if (!iri_arc_valid($iri, false)) {
1124
                                                $errors[] = _L('Warning').' ['._L('OID %1',$dot_notation).']: '._L('Ignored Unicode label %1, because it is invalid',$iri);
1125
                                                $this_oid_has_warnings = true;
1126
                                        } else {
1302 daniel-mar 1127
                                                OIDplus::db()->query("delete from ###iri where oid = ? and name = ?", array($id, $iri)); // Attention: Requires case-SENSITIVE database collation!!
635 daniel-mar 1128
                                                OIDplus::db()->query("insert into ###iri (oid, name) values (?, ?)", array($id, $iri));
1129
                                        }
1130
                                }
1131
                        }
1132
 
1133
                        if ($this_oid_has_warnings) $count_warnings++;
1134
                        $ok_oids[] = $id;
1135
                }
1136
 
1137
                // De-orphanize
978 daniel-mar 1138
                //if ($orphan_mode === self::ORPHAN_AUTO_DEORPHAN) {
1139
                //      OIDplus::db()->query("update ###objects set parent = 'oid:' where parent like 'oid:%' and parent not in (select id from ###objects)");
1140
                //      OIDplusObject::resetObjectInformationCache();
1141
                //}
635 daniel-mar 1142
                foreach ($ok_oids as $id) {
1143
                        // De-orphanize if neccessary
1144
                        if ($orphan_mode === self::ORPHAN_AUTO_DEORPHAN) {
1145
                                $res = OIDplus::db()->query("select * from ###objects where id = ? and parent not in (select id from ###objects)", array($id));
790 daniel-mar 1146
                                if ($res->any()) {
635 daniel-mar 1147
                                        $errors[] = _L("%1 was de-orphaned (placed as root OID) because its parent is not existing.",$id);
1148
                                        $count_warnings++;
1149
                                        OIDplus::db()->query("update ###objects set parent = 'oid:' where id = ? and parent not in (select id from ###objects)", array($id));
978 daniel-mar 1150
                                        OIDplusObject::resetObjectInformationCache();
635 daniel-mar 1151
                                }
1152
                        }
1153
 
1154
                        // We do the logging at the end, otherwise SUPOIDRA() might not work correctly if the OIDs were not imported in order or if there were orphans
1267 daniel-mar 1155
                        OIDplus::logger()->log("V2:[INFO]OID(%1)+[INFO]SUPOID(%1)+[INFO]SUPOIDRA(%1)+[OK/INFO]A", "Object '%1' was automatically created by the XML import tool", $id);
635 daniel-mar 1156
                }
1157
 
1158
                $count_imported_oids = count($ok_oids);
1159
 
1160
                return array($count_imported_oids, $count_already_existing, $count_errors, $count_warnings);
1161
 
1162
        }
1163
 
1116 daniel-mar 1164
        /**
1131 daniel-mar 1165
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8
1130 daniel-mar 1166
         * @param string|null $user
1116 daniel-mar 1167
         * @return array
1168
         * @throws OIDplusException
1169
         */
1130 daniel-mar 1170
        public function getNotifications(string $user=null): array {
1000 daniel-mar 1171
                $notifications = array();
1172
                if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) {
1181 daniel-mar 1173
                        if (!url_post_contents_available(true, $reason)) {
1000 daniel-mar 1174
                                $title = _L('OID-Info.com import/export');
1189 daniel-mar 1175
                                $notifications[] = new OIDplusNotification('ERR', _L('OIDplus plugin "%1" is enabled, but OIDplus cannot connect to the Internet.', '<a '.OIDplus::gui()->link('oidplus:datatransfer').'>'.htmlentities($title).'</a>').' '.$reason);
1000 daniel-mar 1176
                        }
1177
                }
1178
                return $notifications;
1179
        }
1180
 
635 daniel-mar 1181
}