Subversion Repositories oidplus

Rev

Rev 1363 | Rev 1375 | 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>';
647
                        $tabcont .= '<h2>'._L('Automatic export to oid-info.com').'</h2>';
648
                        $privacy_level = OIDplus::config()->getValue('reg_privacy');
649
                        if ($privacy_level == 0) {
650
                                $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>';
651
                        } else {
652
                                $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>';
653
                        }
654
                        $tabcont .= '<h2>'._L('Comparison with oid-info.com').'</h2>';
655
                        $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>';
656
                        $out['text'] .= OIDplus::gui()->tabContentPage('export', $tabcont, $tab === 'export');
657
                        // ---------------- "Import" tab
658
                        $tabcont  = '<h2>'._L('Import XML file').'</h2>';
1371 daniel-mar 659
                        $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 660
                        // TODO: we need a waiting animation!
661
                        $tabcont .= '<form action="javascript:void(0);" onsubmit="return OIDplusPageAdminOIDInfoExport.uploadXmlFileOnSubmit(this);" enctype="multipart/form-data" id="uploadXmlFileForm">';
1359 daniel-mar 662
                        $tabcont .= '<div>'._L('Choose XML file here').':<br><input type="file" name="userfile" value="" id="userfile">';
635 daniel-mar 663
                        $tabcont .= '<br><input type="submit" value="'._L('Import XML').'"></div>';
664
                        $tabcont .= '</form>';
665
                        $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>';
666
                        $tabcont .= '<h2>'._L('Comparison with oid-info.com').'</h2>';
667
                        $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>';
668
                        $out['text'] .= OIDplus::gui()->tabContentPage('import', $tabcont, $tab === 'import');
669
                        $out['text'] .= OIDplus::gui()->tabContentEnd();
670
                        // ---------------- Tab control END
671
 
672
                        $out['text'] .= '</div></div><script>$("#dataTransferArea")[0].style.visibility = "visible";</script>';
673
                }
674
        }
675
 
1116 daniel-mar 676
        /**
677
         * @param array $json
678
         * @param string|null $ra_email
679
         * @param bool $nonjs
680
         * @param string $req_goto
681
         * @return bool
682
         * @throws OIDplusException
683
         */
684
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
635 daniel-mar 685
                if (!OIDplus::authUtils()->isAdminLoggedIn()) return false;
686
 
800 daniel-mar 687
                if (file_exists(__DIR__.'/img/main_icon16.png')) {
801 daniel-mar 688
                        $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png';
635 daniel-mar 689
                } else {
690
                        $tree_icon = null; // default icon (folder)
691
                }
692
 
693
                $json[] = array(
694
                        'id' => 'oidplus:datatransfer',
695
                        'icon' => $tree_icon,
1359 daniel-mar 696
                        'text' => _L('Data Exchange (oid-info.com)')
635 daniel-mar 697
                );
698
 
699
                return true;
700
        }
701
 
1116 daniel-mar 702
        /**
703
         * @param string $request
704
         * @return array|false
705
         */
706
        public function tree_search(string $request) {
635 daniel-mar 707
                return false;
708
        }
709
 
1116 daniel-mar 710
        /**
1130 daniel-mar 711
         * @param bool $only_non_existing
1116 daniel-mar 712
         * @return string[]
713
         * @throws OIDplusException
714
         * @throws \OIDInfoException
715
         */
