PluginProbe
CloudGuard / trunk
CloudGuard vtrunk
cloudguard / cloudguard.php

cloudguard.php in CloudGuard trunk, at cloudguard.php

760 lines 23.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: CloudGuard
4 Plugin URI: https://wordpress.org/plugins/cloudguard/
5 Description: Restrict access to your login page using Cloudflare Geolocation.
6 Author: pipdig
7 Author URI: https://www.pipdig.co/
8 Version: 1.4.6
9 Text Domain: cloudguard
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 if (!defined('ABSPATH')) die;
27
28
29 // Load languages
30 function cloudguard_textdomain() {
31 load_plugin_textdomain('cloudguard', false, 'cloudguard/lang');
32 }
33 add_action('plugins_loaded', 'cloudguard_textdomain');
34
35
36 function cloudguard_php_login_check() {
37
38 $xmlrpc = false;
39 if (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) {
40 $xmlrpc = true;
41 }
42
43 $jetpack = false;
44 if (defined('JETPACK__PLUGIN_DIR') && JETPACK__PLUGIN_DIR) {
45 $jetpack = true;
46 }
47
48 if ((in_array($GLOBALS['pagenow'], array('wp-login.php', 'wp-register.php'))) || ($xmlrpc && !$jetpack)) {
49
50 if (!isset($_SERVER['HTTP_CF_IPCOUNTRY'])) { // check if Geolocation enabled. If not, bail.
51 return;
52 }
53
54 $attempt_country_code = strip_tags(strtoupper($_SERVER["HTTP_CF_IPCOUNTRY"]));
55
56 $options = get_option('cloudguard_options');
57
58 if (empty($options['accepted_country'])) { // check if country code added to options page. If not, bail.
59 return;
60 } else {
61 $accepted_country_list = strip_tags($options['accepted_country']);
62 $accepted_country_list = str_replace(" ", "", $accepted_country_list);
63 $accepted_country_list = strtoupper($accepted_country_list);
64 $accepted_country_list = preg_replace('/,+/', ',', $accepted_country_list); // remove consecutive commas
65 $accepted_countries = explode(',',$accepted_country_list); // convert comma list into array
66 }
67
68 if (!in_array($attempt_country_code, $accepted_countries)) {
69
70 $blocked_attempts = get_option('cloudguard_blocked_attempts');
71
72 if (empty($blocked_attempts[$attempt_country_code])) {
73 $blocked_attempts[$attempt_country_code] = 1;
74 } else {
75 $blocked_attempts[$attempt_country_code]++;
76 }
77
78 update_option('cloudguard_blocked_attempts', $blocked_attempts, 'no');
79
80 // if redirect option set, redirect to url
81 if (!empty($options['cloudguard_redirect']) && !$xmlrpc) {
82 wp_redirect(esc_url($options['cloudguard_redirect']), 301);
83 die();
84 }
85
86 // display message to blocked user
87 if (!empty($options['cloudguard_message'])) {
88 $message = strip_tags($options['cloudguard_message']); // need to escape
89 } else {
90 $message = 'Access denied.';
91 }
92
93 $status_code = 403;
94 status_header($status_code);
95 wp_die($message);
96 }
97
98 }
99
100 }
101 add_action('init', 'cloudguard_php_login_check');
102
103
104 function cloudguard_admin_assets($hook) {
105 if (isset($_GET['page']) && $_GET['page'] == 'cloudguard') {
106 wp_enqueue_script('cloudguard-ammap', plugins_url('assets/ammap/ammap.js', __FILE__), array(), null, false);
107 wp_enqueue_script('cloudguard-ammap-world', plugins_url('assets/ammap/maps/js/worldLow.js', __FILE__), array(), null, false);
108 }
109 }
110 add_action('admin_enqueue_scripts', 'cloudguard_admin_assets');
111
112
113 function cloudguard_plugin_action_links($links) {
114 $links[] = '<a href="'.get_admin_url(null, 'options-general.php?page=cloudguard').'">'.__('Settings').'</a>';
115 return $links;
116 }
117 add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'cloudguard_plugin_action_links');
118
119
120 function cloudguard_admin_menu() {
121 global $submenu;
122 add_submenu_page('options-general.php', 'CloudGuard', 'CloudGuard', 'manage_options', 'cloudguard', 'cloudguard_options_page');
123 }
124 add_action('admin_menu', 'cloudguard_admin_menu', 99);
125
126
127 function cloudguard_options_init() {
128 register_setting('cloudguard_page', 'cloudguard_options');
129 add_settings_section(
130 'cloudguard_page_section',
131 '', // title
132 'cloudguard_options_section_callback',
133 'cloudguard_page'
134 );
135 add_settings_field(
136 'cloudguard_country_code',
137 __('2 Letter Country Code', 'cloudguard'),
138 'cloudguard_country_code_render',
139 'cloudguard_page',
140 'cloudguard_page_section'
141 );
142 add_settings_field(
143 'cloudguard_message',
144 __('Message to display to user when blocked by CloudGuard (Optional)', 'cloudguard'),
145 'cloudguard_message_render',
146 'cloudguard_page',
147 'cloudguard_page_section'
148 );
149 add_settings_field(
150 'cloudguard_redirect',
151 __('URL to redirect user to when blocked by CloudGuard (Optional)', 'cloudguard'),
152 'cloudguard_redirect_render',
153 'cloudguard_page',
154 'cloudguard_page_section'
155 );
156 }
157 add_action('admin_init', 'cloudguard_options_init');
158
159
160
161 function cloudguard_country_code_render() {
162 $options = get_option('cloudguard_options');
163 $accepted_country = strip_tags($options['accepted_country']);
164 ?>
165 <input type="text" name="cloudguard_options[accepted_country]" id="country_code" <?php if (!empty($accepted_country)) { ?>style="text-transform: uppercase;" <?php } ?> placeholder="<?php echo esc_attr(__('For example: US', 'cloudguard')); ?>" value="<?php if (isset($accepted_country)) { echo $accepted_country; } ?>"/>
166 <script>
167 document.getElementById('country_code').onkeyup = function(event) {
168 this.value = this.value.replace(/[^a-zA-Z,]/g, '');
169 }
170 </script>
171 <?php
172 }
173
174 function cloudguard_message_render() {
175 $options = get_option('cloudguard_options');
176 $cloudguard_message = strip_tags($options['cloudguard_message']);
177 ?>
178 <input type="text" name="cloudguard_options[cloudguard_message]" placeholder="<?php echo esc_attr(__('Default: Access denied.', 'cloudguard')); ?>" value="<?php if (!empty($cloudguard_message)) { echo $cloudguard_message; } ?>"/>
179 <?php
180 }
181
182 function cloudguard_redirect_render() {
183 $options = get_option('cloudguard_options');
184 $cloudguard_redirect = esc_url($options['cloudguard_redirect']);
185 ?>
186 <input type="url" name="cloudguard_options[cloudguard_redirect]" placeholder="e.g. https://www.google.com" value="<?php if (!empty($cloudguard_redirect)) { echo $cloudguard_redirect; } ?>"/>
187 <span>If you'd like to automatically redirect countries that do not have access.</span>
188 <?php
189 }
190
191
192 function cloudguard_options_section_callback() {
193 ?><p><?php printf(__('Enter the <a href="%s" target="_blank" rel="noopener">2 digit code</a> of the country you wish to <b>ALLOW</b> access from.', 'cloudguard'), esc_url('https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements')); ?></p><?php
194 ?><p><?php _e('You can allow access to multiple countries by entering a comma separated list. For example: GB,US,AU', 'cloudguard'); ?></p><?php
195 ?><p><?php _e('All <b>other</b> countries will be blocked from accessing the login/register page.', 'cloudguard'); ?></p><?php
196 if (isset($_SERVER['HTTP_CF_IPCOUNTRY'])){ ?><p><?php _e('Your current location:', 'cloudguard'); ?> <?php echo strip_tags(strtoupper($_SERVER["HTTP_CF_IPCOUNTRY"])); ?></p><?php }
197 }
198
199 function cloudguard_options_page() {
200 ?>
201
202 <style>
203 .wrap input[type="text"], .wrap input[type="url"] { width: 280px; max-width: 100%; }
204 </style>
205
206 <div class="wrap">
207
208 <h1><?php _e('CloudGuard Settings', 'cloudguard'); ?></h1>
209
210 <div id="poststuff">
211
212 <div id="post-body" class="metabox-holder columns-1">
213
214 <!-- main content -->
215 <div id="post-body-content">
216
217 <div class="meta-box-sortables ui-sortable">
218
219 <div class="postbox">
220
221 <div class="inside">
222
223 <?php if (!isset($_SERVER['HTTP_CF_IPCOUNTRY'])) { // check if CF geo active ?>
224
225 <h3><?php _e('Settings currently disabled. You will need to complete the steps below to enable the use of this plugin:'); ?></h3>
226
227 <ol>
228 <li>Check that the domain DNS is enabled with an <a href="https://support.cloudflare.com/hc/en-us/articles/200169626-What-subdomains-are-appropriate-for-orange-gray-clouds" target="_blank" rel="noopener">Orange Cloud</a>.</li>
229 <li><?php printf(__('Enable <a href="%s" target="_blank" rel="noopener">Geolocation</a> for this site in your Cloudflare dashboard.', 'cloudguard'), esc_url('https://support.cloudflare.com/hc/en-us/articles/200168236-What-does-CloudFlare-IP-Geolocation-do-')); ?></li>
230 </ol>
231
232 <p>Please note it may take several hours for Geolocation to begin working after enabling it.</p>
233
234
235 <?php } else { // cloudflare geo enabled, let's display options: ?>
236
237 <form action='options.php' method='post'>
238 <?php
239 settings_fields('cloudguard_page');
240 do_settings_sections('cloudguard_page');
241 submit_button();
242 ?>
243 </form>
244 <?php
245
246 } //end if for cloudlare geo
247 ?>
248 </div>
249 <!-- .inside -->
250 </div>
251 <!-- .postbox -->
252
253
254 <?php
255 $options = get_option('cloudguard_options');
256 if (isset($_SERVER['HTTP_CF_IPCOUNTRY']) && !empty($options['accepted_country'])) { // check if CF geo active
257
258 $accepted_country_list = strip_tags($options['accepted_country']);
259 $accepted_country_list = str_replace(" ", "", $accepted_country_list);
260 $accepted_country_list = strtoupper($accepted_country_list);
261 $accepted_countries = explode(',',$accepted_country_list); //convert comma list into array
262 $blocked_attempts = get_option('cloudguard_blocked_attempts');
263 ?>
264 <div class="postbox">
265 <div style="text-align: center">
266 <?php
267 if (!empty($blocked_attempts)) {
268 ?>
269 <h3><?php _e('CloudGuard has protected your website from:', 'cloudguard'); ?></h3>
270 <?php } else { ?>
271 <h3><?php _e('This area will display blocked login attempts over time.', 'cloudguard'); ?></h3>
272 <?php } ?>
273 </div>
274
275 <!-- amCharts javascript code -->
276 <script type="text/javascript">
277 AmCharts.makeChart("map",{
278 "type": "map",
279 "pathToImages": "<?php echo plugin_dir_url(__FILE__); ?>assets/ammap/images/",
280 "addClassNames": true,
281 "fontSize": 14,
282 "color": "#ffffff",
283 "backgroundAlpha": 1,
284 "backgroundColor": "rgba(255,255,255,0)",
285 "dataProvider": {
286 "map": "worldLow",
287 "getAreasFromMap": true,
288 "areas": [
289 <?php
290 foreach ($blocked_attempts as $country => $attempts) {
291 if ($attempts <= 2) {
292 $opacity = '0.2';
293 } elseif ($attempts > 2 && $attempts <= 5) {
294 $opacity = '0.25';
295 } elseif ($attempts > 5 && $attempts <= 10) {
296 $opacity = '0.3';
297 } elseif ($attempts > 10 && $attempts <= 20) {
298 $opacity = '0.35';
299 } elseif ($attempts > 20 && $attempts <= 35) {
300 $opacity = '0.4';
301 } elseif ($attempts > 35 && $attempts <= 50) {
302 $opacity = '0.45';
303 } elseif ($attempts > 50 && $attempts <= 75) {
304 $opacity = '0.5';
305 } elseif ($attempts > 75 && $attempts <= 125) {
306 $opacity = '0.6';
307 } elseif ($attempts > 125 && $attempts <= 250) {
308 $opacity = '0.68';
309 } elseif ($attempts > 250 && $attempts <= 500) {
310 $opacity = '0.8';
311 } elseif ($attempts > 500 && $attempts <= 750) {
312 $opacity = '0.9';
313 } elseif ($attempts > 750) {
314 $opacity = '0.98';
315 }
316 echo '
317 {
318 "id": "'.esc_attr($country).'",
319 "title": "'.$attempts.' '.__('blocked from', 'cloudguard').' '.cloudguard_code_to_country($country).'",
320 "color": "rgba(204, 33, 39,'.$opacity.')"
321 }, ';
322 }
323 foreach ($accepted_countries as $accepted_country) { ?>
324 {
325 "id": "<?php echo esc_attr($accepted_country); ?>",
326 "title": "<?php echo esc_attr(__('Access granted:', 'cloudguard')); ?> <?php echo cloudguard_code_to_country($accepted_country); ?>",
327 "color": "rgba(202, 223, 170,1)"
328 },
329 <?php } // end foreach ?>
330 ]
331 },
332 "balloon": {
333 "horizontalPadding": 15,
334 "borderAlpha": 0,
335 "borderThickness": 1,
336 "verticalPadding": 15
337 },
338 "areasSettings": {
339 "color": "rgba(170, 170, 170,0.5)",
340 "outlineColor": "rgba(80,80,80,0)",
341 "rollOverOutlineColor": "rgba(80,80,80,1)",
342 "rollOverBrightness": 20,
343 "selectedBrightness": 20,
344 "selectable": false,
345 "unlistedAreasAlpha": 0,
346 "unlistedAreasOutlineAlpha": 0
347 },
348 "zoomControl": {
349 "zoomControlEnabled": true,
350 "homeButtonEnabled": false,
351 "panControlEnabled": false,
352 "right": 38,
353 "bottom": 30,
354 "minZoomLevel": 0.25,
355 "gridHeight": 100,
356 "gridAlpha": 0.1,
357 "gridBackgroundAlpha": 0,
358 "gridColor": "#ffffff",
359 "draggerAlpha": 1,
360 "buttonCornerRadius": 2
361 }
362 });
363 </script>
364
365 <div id="map" style="width: 90%; height: 450px; margin: 20px;"></div>
366
367 </div>
368 <!-- .postbox -->
369 <?php } // end if CF plugin and geo active ?>
370 </div>
371 <!-- .meta-box-sortables .ui-sortable -->
372
373 </div>
374 <!-- post-body-content -->
375
376 </div>
377 <!-- #post-body .metabox-holder .columns-1 -->
378
379 <br class="clear">
380 </div>
381 <!-- #poststuff -->
382
383 </div> <!-- .wrap -->
384
385 <?php
386 }
387
388
389
390 // dashboard widget
391 function cloudguard_dash_widgets() {
392 add_meta_box(
393 'cloudguard_dash_widget',
394 'CloudGuard',
395 'cloudguard_dash_widget_func',
396 'dashboard',
397 'side',
398 'high'
399 );
400 }
401 add_action('wp_dashboard_setup', 'cloudguard_dash_widgets');
402
403 function cloudguard_dash_widget_func() {
404
405 if (current_user_can('manage_options')) {
406 // clear stats if button clicked
407 if (isset($_POST['cloudguard_clear_log'])) {
408 if (!isset($_POST['cloudguard_nonce_field']) || !wp_verify_nonce($_POST['cloudguard_nonce_field'], 'cloudguard_nonce_action')) {
409 return;
410 }
411 delete_option('cloudguard_blocked_attempts');
412 echo '<div id="message" class="updated fade"><p>'. __('CloudGuard stats have been cleared', 'cloudguard'). '</p></div>';
413 }
414 }
415
416 $blocked_attempts = get_option('cloudguard_blocked_attempts');
417
418 if (!empty($blocked_attempts)) {
419
420 arsort($blocked_attempts);
421 echo '<p>'.__('Top 5 login attempts blocked by CloudGuard:', 'cloudguard').'</p>';
422 echo '<style scoped>.cg_flag{position:relative;top:3px}</style>';
423 $i = $top_blocked = 0;
424 foreach ($blocked_attempts as $country => $attempts) {
425
426 $flag_img_src = plugin_dir_url(__FILE__).'assets/flags/'.strtolower($country).'.png';
427
428 if (!file_exists($flag_img_src)) {
429 $flag_img_src = plugin_dir_url(__FILE__).'assets/flags/xx.png';
430 }
431
432 echo '<p><img class="cg_flag" src="'.esc_url($flag_img_src).'" alt=""/> '.cloudguard_code_to_country($country).' ('.absint($attempts).')</p>';
433
434 if ($i == 0) {
435 $top_blocked = absint($attempts);
436 }
437
438 if (++$i == 5) break;
439
440 }
441 if (current_user_can('manage_options')) {
442 echo '<p><a href="'.get_admin_url(null, 'options-general.php?page=cloudguard').'">'.__('Click here for more statistics', 'cloudguard').'</a></p>';
443 }
444
445 if (current_user_can('manage_options')) {
446 ?>
447 <form action="index.php" method="post">
448 <?php wp_nonce_field('cloudguard_nonce_action', 'cloudguard_nonce_field'); ?>
449 <input type="hidden" value="true" name="cloudguard_clear_log" />
450 <p class="submit">
451 <input name="submit" class="button" value="<?php echo esc_attr(__('Clear stats', 'cloudguard')); ?>" type="submit" />
452 </p>
453 </form>
454 <?php
455 // show some love if more than 75 blocks have been successful
456 if (!get_option('cloudguard_nag') && ($top_blocked > 75)) {
457 ?>
458 <div id="cloudguard_nag_wrapper">
459 <hr style="margin-top: 30px">
460 <p><strong>It looks like CloudGuard is working very well on your site!</strong></p>
461 <p>Would you like to <a href="https://wordpress.org/support/plugin/cloudguard/reviews/?rate=5#new-post" target="_blank">leave a rating</a>? This will help us to provide continued support and updates.</p>
462 <p><a href="https://wordpress.org/support/plugin/cloudguard/reviews/?rate=5#new-post" target="_blank" class="button">Leave a rating</a> <a href="#" id="cloudguard_remove_nag" class="button">Remove this notice</a></p>
463 </p>
464
465 <script>
466 jQuery(document).ready(function($) {
467 $('#cloudguard_remove_nag').click(function(e) {
468 var data = {action: 'cloudguard_nag_ajax'};
469 $.post(ajaxurl, data, function(response) {
470 //alert(response);
471 $('#cloudguard_nag_wrapper').fadeOut(500);
472 });
473 });
474 });
475 </script>
476 </div>
477 <?php
478 } // endif nag checker
479
480 }
481
482 } else {
483 echo '<p>'.sprintf(__('This widget will display recent login attempts blocked by <a href="%s" target="_blank">CloudGuard</a>.', 'cloudguard'), esc_url('https://wordpress.org/plugins/cloudguard/')).'</p>';
484 }
485 }
486
487
488 function cloudguard_nag_ajax_callback() {
489 update_option('cloudguard_nag', 1);
490 wp_die();
491 }
492 add_action('wp_ajax_cloudguard_nag_ajax', 'cloudguard_nag_ajax_callback');
493
494
495 function cloudguard_code_to_country($code){
496
497 $code = strtoupper($code);
498
499 $country_list = array(
500 'AF' => 'Afghanistan',
501 'AX' => 'Aland Islands',
502 'AL' => 'Albania',
503 'DZ' => 'Algeria',
504 'AS' => 'American Samoa',
505 'AD' => 'Andorra',
506 'AO' => 'Angola',
507 'AI' => 'Anguilla',
508 'AQ' => 'Antarctica',
509 'AG' => 'Antigua and Barbuda',
510 'AR' => 'Argentina',
511 'AM' => 'Armenia',
512 'AW' => 'Aruba',
513 'AU' => 'Australia',
514 'AT' => 'Austria',
515 'AZ' => 'Azerbaijan',
516 'BS' => 'Bahamas',
517 'BH' => 'Bahrain',
518 'BD' => 'Bangladesh',
519 'BB' => 'Barbados',
520 'BY' => 'Belarus',
521 'BE' => 'Belgium',
522 'BZ' => 'Belize',
523 'BJ' => 'Benin',
524 'BM' => 'Bermuda',
525 'BT' => 'Bhutan',
526 'BO' => 'Bolivia',
527 'BQ' => 'Bonaire, Saint Eustatius and Saba',
528 'BA' => 'Bosnia and Herzegovina',
529 'BW' => 'Botswana',
530 'BV' => 'Bouvet Island',
531 'BR' => 'Brazil',
532 'IO' => 'British Indian Ocean Territory',
533 'VG' => 'British Virgin Islands',
534 'BN' => 'Brunei',
535 'BG' => 'Bulgaria',
536 'BF' => 'Burkina Faso',
537 'BI' => 'Burundi',
538 'KH' => 'Cambodia',
539 'CM' => 'Cameroon',
540 'CA' => 'Canada',
541 'CV' => 'Cape Verde',
542 'KY' => 'Cayman Islands',
543 'CF' => 'Central African Republic',
544 'TD' => 'Chad',
545 'CL' => 'Chile',
546 'CN' => 'China',
547 'CX' => 'Christmas Island',
548 'CC' => 'Cocos Islands',
549 'CO' => 'Colombia',
550 'KM' => 'Comoros',
551 'CK' => 'Cook Islands',
552 'CR' => 'Costa Rica',
553 'HR' => 'Croatia',
554 'CU' => 'Cuba',
555 'CW' => 'Curacao',
556 'CY' => 'Cyprus',
557 'CZ' => 'Czech Republic',
558 'CD' => 'Democratic Republic of the Congo',
559 'DK' => 'Denmark',
560 'DJ' => 'Djibouti',
561 'DM' => 'Dominica',
562 'DO' => 'Dominican Republic',
563 'TL' => 'East Timor',
564 'EC' => 'Ecuador',
565 'EG' => 'Egypt',
566 'SV' => 'El Salvador',
567 'GQ' => 'Equatorial Guinea',
568 'ER' => 'Eritrea',
569 'EE' => 'Estonia',
570 'ET' => 'Ethiopia',
571 'FK' => 'Falkland Islands',
572 'FO' => 'Faroe Islands',
573 'FJ' => 'Fiji',
574 'FI' => 'Finland',
575 'FR' => 'France',
576 'GF' => 'French Guiana',
577 'PF' => 'French Polynesia',
578 'TF' => 'French Southern Territories',
579 'GA' => 'Gabon',
580 'GM' => 'Gambia',
581 'GE' => 'Georgia',
582 'DE' => 'Germany',
583 'GH' => 'Ghana',
584 'GI' => 'Gibraltar',
585 'GR' => 'Greece',
586 'GL' => 'Greenland',
587 'GD' => 'Grenada',
588 'GP' => 'Guadeloupe',
589 'GU' => 'Guam',
590 'GT' => 'Guatemala',
591 'GG' => 'Guernsey',
592 'GN' => 'Guinea',
593 'GW' => 'Guinea-Bissau',
594 'GY' => 'Guyana',
595 'HT' => 'Haiti',
596 'HM' => 'Heard Island and McDonald Islands',
597 'HN' => 'Honduras',
598 'HK' => 'Hong Kong',
599 'HU' => 'Hungary',
600 'IS' => 'Iceland',
601 'IN' => 'India',
602 'ID' => 'Indonesia',
603 'IR' => 'Iran',
604 'IQ' => 'Iraq',
605 'IE' => 'Ireland',
606 'IM' => 'Isle of Man',
607 'IL' => 'Israel',
608 'IT' => 'Italy',
609 'CI' => 'Ivory Coast',
610 'JM' => 'Jamaica',
611 'JP' => 'Japan',
612 'JE' => 'Jersey',
613 'JO' => 'Jordan',
614 'KZ' => 'Kazakhstan',
615 'KE' => 'Kenya',
616 'KI' => 'Kiribati',
617 'XK' => 'Kosovo',
618 'KW' => 'Kuwait',
619 'KG' => 'Kyrgyzstan',
620 'LA' => 'Laos',
621 'LV' => 'Latvia',
622 'LB' => 'Lebanon',
623 'LS' => 'Lesotho',
624 'LR' => 'Liberia',
625 'LY' => 'Libya',
626 'LI' => 'Liechtenstein',
627 'LT' => 'Lithuania',
628 'LU' => 'Luxembourg',
629 'MO' => 'Macao',
630 'MK' => 'Macedonia',
631 'MG' => 'Madagascar',
632 'MW' => 'Malawi',
633 'MY' => 'Malaysia',
634 'MV' => 'Maldives',
635 'ML' => 'Mali',
636 'MT' => 'Malta',
637 'MH' => 'Marshall Islands',
638 'MQ' => 'Martinique',
639 'MR' => 'Mauritania',
640 'MU' => 'Mauritius',
641 'YT' => 'Mayotte',
642 'MX' => 'Mexico',
643 'FM' => 'Micronesia',
644 'MD' => 'Moldova',
645 'MC' => 'Monaco',
646 'MN' => 'Mongolia',
647 'ME' => 'Montenegro',
648 'MS' => 'Montserrat',
649 'MA' => 'Morocco',
650 'MZ' => 'Mozambique',
651 'MM' => 'Myanmar',
652 'NA' => 'Namibia',
653 'NR' => 'Nauru',
654 'NP' => 'Nepal',
655 'NL' => 'Netherlands',
656 'NC' => 'New Caledonia',
657 'NZ' => 'New Zealand',
658 'NI' => 'Nicaragua',
659 'NE' => 'Niger',
660 'NG' => 'Nigeria',
661 'NU' => 'Niue',
662 'NF' => 'Norfolk Island',
663 'KP' => 'North Korea',
664 'MP' => 'Northern Mariana Islands',
665 'NO' => 'Norway',
666 'OM' => 'Oman',
667 'PK' => 'Pakistan',
668 'PW' => 'Palau',
669 'PS' => 'Palestinian Territory',
670 'PA' => 'Panama',
671 'PG' => 'Papua New Guinea',
672 'PY' => 'Paraguay',
673 'PE' => 'Peru',
674 'PH' => 'Philippines',
675 'PN' => 'Pitcairn',
676 'PL' => 'Poland',
677 'PT' => 'Portugal',
678 'PR' => 'Puerto Rico',
679 'QA' => 'Qatar',
680 'CG' => 'Republic of the Congo',
681 'RE' => 'Reunion',
682 'RO' => 'Romania',
683 'RU' => 'Russia',
684 'RW' => 'Rwanda',
685 'BL' => 'Saint Barthelemy',
686 'SH' => 'Saint Helena',
687 'KN' => 'Saint Kitts and Nevis',
688 'LC' => 'Saint Lucia',
689 'MF' => 'Saint Martin',
690 'PM' => 'Saint Pierre and Miquelon',
691 'VC' => 'Saint Vincent and the Grenadines',
692 'WS' => 'Samoa',
693 'SM' => 'San Marino',
694 'ST' => 'Sao Tome and Principe',
695 'SA' => 'Saudi Arabia',
696 'SN' => 'Senegal',
697 'RS' => 'Serbia',
698 'SC' => 'Seychelles',
699 'SL' => 'Sierra Leone',
700 'SG' => 'Singapore',
701 'SX' => 'Sint Maarten',
702 'SK' => 'Slovakia',
703 'SI' => 'Slovenia',
704 'SB' => 'Solomon Islands',
705 'SO' => 'Somalia',
706 'ZA' => 'South Africa',
707 'GS' => 'South Georgia and the South Sandwich Islands',
708 'KR' => 'South Korea',
709 'SS' => 'South Sudan',
710 'ES' => 'Spain',
711 'LK' => 'Sri Lanka',
712 'SD' => 'Sudan',
713 'SR' => 'Suriname',
714 'SJ' => 'Svalbard and Jan Mayen',
715 'SZ' => 'Swaziland',
716 'SE' => 'Sweden',
717 'CH' => 'Switzerland',
718 'SY' => 'Syria',
719 'TW' => 'Taiwan',
720 'TJ' => 'Tajikistan',
721 'TZ' => 'Tanzania',
722 'TH' => 'Thailand',
723 'TG' => 'Togo',
724 'TK' => 'Tokelau',
725 'TO' => 'Tonga',
726 'TT' => 'Trinidad and Tobago',
727 'TN' => 'Tunisia',
728 'TR' => 'Turkey',
729 'TM' => 'Turkmenistan',
730 'TC' => 'Turks and Caicos Islands',
731 'TV' => 'Tuvalu',
732 'VI' => 'U.S. Virgin Islands',
733 'UG' => 'Uganda',
734 'UA' => 'Ukraine',
735 'AE' => 'United Arab Emirates',
736 'GB' => 'United Kingdom',
737 'US' => 'United States',
738 'UM' => 'United States Minor Outlying Islands',
739 'UY' => 'Uruguay',
740 'UZ' => 'Uzbekistan',
741 'VU' => 'Vanuatu',
742 'VA' => 'Vatican',
743 'VE' => 'Venezuela',
744 'VN' => 'Vietnam',
745 'WF' => 'Wallis and Futuna',
746 'EH' => 'Western Sahara',
747 'YE' => 'Yemen',
748 'ZM' => 'Zambia',
749 'ZW' => 'Zimbabwe',
750 'T1' => 'TOR', // Cloudflare TOR
751 'XX' => 'Unknown', // Cloudflare unknown location
752 );
753
754 if (!isset($country_list[$code])) {
755 return $code;
756 }
757
758 return $country_list[$code];
759 }
760