Subversion Repositories oidplus

Rev

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