1130 daniel-mar 716
        public static function outputXML(bool $only_non_existing): array {
940 daniel-mar 717
                $out_type = null;
718
                $out_content = '';
719
 
1050 daniel-mar 720
                // This file contains class \OIDInfoAPI.
635 daniel-mar 721
                // We cannot include this in init(), because the init
722
                // of the registration plugin (OIDplusPageAdminRegistration) uses
723
                // OIDplusPageAdminOIDInfoExport::outputXML() before
724
                // OIDplusPageAdminOIDInfoExport::init() ,
725
                // because OIDplusPageAdminRegistration::init() comes first sometimes.
726
                require_once __DIR__ . '/oidinfo_api.inc.php';
727
 
1050 daniel-mar 728
                $oa = new \OIDInfoAPI();
724 daniel-mar 729
                if ($only_non_existing) {
730
                        if (!function_exists('socket_create')) {
731
                                throw new OIDplusException(_L('You must install the PHP "sockets" in order to check for non-existing OIDs.'));
732
                        }
733
                        $oa->addSimplePingProvider('viathinksoft.de:49500');
734
                }
635 daniel-mar 735
 
736
                $email = OIDplus::config()->getValue('admin_email');
737
                if (empty($email)) $email = 'unknown@example.com';
738
 
724 daniel-mar 739
                $sys_title = OIDplus::config()->getValue('system_title');
740
                $name1 = !empty($sys_title) ? $sys_title : 'OIDplus 2.0';
1130 daniel-mar 741
                $name2 = $_SERVER['SERVER_NAME'] ?? 'Export interface';
940 daniel-mar 742
                $out_content .= $oa->xmlAddHeader($name1, $name2, $email); // do not translate
635 daniel-mar 743
 
744
                $params['allow_html'] = true;
745
                $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 746
                $params['soft_correct_behavior'] = \OIDInfoAPI::SOFT_CORRECT_BEHAVIOR_NONE;
635 daniel-mar 747
                $params['do_online_check'] = false; // Flag to disable this online check, because it generates a lot of traffic and runtime.
748
                $params['do_illegality_check'] = true;
749
                $params['do_simpleping_check'] = $only_non_existing;
750
                $params['auto_extract_name'] = '';
751
                $params['auto_extract_url'] = '';
752
                $params['always_output_comment'] = false;
753
                $params['creation_allowed_check'] = $only_non_existing;
754
                $params['tolerant_htmlentities'] = true;
755
                $params['ignore_xhtml_light'] = false;
756
 
757
                $nonConfidential = OIDplusObject::getAllNonConfidential();
758
                natsort($nonConfidential);
759
 
760
                foreach ($nonConfidential as $id) {
977 daniel-mar 761
                        $obj = OIDplusObject::parse($id);
762
                        if ($obj) {
635 daniel-mar 763
                                $elements['identifier'] = array();
977 daniel-mar 764
                                $res_asn = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($id));
765
                                while ($row_asn = $res_asn->fetch_object()) {
766
                                        $elements['identifier'][] = $row_asn->name; // 'unicode-label' is currently not in the standard format (oid.xsd)
635 daniel-mar 767
                                }
768
 
769
                                $elements['unicode-label'] = array();
977 daniel-mar 770
                                $res_iri = OIDplus::db()->query("select * from ###iri where oid = ?", array($id));
771
                                while ($row_iri = $res_iri->fetch_object()) {
772
                                        $elements['unicode-label'][] = $row_iri->name;
635 daniel-mar 773
                                }
774
 
977 daniel-mar 775
                                $title = $obj->getTitle();
776
                                $description = $obj->getDescription();
777
                                $comment = $obj->getComment();
778
                                if (!empty($title)) {
779
                                        $elements['description'] = $title;
780
                                        $elements['information'] = $description;
781
                                        if (trim($title) == trim(strip_tags($description))) {
635 daniel-mar 782
                                                $elements['information'] = '';
783
                                        }
784
                                } else if (isset($elements['identifier'][0])) {
785
                                        $elements['description'] = '"'.$elements['identifier'][0].'"';
977 daniel-mar 786
                                        $elements['information'] = $description;
635 daniel-mar 787
                                } else if (isset($elements['unicode-label'][0])) {
788
                                        $elements['description'] = '"'.$elements['unicode-label'][0].'"';
977 daniel-mar 789
                                        $elements['information'] = $description;
790
                                } else if (!empty($description)) {
791
                                        $elements['description'] = $description;
635 daniel-mar 792
                                        $elements['information'] = '';
977 daniel-mar 793
                                } else if (!empty($comment)) {
794
                                        $elements['description'] = $comment;
635 daniel-mar 795
                                        $elements['information'] = '';
796
                                } else {
797
                                        $elements['description'] = '<i>No description available</i>'; // do not translate
798
                                        $elements['information'] = '';
799
                                }
800
 
801
                                if ($elements['information'] != '') {
802
                                        $elements['information'] .= '<br/><br/>';
803
                                }
804
 
801 daniel-mar 805
                                $elements['information'] .= 'See <a href="'.OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL).'?goto='.urlencode($id).'">more information</a>.'; // do not translate
635 daniel-mar 806
 
807
                                if (explode(':',$id,2)[0] != 'oid') {
808
                                        $elements['information'] = "Object: $id\n\n" . $elements['information']; // do not translate
809
                                }
810
 
811
                                $elements['description'] = self::repair_relative_links($elements['description']);
812
                                $elements['information'] = self::repair_relative_links($elements['information']);
813
 
814
                                $elements['first-registrant']['first-name'] = '';
815
                                $elements['first-registrant']['last-name'] = '';
816
                                $elements['first-registrant']['address'] = '';
817
                                $elements['first-registrant']['email'] = '';
818
                                $elements['first-registrant']['phone'] = '';
819
                                $elements['first-registrant']['fax'] = '';
1142 daniel-mar 820
                                $create_ts = $obj->getCreatedTime();
821
                                $elements['first-registrant']['creation-date'] = $create_ts ? self::_formatdate($create_ts) : '';
635 daniel-mar 822
 
823
                                $elements['current-registrant']['first-name'] = '';
824
                                $elements['current-registrant']['last-name'] = '';
977 daniel-mar 825
                                $elements['current-registrant']['email'] = $obj->getRaMail();
635 daniel-mar 826
                                $elements['current-registrant']['phone'] = '';
827
                                $elements['current-registrant']['fax'] = '';
828
                                $elements['current-registrant']['address'] = '';
829
 
977 daniel-mar 830
                                $res_ra = OIDplus::db()->query("select * from ###ra where email = ?", array($obj->getRaMail()));
831
                                if ($res_ra->any()) {
832
                                        $row_ra = $res_ra->fetch_object();
635 daniel-mar 833
 
834
                                        $tmp = array();
977 daniel-mar 835
                                        if (!empty($row_ra->personal_name)) {
836
                                                $name_ary = split_firstname_lastname($row_ra->personal_name);
635 daniel-mar 837
                                                $elements['current-registrant']['first-name'] = $name_ary[0];
838
                                                $elements['current-registrant']['last-name']  = $name_ary[1];
977 daniel-mar 839
                                                if (!empty($row_ra->ra_name)       ) $tmp[] = $row_ra->ra_name;
840
                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
841
                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 842
                                        } else {
977 daniel-mar 843
                                                $elements['current-registrant']['first-name'] = $row_ra->ra_name;
635 daniel-mar 844
                                                $elements['current-registrant']['last-name']  = '';
977 daniel-mar 845
                                                if (!empty($row_ra->personal_name) ) $tmp[] = $row_ra->personal_name;
846
                                                if (!empty($row_ra->office)        ) $tmp[] = $row_ra->office;
847
                                                if (!empty($row_ra->organization)  ) $tmp[] = $row_ra->organization;
635 daniel-mar 848
                                        }
849
 
977 daniel-mar 850
                                        if ((count($tmp) > 0) && ($tmp[0] == $row_ra->ra_name)) array_shift($tmp);
635 daniel-mar 851
                                        $tmp = array_unique($tmp);
852
 
977 daniel-mar 853
                                        if (!$row_ra->privacy) {
854
                                                if (!empty($row_ra->street))   $tmp[] = $row_ra->street;
855
                                                if (!empty($row_ra->zip_town)) $tmp[] = $row_ra->zip_town;
856
                                                if (!empty($row_ra->country))  $tmp[] = $row_ra->country;
857
                                                $elements['current-registrant']['phone'] = !empty($row_ra->phone) ? $row_ra->phone : $row_ra->mobile;
858
                                                $elements['current-registrant']['fax'] = $row_ra->fax;
635 daniel-mar 859
                                        }
977 daniel-mar 860
                                        if (empty($row_ra->zip_town) && empty($row_ra->country)) {
635 daniel-mar 861
                                                // The address is useless if we do neither know city nor country
862
                                                // Ignore it
863
                                                $elements['current-registrant']['address'] = '';
864
                                        } else {
865
                                                $elements['current-registrant']['address'] = implode("<br/>", $tmp);
866
                                        }
867
                                }
1142 daniel-mar 868
                                $update_ts = $obj->getUpdatedTime();
869
                                $elements['current-registrant']['modification-date'] = $update_ts ? self::_formatdate($update_ts) : '';
635 daniel-mar 870
 
871
                                // Request from O.D. 20 May 2019: First registrant should not be empty (especially for cases where Creation and Modify Dates are the same)
872
                                // Actually, this is a problem because we don't know the first registrant.
873
                                // However, since oidinfo gets their XML very fast (if using registration), it is likely that the reported RA is still the same...
874
                                // ... and changes at the RA are not reported to oid-info.com anyways - the XML is only for creation
875
 
876
                                $elements['first-registrant']['first-name'] = $elements['current-registrant']['first-name'];
877
                                $elements['first-registrant']['last-name']  = $elements['current-registrant']['last-name'];
878
                                $elements['first-registrant']['address']    = $elements['current-registrant']['address'];
879
                                $elements['first-registrant']['email']      = $elements['current-registrant']['email'];
880
                                $elements['first-registrant']['phone']      = $elements['current-registrant']['phone'];
881
                                $elements['first-registrant']['fax']        = $elements['current-registrant']['fax'];
882
 
883
                                $elements['current-registrant']['first-name'] = '';
884
                                $elements['current-registrant']['last-name'] = '';
885
                                $elements['current-registrant']['address'] = '';
886
                                $elements['current-registrant']['email'] = '';
887
                                $elements['current-registrant']['phone'] = '';
888
                                $elements['current-registrant']['fax'] = '';
889
                                $elements['current-registrant']['modification-date'] = '';
890
 
891
                                // End request O.D. 20 May 2019
892
 
893
                                list($ns,$id) = explode(':',$obj->nodeId());
894
                                if ($ns == 'oid') {
940 daniel-mar 895
                                        $out_content .= $oa->createXMLEntry($id, $elements, $params, $comment=$obj->nodeId());
635 daniel-mar 896
                                } else {
897
                                        $alt_ids = $obj->getAltIds(); // TODO: slow!
898
                                        foreach ($alt_ids as $alt_id) {
899
                                                $ns = $alt_id->getNamespace();
900
                                                $id = $alt_id->getId();
901
                                                $desc = $alt_id->getDescription();
902
                                                if ($ns == 'oid') {
1052 daniel-mar 903
                                                        // 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 904
                                                        if (strpos($id, '2.25.') === 0) continue; // don't spam the uuid arc with GUID objects
940 daniel-mar 905
                                                        $out_content .= $oa->createXMLEntry($id, $elements, $params, $comment=$obj->nodeId());
635 daniel-mar 906
                                                }
907
                                        }
908
                                }
909
                        }
