Subversion Repositories oidplus

Rev

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