Subversion Repositories oidplus

Rev

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