910
                }
911
 
940 daniel-mar 912
                $out_content .= $oa->xmlAddFooter();
913
 
914
                $out_type = 'text/xml';
915
                return array($out_content, $out_type);
635 daniel-mar 916
        }
917
 
1116 daniel-mar 918
        /**
1125 daniel-mar 919
         * @param string $str
920
         * @return string
1116 daniel-mar 921
         */
1125 daniel-mar 922
        private static function _formatdate(string $str): string {
635 daniel-mar 923
                $str = explode(' ',$str)[0];
924
                if ($str == '0000-00-00') $str = '';
925
                return $str;
926
        }
927
 
1116 daniel-mar 928
        /**
1130 daniel-mar 929
         * @param string $str
930
         * @return string
1116 daniel-mar 931
         * @throws OIDplusException
932
         */
1130 daniel-mar 933
        private static function repair_relative_links(string $str): string {
934
                return preg_replace_callback('@(href\s*=\s*([\'"]))(.+)(\\2)@ismU', function($treffer) {
635 daniel-mar 935
                        $url = $treffer[3];
936
                        if ((stripos($url,'http:') !== 0) && (stripos($url,'https:') !== 0) && (stripos($url,'ftp:') !== 0)) {
937
                                if (stripos($url,'www.') === 0) {
938
                                        $url .= 'http://' . $url;
939
                                } else {
801 daniel-mar 940
                                        $url = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL) . $url; // TODO: Canonical or not?
635 daniel-mar 941
                                }
942
                        }
943
                        return $treffer[1].$url.$treffer[4];
944
                }, $str);
