Subversion Repositories oidplus

Rev

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