Subversion Repositories oidplus

Rev

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