945
        }
946
 
1116 daniel-mar 947
        /**
1125 daniel-mar 948
         * @param string $address
949
         * @return string[]
1116 daniel-mar 950
         */
1125 daniel-mar 951
        private static function split_address_country(string $address): array {
635 daniel-mar 952
                global $oidinfo_countries;
953
                $ary = explode("\n", $address);
954
                $last_line = array_pop($ary);
955
                $rest = implode("\n", $ary);
956
                if (isset($oidinfo_countries[$last_line])) {
957
                        return array($rest, $oidinfo_countries[$last_line]);
958
                } else {
959
                        return array($rest."\n".$last_line, '');
960
                }
961
        }
962
 
1116 daniel-mar 963
        /**
1130 daniel-mar 964
         * @param string $name
1116 daniel-mar 965
         * @return array
966
         */
1130 daniel-mar 967
        private static function split_name(string $name): array {
635 daniel-mar 968
                // uses regex that accepts any word character or hyphen in last name
969
                // https://stackoverflow.com/questions/13637145/split-text-string-into-first-and-last-name-in-php
970
                $name = trim($name);
971
                $last_name = (strpos($name, ' ') === false) ? '' : preg_replace('#.*\s([\w-]*)$#', '$1', $name);
972
                $first_name = trim( preg_replace('#'.preg_quote($last_name,'#').'#', '', $name ) );
973
                return array($first_name, $last_name);
974
        }
