PluginProbe
IP2Location Redirection / 1.41.2
IP2Location Redirection v1.41.2
1.42.0 1.41.4 1.41.3 1.41.2 1.41.1 1.41.0 1.40.3 1.40.2 1.40.1 1.40.0 1.39.2 1.39.1 1.9.2 1.9.3 2.21.1 2.21.2 2.25.16 2.35.1 trunk 1.10.0 1.10.1 1.10.3 1.11.0 1.11.1 1.11.2 All 168 releases
ip2location-redirection / ip2location-redirection.php

ip2location-redirection.php in IP2Location Redirection 1.41.2, at ip2location-redirection.php

3,483 lines 215.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: IP2Location Redirection
5 * Plugin URI: https://ip2location.com/resources/wordpress-ip2location-redirection
6 * Description: Redirect visitors by their country.
7 * Version: 1.41.2
8 * Requires PHP: 7.4
9 * Author: IP2Location
10 * Author URI: https://www.ip2location.com
11 * Text Domain: ip2location-redirection.
12 */
13 $upload_dir = wp_upload_dir();
14 defined('FS_METHOD') || define('FS_METHOD', 'direct');
15 defined('IP2LOCATION_DIR') || define('IP2LOCATION_DIR', $upload_dir['basedir'] . \DIRECTORY_SEPARATOR . 'ip2location' . \DIRECTORY_SEPARATOR);
16 define('IPLR_ROOT', __DIR__ . \DIRECTORY_SEPARATOR);
17
18 // For development usage only when WP_DEBUG is enabled and request is from localhost.
19 if (defined('WP_DEBUG') && WP_DEBUG && !filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) && isset($_SERVER['DEV_MODE'])) {
20 $_SERVER['REMOTE_ADDR'] = '8.8.8.8';
21 }
22
23 require_once IPLR_ROOT . 'vendor' . \DIRECTORY_SEPARATOR . 'autoload.php';
24
25 // Initial class
26 $ip2location_redirection = new IP2LocationRedirection();
27
28 register_activation_hook(__FILE__, [$ip2location_redirection, 'set_default_values']);
29
30 add_action('plugins_loaded', [$ip2location_redirection, 'redirect']);
31 add_action('init', [$ip2location_redirection, 'set_locale']);
32 add_action('admin_enqueue_scripts', [$ip2location_redirection, 'plugin_enqueues']);
33 add_action('admin_init', [$ip2location_redirection, 'admin_init']);
34 add_action('wp_ajax_ip2location_redirection_update_ip2location_database', [$ip2location_redirection, 'update_ip2location_database']);
35 add_action('wp_ajax_ip2location_redirection_validate_token', [$ip2location_redirection, 'validate_token']);
36 add_action('wp_ajax_ip2location_redirection_validate_api_key', [$ip2location_redirection, 'validate_api_key']);
37 add_action('wp_ajax_ip2location_redirection_submit_feedback', [$ip2location_redirection, 'submit_feedback']);
38 add_action('wp_ajax_ip2location_redirection_search_post', [$ip2location_redirection, 'search_post']);
39 add_action('wp_ajax_ip2location_redirection_restore', [$ip2location_redirection, 'restore']);
40 add_action('admin_notices', [$ip2location_redirection, 'show_notice']);
41 add_action('wp_footer', [$ip2location_redirection, 'footer']);
42 add_action('admin_footer_text', [$ip2location_redirection, 'admin_footer_text']);
43 add_action('ip2location_redirection_hourly_event', [$ip2location_redirection, 'hourly_event']);
44 add_action('ip2location_redirection_daily_event', [$ip2location_redirection, 'daily_event']);
45
46 class IP2LocationRedirection
47 {
48 private $session = [
49 'location' => '??',
50 'lookup_mode' => '??',
51 'cache' => false,
52 ];
53
54 private $allowed_options = [
55 'api_key', 'auto_update', 'database', 'debug_log_enabled', 'download_ipv4_only', 'enable_region_redirect', 'enabled', 'first_redirect', 'first_redirect_cookie_lifetime', 'ignore_query_string', 'ip_whitelist', 'lookup_mode', 'noredirect_enabled', 'private_key', 'real_ip_header', 'rules', 'session_message', 'skip_admins', 'skip_bots', 'skip_ai_bots', 'token'
56 ];
57
58 private $debug_log = '';
59
60 public function __construct()
61 {
62 // Set priority
63 $this->set_priority();
64
65 // Check for IP2Location BIN directory.
66 if (!file_exists(IP2LOCATION_DIR)) {
67 wp_mkdir_p(IP2LOCATION_DIR);
68 }
69
70 // Check for cache directory.
71 if (!file_exists(IP2LOCATION_DIR . 'caches')) {
72 wp_mkdir_p(IP2LOCATION_DIR . 'caches');
73 }
74
75 $this->debug_log = 'debug_' . md5($this->get_option('private_key') . get_site_url() . get_option('admin_email')) . '.log';
76
77 add_action('admin_menu', [$this, 'add_admin_menu']);
78 }
79
80 public function set_locale()
81 {
82 load_plugin_textdomain('ip2location_redirection', false, IPLR_ROOT . '/languages/');
83 }
84
85 public function add_admin_menu()
86 {
87 add_menu_page(__('Redirection', 'ip2location-redirection'), __('Redirection', 'ip2location-redirection'), 'manage_options', 'ip2location-redirection', [$this, 'rules_page'], 'dashicons-admin-ip2location', 31);
88 add_submenu_page('ip2location-redirection', __('Rules', 'ip2location-redirection'), __('Rules', 'ip2location-redirection'), 'manage_options', 'ip2location-redirection', [$this, 'rules_page']);
89 add_submenu_page('ip2location-redirection', __('IP Lookup', 'ip2location-redirection'), __('IP Lookup', 'ip2location-redirection'), 'manage_options', 'ip2location-redirection-ip-lookup', [$this, 'ip_lookup_page']);
90 add_submenu_page('ip2location-redirection', __('Settings', 'ip2location-redirection'), __('Settings', 'ip2location-redirection'), 'manage_options', 'ip2location-redirection-settings', [$this, 'settings_page']);
91
92 $this->cache_clear();
93 }
94
95 public function admin_init()
96 {
97 if ($this->post('action') === 'download_ip2location_redirection_backup') {
98 if (!current_user_can('administrator')) {
99 exit;
100 }
101
102 check_admin_referer('backup');
103
104 $results = $this->wpdb_get_results("SELECT option_name, option_value FROM {$GLOBALS['wpdb']->prefix}options WHERE option_name LIKE 'ip2location_redirection_%'");
105
106 if ($results) {
107 $options = [];
108
109 foreach ($results as $result) {
110 $options[$result->option_name] = $result->option_value;
111 }
112
113 ob_end_flush();
114 header('Content-type: application/json');
115 header('Content-Disposition: attachment; filename="ip2location_redirection.json"');
116 exit(json_encode($options));
117 }
118 }
119 }
120
121 public function restore()
122 {
123 header('Content-Type: application/json');
124
125 if (!current_user_can('administrator')) {
126 exit(json_encode([
127 'status' => 'ERROR',
128 'message' => __('Permission denied.', 'ip2location-redirection'),
129 ]));
130 }
131
132 check_admin_referer('restore', '__nonce');
133
134 if (!isset($_FILES['restore_file']) || $_FILES['restore_file']['error'] !== UPLOAD_ERR_OK) {
135 exit(json_encode([
136 'status' => 'ERROR',
137 'message' => __('File upload error.', 'ip2location-redirection')
138 ]));
139 }
140
141 $rows = json_decode(file_get_contents($_FILES['restore_file']['tmp_name']));
142
143 if ($rows === null) {
144 exit(json_encode([
145 'status' => 'ERROR',
146 'message' => __('Invalid file format.', 'ip2location-redirection'),
147 ]));
148 }
149
150 foreach ($rows as $key => $value) {
151 // Skip invalid options
152 if (!in_array(str_replace('ip2location_redirection_', '', $key), $this->allowed_options)) {
153 continue;
154 }
155
156 update_option($key, ((is_array($value)) ? $this->sanitize_array($value) : sanitize_text_field($value)));
157 }
158
159 $this->update_option('session_message', 'Restore completed.');
160
161 exit(json_encode([
162 'status' => 'OK',
163 ]));
164 }
165
166 public function show_notice()
167 {
168 if ($this->is_setup_completed()) {
169 return;
170 }
171
172 echo '
173 <div class="error">
174 <p>
175 ' . sprintf(__('IP2Location Redirection requires the IP2Location BIN database to work. %1$sSetup your database%2$s now.', 'ip2location-redirection'), '<a href="' . get_admin_url() . 'admin.php?page=ip2location-redirection">', '</a>') . '
176 </p>
177 </div>';
178 }
179
180 public function plugin_enqueues($hook)
181 {
182 // Deactivation feedback modal on the Plugins screen (only those assets).
183 if ($hook == 'plugins.php') {
184 wp_enqueue_script('jquery-ui-dialog');
185 wp_enqueue_style('wp-jquery-ui-dialog');
186 wp_enqueue_script('iplr-feedback-js', plugins_url('/assets/js/feedback.js', __FILE__), ['jquery'], null, true);
187
188 return;
189 }
190
191 // Identify the page from the menu slug (the "page" query argument) rather
192 // than the admin_enqueue_scripts $hook: WordPress derives the submenu hook
193 // suffix prefix from sanitize_title( $menu_title ), so it changes with the
194 // admin locale (e.g. "redirection_page_..." vs "doorverwijzing_page_...").
195 $page = $this->get('page');
196
197 $pages = [
198 'ip2location-redirection' => 'rules',
199 'ip2location-redirection-ip-lookup' => 'ip-lookup',
200 'ip2location-redirection-settings' => 'settings',
201 ];
202
203 if (!isset($pages[$page])) {
204 return;
205 }
206
207 $page = $pages[$page];
208
209 // Shared stylesheet, scoped to the plugin's own pages only.
210 wp_enqueue_style('iplr-styles', untrailingslashit(plugins_url('/', __FILE__)) . '/assets/css/styles.css');
211
212 switch ($page) {
213 case 'rules':
214 wp_enqueue_script('iplr-rules-js', plugins_url('/assets/js/rules.js?t=' . microtime(true), __FILE__), ['jquery'], null, true);
215 wp_enqueue_script('iplr-chosen-js', plugins_url('/assets/js/chosen.jquery.min.js', __FILE__), ['jquery'], null, true);
216 wp_enqueue_script('iplr-tagsinput-js', plugins_url('/assets/js/jquery.tagsinput.min.js', __FILE__), ['jquery'], null, true);
217 wp_enqueue_script('iplr-jquery-ui', plugins_url('/assets/js/jquery-ui.min.js', __FILE__), ['jquery'], null, true);
218
219 wp_enqueue_style('iplr-chosen-css', plugins_url('/assets/css/chosen.min.css', __FILE__), [], null);
220 wp_enqueue_style('iplr-tagsinput-css', plugins_url('/assets/css/jquery.tagsinput.min.css', __FILE__), [], null);
221 wp_enqueue_style('iplr-custom-styles', untrailingslashit(plugins_url('/', __FILE__)) . '/assets/css/customs.css');
222
223 break;
224
225 case 'ip-lookup':
226 break;
227
228 case 'settings':
229 wp_enqueue_script('jquery-form');
230 wp_enqueue_script('iplr-jquery-upload-file-js', plugins_url('/assets/js/jquery.uploadfile.min.js', __FILE__), ['jquery', 'jquery-form'], null, true);
231 wp_enqueue_style('iplr-jquery-upload-file-css', plugins_url('/assets/css/uploadfile.min.css', __FILE__), [], null);
232 wp_enqueue_script('iplr_admin_script_js', plugins_url('/assets/js/settings.js', __FILE__), ['jquery', 'iplr-jquery-upload-file-js'], null, true);
233
234 break;
235 }
236 }
237
238 public function set_default_values()
239 {
240 // Initial default settings
241 add_option('ip2location_redirection_api_key', '');
242 add_option('ip2location_redirection_database', '');
243 add_option('ip2location_redirection_debug_log_enabled', '0');
244 add_option('ip2location_redirection_download_ipv4_only', '0');
245 add_option('ip2location_redirection_enable_region_redirect', '0');
246 add_option('ip2location_redirection_enabled', '1');
247 add_option('ip2location_redirection_first_redirect', '0');
248 add_option('ip2location_redirection_ignore_query_string', '1');
249 add_option('ip2location_redirection_first_redirect_cookie_lifetime', '1 day');
250 add_option('ip2location_redirection_ip_whitelist', '');
251 add_option('ip2location_redirection_lookup_mode', 'bin');
252 add_option('ip2location_redirection_noredirect_enabled', '0');
253 add_option('ip2location_redirection_private_key', '');
254 add_option('ip2location_redirection_real_ip_header', '');
255 add_option('ip2location_redirection_rules', '[]');
256 add_option('ip2location_redirection_session_message', '');
257 add_option('ip2location_redirection_skip_admins', '1');
258 add_option('ip2location_redirection_skip_bots', '0');
259 add_option('ip2location_redirection_skip_ai_bots', '0');
260 add_option('ip2location_redirection_token', '');
261
262 // Create scheduled task
263 if (!wp_next_scheduled('ip2location_redirection_hourly_event')) {
264 wp_schedule_event(time(), 'hourly', 'ip2location_redirection_hourly_event');
265 }
266
267 if (!wp_next_scheduled('ip2location_redirection_daily_event')) {
268 wp_schedule_event(time(), 'daily', 'ip2location_redirection_daily_event');
269 }
270 }
271
272 public function update_ip2location_database()
273 {
274 check_admin_referer('update_database', '__nonce');
275
276 @set_time_limit(300);
277
278 header('Content-Type: application/json');
279
280 if (!current_user_can('administrator')) {
281 exit(json_encode([
282 'status' => 'ERROR',
283 'message' => __('Permission denied.', 'ip2location-redirection'),
284 ]));
285 }
286
287 try {
288 $token = $this->post('token');
289 $enable_region = $this->is_checked('enable_region');
290 $ipv4_only = $this->post('ipv4_only') === 'true';
291
292 $this->perform_database_update($token, $enable_region, $ipv4_only);
293
294 exit(json_encode([
295 'status' => 'OK',
296 'message' => '',
297 ]));
298 } catch (Exception $e) {
299 exit(json_encode([
300 'status' => 'ERROR',
301 'message' => $e->getMessage(),
302 ]));
303 }
304 }
305
306 private function perform_database_update($token, $enable_region, $ipv4_only)
307 {
308 require_once ABSPATH . 'wp-admin/includes/file.php';
309 WP_Filesystem();
310 global $wp_filesystem;
311
312 $ipv6 = ($ipv4_only) ? '' : 'IPV6';
313
314 if ($enable_region) {
315 $code = 'DB3BIN' . $ipv6;
316 } else {
317 $code = 'DB1BIN' . $ipv6;
318 }
319
320 $working_dir = IP2LOCATION_DIR . 'working' . \DIRECTORY_SEPARATOR;
321 $zip_file = $working_dir . 'database.zip';
322
323 // Remove existing working directory
324 $wp_filesystem->delete($working_dir, true);
325
326 // Create working directory
327 $wp_filesystem->mkdir($working_dir);
328
329 if (!class_exists('WP_Http')) {
330 include_once ABSPATH . WPINC . '/class-http.php';
331 }
332
333 $request = new WP_Http();
334
335 // Check download permission
336 $response = $request->request('https://www.ip2location.com/download-info?' . http_build_query([
337 'package' => $code,
338 'token' => $token,
339 'source' => 'wp_redirection',
340 ]));
341
342 $parts = explode(';', $response['body']);
343
344 if ($parts[0] != 'OK') {
345 // Download LITE version
346 if ($enable_region) {
347 $code = 'DB3LITEBIN' . $ipv6;
348 } else {
349 $code = 'DB1LITEBIN' . $ipv6;
350 }
351
352 $response = $request->request('https://www.ip2location.com/download-info?' . http_build_query([
353 'package' => $code,
354 'token' => $token,
355 'source' => 'wp_redirection',
356 ]));
357
358 $parts = explode(';', $response['body']);
359
360 if ($parts[0] != 'OK') {
361 throw new Exception(__('You do not have permission to download this database.', 'ip2location-redirection'));
362 }
363 }
364
365 // Start downloading BIN database from IP2Location website
366 $response = $request->request('https://www.ip2location.com/download?' . http_build_query([
367 'file' => $code,
368 'token' => $token,
369 'source' => 'wp_redirection',
370 ]), [
371 'timeout' => 300,
372 'follow_redirects' => true,
373 ]);
374
375 if ((isset($response->errors)) || (!in_array('200', $response['response']))) {
376 $wp_filesystem->delete($working_dir, true);
377
378 throw new Exception(__('Connection timed out while downloading database.', 'ip2location-redirection'));
379 }
380
381 // Save downloaded package.
382 $fp = fopen($zip_file, 'w');
383
384 if (!$fp) {
385 throw new Exception(__('No permission to write into file system.', 'ip2location-redirection'));
386 }
387
388 fwrite($fp, $response['body']);
389 fclose($fp);
390
391 if (filesize($zip_file) < 51200) {
392 $message = file_get_contents($zip_file);
393 $wp_filesystem->delete($working_dir, true);
394
395 throw new Exception(__('Downloaded database is corrupted. Please try again later.', 'ip2location-redirection'));
396 }
397
398 // Unzip the package to working directory
399 $result = unzip_file($zip_file, $working_dir);
400
401 // Once extracted, delete the package.
402 unlink($zip_file);
403
404 if (is_wp_error($result)) {
405 $wp_filesystem->delete($working_dir, true);
406
407 throw new Exception(__('There is problem when decompress the database.', 'ip2location-redirection'));
408 }
409
410 // File the BIN database
411 $bin_database = '';
412 $files = scandir($working_dir);
413
414 foreach ($files as $file) {
415 if (strtoupper(substr($file, -4)) == '.BIN') {
416 $bin_database = $file;
417 break;
418 }
419 }
420
421 // Move file to IP2Location directory
422 $wp_filesystem->move($working_dir . $bin_database, IP2LOCATION_DIR . $bin_database, true);
423
424 $this->update_option('lookup_mode', 'bin');
425 $this->update_option('database', $bin_database);
426 $this->update_option('token', $token);
427 $this->update_option('download_ipv4_only', ($ipv4_only) ? 1 : 0);
428 $this->update_option('enable_region_redirect', ($enable_region) ? 1 : 0);
429
430 // Remove working directory
431 $wp_filesystem->delete($working_dir, true);
432
433 // Flush caches
434 $this->cache_flush();
435 }
436
437 public function validate_token()
438 {
439 check_admin_referer('validate_token', '__nonce');
440
441 header('Content-Type: application/json');
442
443 try {
444 $token = $this->post('token');
445
446 // Check download permission
447 $response = wp_remote_get('https://www.ip2location.com/download-info?' . http_build_query([
448 'package' => 'DB1BIN',
449 'token' => $token,
450 'source' => 'wp_redirection',
451 ]));
452
453 if (is_wp_error($response)) {
454 exit(json_encode([
455 'status' => 'ERROR',
456 'message' => $response->get_error_message(),
457 ]));
458 }
459
460 $parts = explode(';', $response['body']);
461
462 if ($parts[0] != 'OK') {
463 $response = wp_remote_get('https://www.ip2location.com/download-info?' . http_build_query([
464 'package' => 'DB1LITEBIN',
465 'token' => $token,
466 'source' => 'wp_redirection',
467 ]));
468
469 $parts = explode(';', $response['body']);
470
471 if ($parts[0] != 'OK') {
472 exit(json_encode([
473 'status' => 'ERROR',
474 'message' => __('Invalid download token.', 'ip2location-redirection'),
475 ]));
476 }
477 }
478
479 $this->update_option('token', $token);
480
481 exit(json_encode([
482 'status' => 'OK',
483 'message' => '',
484 ]));
485 } catch (Exception $e) {
486 exit(json_encode([
487 'status' => 'ERROR',
488 'message' => $e->getMessage(),
489 ]));
490 }
491 }
492
493 public function validate_api_key()
494 {
495 header('Content-Type: application/json');
496
497 check_admin_referer('validate_api_key', '__nonce');
498
499 if (!current_user_can('administrator')) {
500 exit(json_encode([
501 'status' => 'ERROR',
502 'message' => __('Permission denied.', 'ip2location-redirection'),
503 ]));
504 }
505
506 try {
507 $apiKey = $this->post('key');
508
509 if (empty($apiKey)) {
510 exit(json_encode([
511 'status' => 'ERROR',
512 'message' => __('Invalid API key.', 'ip2location-redirection'),
513 ]));
514 }
515
516 // Check download permission
517 $response = wp_remote_get('https://api.ip2location.io/?' . http_build_query([
518 'key' => $apiKey,
519 'source' => 'wp_redirection',
520 ]));
521
522 if (is_wp_error($response)) {
523 exit(json_encode([
524 'status' => 'ERROR',
525 'message' => $response->get_error_message(),
526 ]));
527 }
528
529 if (!isset($response['response']['code'])) {
530 exit(json_encode([
531 'status' => 'ERROR',
532 'message' => __('Remote server is not responding. Please try again later.', 'ip2location-redirection'),
533 ]));
534 }
535
536 if ($response['response']['code'] != 200) {
537 exit(json_encode([
538 'status' => 'ERROR',
539 'message' => __('Invalid API key.', 'ip2location-redirection'),
540 ]));
541 }
542
543 $this->update_option('lookup_mode', 'ws');
544 $this->update_option('api_key', $apiKey);
545
546 exit(json_encode([
547 'status' => 'OK',
548 'message' => '',
549 ]));
550 } catch (Exception $e) {
551 exit(json_encode([
552 'status' => 'ERROR',
553 'message' => $e->getMessage(),
554 ]));
555 }
556 }
557
558 public function search_post()
559 {
560 check_admin_referer('search_post', '__nonce');
561
562 header('Content-Type: application/json');
563
564 $keyword = $this->post('search');
565
566 $results = [];
567
568 if (mb_strlen($keyword) < 3) {
569 $results[] = [
570 'id' => '',
571 'name' => 'No result',
572 ];
573 exit(json_encode($results));
574 }
575
576 $rows = $this->wpdb_get_results("SELECT `ID`, `post_type`, `post_title` FROM `{$GLOBALS['wpdb']->prefix}posts` WHERE `post_title` LIKE %s AND `post_status` = 'publish' AND `post_type` IN ('post', 'page', 'product') LIMIT 25", [
577 '%' . $keyword . '%'
578 ]);
579
580 if (count($rows) > 0) {
581 foreach ($rows as $row) {
582 $results[] = [
583 'id' => (($row->post_type == 'page') ? 'page-' : 'post-') . $row->ID,
584 'name' => (($row->post_type == 'page') ? 'Page' : 'Post') . '' . $row->post_title,
585 ];
586 }
587 } else {
588 $results[] = [
589 'id' => '',
590 'name' => 'No result',
591 ];
592 }
593
594 exit(json_encode($results));
595 }
596
597 public function submit_feedback()
598 {
599 if (!current_user_can('deactivate_plugins')) {
600 exit;
601 }
602
603 check_admin_referer('submit_feedback', '__nonce');
604
605 $feedback = $this->post('feedback');
606 $others = $this->post('others');
607
608 $options = [
609 1 => __('I no longer need the plugin', 'ip2location-redirection'),
610 2 => __('I couldn\'t get the plugin to work', 'ip2location-redirection'),
611 3 => __('The plugin doesn\'t meet my requirements', 'ip2location-redirection'),
612 4 => __('Other concerns', 'ip2location-redirection') . (($others) ? (' - ' . $others) : ''),
613 4];
614
615 if (isset($options[$feedback])) {
616 wp_remote_get('https://www.ip2location.com/wp-plugin-feedback?' . http_build_query([
617 'name' => 'ip2location-redirection',
618 'message' => $options[$feedback],
619 ]), ['timeout' => 5]);
620 }
621 }
622
623 public function rules_page()
624 {
625 $general_status = '';
626 $cache_warning = '';
627
628 $rules = [];
629 $wpml_settings = get_option('icl_sitepress_settings');
630
631 if (($name = $this->cache_plugin_detected()) !== false) {
632 $cache_warning = '
633 <div class="error">
634 <p>
635 It appears that you are currently using <strong>' . $name . '</strong>, which is not fully compatible with the IP2Location Redirection. This may lead to unintended issues. We recommend disabling and uninstalling the cache plugin.
636 </p>
637 </div>';
638 }
639
640 $enable_redirection = $this->is_checked('enable_redirection', $this->get_option('enabled'));
641 $first_redirect = $this->is_checked('first_redirect', $this->get_option('first_redirect'));
642 $enable_noredirect = $this->is_checked('enable_noredirect', $this->get_option('noredirect_enabled'));
643 $ignore_query_string = $this->is_checked('ignore_query_string', $this->get_option('ignore_query_string'));
644 $skip_bots = $this->is_checked('skip_bots', $this->get_option('skip_bots'));
645 $skip_ai_bots = $this->is_checked('skip_ai_bots', $this->get_option('skip_ai_bots'));
646 $skip_admins = $this->is_checked('skip_admins', $this->get_option('skip_admins'));
647 $ip_whitelist = $this->post('ip_whitelist', $this->get_option('ip_whitelist'));
648
649 $cookie_lifetime = $this->post('first_redirect_cookie_lifetime', $this->get_option('first_redirect_cookie_lifetime'));
650
651 $cookie_lifetime_options = [
652 '1 day' => __('1 day', 'ip2location-redirection'),
653 '1 week' => __('1 week', 'ip2location-redirection'),
654 '1 month' => __('1 month', 'ip2location-redirection'),
655 '1 year' => __('1 year', 'ip2location-redirection'),
656 ];
657
658 if (!isset($cookie_lifetime_options[$cookie_lifetime])) {
659 $cookie_lifetime = '1 day';
660 }
661
662 $cookie_lifetime_select = '<select name="first_redirect_cookie_lifetime" id="first_redirect_cookie_lifetime">';
663
664 foreach ($cookie_lifetime_options as $value => $label) {
665 $cookie_lifetime_select .= '<option value="' . esc_attr($value) . '"' . (($cookie_lifetime == $value) ? ' selected' : '') . '>' . esc_html($label) . '</option>';
666 }
667
668 $cookie_lifetime_select .= '</select>';
669 if ($this->post('submit')) {
670 check_admin_referer('save_rules');
671
672 if (is_array($this->post('country_codes'))) {
673 $index = 0;
674
675 foreach ($this->post('country_codes') as $country_codes) {
676 $country_codes = explode(',', $country_codes);
677 $rule_status = $this->post('rule_status')[$index] ?? '';
678 $status_code = $this->post('status_code')[$index] ?? '';
679 $wpml_code = $this->post('wpml_code')[$index] ?? '';
680 $from = $this->post('from')[$index] ?? '';
681 $to = $this->post('to')[$index] ?? '';
682 $post_from = $this->post('post_from')[$index] ?? '';
683 $post_to = $this->post('post_to')[$index] ?? '';
684 $url_from = $this->post('url_from')[$index] ?? '';
685 $url_to = $this->post('url_to')[$index] ?? '';
686 $path_mode = $this->post('path_mode')[$index] ?? '';
687 $path_keyword = $this->post('path_keyword')[$index] ?? '';
688 $new_parameter = $this->post('new_parameter')[$index] ?? '';
689 $domain_from = $this->post('domain_from')[$index] ?? '';
690 $domain_to = $this->post('domain_to')[$index] ?? '';
691 $keep_query = $this->post('keep_query')[$index] ?? '';
692 $dialog_message = $this->post('dialog_message')[$index] ?? '';
693 $total_hits = $this->post('total_hits')[$index] ?? 0;
694 $last_access = $this->post('last_access')[$index] ?? '';
695
696 // Domain redirection must redirect from domain to domain
697 if (($from == 'domain' && $to != 'domain') || ($to == 'domain' && $from != 'domain')) {
698 ++$index;
699 continue;
700 }
701
702 // Destination cannot be empty
703 if (empty($to)) {
704 ++$index;
705 continue;
706 }
707
708 if ($from != 'url') {
709 $url_from = '';
710 }
711
712 if ($to != 'url') {
713 $url_to = '';
714 }
715
716 if ($from != 'domain' || $to != 'domain') {
717 $domain_from = '';
718 $domain_to = '';
719 }
720
721 if ($from != 'post') {
722 $post_from = '';
723 }
724
725 if ($to != 'post') {
726 $post_to = '';
727 }
728
729 // Validate domain name
730 if ($from == 'domain' && !preg_match('/^(?:[-A-Za-z0-9]+\.)+[A-Za-z]{2,20}$/', $domain_from)) {
731 $general_status .= '
732 <div id="message" class="error">
733 <p>
734 ' . sprintf(__('%1$s is not a domain name.', 'ip2location-redirection'), '<strong>' . esc_html($domain_from) . '</strong>') . '
735 </p>
736 </div>';
737
738 break;
739 }
740
741 if ($to == 'domain' && !preg_match('/^(?:[-A-Za-z0-9]+\.)+[A-Za-z]{2,20}$/', $domain_to)) {
742 $general_status .= '
743 <div id="message" class="error">
744 <p>
745 ' . sprintf(__('%1$s is not a domain name.', 'ip2location-redirection'), '<strong>' . esc_html($domain_to) . '</strong>') . '
746 </p>
747 </div>';
748
749 break;
750 }
751
752 // Both URL from and to cannot be same.
753 if ($from == 'url' && $to == 'url' && $url_from == $url_to) {
754 $general_status .= '
755 <div id="message" class="error">
756 <p>
757 ' . __('Target URL and destination URL cannot be same.', 'ip2location-redirection') . '
758 </p>
759 </div>';
760
761 break;
762 }
763
764 // Both domain from and to cannot be same.
765 if ($from == 'domain' && $to == 'domain' && $domain_from == $domain_to) {
766 $general_status .= '
767 <div id="message" class="error">
768 <p>
769 ' . sprintf(__('Target domain and destination domain %1$s cannot be same.', 'ip2location-redirection'), '<strong>' . esc_html($domain_from) . '</strong>') . '
770 </p>
771 </div>';
772
773 break;
774 }
775
776 if ($from == 'url' && !filter_var($url_from, \FILTER_VALIDATE_URL)) {
777 $general_status .= '
778 <div id="message" class="error">
779 <p>
780 ' . sprintf(__('%1$s is not a valid URL.', 'ip2location-redirection'), '<strong>' . esc_html($this->post('url_form')[$index]) . '</strong>') . '
781 </p>
782 </div>';
783
784 break;
785 }
786
787 if ($to == 'url' && !filter_var($url_to, \FILTER_VALIDATE_URL)) {
788 $general_status .= '
789 <div id="message" class="error">
790 <p>
791 ' . sprintf(__('%1$s is not a valid URL.', 'ip2location-redirection'), '<strong>' . esc_html($url_to) . '</strong>') . '
792 </p>
793 </div>';
794
795 break;
796 }
797
798 // Both post/page from and to cannot be same.
799 if ($from == 'post' && $to == 'post' && $post_from == $post_to) {
800 $general_status .= '
801 <div id="message" class="error">
802 <p>
803 ' . __('Target post and destination post cannot be same.', 'ip2location-redirection') . '
804 </p>
805 </div>';
806
807 break;
808 }
809
810 $idx = 0;
811 foreach ($country_codes as $country_code) {
812 if ($this->post('exclude')[$index]) {
813 $country_codes[$idx] = (substr($country_code, 0, 1) == '-') ? $country_code : ('-' . $country_code);
814 } else {
815 $country_codes[$idx] = (substr($country_code, 0, 1) == '-') ? substr($country_code, 1) : $country_code;
816 }
817
818 ++$idx;
819 }
820
821 if ($from == 'domain') {
822 $url_from = $domain_from;
823 $url_to = $domain_to;
824
825 if ($keep_query) {
826 $url_from = '*' . $url_from;
827 }
828 }
829
830 $dialog_message = ($status_code != 'dialog') ? '' : $dialog_message;
831
832 $rules[] = [
833 'is_active' => ($rule_status == '1'),
834 'country_codes' => $country_codes,
835 'page_from' => ($from == 'post') ? $post_from : $from,
836 'page_to' => ($to == 'post') ? $post_to : $to,
837 'url_from' => $url_from,
838 'url_to' => $url_to,
839 'path_mode' => $path_mode,
840 'path_keyword' => $path_keyword,
841 'new_parameter' => $new_parameter,
842 'language_code' => $wpml_code,
843 'http_code' => $status_code,
844 'dialog_message' => $dialog_message,
845 'total_hits' => $total_hits,
846 'last_access' => $last_access,
847 ];
848
849 ++$index;
850 }
851 }
852
853 if ($ip_whitelist) {
854 $ip_whitelist = $this->sanitize_list($ip_whitelist);
855 }
856
857 if (empty($general_status)) {
858 $this->update_option('enabled', $enable_redirection);
859 $this->update_option('first_redirect', $first_redirect);
860 $this->update_option('rules', json_encode($rules));
861 $this->update_option('first_redirect_cookie_lifetime', $cookie_lifetime);
862 $this->update_option('noredirect_enabled', $enable_noredirect);
863 $this->update_option('ignore_query_string', $ignore_query_string);
864 $this->update_option('skip_bots', $skip_bots);
865 $this->update_option('skip_ai_bots', $skip_ai_bots);
866 $this->update_option('skip_admins', $skip_admins);
867 $this->update_option('ip_whitelist', $ip_whitelist);
868
869 $general_status = '
870 <div id="message" class="updated">
871 <p>' . __('Changes saved.', 'ip2location-redirection') . '</p>
872 </div>';
873 }
874 }
875
876 echo '
877 <div class="wrap">
878 <h1>' . __('Rules', 'ip2location-redirection') . '</h1>
879
880 ' . $cache_warning . '
881 ' . $general_status . '
882
883 <form method="post" novalidate="novalidate">
884 <table class="form-table">
885 <tr>
886 <td>
887 <label for="enable_redirection">
888 <input type="checkbox" name="enable_redirection" id="enable_redirection"' . (($enable_redirection) ? ' checked' : '') . '>
889 ' . __('Enable Redirection', 'ip2location-redirection') . '
890 </label>
891 </td>
892 </tr>
893 <tr>
894 <td>
895 <label for="first_redirect">
896 <input type="checkbox" name="first_redirect" id="first_redirect"' . (($first_redirect) ? ' checked' : '') . '>
897 ' . __('Redirect on first visit only. Subsequent visits will be ignored.', 'ip2location-redirection') . '
898 <span class="dashicons dashicons-info" title="' . esc_attr__('A cookie is set in the visitor\'s browser after the first redirect. The visitor will not be redirected again until the cookie expires.', 'ip2location-redirection') . '" style="cursor:help;vertical-align:middle;color:#666;"></span>
899 </label>
900 </td>
901 </tr>
902 <tr>
903 <td>
904 <label for="first_redirect_cookie_lifetime">
905 ' . __('Cookie lifetime', 'ip2location-redirection') . '
906 ' . $cookie_lifetime_select . '
907 </label>
908 </td>
909 </tr>
910 <tr>
911 <td>
912 <table class="wp-list-table widefat striped">
913 <thead>
914 <tr>
915 <th>' . __('Location', 'ip2location-redirection') . '</th>
916 <th>' . __('From', 'ip2location-redirection') . '</th>
917 <th>' . __('Destination', 'ip2location-redirection') . '</th>
918 <th>' . __('Status', 'ip2location-redirection') . '</th>
919 <th colspan="2">&nbsp;</th>
920 </tr>
921 </thead>
922 <tbody id="rules">
923 </tbody>
924 </table>
925 </td>
926 </tr>
927 <tr>
928 <td>
929 <p style="margin-bottom:10px">
930 <strong>' . __('Exclude the below IP addresses from redirection:', 'ip2location-redirection') . '</strong>
931 </p>
932
933 <fieldset>
934 <input type="text" name="ip_whitelist" id="ip_whitelist" value="' . esc_attr($ip_whitelist) . '" class="regular-text ip-address-list" />
935 <p class="description">' . __('Please enter IP address or CIDR notation.', 'ip2location-redirection') . '</p>
936 </fieldset>
937 </td>
938 </tr>
939 <tr>
940 <td>
941 <label for="enable_noredirect">
942 <input type="checkbox" name="enable_noredirect" id="enable_noredirect"' . (($enable_noredirect) ? ' checked' : '') . '>
943 ' . sprintf(__('Skip redirection if %1$s found in URL. For example,', 'ip2location-redirection'), '<strong>noredirect=true</strong>') . ' https://www.example.com/?page=1&<code>noredirect=true</code>
944 </label>
945 </td>
946 </tr>
947 <tr>
948 <td>
949 <label for="ignore_query_string">
950 <input type="checkbox" name="ignore_query_string" id="ignore_query_string"' . (($ignore_query_string) ? ' checked' : '') . '>
951 ' . __('Ignore query strings and parameters when matching page.', 'ip2location-redirection') . '
952 </label>
953 </td>
954 </tr>
955 <tr>
956 <td>
957 <label for="skip_bots">
958 <input type="checkbox" name="skip_bots" id="skip_bots"' . (($skip_bots) ? ' checked' : '') . '>
959 ' . __('Do not redirect bots and crawlers.', 'ip2location-redirection') . '
960 </label>
961 </td>
962 </tr>
963 <tr>
964 <td>
965 <label for="skip_ai_bots">
966 <input type="checkbox" name="skip_ai_bots" id="skip_ai_bots"' . (($skip_ai_bots) ? ' checked' : '') . '>
967 ' . __('Do not redirect AI bots.', 'ip2location-redirection') . '
968 </label>
969 </td>
970 </tr>
971 <tr>
972 <td>
973 <label for="skip_admins">
974 <input type="checkbox" name="skip_admins" id="skip_admins"' . (($skip_admins) ? ' checked' : '') . '>
975 ' . __('Do not redirect administrators.', 'ip2location-redirection') . '
976 </label>
977 </td>
978 </tr>
979 </table>
980
981 <p class="submit">
982 <input type="submit" name="submit" id="submit" class="button button-primary" value="' . __('Save Changes', 'ip2location-redirection') . '" />
983 </p>
984 <input type="hidden" id="search_post_nonce" value="' . wp_create_nonce('search_post') . '">
985 <input type="hidden" id="validate_token_nonce" value="' . wp_create_nonce('validate_token') . '">
986 ' . wp_nonce_field('save_rules') . '
987 </form>
988
989 <div class="clear"></div>
990 </div>
991 <input type="hidden" id="is_region_supported" value="' . (($this->is_region_supported()) ? 'true' : 'false') . '">';
992
993 if (($records = json_decode($this->get_option('rules'))) !== null) {
994 if (!isset($records[0]->is_active)) {
995 $list = [];
996
997 foreach ($records as $values) {
998 if (count($values) == 5) {
999 $list[] = [
1000 'is_active' => true,
1001 'country_codes' => explode(';', $values[0]),
1002 'page_from' => $values[1],
1003 'page_to' => $values[2],
1004 'url_from' => '',
1005 'url_to' => $values[3],
1006 'new_parameter' => '',
1007 'language_code' => '',
1008 'http_code' => $values[4],
1009 ];
1010 } elseif (count($values) == 7) {
1011 $list[] = [
1012 'is_active' => (bool) $values[6],
1013 'country_codes' => explode(';', $values[0]),
1014 'page_from' => $values[1],
1015 'page_to' => $values[2],
1016 'url_from' => $values[3],
1017 'url_to' => $values[4],
1018 'new_parameter' => '',
1019 'language_code' => '',
1020 'http_code' => $values[5],
1021 ];
1022 } elseif (count($values) == 8) {
1023 $list[] = [
1024 'is_active' => (bool) $values[7],
1025 'country_codes' => explode(';', $values[0]),
1026 'page_from' => $values[1],
1027 'page_to' => $values[2],
1028 'url_from' => $values[3],
1029 'url_to' => $values[4],
1030 'new_parameter' => '',
1031 'language_code' => $values[5],
1032 'http_code' => $values[6],
1033 ];
1034 } else {
1035 $list[] = [
1036 'is_active' => (bool) $values[8],
1037 'country_codes' => explode(';', $values[0]),
1038 'page_from' => $values[1],
1039 'page_to' => $values[2],
1040 'url_from' => $values[3],
1041 'url_to' => $values[4],
1042 'new_parameter' => $values[5],
1043 'language_code' => $values[6],
1044 'http_code' => $values[7],
1045 ];
1046 }
1047 }
1048
1049 $this->update_option('rules', json_encode($list));
1050 }
1051 }
1052
1053 $rules = json_decode((string) $this->get_option('rules'));
1054
1055 if ($rules) {
1056 for ($i = 0; $i < count($rules); ++$i) {
1057 if (substr($rules[$i]->page_from, 0, 4) == 'page') {
1058 $rules[$i]->page_from .= ';Page → ' . $this->get_post_title(substr($rules[$i]->page_from, 5));
1059 }
1060
1061 if (substr($rules[$i]->page_from, 0, 4) == 'post') {
1062 $rules[$i]->page_from .= ';Post → ' . $this->get_post_title(substr($rules[$i]->page_from, 5));
1063 }
1064
1065 if (substr($rules[$i]->page_to, 0, 4) == 'page') {
1066 $rules[$i]->page_to .= ';Page → ' . $this->get_post_title(substr($rules[$i]->page_to, 5));
1067 }
1068
1069 if (substr($rules[$i]->page_to, 0, 4) == 'post') {
1070 $rules[$i]->page_to .= ';Post → ' . $this->get_post_title(substr($rules[$i]->page_to, 5));
1071 }
1072
1073 if (!isset($rules[$i]->total_hits)) {
1074 $rules[$i]->total_hits = 0;
1075 }
1076
1077 if (!isset($rules[$i]->last_access)) {
1078 $rules[$i]->last_access = null;
1079 }
1080 }
1081 }
1082
1083 $scripts = [];
1084
1085 $scripts[] = '';
1086 $scripts[] = '<script>';
1087 $scripts[] = 'var rules = ' . json_encode($rules) . ';';
1088 $scripts[] = 'var wpml_installed = ' . (($wpml_settings) ? 'true' : 'false') . ';';
1089 $scripts[] = '</script>';
1090
1091 echo implode("\n", $scripts);
1092
1093 if (!$this->is_setup_completed()) {
1094 echo '
1095 <div id="modal-get-started" class="ip2location-modal" style="display:block">
1096 <div class="ip2location-modal-content">
1097 <div style="text-align:center;margin:10px auto;">
1098 <img src="' . plugins_url('/assets/img/logo.png', __FILE__) . '" width="200" height="24" style="text-align:center;" alt="IP2Location"><br>
1099 <img src="' . plugins_url('/assets/img/get-started.png', __FILE__) . '" width="160" height="125" style="display:block;margin:5px auto 0;" alt="IP2Location Redirection">
1100 </div>
1101 <p style="margin-top:0;">
1102 ' . sprintf(__('%1$sIP2Location Redirection%2$s is a plugin designed to redirect visitors or traffic based on their geolocation determined by their IP address.', 'ip2location-redirection'), '<strong>', '</strong>') . '
1103 </p>
1104 <p>
1105 ' . __('Please follow these steps to complete the setup.', 'ip2location-redirection') . '
1106 </p>';
1107
1108 if (!extension_loaded('bcmath')) {
1109 echo '
1110 <span class="dashicons dashicons-warning"></span> ' . sprintf(__('IP2Location requires %1$s PHP extension enabled. Please enable this extension in your %2$s.', 'ip2location-redirection'), '<strong>bcmath</strong>', '<strong>php.ini</strong>') . '
1111 <p style="text-align:center;margin-top:25px">
1112 <button class="button button-primary" style="padding:3px 18px;" disabled>' . __('Get Started', 'ip2location-redirection') . '</button>
1113 </p>';
1114 } else {
1115 echo '
1116 <p style="text-align:center;margin-top:25px">
1117 <button class="button button-primary" id="btn-get-started" style="padding:3px 18px;">' . __('Get Started', 'ip2location-redirection') . '</button>
1118 </p>';
1119 }
1120
1121 echo '
1122 </div>
1123 </div>
1124
1125 <div id="modal-step-1" class="ip2location-modal">
1126 <div class="ip2location-modal-content">
1127 <div class="ip2location-sel-form">
1128 <div class="ip2location-sel-con">
1129 <h1 style="line-height:1.2;font-size:23px;text-align:center;margin-bottom:25px;">' . __('Choose Query Method', 'ip2location-redirection') . '</h1>
1130 <div class="ip2location-sel-img-div">
1131 <input width="100" type="radio" name="ipl-sel" id="db" value="db" checked>
1132 <label for="db">
1133 <span class="ip2location-sel-img">
1134 <img src="' . plugins_url('/assets/img/db.png', __FILE__) . '" width="90" height="90" style="text-align:center;" alt="IP2Location BIN Database">
1135 </span>
1136 </label>
1137 <h4 style="margin-bottom:0;">' . __('IP2Location BIN Database (Local Query)', 'ip2location-redirection') . '</h4>
1138 <p style="margin-top:8px;">' . __('Free geolocation database download', 'ip2location-redirection') . '</p>
1139 </div>
1140 <div class="ip2location-sel-img-div">
1141 <input type="radio" name="ipl-sel" id="api" value="api" >
1142 <label for="api">
1143 <span class="ip2location-sel-img">
1144 <img src="' . plugins_url('/assets/img/api.png', __FILE__) . '" width="90" height="90" style="text-align:center;" alt="IP2Location.io IP Geolocation API">
1145 </span>
1146 </label>
1147 <h4 style="margin-bottom:0;">' . __('IP2Location.io IP Geolocation API (Remote Query)', 'ip2location-redirection') . '</h4>
1148 <p style="margin-top:8px;">' . __('Free 50K IP geolocation queries per month', 'ip2location-redirection') . '</p>
1149 </div>
1150 </div>
1151 </div>
1152 <p style="text-align:right;margin-top:15px">
1153 <button id="btn-to-step-1" class="button button-primary" style="padding:3px 18px;">' . __('Next', 'ip2location-redirection') . ' &raquo;</button>
1154 </p>
1155 </div>
1156 </div>
1157
1158 <!-- db -->
1159 <div id="modal-db-step-1" class="ip2location-modal">
1160 <div class="ip2location-modal-content">
1161 <div style="text-align:center;">
1162 <h1 style="line-height:1.2;font-size:23px;margin-bottom:25px;">' . __('Set Up IP2Location LITE BIN Database', 'ip2location-redirection') . '</h1>
1163 <table class="setup ip2location-steps" width="200">
1164 <tr>
1165 <td style="text-align:center;">
1166 <img src="' . plugins_url('/assets/img/step-1-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 1"><br>
1167 ' . __('Step 1', 'ip2location-redirection') . '
1168 </td>
1169 <td style="text-align:center;">
1170 <img src="' . plugins_url('/assets/img/step-2.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 2"><br>
1171 ' . __('Step 2', 'ip2location-redirection') . '
1172 </td>
1173 <td style="text-align:center;">
1174 <img src="' . plugins_url('/assets/img/step-3.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 3"><br>
1175 ' . __('Step 3', 'ip2location-redirection') . '
1176 </td>
1177 </tr>
1178 </table>
1179 <div class="ip2location-line"></div>
1180 </div>
1181 <form>
1182 <p>
1183 <label>' . __('Enter IP2Location LITE download token', 'ip2location-redirection') . '</label>
1184 <input type="text" id="setup_token" class="regular-text code" maxlength="64" style="width:100%; margin-top: 10px; margin-bottom: 4px;">
1185 </p>
1186 <p class="description">
1187 ' . sprintf(__('Don\'t have an account yet? Sign up a %1$s free IP geolocation account%2$s to obtain your download token.', 'ip2location-redirection'), '<a href="https://lite.ip2location.com/sign-up#wordpress-wzdir" target="_blank">', '</a>') . '
1188 </p>
1189 <p id="token_status" style="margin-top:20px;margin-bottom:20px;">&nbsp;</p>
1190 </form>
1191 <p style="text-align:right;margin-top:15px">
1192 <button id="btn-to-db-step-0" class="button button-secondary" style="padding:3px 18px;margin-right:8px;" >&laquo; ' . __('Previous', 'ip2location-redirection') . '</button>
1193 <button id="btn-to-db-step-2" class="button button-primary" style="padding:3px 18px;" disabled>' . __('Next', 'ip2location-redirection') . ' &raquo;</button>
1194 </p>
1195 </div>
1196 </div>
1197
1198 <div id="modal-db-step-2" class="ip2location-modal">
1199 <div class="ip2location-modal-content">
1200 <div style="text-align:center;">
1201 <h1 style="line-height:1.2;font-size:23px;margin-bottom:25px;">' . __('Download IP2Location BIN Database', 'ip2location-redirection') . '</h1>
1202 <table class="setup ip2location-steps" width="200">
1203 <tr>
1204 <td style="text-align:center;">
1205 <img src="' . plugins_url('/assets/img/step-1-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 1"><br>
1206 ' . __('Step 1', 'ip2location-redirection') . '
1207 </td>
1208 <td style="text-align:center;">
1209 <img src="' . plugins_url('/assets/img/step-2-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 2"><br>
1210 ' . __('Step 2', 'ip2location-redirection') . '
1211 </td>
1212 <td style="text-align:center;">
1213 <img src="' . plugins_url('/assets/img/step-3.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 3"><br>
1214 ' . __('Step 3', 'ip2location-redirection') . '
1215 </td>
1216 </tr>
1217 </table>
1218 <div class="ip2location-line"></div>
1219 </div>
1220
1221 <form style="height:140px">
1222 <p id="ip2location_download_status"></p>
1223 </form>
1224 <p style="text-align:right;margin-top:30px">
1225 <button id="btn-to-db-step-1" class="button button-secondary" style="padding:3px 18px;margin-right:8px;" disabled>&laquo; ' . __('Previous', 'ip2location-redirection') . '</button>
1226 <button id="btn-to-db-step-3" class="button button-primary" style="padding:3px 18px;" disabled>' . __('Next', 'ip2location-redirection') . ' &raquo;</button>
1227 </p>
1228 </div>
1229 </div>
1230
1231 <div id="modal-db-step-3" class="ip2location-modal">
1232 <div class="ip2location-modal-content">
1233 <div style="text-align:center;">
1234 <h1 style="line-height:1.2;font-size:23px;margin-bottom:25px;">' . __('Configure The Rules', 'ip2location-redirection') . '</h1>
1235 <table class="setup ip2location-steps" width="200">
1236 <tr>
1237 <td style="text-align:center;">
1238 <img src="' . plugins_url('/assets/img/step-1-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 1"><br>
1239 ' . __('Step 1', 'ip2location-redirection') . '
1240 </td>
1241 <td style="text-align:center;">
1242 <img src="' . plugins_url('/assets/img/step-2-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 2"><br>
1243 ' . __('Step 2', 'ip2location-redirection') . '
1244 </td>
1245 <td style="text-align:center;">
1246 <img src="' . plugins_url('/assets/img/step-3-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 3"><br>
1247 ' . __('Step 3', 'ip2location-redirection') . '
1248 </td>
1249 </tr>
1250 </table>
1251 <div class="ip2location-line"></div>
1252 </div>
1253
1254 <form style="height:75px;">
1255 <p>
1256 ' . __('Please click the “Finish” button to start configuring your rules.', 'ip2location-redirection') . '
1257 </p>
1258 </form>
1259 <p style="text-align:right;margin-top:30px">
1260 <button class="button button-primary" style="padding:3px 18px;" onclick="window.location.href=\'' . admin_url('admin.php?page=ip2location-redirection') . '\';">' . __('Finish', 'ip2location-redirection') . '</button>
1261 </p>
1262 </div>
1263 </div>
1264
1265 <!-- api -->
1266 <div id="modal-api-step-1" class="ip2location-modal">
1267 <div class="ip2location-modal-content">
1268 <div style="text-align:center;">
1269 <h1 style="line-height:1.2;font-size:23px;margin-bottom:25px;">' . __('Set Up IP2Location.io IP Geolocation Service', 'ip2location-redirection') . '</h1>
1270 <table class="setup ip2location-steps" width="200">
1271 <tr>
1272 <td style="text-align:center;">
1273 <img src="' . plugins_url('/assets/img/step-1-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 1"><br>
1274 ' . __('Step 1', 'ip2location-redirection') . '
1275 </td>
1276 <td style="text-align:center;">
1277 <img src="' . plugins_url('/assets/img/step-3.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 2"><br>
1278 ' . __('Step 2', 'ip2location-redirection') . '
1279 </td>
1280 </tr>
1281 </table>
1282 <div class="ip2location-api-line"></div>
1283 </div>
1284 <form>
1285 <p>
1286 <label>' . __('Enter IP2Location.io IP Geolocation API key', 'ip2location-redirection') . '</label>
1287 <input type="text" id="setup_api_key" class="regular-text code" maxlength="64" style="width:100%;margin-top: 10px; margin-bottom: 4px;">
1288 </p>
1289 <p class="description">
1290 ' . sprintf(__('Don\'t have an account yet? Sign up a %1$s free IP geolocation plan%2$s to obtain your API key.', 'ip2location-redirection'), '<a href="https://www.ip2location.io/sign-up?ref=wp_ir" target="_blank">', '</a>') . '
1291 </p>
1292 <p id="api_status">&nbsp;</p>
1293 </form>
1294 <p style="text-align:right;margin-top:30px">
1295 <button id="btn-to-api-step-0" class="button button-secondary" style="padding:3px 18px;margin-right:8px;">&laquo; ' . __('Previous', 'ip2location-redirection') . '</button>
1296 <button id="btn-to-api-step-2" class="button button-primary" style="padding:3px 18px;" >' . __('Next', 'ip2location-redirection') . ' &raquo;</button>
1297 </p>
1298 </div>
1299 </div>
1300
1301 <div id="modal-api-step-2" class="ip2location-modal">
1302 <div class="ip2location-modal-content">
1303 <div style="text-align:center;">
1304 <h1 style="line-height:1.2;font-size:23px;margin-bottom:25px;">' . __('Configure The Rules', 'ip2location-redirection') . '</h1>
1305 <table class="setup ip2location-steps" width="200">
1306 <tr>
1307 <td style="text-align:center;">
1308 <img src="' . plugins_url('/assets/img/step-1-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 1"><br>
1309 ' . __('Step 1', 'ip2location-redirection') . '
1310 </td>
1311 <td style="text-align:center;">
1312 <img src="' . plugins_url('/assets/img/step-3-selected.png', __FILE__) . '" width="36" height="36" style="text-align:center;" alt="Wizard Step 2"><br>
1313 ' . __('Step 2', 'ip2location-redirection') . '
1314 </td>
1315 </tr>
1316 </table>
1317 <div class="ip2location-api-line"></div>
1318 </div>
1319
1320 <form style="height:75px;">
1321 <p>
1322 ' . __('Please click the “Finish” button to start configuring your rules.', 'ip2location-redirection') . '
1323 </p>
1324 </form>
1325 <p style="text-align:right;margin-top:30px">
1326 <button class="button button-primary" style="padding:3px 18px;" onclick="window.location.href=\'' . admin_url('admin.php?page=ip2location-redirection&tab=general') . '\';">' . __('Finish', 'ip2location-redirection') . '</button>
1327 </p>
1328 </div>
1329 </div>
1330 <input type="hidden" id="update_nonce" value="' . wp_create_nonce('update_database') . '">
1331 <input type="hidden" id="validate_api_key_nonce" value="' . wp_create_nonce('validate_api_key') . '">';
1332 }
1333 }
1334
1335 public function ip_lookup_page()
1336 {
1337 $disabled = (!$this->is_setup_completed());
1338
1339 $ip_lookup_status = '';
1340
1341 $ip_address = $this->post('ip_address', $this->ip());
1342
1343 if ($this->post('submit')) {
1344 if (!filter_var($ip_address, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
1345 $ip_lookup_status = '
1346 <div id="message" class="error">
1347 <p>
1348 <strong>' . __('ERROR', 'ip2location-redirection') . '</strong>:
1349 ' . __('Please enter a valid IP address.', 'ip2location-redirection') . '
1350 </p>
1351 </div>';
1352 } else {
1353 $result = $this->get_location($ip_address);
1354
1355 if (empty($result['country_code'])) {
1356 $ip_lookup_status = '
1357 <div id="message" class="error">
1358 <p>
1359 <strong>' . __('ERROR', 'ip2location-redirection') . '</strong>:
1360 ' . sprintf(__('Unable to lookup IP address %1$s.', 'ip2location-redirection'), '<strong>' . esc_html($ip_address) . '</strong>') . '
1361 </p>
1362 </div>';
1363 } else {
1364 $ip_lookup_status = '
1365 <div id="message" class="updated">
1366 <p>
1367 ' . sprintf(__('IP address %1$s belongs to %2$s.', 'ip2location-redirection'), '<code>' . esc_html($ip_address) . '</code>', '<strong>' . $result['country_name'] . ' (' . $result['country_code'] . ')' . (($result['region_name']) ? (', ' . $result['region_name']) : '') . '</strong>') . '
1368 </p>
1369 </div>';
1370 }
1371 }
1372 }
1373
1374 echo '
1375 <div class="wrap">
1376 <h1>' . __('IP Lookup', 'ip2location-redirection') . '</h1>
1377
1378 ' . $ip_lookup_status . '
1379
1380 <form method="post" novalidate="novalidate">
1381 <table class="form-table">
1382 <tr>
1383 <th scope="row"><label for="ip_address">' . __('IP Address', 'ip2location-redirection') . '</label></th>
1384 <td>
1385 <input name="ip_address" type="text" id="ip_address" value="' . esc_attr($ip_address) . '" class="regular-text"' . (($disabled) ? ' disabled' : '') . ' />
1386 <p class="description">' . __('Enter a valid IP address to lookup for country information.', 'ip2location-redirection') . '</p>
1387 </td>
1388 </tr>
1389 </table>
1390
1391 <p class="submit">
1392 <input type="submit" name="submit" id="submit" class="button button-primary" value="' . __('Lookup', 'ip2location-redirection') . '"' . (($disabled) ? ' disabled' : '') . ' />
1393 </p>
1394 </form>
1395
1396 <div class="clear"></div>
1397 </div>';
1398 }
1399
1400 public function settings_page()
1401 {
1402 $disabled = (!$this->is_setup_completed());
1403
1404 $settings_status = '';
1405
1406 $real_ip_headers = [
1407 'REMOTE_ADDR',
1408 'HTTP_CF_CONNECTING_IP',
1409 'HTTP_CLIENT_IP',
1410 'HTTP_FORWARDED',
1411 'HTTP_INCAP_CLIENT_IP',
1412 'HTTP_X_FORWARDED',
1413 'HTTP_X_FORWARDED_FOR',
1414 'HTTP_X_REAL_IP',
1415 'HTTP_X_SUCURI_CLIENTIP',
1416 ];
1417
1418 $lookup_mode = $this->post('lookup_mode', $this->get_option('lookup_mode'));
1419 $api_key = $this->post('api_key', $this->get_option('api_key'));
1420 $download_token = $this->post('download_token', $this->get_option('token'));
1421 $enable_region_redirection = $this->is_checked('enable_region_redirection', $this->get_option('enable_region_redirect'));
1422 $download_ipv4_only = $this->is_checked('download_ipv4_only', $this->get_option('download_ipv4_only'));
1423 $enable_debug_log = $this->is_checked('enable_debug_log', $this->get_option('debug_log_enabled'));
1424 $real_ip_header = $this->post('real_ip_header', $this->get_option('real_ip_header'));
1425 $enable_auto_update = $this->is_checked('enable_auto_update', $this->get_option('auto_update'));
1426
1427 if (!in_array($real_ip_header, array_values($real_ip_headers))) {
1428 $real_ip_header = '';
1429 }
1430
1431 if (!$this->is_region_supported()) {
1432 $enable_region_redirection = 0;
1433 }
1434
1435 if ($this->post('cache_nonce')) {
1436 check_admin_referer('cache', 'cache_nonce');
1437
1438 $this->cache_flush();
1439
1440 $settings_status = '
1441 <div class="updated">
1442 <p>' . __('All cache has been flushed.', 'ip2location-redirection') . '</p>
1443 </div>';
1444 }
1445
1446 if ($this->post('submit')) {
1447 check_admin_referer('save_settings');
1448
1449 if ($lookup_mode == 'ws') {
1450 if (!empty($api_key)) {
1451 $response = wp_remote_get('https://api.ip2location.io/?' . http_build_query([
1452 'key' => $api_key,
1453 'check' => 1,
1454 'source' => 'wordpress-wzdir',
1455 ]), ['timeout' => 3]);
1456
1457 $json = json_decode($response['body']);
1458
1459 if (isset($json->error)) {
1460 $response = wp_remote_get('https://api.ip2location.com/v2/?' . http_build_query([
1461 'key' => $api_key,
1462 'check' => 1,
1463 ]));
1464
1465 $json = json_decode($response['body']);
1466
1467 if (empty($json)) {
1468 $settings_status = '
1469 <div class="error">
1470 <p>
1471 <strong>' . __('ERROR', 'ip2location-redirection') . '</strong>:
1472 ' . __('Error when accessing IP2Location web service gateway.', 'ip2location-redirection') . '
1473 </p>
1474 </div>';
1475 } else {
1476 if (!preg_match('/^[0-9]+$/', $json->response)) {
1477 $settings_status = '
1478 <div class="error">
1479 <p>
1480 <strong>' . __('ERROR', 'ip2location-redirection') . '</strong>:
1481 ' . __('Invalid IP2Location API key.', 'ip2location-redirection') . '
1482 </p>
1483 </div>';
1484 } else {
1485 $this->update_option('api_key', $api_key);
1486 }
1487 }
1488 } else {
1489 if (!preg_match('/^[0-9]+$/', $json->response)) {
1490 $settings_status = '
1491 <div class="error">
1492 <p>
1493 <strong>' . __('ERROR', 'ip2location-redirection') . '</strong>:
1494 ' . __('Invalid IP2Location API key.', 'ip2location-redirection') . '
1495 </p>
1496 </div>';
1497 } else {
1498 $this->update_option('api_key', $api_key);
1499 }
1500 }
1501 } else {
1502 $this->update_option('api_key', '');
1503 }
1504 }
1505
1506 if (empty($settings_status)) {
1507 if (!$enable_debug_log) {
1508 if (file_exists(IP2LOCATION_DIR . $this->debug_log)) {
1509 @unlink(IP2LOCATION_DIR . $this->debug_log);
1510 }
1511 } else {
1512 if (!$this->get_option('private_key')) {
1513 add_option('ip2location_redirection_private_key', hash('sha256', microtime(true) . get_site_url() . get_option('admin_email')));
1514 }
1515 }
1516
1517 $this->update_option('lookup_mode', $lookup_mode);
1518 $this->update_option('enable_region_redirect', $enable_region_redirection);
1519 $this->update_option('token', $download_token);
1520 $this->update_option('debug_log_enabled', $enable_debug_log);
1521 $this->update_option('download_ipv4_only', $download_ipv4_only);
1522 $this->update_option('real_ip_header', $real_ip_header);
1523 $this->update_option('auto_update', $enable_auto_update);
1524
1525 $settings_status .= '
1526 <div id="message" class="updated">
1527 <p>' . __('Changes saved.', 'ip2location-redirection') . '</p>
1528 </div>';
1529 }
1530 }
1531
1532 $date = $this->get_database_date();
1533
1534 echo '
1535 <div class="wrap">
1536 <h1>' . __('Settings', 'ip2location-redirection') . '</h1>
1537
1538 ' . $settings_status;
1539
1540 if ($this->get_option('session_message')) {
1541 echo '
1542 <div class="updated">
1543 <p>' . $this->get_option('session_message') . '</p>
1544 </div>';
1545
1546 $this->update_option('session_message', '');
1547 }
1548
1549 echo '
1550 <form method="post" novalidate="novalidate">
1551 <table class="form-table">
1552 <tr>
1553 <th scope="row">
1554 <label for="lookup_mode">' . __('Lookup Mode', 'ip2location-redirection') . '</label>
1555 </th>
1556 <td>
1557 <select name="lookup_mode" id="lookup_mode"' . (($disabled) ? ' disabled' : '') . '>
1558 <option value="bin"' . (($lookup_mode == 'bin') ? ' selected' : '') . '> ' . __('Local BIN Database', 'ip2location-redirection') . '</option>
1559 <option value="ws"' . (($lookup_mode == 'ws') ? ' selected' : '') . '> ' . __('API Web Service', 'ip2location-redirection') . '</option>
1560 </select>
1561 </td>
1562 </tr>
1563 <tr>
1564 <td></td>
1565 <td>
1566 <div id="bin_database"' . (($lookup_mode == 'ws') ? ' style="display:none"' : '') . '>
1567 <div class="iplr-panel">
1568 <table class="form-table">
1569 <tr>
1570 <th scope="row">
1571 <label for="download_token">' . __('Download Token', 'ip2location-redirection') . '</label>
1572 </th>
1573 <td>
1574 <input type="text" name="download_token" id="download_token" value="' . esc_attr($download_token) . '" class="regular-text code input-field"' . (($disabled) ? ' disabled' : '') . ' />
1575 <p class="description">
1576 ' . __('Enter your IP2Location download token.', 'ip2location-redirection') . '
1577 </p>
1578 </td>
1579 </tr>
1580 <tr>
1581 <td></td>
1582 <td>
1583 <label for="enable_region_redirection">
1584 <input type="checkbox" name="enable_region_redirection" id="enable_region_redirection" value="true"' . (($enable_region_redirection) ? ' checked' : '') . (($disabled) ? ' disabled' : '') . '> ' . __('Enable region database', 'ip2location-redirection') . '
1585 </label>
1586
1587 <p class="description">
1588 ' . __('A larger database will be downloaded. Disable this option if your system has limited resources.', 'ip2location-redirection') . '
1589 </p>
1590 </td>
1591 </tr>
1592 <tr>
1593 <td></td>
1594 <td>
1595 <label for="download_ipv4_only">
1596 <input type="checkbox" name="download_ipv4_only" id="download_ipv4_only" value="true"' . (($download_ipv4_only) ? ' checked' : '') . (($disabled) ? ' disabled' : '') . '> ' . __('Download IPv4 database only', 'ip2location-redirection') . '
1597 </label>
1598
1599 <p class="description">
1600 ' . __('Download a smaller database which is faster in lookup speed. Perfect for website with only IPv4 supported.', 'ip2location-redirection') . '
1601 </p>
1602 </td>
1603 </tr>
1604 <tr>
1605 <th scope="row">
1606 <label>' . __('Database File', 'ip2location-redirection') . '</label>
1607 </th>
1608 <td>
1609 <div>' . ((!is_file(IP2LOCATION_DIR . $this->get_option('database'))) ? '<span class="dashicons dashicons-warning" title="' . __('Database file not found.', 'ip2location-redirection') . '"></span>' : '') . esc_html($this->get_option('database')) . '
1610 </td>
1611 </tr>
1612 <tr>
1613 <th scope="row">
1614 <label>' . __('Database Path', 'ip2location-redirection') . '</label>
1615 </th>
1616 <td>
1617 <div>' . IP2LOCATION_DIR . '</div>
1618 </td>
1619 </tr>
1620 <tr>
1621 <th scope="row">
1622 <label>' . __('Database Date', 'ip2location-redirection') . '</label>
1623 </th>
1624 <td>
1625 ' . esc_html(($date) ?: '-') . '
1626 </td>
1627 </tr>
1628 <tr>
1629 <td></td>
1630 <td>
1631 <label for="enable_auto_update">
1632 <input type="checkbox" name="enable_auto_update" id="enable_auto_update" value="true"' . (($enable_auto_update) ? ' checked' : '') . (($disabled) ? ' disabled' : '') . '> ' . __('Enable auto update', 'ip2location-redirection') . '
1633 </label>
1634
1635 <p class="description">
1636 ' . __('Enable automatic updates to keep the BIN database up to date.', 'ip2location-redirection') . '
1637 </p>
1638 </td>
1639 </tr>
1640 <tr>
1641 <td></td>
1642 <td id="update_status"><td>
1643 </tr>
1644 <tr>
1645 <td></td>
1646 <td><button id="update_ip2location_database" type="button" class="button button-secondary"' . (($disabled) ? ' disabled' : '') . '>' . __('Update Database', 'ip2location-redirection') . '</button></td>
1647 </tr>
1648 </table>
1649 </div>';
1650
1651 if (preg_match('/LITE/', $this->get_option('database'))) {
1652 echo '
1653 <p class="description">
1654 ' . sprintf(__('If you are looking for high accuracy result, you should consider using the commercial version of %1$sIP2Location BIN database%2$s.', 'ip2location-redirection'), '<a href="https://www.ip2location.com/database/db3-ip-country-region-city#wordpress-wzdir" target="_blank">', '</a>') . '
1655 </p>';
1656 }
1657 echo '
1658 </div>
1659 <div id="api_web_service"' . (($lookup_mode == 'bin') ? ' style="display:none"' : '') . '>
1660 <div class="iplr-panel">
1661 <table class="form-table">';
1662
1663 $legacyApi = false;
1664
1665 if (!empty($api_key) && preg_match('/^[0-9A-Z]{10}$/', $api_key)) {
1666 $response = wp_remote_get('https://api.ip2location.com/v2/?' . http_build_query([
1667 'key' => $api_key,
1668 'check' => 1,
1669 ]));
1670
1671 $json = json_decode($response['body']);
1672
1673 if (!empty($json)) {
1674 $legacyApi = true;
1675 }
1676 }
1677
1678 echo '
1679 <tr>
1680 <th scope="row">
1681 <label for="api_key">' . __('API Key', 'ip2location-redirection') . '</label>
1682 </th>
1683 <td>
1684 <input name="api_key" type="text" id="api_key" value="' . esc_attr($api_key) . '" class="regular-text" />';
1685
1686 if ($legacyApi) {
1687 echo ' <strong><i>(legacy API)</i></strong>';
1688 }
1689
1690 echo '
1691 <p class="description">' . sprintf(__('Your IP2Location %1$sGeolocation%2$s API key.', 'ip2location-redirection'), '<a href="https://www.ip2location.io/pricing" target="_blank">', '</a>') . '</p>
1692 </td>
1693 </tr>';
1694
1695 if (!empty($api_key) && $legacyApi) {
1696 if (!empty($json)) {
1697 if (preg_match('/^[0-9]+$/', $json->response)) {
1698 echo '
1699 <tr>
1700 <th scope="row">
1701 <label for="available_credit">' . __('Available Credit', 'ip2location-redirection') . '</label>
1702 </th>
1703 <td>
1704 ' . number_format($json->response, 0, '', ',') . '
1705 </td>
1706 </tr>';
1707 }
1708 }
1709 }
1710
1711 echo '
1712 </table>
1713 </div>
1714 </div>
1715 </td>
1716 </tr>
1717 <tr>
1718 <td colspan="2">
1719 <label for="enable_debug_log">
1720 <input type="checkbox" name="enable_debug_log" id="enable_debug_log" value="1"' . (($enable_debug_log == 1) ? ' checked' : '') . (($disabled) ? ' disabled' : '') . ' /> ' . __('Enable Debugging Log', 'ip2location-redirection') . '
1721 <p class="description">
1722 ' . sprintf(__('Debug log will store under %1s.', 'ip2location-redirection'), IP2LOCATION_DIR . $this->debug_log) . '
1723 <br>
1724 <strong>For security concerns, please disable this option after completed debugging process.</strong>
1725 </p>
1726 </label>
1727 </td>
1728 </tr>
1729 <tr>
1730 <th scope="row">
1731 <label>' . __('Real IP Detection', 'ip2location-redirection') . '</label>
1732 </th>
1733 <td>
1734 <select name="real_ip_header" id="real_ip_header">
1735 <option value=""' . ((empty($real_ip_header)) ? ' selected' : '') . '> No Override</option>';
1736
1737 foreach ($real_ip_headers as $value) {
1738 echo '
1739 <option value="' . $value . '"' . (($real_ip_header == $value) ? ' selected' : '') . '> ' . $value . '</option>';
1740 }
1741
1742 echo '
1743 </select>
1744 <p class="description">
1745 ' . __('If your WordPress is installed behind a reverse proxy or load balancer, the real IP address of the visitors may not forwarded correctly and causing inaccurate country results. Use this option to override the IP detected by IP2Location.', 'ip2location-redirection') . '
1746 </p>
1747 <p class="description">
1748 ' . __('Detected IP: <strong>' . esc_html($this->ip()) . '</strong>.', 'ip2location-redirection') . '
1749 </p>
1750 </td>
1751 </tr>
1752 <tr>
1753 <th scope="row">
1754 <label>' . __('Backup', 'ip2location-redirection') . '</label>
1755 </th>
1756 <td>
1757 <button id="btn_download_backup" type="button" class="button button-secondary">' . __('Download Backup', 'ip2location-redirection') . '</button>
1758 <p class="description">
1759 ' . __('Download all settings to restore your configuration on new installation.', 'ip2location-redirection') . '
1760 </p>
1761 </td>
1762 </tr>
1763 <tr>
1764 <th scope="row">
1765 <label>' . __('Restore', 'ip2location-redirection') . '</label>
1766 </th>
1767 <td>
1768 <div id="restore_file"></div>
1769 <p class="description">
1770 ' . __('Restore settings from previous installation.', 'ip2location-redirection') . '
1771 </p>
1772 <input type="hidden" id="restore_nonce" value="' . wp_create_nonce('restore') . '">
1773 </td>
1774 </tr>
1775 <tr>
1776 <th scope="row">
1777 <label>' . __('Cache', 'ip2location-redirection') . '</label>
1778 </th>
1779 <td>
1780 <button id="btn_clear_cache" type="button" class="button button-danger">' . __('Clear Cache', 'ip2location-redirection') . ' (' . $this->display_bytes($this->cache_size()) . ')</button>
1781 <p class="description">
1782 ' . __('Clear all cached data.', 'ip2location-redirection') . '
1783 </p>
1784 <input type="hidden" id="cache_nonce" value="' . wp_create_nonce('cache') . '">
1785 </td>
1786 </tr>
1787 </table>
1788
1789 <p class="submit">
1790 <input type="submit" name="submit" id="submit" class="button button-primary" value="' . __('Save Changes', 'ip2location-redirection') . '"' . (($disabled) ? ' disabled' : '') . ' />
1791 </p>
1792
1793 <input type="hidden" id="update_nonce" value="' . wp_create_nonce('update_database') . '">
1794 ' . wp_nonce_field('save_settings') . '
1795 </form>
1796
1797 <form id="form_download_backup" method="post">
1798 ' . wp_nonce_field('backup') . '
1799 <input type="hidden" name="action" value="download_ip2location_redirection_backup">
1800 </form>
1801
1802 <div class="clear"></div>
1803 </div>';
1804 }
1805
1806 public function redirect()
1807 {
1808 // Disable redirection for WP-CLI
1809 if (defined('WP_CLI') && WP_CLI) {
1810 return;
1811 }
1812
1813 // Disable redirection on admin pages
1814 if (is_admin() && $this->get_option('skip_admins')) {
1815 $this->write_debug_log('Redirection skipped for administrators.');
1816 return;
1817 }
1818
1819 // Disable redirection on administrator session
1820 if (current_user_can('administrator') && $this->get_option('skip_admins')) {
1821 $this->write_debug_log('Redirection skipped for administrators.');
1822 return;
1823 }
1824
1825 // Disable redirection on admin pages
1826 if (substr($_SERVER['REQUEST_URI'], 0, 9) == '/wp-login' || substr($_SERVER['REQUEST_URI'], 0, 9) == '/wp-admin') {
1827 return;
1828 }
1829
1830 // Ignore static files
1831 if (preg_match('/\.(7z|apk|avi|avif|bin|bmp|bz2|class|css|csv|dmg|doc|docx|ejs|eot|eps|exe|flac|gif|gz|ico|iso|jar|jpeg|jpg|js|mid|midi|mkv|mp3|mp4|ogg|otf|pdf|pict|pls|png|ppt|pptx|ps|rar|svg|svgz|swf|tar|tif|tiff|ttf|webm|webp|woff|woff2|xls|xlsx|zip|zst)$/i', $_SERVER['REQUEST_URI'])) {
1832 return;
1833 }
1834
1835 // Ignore internal XHR calls
1836 if (preg_match('/wp-json|admin-ajax|wc-ajax|jm-ajax|doing_wp_cron/', $_SERVER['REQUEST_URI'])) {
1837 return;
1838 }
1839
1840 if (!$this->get_option('enabled')) {
1841 $this->write_debug_log(__('Redirection disabled.', 'ip2location-redirection'));
1842
1843 return;
1844 }
1845
1846 // Overwrite headers to prevent content being cached
1847 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
1848 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
1849 header('Cache-Control: max-age=0, no-cache, no-store, must-revalidate');
1850 header('Pragma: no-cache');
1851
1852 if ($this->get_option('ip_whitelist')) {
1853 $records = explode(';', $this->get_option('ip_whitelist'));
1854
1855 foreach ($records as $record) {
1856 // CIDR notation
1857 if (strpos($record, '/') !== false) {
1858 if ($this->cidr_match($this->ip(), $record)) {
1859 $this->write_debug_log('IP is in whitelist.');
1860
1861 return;
1862 }
1863 } else {
1864 if ($this->ip() == $record) {
1865 $this->write_debug_log('IP is in whitelist.');
1866
1867 return;
1868 }
1869 }
1870 }
1871 }
1872
1873 if ($this->get_option('skip_bots') && $this->is_bot()) {
1874 $this->write_debug_log('Web crawler detected.');
1875
1876 return;
1877 }
1878
1879 if ($this->get_option('skip_ai_bots') && $this->is_ai_bot()) {
1880 $this->write_debug_log('AI crawler detected.');
1881
1882 return;
1883 }
1884
1885 if ($this->get_option('noredirect_enabled')) {
1886 if ($this->get('noredirect') === 'true') {
1887 $this->write_debug_log('"noredirect" parameter is found.');
1888
1889 return;
1890 }
1891 }
1892
1893 if ($this->get_option('first_redirect')) {
1894 if (isset($_COOKIE['ip2location_redirection_first_visit']) && strpos($_COOKIE['ip2location_redirection_first_visit'], ';') !== false) {
1895 list($time, $hash) = explode(';', $_COOKIE['ip2location_redirection_first_visit']);
1896
1897 if (md5($time . 'a09f0749-6683-5ada-882c-eb3263a252d3') == $hash) {
1898 $this->write_debug_log('Non-first visits.');
1899
1900 return;
1901 }
1902 }
1903 }
1904
1905 $time = time();
1906
1907 $expires = strtotime($this->get_option('first_redirect_cookie_lifetime') ?: '1 day');
1908 setcookie('ip2location_redirection_first_visit', $time . ';' . md5($time . 'a09f0749-6683-5ada-882c-eb3263a252d3'), $expires, '/', '', true, true);
1909
1910 if (($rules = json_decode($this->get_option('rules'))) !== null) {
1911 $result = $this->get_location($this->ip());
1912
1913 if (empty($result['country_code'])) {
1914 $this->write_debug_log('Cannot identify location.', 'ERROR');
1915
1916 return;
1917 }
1918
1919 for ($i = 0; $i < count($rules); $i++) {
1920 $is_active = (bool) $rules[$i]->is_active ?? false;
1921 $country_codes = $rules[$i]->country_codes ?? [];
1922 $page_from = $rules[$i]->page_from ?? '';
1923 $page_to = $rules[$i]->page_to ?? '';
1924 $url_from = $rules[$i]->url_from ?? '';
1925 $url_to = $rules[$i]->url_to ?? '';
1926 $path_mode = $rules[$i]->path_mode ?? 'exact';
1927 $path_keyword = $rules[$i]->path_keyword ?? '';
1928 $new_parameter = $rules[$i]->new_parameter ?? '';
1929 $wpml_code = $rules[$i]->language_code ?? '';
1930 $http_code = $rules[$i]->http_code ?? 302;
1931 $dialog_message = $rules[$i]->dialog_message ?? '';
1932
1933 if (!$is_active) {
1934 continue;
1935 }
1936
1937 if ($this->is_country_match($result, $country_codes)) {
1938 $this->write_debug_log('"' . $result['country_code'] . '" is listed in [' . implode(', ', $country_codes) . ']', 'MATCHED');
1939
1940 if ($page_from == 'path') {
1941 $trigger = false;
1942 $parts = parse_url($this->get_current_url());
1943 $path = $parts['path'] ?? '';
1944
1945 switch ($path_mode) {
1946 case 'exact':
1947 if ($path == $path_keyword) {
1948 $trigger = true;
1949 $this->write_debug_log('Path "' . $path . '" matched "' . $path_keyword . '".', 'MATCHED');
1950 }
1951 break;
1952 case 'contains':
1953 if (strpos($path, $path_keyword) !== false) {
1954 $trigger = true;
1955 $this->write_debug_log('Path "' . $path . '" contains "' . $path_keyword . '".', 'MATCHED');
1956 }
1957 break;
1958 case 'not_contains':
1959 if (strpos($path, $path_keyword) === false) {
1960 $trigger = true;
1961 $this->write_debug_log('Path "' . $path . '" does not contain "' . $path_keyword . '".', 'MATCHED');
1962 }
1963 break;
1964 case 'begin':
1965 if (str_starts_with($path, $path_keyword)) {
1966 $trigger = true;
1967 $this->write_debug_log('Path "' . $path . '" starts with "' . $path_keyword . '".', 'MATCHED');
1968 }
1969 break;
1970 case 'end':
1971 if (str_ends_with($path, $path_keyword)) {
1972 $trigger = true;
1973 $this->write_debug_log('Path "' . $path . '" ends with "' . $path_keyword . '".', 'MATCHED');
1974 }
1975 break;
1976 }
1977
1978 if ($trigger) {
1979 if ($page_to == 'url') {
1980 if ($_SERVER['QUERY_STRING']) {
1981 parse_str($_SERVER['QUERY_STRING'], $query_string);
1982
1983 unset($query_string['page_id'], $query_string['p']);
1984
1985 $parts = parse_url($url_to);
1986
1987 $post_query = [];
1988
1989 if (isset($parts['query'])) {
1990 parse_str($parts['query'], $post_query);
1991 }
1992
1993 $path = (isset($parts['path'])) ? $parts['path'] : '';
1994
1995 $queries = array_merge($query_string, $post_query);
1996
1997 unset($queries['p']);
1998
1999 $extra_queries = [];
2000
2001 if (!empty($new_parameter)) {
2002 parse_str($new_parameter, $extra_queries);
2003 }
2004
2005 $target_url = $this->build_url($parts['scheme'], $parts['host'], $path, array_merge($queries, $extra_queries));
2006
2007 // Prevent infinite loop
2008 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2009 return;
2010 }
2011
2012 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2013 }
2014
2015 // Prevent infinite loop
2016 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($url_to)) {
2017 return;
2018 }
2019
2020 $this->redirect_to($url_to, $http_code, $i, $dialog_message);
2021 }
2022
2023 list($page_type, $page_id) = explode('-', $page_to);
2024
2025 // Prevent infinite redirect to same page
2026 if ($page_id === $this->get_page_id() && !$wpml_code) {
2027 return;
2028 }
2029
2030 $target_url = $this->get_permalink($page_id);
2031
2032 if ($wpml_code) {
2033 $translated_id = apply_filters('wpml_object_id', $page_id, get_post_type($page_id), true, $wpml_code);
2034 if ($translated_id) {
2035 $target_url = $this->get_permalink($translated_id);
2036 $wpml_settings = get_option('icl_sitepress_settings');
2037 if (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 1 && $wpml_code !== ($wpml_settings['default_language'] ?? '')) {
2038 if (strpos($target_url, '://') === false) {
2039 $target_url = '/' . $wpml_code . $target_url;
2040 } else {
2041 $parts = parse_url($target_url);
2042 $parts['path'] = '/' . $wpml_code . ($parts['path'] ?? '/');
2043 $target_url = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], []);
2044 }
2045 } elseif (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 3) {
2046 $target_url .= ((strpos($target_url, '?') === false) ? '?' : '&') . 'lang=' . $wpml_code;
2047 }
2048 }
2049 }
2050
2051 // Normalize to full URL
2052 if (strpos($target_url, '://') === false && $this->http_host()) {
2053 $parts = parse_url($this->get_current_url());
2054 $target_url = $this->build_url($parts['scheme'], $parts['host'], $target_url, []);
2055 }
2056
2057 // Prevent infinite loop
2058 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2059 return;
2060 }
2061
2062 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2063 }
2064 }
2065
2066 if ($page_from == 'domain') {
2067 // Keep query string
2068 if (substr($url_from, 0, 1) == '*') {
2069 if (substr($url_from, 1) == $this->http_host()) {
2070 $this->write_debug_log('Domain "' . $url_from . '" matched "' . $this->http_host() . '".', 'MATCHED');
2071 $target_url = str_replace(substr($url_from, 1), $url_to . ((!empty($new_parameter) ? (((strpos($url_to, '?') === false) ? '?' : '&') . $new_parameter) : '')), $this->get_current_url());
2072 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2073 return;
2074 }
2075 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2076 } else {
2077 $this->write_debug_log('Domain "' . $url_from . '" not match "' . $this->http_host() . '".');
2078 }
2079 } else {
2080 if ($url_from == $this->http_host()) {
2081 $this->write_debug_log('Domain "' . $url_from . '" matched "' . $this->http_host() . '".', 'MATCHED');
2082 $target_url = str_replace($url_from, $url_to . ((!empty($new_parameter) ? ('?' . $new_parameter) : '')), $this->get_current_url(false));
2083 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2084 return;
2085 }
2086 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2087 } else {
2088 $this->write_debug_log('Domain "' . $url_from . '" not match "' . $this->http_host() . '".');
2089 }
2090 }
2091 }
2092
2093 if ($this->get_option('ignore_query_string') && strpos($this->get_current_url(), '?') !== false) {
2094 // Remove query string
2095 $current_url = trim(substr($this->get_current_url(), 0, strpos($this->get_current_url(), '?')), '/');
2096 } else {
2097 $current_url = trim($this->get_current_url(), '/');
2098 }
2099
2100 if ($page_from == 'any' || ($page_from == 'home' && $this->is_home()) || ($page_from == 'url' && $current_url == trim($url_from, '/'))) {
2101 if ($page_to == 'url') {
2102 if ($_SERVER['QUERY_STRING']) {
2103 parse_str($_SERVER['QUERY_STRING'], $query_string);
2104
2105 unset($query_string['page_id'], $query_string['p']);
2106
2107 $parts = parse_url($url_to);
2108
2109 $post_query = [];
2110
2111 if (isset($parts['query'])) {
2112 parse_str($parts['query'], $post_query);
2113 }
2114
2115 $path = (isset($parts['path'])) ? $parts['path'] : '';
2116
2117 $queries = array_merge($query_string, $post_query);
2118
2119 unset($queries['p']);
2120
2121 $extra_queries = [];
2122
2123 if (!empty($new_parameter)) {
2124 parse_str($new_parameter, $extra_queries);
2125 }
2126
2127 $target_url = $this->build_url($parts['scheme'], $parts['host'], $path, array_merge($queries, $extra_queries));
2128
2129 // Prevent infinite loop
2130 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2131 return;
2132 }
2133
2134 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2135 }
2136
2137 // Prevent infinite loop
2138 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($url_to)) {
2139 return;
2140 }
2141
2142 $this->redirect_to($url_to, $http_code, $i, $dialog_message);
2143 }
2144
2145 list($page_type, $page_id) = explode('-', $page_to);
2146
2147 // Prevent infinite redirect to same page
2148 if ($page_id === $this->get_page_id() && !$wpml_code) {
2149 return;
2150 }
2151
2152 $target_url = $this->get_permalink($page_id);
2153
2154 if ($wpml_code) {
2155 $translated_id = apply_filters('wpml_object_id', $page_id, get_post_type($page_id), true, $wpml_code);
2156 if ($translated_id) {
2157 $target_url = $this->get_permalink($translated_id);
2158 $wpml_settings = get_option('icl_sitepress_settings');
2159 if (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 1 && $wpml_code !== ($wpml_settings['default_language'] ?? '')) {
2160 if (strpos($target_url, '://') === false) {
2161 $target_url = '/' . $wpml_code . $target_url;
2162 } else {
2163 $parts = parse_url($target_url);
2164 $parts['path'] = '/' . $wpml_code . ($parts['path'] ?? '/');
2165 $target_url = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], []);
2166 }
2167 } elseif (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 3) {
2168 $target_url .= ((strpos($target_url, '?') === false) ? '?' : '&') . 'lang=' . $wpml_code;
2169 }
2170 }
2171 }
2172
2173 // Normalize to full URL
2174 if (strpos($target_url, '://') === false && $this->http_host()) {
2175 $parts = parse_url($this->get_current_url());
2176 $target_url = $this->build_url($parts['scheme'], $parts['host'], $target_url, []);
2177 }
2178
2179 // Prevent infinite loop
2180 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2181 return;
2182 }
2183
2184 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2185 }
2186
2187 if ($page_from == 'home') {
2188 $page_id = get_option('page_on_front');
2189 } else {
2190 if (strpos($page_from, '-') === false) {
2191 if ($page_from == 'url') {
2192 $this->write_debug_log('URL "' . $this->get_current_url() . '" not match "' . $url_from . '".');
2193 } else {
2194 $this->write_debug_log('Invalid page "' . $page_from . '".');
2195 }
2196
2197 continue;
2198 }
2199
2200 list($page_type, $page_id) = explode('-', $page_from);
2201 }
2202
2203 if ($page_id === $this->get_page_id()) {
2204 if ($page_to == 'url') {
2205 if ($_SERVER['QUERY_STRING']) {
2206 parse_str($_SERVER['QUERY_STRING'], $query_string);
2207
2208 unset($query_string['page_id'], $query_string['p'], $query_string['add-to-cart']);
2209
2210 $parts = parse_url($url_to);
2211
2212 $post_query = [];
2213
2214 if (isset($parts['query'])) {
2215 parse_str($parts['query'], $post_query);
2216 }
2217
2218 $queries = array_merge($post_query, $query_string);
2219
2220 unset($queries['p']);
2221
2222 $extra_queries = [];
2223
2224 if (!empty($new_parameter)) {
2225 parse_str($new_parameter, $extra_queries);
2226 }
2227
2228 $target_url = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], array_merge($queries, $extra_queries));
2229 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2230 return;
2231 }
2232 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2233 }
2234
2235 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($url_to)) {
2236 return;
2237 }
2238 $this->redirect_to($url_to, $http_code, $i, $dialog_message);
2239 }
2240
2241 list($page_type, $page_id) = explode('-', $page_to);
2242
2243 // Prevent infinite redirect to same page
2244 if ($page_id === $this->get_page_id() && !$wpml_code) {
2245 return;
2246 }
2247
2248 if ($_SERVER['QUERY_STRING']) {
2249 parse_str($_SERVER['QUERY_STRING'], $query_string);
2250
2251 unset($query_string['page_id'], $query_string['p'], $query_string['add-to-cart']);
2252
2253 $post_url = $this->get_permalink($page_id);
2254
2255 if ($wpml_code) {
2256 $translated_id = apply_filters('wpml_object_id', $page_id, get_post_type($page_id), true, $wpml_code);
2257 if ($translated_id) {
2258 $post_url = $this->get_permalink($translated_id);
2259 $wpml_settings = get_option('icl_sitepress_settings');
2260 if (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 1 && $wpml_code !== ($wpml_settings['default_language'] ?? '')) {
2261 if (strpos($post_url, '://') === false) {
2262 $post_url = '/' . $wpml_code . $post_url;
2263 } else {
2264 $parts = parse_url($post_url);
2265 $parts['path'] = '/' . $wpml_code . ($parts['path'] ?? '/');
2266 $post_url = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], []);
2267 }
2268 } elseif (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 3) {
2269 $post_url .= ((strpos($post_url, '?') === false) ? '?' : '&') . 'lang=' . $wpml_code;
2270 }
2271 }
2272 }
2273
2274 $parts = parse_url($post_url);
2275
2276 $post_query = [];
2277
2278 if (isset($parts['query'])) {
2279 parse_str($parts['query'], $post_query);
2280 }
2281
2282 $queries = array_merge($post_query, $query_string);
2283
2284 $extra_queries = [];
2285 if (!empty($new_parameter)) {
2286 parse_str($new_parameter, $extra_queries);
2287 }
2288
2289 $target_url = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], array_merge($queries, $extra_queries));
2290 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($target_url)) {
2291 return;
2292 }
2293 $this->redirect_to($target_url, $http_code, $i, $dialog_message);
2294 }
2295
2296 $link = $this->get_permalink($page_id);
2297
2298 if ($wpml_code) {
2299 $translated_id = apply_filters('wpml_object_id', $page_id, get_post_type($page_id), true, $wpml_code);
2300 if ($translated_id) {
2301 $link = $this->get_permalink($translated_id);
2302 $wpml_settings = get_option('icl_sitepress_settings');
2303 if (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 1 && $wpml_code !== ($wpml_settings['default_language'] ?? '')) {
2304 if (strpos($link, '://') === false) {
2305 $link = '/' . $wpml_code . $link;
2306 } else {
2307 $parts = parse_url($link);
2308 $parts['path'] = '/' . $wpml_code . ($parts['path'] ?? '/');
2309 $link = $this->build_url($parts['scheme'], $parts['host'], $parts['path'], []);
2310 }
2311 } elseif (isset($wpml_settings['language_negotiation_type']) && $wpml_settings['language_negotiation_type'] == 3) {
2312 $link .= ((strpos($link, '?') === false) ? '?' : '&') . 'lang=' . $wpml_code;
2313 }
2314 }
2315 }
2316 if (!empty($new_parameter)) {
2317 $link .= ((strpos($link, '?') === false) ? '?' : '&') . $new_parameter;
2318 }
2319
2320 // Normalize to full URL
2321 if (strpos($link, '://') === false && $this->http_host()) {
2322 $parts = parse_url($this->get_current_url());
2323 $link = $this->build_url($parts['scheme'], $parts['host'], $link, []);
2324 }
2325
2326 // Prevent infinite loop
2327 if ($this->normalize_url($this->get_current_url()) === $this->normalize_url($link)) {
2328 return;
2329 }
2330
2331 $this->redirect_to($link, $http_code, $i, $dialog_message);
2332 }
2333
2334 $this->write_debug_log('Page is not matched.');
2335 } else {
2336 $this->write_debug_log('"' . $result['country_code'] . '" is NOT listed in [' . implode(', ', $country_codes) . ']');
2337 }
2338 }
2339 }
2340 }
2341
2342 public function footer()
2343 {
2344 echo "<!--\n";
2345 echo "The IP2Location Redirection is using IP2Location LITE geolocation database. Please visit https://lite.ip2location.com for more information.\n";
2346 echo sha1(microtime()) . "\n";
2347 echo "-->\n";
2348 }
2349
2350 public function write_debug_log($message, $action = 'ABORTED')
2351 {
2352 if (!$this->get_option('debug_log_enabled')) {
2353 return;
2354 }
2355
2356 error_log(json_encode([
2357 'time' => gmdate('Y-m-d H:i:s'),
2358 'client_ip' => $this->ip(),
2359 'location' => $this->session['location'],
2360 'lookup_by' => $this->session['lookup_mode'],
2361 'cache' => $this->session['cache'],
2362 'uri' => $this->get_current_url(),
2363 'message' => $message,
2364 'action' => $action,
2365 ]) . "\n", 3, IP2LOCATION_DIR . $this->debug_log);
2366 }
2367
2368 public function admin_footer_text($footer_text)
2369 {
2370 global $pagenow;
2371
2372 $current_screen = get_current_screen();
2373
2374 if ($current_screen && strpos($current_screen->id, 'ip2location-redirection') !== false) {
2375 $footer_text .= sprintf(
2376 __('Enjoyed %1$s? Please leave us a %2$s rating. A huge thanks in advance!', 'ip2location-redirection'),
2377 '<strong>' . __('IP2Location Redirection', 'ip2location-redirection') . '</strong>',
2378 '<a href="https://wordpress.org/support/plugin/ip2location-redirection/reviews/?filter=5/#new-post" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
2379 );
2380 }
2381
2382 if ($pagenow == 'plugins.php') {
2383 return $footer_text . '
2384 <div id="ip2location-redirection-feedback-modal" class="ip2location-modal">
2385 <div class="ip2location-modal-content">
2386 <span class="ip2location-close">&times;</span>
2387
2388 <p>
2389 <h3>' . __('Would you mind sharing with us the reason to deactivate the plugin?', 'ip2location-redirection') . '</h3>
2390 </p>
2391 <span id="ip2location-redirection-feedback-response"></span>
2392 <p>
2393 <label>
2394 <input type="radio" name="ip2location-redirection-feedback" value="1"> ' . __('I no longer need the plugin', 'ip2location-redirection') . '
2395 </label>
2396 </p>
2397 <p>
2398 <label>
2399 <input type="radio" name="ip2location-redirection-feedback" value="2"> ' . __('I couldn\'t get the plugin to work', 'ip2location-redirection') . '
2400 </label>
2401 </p>
2402 <p>
2403 <label>
2404 <input type="radio" name="ip2location-redirection-feedback" value="3"> ' . __('The plugin doesn\'t meet my requirements', 'ip2location-redirection') . '
2405 </label>
2406 </p>
2407 <p>
2408 <label>
2409 <input type="radio" name="ip2location-redirection-feedback" value="4"> ' . __('Other concerns', 'ip2location-redirection') . '
2410 <br><br>
2411 <textarea id="ip2location-redirection-feedback-other" style="display:none;width:100%"></textarea>
2412 </label>
2413 </p>
2414 <p>
2415 <div style="float:left">
2416 <input type="button" id="ip2location-redirection-submit-feedback-button" class="button button-danger" value="' . __('Submit & Deactivate', 'ip2location-redirection') . '" />
2417 </div>
2418 <div style="float:right">
2419 <a href="#">' . __('Skip & Deactivate', 'ip2location-redirection') . '</a>
2420 </div>
2421 <div style="clear:both"></div>
2422 </p>
2423
2424 <input type="hidden" id="ip2location-redirection-submit-feedback-nonce" value="' . wp_create_nonce('submit_feedback') . '">
2425 </div>
2426 </div>';
2427 }
2428
2429 return $footer_text;
2430 }
2431
2432 public function hourly_event()
2433 {
2434 $this->cache_clear();
2435 $this->set_priority();
2436 }
2437
2438 public function daily_event()
2439 {
2440 // Do not run update if lookup mode is not bin
2441 if ($this->get_option('lookup_mode') != 'bin') {
2442 return;
2443 }
2444
2445 // Do not run update if auto update is disabled
2446 if (!$this->get_option('auto_update')) {
2447 return;
2448 }
2449
2450 $token = $this->get_option('token');
2451 $enable_region = $this->get_option('enable_region_redirect');
2452 $ipv4_only = $this->get_option('download_ipv4_only');
2453
2454 if (empty($token)) {
2455 return;
2456 }
2457
2458 // Do not perform updates if the database date is less than 29 days
2459 if (strtotime((string) $this->get_database_date()) > strtotime('-29 days')) {
2460 return;
2461 }
2462
2463 try {
2464 $this->perform_database_update($token, $enable_region, $ipv4_only);
2465 $this->write_debug_log('IP2Location BIN Database updated via cron job.', 'SUCCESS');
2466 } catch (Exception $e) {
2467 $this->write_debug_log('IP2Location BIN Database update failed: ' . $e->getMessage(), 'ERROR');
2468 }
2469 }
2470
2471 private function normalize_url($url)
2472 {
2473 // Convert relative URLs to absolute for comparison
2474 if (strpos($url, '://') === false) {
2475 $parts = parse_url($this->get_current_url());
2476 if ($parts === false || !isset($parts['scheme']) || !isset($parts['host'])) {
2477 return $url;
2478 }
2479 $url = $parts['scheme'] . '://' . $parts['host'] . '/' . ltrim($url, '/');
2480 }
2481
2482 $parsed = parse_url($url);
2483 if ($parsed === false || !isset($parsed['host'])) {
2484 return $url;
2485 }
2486
2487 $scheme = $parsed['scheme'] ?? 'https';
2488 $host = $parsed['host'];
2489 $path = $parsed['path'] ?? '/';
2490
2491 return rtrim($scheme . '://' . $host . $path, '/');
2492 }
2493
2494 private function wpdb_query($query, ...$args)
2495 {
2496 if (count(func_get_args()) > 1) {
2497 return $GLOBALS['wpdb']->query($GLOBALS['wpdb']->prepare($query, ...$args));
2498 }
2499
2500 return $GLOBALS['wpdb']->query($query);
2501 }
2502
2503 private function wpdb_get_value($query, ...$args)
2504 {
2505 if (count(func_get_args()) > 1) {
2506 return $GLOBALS['wpdb']->get_var($GLOBALS['wpdb']->prepare($query, ...$args));
2507 }
2508
2509 return $GLOBALS['wpdb']->get_var($query);
2510 }
2511
2512 private function wpdb_get_results($query, ...$args)
2513 {
2514 if (count(func_get_args()) > 1) {
2515 return $GLOBALS['wpdb']->get_results($GLOBALS['wpdb']->prepare($query, ...$args));
2516 }
2517
2518 return $GLOBALS['wpdb']->get_results($query);
2519 }
2520
2521 private function post($key, $default = '', $checkbox = false)
2522 {
2523 return (isset($_POST[$key])) ? ((is_array($_POST[$key])) ? $this->sanitize_array($_POST[$key]) : sanitize_text_field($_POST[$key])) : $default;
2524 }
2525
2526 private function get($key, $default = '', $checkbox = false)
2527 {
2528 return (isset($_GET[$key])) ? ((is_array($_GET[$key])) ? $this->sanitize_array($_GET[$key]) : sanitize_text_field($_GET[$key])) : $default;
2529 }
2530
2531 private function is_checked($key, $default = 0)
2532 {
2533 return ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_POST[$key])) ? 0 : ((isset($_POST[$key])) ? 1 : (int) $default);
2534 }
2535
2536 private function update_option($key, $value)
2537 {
2538 if (!in_array($key, $this->allowed_options)) {
2539 return false;
2540 }
2541
2542 return update_option('ip2location_redirection_' . $key, $value);
2543 }
2544
2545 private function get_option($key)
2546 {
2547 return get_option('ip2location_redirection_' . $key);
2548 }
2549
2550 private function cache_plugin_detected()
2551 {
2552 $plugins = [
2553 'Breeze' => 'breeze/breeze.php',
2554 'Cache Enabler' => 'cache-enabler/cache-enabler.php',
2555 'LiteSpeed Cache' => 'litespeed-cache/litespeed-cache.php',
2556 'Super Page Cache' => 'wp-cloudflare-page-cache/wp-cloudflare-super-page-cache.php',
2557 'W3 Total Cache' => 'w3-total-cache/w3-total-cache.php',
2558 'WP Fastest Cache' => 'wp-fastest-cache/wpFastestCache.php',
2559 'WP Optimizer' => 'wp-optimize/wp-optimize.php',
2560 'WP Rocket' => 'wp-rocket/wp-rocket.php',
2561 'WP Super Cache' => 'wp-super-cache/wp-cache.php',
2562 ];
2563
2564 foreach ($plugins as $name => $path) {
2565 if (is_plugin_active($path)) {
2566 return $name;
2567 }
2568 }
2569
2570 return false;
2571 }
2572
2573 private function set_priority()
2574 {
2575 global $pagenow;
2576
2577 // Do not do this in plugins page to prevent deactivation issues.
2578 if ($pagenow != 'plugins.php') {
2579 // Make sure this plugin loaded as first priority.
2580 $this_plugin = plugin_basename(trim(preg_replace('/(.*)plugins\/(.*)$/', WP_PLUGIN_DIR . '/$2', __FILE__)));
2581 $active_plugins = get_option('active_plugins');
2582
2583 if (!is_array($active_plugins)) {
2584 return;
2585 }
2586
2587 // Remove all existing occurrences first to avoid duplicate entries
2588 $expected = array_values(array_diff($active_plugins, [$this_plugin]));
2589 array_unshift($expected, $this_plugin);
2590
2591 if ($expected !== $active_plugins) {
2592 update_option('active_plugins', $expected);
2593 }
2594 }
2595 }
2596
2597 private function is_country_match($result, $codes)
2598 {
2599 $country_code = $result['country_code'];
2600 $region_code = $result['region_code'];
2601
2602 if (is_array($codes)) {
2603 // Check for "Any Country" option
2604 if (in_array('ANY', $codes)) {
2605 return true;
2606 }
2607
2608 $index = 0;
2609
2610 foreach ($codes as $country) {
2611 if ($country_code == $country) {
2612 return true;
2613 }
2614
2615 if (strpos($country, '.') !== false) {
2616 if ($region_code == $country) {
2617 return true;
2618 }
2619 }
2620
2621 if (strpos($country, '.') !== false) {
2622 if (substr($country, 0, 1) == '-' && substr($country, 1) != $region_code) {
2623 ++$index;
2624 }
2625 } else {
2626 if (substr($country, 0, 1) == '-' && substr($country, 1) != $country_code) {
2627 ++$index;
2628 }
2629 }
2630
2631 if ($index == count($codes)) {
2632 return true;
2633 }
2634 }
2635
2636 return false;
2637 }
2638
2639 if ($country_code == $codes) {
2640 return true;
2641 }
2642
2643 if (substr($codes, 0, 1) == '-' && substr($codes, 1) != $country_code) {
2644 return true;
2645 }
2646
2647 return false;
2648 }
2649
2650 private function is_bot()
2651 {
2652 return preg_match('/baidu|bingbot|facebookexternalhit|googlebot|-google|ia_archiver|msnbot|naverbot|pingdom|seznambot|slurp|teoma|twitter|yandex|yeti|linkedinbot|pinterest/i', $this->user_agent());
2653 }
2654
2655 private function is_ai_bot()
2656 {
2657 $ai_bots = [
2658 'GPTBot', // OpenAI web crawler for training
2659 'ChatGPT-User', // ChatGPT web browsing plugin
2660 'OAI-SearchBot', // OpenAI Search
2661 'anthropic-ai', // Anthropic (Claude)
2662 'ClaudeBot', // Anthropic (Claude) general bot
2663 'Claude-Web', // Anthropic (Claude) web bot
2664 'Google-Extended', // Google's AI training crawler (Gemini)
2665 'PerplexityBot', // Perplexity AI search
2666 'cohere-ai', // Cohere AI
2667 'omgili', // Webhose/Omgili (Often used for AI datasets)
2668 'omgilibot', // Webhose/Omgili
2669 'Diffbot', // Diffbot (Visual AI scraping)
2670 'Bytespider', // ByteDance (TikTok/Douyin AI crawler)
2671 'CCBot', // Common Crawl (Primary data source for many LLMs)
2672 'Amazonbot', // Amazon's general crawler (often used for Alexa/AI)
2673 'Applebot-Extended', // Apple's AI training bot
2674 'meta-externalagent', // Meta (Facebook) AI crawler
2675 'mistral-ai', // Mistral AI
2676 'ImagesiftBot', // Image scraper often used for AI vision training
2677 'PetalBot', // Petal Search (Huawei), sometimes used for AI
2678 'Scrapy', // General Python scraper framework (often used for AI scraping)
2679 'YouBot' // You.com AI search engine
2680 ];
2681
2682 return preg_match('/(' . implode('|', array_map('preg_quote', $ai_bots)) . ')/i', $this->user_agent());
2683 }
2684
2685 private function user_agent()
2686 {
2687 return $_SERVER['HTTP_USER_AGENT'] ?? '';
2688 }
2689
2690 private function ip()
2691 {
2692 if ($this->get_option('real_ip_header')) {
2693 return $_SERVER[$this->get_option('real_ip_header')] ?? $_SERVER['REMOTE_ADDR'];
2694 }
2695
2696 // Possible using CloudFlare service
2697 if (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP)) {
2698 // Make sure originated IP is coming from CloudFlare network
2699 $networks = [
2700 '173.245.48.0/20',
2701 '103.21.244.0/22',
2702 '103.22.200.0/22',
2703 '103.31.4.0/22',
2704 '141.101.64.0/18',
2705 '108.162.192.0/18',
2706 '190.93.240.0/20',
2707 '188.114.96.0/20',
2708 '197.234.240.0/22',
2709 '198.41.128.0/17',
2710 '162.158.0.0/15',
2711 '104.16.0.0/13',
2712 '104.24.0.0/14',
2713 '172.64.0.0/13',
2714 '131.0.72.0/22',
2715 '2400:cb00::/32',
2716 '2606:4700::/32',
2717 '2803:f800::/32',
2718 '2405:b500::/32',
2719 '2405:8100::/32',
2720 '2a06:98c0::/29',
2721 '2c0f:f248::/32',
2722 ];
2723
2724 foreach ($networks as $network) {
2725 if ($this->cidr_match($_SERVER['REMOTE_ADDR'], $network)) {
2726 return $_SERVER['HTTP_CF_CONNECTING_IP'];
2727 }
2728 }
2729 }
2730
2731 // Possible Securi Firewall
2732 if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
2733 // Make sure originated IP is coming from Securi network
2734 $networks = [
2735 '192.88.134.0/23',
2736 '185.93.228.0/22',
2737 '66.248.200.0/22',
2738 '208.109.0.0/22',
2739 '2a02:fe80::/29',
2740 ];
2741
2742 foreach ($networks as $network) {
2743 if ($this->cidr_match($_SERVER['REMOTE_ADDR'], $network)) {
2744 return $_SERVER['HTTP_X_FORWARDED_FOR'];
2745 }
2746 }
2747 }
2748
2749 // Possible local reverse proxy server
2750 if (!filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
2751 if (isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
2752 return $_SERVER['HTTP_X_REAL_IP'];
2753 }
2754
2755 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
2756 // Get server IP address
2757 $server_ip = (isset($_SERVER['SERVER_ADDR'])) ? $_SERVER['SERVER_ADDR'] : '';
2758
2759 $ip = trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
2760
2761 if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE) && $ip != $server_ip) {
2762 return $ip;
2763 }
2764 }
2765 }
2766
2767 return $_SERVER['REMOTE_ADDR'];
2768 }
2769
2770 private function is_home()
2771 {
2772 if (isset($_SERVER['REQUEST_URI']) && preg_replace('/\?[^$]*/', '', $_SERVER['REQUEST_URI']) == '/') {
2773 return true;
2774 }
2775
2776 return is_home();
2777 }
2778
2779 private function build_url($scheme, $host, $path, $queries)
2780 {
2781 if (!$host) {
2782 return $path . (($queries) ? ('?' . http_build_query($queries)) : '');
2783 }
2784
2785 return $scheme . '://' . $host . (($path) ?: '/') . (($queries) ? ('?' . http_build_query($queries)) : '');
2786 }
2787
2788 private function get_current_url($add_query = true)
2789 {
2790 if (empty($this->http_host())) {
2791 return '';
2792 }
2793
2794 $current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' ? 'https' : 'http') . '://' . $this->http_host() . $_SERVER['REQUEST_URI'];
2795
2796 $parts = parse_url($current_url);
2797
2798 $queries = [];
2799
2800 if (isset($parts['query'])) {
2801 parse_str($parts['query'], $queries);
2802 }
2803
2804 return $this->build_url($parts['scheme'], $parts['host'], (isset($parts['path'])) ? $parts['path'] : '', ($add_query) ? $queries : []);
2805 }
2806
2807 private function redirect_to($url, $mode, $rule_index, $message = '')
2808 {
2809 if (preg_match('/page_id=([0-9]+)$/', $url, $matches)) {
2810 $url = $this->get_permalink($matches[1]);
2811 }
2812
2813 $url = preg_replace('/^\/+/', '/', $url);
2814
2815 switch ($mode) {
2816 case 'dialog':
2817 $escaped_message = esc_html($message);
2818 $escaped_url = esc_url($url);
2819 echo <<< HTML
2820 <!DOCTYPE html>
2821 <html lang="en">
2822 <head>
2823 <title>Redirection</title>
2824 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/css/bootstrap.min.css">
2825 </head>
2826 <body class="bg-secondary-subtle">
2827 <div class="container mt-5">
2828 <div class="row">
2829 <div class="col-12 col-md-6 offset-md-3 text-center">
2830 <div class="card w-100">
2831 <div class="card-body">
2832 <h5 class="card-title">Redirection</h5>
2833 <p class="card-text">
2834 <div class="alert alert-secondary">{$escaped_message}</div>
2835 </p>
2836 <button class="btn btn-dark" onclick="window.location.href = '{$escaped_url}'">Go to Destination</button>
2837 </div>
2838 </div>
2839 </div>
2840 </div>
2841 </div>
2842 </body>
2843 </html>
2844 HTML;
2845
2846 $this->write_debug_log('Destination: ' . $url, 'DIALOG DISPLAYED');
2847 break;
2848 case '301':
2849 header('HTTP/1.1 301 Moved Permanently');
2850 header('Location: ' . $url, true, 301);
2851
2852 $this->write_debug_log('Destination: ' . $url, 'REDIRECTED');
2853 break;
2854
2855 case '302':
2856 header('HTTP/1.1 302 Found');
2857 header('Location: ' . $url, true, 302);
2858
2859 $this->write_debug_log('Destination: ' . $url, 'REDIRECTED');
2860 break;
2861 }
2862
2863 $rules = json_decode($this->get_option('rules'));
2864
2865 $rules[$rule_index]->total_hits++;
2866 $rules[$rule_index]->last_access = date('Y-m-d H:i:s');
2867 $this->update_option('rules', json_encode($rules));
2868
2869 exit;
2870 }
2871
2872 private function get_location($ip)
2873 {
2874 // Read result from cache to prevent duplicate lookup.
2875 if ($data = $this->cache_get($ip)) {
2876 $this->session['location'] = $data->country_code . (($data->region_code) ? (', ' . $data->region_code) : '');
2877 $this->session['lookup_mode'] = 'Cache';
2878 $this->session['cache'] = true;
2879
2880 return [
2881 'country_code' => $data->country_code,
2882 'country_name' => $data->country_name,
2883 'region_code' => $data->region_code,
2884 'region_name' => $data->region_name,
2885 ];
2886 }
2887
2888 switch ($this->get_option('lookup_mode')) {
2889 // IP2Location Web Service
2890 case 'ws':
2891 $this->session['lookup_mode'] = 'WS';
2892
2893 $response = wp_remote_get('https://api.ip2location.io/?' . http_build_query([
2894 'key' => $this->get_option('api_key'),
2895 'ip' => $ip,
2896 'source' => 'wp-redirection',
2897 ]));
2898
2899 $json = json_decode($response['body']);
2900
2901 if (isset($json->error)) {
2902 $response = wp_remote_get('https://api.ip2location.com/v2/?' . http_build_query([
2903 'key' => $this->get_option('api_key'),
2904 'ip' => $ip,
2905 'package' => ($this->get_option('enable_region_redirect')) ? 'WS3' : 'WS1',
2906 ]));
2907
2908 $json = json_decode($response['body']);
2909
2910 if (empty($json)) {
2911 $this->write_debug_log('Web service timed out.', 'ERROR');
2912
2913 return [
2914 'country_code' => '',
2915 'country_name' => '',
2916 'region_code' => '',
2917 'region_name' => '',
2918 ];
2919 } elseif ($json->response != 'OK') {
2920 $this->write_debug_log($json->response, 'ERROR');
2921
2922 return [
2923 'country_code' => '',
2924 'country_name' => '',
2925 'region_code' => '',
2926 'region_name' => '',
2927 ];
2928 }
2929 }
2930
2931 // Store result into cache for later use.
2932 $caches = [
2933 'country_code' => $json->country_code,
2934 'country_name' => $this->get_country_name($json->country_code),
2935 'region_code' => $this->get_region_code($json->country_code, $json->region_name),
2936 'region_name' => $json->region_name,
2937 ];
2938
2939 $this->cache_add($ip, $caches);
2940
2941 $this->session['location'] = $caches['country_code'] . (($caches['region_code']) ? (', ' . $caches['region_code']) : '');
2942
2943 return [
2944 'country_code' => $caches['country_code'],
2945 'country_name' => $caches['country_name'],
2946 'region_code' => $caches['region_code'],
2947 'region_name' => $caches['region_name'],
2948 ];
2949
2950 // Local BIN database
2951 default:
2952 case 'bin':
2953 $this->session['lookup_mode'] = 'BIN';
2954
2955 // Make sure IP2Location database is exist.
2956 if (!is_file(IP2LOCATION_DIR . $this->get_option('database'))) {
2957 $this->write_debug_log('Database not found.', 'ERROR');
2958
2959 return [
2960 'country_code' => '',
2961 'country_name' => '',
2962 'region_code' => '',
2963 'region_name' => '',
2964 ];
2965 }
2966
2967 // Create IP2Location object.
2968 $db = new \IP2Location\Database(IP2LOCATION_DIR . $this->get_option('database'), \IP2Location\Database::FILE_IO);
2969
2970 // Get geolocation by IP address.
2971 $response = $db->lookup($ip, \IP2Location\Database::ALL);
2972
2973 if (!isset($response['countryCode'])) {
2974 return [
2975 'country_code' => '',
2976 'country_name' => '',
2977 'region_code' => '',
2978 'region_name' => '',
2979 ];
2980 }
2981
2982 // Store result into cache for later use.
2983 $caches = [
2984 'country_code' => $response['countryCode'],
2985 'country_name' => $response['countryName'],
2986 'region_code' => '',
2987 'region_name' => '',
2988 ];
2989
2990 if (!preg_match('/unavailable/', $response['regionName'])) {
2991 $caches['region_code'] = $this->get_region_code($response['countryCode'], $response['regionName']);
2992 $caches['region_name'] = $response['regionName'];
2993 }
2994
2995 $this->cache_add($ip, $caches);
2996
2997 $this->session['location'] = $caches['country_code'] . (($caches['region_code']) ? (', ' . $caches['region_code']) : '');
2998
2999 return [
3000 'country_code' => $caches['country_code'],
3001 'country_name' => $caches['country_name'],
3002 'region_code' => $caches['region_code'],
3003 'region_name' => $caches['region_name'],
3004 ];
3005 }
3006 }
3007
3008 private function get_country_name($code)
3009 {
3010 $countries = ['AF' => 'Afghanistan', 'AX' => 'Aland Islands', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AS' => 'American Samoa', 'AD' => 'Andorra', 'AO' => 'Angola', 'AI' => 'Anguilla', 'AQ' => 'Antarctica', 'AG' => 'Antigua and Barbuda', 'AR' => 'Argentina', 'AM' => 'Armenia', 'AW' => 'Aruba', 'AU' => 'Australia', 'AT' => 'Austria', 'AZ' => 'Azerbaijan', 'BS' => 'Bahamas', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BB' => 'Barbados', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BZ' => 'Belize', 'BJ' => 'Benin', 'BM' => 'Bermuda', 'BT' => 'Bhutan', 'BO' => 'Bolivia (Plurinational State of)', 'BQ' => 'Bonaire, Sint Eustatius and Saba', 'BA' => 'Bosnia and Herzegovina', 'BW' => 'Botswana', 'BV' => 'Bouvet Island', 'BR' => 'Brazil', 'IO' => 'British Indian Ocean Territory', 'BN' => 'Brunei Darussalam', 'BG' => 'Bulgaria', 'BF' => 'Burkina Faso', 'BI' => 'Burundi', 'CV' => 'Cabo Verde', 'KH' => 'Cambodia', 'CM' => 'Cameroon', 'CA' => 'Canada', 'KY' => 'Cayman Islands', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'CL' => 'Chile', 'CN' => 'China', 'CX' => 'Christmas Island', 'CC' => 'Cocos (Keeling) Islands', 'CO' => 'Colombia', 'KM' => 'Comoros', 'CG' => 'Congo', 'CD' => 'Congo (Democratic Republic of the)', 'CK' => 'Cook Islands', 'CR' => 'Costa Rica', 'CI' => 'Cote D\'ivoire', 'HR' => 'Croatia', 'CU' => 'Cuba', 'CW' => 'Curacao', 'CY' => 'Cyprus', 'CZ' => 'Czechia', 'DK' => 'Denmark', 'DJ' => 'Djibouti', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'EC' => 'Ecuador', 'EG' => 'Egypt', 'SV' => 'El Salvador', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'EE' => 'Estonia', 'ET' => 'Ethiopia', 'FK' => 'Falkland Islands (Malvinas)', 'FO' => 'Faroe Islands', 'FJ' => 'Fiji', 'FI' => 'Finland', 'FR' => 'France', 'GF' => 'French Guiana', 'PF' => 'French Polynesia', 'TF' => 'French Southern Territories', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GE' => 'Georgia', 'DE' => 'Germany', 'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GR' => 'Greece', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GU' => 'Guam', 'GT' => 'Guatemala', 'GG' => 'Guernsey', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'GY' => 'Guyana', 'HT' => 'Haiti', 'HM' => 'Heard Island and Mcdonald Islands', 'VA' => 'Holy See', 'HN' => 'Honduras', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran (Islamic Republic of)', 'IQ' => 'Iraq', 'IE' => 'Ireland', 'IM' => 'Isle of Man', 'IL' => 'Israel', 'IT' => 'Italy', 'JM' => 'Jamaica', 'JP' => 'Japan', 'JE' => 'Jersey', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KE' => 'Kenya', 'KI' => 'Kiribati', 'KP' => 'Korea (Democratic People\'s Republic of)', 'KR' => 'Korea (Republic of)', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => 'Lao People\'s Democratic Republic', 'LV' => 'Latvia', 'LB' => 'Lebanon', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libya', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MO' => 'Macao', 'MK' => 'North Macedonia', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'ML' => 'Mali', 'MT' => 'Malta', 'MH' => 'Marshall Islands', 'MQ' => 'Martinique', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte', 'MX' => 'Mexico', 'FM' => 'Micronesia (Federated States of)', 'MD' => 'Moldova (Republic of)', 'MC' => 'Monaco', 'MN' => 'Mongolia', 'ME' => 'Montenegro', 'MS' => 'Montserrat', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'MM' => 'Myanmar', 'NA' => 'Namibia', 'NR' => 'Nauru', 'NP' => 'Nepal', 'NL' => 'Netherlands', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NI' => 'Nicaragua', 'NE' => 'Niger', 'NG' => 'Nigeria', 'NU' => 'Niue', 'NF' => 'Norfolk Island', 'MP' => 'Northern Mariana Islands', 'NO' => 'Norway', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PW' => 'Palau', 'PS' => 'Palestine, State of', 'PA' => 'Panama', 'PG' => 'Papua New Guinea', 'PY' => 'Paraguay', 'PE' => 'Peru', 'PH' => 'Philippines', 'PN' => 'Pitcairn', 'PL' => 'Poland', 'PT' => 'Portugal', 'PR' => 'Puerto Rico', 'QA' => 'Qatar', 'RE' => 'Reunion', 'RO' => 'Romania', 'RU' => 'Russian Federation', 'RW' => 'Rwanda', 'BL' => 'Saint Barthelemy', 'SH' => 'Saint Helena, Ascension and Tristan da Cunha', 'KN' => 'Saint Kitts and Nevis', 'LC' => 'Saint Lucia', 'MF' => 'Saint Martin (French Part)', 'PM' => 'Saint Pierre and Miquelon', 'VC' => 'Saint Vincent and The Grenadines', 'WS' => 'Samoa', 'SM' => 'San Marino', 'ST' => 'Sao Tome and Principe', 'SA' => 'Saudi Arabia', 'SN' => 'Senegal', 'RS' => 'Serbia', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SG' => 'Singapore', 'SX' => 'Sint Maarten (Dutch Part)', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'SB' => 'Solomon Islands', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'GS' => 'South Georgia and The South Sandwich Islands', 'SS' => 'South Sudan', 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SD' => 'Sudan', 'SR' => 'Suriname', 'SJ' => 'Svalbard and Jan Mayen', 'SZ' => 'Eswatini', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'SY' => 'Syrian Arab Republic', 'TW' => 'Taiwan (Province of China)', 'TJ' => 'Tajikistan', 'TZ' => 'Tanzania, United Republic of', 'TH' => 'Thailand', 'TL' => 'Timor-Leste', 'TG' => 'Togo', 'TK' => 'Tokelau', 'TO' => 'Tonga', 'TT' => 'Trinidad and Tobago', 'TN' => 'Tunisia', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'TC' => 'Turks and Caicos Islands', 'TV' => 'Tuvalu', 'UG' => 'Uganda', 'UA' => 'Ukraine', 'AE' => 'United Arab Emirates', 'GB' => 'United Kingdom of Great Britain and Northern Ireland', 'US' => 'United States', 'UM' => 'United States Minor Outlying Islands', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan', 'VU' => 'Vanuatu', 'VE' => 'Venezuela (Bolivarian Republic of)', 'VN' => 'Viet Nam', 'VG' => 'Virgin Islands (British)', 'VI' => 'Virgin Islands (U.S.)', 'WF' => 'Wallis and Futuna', 'EH' => 'Western Sahara', 'YE' => 'Yemen', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe'];
3011
3012 return (isset($countries[$code])) ? $countries[$code] : '';
3013 }
3014
3015 private function get_region_code($country_code, $region_name)
3016 {
3017 $regions = [
3018 'AD' => ['AD.07' => 'Andorra la Vella', 'AD.02' => 'Canillo', 'AD.03' => 'Encamp', 'AD.08' => 'Escaldes-Engordany', 'AD.04' => 'La Massana', 'AD.05' => 'Ordino', 'AD.06' => 'Sant Julia de Loria'],
3019 'AE' => ['AE.AJ' => '\'Ajman', 'AE.AZ' => 'Abu Zaby', 'AE.FU' => 'Al Fujayrah', 'AE.SH' => 'Ash Shariqah', 'AE.DU' => 'Dubayy', 'AE.RK' => 'Ra\'s al Khaymah', 'AE.UQ' => 'Umm al Qaywayn'],
3020 'AF' => ['AF.BDS' => 'Badakhshan', 'AF.BDG' => 'Badghis', 'AF.BGL' => 'Baghlan', 'AF.BAL' => 'Balkh', 'AF.BAM' => 'Bamyan', 'AF.DAY' => 'Daykundi', 'AF.FRA' => 'Farah', 'AF.FYB' => 'Faryab', 'AF.GHA' => 'Ghazni', 'AF.GHO' => 'Ghor', 'AF.HEL' => 'Helmand', 'AF.HER' => 'Herat', 'AF.JOW' => 'Jowzjan', 'AF.KAB' => 'Kabul', 'AF.KAN' => 'Kandahar', 'AF.KAP' => 'Kapisa', 'AF.KHO' => 'Khost', 'AF.KNR' => 'Kunar', 'AF.KDZ' => 'Kunduz', 'AF.LAG' => 'Laghman', 'AF.LOG' => 'Logar', 'AF.NAN' => 'Nangarhar', 'AF.NIM' => 'Nimroz', 'AF.NUR' => 'Nuristan', 'AF.PKA' => 'Paktika', 'AF.PIA' => 'Paktiya', 'AF.PAN' => 'Panjshayr', 'AF.PAR' => 'Parwan', 'AF.SAM' => 'Samangan', 'AF.SAR' => 'Sar-e Pul', 'AF.TAK' => 'Takhar', 'AF.URU' => 'Uruzgan', 'AF.WAR' => 'Wardak', 'AF.ZAB' => 'Zabul'],
3021 'AG' => ['AG.10' => 'Barbuda', 'AG.11' => 'Redonda', 'AG.03' => 'Saint George', 'AG.04' => 'Saint John', 'AG.05' => 'Saint Mary', 'AG.06' => 'Saint Paul', 'AG.07' => 'Saint Peter', 'AG.08' => 'Saint Philip'],
3022 'AL' => ['AL.01' => 'Berat', 'AL.09' => 'Diber', 'AL.02' => 'Durres', 'AL.03' => 'Elbasan', 'AL.04' => 'Fier', 'AL.05' => 'Gjirokaster', 'AL.06' => 'Korce', 'AL.07' => 'Kukes', 'AL.08' => 'Lezhe', 'AL.10' => 'Shkoder', 'AL.11' => 'Tirane', 'AL.12' => 'Vlore'],
3023 'AM' => ['AM.AG' => 'Aragacotn', 'AM.AR' => 'Ararat', 'AM.AV' => 'Armavir', 'AM.ER' => 'Erevan', 'AM.GR' => 'Gegark\'unik\'', 'AM.KT' => 'Kotayk\'', 'AM.LO' => 'Lori', 'AM.SH' => 'Sirak', 'AM.SU' => 'Syunik\'', 'AM.TV' => 'Tavus', 'AM.VD' => 'Vayoc Jor'],
3024 'AO' => ['AO.BGO' => 'Bengo', 'AO.BGU' => 'Benguela', 'AO.BIE' => 'Bie', 'AO.CAB' => 'Cabinda', 'AO.CCU' => 'Cuando Cubango', 'AO.CNO' => 'Cuanza-Norte', 'AO.CUS' => 'Cuanza-Sul', 'AO.CNN' => 'Cunene', 'AO.HUA' => 'Huambo', 'AO.HUI' => 'Huila', 'AO.LUA' => 'Luanda', 'AO.LNO' => 'Lunda-Norte', 'AO.LSU' => 'Lunda-Sul', 'AO.MAL' => 'Malange', 'AO.MOX' => 'Moxico', 'AO.NAM' => 'Namibe', 'AO.UIG' => 'Uige', 'AO.ZAI' => 'Zaire'],
3025 'AR' => ['AR.B' => 'Buenos Aires', 'AR.K' => 'Catamarca', 'AR.H' => 'Chaco', 'AR.U' => 'Chubut', 'AR.C' => 'Ciudad Autonoma de Buenos Aires', 'AR.X' => 'Cordoba', 'AR.W' => 'Corrientes', 'AR.E' => 'Entre Rios', 'AR.P' => 'Formosa', 'AR.Y' => 'Jujuy', 'AR.L' => 'La Pampa', 'AR.F' => 'La Rioja', 'AR.M' => 'Mendoza', 'AR.N' => 'Misiones', 'AR.Q' => 'Neuquen', 'AR.R' => 'Rio Negro', 'AR.A' => 'Salta', 'AR.J' => 'San Juan', 'AR.D' => 'San Luis', 'AR.Z' => 'Santa Cruz', 'AR.S' => 'Santa Fe', 'AR.G' => 'Santiago del Estero', 'AR.V' => 'Tierra del Fuego', 'AR.T' => 'Tucuman'],
3026 'AT' => ['AT.1' => 'Burgenland', 'AT.2' => 'Karnten', 'AT.3' => 'Niederosterreich', 'AT.4' => 'Oberosterreich', 'AT.5' => 'Salzburg', 'AT.6' => 'Steiermark', 'AT.7' => 'Tirol', 'AT.8' => 'Vorarlberg', 'AT.9' => 'Wien'],
3027 'AU' => ['AU.ACT' => 'Australian Capital Territory', 'AU.NSW' => 'New South Wales', 'AU.NT' => 'Northern Territory', 'AU.QLD' => 'Queensland', 'AU.SA' => 'South Australia', 'AU.TAS' => 'Tasmania', 'AU.VIC' => 'Victoria', 'AU.WA' => 'Western Australia'],
3028 'AZ' => ['AZ.ABS' => 'Abseron', 'AZ.AGC' => 'Agcabadi', 'AZ.AGM' => 'Agdam', 'AZ.AGS' => 'Agdas', 'AZ.AGA' => 'Agstafa', 'AZ.AGU' => 'Agsu', 'AZ.AST' => 'Astara', 'AZ.BA' => 'Baki', 'AZ.BAL' => 'Balakan', 'AZ.BAR' => 'Barda', 'AZ.BEY' => 'Beylaqan', 'AZ.BIL' => 'Bilasuvar', 'AZ.CAB' => 'Cabrayil', 'AZ.CAL' => 'Calilabad', 'AZ.CUL' => 'Culfa', 'AZ.DAS' => 'Daskasan', 'AZ.FUZ' => 'Fuzuli', 'AZ.GAD' => 'Gadabay', 'AZ.GA' => 'Ganca', 'AZ.GOR' => 'Goranboy', 'AZ.GOY' => 'Goycay', 'AZ.GYG' => 'Goygol', 'AZ.HAC' => 'Haciqabul', 'AZ.IMI' => 'Imisli', 'AZ.ISM' => 'Ismayilli', 'AZ.KAL' => 'Kalbacar', 'AZ.KAN' => 'Kangarli', 'AZ.KUR' => 'Kurdamir', 'AZ.LAC' => 'Lacin', 'AZ.LA' => 'Lankaran', 'AZ.LER' => 'Lerik', 'AZ.MAS' => 'Masalli', 'AZ.MI' => 'Mingacevir', 'AZ.NA' => 'Naftalan', 'AZ.NX' => 'Naxcivan', 'AZ.NEF' => 'Neftcala', 'AZ.OGU' => 'Oguz', 'AZ.ORD' => 'Ordubad', 'AZ.QAB' => 'Qabala', 'AZ.QAX' => 'Qax', 'AZ.QAZ' => 'Qazax', 'AZ.QOB' => 'Qobustan', 'AZ.QBA' => 'Quba', 'AZ.QBI' => 'Qubadli', 'AZ.QUS' => 'Qusar', 'AZ.SAT' => 'Saatli', 'AZ.SAB' => 'Sabirabad', 'AZ.SBN' => 'Sabran', 'AZ.SAD' => 'Sadarak', 'AZ.SAH' => 'Sahbuz', 'AZ.SAK' => 'Saki', 'AZ.SAL' => 'Salyan', 'AZ.SMI' => 'Samaxi', 'AZ.SKR' => 'Samkir', 'AZ.SMX' => 'Samux', 'AZ.SAR' => 'Sharur', 'AZ.SR' => 'Sirvan', 'AZ.SIY' => 'Siyazan', 'AZ.SM' => 'Sumqayit', 'AZ.SUS' => 'Susa', 'AZ.TAR' => 'Tartar', 'AZ.TOV' => 'Tovuz', 'AZ.UCA' => 'Ucar', 'AZ.XAC' => 'Xacmaz', 'AZ.XA' => 'Xankandi', 'AZ.XIZ' => 'Xizi', 'AZ.XCI' => 'Xocali', 'AZ.XVD' => 'Xocavand', 'AZ.YAR' => 'Yardimli', 'AZ.YEV' => 'Yevlax', 'AZ.ZAN' => 'Zangilan', 'AZ.ZAQ' => 'Zaqatala', 'AZ.ZAR' => 'Zardab'],
3029 'BA' => ['BA.BRC' => 'Brcko distrikt', 'BA.BIH' => 'Federacija Bosne i Hercegovine', 'BA.SRP' => 'Republika Srpska'],
3030 'BB' => ['BB.01' => 'Christ Church', 'BB.02' => 'Saint Andrew', 'BB.03' => 'Saint George', 'BB.04' => 'Saint James', 'BB.05' => 'Saint John', 'BB.06' => 'Saint Joseph', 'BB.07' => 'Saint Lucy', 'BB.08' => 'Saint Michael', 'BB.09' => 'Saint Peter', 'BB.10' => 'Saint Philip', 'BB.11' => 'Saint Thomas'],
3031 'BD' => ['BD.A' => 'Barisal', 'BD.B' => 'Chittagong', 'BD.C' => 'Dhaka', 'BD.D' => 'Khulna', 'BD.E' => 'Rajshahi', 'BD.F' => 'Rangpur', 'BD.G' => 'Sylhet'],
3032 'BE' => ['BE.VAN' => 'Antwerpen', 'BE.WBR' => 'Brabant wallon', 'BE.BRU' => 'Brussels Hoofdstedelijk Gewest', 'BE.WHT' => 'Hainaut', 'BE.WLG' => 'Liege', 'BE.VLI' => 'Limburg', 'BE.WLX' => 'Luxembourg', 'BE.WNA' => 'Namur', 'BE.VOV' => 'Oost-Vlaanderen', 'BE.VLG' => 'Vlaams Gewest', 'BE.VBR' => 'Vlaams-Brabant', 'BE.VWV' => 'West-Vlaanderen', 'BE.WAL' => 'wallonne, Region'],
3033 'BF' => ['BF.BAL' => 'Bale', 'BF.BAM' => 'Bam', 'BF.BAN' => 'Banwa', 'BF.BAZ' => 'Bazega', 'BF.BGR' => 'Bougouriba', 'BF.BLG' => 'Boulgou', 'BF.BLK' => 'Boulkiemde', 'BF.COM' => 'Comoe', 'BF.GAN' => 'Ganzourgou', 'BF.GNA' => 'Gnagna', 'BF.GOU' => 'Gourma', 'BF.HOU' => 'Houet', 'BF.IOB' => 'Ioba', 'BF.KAD' => 'Kadiogo', 'BF.KEN' => 'Kenedougou', 'BF.KMD' => 'Komondjari', 'BF.KMP' => 'Kompienga', 'BF.KOS' => 'Kossi', 'BF.KOP' => 'Koulpelogo', 'BF.KOT' => 'Kouritenga', 'BF.KOW' => 'Kourweogo', 'BF.LER' => 'Leraba', 'BF.LOR' => 'Loroum', 'BF.MOU' => 'Mouhoun', 'BF.NAO' => 'Nahouri', 'BF.NAM' => 'Namentenga', 'BF.NAY' => 'Nayala', 'BF.NOU' => 'Noumbiel', 'BF.OUB' => 'Oubritenga', 'BF.OUD' => 'Oudalan', 'BF.PAS' => 'Passore', 'BF.PON' => 'Poni', 'BF.SNG' => 'Sanguie', 'BF.SMT' => 'Sanmatenga', 'BF.SEN' => 'Seno', 'BF.SIS' => 'Sissili', 'BF.SOM' => 'Soum', 'BF.SOR' => 'Sourou', 'BF.TAP' => 'Tapoa', 'BF.TUI' => 'Tuy', 'BF.YAG' => 'Yagha', 'BF.YAT' => 'Yatenga', 'BF.ZIR' => 'Ziro', 'BF.ZON' => 'Zondoma', 'BF.ZOU' => 'Zoundweogo'],
3034 'BG' => ['BG.01' => 'Blagoevgrad', 'BG.02' => 'Burgas', 'BG.08' => 'Dobrich', 'BG.07' => 'Gabrovo', 'BG.26' => 'Haskovo', 'BG.09' => 'Kardzhali', 'BG.10' => 'Kyustendil', 'BG.11' => 'Lovech', 'BG.12' => 'Montana', 'BG.13' => 'Pazardzhik', 'BG.14' => 'Pernik', 'BG.15' => 'Pleven', 'BG.16' => 'Plovdiv', 'BG.17' => 'Razgrad', 'BG.18' => 'Ruse', 'BG.27' => 'Shumen', 'BG.19' => 'Silistra', 'BG.20' => 'Sliven', 'BG.21' => 'Smolyan', 'BG.23' => 'Sofia', 'BG.22' => 'Sofia (stolitsa)', 'BG.24' => 'Stara Zagora', 'BG.25' => 'Targovishte', 'BG.03' => 'Varna', 'BG.04' => 'Veliko Tarnovo', 'BG.05' => 'Vidin', 'BG.06' => 'Vratsa', 'BG.28' => 'Yambol'],
3035 'BH' => ['BH.13' => 'Al \'Asimah', 'BH.14' => 'Al Janubiyah', 'BH.15' => 'Al Muharraq', 'BH.17' => 'Ash Shamaliyah'],
3036 'BI' => ['BI.BB' => 'Bubanza', 'BI.BM' => 'Bujumbura Mairie', 'BI.BL' => 'Bujumbura Rural', 'BI.BR' => 'Bururi', 'BI.CA' => 'Cankuzo', 'BI.CI' => 'Cibitoke', 'BI.GI' => 'Gitega', 'BI.KR' => 'Karuzi', 'BI.KY' => 'Kayanza', 'BI.KI' => 'Kirundo', 'BI.MA' => 'Makamba', 'BI.MU' => 'Muramvya', 'BI.MY' => 'Muyinga', 'BI.MW' => 'Mwaro', 'BI.NG' => 'Ngozi', 'BI.RM' => 'Rumonge', 'BI.RT' => 'Rutana', 'BI.RY' => 'Ruyigi'],
3037 'BJ' => ['BJ.AL' => 'Alibori', 'BJ.AK' => 'Atacora', 'BJ.AQ' => 'Atlantique', 'BJ.BO' => 'Borgou', 'BJ.CO' => 'Collines', 'BJ.KO' => 'Couffo', 'BJ.DO' => 'Donga', 'BJ.LI' => 'Littoral', 'BJ.MO' => 'Mono', 'BJ.OU' => 'Oueme', 'BJ.PL' => 'Plateau', 'BJ.ZO' => 'Zou'],
3038 'BN' => ['BN.BE' => 'Belait', 'BN.BM' => 'Brunei-Muara', 'BN.TE' => 'Temburong', 'BN.TU' => 'Tutong'],
3039 'BO' => ['BO.H' => 'Chuquisaca', 'BO.C' => 'Cochabamba', 'BO.B' => 'El Beni', 'BO.L' => 'La Paz', 'BO.O' => 'Oruro', 'BO.N' => 'Pando', 'BO.P' => 'Potosi', 'BO.S' => 'Santa Cruz', 'BO.T' => 'Tarija'],
3040 'BQ' => ['BQ.BO' => 'Bonaire', 'BQ.SA' => 'Saba', 'BQ.SE' => 'Sint Eustatius'],
3041 'BR' => ['BR.AC' => 'Acre', 'BR.AL' => 'Alagoas', 'BR.AP' => 'Amapa', 'BR.AM' => 'Amazonas', 'BR.BA' => 'Bahia', 'BR.CE' => 'Ceara', 'BR.DF' => 'Distrito Federal', 'BR.ES' => 'Espirito Santo', 'BR.GO' => 'Goias', 'BR.MA' => 'Maranhao', 'BR.MT' => 'Mato Grosso', 'BR.MS' => 'Mato Grosso do Sul', 'BR.MG' => 'Minas Gerais', 'BR.PA' => 'Para', 'BR.PB' => 'Paraiba', 'BR.PR' => 'Parana', 'BR.PE' => 'Pernambuco', 'BR.PI' => 'Piaui', 'BR.RN' => 'Rio Grande do Norte', 'BR.RS' => 'Rio Grande do Sul', 'BR.RJ' => 'Rio de Janeiro', 'BR.RO' => 'Rondonia', 'BR.RR' => 'Roraima', 'BR.SC' => 'Santa Catarina', 'BR.SP' => 'Sao Paulo', 'BR.SE' => 'Sergipe', 'BR.TO' => 'Tocantins'],
3042 'BS' => ['BS.AK' => 'Acklins', 'BS.BY' => 'Berry Islands', 'BS.BI' => 'Bimini', 'BS.BP' => 'Black Point', 'BS.CI' => 'Cat Island', 'BS.CO' => 'Central Abaco', 'BS.CS' => 'Central Andros', 'BS.CE' => 'Central Eleuthera', 'BS.FP' => 'City of Freeport', 'BS.CK' => 'Crooked Island and Long Cay', 'BS.EG' => 'East Grand Bahama', 'BS.EX' => 'Exuma', 'BS.GC' => 'Grand Cay', 'BS.HI' => 'Harbour Island', 'BS.HT' => 'Hope Town', 'BS.IN' => 'Inagua', 'BS.LI' => 'Long Island', 'BS.MC' => 'Mangrove Cay', 'BS.MG' => 'Mayaguana', 'BS.MI' => 'Moore\'s Island', 'BS.NP' => 'New Providence', 'BS.NO' => 'North Abaco', 'BS.NS' => 'North Andros', 'BS.NE' => 'North Eleuthera', 'BS.RI' => 'Ragged Island', 'BS.RC' => 'Rum Cay', 'BS.SS' => 'San Salvador', 'BS.SO' => 'South Abaco', 'BS.SA' => 'South Andros', 'BS.SE' => 'South Eleuthera', 'BS.SW' => 'Spanish Wells', 'BS.WG' => 'West Grand Bahama'],
3043 'BT' => ['BT.33' => 'Bumthang', 'BT.12' => 'Chhukha', 'BT.22' => 'Dagana', 'BT.GA' => 'Gasa', 'BT.13' => 'Haa', 'BT.44' => 'Lhuentse', 'BT.42' => 'Monggar', 'BT.11' => 'Paro', 'BT.43' => 'Pema Gatshel', 'BT.23' => 'Punakha', 'BT.45' => 'Samdrup Jongkhar', 'BT.14' => 'Samtse', 'BT.31' => 'Sarpang', 'BT.15' => 'Thimphu', 'BT.TY' => 'Trashi Yangtse', 'BT.41' => 'Trashigang', 'BT.32' => 'Trongsa', 'BT.21' => 'Tsirang', 'BT.24' => 'Wangdue Phodrang', 'BT.34' => 'Zhemgang'],
3044 'BW' => ['BW.CE' => 'Central', 'BW.CH' => 'Chobe', 'BW.GH' => 'Ghanzi', 'BW.KG' => 'Kgalagadi', 'BW.KL' => 'Kgatleng', 'BW.KW' => 'Kweneng', 'BW.NE' => 'North East', 'BW.NW' => 'North West', 'BW.SE' => 'South East', 'BW.SO' => 'Southern'],
3045 'BY' => ['BY.BR' => 'Brestskaya voblasts\'', 'BY.HO' => 'Homyel\'skaya voblasts\'', 'BY.HM' => 'Horad Minsk', 'BY.HR' => 'Hrodzenskaya voblasts\'', 'BY.MA' => 'Mahilyowskaya voblasts\'', 'BY.MI' => 'Minskaya voblasts\'', 'BY.VI' => 'Vitsyebskaya voblasts\''],
3046 'BZ' => ['BZ.BZ' => 'Belize', 'BZ.CY' => 'Cayo', 'BZ.CZL' => 'Corozal', 'BZ.OW' => 'Orange Walk', 'BZ.SC' => 'Stann Creek', 'BZ.TOL' => 'Toledo'],
3047 'CA' => ['CA.AB' => 'Alberta', 'CA.BC' => 'British Columbia', 'CA.MB' => 'Manitoba', 'CA.NB' => 'New Brunswick', 'CA.NL' => 'Newfoundland and Labrador', 'CA.NT' => 'Northwest Territories', 'CA.NS' => 'Nova Scotia', 'CA.NU' => 'Nunavut', 'CA.ON' => 'Ontario', 'CA.PE' => 'Prince Edward Island', 'CA.QC' => 'Quebec', 'CA.SK' => 'Saskatchewan', 'CA.YT' => 'Yukon'],
3048 'CD' => ['CD.BU' => 'Bas-Uele', 'CD.EQ' => 'Equateur', 'CD.HK' => 'Haut-Katanga', 'CD.HL' => 'Haut-Lomami', 'CD.HU' => 'Haut-Uele', 'CD.IT' => 'Ituri', 'CD.KS' => 'Kasai', 'CD.KC' => 'Kasai Central', 'CD.KE' => 'Kasai Oriental', 'CD.KN' => 'Kinshasa', 'CD.BC' => 'Kongo Central', 'CD.KG' => 'Kwango', 'CD.KL' => 'Kwilu', 'CD.LO' => 'Lomami', 'CD.LU' => 'Lualaba', 'CD.MN' => 'Mai-Ndombe', 'CD.MA' => 'Maniema', 'CD.MO' => 'Mongala', 'CD.NK' => 'NorD.Kivu', 'CD.NU' => 'NorD.Ubangi', 'CD.SA' => 'Sankuru', 'CD.SK' => 'SuD.Kivu', 'CD.SU' => 'SuD.Ubangi', 'CD.TA' => 'Tanganyika', 'CD.TO' => 'Tshopo', 'CD.TU' => 'Tshuapa'],
3049 'CF' => ['CF.BB' => 'Bamingui-Bangoran', 'CF.BGF' => 'Bangui', 'CF.BK' => 'Basse-Kotto', 'CF.KB' => 'Gribingui', 'CF.HM' => 'Haut-Mbomou', 'CF.HK' => 'Haute-Kotto', 'CF.KG' => 'Kemo-Gribingui', 'CF.LB' => 'Lobaye', 'CF.HS' => 'Mambere-Kadei', 'CF.MB' => 'Mbomou', 'CF.NM' => 'Nana-Mambere', 'CF.MP' => 'Ombella-Mpoko', 'CF.UK' => 'Ouaka', 'CF.AC' => 'Ouham', 'CF.OP' => 'Ouham-Pende', 'CF.SE' => 'Sangha', 'CF.VK' => 'Vakaga'],
3050 'CG' => ['CG.11' => 'Bouenza', 'CG.BZV' => 'Brazzaville', 'CG.8' => 'Cuvette', 'CG.15' => 'Cuvette-Ouest', 'CG.5' => 'Kouilou', 'CG.2' => 'Lekoumou', 'CG.7' => 'Likouala', 'CG.9' => 'Niari', 'CG.14' => 'Plateaux', 'CG.16' => 'Pointe-Noire', 'CG.12' => 'Pool', 'CG.13' => 'Sangha'],
3051 'CH' => ['CH.AG' => 'Aargau', 'CH.AR' => 'Appenzell Ausserrhoden', 'CH.AI' => 'Appenzell Innerrhoden', 'CH.BL' => 'Basel-Landschaft', 'CH.BS' => 'Basel-Stadt', 'CH.BE' => 'Bern', 'CH.FR' => 'Fribourg', 'CH.GE' => 'Geneve', 'CH.GL' => 'Glarus', 'CH.GR' => 'Graubunden', 'CH.JU' => 'Jura', 'CH.LU' => 'Luzern', 'CH.NE' => 'Neuchatel', 'CH.NW' => 'Nidwalden', 'CH.OW' => 'Obwalden', 'CH.SG' => 'Sankt Gallen', 'CH.SH' => 'Schaffhausen', 'CH.SZ' => 'Schwyz', 'CH.SO' => 'Solothurn', 'CH.TG' => 'Thurgau', 'CH.TI' => 'Ticino', 'CH.UR' => 'Uri', 'CH.VS' => 'Valais', 'CH.VD' => 'Vaud', 'CH.ZG' => 'Zug', 'CH.ZH' => 'Zurich'],
3052 'CI' => ['CI.AB' => 'Abidjan', 'CI.BS' => 'Bas-Sassandra', 'CI.CM' => 'Comoe', 'CI.DN' => 'Denguele', 'CI.GD' => 'Goh-Djiboua', 'CI.LC' => 'Lacs', 'CI.LG' => 'Lagunes', 'CI.MG' => 'Montagnes', 'CI.SM' => 'Sassandra-Marahoue', 'CI.SV' => 'Savanes', 'CI.VB' => 'Vallee du Bandama', 'CI.WR' => 'Woroba', 'CI.YM' => 'Yamoussoukro', 'CI.ZZ' => 'Zanzan'],
3053 'CL' => ['CL.AI' => 'Aisen del General Carlos Ibanez del Campo', 'CL.AN' => 'Antofagasta', 'CL.AP' => 'Arica y Parinacota', 'CL.AT' => 'Atacama', 'CL.BI' => 'Biobio', 'CL.CO' => 'Coquimbo', 'CL.AR' => 'La Araucania', 'CL.LI' => 'Libertador General Bernardo O\'Higgins', 'CL.LL' => 'Los Lagos', 'CL.LR' => 'Los Rios', 'CL.MA' => 'Magallanes', 'CL.ML' => 'Maule', 'CL.NB' => 'Nuble', 'CL.RM' => 'Region Metropolitana de Santiago', 'CL.TA' => 'Tarapaca', 'CL.VS' => 'Valparaiso'],
3054 'CM' => ['CM.AD' => 'Adamaoua', 'CM.CE' => 'Centre', 'CM.ES' => 'Est', 'CM.EN' => 'Extreme-Nord', 'CM.LT' => 'Littoral', 'CM.NO' => 'Nord', 'CM.NW' => 'Nord-Ouest', 'CM.OU' => 'Ouest', 'CM.SU' => 'Sud', 'CM.SW' => 'Sud-Ouest'],
3055 'CN' => ['CN.AH' => 'Anhui', 'CN.BJ' => 'Beijing', 'CN.CQ' => 'Chongqing', 'CN.FJ' => 'Fujian', 'CN.GS' => 'Gansu', 'CN.GD' => 'Guangdong', 'CN.GX' => 'Guangxi', 'CN.GZ' => 'Guizhou', 'CN.HI' => 'Hainan', 'CN.HE' => 'Hebei', 'CN.HL' => 'Heilongjiang', 'CN.HA' => 'Henan', 'CN.HB' => 'Hubei', 'CN.HN' => 'Hunan', 'CN.JS' => 'Jiangsu', 'CN.JX' => 'Jiangxi', 'CN.JL' => 'Jilin', 'CN.LN' => 'Liaoning', 'CN.NM' => 'Nei Mongol', 'CN.NX' => 'Ningxia', 'CN.QH' => 'Qinghai', 'CN.SN' => 'Shaanxi', 'CN.SD' => 'Shandong', 'CN.SH' => 'Shanghai', 'CN.SX' => 'Shanxi', 'CN.SC' => 'Sichuan', 'CN.TJ' => 'Tianjin', 'CN.XJ' => 'Xinjiang', 'CN.XZ' => 'Xizang', 'CN.YN' => 'Yunnan', 'CN.ZJ' => 'Zhejiang'],
3056 'CO' => ['CO.AMA' => 'Amazonas', 'CO.ANT' => 'Antioquia', 'CO.ARA' => 'Arauca', 'CO.ATL' => 'Atlantico', 'CO.BOL' => 'Bolivar', 'CO.BOY' => 'Boyaca', 'CO.CAL' => 'Caldas', 'CO.CAQ' => 'Caqueta', 'CO.CAS' => 'Casanare', 'CO.CAU' => 'Cauca', 'CO.CES' => 'Cesar', 'CO.CHO' => 'Choco', 'CO.COR' => 'Cordoba', 'CO.CUN' => 'Cundinamarca', 'CO.DC' => 'Distrito Capital de Bogota', 'CO.GUA' => 'Guainia', 'CO.GUV' => 'Guaviare', 'CO.HUI' => 'Huila', 'CO.LAG' => 'La Guajira', 'CO.MAG' => 'Magdalena', 'CO.MET' => 'Meta', 'CO.NAR' => 'Narino', 'CO.NSA' => 'Norte de Santander', 'CO.PUT' => 'Putumayo', 'CO.QUI' => 'Quindio', 'CO.RIS' => 'Risaralda', 'CO.SAP' => 'San Andres, Providencia y Santa Catalina', 'CO.SAN' => 'Santander', 'CO.SUC' => 'Sucre', 'CO.TOL' => 'Tolima', 'CO.VAC' => 'Valle del Cauca', 'CO.VAU' => 'Vaupes', 'CO.VID' => 'Vichada'],
3057 'CR' => ['CR.A' => 'Alajuela', 'CR.C' => 'Cartago', 'CR.G' => 'Guanacaste', 'CR.H' => 'Heredia', 'CR.L' => 'Limon', 'CR.P' => 'Puntarenas', 'CR.SJ' => 'San Jose'],
3058 'CU' => ['CU.15' => 'Artemisa', 'CU.09' => 'Camaguey', 'CU.08' => 'Ciego de Avila', 'CU.06' => 'Cienfuegos', 'CU.12' => 'Granma', 'CU.14' => 'Guantanamo', 'CU.11' => 'Holguin', 'CU.99' => 'Isla de la Juventud', 'CU.03' => 'La Habana', 'CU.10' => 'Las Tunas', 'CU.04' => 'Matanzas', 'CU.16' => 'Mayabeque', 'CU.01' => 'Pinar del Rio', 'CU.07' => 'Sancti Spiritus', 'CU.13' => 'Santiago de Cuba', 'CU.05' => 'Villa Clara'],
3059 'CV' => ['CV.BV' => 'Boa Vista', 'CV.BR' => 'Brava', 'CV.MA' => 'Maio', 'CV.MO' => 'Mosteiros', 'CV.PA' => 'Paul', 'CV.PN' => 'Porto Novo', 'CV.PR' => 'Praia', 'CV.RB' => 'Ribeira Brava', 'CV.RG' => 'Ribeira Grande', 'CV.RS' => 'Ribeira Grande de Santiago', 'CV.SL' => 'Sal', 'CV.CA' => 'Santa Catarina', 'CV.CF' => 'Santa Catarina do Fogo', 'CV.CR' => 'Santa Cruz', 'CV.SD' => 'Sao Domingos', 'CV.SF' => 'Sao Filipe', 'CV.SO' => 'Sao Lourenco dos Orgaos', 'CV.SM' => 'Sao Miguel', 'CV.SS' => 'Sao Salvador do Mundo', 'CV.SV' => 'Sao Vicente', 'CV.TA' => 'Tarrafal', 'CV.TS' => 'Tarrafal de Sao Nicolau'],
3060 'CY' => ['CY.04' => 'Ammochostos', 'CY.06' => 'Keryneia', 'CY.03' => 'Larnaka', 'CY.01' => 'Lefkosia', 'CY.02' => 'Lemesos', 'CY.05' => 'Pafos'],
3061 'CZ' => ['CZ.31' => 'Jihocesky kraj', 'CZ.64' => 'Jihomoravsky kraj', 'CZ.41' => 'Karlovarsky kraj', 'CZ.63' => 'Kraj Vysocina', 'CZ.52' => 'Kralovehradecky kraj', 'CZ.51' => 'Liberecky kraj', 'CZ.80' => 'Moravskoslezsky kraj', 'CZ.71' => 'Olomoucky kraj', 'CZ.53' => 'Pardubicky kraj', 'CZ.32' => 'Plzensky kraj', 'CZ.10' => 'Praha, Hlavni mesto', 'CZ.20' => 'Stredocesky kraj', 'CZ.42' => 'Ustecky kraj', 'CZ.72' => 'Zlinsky kraj'],
3062 'DE' => ['DE.BW' => 'Baden-Wurttemberg', 'DE.BY' => 'Bayern', 'DE.BE' => 'Berlin', 'DE.BB' => 'Brandenburg', 'DE.HB' => 'Bremen', 'DE.HH' => 'Hamburg', 'DE.HE' => 'Hessen', 'DE.MV' => 'Mecklenburg-Vorpommern', 'DE.NI' => 'Niedersachsen', 'DE.NW' => 'Nordrhein-Westfalen', 'DE.RP' => 'Rheinland-Pfalz', 'DE.SL' => 'Saarland', 'DE.SN' => 'Sachsen', 'DE.ST' => 'Sachsen-Anhalt', 'DE.SH' => 'Schleswig-Holstein', 'DE.TH' => 'Thuringen'],
3063 'DJ' => ['DJ.AS' => 'Ali Sabieh', 'DJ.AR' => 'Arta', 'DJ.DI' => 'Dikhil', 'DJ.DJ' => 'Djibouti', 'DJ.OB' => 'Obock', 'DJ.TA' => 'Tadjourah'],
3064 'DK' => ['DK.84' => 'Hovedstaden', 'DK.82' => 'Midtjylland', 'DK.81' => 'Nordjylland', 'DK.85' => 'Sjaelland', 'DK.83' => 'Syddanmark'],
3065 'DM' => ['DM.02' => 'Saint Andrew', 'DM.03' => 'Saint David', 'DM.04' => 'Saint George', 'DM.05' => 'Saint John', 'DM.06' => 'Saint Joseph', 'DM.07' => 'Saint Luke', 'DM.08' => 'Saint Mark', 'DM.09' => 'Saint Patrick', 'DM.10' => 'Saint Paul', 'DM.11' => 'Saint Peter'],
3066 'DO' => ['DO.02' => 'Azua', 'DO.03' => 'Baoruco', 'DO.04' => 'Barahona', 'DO.05' => 'Dajabon', 'DO.01' => 'Distrito Nacional (Santo Domingo)', 'DO.06' => 'Duarte', 'DO.08' => 'El Seibo', 'DO.07' => 'Elias Pina', 'DO.09' => 'Espaillat', 'DO.30' => 'Hato Mayor', 'DO.19' => 'Hermanas Mirabal', 'DO.10' => 'Independencia', 'DO.11' => 'La Altagracia', 'DO.12' => 'La Romana', 'DO.13' => 'La Vega', 'DO.14' => 'Maria Trinidad Sanchez', 'DO.28' => 'Monsenor Nouel', 'DO.15' => 'Monte Cristi', 'DO.29' => 'Monte Plata', 'DO.16' => 'Pedernales', 'DO.17' => 'Peravia', 'DO.18' => 'Puerto Plata', 'DO.20' => 'Samana', 'DO.21' => 'San Cristobal', 'DO.31' => 'San Jose de Ocoa', 'DO.22' => 'San Juan', 'DO.23' => 'San Pedro de Macoris', 'DO.24' => 'Sanchez Ramirez', 'DO.25' => 'Santiago', 'DO.26' => 'Santiago Rodriguez', 'DO.32' => 'Santo Domingo', 'DO.27' => 'Valverde'],
3067 'DZ' => ['DZ.01' => 'Adrar', 'DZ.44' => 'Ain Defla', 'DZ.46' => 'Ain Temouchent', 'DZ.16' => 'Alger', 'DZ.23' => 'Annaba', 'DZ.05' => 'Batna', 'DZ.08' => 'Bechar', 'DZ.06' => 'Bejaia', 'DZ.52' => 'Beni Abbes', 'DZ.07' => 'Biskra', 'DZ.09' => 'Blida', 'DZ.50' => 'Bordj Badji Mokhtar', 'DZ.34' => 'Bordj Bou Arreridj', 'DZ.10' => 'Bouira', 'DZ.35' => 'Boumerdes', 'DZ.02' => 'Chlef', 'DZ.25' => 'Constantine', 'DZ.56' => 'Djanet', 'DZ.17' => 'Djelfa', 'DZ.32' => 'El Bayadh', 'DZ.57' => 'El Meghaier', 'DZ.58' => 'El Meniaa', 'DZ.39' => 'El Oued', 'DZ.36' => 'El Tarf', 'DZ.47' => 'Ghardaia', 'DZ.24' => 'Guelma', 'DZ.33' => 'Illizi', 'DZ.54' => 'In Guezzam', 'DZ.53' => 'In Salah', 'DZ.18' => 'Jijel', 'DZ.40' => 'Khenchela', 'DZ.03' => 'Laghouat', 'DZ.28' => 'M\'sila', 'DZ.29' => 'Mascara', 'DZ.26' => 'Medea', 'DZ.43' => 'Mila', 'DZ.27' => 'Mostaganem', 'DZ.45' => 'Naama', 'DZ.31' => 'Oran', 'DZ.30' => 'Ouargla', 'DZ.51' => 'Ouled Djellal', 'DZ.04' => 'Oum el Bouaghi', 'DZ.48' => 'Relizane', 'DZ.20' => 'Saida', 'DZ.19' => 'Setif', 'DZ.22' => 'Sidi Bel Abbes', 'DZ.21' => 'Skikda', 'DZ.41' => 'Souk Ahras', 'DZ.11' => 'Tamanrasset', 'DZ.12' => 'Tebessa', 'DZ.14' => 'Tiaret', 'DZ.49' => 'Timimoun', 'DZ.37' => 'Tindouf', 'DZ.42' => 'Tipaza', 'DZ.38' => 'Tissemsilt', 'DZ.15' => 'Tizi Ouzou', 'DZ.13' => 'Tlemcen', 'DZ.55' => 'Touggourt'],
3068 'EC' => ['EC.A' => 'Azuay', 'EC.B' => 'Bolivar', 'EC.F' => 'Canar', 'EC.C' => 'Carchi', 'EC.H' => 'Chimborazo', 'EC.X' => 'Cotopaxi', 'EC.O' => 'El Oro', 'EC.E' => 'Esmeraldas', 'EC.W' => 'Galapagos', 'EC.G' => 'Guayas', 'EC.I' => 'Imbabura', 'EC.L' => 'Loja', 'EC.R' => 'Los Rios', 'EC.M' => 'Manabi', 'EC.S' => 'Morona Santiago', 'EC.N' => 'Napo', 'EC.D' => 'Orellana', 'EC.Y' => 'Pastaza', 'EC.P' => 'Pichincha', 'EC.SE' => 'Santa Elena', 'EC.SD' => 'Santo Domingo de los Tsachilas', 'EC.U' => 'Sucumbios', 'EC.T' => 'Tungurahua', 'EC.Z' => 'Zamora Chinchipe'],
3069 'EE' => ['EE.37' => 'Harjumaa', 'EE.39' => 'Hiiumaa', 'EE.44' => 'Ida-Virumaa', 'EE.51' => 'Jarvamaa', 'EE.49' => 'Jogevamaa', 'EE.59' => 'Laane-Virumaa', 'EE.57' => 'Laanemaa', 'EE.67' => 'Parnumaa', 'EE.65' => 'Polvamaa', 'EE.70' => 'Raplamaa', 'EE.74' => 'Saaremaa', 'EE.78' => 'Tartumaa', 'EE.82' => 'Valgamaa', 'EE.84' => 'Viljandimaa', 'EE.86' => 'Vorumaa'],
3070 'EG' => ['EG.DK' => 'Ad Daqahliyah', 'EG.BA' => 'Al Bahr al Ahmar', 'EG.BH' => 'Al Buhayrah', 'EG.FYM' => 'Al Fayyum', 'EG.GH' => 'Al Gharbiyah', 'EG.ALX' => 'Al Iskandariyah', 'EG.IS' => 'Al Isma\'iliyah', 'EG.GZ' => 'Al Jizah', 'EG.MNF' => 'Al Minufiyah', 'EG.MN' => 'Al Minya', 'EG.C' => 'Al Qahirah', 'EG.KB' => 'Al Qalyubiyah', 'EG.LX' => 'Al Uqsur', 'EG.WAD' => 'Al Wadi al Jadid', 'EG.SUZ' => 'As Suways', 'EG.SHR' => 'Ash Sharqiyah', 'EG.ASN' => 'Aswan', 'EG.AST' => 'Asyut', 'EG.BNS' => 'Bani Suwayf', 'EG.PTS' => 'Bur Sa\'id', 'EG.DT' => 'Dumyat', 'EG.JS' => 'Janub Sina\'', 'EG.KFS' => 'Kafr ash Shaykh', 'EG.MT' => 'Matruh', 'EG.KN' => 'Qina', 'EG.SIN' => 'Shamal Sina\'', 'EG.SHG' => 'Suhaj'],
3071 'ER' => ['ER.MA' => 'Al Awsat', 'ER.DU' => 'Al Janubi', 'ER.AN' => 'Ansaba', 'ER.DK' => 'Janubi al Bahri al Ahmar', 'ER.GB' => 'Qash-Barkah', 'ER.SK' => 'Shimali al Bahri al Ahmar'],
3072 'ES' => ['ES.AN' => 'Andalucia', 'ES.AR' => 'Aragon', 'ES.AS' => 'Asturias, Principado de', 'ES.CN' => 'Canarias', 'ES.CB' => 'Cantabria', 'ES.CL' => 'Castilla y Leon', 'ES.CM' => 'Castilla-La Mancha', 'ES.CT' => 'Catalunya', 'ES.CE' => 'Ceuta', 'ES.EX' => 'Extremadura', 'ES.GA' => 'Galicia', 'ES.IB' => 'Illes Balears', 'ES.RI' => 'La Rioja', 'ES.MD' => 'Madrid, Comunidad de', 'ES.ML' => 'Melilla', 'ES.MC' => 'Murcia, Region de', 'ES.NC' => 'Navarra, Comunidad Foral de', 'ES.PV' => 'Pais Vasco', 'ES.VC' => 'Valenciana, Comunidad'],
3073 'ET' => ['ET.AA' => 'Addis Ababa', 'ET.AF' => 'Afar', 'ET.AM' => 'Amara', 'ET.BE' => 'Benshangul-Gumaz', 'ET.DD' => 'Dire Dawa', 'ET.GA' => 'Gambela Peoples', 'ET.HA' => 'Harari People', 'ET.OR' => 'Oromia', 'ET.SI' => 'Sidama', 'ET.SO' => 'Somali', 'ET.SN' => 'Southern Nations, Nationalities and Peoples', 'ET.SW' => 'Southwest Ethiopia Peoples', 'ET.TI' => 'Tigrai'],
3074 'FI' => ['FI.01' => 'Ahvenanmaan maakunta', 'FI.02' => 'Etela-Karjala', 'FI.03' => 'Etela-Pohjanmaa', 'FI.04' => 'Etela-Savo', 'FI.05' => 'Kainuu', 'FI.06' => 'Kanta-Hame', 'FI.07' => 'Keski-Pohjanmaa', 'FI.08' => 'Keski-Suomi', 'FI.09' => 'Kymenlaakso', 'FI.10' => 'Lappi', 'FI.16' => 'Paijat-Hame', 'FI.11' => 'Pirkanmaa', 'FI.12' => 'Pohjanmaa', 'FI.13' => 'Pohjois-Karjala', 'FI.14' => 'Pohjois-Pohjanmaa', 'FI.15' => 'Pohjois-Savo', 'FI.17' => 'Satakunta', 'FI.18' => 'Uusimaa', 'FI.19' => 'Varsinais-Suomi'],
3075 'FJ' => ['FJ.C' => 'Central', 'FJ.E' => 'Eastern', 'FJ.N' => 'Northern', 'FJ.R' => 'Rotuma', 'FJ.W' => 'Western'],
3076 'FM' => ['FM.TRK' => 'Chuuk', 'FM.KSA' => 'Kosrae', 'FM.PNI' => 'Pohnpei', 'FM.YAP' => 'Yap'],
3077 'FR' => ['FR.ARA' => 'Auvergne-Rhone-Alpes', 'FR.BFC' => 'Bourgogne-Franche-Comte', 'FR.BRE' => 'Bretagne', 'FR.CVL' => 'Centre-Val de Loire', 'FR.COR' => 'Corse', 'FR.GES' => 'Grand-Est', 'FR.HDF' => 'Hauts-de-France', 'FR.IDF' => 'Ile-de-France', 'FR.NOR' => 'Normandie', 'FR.NAQ' => 'Nouvelle-Aquitaine', 'FR.OCC' => 'Occitanie', 'FR.PDL' => 'Pays-de-la-Loire', 'FR.PAC' => 'Provence-Alpes-Cote-d\'Azur'],
3078 'GA' => ['GA.1' => 'Estuaire', 'GA.2' => 'Haut-Ogooue', 'GA.3' => 'Moyen-Ogooue', 'GA.4' => 'Ngounie', 'GA.5' => 'Nyanga', 'GA.6' => 'Ogooue-Ivindo', 'GA.7' => 'Ogooue-Lolo', 'GA.8' => 'Ogooue-Maritime', 'GA.9' => 'Woleu-Ntem'],
3079 'GB' => ['GB.ENG' => 'England', 'GB.NIR' => 'Northern Ireland', 'GB.SCT' => 'Scotland', 'GB.WLS' => 'Wales'],
3080 'GD' => ['GD.01' => 'Saint Andrew', 'GD.02' => 'Saint David', 'GD.03' => 'Saint George', 'GD.04' => 'Saint John', 'GD.05' => 'Saint Mark', 'GD.06' => 'Saint Patrick', 'GD.10' => 'Southern Grenadine Islands'],
3081 'GE' => ['GE.AB' => 'Abkhazia', 'GE.AJ' => 'Ajaria', 'GE.GU' => 'Guria', 'GE.IM' => 'Imereti', 'GE.KA' => 'K\'akheti', 'GE.KK' => 'Kvemo Kartli', 'GE.MM' => 'Mtskheta-Mtianeti', 'GE.RL' => 'Rach\'a-Lechkhumi-Kvemo Svaneti', 'GE.SZ' => 'Samegrelo-Zemo Svaneti', 'GE.SJ' => 'Samtskhe-Javakheti', 'GE.SK' => 'Shida Kartli', 'GE.TB' => 'Tbilisi'],
3082 'GH' => ['GH.AF' => 'Ahafo', 'GH.AH' => 'Ashanti', 'GH.BO' => 'Bono', 'GH.BE' => 'Bono East', 'GH.CP' => 'Central', 'GH.EP' => 'Eastern', 'GH.AA' => 'Greater Accra', 'GH.NP' => 'Northern', 'GH.OT' => 'Oti', 'GH.SV' => 'Savannah', 'GH.UE' => 'Upper East', 'GH.UW' => 'Upper West', 'GH.TV' => 'Volta', 'GH.WP' => 'Western', 'GH.WN' => 'Western North'],
3083 'GL' => ['GL.AV' => 'Avannaata Kommunia', 'GL.KU' => 'Kommune Kujalleq', 'GL.QT' => 'Kommune Qeqertalik', 'GL.SM' => 'Kommuneqarfik Sermersooq', 'GL.QE' => 'Qeqqata Kommunia'],
3084 'GM' => ['GM.B' => 'Banjul', 'GM.M' => 'Central River', 'GM.L' => 'Lower River', 'GM.N' => 'North Bank', 'GM.U' => 'Upper River', 'GM.W' => 'Western'],
3085 'GN' => ['GN.BE' => 'Beyla', 'GN.BF' => 'Boffa', 'GN.B' => 'Boke', 'GN.C' => 'Conakry', 'GN.CO' => 'Coyah', 'GN.DB' => 'Dabola', 'GN.DL' => 'Dalaba', 'GN.DI' => 'Dinguiraye', 'GN.DU' => 'Dubreka', 'GN.F' => 'Faranah', 'GN.FA' => 'Faranah', 'GN.FO' => 'Forecariah', 'GN.FR' => 'Fria', 'GN.GA' => 'Gaoual', 'GN.GU' => 'Guekedou', 'GN.K' => 'Kankan', 'GN.KE' => 'Kerouane', 'GN.D' => 'Kindia', 'GN.KS' => 'Kissidougou', 'GN.KB' => 'Koubia', 'GN.KN' => 'Koundara', 'GN.KO' => 'Kouroussa', 'GN.L' => 'Labe', 'GN.LA' => 'Labe', 'GN.LE' => 'Lelouma', 'GN.LO' => 'Lola', 'GN.MC' => 'Macenta', 'GN.ML' => 'Mali', 'GN.M' => 'Mamou', 'GN.MD' => 'Mandiana', 'GN.N' => 'Nzerekore', 'GN.PI' => 'Pita', 'GN.SI' => 'Siguiri', 'GN.TE' => 'Telimele', 'GN.TO' => 'Tougue', 'GN.YO' => 'Yomou'],
3086 'GQ' => ['GQ.AN' => 'Annobon', 'GQ.BN' => 'Bioko Norte', 'GQ.BS' => 'Bioko Sur', 'GQ.CS' => 'Centro Sur', 'GQ.DJ' => 'Djibloho', 'GQ.KN' => 'Kie-Ntem', 'GQ.LI' => 'Litoral', 'GQ.WN' => 'Wele-Nzas'],
3087 'GR' => ['GR.69' => 'Agion Oros', 'GR.A' => 'Anatoliki Makedonia kai Thraki', 'GR.I' => 'Attiki', 'GR.G' => 'Dytiki Ellada', 'GR.C' => 'Dytiki Makedonia', 'GR.F' => 'Ionia Nisia', 'GR.D' => 'Ipeiros', 'GR.B' => 'Kentriki Makedonia', 'GR.M' => 'Kriti', 'GR.L' => 'Notio Aigaio', 'GR.J' => 'Peloponnisos', 'GR.H' => 'Sterea Ellada', 'GR.E' => 'Thessalia', 'GR.K' => 'Voreio Aigaio'],
3088 'GT' => ['GT.AV' => 'Alta Verapaz', 'GT.BV' => 'Baja Verapaz', 'GT.CM' => 'Chimaltenango', 'GT.CQ' => 'Chiquimula', 'GT.PR' => 'El Progreso', 'GT.ES' => 'Escuintla', 'GT.GU' => 'Guatemala', 'GT.HU' => 'Huehuetenango', 'GT.IZ' => 'Izabal', 'GT.JA' => 'Jalapa', 'GT.JU' => 'Jutiapa', 'GT.PE' => 'Peten', 'GT.QZ' => 'Quetzaltenango', 'GT.QC' => 'Quiche', 'GT.RE' => 'Retalhuleu', 'GT.SA' => 'Sacatepequez', 'GT.SM' => 'San Marcos', 'GT.SR' => 'Santa Rosa', 'GT.SO' => 'Solola', 'GT.SU' => 'Suchitepequez', 'GT.TO' => 'Totonicapan', 'GT.ZA' => 'Zacapa'],
3089 'GW' => ['GW.BA' => 'Bafata', 'GW.BM' => 'Biombo', 'GW.BS' => 'Bissau', 'GW.BL' => 'Bolama', 'GW.CA' => 'Cacheu', 'GW.GA' => 'Gabu', 'GW.OI' => 'Oio', 'GW.QU' => 'Quinara', 'GW.TO' => 'Tombali'],
3090 'GY' => ['GY.BA' => 'Barima-Waini', 'GY.CU' => 'Cuyuni-Mazaruni', 'GY.DE' => 'Demerara-Mahaica', 'GY.EB' => 'East Berbice-Corentyne', 'GY.ES' => 'Essequibo Islands-West Demerara', 'GY.MA' => 'Mahaica-Berbice', 'GY.PM' => 'Pomeroon-Supenaam', 'GY.PT' => 'Potaro-Siparuni', 'GY.UD' => 'Upper Demerara-Berbice', 'GY.UT' => 'Upper Takutu-Upper Essequibo'],
3091 'HN' => ['HN.AT' => 'Atlantida', 'HN.CH' => 'Choluteca', 'HN.CL' => 'Colon', 'HN.CM' => 'Comayagua', 'HN.CP' => 'Copan', 'HN.CR' => 'Cortes', 'HN.EP' => 'El Paraiso', 'HN.FM' => 'Francisco Morazan', 'HN.GD' => 'Gracias a Dios', 'HN.IN' => 'Intibuca', 'HN.IB' => 'Islas de la Bahia', 'HN.LP' => 'La Paz', 'HN.LE' => 'Lempira', 'HN.OC' => 'Ocotepeque', 'HN.OL' => 'Olancho', 'HN.SB' => 'Santa Barbara', 'HN.VA' => 'Valle', 'HN.YO' => 'Yoro'],
3092 'HR' => ['HR.07' => 'Bjelovarsko-bilogorska zupanija', 'HR.12' => 'Brodsko-posavska zupanija', 'HR.19' => 'Dubrovacko-neretvanska zupanija', 'HR.21' => 'Grad Zagreb', 'HR.18' => 'Istarska zupanija', 'HR.04' => 'Karlovacka zupanija', 'HR.06' => 'Koprivnicko-krizevacka zupanija', 'HR.02' => 'Krapinsko-zagorska zupanija', 'HR.09' => 'Licko-senjska zupanija', 'HR.20' => 'Medimurska zupanija', 'HR.14' => 'Osjecko-baranjska zupanija', 'HR.11' => 'Pozesko-slavonska zupanija', 'HR.08' => 'Primorsko-goranska zupanija', 'HR.15' => 'Sibensko-kninska zupanija', 'HR.03' => 'Sisacko-moslavacka zupanija', 'HR.17' => 'Splitsko-dalmatinska zupanija', 'HR.05' => 'Varazdinska zupanija', 'HR.10' => 'Viroviticko-podravska zupanija', 'HR.16' => 'Vukovarsko-srijemska zupanija', 'HR.13' => 'Zadarska zupanija', 'HR.01' => 'Zagrebacka zupanija'],
3093 'HT' => ['HT.AR' => 'Artibonite', 'HT.CE' => 'Centre', 'HT.GA' => 'Grande\'Anse', 'HT.NI' => 'Nippes', 'HT.ND' => 'Nord', 'HT.NE' => 'Nord-Est', 'HT.NO' => 'Nord-Ouest', 'HT.OU' => 'Ouest', 'HT.SD' => 'Sud', 'HT.SE' => 'Sud-Est'],
3094 'HU' => ['HU.BK' => 'Bacs-Kiskun', 'HU.BA' => 'Baranya', 'HU.BE' => 'Bekes', 'HU.BZ' => 'Borsod-Abauj-Zemplen', 'HU.BU' => 'Budapest', 'HU.CS' => 'Csongrad', 'HU.FE' => 'Fejer', 'HU.GS' => 'Gyor-Moson-Sopron', 'HU.HB' => 'Hajdu-Bihar', 'HU.HE' => 'Heves', 'HU.JN' => 'Jasz-Nagykun-Szolnok', 'HU.KE' => 'Komarom-Esztergom', 'HU.NO' => 'Nograd', 'HU.PE' => 'Pest', 'HU.SO' => 'Somogy', 'HU.SZ' => 'Szabolcs-Szatmar-Bereg', 'HU.TO' => 'Tolna', 'HU.VA' => 'Vas', 'HU.VE' => 'Veszprem', 'HU.ZA' => 'Zala'],
3095 'ID' => ['ID.AC' => 'Aceh', 'ID.BA' => 'Bali', 'ID.BT' => 'Banten', 'ID.BE' => 'Bengkulu', 'ID.GO' => 'Gorontalo', 'ID.JK' => 'Jakarta Raya', 'ID.JA' => 'Jambi', 'ID.JB' => 'Jawa Barat', 'ID.JT' => 'Jawa Tengah', 'ID.JI' => 'Jawa Timur', 'ID.KB' => 'Kalimantan Barat', 'ID.KS' => 'Kalimantan Selatan', 'ID.KT' => 'Kalimantan Tengah', 'ID.KI' => 'Kalimantan Timur', 'ID.KU' => 'Kalimantan Utara', 'ID.BB' => 'Kepulauan Bangka Belitung', 'ID.KR' => 'Kepulauan Riau', 'ID.LA' => 'Lampung', 'ID.ML' => 'Maluku', 'ID.MU' => 'Maluku Utara', 'ID.NB' => 'Nusa Tenggara Barat', 'ID.NT' => 'Nusa Tenggara Timur', 'ID.PP' => 'Papua', 'ID.PB' => 'Papua Barat', 'ID.PE' => 'Papua Pengunungan', 'ID.PS' => 'Papua Selatan', 'ID.PT' => 'Papua Tengah', 'ID.RI' => 'Riau', 'ID.SR' => 'Sulawesi Barat', 'ID.SN' => 'Sulawesi Selatan', 'ID.ST' => 'Sulawesi Tengah', 'ID.SG' => 'Sulawesi Tenggara', 'ID.SA' => 'Sulawesi Utara', 'ID.SB' => 'Sumatera Barat', 'ID.SS' => 'Sumatera Selatan', 'ID.SU' => 'Sumatera Utara', 'ID.YO' => 'Yogyakarta'],
3096 'IE' => ['IE.CW' => 'Carlow', 'IE.CN' => 'Cavan', 'IE.CE' => 'Clare', 'IE.CO' => 'Cork', 'IE.DL' => 'Donegal', 'IE.D' => 'Dublin', 'IE.G' => 'Galway', 'IE.KY' => 'Kerry', 'IE.KE' => 'Kildare', 'IE.KK' => 'Kilkenny', 'IE.LS' => 'Laois', 'IE.LM' => 'Leitrim', 'IE.LK' => 'Limerick', 'IE.LD' => 'Longford', 'IE.LH' => 'Louth', 'IE.MO' => 'Mayo', 'IE.MH' => 'Meath', 'IE.MN' => 'Monaghan', 'IE.OY' => 'Offaly', 'IE.RN' => 'Roscommon', 'IE.SO' => 'Sligo', 'IE.TA' => 'Tipperary', 'IE.WD' => 'Waterford', 'IE.WH' => 'Westmeath', 'IE.WX' => 'Wexford', 'IE.WW' => 'Wicklow'],
3097 'IL' => ['IL.D' => 'HaDarom', 'IL.M' => 'HaMerkaz', 'IL.Z' => 'HaTsafon', 'IL.HA' => 'Hefa', 'IL.TA' => 'Tel Aviv', 'IL.JM' => 'Yerushalayim'],
3098 'IN' => ['IN.AN' => 'Andaman and Nicobar Islands', 'IN.AP' => 'Andhra Pradesh', 'IN.AR' => 'Arunachal Pradesh', 'IN.AS' => 'Assam', 'IN.BR' => 'Bihar', 'IN.CH' => 'Chandigarh', 'IN.CT' => 'Chhattisgarh', 'IN.DN' => 'Dadra and Nagar Haveli', 'IN.DH' => 'Dadra and Nagar Haveli and Daman and Diu', 'IN.DL' => 'Delhi', 'IN.GA' => 'Goa', 'IN.GJ' => 'Gujarat', 'IN.HR' => 'Haryana', 'IN.HP' => 'Himachal Pradesh', 'IN.JK' => 'Jammu and Kashmir', 'IN.JH' => 'Jharkhand', 'IN.KA' => 'Karnataka', 'IN.KL' => 'Kerala', 'IN.LA' => 'Ladakh', 'IN.LD' => 'Lakshadweep', 'IN.MP' => 'Madhya Pradesh', 'IN.MH' => 'Maharashtra', 'IN.MN' => 'Manipur', 'IN.ML' => 'Meghalaya', 'IN.MZ' => 'Mizoram', 'IN.NL' => 'Nagaland', 'IN.OR' => 'Odisha', 'IN.PY' => 'Puducherry', 'IN.PB' => 'Punjab', 'IN.RJ' => 'Rajasthan', 'IN.SK' => 'Sikkim', 'IN.TN' => 'Tamil Nadu', 'IN.TG' => 'Telangana', 'IN.TR' => 'Tripura', 'IN.UP' => 'Uttar Pradesh', 'IN.UT' => 'Uttarakhand', 'IN.WB' => 'West Bengal'],
3099 'IQ' => ['IQ.AN' => 'Al Anbar', 'IQ.BA' => 'Al Basrah', 'IQ.MU' => 'Al Muthanna', 'IQ.QA' => 'Al Qadisiyah', 'IQ.NA' => 'An Najaf', 'IQ.AR' => 'Arbil', 'IQ.SU' => 'As Sulaymaniyah', 'IQ.BB' => 'Babil', 'IQ.BG' => 'Baghdad', 'IQ.DA' => 'Dahuk', 'IQ.DQ' => 'Dhi Qar', 'IQ.DI' => 'Diyala', 'IQ.KA' => 'Karbala\'', 'IQ.KI' => 'Kirkuk', 'IQ.MA' => 'Maysan', 'IQ.NI' => 'Ninawa', 'IQ.SD' => 'Salah ad Din', 'IQ.WA' => 'Wasit'],
3100 'IR' => ['IR.32' => 'Alborz', 'IR.03' => 'Ardabil', 'IR.02' => 'Azarbayjan-e Gharbi', 'IR.01' => 'Azarbayjan-e Sharqi', 'IR.06' => 'Bushehr', 'IR.08' => 'Chahar Mahal va Bakhtiari', 'IR.04' => 'Esfahan', 'IR.14' => 'Fars', 'IR.19' => 'Gilan', 'IR.27' => 'Golestan', 'IR.24' => 'Hamadan', 'IR.23' => 'Hormozgan', 'IR.05' => 'Ilam', 'IR.15' => 'Kerman', 'IR.17' => 'Kermanshah', 'IR.29' => 'Khorasan-e Jonubi', 'IR.30' => 'Khorasan-e Razavi', 'IR.31' => 'Khorasan-e Shomali', 'IR.10' => 'Khuzestan', 'IR.18' => 'Kohgiluyeh va Bowyer Ahmad', 'IR.16' => 'Kordestan', 'IR.20' => 'Lorestan', 'IR.22' => 'Markazi', 'IR.21' => 'Mazandaran', 'IR.28' => 'Qazvin', 'IR.26' => 'Qom', 'IR.12' => 'Semnan', 'IR.13' => 'Sistan va Baluchestan', 'IR.07' => 'Tehran', 'IR.25' => 'Yazd', 'IR.11' => 'Zanjan'],
3101 'IS' => ['IS.7' => 'Austurland', 'IS.1' => 'Hofudborgarsvaedi', 'IS.6' => 'Nordurland eystra', 'IS.5' => 'Nordurland vestra', 'IS.8' => 'Sudurland', 'IS.2' => 'Sudurnes', 'IS.4' => 'Vestfirdir', 'IS.3' => 'Vesturland'],
3102 'IT' => ['IT.65' => 'Abruzzo', 'IT.77' => 'Basilicata', 'IT.78' => 'Calabria', 'IT.72' => 'Campania', 'IT.45' => 'Emilia-Romagna', 'IT.36' => 'Friuli-Venezia Giulia', 'IT.62' => 'Lazio', 'IT.42' => 'Liguria', 'IT.25' => 'Lombardia', 'IT.57' => 'Marche', 'IT.67' => 'Molise', 'IT.21' => 'Piemonte', 'IT.75' => 'Puglia', 'IT.88' => 'Sardegna', 'IT.82' => 'Sicilia', 'IT.52' => 'Toscana', 'IT.32' => 'Trentino-Alto Adige', 'IT.55' => 'Umbria', 'IT.23' => 'Valle d\'Aosta', 'IT.34' => 'Veneto'],
3103 'JM' => ['JM.13' => 'Clarendon', 'JM.09' => 'Hanover', 'JM.01' => 'Kingston', 'JM.12' => 'Manchester', 'JM.04' => 'Portland', 'JM.02' => 'Saint Andrew', 'JM.06' => 'Saint Ann', 'JM.14' => 'Saint Catherine', 'JM.11' => 'Saint Elizabeth', 'JM.08' => 'Saint James', 'JM.05' => 'Saint Mary', 'JM.03' => 'Saint Thomas', 'JM.07' => 'Trelawny', 'JM.10' => 'Westmoreland'],
3104 'JO' => ['JO.AJ' => '\'Ajlun', 'JO.AQ' => 'Al \'Aqabah', 'JO.AM' => 'Al \'Asimah', 'JO.BA' => 'Al Balqa\'', 'JO.KA' => 'Al Karak', 'JO.MA' => 'Al Mafraq', 'JO.AT' => 'At Tafilah', 'JO.AZ' => 'Az Zarqa\'', 'JO.IR' => 'Irbid', 'JO.JA' => 'Jarash', 'JO.MN' => 'Ma\'an', 'JO.MD' => 'Madaba'],
3105 'JP' => ['JP.23' => 'Aichi', 'JP.05' => 'Akita', 'JP.02' => 'Aomori', 'JP.12' => 'Chiba', 'JP.38' => 'Ehime', 'JP.18' => 'Fukui', 'JP.40' => 'Fukuoka', 'JP.07' => 'Fukushima', 'JP.21' => 'Gifu', 'JP.10' => 'Gunma', 'JP.34' => 'Hiroshima', 'JP.01' => 'Hokkaido', 'JP.28' => 'Hyogo', 'JP.08' => 'Ibaraki', 'JP.17' => 'Ishikawa', 'JP.03' => 'Iwate', 'JP.37' => 'Kagawa', 'JP.46' => 'Kagoshima', 'JP.14' => 'Kanagawa', 'JP.39' => 'Kochi', 'JP.43' => 'Kumamoto', 'JP.26' => 'Kyoto', 'JP.24' => 'Mie', 'JP.04' => 'Miyagi', 'JP.45' => 'Miyazaki', 'JP.20' => 'Nagano', 'JP.42' => 'Nagasaki', 'JP.29' => 'Nara', 'JP.15' => 'Niigata', 'JP.44' => 'Oita', 'JP.33' => 'Okayama', 'JP.47' => 'Okinawa', 'JP.27' => 'Osaka', 'JP.41' => 'Saga', 'JP.11' => 'Saitama', 'JP.25' => 'Shiga', 'JP.32' => 'Shimane', 'JP.22' => 'Shizuoka', 'JP.09' => 'Tochigi', 'JP.36' => 'Tokushima', 'JP.13' => 'Tokyo', 'JP.31' => 'Tottori', 'JP.16' => 'Toyama', 'JP.30' => 'Wakayama', 'JP.06' => 'Yamagata', 'JP.35' => 'Yamaguchi', 'JP.19' => 'Yamanashi'],
3106 'KE' => ['KE.01' => 'Baringo', 'KE.02' => 'Bomet', 'KE.03' => 'Bungoma', 'KE.04' => 'Busia', 'KE.05' => 'Elgeyo/Marakwet', 'KE.06' => 'Embu', 'KE.07' => 'Garissa', 'KE.08' => 'Homa Bay', 'KE.09' => 'Isiolo', 'KE.10' => 'Kajiado', 'KE.11' => 'Kakamega', 'KE.12' => 'Kericho', 'KE.13' => 'Kiambu', 'KE.14' => 'Kilifi', 'KE.15' => 'Kirinyaga', 'KE.16' => 'Kisii', 'KE.17' => 'Kisumu', 'KE.18' => 'Kitui', 'KE.19' => 'Kwale', 'KE.20' => 'Laikipia', 'KE.21' => 'Lamu', 'KE.22' => 'Machakos', 'KE.23' => 'Makueni', 'KE.24' => 'Mandera', 'KE.25' => 'Marsabit', 'KE.26' => 'Meru', 'KE.27' => 'Migori', 'KE.28' => 'Mombasa', 'KE.29' => 'Murang\'a', 'KE.30' => 'Nairobi City', 'KE.31' => 'Nakuru', 'KE.32' => 'Nandi', 'KE.33' => 'Narok', 'KE.34' => 'Nyamira', 'KE.35' => 'Nyandarua', 'KE.36' => 'Nyeri', 'KE.37' => 'Samburu', 'KE.38' => 'Siaya', 'KE.39' => 'Taita/Taveta', 'KE.40' => 'Tana River', 'KE.41' => 'Tharaka-Nithi', 'KE.42' => 'Trans Nzoia', 'KE.43' => 'Turkana', 'KE.44' => 'Uasin Gishu', 'KE.45' => 'Vihiga', 'KE.46' => 'Wajir', 'KE.47' => 'West Pokot'],
3107 'KG' => ['KG.B' => 'Batken', 'KG.GB' => 'Bishkek Shaary', 'KG.C' => 'Chuy', 'KG.J' => 'Jalal-Abad', 'KG.N' => 'Naryn', 'KG.GO' => 'Osh Shaary', 'KG.T' => 'Talas', 'KG.Y' => 'Ysyk-Kol'],
3108 'KH' => ['KH.2' => 'Baat Dambang', 'KH.1' => 'Banteay Mean Choay', 'KH.23' => 'Kaeb', 'KH.3' => 'Kampong Chaam', 'KH.4' => 'Kampong Chhnang', 'KH.5' => 'Kampong Spueu', 'KH.6' => 'Kampong Thum', 'KH.7' => 'Kampot', 'KH.8' => 'Kandaal', 'KH.9' => 'Kaoh Kong', 'KH.10' => 'Kracheh', 'KH.11' => 'Mondol Kiri', 'KH.22' => 'Otdar Mean Chey', 'KH.24' => 'Pailin', 'KH.12' => 'Phnom Penh', 'KH.15' => 'Pousaat', 'KH.18' => 'Preah Sihanouk', 'KH.13' => 'Preah Vihear', 'KH.14' => 'Prey Veaeng', 'KH.16' => 'Rotanak Kiri', 'KH.17' => 'Siem Reab', 'KH.19' => 'Stueng Traeng', 'KH.20' => 'Svaay Rieng', 'KH.21' => 'Taakaev', 'KH.25' => 'Tbong Khmum'],
3109 'KI' => ['KI.G' => 'Gilbert Islands', 'KI.L' => 'Line Islands', 'KI.P' => 'Phoenix Islands'],
3110 'KM' => ['KM.A' => 'Anjouan', 'KM.G' => 'Grande Comore', 'KM.M' => 'Moheli'],
3111 'KN' => ['KN.01' => 'Christ Church Nichola Town', 'KN.02' => 'Saint Anne Sandy Point', 'KN.03' => 'Saint George Basseterre', 'KN.04' => 'Saint George Gingerland', 'KN.05' => 'Saint James Windward', 'KN.06' => 'Saint John Capisterre', 'KN.07' => 'Saint John Figtree', 'KN.08' => 'Saint Mary Cayon', 'KN.09' => 'Saint Paul Capisterre', 'KN.10' => 'Saint Paul Charlestown', 'KN.11' => 'Saint Peter Basseterre', 'KN.12' => 'Saint Thomas Lowland', 'KN.13' => 'Saint Thomas Middle Island', 'KN.15' => 'Trinity Palmetto Point'],
3112 'KP' => ['KP.04' => 'Chagang-do', 'KP.09' => 'Hamgyong-bukto', 'KP.08' => 'Hamgyong-namdo', 'KP.06' => 'Hwanghae-bukto', 'KP.05' => 'Hwanghae-namdo', 'KP.07' => 'Kangwon-do', 'KP.03' => 'P\'yongan-bukto', 'KP.02' => 'P\'yongan-namdo', 'KP.01' => 'P\'yongyang', 'KP.13' => 'Rason', 'KP.10' => 'Ryanggang-do'],
3113 'KR' => ['KR.26' => 'Busan-gwangyeoksi', 'KR.43' => 'Chungcheongbuk-do', 'KR.44' => 'Chungcheongnam-do', 'KR.27' => 'Daegu-gwangyeoksi', 'KR.30' => 'Daejeon-gwangyeoksi', 'KR.42' => 'Gangwon-do', 'KR.29' => 'Gwangju-gwangyeoksi', 'KR.41' => 'Gyeonggi-do', 'KR.47' => 'Gyeongsangbuk-do', 'KR.48' => 'Gyeongsangnam-do', 'KR.28' => 'Incheon-gwangyeoksi', 'KR.49' => 'Jeju-teukbyeoljachido', 'KR.45' => 'Jeollabuk-do', 'KR.46' => 'Jeollanam-do', 'KR.11' => 'Seoul-teukbyeolsi', 'KR.31' => 'Ulsan-gwangyeoksi'],
3114 'KW' => ['KW.KU' => 'Al \'Asimah', 'KW.AH' => 'Al Ahmadi', 'KW.FA' => 'Al Farwaniyah', 'KW.JA' => 'Al Jahra\'', 'KW.HA' => 'Hawalli', 'KW.MU' => 'Mubarak al Kabir'],
3115 'KZ' => ['KZ.10' => 'Abay oblysy', 'KZ.75' => 'Almaty', 'KZ.19' => 'Almaty oblysy', 'KZ.11' => 'Aqmola oblysy', 'KZ.15' => 'Aqtobe oblysy', 'KZ.71' => 'Astana', 'KZ.23' => 'Atyrau oblysy', 'KZ.27' => 'Batys Qazaqstan oblysy', 'KZ.47' => 'Mangghystau oblysy', 'KZ.55' => 'Pavlodar oblysy', 'KZ.35' => 'Qaraghandy oblysy', 'KZ.39' => 'Qostanay oblysy', 'KZ.43' => 'Qyzylorda oblysy', 'KZ.63' => 'Shyghys Qazaqstan oblysy', 'KZ.79' => 'Shymkent', 'KZ.59' => 'Soltustik Qazaqstan oblysy', 'KZ.61' => 'Turkistan oblysy', 'KZ.62' => 'Ulytau oblysy', 'KZ.31' => 'Zhambyl oblysy', 'KZ.33' => 'Zhetisu oblysy'],
3116 'LA' => ['LA.AT' => 'Attapu', 'LA.BK' => 'Bokeo', 'LA.BL' => 'Bolikhamxai', 'LA.CH' => 'Champasak', 'LA.HO' => 'Houaphan', 'LA.KH' => 'Khammouan', 'LA.LM' => 'Louang Namtha', 'LA.LP' => 'Louangphabang', 'LA.OU' => 'Oudomxai', 'LA.PH' => 'Phongsali', 'LA.SL' => 'Salavan', 'LA.SV' => 'Savannakhet', 'LA.VI' => 'Viangchan', 'LA.XA' => 'Xaignabouli', 'LA.XS' => 'Xaisomboun', 'LA.XE' => 'Xekong', 'LA.XI' => 'Xiangkhouang'],
3117 'LB' => ['LB.AK' => 'Aakkar', 'LB.BH' => 'Baalbek-Hermel', 'LB.BI' => 'Beqaa', 'LB.BA' => 'Beyrouth', 'LB.AS' => 'Liban-Nord', 'LB.JA' => 'Liban-Sud', 'LB.JL' => 'Mont-Liban', 'LB.NA' => 'Nabatiye'],
3118 'LC' => ['LC.01' => 'Anse la Raye', 'LC.12' => 'Canaries', 'LC.02' => 'Castries', 'LC.03' => 'Choiseul', 'LC.05' => 'Dennery', 'LC.06' => 'Gros Islet', 'LC.07' => 'Laborie', 'LC.08' => 'Micoud', 'LC.10' => 'Soufriere', 'LC.11' => 'Vieux Fort'],
3119 'LI' => ['LI.01' => 'Balzers', 'LI.02' => 'Eschen', 'LI.03' => 'Gamprin', 'LI.04' => 'Mauren', 'LI.05' => 'Planken', 'LI.06' => 'Ruggell', 'LI.07' => 'Schaan', 'LI.08' => 'Schellenberg', 'LI.09' => 'Triesen', 'LI.10' => 'Triesenberg', 'LI.11' => 'Vaduz'],
3120 'LK' => ['LK.2' => 'Central Province', 'LK.5' => 'Eastern Province', 'LK.7' => 'North Central Province', 'LK.6' => 'North Western Province', 'LK.4' => 'Northern Province', 'LK.9' => 'Sabaragamuwa Province', 'LK.3' => 'Southern Province', 'LK.8' => 'Uva Province', 'LK.1' => 'Western Province'],
3121 'LR' => ['LR.BM' => 'Bomi', 'LR.BG' => 'Bong', 'LR.GP' => 'Gbarpolu', 'LR.GB' => 'Grand Bassa', 'LR.CM' => 'Grand Cape Mount', 'LR.GG' => 'Grand Gedeh', 'LR.GK' => 'Grand Kru', 'LR.LO' => 'Lofa', 'LR.MG' => 'Margibi', 'LR.MY' => 'Maryland', 'LR.MO' => 'Montserrado', 'LR.NI' => 'Nimba', 'LR.RI' => 'River Cess', 'LR.RG' => 'River Gee', 'LR.SI' => 'Sinoe'],
3122 'LS' => ['LS.D' => 'Berea', 'LS.B' => 'Botha-Bothe', 'LS.C' => 'Leribe', 'LS.E' => 'Mafeteng', 'LS.A' => 'Maseru', 'LS.F' => 'Mohale\'s Hoek', 'LS.J' => 'Mokhotlong', 'LS.H' => 'Qacha\'s Nek', 'LS.G' => 'Quthing', 'LS.K' => 'Thaba-Tseka'],
3123 'LT' => ['LT.AL' => 'Alytaus apskritis', 'LT.KU' => 'Kauno apskritis', 'LT.KL' => 'Klaipedos apskritis', 'LT.MR' => 'Marijampoles apskritis', 'LT.PN' => 'Panevezio apskritis', 'LT.SA' => 'Siauliu apskritis', 'LT.TA' => 'Taurages apskritis', 'LT.TE' => 'Telsiu apskritis', 'LT.UT' => 'Utenos apskritis', 'LT.VL' => 'Vilniaus apskritis'],
3124 'LU' => ['LU.CA' => 'Capellen', 'LU.CL' => 'Clervaux', 'LU.DI' => 'Diekirch', 'LU.EC' => 'Echternach', 'LU.ES' => 'Esch-sur-Alzette', 'LU.GR' => 'Grevenmacher', 'LU.LU' => 'Luxembourg', 'LU.ME' => 'Mersch', 'LU.RD' => 'Redange', 'LU.RM' => 'Remich', 'LU.VD' => 'Vianden', 'LU.WI' => 'Wiltz'],
3125 'LV' => ['LV.011' => 'Adazu novads', 'LV.002' => 'Aizkraukles novads', 'LV.007' => 'Aluksnes novads', 'LV.111' => 'Augsdaugavas novads', 'LV.015' => 'Balvu novads', 'LV.016' => 'Bauskas novads', 'LV.022' => 'Cesu novads', 'LV.DGV' => 'Daugavpils', 'LV.112' => 'Dienvidkurzemes novads', 'LV.026' => 'Dobeles novads', 'LV.033' => 'Gulbenes novads', 'LV.042' => 'Jekabpils novads', 'LV.JEL' => 'Jelgava', 'LV.041' => 'Jelgavas novads', 'LV.JUR' => 'Jurmala', 'LV.052' => 'Kekavas novads', 'LV.047' => 'Kraslavas novads', 'LV.050' => 'Kuldigas novads', 'LV.LPX' => 'Liepaja', 'LV.054' => 'Limbazu novads', 'LV.056' => 'Livanu novads', 'LV.058' => 'Ludzas novads', 'LV.059' => 'Madonas novads', 'LV.062' => 'Marupes novads', 'LV.067' => 'Ogres novads', 'LV.068' => 'Olaines novads', 'LV.073' => 'Preilu novads', 'LV.REZ' => 'Rezekne', 'LV.077' => 'Rezeknes novads', 'LV.RIX' => 'Riga', 'LV.080' => 'Ropazu novads', 'LV.087' => 'Salaspils novads', 'LV.088' => 'Saldus novads', 'LV.089' => 'Saulkrastu novads', 'LV.091' => 'Siguldas novads', 'LV.094' => 'Smiltenes novads', 'LV.097' => 'Talsu novads', 'LV.099' => 'Tukuma novads', 'LV.101' => 'Valkas novads', 'LV.113' => 'Valmieras novads', 'LV.102' => 'Varaklanu novads', 'LV.VEN' => 'Ventspils', 'LV.106' => 'Ventspils novads'],
3126 'LY' => ['LY.BU' => 'Al Butnan', 'LY.JA' => 'Al Jabal al Akhdar', 'LY.JG' => 'Al Jabal al Gharbi', 'LY.JI' => 'Al Jafarah', 'LY.JU' => 'Al Jufrah', 'LY.KF' => 'Al Kufrah', 'LY.MJ' => 'Al Marj', 'LY.MB' => 'Al Marqab', 'LY.WA' => 'Al Wahat', 'LY.NQ' => 'An Nuqat al Khams', 'LY.ZA' => 'Az Zawiyah', 'LY.BA' => 'Banghazi', 'LY.DR' => 'Darnah', 'LY.GT' => 'Ghat', 'LY.MI' => 'Misratah', 'LY.MQ' => 'Murzuq', 'LY.NL' => 'Nalut', 'LY.SB' => 'Sabha', 'LY.SR' => 'Surt', 'LY.TB' => 'Tarabulus', 'LY.WD' => 'Wadi al Hayat', 'LY.WS' => 'Wadi ash Shati\''],
3127 'MA' => ['MA.05' => 'Beni-Mellal-Khenifra', 'MA.06' => 'Casablanca-Settat', 'MA.12' => 'Dakhla-Oued Ed-Dahab (EH)', 'MA.08' => 'Draa-Tafilalet', 'MA.03' => 'Fes- Meknes', 'MA.10' => 'Guelmim-Oued Noun (EH-partial)', 'MA.02' => 'L\'Oriental', 'MA.11' => 'Laayoune-Sakia El Hamra (EH-partial)', 'MA.07' => 'Marrakech-Safi', 'MA.04' => 'Rabat-Sale-Kenitra', 'MA.09' => 'Souss-Massa', 'MA.01' => 'Tanger-Tetouan-Al Hoceima'],
3128 'MC' => ['MC.FO' => 'Fontvieille', 'MC.JE' => 'Jardin Exotique', 'MC.CL' => 'La Colle', 'MC.CO' => 'La Condamine', 'MC.GA' => 'La Gare', 'MC.SO' => 'La Source', 'MC.LA' => 'Larvotto', 'MC.MA' => 'Malbousquet', 'MC.MO' => 'Monaco-Ville', 'MC.MG' => 'Moneghetti', 'MC.MC' => 'Monte-Carlo', 'MC.MU' => 'Moulins', 'MC.PH' => 'Port-Hercule', 'MC.SR' => 'Saint-Roman', 'MC.SD' => 'Sainte-Devote', 'MC.SP' => 'Spelugues', 'MC.VR' => 'Vallon de la Rousse'],
3129 'MD' => ['MD.AN' => 'Anenii Noi', 'MD.BA' => 'Balti', 'MD.BS' => 'Basarabeasca', 'MD.BD' => 'Bender', 'MD.BR' => 'Briceni', 'MD.CA' => 'Cahul', 'MD.CL' => 'Calarasi', 'MD.CT' => 'Cantemir', 'MD.CS' => 'Causeni', 'MD.CU' => 'Chisinau', 'MD.CM' => 'Cimislia', 'MD.CR' => 'Criuleni', 'MD.DO' => 'Donduseni', 'MD.DR' => 'Drochia', 'MD.DU' => 'Dubasari', 'MD.ED' => 'Edinet', 'MD.FA' => 'Falesti', 'MD.FL' => 'Floresti', 'MD.GA' => 'Gagauzia, Unitatea teritoriala autonoma', 'MD.GL' => 'Glodeni', 'MD.HI' => 'Hincesti', 'MD.IA' => 'Ialoveni', 'MD.LE' => 'Leova', 'MD.NI' => 'Nisporeni', 'MD.OC' => 'Ocnita', 'MD.OR' => 'Orhei', 'MD.RE' => 'Rezina', 'MD.RI' => 'Riscani', 'MD.SI' => 'Singerei', 'MD.SD' => 'Soldanesti', 'MD.SO' => 'Soroca', 'MD.SV' => 'Stefan Voda', 'MD.SN' => 'Stinga Nistrului, unitatea teritoriala din', 'MD.ST' => 'Straseni', 'MD.TA' => 'Taraclia', 'MD.TE' => 'Telenesti', 'MD.UN' => 'Ungheni'],
3130 'ME' => ['ME.01' => 'Andrijevica', 'ME.02' => 'Bar', 'ME.03' => 'Berane', 'ME.04' => 'Bijelo Polje', 'ME.05' => 'Budva', 'ME.06' => 'Cetinje', 'ME.07' => 'Danilovgrad', 'ME.22' => 'Gusinje', 'ME.08' => 'Herceg-Novi', 'ME.09' => 'Kolasin', 'ME.10' => 'Kotor', 'ME.11' => 'Mojkovac', 'ME.12' => 'Niksic', 'ME.23' => 'Petnjica', 'ME.13' => 'Plav', 'ME.14' => 'Pljevlja', 'ME.15' => 'Pluzine', 'ME.16' => 'Podgorica', 'ME.17' => 'Rozaje', 'ME.18' => 'Savnik', 'ME.19' => 'Tivat', 'ME.24' => 'Tuzi', 'ME.20' => 'Ulcinj', 'ME.21' => 'Zabljak'],
3131 'MG' => ['MG.T' => 'Antananarivo', 'MG.D' => 'Antsiranana', 'MG.F' => 'Fianarantsoa', 'MG.M' => 'Mahajanga', 'MG.A' => 'Toamasina', 'MG.U' => 'Toliara'],
3132 'MH' => ['MH.ALL' => 'Ailinglaplap', 'MH.ALK' => 'Ailuk', 'MH.ARN' => 'Arno', 'MH.AUR' => 'Aur', 'MH.KIL' => 'Bikini & Kili', 'MH.EBO' => 'Ebon', 'MH.ENI' => 'Enewetak & Ujelang', 'MH.JAB' => 'Jabat', 'MH.JAL' => 'Jaluit', 'MH.KWA' => 'Kwajalein', 'MH.LAE' => 'Lae', 'MH.LIB' => 'Lib', 'MH.LIK' => 'Likiep', 'MH.MAJ' => 'Majuro', 'MH.MAL' => 'Maloelap', 'MH.MEJ' => 'Mejit', 'MH.MIL' => 'Mili', 'MH.NMK' => 'Namdrik', 'MH.NMU' => 'Namu', 'MH.RON' => 'Rongelap', 'MH.UJA' => 'Ujae', 'MH.UTI' => 'Utrik', 'MH.WTH' => 'Wotho', 'MH.WTJ' => 'Wotje'],
3133 'MK' => ['MK.801' => 'Aerodrom', 'MK.802' => 'Aracinovo', 'MK.201' => 'Berovo', 'MK.501' => 'Bitola', 'MK.401' => 'Bogdanci', 'MK.601' => 'Bogovinje', 'MK.402' => 'Bosilovo', 'MK.602' => 'Brvenica', 'MK.803' => 'Butel', 'MK.815' => 'Cair', 'MK.109' => 'Caska', 'MK.814' => 'Centar', 'MK.313' => 'Centar Zupa', 'MK.210' => 'Cesinovo-Oblesevo', 'MK.816' => 'Cucer Sandevo', 'MK.303' => 'Debar', 'MK.304' => 'Debarca', 'MK.203' => 'Delcevo', 'MK.502' => 'Demir Hisar', 'MK.103' => 'Demir Kapija', 'MK.406' => 'Dojran', 'MK.503' => 'Dolneni', 'MK.804' => 'Gazi Baba', 'MK.405' => 'Gevgelija', 'MK.805' => 'Gjorce Petrov', 'MK.604' => 'Gostivar', 'MK.102' => 'Gradsko', 'MK.807' => 'Ilinden', 'MK.606' => 'Jegunovce', 'MK.205' => 'Karbinci', 'MK.808' => 'Karpos', 'MK.104' => 'Kavadarci', 'MK.307' => 'Kicevo', 'MK.809' => 'Kisela Voda', 'MK.206' => 'Kocani', 'MK.407' => 'Konce', 'MK.701' => 'Kratovo', 'MK.702' => 'Kriva Palanka', 'MK.504' => 'Krivogastani', 'MK.505' => 'Krusevo', 'MK.703' => 'Kumanovo', 'MK.704' => 'Lipkovo', 'MK.105' => 'Lozovo', 'MK.207' => 'Makedonska Kamenica', 'MK.308' => 'Makedonski Brod', 'MK.607' => 'Mavrovo i Rostusa', 'MK.506' => 'Mogila', 'MK.106' => 'Negotino', 'MK.507' => 'Novaci', 'MK.408' => 'Novo Selo', 'MK.310' => 'Ohrid', 'MK.208' => 'Pehcevo', 'MK.810' => 'Petrovec', 'MK.311' => 'Plasnica', 'MK.508' => 'Prilep', 'MK.209' => 'Probistip', 'MK.409' => 'Radovis', 'MK.705' => 'Rankovce', 'MK.509' => 'Resen', 'MK.107' => 'Rosoman', 'MK.811' => 'Saraj', 'MK.812' => 'Sopiste', 'MK.706' => 'Staro Nagoricane', 'MK.211' => 'Stip', 'MK.312' => 'Struga', 'MK.410' => 'Strumica', 'MK.813' => 'Studenicani', 'MK.817' => 'Suto Orizari', 'MK.108' => 'Sveti Nikole', 'MK.608' => 'Tearce', 'MK.609' => 'Tetovo', 'MK.403' => 'Valandovo', 'MK.404' => 'Vasilevo', 'MK.101' => 'Veles', 'MK.301' => 'Vevcani', 'MK.202' => 'Vinica', 'MK.603' => 'Vrapciste', 'MK.806' => 'Zelenikovo', 'MK.605' => 'Zelino', 'MK.204' => 'Zrnovci'],
3134 'ML' => ['ML.BKO' => 'Bamako', 'ML.7' => 'Gao', 'ML.1' => 'Kayes', 'ML.8' => 'Kidal', 'ML.2' => 'Koulikoro', 'ML.9' => 'Menaka', 'ML.5' => 'Mopti', 'ML.4' => 'Segou', 'ML.3' => 'Sikasso', 'ML.10' => 'Taoudenit', 'ML.6' => 'Tombouctou'],
3135 'MM' => ['MM.07' => 'Ayeyarwady', 'MM.02' => 'Bago', 'MM.14' => 'Chin', 'MM.11' => 'Kachin', 'MM.12' => 'Kayah', 'MM.13' => 'Kayin', 'MM.03' => 'Magway', 'MM.04' => 'Mandalay', 'MM.15' => 'Mon', 'MM.18' => 'Nay Pyi Taw', 'MM.16' => 'Rakhine', 'MM.01' => 'Sagaing', 'MM.17' => 'Shan', 'MM.05' => 'Tanintharyi', 'MM.06' => 'Yangon'],
3136 'MN' => ['MN.073' => 'Arhangay', 'MN.071' => 'Bayan-Olgiy', 'MN.069' => 'Bayanhongor', 'MN.067' => 'Bulgan', 'MN.037' => 'Darhan uul', 'MN.061' => 'Dornod', 'MN.063' => 'Dornogovi', 'MN.059' => 'Dundgovi', 'MN.057' => 'Dzavhan', 'MN.065' => 'Govi-Altay', 'MN.064' => 'Govi-Sumber', 'MN.039' => 'Hentiy', 'MN.043' => 'Hovd', 'MN.041' => 'Hovsgol', 'MN.053' => 'Omnogovi', 'MN.035' => 'Orhon', 'MN.055' => 'Ovorhangay', 'MN.049' => 'Selenge', 'MN.051' => 'Suhbaatar', 'MN.047' => 'Tov', 'MN.1' => 'Ulaanbaatar', 'MN.046' => 'Uvs'],
3137 'MR' => ['MR.07' => 'Adrar', 'MR.03' => 'Assaba', 'MR.05' => 'Brakna', 'MR.08' => 'Dakhlet Nouadhibou', 'MR.04' => 'Gorgol', 'MR.10' => 'Guidimaka', 'MR.01' => 'Hodh ech Chargui', 'MR.02' => 'Hodh el Gharbi', 'MR.12' => 'Inchiri', 'MR.13' => 'Nouakchott Ouest', 'MR.15' => 'Nouakchott Sud', 'MR.09' => 'Tagant', 'MR.11' => 'Tiris Zemmour', 'MR.06' => 'Trarza'],
3138 'MT' => ['MT.01' => 'Attard', 'MT.02' => 'Balzan', 'MT.03' => 'Birgu', 'MT.04' => 'Birkirkara', 'MT.05' => 'Birzebbuga', 'MT.06' => 'Bormla', 'MT.07' => 'Dingli', 'MT.08' => 'Fgura', 'MT.09' => 'Floriana', 'MT.10' => 'Fontana', 'MT.13' => 'Ghajnsielem', 'MT.14' => 'Gharb', 'MT.15' => 'Gharghur', 'MT.16' => 'Ghasri', 'MT.17' => 'Ghaxaq', 'MT.11' => 'Gudja', 'MT.12' => 'Gzira', 'MT.18' => 'Hamrun', 'MT.19' => 'Iklin', 'MT.20' => 'Isla', 'MT.21' => 'Kalkara', 'MT.22' => 'Kercem', 'MT.23' => 'Kirkop', 'MT.24' => 'Lija', 'MT.25' => 'Luqa', 'MT.26' => 'Marsa', 'MT.27' => 'Marsaskala', 'MT.28' => 'Marsaxlokk', 'MT.29' => 'Mdina', 'MT.30' => 'Mellieha', 'MT.31' => 'Mgarr', 'MT.32' => 'Mosta', 'MT.33' => 'Mqabba', 'MT.34' => 'Msida', 'MT.35' => 'Mtarfa', 'MT.36' => 'Munxar', 'MT.37' => 'Nadur', 'MT.38' => 'Naxxar', 'MT.39' => 'Paola', 'MT.40' => 'Pembroke', 'MT.41' => 'Pieta', 'MT.42' => 'Qala', 'MT.43' => 'Qormi', 'MT.44' => 'Qrendi', 'MT.45' => 'Rabat Gozo', 'MT.46' => 'Rabat Malta', 'MT.47' => 'Safi', 'MT.49' => 'Saint John', 'MT.48' => 'Saint Julian\'s', 'MT.50' => 'Saint Lawrence', 'MT.53' => 'Saint Lucia\'s', 'MT.51' => 'Saint Paul\'s Bay', 'MT.52' => 'Sannat', 'MT.54' => 'Santa Venera', 'MT.55' => 'Siggiewi', 'MT.56' => 'Sliema', 'MT.57' => 'Swieqi', 'MT.58' => 'Ta\' Xbiex', 'MT.59' => 'Tarxien', 'MT.60' => 'Valletta', 'MT.61' => 'Xaghra', 'MT.62' => 'Xewkija', 'MT.63' => 'Xghajra', 'MT.64' => 'Zabbar', 'MT.65' => 'Zebbug Gozo', 'MT.66' => 'Zebbug Malta', 'MT.67' => 'Zejtun', 'MT.68' => 'Zurrieq'],
3139 'MU' => ['MU.AG' => 'Agalega Islands', 'MU.BL' => 'Black River', 'MU.CC' => 'Cargados Carajos Shoals', 'MU.FL' => 'Flacq', 'MU.GP' => 'Grand Port', 'MU.MO' => 'Moka', 'MU.PA' => 'Pamplemousses', 'MU.PW' => 'Plaines Wilhems', 'MU.PL' => 'Port Louis', 'MU.RR' => 'Riviere du Rempart', 'MU.RO' => 'Rodrigues Islands', 'MU.SA' => 'Savanne'],
3140 'MV' => ['MV.01' => 'Addu City', 'MV.03' => 'Faadhippolhu', 'MV.04' => 'Felidhu Atoll', 'MV.29' => 'Fuvammulah', 'MV.05' => 'Hahdhunmathi', 'MV.08' => 'Kolhumadulu', 'MV.MLE' => 'Male', 'MV.12' => 'Mulaku Atoll', 'MV.02' => 'North Ari Atoll', 'MV.27' => 'North Huvadhu Atoll', 'MV.13' => 'North Maalhosmadulu', 'MV.24' => 'North Miladhunmadulu', 'MV.14' => 'North Nilandhe Atoll', 'MV.07' => 'North Thiladhunmathi', 'MV.00' => 'South Ari Atoll', 'MV.28' => 'South Huvadhu Atoll', 'MV.20' => 'South Maalhosmadulu', 'MV.25' => 'South Miladhunmadulu', 'MV.17' => 'South Nilandhe Atoll', 'MV.23' => 'South Thiladhunmathi'],
3141 'MW' => ['MW.BA' => 'Balaka', 'MW.BL' => 'Blantyre', 'MW.CK' => 'Chikwawa', 'MW.CR' => 'Chiradzulu', 'MW.CT' => 'Chitipa', 'MW.DE' => 'Dedza', 'MW.DO' => 'Dowa', 'MW.KR' => 'Karonga', 'MW.KS' => 'Kasungu', 'MW.LK' => 'Likoma', 'MW.LI' => 'Lilongwe', 'MW.MH' => 'Machinga', 'MW.MG' => 'Mangochi', 'MW.MC' => 'Mchinji', 'MW.MU' => 'Mulanje', 'MW.MW' => 'Mwanza', 'MW.MZ' => 'Mzimba', 'MW.NE' => 'Neno', 'MW.NB' => 'Nkhata Bay', 'MW.NK' => 'Nkhotakota', 'MW.NS' => 'Nsanje', 'MW.NU' => 'Ntcheu', 'MW.NI' => 'Ntchisi', 'MW.PH' => 'Phalombe', 'MW.RU' => 'Rumphi', 'MW.SA' => 'Salima', 'MW.TH' => 'Thyolo', 'MW.ZO' => 'Zomba'],
3142 'MX' => ['MX.AGU' => 'Aguascalientes', 'MX.BCN' => 'Baja California', 'MX.BCS' => 'Baja California Sur', 'MX.CAM' => 'Campeche', 'MX.CHP' => 'Chiapas', 'MX.CHH' => 'Chihuahua', 'MX.CMX' => 'Ciudad de Mexico', 'MX.COA' => 'Coahuila de Zaragoza', 'MX.COL' => 'Colima', 'MX.DUR' => 'Durango', 'MX.GUA' => 'Guanajuato', 'MX.GRO' => 'Guerrero', 'MX.HID' => 'Hidalgo', 'MX.JAL' => 'Jalisco', 'MX.MEX' => 'Mexico', 'MX.MIC' => 'Michoacan de Ocampo', 'MX.MOR' => 'Morelos', 'MX.NAY' => 'Nayarit', 'MX.NLE' => 'Nuevo Leon', 'MX.OAX' => 'Oaxaca', 'MX.PUE' => 'Puebla', 'MX.QUE' => 'Queretaro', 'MX.ROO' => 'Quintana Roo', 'MX.SLP' => 'San Luis Potosi', 'MX.SIN' => 'Sinaloa', 'MX.SON' => 'Sonora', 'MX.TAB' => 'Tabasco', 'MX.TAM' => 'Tamaulipas', 'MX.TLA' => 'Tlaxcala', 'MX.VER' => 'Veracruz de Ignacio de la Llave', 'MX.YUC' => 'Yucatan', 'MX.ZAC' => 'Zacatecas'],
3143 'MY' => ['MY.01' => 'Johor', 'MY.02' => 'Kedah', 'MY.03' => 'Kelantan', 'MY.04' => 'Melaka', 'MY.05' => 'Negeri Sembilan', 'MY.06' => 'Pahang', 'MY.08' => 'Perak', 'MY.09' => 'Perlis', 'MY.07' => 'Pulau Pinang', 'MY.12' => 'Sabah', 'MY.13' => 'Sarawak', 'MY.10' => 'Selangor', 'MY.11' => 'Terengganu', 'MY.14' => 'Wilayah Persekutuan Kuala Lumpur', 'MY.15' => 'Wilayah Persekutuan Labuan', 'MY.16' => 'Wilayah Persekutuan Putrajaya'],
3144 'MZ' => ['MZ.P' => 'Cabo Delgado', 'MZ.G' => 'Gaza', 'MZ.I' => 'Inhambane', 'MZ.B' => 'Manica', 'MZ.L' => 'Maputo', 'MZ.N' => 'Nampula', 'MZ.A' => 'Niassa', 'MZ.S' => 'Sofala', 'MZ.T' => 'Tete', 'MZ.Q' => 'Zambezia'],
3145 'NA' => ['NA.ER' => 'Erongo', 'NA.HA' => 'Hardap', 'NA.KA' => 'Karas', 'NA.KE' => 'Kavango East', 'NA.KW' => 'Kavango West', 'NA.KH' => 'Khomas', 'NA.KU' => 'Kunene', 'NA.OW' => 'Ohangwena', 'NA.OH' => 'Omaheke', 'NA.OS' => 'Omusati', 'NA.ON' => 'Oshana', 'NA.OT' => 'Oshikoto', 'NA.OD' => 'Otjozondjupa', 'NA.CA' => 'Zambezi'],
3146 'NE' => ['NE.1' => 'Agadez', 'NE.2' => 'Diffa', 'NE.3' => 'Dosso', 'NE.4' => 'Maradi', 'NE.8' => 'Niamey', 'NE.5' => 'Tahoua', 'NE.6' => 'Tillaberi', 'NE.7' => 'Zinder'],
3147 'NG' => ['NG.AB' => 'Abia', 'NG.FC' => 'Abuja Federal Capital Territory', 'NG.AD' => 'Adamawa', 'NG.AK' => 'Akwa Ibom', 'NG.AN' => 'Anambra', 'NG.BA' => 'Bauchi', 'NG.BY' => 'Bayelsa', 'NG.BE' => 'Benue', 'NG.BO' => 'Borno', 'NG.CR' => 'Cross River', 'NG.DE' => 'Delta', 'NG.EB' => 'Ebonyi', 'NG.ED' => 'Edo', 'NG.EK' => 'Ekiti', 'NG.EN' => 'Enugu', 'NG.GO' => 'Gombe', 'NG.IM' => 'Imo', 'NG.JI' => 'Jigawa', 'NG.KD' => 'Kaduna', 'NG.KN' => 'Kano', 'NG.KT' => 'Katsina', 'NG.KE' => 'Kebbi', 'NG.KO' => 'Kogi', 'NG.KW' => 'Kwara', 'NG.LA' => 'Lagos', 'NG.NA' => 'Nasarawa', 'NG.NI' => 'Niger', 'NG.OG' => 'Ogun', 'NG.ON' => 'Ondo', 'NG.OS' => 'Osun', 'NG.OY' => 'Oyo', 'NG.PL' => 'Plateau', 'NG.RI' => 'Rivers', 'NG.SO' => 'Sokoto', 'NG.TA' => 'Taraba', 'NG.YO' => 'Yobe', 'NG.ZA' => 'Zamfara'],
3148 'NI' => ['NI.BO' => 'Boaco', 'NI.CA' => 'Carazo', 'NI.CI' => 'Chinandega', 'NI.CO' => 'Chontales', 'NI.AN' => 'Costa Caribe Norte', 'NI.AS' => 'Costa Caribe Sur', 'NI.ES' => 'Esteli', 'NI.GR' => 'Granada', 'NI.JI' => 'Jinotega', 'NI.LE' => 'Leon', 'NI.MD' => 'Madriz', 'NI.MN' => 'Managua', 'NI.MS' => 'Masaya', 'NI.MT' => 'Matagalpa', 'NI.NS' => 'Nueva Segovia', 'NI.SJ' => 'Rio San Juan', 'NI.RI' => 'Rivas'],
3149 'NL' => ['NL.DR' => 'Drenthe', 'NL.FL' => 'Flevoland', 'NL.FR' => 'Fryslan', 'NL.GE' => 'Gelderland', 'NL.GR' => 'Groningen', 'NL.LI' => 'Limburg', 'NL.NB' => 'Noord-Brabant', 'NL.NH' => 'Noord-Holland', 'NL.OV' => 'Overijssel', 'NL.UT' => 'Utrecht', 'NL.ZE' => 'Zeeland', 'NL.ZH' => 'Zuid-Holland'],
3150 'NO' => ['NO.42' => 'Agder', 'NO.34' => 'Innlandet', 'NO.22' => 'Jan Mayen (Arctic Region)', 'NO.15' => 'More og Romsdal', 'NO.18' => 'Nordland', 'NO.03' => 'Oslo', 'NO.11' => 'Rogaland', 'NO.21' => 'Svalbard (Arctic Region)', 'NO.50' => 'Troendelag', 'NO.54' => 'Troms og Finnmark', 'NO.50' => 'Trondelag', 'NO.38' => 'Vestfold og Telemark', 'NO.46' => 'Vestland', 'NO.30' => 'Viken'],
3151 'NP' => ['NP.BA' => 'Bagmati', 'NP.BH' => 'Bheri', 'NP.DH' => 'Dhawalagiri', 'NP.GA' => 'Gandaki', 'NP.JA' => 'Janakpur', 'NP.KA' => 'Karnali', 'NP.KO' => 'Kosi', 'NP.LU' => 'Lumbini', 'NP.MA' => 'Mahakali', 'NP.ME' => 'Mechi', 'NP.NA' => 'Narayani', 'NP.RA' => 'Rapti', 'NP.SA' => 'Sagarmatha', 'NP.SE' => 'Seti'],
3152 'NR' => ['NR.01' => 'Aiwo', 'NR.02' => 'Anabar', 'NR.03' => 'Anetan', 'NR.04' => 'Anibare', 'NR.05' => 'Baitsi', 'NR.06' => 'Boe', 'NR.07' => 'Buada', 'NR.08' => 'Denigomodu', 'NR.09' => 'Ewa', 'NR.10' => 'Ijuw', 'NR.11' => 'Meneng', 'NR.12' => 'Nibok', 'NR.13' => 'Uaboe', 'NR.14' => 'Yaren'],
3153 'NZ' => ['NZ.AUK' => 'Auckland', 'NZ.BOP' => 'Bay of Plenty', 'NZ.CAN' => 'Canterbury', 'NZ.CIT' => 'Chatham Islands Territory', 'NZ.GIS' => 'Gisborne', 'NZ.HKB' => 'Hawke\'s Bay', 'NZ.MWT' => 'Manawatu-Wanganui', 'NZ.MBH' => 'Marlborough', 'NZ.NSN' => 'Nelson', 'NZ.NTL' => 'Northland', 'NZ.OTA' => 'Otago', 'NZ.STL' => 'Southland', 'NZ.TKI' => 'Taranaki', 'NZ.TAS' => 'Tasman', 'NZ.WKO' => 'Waikato', 'NZ.WGN' => 'Wellington', 'NZ.WTC' => 'West Coast'],
3154 'OM' => ['OM.DA' => 'Ad Dakhiliyah', 'OM.BU' => 'Al Buraymi', 'OM.WU' => 'Al Wusta', 'OM.ZA' => 'Az Zahirah', 'OM.BJ' => 'Janub al Batinah', 'OM.SJ' => 'Janub ash Sharqiyah', 'OM.MA' => 'Masqat', 'OM.MU' => 'Musandam', 'OM.BS' => 'Shamal al Batinah', 'OM.SS' => 'Shamal ash Sharqiyah', 'OM.ZU' => 'Zufar'],
3155 'PA' => ['PA.1' => 'Bocas del Toro', 'PA.4' => 'Chiriqui', 'PA.2' => 'Cocle', 'PA.3' => 'Colon', 'PA.5' => 'Darien', 'PA.EM' => 'Embera', 'PA.KY' => 'Guna Yala', 'PA.6' => 'Herrera', 'PA.7' => 'Los Santos', 'PA.NT' => 'Naso Tjer Di', 'PA.NB' => 'Ngobe-Bugle', 'PA.8' => 'Panama', 'PA.10' => 'Panama Oeste', 'PA.9' => 'Veraguas'],
3156 'PE' => ['PE.AMA' => 'Amazonas', 'PE.ANC' => 'Ancash', 'PE.APU' => 'Apurimac', 'PE.ARE' => 'Arequipa', 'PE.AYA' => 'Ayacucho', 'PE.CAJ' => 'Cajamarca', 'PE.CUS' => 'Cusco', 'PE.CAL' => 'El Callao', 'PE.HUV' => 'Huancavelica', 'PE.HUC' => 'Huanuco', 'PE.ICA' => 'Ica', 'PE.JUN' => 'Junin', 'PE.LAL' => 'La Libertad', 'PE.LAM' => 'Lambayeque', 'PE.LIM' => 'Lima', 'PE.LOR' => 'Loreto', 'PE.MDD' => 'Madre de Dios', 'PE.MOQ' => 'Moquegua', 'PE.PAS' => 'Pasco', 'PE.PIU' => 'Piura', 'PE.PUN' => 'Puno', 'PE.SAM' => 'San Martin', 'PE.TAC' => 'Tacna', 'PE.TUM' => 'Tumbes', 'PE.UCA' => 'Ucayali'],
3157 'PG' => ['PG.NSB' => 'Bougainville', 'PG.CPM' => 'Central', 'PG.CPK' => 'Chimbu', 'PG.EBR' => 'East New Britain', 'PG.ESW' => 'East Sepik', 'PG.EHG' => 'Eastern Highlands', 'PG.EPW' => 'Enga', 'PG.GPK' => 'Gulf', 'PG.HLA' => 'Hela', 'PG.JWK' => 'Jiwaka', 'PG.MPM' => 'Madang', 'PG.MRL' => 'Manus', 'PG.MBA' => 'Milne Bay', 'PG.MPL' => 'Morobe', 'PG.NCD' => 'National Capital District (Port Moresby)', 'PG.NIK' => 'New Ireland', 'PG.NPP' => 'Northern', 'PG.SHM' => 'Southern Highlands', 'PG.WBK' => 'West New Britain', 'PG.SAN' => 'West Sepik', 'PG.WPD' => 'Western', 'PG.WHM' => 'Western Highlands'],
3158 'PH' => ['PH.ABR' => 'Abra', 'PH.AGN' => 'Agusan del Norte', 'PH.AGS' => 'Agusan del Sur', 'PH.AKL' => 'Aklan', 'PH.ALB' => 'Albay', 'PH.ANT' => 'Antique', 'PH.APA' => 'Apayao', 'PH.AUR' => 'Aurora', 'PH.BAS' => 'Basilan', 'PH.BAN' => 'Bataan', 'PH.BTN' => 'Batanes', 'PH.BTG' => 'Batangas', 'PH.BEN' => 'Benguet', 'PH.BIL' => 'Biliran', 'PH.BOH' => 'Bohol', 'PH.BUK' => 'Bukidnon', 'PH.BUL' => 'Bulacan', 'PH.CAG' => 'Cagayan', 'PH.CAN' => 'Camarines Norte', 'PH.CAS' => 'Camarines Sur', 'PH.CAM' => 'Camiguin', 'PH.CAP' => 'Capiz', 'PH.CAT' => 'Catanduanes', 'PH.CAV' => 'Cavite', 'PH.CEB' => 'Cebu', 'PH.NCO' => 'Cotabato', 'PH.DVO' => 'Davao Occidental', 'PH.DAO' => 'Davao Oriental', 'PH.COM' => 'Davao de Oro', 'PH.DAV' => 'Davao del Norte', 'PH.DAS' => 'Davao del Sur', 'PH.DIN' => 'Dinagat Islands', 'PH.EAS' => 'Eastern Samar', 'PH.GUI' => 'Guimaras', 'PH.IFU' => 'Ifugao', 'PH.ILN' => 'Ilocos Norte', 'PH.ILS' => 'Ilocos Sur', 'PH.ILI' => 'Iloilo', 'PH.ISA' => 'Isabela', 'PH.KAL' => 'Kalinga', 'PH.LUN' => 'La Union', 'PH.LAG' => 'Laguna', 'PH.LAN' => 'Lanao del Norte', 'PH.LAS' => 'Lanao del Sur', 'PH.LEY' => 'Leyte', 'PH.MAG' => 'Maguindanao', 'PH.MAD' => 'Marinduque', 'PH.MAS' => 'Masbate', 'PH.MDC' => 'Mindoro Occidental', 'PH.MDR' => 'Mindoro Oriental', 'PH.MSC' => 'Misamis Occidental', 'PH.MSR' => 'Misamis Oriental', 'PH.MOU' => 'Mountain Province', 'PH.00' => 'National Capital Region', 'PH.NEC' => 'Negros Occidental', 'PH.NER' => 'Negros Oriental', 'PH.NSA' => 'Northern Samar', 'PH.NUE' => 'Nueva Ecija', 'PH.NUV' => 'Nueva Vizcaya', 'PH.PLW' => 'Palawan', 'PH.PAM' => 'Pampanga', 'PH.PAN' => 'Pangasinan', 'PH.QUE' => 'Quezon', 'PH.QUI' => 'Quirino', 'PH.RIZ' => 'Rizal', 'PH.ROM' => 'Romblon', 'PH.WSA' => 'Samar', 'PH.SAR' => 'Sarangani', 'PH.SIG' => 'Siquijor', 'PH.SOR' => 'Sorsogon', 'PH.SCO' => 'South Cotabato', 'PH.SLE' => 'Southern Leyte', 'PH.SUK' => 'Sultan Kudarat', 'PH.SLU' => 'Sulu', 'PH.SUN' => 'Surigao del Norte', 'PH.SUR' => 'Surigao del Sur', 'PH.TAR' => 'Tarlac', 'PH.TAW' => 'Tawi-Tawi', 'PH.ZMB' => 'Zambales', 'PH.ZSI' => 'Zamboanga Sibugay', 'PH.ZAN' => 'Zamboanga del Norte', 'PH.ZAS' => 'Zamboanga del Sur'],
3159 'PK' => ['PK.JK' => 'Azad Jammu and Kashmir', 'PK.BA' => 'Balochistan', 'PK.GB' => 'Gilgit-Baltistan', 'PK.IS' => 'Islamabad', 'PK.KP' => 'Khyber Pakhtunkhwa', 'PK.PB' => 'Punjab', 'PK.SD' => 'Sindh'],
3160 'PL' => ['PL.02' => 'Dolnoslaskie', 'PL.04' => 'Kujawsko-pomorskie', 'PL.10' => 'Lodzkie', 'PL.06' => 'Lubelskie', 'PL.08' => 'Lubuskie', 'PL.12' => 'Malopolskie', 'PL.14' => 'Mazowieckie', 'PL.16' => 'Opolskie', 'PL.18' => 'Podkarpackie', 'PL.20' => 'Podlaskie', 'PL.22' => 'Pomorskie', 'PL.24' => 'Slaskie', 'PL.26' => 'Swietokrzyskie', 'PL.28' => 'Warminsko-mazurskie', 'PL.30' => 'Wielkopolskie', 'PL.32' => 'Zachodniopomorskie'],
3161 'PS' => ['PS.BTH' => 'Bethlehem', 'PS.DEB' => 'Deir El Balah', 'PS.GZA' => 'Gaza', 'PS.HBN' => 'Hebron', 'PS.JEN' => 'Jenin', 'PS.JRH' => 'Jericho and Al Aghwar', 'PS.JEM' => 'Jerusalem', 'PS.KYS' => 'Khan Yunis', 'PS.NBS' => 'Nablus', 'PS.NGZ' => 'North Gaza', 'PS.QQA' => 'Qalqilya', 'PS.RFH' => 'Rafah', 'PS.RBH' => 'Ramallah', 'PS.SLT' => 'Salfit', 'PS.TBS' => 'Tubas', 'PS.TKM' => 'Tulkarm'],
3162 'PT' => ['PT.01' => 'Aveiro', 'PT.02' => 'Beja', 'PT.03' => 'Braga', 'PT.04' => 'Braganca', 'PT.05' => 'Castelo Branco', 'PT.06' => 'Coimbra', 'PT.07' => 'Evora', 'PT.08' => 'Faro', 'PT.09' => 'Guarda', 'PT.10' => 'Leiria', 'PT.11' => 'Lisboa', 'PT.12' => 'Portalegre', 'PT.13' => 'Porto', 'PT.30' => 'Regiao Autonoma da Madeira', 'PT.20' => 'Regiao Autonoma dos Acores', 'PT.14' => 'Santarem', 'PT.15' => 'Setubal', 'PT.16' => 'Viana do Castelo', 'PT.17' => 'Vila Real', 'PT.18' => 'Viseu'],
3163 'PW' => ['PW.002' => 'Aimeliik', 'PW.004' => 'Airai', 'PW.010' => 'Angaur', 'PW.050' => 'Hatohobei', 'PW.100' => 'Kayangel', 'PW.150' => 'Koror', 'PW.212' => 'Melekeok', 'PW.214' => 'Ngaraard', 'PW.218' => 'Ngarchelong', 'PW.222' => 'Ngardmau', 'PW.224' => 'Ngatpang', 'PW.226' => 'Ngchesar', 'PW.227' => 'Ngeremlengui', 'PW.228' => 'Ngiwal', 'PW.350' => 'Peleliu', 'PW.370' => 'Sonsorol'],
3164 'PY' => ['PY.16' => 'Alto Paraguay', 'PY.10' => 'Alto Parana', 'PY.13' => 'Amambay', 'PY.ASU' => 'Asuncion', 'PY.19' => 'Boqueron', 'PY.5' => 'Caaguazu', 'PY.6' => 'Caazapa', 'PY.14' => 'Canindeyu', 'PY.11' => 'Central', 'PY.1' => 'Concepcion', 'PY.3' => 'Cordillera', 'PY.4' => 'Guaira', 'PY.7' => 'Itapua', 'PY.8' => 'Misiones', 'PY.12' => 'Neembucu', 'PY.9' => 'Paraguari', 'PY.15' => 'Presidente Hayes', 'PY.2' => 'San Pedro'],
3165 'QA' => ['QA.DA' => 'Ad Dawhah', 'QA.KH' => 'Al Khawr wa adh Dhakhirah', 'QA.WA' => 'Al Wakrah', 'QA.RA' => 'Ar Rayyan', 'QA.MS' => 'Ash Shamal', 'QA.SH' => 'Ash Shihaniyah', 'QA.ZA' => 'Az Za\'ayin', 'QA.US' => 'Umm Salal'],
3166 'RO' => ['RO.AB' => 'Alba', 'RO.AR' => 'Arad', 'RO.AG' => 'Arges', 'RO.BC' => 'Bacau', 'RO.BH' => 'Bihor', 'RO.BN' => 'Bistrita-Nasaud', 'RO.BT' => 'Botosani', 'RO.BR' => 'Braila', 'RO.BV' => 'Brasov', 'RO.B' => 'Bucuresti', 'RO.BZ' => 'Buzau', 'RO.CL' => 'Calarasi', 'RO.CS' => 'Caras-Severin', 'RO.CJ' => 'Cluj', 'RO.CT' => 'Constanta', 'RO.CV' => 'Covasna', 'RO.DB' => 'Dambovita', 'RO.DJ' => 'Dolj', 'RO.GL' => 'Galati', 'RO.GR' => 'Giurgiu', 'RO.GJ' => 'Gorj', 'RO.HR' => 'Harghita', 'RO.HD' => 'Hunedoara', 'RO.IL' => 'Ialomita', 'RO.IS' => 'Iasi', 'RO.IF' => 'Ilfov', 'RO.MM' => 'Maramures', 'RO.MH' => 'Mehedinti', 'RO.MS' => 'Mures', 'RO.NT' => 'Neamt', 'RO.OT' => 'Olt', 'RO.PH' => 'Prahova', 'RO.SJ' => 'Salaj', 'RO.SM' => 'Satu Mare', 'RO.SB' => 'Sibiu', 'RO.SV' => 'Suceava', 'RO.TR' => 'Teleorman', 'RO.TM' => 'Timis', 'RO.TL' => 'Tulcea', 'RO.VL' => 'Valcea', 'RO.VS' => 'Vaslui', 'RO.VN' => 'Vrancea'],
3167 'RS' => ['RS.00' => 'Beograd', 'RS.14' => 'Borski okrug', 'RS.11' => 'Branicevski okrug', 'RS.23' => 'Jablanicki okrug', 'RS.06' => 'Juznobacki okrug', 'RS.04' => 'Juznobanatski okrug', 'RS.09' => 'Kolubarski okrug', 'RS.25' => 'Kosovski okrug', 'RS.28' => 'Kosovsko-Mitrovacki okrug', 'RS.29' => 'Kosovsko-Pomoravski okrug', 'RS.08' => 'Macvanski okrug', 'RS.17' => 'Moravicki okrug', 'RS.20' => 'Nisavski okrug', 'RS.24' => 'Pcinjski okrug', 'RS.26' => 'Pecki okrug', 'RS.22' => 'Pirotski okrug', 'RS.10' => 'Podunavski okrug', 'RS.13' => 'Pomoravski okrug', 'RS.27' => 'Prizrenski okrug', 'RS.19' => 'Rasinski okrug', 'RS.18' => 'Raski okrug', 'RS.01' => 'Severnobacki okrug', 'RS.03' => 'Severnobanatski okrug', 'RS.02' => 'Srednjebanatski okrug', 'RS.07' => 'Sremski okrug', 'RS.12' => 'Sumadijski okrug', 'RS.21' => 'Toplicki okrug', 'RS.15' => 'Zajecarski okrug', 'RS.05' => 'Zapadnobacki okrug', 'RS.16' => 'Zlatiborski okrug'],
3168 'RU' => ['RU.AD' => 'Adygeya, Respublika', 'RU.AL' => 'Altay, Respublika', 'RU.ALT' => 'Altayskiy kray', 'RU.AMU' => 'Amurskaya oblast\'', 'RU.ARK' => 'Arkhangel\'skaya oblast\'', 'RU.AST' => 'Astrakhanskaya oblast\'', 'RU.BA' => 'Bashkortostan, Respublika', 'RU.BEL' => 'Belgorodskaya oblast\'', 'RU.BRY' => 'Bryanskaya oblast\'', 'RU.BU' => 'Buryatiya, Respublika', 'RU.CE' => 'Chechenskaya Respublika', 'RU.CHE' => 'Chelyabinskaya oblast\'', 'RU.CHU' => 'Chukotskiy avtonomnyy okrug', 'RU.CU' => 'Chuvashskaya Respublika', 'RU.DA' => 'Dagestan, Respublika', 'RU.IN' => 'Ingushetiya, Respublika', 'RU.IRK' => 'Irkutskaya oblast\'', 'RU.IVA' => 'Ivanovskaya oblast\'', 'RU.KB' => 'Kabardino-Balkarskaya Respublika', 'RU.KGD' => 'Kaliningradskaya oblast\'', 'RU.KL' => 'Kalmykiya, Respublika', 'RU.KLU' => 'Kaluzhskaya oblast\'', 'RU.KAM' => 'Kamchatskiy kray', 'RU.KC' => 'Karachayevo-Cherkesskaya Respublika', 'RU.KR' => 'Kareliya, Respublika', 'RU.KEM' => 'Kemerovskaya oblast\'', 'RU.KHA' => 'Khabarovskiy kray', 'RU.KK' => 'Khakasiya, Respublika', 'RU.KHM' => 'Khanty-Mansiyskiy avtonomnyy okrug', 'RU.KIR' => 'Kirovskaya oblast\'', 'RU.KO' => 'Komi, Respublika', 'RU.KOS' => 'Kostromskaya oblast\'', 'RU.KDA' => 'Krasnodarskiy kray', 'RU.KYA' => 'Krasnoyarskiy kray', 'RU.KGN' => 'Kurganskaya oblast\'', 'RU.KRS' => 'Kurskaya oblast\'', 'RU.LEN' => 'Leningradskaya oblast\'', 'RU.LIP' => 'Lipetskaya oblast\'', 'RU.MAG' => 'Magadanskaya oblast\'', 'RU.ME' => 'Mariy El, Respublika', 'RU.MO' => 'Mordoviya, Respublika', 'RU.MOS' => 'Moskovskaya oblast\'', 'RU.MOW' => 'Moskva', 'RU.MUR' => 'Murmanskaya oblast\'', 'RU.NEN' => 'Nenetskiy avtonomnyy okrug', 'RU.NIZ' => 'Nizhegorodskaya oblast\'', 'RU.NGR' => 'Novgorodskaya oblast\'', 'RU.NVS' => 'Novosibirskaya oblast\'', 'RU.OMS' => 'Omskaya oblast\'', 'RU.ORE' => 'Orenburgskaya oblast\'', 'RU.ORL' => 'Orlovskaya oblast\'', 'RU.PNZ' => 'Penzenskaya oblast\'', 'RU.PER' => 'Permskiy kray', 'RU.PRI' => 'Primorskiy kray', 'RU.PSK' => 'Pskovskaya oblast\'', 'RU.ROS' => 'Rostovskaya oblast\'', 'RU.RYA' => 'Ryazanskaya oblast\'', 'RU.SA' => 'Saha, Respublika', 'RU.SAK' => 'Sakhalinskaya oblast\'', 'RU.SAM' => 'Samarskaya oblast\'', 'RU.SPE' => 'Sankt-Peterburg', 'RU.SAR' => 'Saratovskaya oblast\'', 'RU.SE' => 'Severnaya Osetiya, Respublika', 'RU.SMO' => 'Smolenskaya oblast\'', 'RU.STA' => 'Stavropol\'skiy kray', 'RU.SVE' => 'Sverdlovskaya oblast\'', 'RU.TAM' => 'Tambovskaya oblast\'', 'RU.TA' => 'Tatarstan, Respublika', 'RU.TOM' => 'Tomskaya oblast\'', 'RU.TUL' => 'Tul\'skaya oblast\'', 'RU.TVE' => 'Tverskaya oblast\'', 'RU.TYU' => 'Tyumenskaya oblast\'', 'RU.TY' => 'Tyva, Respublika', 'RU.UD' => 'Udmurtskaya Respublika', 'RU.ULY' => 'Ul\'yanovskaya oblast\'', 'RU.VLA' => 'Vladimirskaya oblast\'', 'RU.VGG' => 'Volgogradskaya oblast\'', 'RU.VLG' => 'Vologodskaya oblast\'', 'RU.VOR' => 'Voronezhskaya oblast\'', 'RU.YAN' => 'Yamalo-Nenetskiy avtonomnyy okrug', 'RU.YAR' => 'Yaroslavskaya oblast\'', 'RU.YEV' => 'Yevreyskaya avtonomnaya oblast\'', 'RU.ZAB' => 'Zabaykal\'skiy kray'],
3169 'RW' => ['RW.02' => 'Est', 'RW.03' => 'Nord', 'RW.04' => 'Ouest', 'RW.05' => 'Sud', 'RW.01' => 'Ville de Kigali'],
3170 'SA' => ['SA.14' => '\'Asir', 'SA.11' => 'Al Bahah', 'SA.08' => 'Al Hudud ash Shamaliyah', 'SA.12' => 'Al Jawf', 'SA.03' => 'Al Madinah al Munawwarah', 'SA.05' => 'Al Qasim', 'SA.01' => 'Ar Riyad', 'SA.04' => 'Ash Sharqiyah', 'SA.06' => 'Ha\'il', 'SA.09' => 'Jazan', 'SA.02' => 'Makkah al Mukarramah', 'SA.10' => 'Najran', 'SA.07' => 'Tabuk'],
3171 'SB' => ['SB.CT' => 'Capital Territory (Honiara)', 'SB.CE' => 'Central', 'SB.CH' => 'Choiseul', 'SB.GU' => 'Guadalcanal', 'SB.IS' => 'Isabel', 'SB.MK' => 'Makira-Ulawa', 'SB.ML' => 'Malaita', 'SB.RB' => 'Rennell and Bellona', 'SB.TE' => 'Temotu', 'SB.WE' => 'Western'],
3172 'SC' => ['SC.02' => 'Anse Boileau', 'SC.03' => 'Anse Etoile', 'SC.05' => 'Anse Royale', 'SC.01' => 'Anse aux Pins', 'SC.04' => 'Au Cap', 'SC.06' => 'Baie Lazare', 'SC.07' => 'Baie Sainte Anne', 'SC.08' => 'Beau Vallon', 'SC.09' => 'Bel Air', 'SC.10' => 'Bel Ombre', 'SC.11' => 'Cascade', 'SC.16' => 'English River', 'SC.12' => 'Glacis', 'SC.13' => 'Grand Anse Mahe', 'SC.14' => 'Grand Anse Praslin', 'SC.26' => 'Ile Perseverance I', 'SC.27' => 'Ile Perseverance II', 'SC.15' => 'La Digue', 'SC.24' => 'Les Mamelles', 'SC.17' => 'Mont Buxton', 'SC.18' => 'Mont Fleuri', 'SC.19' => 'Plaisance', 'SC.20' => 'Pointe Larue', 'SC.21' => 'Port Glaud', 'SC.25' => 'Roche Caiman', 'SC.22' => 'Saint Louis', 'SC.23' => 'Takamaka'],
3173 'SD' => ['SD.NB' => 'Blue Nile', 'SD.DC' => 'Central Darfur', 'SD.DE' => 'East Darfur', 'SD.GD' => 'Gedaref', 'SD.GZ' => 'Gezira', 'SD.KA' => 'Kassala', 'SD.KH' => 'Khartoum', 'SD.DN' => 'North Darfur', 'SD.KN' => 'North Kordofan', 'SD.NO' => 'Northern', 'SD.RS' => 'Red Sea', 'SD.NR' => 'River Nile', 'SD.SI' => 'Sennar', 'SD.DS' => 'South Darfur', 'SD.KS' => 'South Kordofan', 'SD.DW' => 'West Darfur', 'SD.GK' => 'West Kordofan', 'SD.NW' => 'White Nile'],
3174 'SE' => ['SE.K' => 'Blekinge lan', 'SE.W' => 'Dalarnas lan', 'SE.X' => 'Gavleborgs lan', 'SE.I' => 'Gotlands lan', 'SE.N' => 'Hallands lan', 'SE.Z' => 'Jamtlands lan', 'SE.F' => 'Jonkopings lan', 'SE.H' => 'Kalmar lan', 'SE.G' => 'Kronobergs lan', 'SE.BD' => 'Norrbottens lan', 'SE.T' => 'Orebro lan', 'SE.E' => 'Ostergotlands lan', 'SE.M' => 'Skane lan', 'SE.D' => 'Sodermanlands lan', 'SE.AB' => 'Stockholms lan', 'SE.C' => 'Uppsala lan', 'SE.S' => 'Varmlands lan', 'SE.AC' => 'Vasterbottens lan', 'SE.Y' => 'Vasternorrlands lan', 'SE.U' => 'Vastmanlands lan', 'SE.O' => 'Vastra Gotalands lan'],
3175 'SH' => ['SH.AC' => 'Ascension', 'SH.HL' => 'Saint Helena', 'SH.TA' => 'Tristan da Cunha'],
3176 'SI' => ['SI.001' => 'Ajdovscina', 'SI.213' => 'Ankaran', 'SI.195' => 'Apace', 'SI.002' => 'Beltinci', 'SI.148' => 'Benedikt', 'SI.149' => 'Bistrica ob Sotli', 'SI.003' => 'Bled', 'SI.150' => 'Bloke', 'SI.004' => 'Bohinj', 'SI.005' => 'Borovnica', 'SI.006' => 'Bovec', 'SI.151' => 'Braslovce', 'SI.007' => 'Brda', 'SI.009' => 'Brezice', 'SI.008' => 'Brezovica', 'SI.152' => 'Cankova', 'SI.011' => 'Celje', 'SI.012' => 'Cerklje na Gorenjskem', 'SI.013' => 'Cerknica', 'SI.014' => 'Cerkno', 'SI.153' => 'Cerkvenjak', 'SI.196' => 'Cirkulane', 'SI.015' => 'Crensovci', 'SI.016' => 'Crna na Koroskem', 'SI.017' => 'Crnomelj', 'SI.018' => 'Destrnik', 'SI.019' => 'Divaca', 'SI.154' => 'Dobje', 'SI.020' => 'Dobrepolje', 'SI.155' => 'Dobrna', 'SI.021' => 'Dobrova-Polhov Gradec', 'SI.156' => 'Dobrovnik', 'SI.022' => 'Dol pri Ljubljani', 'SI.157' => 'Dolenjske Toplice', 'SI.023' => 'Domzale', 'SI.024' => 'Dornava', 'SI.025' => 'Dravograd', 'SI.026' => 'Duplek', 'SI.027' => 'Gorenja vas-Poljane', 'SI.028' => 'Gorisnica', 'SI.207' => 'Gorje', 'SI.029' => 'Gornja Radgona', 'SI.030' => 'Gornji Grad', 'SI.031' => 'Gornji Petrovci', 'SI.158' => 'Grad', 'SI.032' => 'Grosuplje', 'SI.159' => 'Hajdina', 'SI.160' => 'Hoce-Slivnica', 'SI.161' => 'Hodos', 'SI.162' => 'Horjul', 'SI.034' => 'Hrastnik', 'SI.035' => 'Hrpelje-Kozina', 'SI.036' => 'Idrija', 'SI.037' => 'Ig', 'SI.038' => 'Ilirska Bistrica', 'SI.039' => 'Ivancna Gorica', 'SI.040' => 'Izola', 'SI.041' => 'Jesenice', 'SI.163' => 'Jezersko', 'SI.042' => 'Jursinci', 'SI.043' => 'Kamnik', 'SI.044' => 'Kanal', 'SI.045' => 'Kidricevo', 'SI.046' => 'Kobarid', 'SI.047' => 'Kobilje', 'SI.048' => 'Kocevje', 'SI.049' => 'Komen', 'SI.164' => 'Komenda', 'SI.050' => 'Koper', 'SI.197' => 'Kosanjevica na Krki', 'SI.165' => 'Kostel', 'SI.051' => 'Kozje', 'SI.052' => 'Kranj', 'SI.053' => 'Kranjska Gora', 'SI.166' => 'Krizevci', 'SI.054' => 'Krsko', 'SI.055' => 'Kungota', 'SI.056' => 'Kuzma', 'SI.057' => 'Lasko', 'SI.058' => 'Lenart', 'SI.059' => 'Lendava', 'SI.060' => 'Litija', 'SI.061' => 'Ljubljana', 'SI.062' => 'Ljubno', 'SI.063' => 'Ljutomer', 'SI.208' => 'Log-Dragomer', 'SI.064' => 'Logatec', 'SI.065' => 'Loska dolina', 'SI.066' => 'Loski Potok', 'SI.167' => 'Lovrenc na Pohorju', 'SI.067' => 'Luce', 'SI.068' => 'Lukovica', 'SI.069' => 'Majsperk', 'SI.198' => 'Makole', 'SI.070' => 'Maribor', 'SI.168' => 'Markovci', 'SI.071' => 'Medvode', 'SI.072' => 'Menges', 'SI.073' => 'Metlika', 'SI.074' => 'Mezica', 'SI.169' => 'Miklavz na Dravskem polju', 'SI.075' => 'Miren-Kostanjevica', 'SI.212' => 'Mirna', 'SI.170' => 'Mirna Pec', 'SI.076' => 'Mislinja', 'SI.199' => 'Mokronog-Trebelno', 'SI.077' => 'Moravce', 'SI.078' => 'Moravske Toplice', 'SI.079' => 'Mozirje', 'SI.080' => 'Murska Sobota', 'SI.081' => 'Muta', 'SI.082' => 'Naklo', 'SI.083' => 'Nazarje', 'SI.084' => 'Nova Gorica', 'SI.085' => 'Novo Mesto', 'SI.086' => 'Odranci', 'SI.171' => 'Oplotnica', 'SI.087' => 'Ormoz', 'SI.088' => 'Osilnica', 'SI.089' => 'Pesnica', 'SI.090' => 'Piran', 'SI.091' => 'Pivka', 'SI.092' => 'Podcetrtek', 'SI.172' => 'Podlehnik', 'SI.093' => 'Podvelka', 'SI.200' => 'Poljcane', 'SI.173' => 'Polzela', 'SI.094' => 'Postojna', 'SI.174' => 'Prebold', 'SI.095' => 'Preddvor', 'SI.175' => 'Prevalje', 'SI.096' => 'Ptuj', 'SI.097' => 'Puconci', 'SI.098' => 'Race-Fram', 'SI.099' => 'Radece', 'SI.100' => 'Radenci', 'SI.101' => 'Radlje ob Dravi', 'SI.102' => 'Radovljica', 'SI.103' => 'Ravne na Koroskem', 'SI.176' => 'Razkrizje', 'SI.209' => 'Recica ob Savinji', 'SI.201' => 'Rence-Vogrsko', 'SI.104' => 'Ribnica', 'SI.177' => 'Ribnica na Pohorju', 'SI.106' => 'Rogaska Slatina', 'SI.105' => 'Rogasovci', 'SI.107' => 'Rogatec', 'SI.108' => 'Ruse', 'SI.033' => 'Salovci', 'SI.178' => 'Selnica ob Dravi', 'SI.109' => 'Semic', 'SI.183' => 'Sempeter-Vrtojba', 'SI.117' => 'Sencur', 'SI.118' => 'Sentilj', 'SI.119' => 'Sentjernej', 'SI.120' => 'Sentjur', 'SI.211' => 'Sentrupert', 'SI.110' => 'Sevnica', 'SI.111' => 'Sezana', 'SI.121' => 'Skocjan', 'SI.122' => 'Skofja Loka', 'SI.123' => 'Skofljica', 'SI.112' => 'Slovenj Gradec', 'SI.113' => 'Slovenska Bistrica', 'SI.114' => 'Slovenske Konjice', 'SI.124' => 'Smarje pri Jelsah', 'SI.206' => 'Smarjeske Toplice', 'SI.125' => 'Smartno ob Paki', 'SI.194' => 'Smartno pri Litiji', 'SI.179' => 'Sodrazica', 'SI.180' => 'Solcava', 'SI.126' => 'Sostanj', 'SI.202' => 'Sredisce ob Dravi', 'SI.115' => 'Starse', 'SI.127' => 'Store', 'SI.203' => 'Straza', 'SI.181' => 'Sveta Ana', 'SI.204' => 'Sveta Trojica v Slovenskih goricah', 'SI.182' => 'Sveti Andraz v Slovenskih Goricah', 'SI.116' => 'Sveti Jurij ob Scavnici', 'SI.210' => 'Sveti Jurij v Slovenskih goricah', 'SI.205' => 'Sveti Tomaz', 'SI.184' => 'Tabor', 'SI.010' => 'Tisina', 'SI.128' => 'Tolmin', 'SI.129' => 'Trbovlje', 'SI.130' => 'Trebnje', 'SI.185' => 'Trnovska Vas', 'SI.131' => 'Trzic', 'SI.186' => 'Trzin', 'SI.132' => 'Turnisce', 'SI.133' => 'Velenje', 'SI.187' => 'Velika Polana', 'SI.134' => 'Velike Lasce', 'SI.188' => 'Verzej', 'SI.135' => 'Videm', 'SI.136' => 'Vipava', 'SI.137' => 'Vitanje', 'SI.138' => 'Vodice', 'SI.139' => 'Vojnik', 'SI.189' => 'Vransko', 'SI.140' => 'Vrhnika', 'SI.141' => 'Vuzenica', 'SI.142' => 'Zagorje ob Savi', 'SI.190' => 'Zalec', 'SI.143' => 'Zavrc', 'SI.146' => 'Zelezniki', 'SI.191' => 'Zetale', 'SI.147' => 'Ziri', 'SI.192' => 'Zirovnica', 'SI.144' => 'Zrece', 'SI.193' => 'Zuzemberk'],
3177 'SK' => ['SK.BC' => 'Banskobystricky kraj', 'SK.BL' => 'Bratislavsky kraj', 'SK.KI' => 'Kosicky kraj', 'SK.NI' => 'Nitriansky kraj', 'SK.PV' => 'Presovsky kraj', 'SK.TC' => 'Trenciansky kraj', 'SK.TA' => 'Trnavsky kraj', 'SK.ZI' => 'Zilinsky kraj'],
3178 'SL' => ['SL.E' => 'Eastern', 'SL.NW' => 'North Western', 'SL.N' => 'Northern', 'SL.S' => 'Southern', 'SL.W' => 'Western Area'],
3179 'SM' => ['SM.01' => 'Acquaviva', 'SM.06' => 'Borgo Maggiore', 'SM.02' => 'Chiesanuova', 'SM.07' => 'Citta di San Marino', 'SM.03' => 'Domagnano', 'SM.04' => 'Faetano', 'SM.05' => 'Fiorentino', 'SM.08' => 'Montegiardino', 'SM.09' => 'Serravalle'],
3180 'SN' => ['SN.DK' => 'Dakar', 'SN.DB' => 'Diourbel', 'SN.FK' => 'Fatick', 'SN.KA' => 'Kaffrine', 'SN.KL' => 'Kaolack', 'SN.KE' => 'Kedougou', 'SN.KD' => 'Kolda', 'SN.LG' => 'Louga', 'SN.MT' => 'Matam', 'SN.SL' => 'Saint-Louis', 'SN.SE' => 'Sedhiou', 'SN.TC' => 'Tambacounda', 'SN.TH' => 'Thies', 'SN.ZG' => 'Ziguinchor'],
3181 'SO' => ['SO.AW' => 'Awdal', 'SO.BK' => 'Bakool', 'SO.BN' => 'Banaadir', 'SO.BR' => 'Bari', 'SO.BY' => 'Bay', 'SO.GA' => 'Galguduud', 'SO.GE' => 'Gedo', 'SO.HI' => 'Hiiraan', 'SO.JD' => 'Jubbada Dhexe', 'SO.JH' => 'Jubbada Hoose', 'SO.MU' => 'Mudug', 'SO.NU' => 'Nugaal', 'SO.SA' => 'Sanaag', 'SO.SD' => 'Shabeellaha Dhexe', 'SO.SH' => 'Shabeellaha Hoose', 'SO.SO' => 'Sool', 'SO.TO' => 'Togdheer', 'SO.WO' => 'Woqooyi Galbeed'],
3182 'SR' => ['SR.BR' => 'Brokopondo', 'SR.CM' => 'Commewijne', 'SR.CR' => 'Coronie', 'SR.MA' => 'Marowijne', 'SR.NI' => 'Nickerie', 'SR.PR' => 'Para', 'SR.PM' => 'Paramaribo', 'SR.SA' => 'Saramacca', 'SR.SI' => 'Sipaliwini', 'SR.WA' => 'Wanica'],
3183 'SS' => ['SS.EC' => 'Central Equatoria', 'SS.EE' => 'Eastern Equatoria', 'SS.JG' => 'Jonglei', 'SS.LK' => 'Lakes', 'SS.BN' => 'Northern Bahr el Ghazal', 'SS.UY' => 'Unity', 'SS.NU' => 'Upper Nile', 'SS.WR' => 'Warrap', 'SS.BW' => 'Western Bahr el Ghazal', 'SS.EW' => 'Western Equatoria'],
3184 'ST' => ['ST.01' => 'Agua Grande', 'ST.02' => 'Cantagalo', 'ST.03' => 'Caue', 'ST.04' => 'Lemba', 'ST.05' => 'Lobata', 'ST.06' => 'Me-Zochi', 'ST.P' => 'Principe'],
3185 'SV' => ['SV.AH' => 'Ahuachapan', 'SV.CA' => 'Cabanas', 'SV.CH' => 'Chalatenango', 'SV.CU' => 'Cuscatlan', 'SV.LI' => 'La Libertad', 'SV.PA' => 'La Paz', 'SV.UN' => 'La Union', 'SV.MO' => 'Morazan', 'SV.SM' => 'San Miguel', 'SV.SS' => 'San Salvador', 'SV.SV' => 'San Vicente', 'SV.SA' => 'Santa Ana', 'SV.SO' => 'Sonsonate', 'SV.US' => 'Usulutan'],
3186 'SY' => ['SY.HA' => 'Al Hasakah', 'SY.LA' => 'Al Ladhiqiyah', 'SY.QU' => 'Al Qunaytirah', 'SY.RA' => 'Ar Raqqah', 'SY.SU' => 'As Suwayda\'', 'SY.DR' => 'Dar\'a', 'SY.DY' => 'Dayr az Zawr', 'SY.DI' => 'Dimashq', 'SY.HL' => 'Halab', 'SY.HM' => 'Hamah', 'SY.HI' => 'Hims', 'SY.ID' => 'Idlib', 'SY.RD' => 'Rif Dimashq', 'SY.TA' => 'Tartus'],
3187 'SZ' => ['SZ.HH' => 'Hhohho', 'SZ.LU' => 'Lubombo', 'SZ.MA' => 'Manzini', 'SZ.SH' => 'Shiselweni'],
3188 'TD' => ['TD.BG' => 'Bahr el Ghazal', 'TD.BA' => 'Batha', 'TD.BO' => 'Borkou', 'TD.CB' => 'Chari-Baguirmi', 'TD.EE' => 'Ennedi-Est', 'TD.EO' => 'Ennedi-Ouest', 'TD.GR' => 'Guera', 'TD.HL' => 'Hadjer Lamis', 'TD.KA' => 'Kanem', 'TD.LC' => 'Lac', 'TD.LO' => 'Logone-Occidental', 'TD.LR' => 'Logone-Oriental', 'TD.MA' => 'Mandoul', 'TD.ME' => 'Mayo-Kebbi-Est', 'TD.MO' => 'Mayo-Kebbi-Ouest', 'TD.MC' => 'Moyen-Chari', 'TD.OD' => 'Ouaddai', 'TD.SA' => 'Salamat', 'TD.SI' => 'Sila', 'TD.TA' => 'Tandjile', 'TD.TI' => 'Tibesti', 'TD.ND' => 'Ville de Ndjamena', 'TD.WF' => 'Wadi Fira'],
3189 'TG' => ['TG.C' => 'Centrale', 'TG.K' => 'Kara', 'TG.M' => 'Maritime', 'TG.P' => 'Plateaux', 'TG.S' => 'Savanes'],
3190 'TH' => ['TH.37' => 'Amnat Charoen', 'TH.15' => 'Ang Thong', 'TH.38' => 'Bueng Kan', 'TH.31' => 'Buri Ram', 'TH.24' => 'Chachoengsao', 'TH.18' => 'Chai Nat', 'TH.36' => 'Chaiyaphum', 'TH.22' => 'Chanthaburi', 'TH.50' => 'Chiang Mai', 'TH.57' => 'Chiang Rai', 'TH.20' => 'Chon Buri', 'TH.86' => 'Chumphon', 'TH.46' => 'Kalasin', 'TH.62' => 'Kamphaeng Phet', 'TH.71' => 'Kanchanaburi', 'TH.40' => 'Khon Kaen', 'TH.81' => 'Krabi', 'TH.10' => 'Krung Thep Maha Nakhon', 'TH.52' => 'Lampang', 'TH.51' => 'Lamphun', 'TH.42' => 'Loei', 'TH.16' => 'Lop Buri', 'TH.58' => 'Mae Hong Son', 'TH.44' => 'Maha Sarakham', 'TH.49' => 'Mukdahan', 'TH.26' => 'Nakhon Nayok', 'TH.73' => 'Nakhon Pathom', 'TH.48' => 'Nakhon Phanom', 'TH.30' => 'Nakhon Ratchasima', 'TH.60' => 'Nakhon Sawan', 'TH.80' => 'Nakhon Si Thammarat', 'TH.55' => 'Nan', 'TH.96' => 'Narathiwat', 'TH.39' => 'Nong Bua Lam Phu', 'TH.43' => 'Nong Khai', 'TH.12' => 'Nonthaburi', 'TH.13' => 'Pathum Thani', 'TH.94' => 'Pattani', 'TH.82' => 'Phangnga', 'TH.93' => 'Phatthalung', 'TH.56' => 'Phayao', 'TH.67' => 'Phetchabun', 'TH.76' => 'Phetchaburi', 'TH.66' => 'Phichit', 'TH.65' => 'Phitsanulok', 'TH.14' => 'Phra Nakhon Si Ayutthaya', 'TH.54' => 'Phrae', 'TH.83' => 'Phuket', 'TH.25' => 'Prachin Buri', 'TH.77' => 'Prachuap Khiri Khan', 'TH.85' => 'Ranong', 'TH.70' => 'Ratchaburi', 'TH.21' => 'Rayong', 'TH.45' => 'Roi Et', 'TH.27' => 'Sa Kaeo', 'TH.47' => 'Sakon Nakhon', 'TH.11' => 'Samut Prakan', 'TH.74' => 'Samut Sakhon', 'TH.75' => 'Samut Songkhram', 'TH.19' => 'Saraburi', 'TH.91' => 'Satun', 'TH.33' => 'Si Sa Ket', 'TH.17' => 'Sing Buri', 'TH.90' => 'Songkhla', 'TH.64' => 'Sukhothai', 'TH.72' => 'Suphan Buri', 'TH.84' => 'Surat Thani', 'TH.32' => 'Surin', 'TH.63' => 'Tak', 'TH.92' => 'Trang', 'TH.23' => 'Trat', 'TH.34' => 'Ubon Ratchathani', 'TH.41' => 'Udon Thani', 'TH.61' => 'Uthai Thani', 'TH.53' => 'Uttaradit', 'TH.95' => 'Yala', 'TH.35' => 'Yasothon'],
3191 'TJ' => ['TJ.DU' => 'Dushanbe', 'TJ.KT' => 'Khatlon', 'TJ.GB' => 'Kuhistoni Badakhshon', 'TJ.RA' => 'Nohiyahoi Tobei Jumhuri', 'TJ.SU' => 'Sughd'],
3192 'TL' => ['TL.AL' => 'Aileu', 'TL.AN' => 'Ainaro', 'TL.BA' => 'Baucau', 'TL.BO' => 'Bobonaro', 'TL.CO' => 'Cova Lima', 'TL.DI' => 'Dili', 'TL.ER' => 'Ermera', 'TL.LA' => 'Lautem', 'TL.LI' => 'Liquica', 'TL.MT' => 'Manatuto', 'TL.MF' => 'Manufahi', 'TL.OE' => 'Oecussi', 'TL.VI' => 'Viqueque'],
3193 'TM' => ['TM.A' => 'Ahal', 'TM.B' => 'Balkan', 'TM.D' => 'Dasoguz', 'TM.L' => 'Lebap', 'TM.M' => 'Mary'],
3194 'TN' => ['TN.31' => 'Beja', 'TN.13' => 'Ben Arous', 'TN.23' => 'Bizerte', 'TN.81' => 'Gabes', 'TN.71' => 'Gafsa', 'TN.32' => 'Jendouba', 'TN.41' => 'Kairouan', 'TN.42' => 'Kasserine', 'TN.73' => 'Kebili', 'TN.12' => 'L\'Ariana', 'TN.14' => 'La Manouba', 'TN.33' => 'Le Kef', 'TN.53' => 'Mahdia', 'TN.82' => 'Medenine', 'TN.52' => 'Monastir', 'TN.21' => 'Nabeul', 'TN.61' => 'Sfax', 'TN.43' => 'Sidi Bouzid', 'TN.34' => 'Siliana', 'TN.51' => 'Sousse', 'TN.83' => 'Tataouine', 'TN.72' => 'Tozeur', 'TN.11' => 'Tunis', 'TN.22' => 'Zaghouan'],
3195 'TO' => ['TO.01' => '\'Eua', 'TO.02' => 'Ha\'apai', 'TO.03' => 'Niuas', 'TO.04' => 'Tongatapu', 'TO.05' => 'Vava\'u'],
3196 'TR' => ['TR.01' => 'Adana', 'TR.02' => 'Adiyaman', 'TR.03' => 'Afyonkarahisar', 'TR.04' => 'Agri', 'TR.68' => 'Aksaray', 'TR.05' => 'Amasya', 'TR.06' => 'Ankara', 'TR.07' => 'Antalya', 'TR.75' => 'Ardahan', 'TR.08' => 'Artvin', 'TR.09' => 'Aydin', 'TR.10' => 'Balikesir', 'TR.74' => 'Bartin', 'TR.72' => 'Batman', 'TR.69' => 'Bayburt', 'TR.11' => 'Bilecik', 'TR.12' => 'Bingol', 'TR.13' => 'Bitlis', 'TR.14' => 'Bolu', 'TR.15' => 'Burdur', 'TR.16' => 'Bursa', 'TR.17' => 'Canakkale', 'TR.18' => 'Cankiri', 'TR.19' => 'Corum', 'TR.20' => 'Denizli', 'TR.21' => 'Diyarbakir', 'TR.81' => 'Duzce', 'TR.22' => 'Edirne', 'TR.23' => 'Elazig', 'TR.24' => 'Erzincan', 'TR.25' => 'Erzurum', 'TR.26' => 'Eskisehir', 'TR.27' => 'Gaziantep', 'TR.28' => 'Giresun', 'TR.29' => 'Gumushane', 'TR.30' => 'Hakkari', 'TR.31' => 'Hatay', 'TR.76' => 'Igdir', 'TR.32' => 'Isparta', 'TR.34' => 'Istanbul', 'TR.35' => 'Izmir', 'TR.46' => 'Kahramanmaras', 'TR.78' => 'Karabuk', 'TR.70' => 'Karaman', 'TR.36' => 'Kars', 'TR.37' => 'Kastamonu', 'TR.38' => 'Kayseri', 'TR.79' => 'Kilis', 'TR.71' => 'Kirikkale', 'TR.39' => 'Kirklareli', 'TR.40' => 'Kirsehir', 'TR.41' => 'Kocaeli', 'TR.42' => 'Konya', 'TR.43' => 'Kutahya', 'TR.44' => 'Malatya', 'TR.45' => 'Manisa', 'TR.47' => 'Mardin', 'TR.33' => 'Mersin', 'TR.48' => 'Mugla', 'TR.49' => 'Mus', 'TR.50' => 'Nevsehir', 'TR.51' => 'Nigde', 'TR.52' => 'Ordu', 'TR.80' => 'Osmaniye', 'TR.53' => 'Rize', 'TR.54' => 'Sakarya', 'TR.55' => 'Samsun', 'TR.63' => 'Sanliurfa', 'TR.56' => 'Siirt', 'TR.57' => 'Sinop', 'TR.73' => 'Sirnak', 'TR.58' => 'Sivas', 'TR.59' => 'Tekirdag', 'TR.60' => 'Tokat', 'TR.61' => 'Trabzon', 'TR.62' => 'Tunceli', 'TR.64' => 'Usak', 'TR.65' => 'Van', 'TR.77' => 'Yalova', 'TR.66' => 'Yozgat', 'TR.67' => 'Zonguldak'],
3197 'TT' => ['TT.ARI' => 'Arima', 'TT.CHA' => 'Chaguanas', 'TT.CTT' => 'Couva-Tabaquite-Talparo', 'TT.DMN' => 'Diego Martin', 'TT.MRC' => 'Mayaro-Rio Claro', 'TT.PED' => 'Penal-Debe', 'TT.PTF' => 'Point Fortin', 'TT.POS' => 'Port of Spain', 'TT.PRT' => 'Princes Town', 'TT.SFO' => 'San Fernando', 'TT.SJL' => 'San Juan-Laventille', 'TT.SGE' => 'Sangre Grande', 'TT.SIP' => 'Siparia', 'TT.TOB' => 'Tobago', 'TT.TUP' => 'Tunapuna-Piarco'],
3198 'TV' => ['TV.FUN' => 'Funafuti', 'TV.NMG' => 'Nanumaga', 'TV.NMA' => 'Nanumea', 'TV.NIT' => 'Niutao', 'TV.NUI' => 'Nui', 'TV.NKF' => 'Nukufetau', 'TV.NKL' => 'Nukulaelae', 'TV.VAI' => 'Vaitupu'],
3199 'TW' => ['TW.CHA' => 'Changhua', 'TW.CYQ' => 'Chiayi', 'TW.HSQ' => 'Hsinchu', 'TW.HUA' => 'Hualien', 'TW.KHH' => 'Kaohsiung', 'TW.KEE' => 'Keelung', 'TW.KIN' => 'Kinmen', 'TW.LIE' => 'Lienchiang', 'TW.MIA' => 'Miaoli', 'TW.NAN' => 'Nantou', 'TW.NWT' => 'New Taipei', 'TW.PEN' => 'Penghu', 'TW.PIF' => 'Pingtung', 'TW.TXG' => 'Taichung', 'TW.TNN' => 'Tainan', 'TW.TPE' => 'Taipei', 'TW.TTT' => 'Taitung', 'TW.TAO' => 'Taoyuan', 'TW.ILA' => 'Yilan', 'TW.YUN' => 'Yunlin'],
3200 'TZ' => ['TZ.01' => 'Arusha', 'TZ.02' => 'Dar es Salaam', 'TZ.03' => 'Dodoma', 'TZ.27' => 'Geita', 'TZ.04' => 'Iringa', 'TZ.05' => 'Kagera', 'TZ.06' => 'Kaskazini Pemba', 'TZ.07' => 'Kaskazini Unguja', 'TZ.28' => 'Katavi', 'TZ.08' => 'Kigoma', 'TZ.09' => 'Kilimanjaro', 'TZ.10' => 'Kusini Pemba', 'TZ.11' => 'Kusini Unguja', 'TZ.12' => 'Lindi', 'TZ.26' => 'Manyara', 'TZ.13' => 'Mara', 'TZ.14' => 'Mbeya', 'TZ.15' => 'Mjini Magharibi', 'TZ.16' => 'Morogoro', 'TZ.17' => 'Mtwara', 'TZ.18' => 'Mwanza', 'TZ.29' => 'Njombe', 'TZ.19' => 'Pwani', 'TZ.20' => 'Rukwa', 'TZ.21' => 'Ruvuma', 'TZ.22' => 'Shinyanga', 'TZ.30' => 'Simiyu', 'TZ.23' => 'Singida', 'TZ.31' => 'Songwe', 'TZ.24' => 'Tabora', 'TZ.25' => 'Tanga'],
3201 'UA' => ['UA.43' => 'Avtonomna Respublika Krym', 'UA.71' => 'Cherkaska oblast', 'UA.74' => 'Chernihivska oblast', 'UA.77' => 'Chernivetska oblast', 'UA.12' => 'Dnipropetrovska oblast', 'UA.14' => 'Donetska oblast', 'UA.26' => 'Ivano-Frankivska oblast', 'UA.63' => 'Kharkivska oblast', 'UA.65' => 'Khersonska oblast', 'UA.68' => 'Khmelnytska oblast', 'UA.35' => 'Kirovohradska oblast', 'UA.30' => 'Kyiv', 'UA.32' => 'Kyivska oblast', 'UA.09' => 'Luhanska oblast', 'UA.46' => 'Lvivska oblast', 'UA.48' => 'Mykolaivska oblast', 'UA.51' => 'Odeska oblast', 'UA.53' => 'Poltavska oblast', 'UA.56' => 'Rivnenska oblast', 'UA.40' => 'Sevastopol', 'UA.59' => 'Sumska oblast', 'UA.61' => 'Ternopilska oblast', 'UA.05' => 'Vinnytska oblast', 'UA.07' => 'Volynska oblast', 'UA.21' => 'Zakarpatska oblast', 'UA.23' => 'Zaporizka oblast', 'UA.18' => 'Zhytomyrska oblast'],
3202 'UG' => ['UG.314' => 'Abim', 'UG.301' => 'Adjumani', 'UG.322' => 'Agago', 'UG.323' => 'Alebtong', 'UG.315' => 'Amolatar', 'UG.324' => 'Amudat', 'UG.216' => 'Amuria', 'UG.316' => 'Amuru', 'UG.302' => 'Apac', 'UG.303' => 'Arua', 'UG.217' => 'Budaka', 'UG.218' => 'Bududa', 'UG.201' => 'Bugiri', 'UG.235' => 'Bugweri', 'UG.420' => 'Buhweju', 'UG.117' => 'Buikwe', 'UG.219' => 'Bukedea', 'UG.118' => 'Bukomansibi', 'UG.220' => 'Bukwo', 'UG.225' => 'Bulambuli', 'UG.416' => 'Buliisa', 'UG.401' => 'Bundibugyo', 'UG.430' => 'Bunyangabu', 'UG.402' => 'Bushenyi', 'UG.202' => 'Busia', 'UG.221' => 'Butaleja', 'UG.119' => 'Butambala', 'UG.233' => 'Butebo', 'UG.120' => 'Buvuma', 'UG.226' => 'Buyende', 'UG.317' => 'Dokolo', 'UG.121' => 'Gomba', 'UG.304' => 'Gulu', 'UG.403' => 'Hoima', 'UG.417' => 'Ibanda', 'UG.203' => 'Iganga', 'UG.418' => 'Isingiro', 'UG.204' => 'Jinja', 'UG.318' => 'Kaabong', 'UG.404' => 'Kabale', 'UG.405' => 'Kabarole', 'UG.213' => 'Kaberamaido', 'UG.427' => 'Kagadi', 'UG.428' => 'Kakumiro', 'UG.237' => 'Kalaki', 'UG.101' => 'Kalangala', 'UG.222' => 'Kaliro', 'UG.122' => 'Kalungu', 'UG.102' => 'Kampala', 'UG.205' => 'Kamuli', 'UG.413' => 'Kamwenge', 'UG.414' => 'Kanungu', 'UG.206' => 'Kapchorwa', 'UG.236' => 'Kapelebyong', 'UG.335' => 'Karenga', 'UG.126' => 'Kasanda', 'UG.406' => 'Kasese', 'UG.207' => 'Katakwi', 'UG.112' => 'Kayunga', 'UG.433' => 'Kazo', 'UG.407' => 'Kibaale', 'UG.103' => 'Kiboga', 'UG.227' => 'Kibuku', 'UG.432' => 'Kikuube', 'UG.419' => 'Kiruhura', 'UG.421' => 'Kiryandongo', 'UG.408' => 'Kisoro', 'UG.434' => 'Kitagwenda', 'UG.305' => 'Kitgum', 'UG.319' => 'Koboko', 'UG.325' => 'Kole', 'UG.306' => 'Kotido', 'UG.208' => 'Kumi', 'UG.333' => 'Kwania', 'UG.228' => 'Kween', 'UG.123' => 'Kyankwanzi', 'UG.422' => 'Kyegegwa', 'UG.415' => 'Kyenjojo', 'UG.125' => 'Kyotera', 'UG.326' => 'Lamwo', 'UG.307' => 'Lira', 'UG.229' => 'Luuka', 'UG.104' => 'Luwero', 'UG.124' => 'Lwengo', 'UG.114' => 'Lyantonde', 'UG.336' => 'Madi-Okollo', 'UG.223' => 'Manafwa', 'UG.320' => 'Maracha', 'UG.105' => 'Masaka', 'UG.409' => 'Masindi', 'UG.214' => 'Mayuge', 'UG.209' => 'Mbale', 'UG.410' => 'Mbarara', 'UG.423' => 'Mitooma', 'UG.115' => 'Mityana', 'UG.308' => 'Moroto', 'UG.309' => 'Moyo', 'UG.106' => 'Mpigi', 'UG.107' => 'Mubende', 'UG.108' => 'Mukono', 'UG.334' => 'Nabilatuk', 'UG.311' => 'Nakapiripirit', 'UG.116' => 'Nakaseke', 'UG.109' => 'Nakasongola', 'UG.230' => 'Namayingo', 'UG.234' => 'Namisindwa', 'UG.224' => 'Namutumba', 'UG.327' => 'Napak', 'UG.310' => 'Nebbi', 'UG.231' => 'Ngora', 'UG.424' => 'Ntoroko', 'UG.411' => 'Ntungamo', 'UG.328' => 'Nwoya', 'UG.337' => 'Obongi', 'UG.331' => 'Omoro', 'UG.329' => 'Otuke', 'UG.321' => 'Oyam', 'UG.312' => 'Pader', 'UG.332' => 'Pakwach', 'UG.210' => 'Pallisa', 'UG.110' => 'Rakai', 'UG.429' => 'Rubanda', 'UG.425' => 'Rubirizi', 'UG.431' => 'Rukiga', 'UG.412' => 'Rukungiri', 'UG.435' => 'Rwampara', 'UG.111' => 'Sembabule', 'UG.232' => 'Serere', 'UG.426' => 'Sheema', 'UG.215' => 'Sironko', 'UG.211' => 'Soroti', 'UG.212' => 'Tororo', 'UG.113' => 'Wakiso', 'UG.313' => 'Yumbe', 'UG.330' => 'Zombo'],
3203 'UM' => ['UM.81' => 'Baker Island', 'UM.84' => 'Howland Island', 'UM.86' => 'Jarvis Island', 'UM.67' => 'Johnston Atoll', 'UM.89' => 'Kingman Reef', 'UM.71' => 'Midway Islands', 'UM.76' => 'Navassa Island', 'UM.95' => 'Palmyra Atoll', 'UM.79' => 'Wake Island'],
3204 'US' => ['US.AL' => 'Alabama', 'US.AK' => 'Alaska', 'US.AZ' => 'Arizona', 'US.AR' => 'Arkansas', 'US.CA' => 'California', 'US.CO' => 'Colorado', 'US.CT' => 'Connecticut', 'US.DE' => 'Delaware', 'US.DC' => 'District of Columbia', 'US.FL' => 'Florida', 'US.GA' => 'Georgia', 'US.HI' => 'Hawaii', 'US.ID' => 'Idaho', 'US.IL' => 'Illinois', 'US.IN' => 'Indiana', 'US.IA' => 'Iowa', 'US.KS' => 'Kansas', 'US.KY' => 'Kentucky', 'US.LA' => 'Louisiana', 'US.ME' => 'Maine', 'US.MD' => 'Maryland', 'US.MA' => 'Massachusetts', 'US.MI' => 'Michigan', 'US.MN' => 'Minnesota', 'US.MS' => 'Mississippi', 'US.MO' => 'Missouri', 'US.MT' => 'Montana', 'US.NE' => 'Nebraska', 'US.NV' => 'Nevada', 'US.NH' => 'New Hampshire', 'US.NJ' => 'New Jersey', 'US.NM' => 'New Mexico', 'US.NY' => 'New York', 'US.NC' => 'North Carolina', 'US.ND' => 'North Dakota', 'US.OH' => 'Ohio', 'US.OK' => 'Oklahoma', 'US.OR' => 'Oregon', 'US.PA' => 'Pennsylvania', 'US.RI' => 'Rhode Island', 'US.SC' => 'South Carolina', 'US.SD' => 'South Dakota', 'US.TN' => 'Tennessee', 'US.TX' => 'Texas', 'US.UT' => 'Utah', 'US.VT' => 'Vermont', 'US.VA' => 'Virginia', 'US.WA' => 'Washington', 'US.WV' => 'West Virginia', 'US.WI' => 'Wisconsin', 'US.WY' => 'Wyoming'],
3205 'UY' => ['UY.AR' => 'Artigas', 'UY.CA' => 'Canelones', 'UY.CL' => 'Cerro Largo', 'UY.CO' => 'Colonia', 'UY.DU' => 'Durazno', 'UY.FS' => 'Flores', 'UY.FD' => 'Florida', 'UY.LA' => 'Lavalleja', 'UY.MA' => 'Maldonado', 'UY.MO' => 'Montevideo', 'UY.PA' => 'Paysandu', 'UY.RN' => 'Rio Negro', 'UY.RV' => 'Rivera', 'UY.RO' => 'Rocha', 'UY.SA' => 'Salto', 'UY.SJ' => 'San Jose', 'UY.SO' => 'Soriano', 'UY.TA' => 'Tacuarembo', 'UY.TT' => 'Treinta y Tres'],
3206 'UZ' => ['UZ.AN' => 'Andijon', 'UZ.BU' => 'Buxoro', 'UZ.FA' => 'Farg\'ona', 'UZ.JI' => 'Jizzax', 'UZ.NG' => 'Namangan', 'UZ.NW' => 'Navoiy', 'UZ.QA' => 'Qashqadaryo', 'UZ.QR' => 'Qoraqalpog\'iston Respublikasi', 'UZ.SA' => 'Samarqand', 'UZ.SI' => 'Sirdaryo', 'UZ.SU' => 'Surxondaryo', 'UZ.TK' => 'Toshkent', 'UZ.XO' => 'Xorazm'],
3207 'VC' => ['VC.01' => 'Charlotte', 'VC.06' => 'Grenadines', 'VC.03' => 'Saint David', 'VC.04' => 'Saint George', 'VC.05' => 'Saint Patrick'],
3208 'VE' => ['VE.Z' => 'Amazonas', 'VE.B' => 'Anzoategui', 'VE.C' => 'Apure', 'VE.D' => 'Aragua', 'VE.E' => 'Barinas', 'VE.F' => 'Bolivar', 'VE.G' => 'Carabobo', 'VE.H' => 'Cojedes', 'VE.Y' => 'Delta Amacuro', 'VE.W' => 'Dependencias Federales', 'VE.A' => 'Distrito Capital', 'VE.I' => 'Falcon', 'VE.J' => 'Guarico', 'VE.X' => 'La Guaira', 'VE.K' => 'Lara', 'VE.L' => 'Merida', 'VE.M' => 'Miranda', 'VE.N' => 'Monagas', 'VE.O' => 'Nueva Esparta', 'VE.P' => 'Portuguesa', 'VE.R' => 'Sucre', 'VE.S' => 'Tachira', 'VE.T' => 'Trujillo', 'VE.U' => 'Yaracuy', 'VE.V' => 'Zulia'],
3209 'VN' => ['VN.44' => 'An Giang', 'VN.43' => 'Ba Ria - Vung Tau', 'VN.54' => 'Bac Giang', 'VN.53' => 'Bac Kan', 'VN.55' => 'Bac Lieu', 'VN.56' => 'Bac Ninh', 'VN.50' => 'Ben Tre', 'VN.31' => 'Binh Dinh', 'VN.57' => 'Binh Duong', 'VN.58' => 'Binh Phuoc', 'VN.40' => 'Binh Thuan', 'VN.59' => 'Ca Mau', 'VN.CT' => 'Can Tho', 'VN.04' => 'Cao Bang', 'VN.DN' => 'Da Nang', 'VN.33' => 'Dak Lak', 'VN.72' => 'Dak Nong', 'VN.71' => 'Dien Bien', 'VN.39' => 'Dong Nai', 'VN.45' => 'Dong Thap', 'VN.30' => 'Gia Lai', 'VN.03' => 'Ha Giang', 'VN.63' => 'Ha Nam', 'VN.HN' => 'Ha Noi', 'VN.23' => 'Ha Tinh', 'VN.61' => 'Hai Duong', 'VN.HP' => 'Hai Phong', 'VN.73' => 'Hau Giang', 'VN.SG' => 'Ho Chi Minh', 'VN.14' => 'Hoa Binh', 'VN.66' => 'Hung Yen', 'VN.34' => 'Khanh Hoa', 'VN.47' => 'Kien Giang', 'VN.28' => 'Kon Tum', 'VN.01' => 'Lai Chau', 'VN.35' => 'Lam Dong', 'VN.09' => 'Lang Son', 'VN.02' => 'Lao Cai', 'VN.41' => 'Long An', 'VN.67' => 'Nam Dinh', 'VN.22' => 'Nghe An', 'VN.18' => 'Ninh Binh', 'VN.36' => 'Ninh Thuan', 'VN.68' => 'Phu Tho', 'VN.32' => 'Phu Yen', 'VN.24' => 'Quang Binh', 'VN.27' => 'Quang Nam', 'VN.29' => 'Quang Ngai', 'VN.13' => 'Quang Ninh', 'VN.25' => 'Quang Tri', 'VN.52' => 'Soc Trang', 'VN.05' => 'Son La', 'VN.37' => 'Tay Ninh', 'VN.20' => 'Thai Binh', 'VN.69' => 'Thai Nguyen', 'VN.21' => 'Thanh Hoa', 'VN.26' => 'Thua Thien-Hue', 'VN.46' => 'Tien Giang', 'VN.51' => 'Tra Vinh', 'VN.07' => 'Tuyen Quang', 'VN.49' => 'Vinh Long', 'VN.70' => 'Vinh Phuc', 'VN.06' => 'Yen Bai'],
3210 'VU' => ['VU.MAP' => 'Malampa', 'VU.PAM' => 'Penama', 'VU.SAM' => 'Sanma', 'VU.SEE' => 'Shefa', 'VU.TAE' => 'Tafea', 'VU.TOB' => 'Torba'],
3211 'WF' => ['WF.AL' => 'Alo', 'WF.SG' => 'Sigave', 'WF.UV' => 'Uvea'],
3212 'WS' => ['WS.AA' => 'A\'ana', 'WS.AL' => 'Aiga-i-le-Tai', 'WS.AT' => 'Atua', 'WS.FA' => 'Fa\'asaleleaga', 'WS.GE' => 'Gaga\'emauga', 'WS.GI' => 'Gagaifomauga', 'WS.PA' => 'Palauli', 'WS.SA' => 'Satupa\'itea', 'WS.TU' => 'Tuamasaga', 'WS.VF' => 'Va\'a-o-Fonoti', 'WS.VS' => 'Vaisigano'],
3213 'YE' => ['YE.AD' => '\'Adan', 'YE.AM' => '\'Amran', 'YE.AB' => 'Abyan', 'YE.DA' => 'Ad Dali\'', 'YE.BA' => 'Al Bayda\'', 'YE.HU' => 'Al Hudaydah', 'YE.JA' => 'Al Jawf', 'YE.MR' => 'Al Mahrah', 'YE.MW' => 'Al Mahwit', 'YE.SA' => 'Amanat al \'Asimah', 'YE.DH' => 'Dhamar', 'YE.HD' => 'Hadramawt', 'YE.HJ' => 'Hajjah', 'YE.IB' => 'Ibb', 'YE.LA' => 'Lahij', 'YE.MA' => 'Ma\'rib', 'YE.RA' => 'Raymah', 'YE.SD' => 'Sa\'dah', 'YE.SN' => 'San\'a\'', 'YE.SH' => 'Shabwah', 'YE.TA' => 'Ta\'izz', 'YE.SU' => 'Arkhabil Suqutra'],
3214 'ZA' => ['ZA.EC' => 'Eastern Cape', 'ZA.FS' => 'Free State', 'ZA.GT' => 'Gauteng', 'ZA.NL' => 'Kwazulu-Natal', 'ZA.LP' => 'Limpopo', 'ZA.MP' => 'Mpumalanga', 'ZA.NW' => 'North-West', 'ZA.NC' => 'Northern Cape', 'ZA.WC' => 'Western Cape'],
3215 'ZM' => ['ZM.02' => 'Central', 'ZM.08' => 'Copperbelt', 'ZM.03' => 'Eastern', 'ZM.04' => 'Luapula', 'ZM.09' => 'Lusaka', 'ZM.10' => 'Muchinga', 'ZM.06' => 'North-Western', 'ZM.05' => 'Northern', 'ZM.07' => 'Southern', 'ZM.01' => 'Western'],
3216 'ZW' => ['ZW.BU' => 'Bulawayo', 'ZW.HA' => 'Harare', 'ZW.MA' => 'Manicaland', 'ZW.MC' => 'Mashonaland Central', 'ZW.ME' => 'Mashonaland East', 'ZW.MW' => 'Mashonaland West', 'ZW.MV' => 'Masvingo', 'ZW.MN' => 'Matabeleland North', 'ZW.MS' => 'Matabeleland South', 'ZW.MI' => 'Midlands'],
3217 ];
3218
3219 if (isset($regions[$country_code])) {
3220 foreach ($regions[$country_code] as $region_code => $name) {
3221 if ($name == $region_name) {
3222 return $region_code;
3223 }
3224 }
3225 }
3226
3227 return false;
3228 }
3229
3230 private function is_setup_completed()
3231 {
3232 if ($this->get_option('lookup_mode') == 'ws' && $this->get_option('api_key')) {
3233 return true;
3234 }
3235
3236 if ($this->get_option('lookup_mode') == 'bin' && is_file(IP2LOCATION_DIR . $this->get_option('database'))) {
3237 return true;
3238 }
3239
3240 return false;
3241 }
3242
3243 private function get_database_date()
3244 {
3245 if (!is_file(IP2LOCATION_DIR . $this->get_option('database'))) {
3246 return;
3247 }
3248
3249 $obj = new \IP2Location\Database(IP2LOCATION_DIR . $this->get_option('database'), \IP2Location\Database::FILE_IO);
3250
3251 return date('Y-m-d', strtotime(str_replace('.', '-', $obj->getDatabaseVersion())));
3252 }
3253
3254 private function is_region_supported()
3255 {
3256 if ($this->get_option('lookup_mode') == 'ws' && $this->get_option('api_key')) {
3257 return true;
3258 }
3259
3260 if (!is_file(IP2LOCATION_DIR . $this->get_option('database'))) {
3261 return null;
3262 }
3263
3264 $obj = new \IP2Location\Database(IP2LOCATION_DIR . $this->get_option('database'), \IP2Location\Database::FILE_IO);
3265
3266 $result = $obj->lookup('8.8.8.8', \IP2Location\Database::ALL);
3267
3268 if (preg_match('/unavailable/', $result['regionName'])) {
3269 return false;
3270 }
3271
3272 return true;
3273 }
3274
3275 private function cidr_match($ip, $cidr)
3276 {
3277 list($subnet, $mask) = explode('/', $cidr);
3278
3279 if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) && filter_var($subnet, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
3280 return (ip2long($ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($subnet);
3281 } elseif (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6) && filter_var($subnet, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
3282 $ip = inet_pton($ip);
3283 $subnet = inet_pton($subnet);
3284
3285 $binMask = str_repeat('f', (int)($mask / 4));
3286 switch ($mask % 4) {
3287 case 0:
3288 break;
3289 case 1:
3290 $binMask .= '8';
3291 break;
3292 case 2:
3293 $binMask .= 'c';
3294 break;
3295 case 3:
3296 $binMask .= 'e';
3297 break;
3298 }
3299
3300 $binMask = str_pad($binMask, 32, '0');
3301 $binMask = pack('H*', $binMask);
3302
3303 return ($ip & $binMask) == $subnet;
3304 }
3305
3306 return false;
3307 }
3308
3309 private function cache_add($key, $value)
3310 {
3311 $value = is_array($value) ? $value : [$value];
3312 file_put_contents(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . md5($key . '_ip2location_redirection') . '.json', json_encode($value));
3313 }
3314
3315 private function cache_get($key)
3316 {
3317 if (file_exists(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . md5($key . '_ip2location_redirection') . '.json')) {
3318 return json_decode(file_get_contents(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . md5($key . '_ip2location_redirection') . '.json'));
3319 }
3320
3321 return null;
3322 }
3323
3324 private function cache_clear($day = 1)
3325 {
3326 require_once ABSPATH . 'wp-admin/includes/file.php';
3327 WP_Filesystem();
3328 global $wp_filesystem;
3329
3330 $now = time();
3331 $files = scandir(IP2LOCATION_DIR . 'caches');
3332
3333 foreach ($files as $file) {
3334 if (substr($file, -5) == '.json') {
3335 if ($now - filemtime(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . $file) >= 60 * 60 * 24 * $day) {
3336 $wp_filesystem->delete(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . $file);
3337 }
3338 }
3339 }
3340 }
3341
3342 private function cache_size()
3343 {
3344 $size = 0;
3345
3346 $files = scandir(IP2LOCATION_DIR . 'caches');
3347
3348 foreach ($files as $file) {
3349 if (substr($file, -5) == '.json') {
3350 $size += filesize(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . $file);
3351 }
3352 }
3353
3354 return $size;
3355 }
3356
3357 private function cache_flush()
3358 {
3359 require_once ABSPATH . 'wp-admin/includes/file.php';
3360 WP_Filesystem();
3361 global $wp_filesystem;
3362
3363 $files = scandir(IP2LOCATION_DIR . 'caches');
3364
3365 foreach ($files as $file) {
3366 if (substr($file, -5) == '.json') {
3367 $wp_filesystem->delete(IP2LOCATION_DIR . 'caches' . \DIRECTORY_SEPARATOR . $file);
3368 }
3369 }
3370 }
3371
3372 private function get_page_id()
3373 {
3374 $post_name = preg_replace('/\/?\?.+$/', '', trim($_SERVER['REQUEST_URI'], '/'));
3375
3376 if (strrpos($post_name, '/') !== false) {
3377 $post_name = substr($post_name, strrpos($post_name, '/') + 1);
3378 }
3379
3380 $results = $this->wpdb_get_results("SELECT * FROM {$GLOBALS['wpdb']->prefix}posts WHERE post_name = %s", [
3381 $post_name
3382 ]);
3383
3384 return ($results) ? $results[0]->ID : null;
3385 }
3386
3387 private function get_post_title($post_id)
3388 {
3389 return $this->wpdb_get_value("SELECT `post_title` FROM {$GLOBALS['wpdb']->prefix}posts WHERE `ID` = %d", [
3390 $post_id
3391 ]);
3392 }
3393
3394 private function get_permalink($page_id)
3395 {
3396 $results = $this->wpdb_get_results("SELECT * FROM {$GLOBALS['wpdb']->prefix}posts WHERE ID = %d", [
3397 $page_id
3398 ]);
3399
3400 if ($results) {
3401 if (preg_match('/page_id=[0-9]+$/', $results[0]->guid)) {
3402 return '/' . $results[0]->post_name;
3403 }
3404
3405 return $results[0]->guid;
3406 }
3407
3408 return null;
3409 }
3410
3411 private function sanitize_array($array)
3412 {
3413 if (is_string($array)) {
3414 return sanitize_text_field($array);
3415 }
3416 foreach ($array as $key => $value) {
3417 if (is_array($value)) {
3418 $array[$key] = $this->sanitize_array($value);
3419 } else {
3420 $array[$key] = sanitize_text_field($value);
3421 }
3422 }
3423
3424 return $array;
3425 }
3426
3427 private function sanitize_list($list)
3428 {
3429 if (strpos($list, ';') === false && !filter_var(str_replace('*', '0', $list), \FILTER_VALIDATE_IP, \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE)) {
3430 return;
3431 }
3432
3433 $items = [];
3434 $parts = explode(';', $list);
3435
3436 sort($parts);
3437
3438 foreach ($parts as $part) {
3439 if (strpos($part, '/') !== false) {
3440 list($ip, $range) = explode('/', $part);
3441
3442 // Skip invalid IP address
3443 if (!filter_var($ip, \FILTER_VALIDATE_IP)) {
3444 continue;
3445 }
3446
3447 // Invalid IPv4 range
3448 if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4) && ((int) $range < 1 || (int) $range > 32)) {
3449 continue;
3450 }
3451
3452 // Invalid IPv6 range
3453 if (filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6) && ((int) $range < 1 || (int) $range > 128)) {
3454 continue;
3455 }
3456 } elseif (!filter_var(str_replace('*', '0', $part), \FILTER_VALIDATE_IP)) {
3457 continue;
3458 }
3459
3460 $items[] = $part;
3461 }
3462
3463 return implode(';', $items);
3464 }
3465
3466 private function http_host()
3467 {
3468 return $_SERVER['HTTP_HOST'] ?? '';
3469 }
3470
3471 private function display_bytes($bytes)
3472 {
3473 $ext = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
3474
3475 $index = 0;
3476 for (; $bytes > 1024; ++$index) {
3477 $bytes /= 1024;
3478 }
3479
3480 return number_format((float) $bytes, 0, '.', ',') . ' ' . $ext[$index];
3481 }
3482 }
3483