Subversion Repositories oidplus

Rev

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