975
 
976
        /*protected*/ const ORPHAN_IGNORE = 0;
977
        /*protected*/ const ORPHAN_AUTO_DEORPHAN = 1;
978
        /*protected*/ const ORPHAN_DISALLOW_ORPHANS = 2;
979
 
1116 daniel-mar 980
        /**
1130 daniel-mar 981
         * @param string $xml_contents
982
         * @param array $errors
983
         * @param bool $replaceExistingOIDs
984
         * @param int $orphan_mode
1125 daniel-mar 985
         * @return int[]
1116 daniel-mar 986
         * @throws OIDplusException
987
         */
1130 daniel-mar 988
        protected function oidinfoImportXML(string $xml_contents, array &$errors, bool $replaceExistingOIDs=false, int $orphan_mode=self::ORPHAN_AUTO_DEORPHAN): array {
635 daniel-mar 989
                // TODO: Implement RA import (let the user decide)
990
                // TODO: Let the user decide about $replaceExistingOIDs
991
                // 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)
992
 
993
                $xml_contents = str_replace('<description>', '<description><![CDATA[', $xml_contents);
994
                $xml_contents = str_replace('</description>', ']]></description>', $xml_contents);
995
 
996
                $xml_contents = str_replace('<information>', '<information><![CDATA[', $xml_contents);
997
                $xml_contents = str_replace('</information>', ']]></information>', $xml_contents);
998
 
999
                $xml = @simplexml_load_string($xml_contents);
1000
 
1001
                $count_already_existing = 0;
1002
                $count_errors = 0;
1003
                $count_warnings = 0;
1004
 
1005
                if (!$xml) {
1006
                        $errors[] = _L('Cannot read XML data. The XML file is probably invalid.');
1007
                        $count_errors++;
1008
                        return array(0, 0, 1, 0);
1009
                }
1010
 
1011
                $ok_oids = array();
1012
 
1013
                foreach ($xml->oid as $xoid) {
1014
 
1015
                        if (isset($xoid->{'dot-notation'})) {
1016
                                $dot_notation = $xoid->{'dot-notation'}->__toString();
1017
                        } else if (isset($xoid->{'asn1-notation'})) {
1018
                                $dot_notation = asn1_to_dot($xoid->{'asn1-notation'}->__toString());
1019
                        } else {
1020
                                $errors[] = _L('Cannot find dot notation because fields asn1-notation and dot-notation are both not existing');
1021
                                $count_errors++;
1022
                                continue;
1023
                        }
1024
 
1025
                        $id = "oid:$dot_notation";
1026
                        $title = isset($xoid->{'description'}) ? $xoid->{'description'}->__toString() : '';
1027
                        $info = isset($xoid->{'description'}) ? $xoid->{'information'}->__toString() : '';
1028
 
991 daniel-mar 1029
                        // For ASN.1 definitions, "Description" is filled with the definition and "Information" is usually empty
1030
                        if (strpos($title,'<br') !== false) {
1031
                                $info = $title . $info;
1032
                                $title = explode(' ',$title)[0];
1033
                        }
1034
 
635 daniel-mar 1035
                        if (isset($xoid->{'current-registrant'}->email)) {
1036
                                $ra = $xoid->{'current-registrant'}->email->__toString();
1037
                        } else if (isset($xoid->{'first-registrant'}->email)) {
1038
                                $ra = $xoid->{'first-registrant'}->email->__toString();
1039
                        } else {
1040
                                $ra = '';
1041
                        }
1042
 
1043
                        if (!oid_valid_dotnotation($dot_notation, false, false)) {
1044
                                $errors[] = _L('Ignored OID %1 because its dot notation is illegal or was not found',$dot_notation);
1045
                                $count_errors++;
1046
                                continue;
1047
                        }
1048
 
1049
                        $parent = 'oid:'.oid_up($dot_notation);
1050
 
1051
                        if ($orphan_mode === self::ORPHAN_DISALLOW_ORPHANS) {
977 daniel-mar 1052
                                if (!OIDplusObject::exists($parent)) {
635 daniel-mar 1053
                                        $errors[] = _L('Cannot import %1, because its parent is not in the database.',$dot_notation);
1054
                                        $count_errors++;
1055
                                        continue;
1056
                                }
1057
                        }
1058
 
1231 daniel-mar 1059
                        if (OIDplus::db()->transaction_supported()) OIDplus::db()->transaction_begin();
1060
                        try {
1061
                                $obj_test = OIDplusObject::findFitting($id);
1062
                                if ($obj_test) {
1063
                                        if ($replaceExistingOIDs) {
1064
                                                OIDplus::db()->query("delete from ###objects where id = ?", array($id));
1065
                                                OIDplus::db()->query("delete from ###asn1id where oid = ?", array($id));
1066
                                                OIDplus::db()->query("delete from ###iri where oid = ?", array($id));
1067
                                        } else {
1068
                                                //$errors[] = "Ignore OID '$dot_notation' because it already exists";
1069
                                                //$count_errors++;
1070
                                                $count_already_existing++;
1071
                                                continue;
1072
                                        }
1073
                                }
978 daniel-mar 1074
 
1231 daniel-mar 1075
                                // TODO: we can probably get the created and modified timestamp from oid-info.com XML
1076
                                OIDplus::db()->query("insert into ###objects (id, parent, title, description, confidential, ra_email) values (?, ?, ?, ?, ?, ?)", array($id, $parent, $title, $info, false, $ra));
1077
 
1078
                                if (OIDplus::db()->transaction_supported()) OIDplus::db()->transaction_commit();
1079
                        } catch (\Exception $e) {
1080
                                if (OIDplus::db()->transaction_supported()) OIDplus::db()->transaction_rollback();
1081
                                throw new $e;
635 daniel-mar 1082
                        }
1083
 
978 daniel-mar 1084
                        OIDplusObject::resetObjectInformationCache();
1085
 
635 daniel-mar 1086
                        $this_oid_has_warnings = false;
1087
 
1088
                        // ---------------------------------------------------------------------
1089
 
1090
                        $asn1ids = array();
1091
                        if (isset($xoid->{'identifier'})) {
1092
                                $asn1ids[] = $xoid->{'identifier'}->__toString();
1093
                        }
1094
                        if (isset($xoid->{'asn1-notation'})) {
1095
                                $last_id = asn1_last_identifier($xoid->{'asn1-notation'}->__toString());
1096
                                if ($last_id) {
1097
                                        $asn1ids[] = $last_id;
1098
                                }
1099
                        }
1100
                        if (isset($xoid->{'synonymous-identifier'})) {
1101
                                foreach ($xoid->{'synonymous-identifier'} as $synid) {
1102
                                        $asn1ids[] = $synid->__toString();
1103
                                }
1104
                        }
1105
                        $asn1ids = array_unique($asn1ids);
1106
                        foreach ($asn1ids as $asn1id) {
1107
                                if (!oid_id_is_valid($asn1id)) {
1108
                                        $errors[] = _L('Warning').' ['._L('OID %1',$dot_notation).']: '._L('Ignored alphanumeric identifier %1, because it is invalid',$asn1id);
1109
                                        $this_oid_has_warnings = true;
1110
                                } else {
1302 daniel-mar 1111
                                        OIDplus::db()->query("delete from ###asn1id where oid = ? and name = ?", array($id, $asn1id)); // Attention: Requires case-SENSITIVE database collation!!
635 daniel-mar 1112
                                        OIDplus::db()->query("insert into ###asn1id (oid, name) values (?, ?)", array($id, $asn1id));
1113
                                }
1114
                        }
1115
 
1116
                        // ---------------------------------------------------------------------
1117
 
1118
                        if (isset($xoid->{'unicode-label'})) {
1119
                                $iris = array();
1120
                                foreach ($xoid->{'unicode-label'} as $iri) {
1121
                                        $iris[] = $iri->__toString();
1122
                                }
1123
                                $iris = array_unique($iris);
1124
                                foreach ($iris as $iri) {
1125
                                        if (!iri_arc_valid($iri, false)) {
1126
                                                $errors[] = _L('Warning').' ['._L('OID %1',$dot_notation).']: '._L('Ignored Unicode label %1, because it is invalid',$iri);
1127
                                                $this_oid_has_warnings = true;
1128
                                        } else {
1302 daniel-mar 1129
                                                OIDplus::db()->query("delete from ###iri where oid = ? and name = ?", array($id, $iri)); // Attention: Requires case-SENSITIVE database collation!!
635 daniel-mar 1130
                                                OIDplus::db()->query("insert into ###iri (oid, name) values (?, ?)", array($id, $iri));
1131
                                        }
1132
                                }
1133
                        }
1134
 
1135
                        if ($this_oid_has_warnings) $count_warnings++;
1136
                        $ok_oids[] = $id;
1137
                }
1138
 
1139
                // De-orphanize
978 daniel-mar 1140
                //if ($orphan_mode === self::ORPHAN_AUTO_DEORPHAN) {
1141
                //      OIDplus::db()->query("update ###objects set parent = 'oid:' where parent like 'oid:%' and parent not in (select id from ###objects)");
1142
                //      OIDplusObject::resetObjectInformationCache();
1143
                //}
635 daniel-mar 1144
                foreach ($ok_oids as $id) {
1145
                        // De-orphanize if neccessary
1146
                        if ($orphan_mode === self::ORPHAN_AUTO_DEORPHAN) {
1147
                                $res = OIDplus::db()->query("select * from ###objects where id = ? and parent not in (select id from ###objects)", array($id));
790 daniel-mar 1148
                                if ($res->any()) {
635 daniel-mar 1149
                                        $errors[] = _L("%1 was de-orphaned (placed as root OID) because its parent is not existing.",$id);
1150
                                        $count_warnings++;
1151
                                        OIDplus::db()->query("update ###objects set parent = 'oid:' where id = ? and parent not in (select id from ###objects)", array($id));
978 daniel-mar 1152
                                        OIDplusObject::resetObjectInformationCache();
635 daniel-mar 1153
                                }
1154
                        }
1155
 
1156
                        // 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 1157
                        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 1158
                }
1159
 
1160
                $count_imported_oids = count($ok_oids);
1161
 
1162
                return array($count_imported_oids, $count_already_existing, $count_errors, $count_warnings);
1163
 
1164
        }
1165
 
1116 daniel-mar 1166
        /**
1131 daniel-mar 1167
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8
1130 daniel-mar 1168
         * @param string|null $user
1116 daniel-mar 1169
         * @return array
1170
         * @throws OIDplusException
1171
         */
1130 daniel-mar 1172
        public function getNotifications(string $user=null): array {
1000 daniel-mar 1173
                $notifications = array();
1174
                if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) {
1181 daniel-mar 1175
                        if (!url_post_contents_available(true, $reason)) {
1000 daniel-mar 1176
                                $title = _L('OID-Info.com import/export');
1189 daniel-mar 1177
                                $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 1178
                        }
1179
                }
1180
                return $notifications;
1181
        }
1182
 
635 daniel-mar 1183
}