Быстрый и надёжный хостинг на SSD-дисках от 165р в месяц   •   Реклама
10 360 просм
50 комм
Поделиться:

Как заблокировать доступ к сайту по определенной стране или городу на PHP?

Бывает, что по какой-то причине вам нужно ограничить доступ к вашему сайту тому или иному городу, стране. Например, ваш сайт имеет, по большей части, контент на русском языке, и вдруг вы замечаете подозрительный трафик из Китая, который сильно тормозит работу вашего сайта.

Чтобы заблокировать доступ к сайту для определенной страны или города, первое, что вам необходимо сделать – это получить IP пользователя, после чего получить необходимую информацию по нему, сделать проверку и в случае совпадения – заблокировать доступ.

А теперь перейдем от слов к практике.

Думаю, что не стоит напоминать, что на вашем сайте должна быть поддержка PHP.

1. Начинаем писать наш мини-модуль блокировки. Воспользуемся суперглобальным массивом «$_SERVER», который поможет вам определить IP адрес пользователя:

<?php

	header("Content-Type: text/html; charset=utf-8");

	if(isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { // Если сайт подключен к Cloudflare
	
		$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"];

	} else {

		$user_ip = $_SERVER["REMOTE_ADDR"];
	
	}

?>

2. На основе полученного IP необходимо определить, откуда наш посетитель. Для этого мы воспользуемся сервисом «freegeoip.net», который бесплатно, на основе IP, предоставит нам некоторую информацию о пользователе.

<?php

	header("Content-Type: text/html; charset=utf-8");
	
	if(isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { // Если сайт подключен к Cloudflare
	
		$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"];

	} else {

		$user_ip = $_SERVER["REMOTE_ADDR"];
	
	}

	$user_info = file_get_contents("http://freegeoip.net/json/".$user_ip);
	$user_info = json_decode($user_info);
	$user_country = $user_info->country_name;
	$user_city = $user_info->city;

?>

Здесь $user_country и $user_city содержат в себе название страны и города соответственно, которые указаны на английском языке.

На момент написания статьи сервис «freegeoip» был в рабочем состоянии. Если вдруг он перестал работать, воспользуйтесь следующими сервисами для получения информации о пользователе:

http://ipinfo.io 
http://xhanch.com/xhanch-api-ip-get-detail/ 
http://geoiplookup.net/ 
http://ip-api.com 
http://ipinfodb.com 

Обратите внимание, что при использовании этих сервисов необходимо внести корректировки в код.

3. Теперь сделаем проверку страны и заблокируем доступ, если страна совпала с указанной вами. На примере России итоговый скрипт будет выглядеть так:

<?php

	header("Content-Type: text/html; charset=utf-8");

	if(isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { // Если сайт подключен к Cloudflare
	
		$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"];

	} else {

		$user_ip = $_SERVER["REMOTE_ADDR"];
	
	}

	$user_info = file_get_contents("http://freegeoip.net/json/".$user_ip);
	$user_info = json_decode($user_info);
	$user_country = $user_info->country_name;
	$user_city = $user_info->city;

	if($user_country == "Russia") { // Проверяем страну посетителя

		@header("HTTP/1.1 503 Service Temporarily Unavailable");
		@header("Status: 503 Service Temporarily Unavailable");
   
		echo <<<HTML

			Извините, но для Вашей страны заблокирован доступ к нашему сайту =(
			
			<style>
				body {
					background: #f4f4f4;
				}
			</style>

HTML;

		die();

	}

?>

Между

echo <<<HTML

	… 

HTML;

вы можете указать любые HTML-теги, CSS-стили или скрипты и таким образом настроить нужное вам оформление для страницы блокировки.

Визуально итог работы нашего скрипта будет такой:

Как заблокировать доступ к сайту по определенной стране или городу на PHP?

Сам код нужно вставлять в самый верх темы вашего сайта, либо же подключать его через:

<?php
	
	include_once("/lock.php");
	
?>

Где «/lock.php» – название скрипта и полный путь до него на вашем хостинге. Для проверки работы скрипта посетите свой сайт через какой-нибудь анонимайзер, который предоставляет выбор страны, или же воспользуйтесь прокси-сервером.

50
комментариев
Форма комментирования этой статьи скрыта. Авторизуйтесь, чтобы расширить привилегии гостевого посещения и получить необходимую помощь от сообщества Pandoge.
    • 0
    1
      •  Пользователь
    6 мая в 11:51

    Артём здравствуйте! Сильно не пинайте, я во всем этом пока не силён, помогите пожалуйста, почитал все коменты но не понял как сделать.

    Мне нужно чтобы мой сайт не показывался в одном конкретном городе, например Москва. Если есть другой вариант, показывать сайт только в указаных городах то будет еще лучше.

    Подскажите как это сделать и куда этот получившийся код вставить.

    Очень и очень надо!

    Спасибо!

    • 0
    3
      •  Пользователь
    10 мая в 12:52

    Артем, подскажите, пожалуйста, а можно как-то закрыть часть страницы? Например, у меня на сайте стоит виджет ВК. Для пользователей с Украины он не отображается и сайт долго висит. Можно как-то сделать, чтобы всем, кроме Украины этот виджет отображался?

      • 0
      830
        •  Администратор
      11 мая в 01:15

      Павел, здравствуйте. Да, можно.

      Скажите какая CMS используется на сайте, подскажу как лучше можно сделать.

      • 0
      3
        •  Пользователь
      16 мая в 09:50

      Артем, использую DLE (Datalife Engine). Спасибо большое за помощь!

      • 0
      830
        •  Администратор
      20 мая в 01:56

      Павел, здравствуйте. Прошу прощения за поздний ответ.

      1. Подключаетесь к сайту по FTP.

      2. В папке /engine/modules/ создаете файл vk-widget.php. Сам файл заполните скриптом:

      <?php
      
      	/*
      	=====================================================
      	Автор: Артем Малков
      	-----------------------------------------------------
      	Назначение: Блокировка виджета VK
      	=====================================================
      	*/
      
      	if(!defined("DATALIFEENGINE")) {
      
        		die("Hacking attempt!");
      
      	}
      	
      	if(isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
      	
      		$user_ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
      
      	} else {
      
      		$user_ip = $_SERVER["REMOTE_ADDR"];
      	
      	}
      
      	$user_info = file_get_contents("http://ip-api.com/json/".$user_ip);
      	$user_info = json_decode($user_info);
      	$user_country = $user_info->country;
      
      	if($user_country != "Ukraine") {
      
      		echo <<<HTML
      
      			Здесь ваш полный код виджета от ВК
      
      HTML;
      
      }
      
      ?>

      Здесь ваш полный код виджета от ВК - замените на все скрипты от ВК.

      3. Далее, в шаблоне вашего сайта, в нужное место вставьте:

      {include file="engine/modules/vk-widget.php"}

      По необходимости очистите кэш сайта.

      • 0
      3
        •  Пользователь
      20 мая в 12:13

      Супер! Все работает! Спасибо вам огромное!

    • 0
    766
      •  Гости
    26 окт в 16:49

    Подскажите, возможно ли блокировать по региону? Скрипт работает через ip-api.com , заметил что там кроме страны и регион выдается. Попробовал заблокировать для пробы Калугу, но почему то не работает, хотя по стране продолжает блокировать. Сам скрипт такой:

    $user_ip = $_SERVER['REMOTE_ADDR'];

    $user_info = file_get_contents('http://ip-api.com/json/'.$user_ip);

    $user_info = json_decode($user_info);

    $user_country = $user_info->country;

    $user_region = $user_info->region;

    if($user_country == "Ukraine" || $user_region == "KLU")

      • 0
      830
        •  Администратор
      26 окт в 18:09

      Алексей, не совсем понял.

      Условие у Вас сейчас такое: если Украина или Калуга - блокируем.

      То есть блокировка происходит по любому из выполненных условий.

      Насчет этого: $user_region == "KLU"

      Ваш $user_region точно определяется как KLU?

      • 0
      766
        •  Гости
      26 окт в 18:35

      Артем, да все верно. С Украиной все работает, как надо.

      ip-api.com определяет $user_region как KLU, пробовал несколько прокси, думаю дело не в них. Также оставлял только одно условие с регионом, т.е. if($user_region == "KLU"), все равно почему то игнорирует условие. Пробовал делать не через region, а через regionName =="Kaluzhskaya oblast'", все равно пропускает. Кэш не забывал чистить перед каждой проверкой.

      • 0
      830
        •  Администратор
      14 янв в 02:25

      Алексей, а если вывести в коде

      var_dump($user_info);

      так же через прокси - что показывает?

      • 0
      766
        •  Гости
      26 окт в 19:31

      Артем, большое спасибо за наводку, разобрался в чем было дело.

      Выдало:

      bject(stdClass)#1 (14) { ["as"]=> string(24) "AS13335 Cloudflare, Inc." ["city"]=> string(17) "Frankfurt am Main" ["country"]=> string(7) "Germany" ["countryCode"]=> string(2) "DE" ["isp"]=> string(10) "Cloudflare" ["lat"]=> float(50.1153) ["lon"]=> float(8.6823) ["org"]=> string(10) "Cloudflare" ["query"]=> string(14) "162.158.90.140" ["region"]=> string(2) "HE" ["regionName"]=> string(5) "Hesse" ["status"]=> string(7) "success" ["timezone"]=> string(13) "Europe/Berlin" ["zip"]=> string(5) "60313" }

      Сайт через cloudflare работает и похоже при недоступности сайта он выдавал кэшированную версию файла страницы, ну или что-то в этом роде, пока не разобрался, но причину понял. Еще раз большое спасибо.

    • 0
    766
      •  Гости
    3 авг в 23:21

    Здравствуйте) Подскажите пожалуйста, установил этот скрипт, проверяю как на запрет доступа для России, так и запрет на все страны кроме России, при входе на сайт выдает ошибку HTTP ERROR 500 на любое из условий и текст предупреждения не выводится, что я не так сделал?)

      • 0
      830
        •  Администратор
      4 авг в 01:31

      Иван, в идеале - посмотреть бы на сайт и на код. И надо узнать, что Вам возвращает сервер при получении данных о пользователе.

    • 0
    766
      •  Гости
    13 июл в 12:28

    Привет, Артем! Я пытаюсь внедрить себе этот код в сайт, но сейчас «freegeoip.net» не работает, редиректит на ipstack.com/, просит регистрацию для получения АПИ ключа, зарегился, получил, сменил ссылку на

    $user_info = file_get_contents('http://api.ipstack.com/193.0.221.68?access_key=829e59d391b1338db09ded4ebce342d4&format=1'.$user_ip); не работает, пробовал другие сервисы.. тоже не работает(((

    Движок Опенкарт 2.3+

      • 0
      830
        •  Администратор
      13 июл в 15:40

      Max, а Вы увенены что не работает? Откройте ссылку в браузере - http://api.ipstack.com/193.0.221.68?access_key=829e59d391b1338db09ded4ebce342d4&format=1

      Ответ приходит.

      Обратите внимание, что IP пользователя подставляется в самое начало - /193.0.221.68?, а не в конец как у вас.

      • 0
      766
        •  Гости
      15 июл в 13:38

      Здравствуйте Артем, Схожая проблема как у Max. Пробовал подставить другие сервисы, а так же ipstack.com. Но результатов ни каких не было. До этого пользовался freegeoip.net все работала отлично. (Кстати спасибо вам за скрипт) . Но сейчас как-то не получается его запустить. Может быть у вас есть какие то аналоги? Делал тоже самое по сути как и мах касательно замены полей.

      • 0
      830
        •  Администратор
      16 июл в 12:52

      TT, мало просто заменить ссылку. Нужно посмотреть, что приходит от того или иного сервиса и переделывать под него код.

      На примере приведенного сервиса ip-api.com это буде выглядеть следующим образом:

      <?php

      header("Content-Type: text/html; charset=utf-8");

      $user_ip = $_SERVER['REMOTE_ADDR'];

      $user_info = file_get_contents('http://ip-api.com/json/'.$user_ip);

      $user_info = json_decode($user_info);

      $user_country = $user_info->country;

      $user_city = $user_info->city;

      echo "Ваша страна: ".$user_country."<br>Ваш город: ".$user_city;

      ?>

      • 0
      766
        •  Гости
      16 июл в 15:28

      Да, извините не указал это. Я проводил изменение полей $user_country = $user_info->country и $user_city = $user_info->city; а так же if($user_country == 'Russia') в соответствии с данными полей представленных в сервисах и подставлял их названия. Я так понимаю, этот скрипт предложенный выше должен показать вывод названия страны и города. Но даже при полном его копировании сайт начинает очень долго грузиться и не выдает названия ни города ни страны.=>"Ваша страна:

      Ваш город: " Или же если брать центральную его часть заменяя ранее содержимое кода он не выводит блокировку так же. Я все же еще поэкспериментирую с другими сервисами возможно я что то упустил из-за незнания. Благодарю вас. Если есть еще какие-то рекомендации и вам не сложно будет их дать я с радостью бы услышал.

      • 0
      830
        •  Администратор
      16 июл в 16:22

      Мне кажется, у вас проблемы с хостингом. Вот что мне выдал скрипт:

      Ваша страна: Russia

      Ваш город: Moscow

      Время выполнения: 0.12987089157104

      Это учитывая время его выполнения (то есть 1 доля секунды). Проверьте, что Вам возвращает:

      echo "Ваш IP: ".$_SERVER['REMOTE_ADDR'];

      • 0
      766
        •  Гости
      16 июл в 17:06

      Этот скрипт работает корректно вернуло мой ip. Кстати возможно какой то конфликт с http://ip-api.com/json. От того и долгая загрузка ибо с другими сервисами хоть и не работает но скорость загрузки не менялась.

      • 0
      830
        •  Администратор
      16 июл в 17:32

      TT, есть возможность предоставить доступы к Вашему хостингу? Проверю что к чему. Можно через комментарии.

      • 0
      766
        •  Гости
      16 июл в 17:33

      Удается выудить из скрипта только ip. Все остальные параметр игнорируются. В принципе если блокировать по названию страны не получиться . Можно ли создать диапазон всех ip адресов допустим РФ и при совпадении с массивом выдавать блокировку? Я использую этот код для блокирования отдельных новостей. Раньше скрипт работал пока сервис http://freegeoip.net/ не перестал работать.

      • 0
      830
        •  Администратор
      14 янв в 02:17

      TT, что в таком случае появляется на экране?

      <?php
      	
      	header("Content-Type: text/html;charset=utf-8");
      	
      	$user_ip = $_SERVER["REMOTE_ADDR"];
      	$user_info = file_get_contents("http://ip-api.com/json/".$user_ip);
      	
      	var_dump($user_info);
      	
      ?>
      • 0
      766
        •  Гости
      16 июл в 20:03

      Увы к хостингу доступ скорее всего не поучиться получить. Но вы уже достаточно помогли. Я примерно понял куда можно копать. Надеюсь что нибудь получиться сделать. Спасибо большое.

    • 0
    766
      •  Гости
    19 мая в 00:26

    "This API endpoint is deprecated and will stop working on July 1st, 2018. For more information please visit: https://github.com/apilayer/freegeoip#readme"

      • 0
      766
        •  Гости
      19 мая в 02:03

      <?php

      header("Content-Type: text/html; charset=utf-8");

      $user_ip = $_SERVER['REMOTE_ADDR'];

      $access_key = 'KEY';

      $user_info = file_get_contents('http://api.ipstack.com/'.$user_ip.'?access_key='.$access_key.'');

      $user_info = json_decode($user_info);

      $user_country = $user_info->country_name;

      $user_city = $user_info->city;

      if($user_country == 'Russia') { // Проверяем страну посетителя

      @header('HTTP/1.1 503 Service Temporarily Unavailable');

      @header('Status: 503 Service Temporarily Unavailable');

      echo <<<HTML

      Извините, но для Вашей страны заблокирован доступ к нашему сайту =(

      <style>

      body {

      background: #f4f4f4;

      }

      </style>

      HTML;

      exit();

      }

      ?>

    • 0
    766
      •  Гости
    13 мар в 14:14

    Спасибо за скрипт. Не подскажете, как добавить в исключения иностранные поисковые машины. Например доступ к сайту установлен только для России, но у нас пользуются не только Яндексом а и Гуглом, как минимум.

      • 5
      830
        •  Администратор
      14 мар в 02:26

      Ростислав, для этого, Вам нужно определить что посетитель Вашего сайта - робот, и если это так - не использовать для него этот скрипт.

      Чуть позже выложу функцию по определению поисковых роботов.

      • 0
      766
        •  Гости
      15 мар в 10:35

      Артем, заранее спасибо, мне это очень интересно.

      • 0
      766
        •  Гости
      23 мар в 11:46

      Никак не пойму почему это не срабатывает с анонимайзерами. Когда в скрипте указан доступ только для РФ, я захожу под немецким ип и сайт успешно загружается.

      • 1
      766
        •  Гости
      23 мар в 12:04

      И почему-то это не работает в опере, что с «турбо» что без

      • 5
      830
        •  Администратор
      14 янв в 02:05

      Ростислав, а что выводит

      echo $user_country;

      и

      echo $user_city;

      ?

      • 0
      766
        •  Гости
      23 мар в 12:50

      Спасибо за отзывчивость! Ниже приведён код который сейчас прописан в самом верху подключающегося на каждой странице header.php.

      Вывести значение переменной $user_country в консоль я не сумел потому сейчас он через эхо выводится в тело, ну Вы сами видите. А вот в яндексбраузере или опере эхо не выполняется, сайт загружается как обычно.

      <?php

      header("Content-Type: text/html; charset=utf-8");

      $user_ip = $_SERVER['REMOTE_ADDR'];

      $user_info = file_get_contents('http://freegeoip.net/json/'.$user_ip);

      $user_info = json_decode($user_info);

      $user_country = $user_info->country_name;

      $user_code = $user_info->country_code;

      if($user_country !== 'Russia' || $user_code !== 'RU' ) {

      @header('HTTP/1.1 503 Service Temporarily Unavailable');

      @header('Status: 503 Service Temporarily Unavailable');

      echo "Запрос отклонён" , "$user_country";

      exit();

      }else {

      echo "$user_country";

      }

      ?>

      • 5
      830
        •  Администратор
      23 мар в 13:07

      Скопировал ваш код - все работает. Что у Вас за CMS? Анонимайзер через который проверяю - noblockme

      • 0
      766
        •  Гости
      23 мар в 13:21

      Артем, да, код в порядке, видимо я неправильно его вставляю. wordpress.

      Дело в том что я проверял работу будучи авторизованным как администратор, в то время как в других браузерах не авторизовался. Сейчас проверил, и получается когда я авторизован код выполняется, а без авторизации - нет. Не в тот header получается вставляю код. Хотя он срабатывал когда я просил знакомых из зарубежья проверить доступен ли сайт, странно.

      • 0
      766
        •  Гости
      23 мар в 14:04

      Прошу прощения, всё дело было в кэше. Спасибо за код! Жду с нетерпением способ отличать роботов, надо попробовать поискать, возможно у того же гугла есть свои постоянные айпишники и добавить их в условия.

    • 1
    766
      •  Гости
    6 фев в 12:41

    Не работает скрипт

      • 10
      830
        •  Администратор
      6 фев в 20:59

      влад, скрипт рабочий на 100%. Проверяйте корректность использования.

    • 0
    766
      •  Гости
    4 фев в 11:41

    у меня такой вопрос, у меня движок dle 12.0 и при загрузке фото появляется на ней надпись (DataLife Engine) как её убрать?

      • 5
      830
        •  Администратор
      4 фев в 14:30

      Сергей, У нас есть полезная статья на эту тему. Почитать можно здесь - https://www.pandoge.com/stati_i_sovety/nastroyka-vodyanogo-znaka-watermark-v-dle

    • 1
    766
      •  Гости
    1 фев в 22:45

    Здравствуйте!

    А как например, открыть доступ только для нескольких городов России, а для всех остальных закрыть?

    Например, закрыть для всех, кроме Москва и Санкт-Петербурга (города чисто для примера взял :-) )

      • 5
      830
        •  Администратор
      14 янв в 01:58

      Павел, На примере той же России.

      Если строка:

      if($user_country == "Russia") {

      делает запрет на Россию, то:

      if($user_country != "Russia") {

      запрещает всем, кроме России и так далее.

      • 0
      766
        •  Гости
      2 фев в 17:00

      Спасибо за ответ, а этот скрипт от роботов не закрывает индексацию?

      И второй вопрос по строке:

      if($user_country !== 'Russia') {

      если две страны, то как их правильно перечислить?

      • 5
      830
        •  Администратор
      14 янв в 01:58

      Павел, если IP робота относиться к запрещенному региону - то наверное запретит.

      Для двух:

      if($user_country != "Russia" || $user_country != "Ukraine") {

      и так далее.

      • 0
      766
        •  Гости
      3 фев в 22:09

      А $user_country и $user_city будут правильно работать для http://ipgeobase.ru ?

      Заметил, что этот сайт более стабильней определяет и работает.

      Или там другие переменные?

      • 10
      830
        •  Администратор
      4 фев в 02:15

      Павел, если я не ошибаюсь - этот сайт в принципе не предоставляет данные для скриптов. То есть, в данном случае код из статьи не будет работать.

      • 0
      766
        •  Гости
      7 сен в 17:19

      С функцией для определения робота что-нибудь известно?

      • 0
      830
        •  Администратор
      7 сен в 18:17

      Павел, что именно?

      • 0
      766
        •  Гости
      9 сен в 21:04

      Заметил, что freegeoip.net теперь редиректит на другой сайт, и не определяет город.

      А для https://ipinfo.io другой код?

      По роботам известно, как их не запретить?

      • 0
      830
        •  Администратор
      10 сен в 13:42

      Павел, для того, чтобы адаптировать код - просто смотрите что возвращает сервер и делайте по аналогии с примером.

      Что касается роботов - внедряйте эту функцию https://www.pandoge.com/stati_i_sovety/kak-opredelit-chto-posetitel-vashego-sayta-poiskovyy-robot-a-ne-chelovek-na-php

Подняться наверх
«Pandoge» - помощник вебмастера