Subversion Repositories oidplus

Rev

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