Потребность узнать с помощью PHP IP посетителя, а также его геолокацию на практике возникает нередко. Например, нам необходимо иметь возможность запрещать показ контента для пользователей из одного региона и разрешать для посетителей из другого. В этой статье мы рассмотрим, как узнать IP посетителя в PHP, и определим страну, код страны и город, используя API стороннего сервиса геолокации.
Как узнать IP посетителя в PHP
Информация об IP пользователя, который заходит на наш сайт, находится в суперглобальном массиве $_SERVER
. Если посетитель не использует прокси-сервер, его IP можно узнать, получив значение элемента массива $_SERVER
по ключу REMOTE_ADDR
:
// В переменную $ip будет присвоен ip-адрес посетителя $ip = $_SERVER['REMOTE_ADDR'];
В случае когда пользователь использует прокси, найти его реальный IP будет сложнее, так как $_SERVER['REMOTE_ADDR']
будет содержать адрес не посетителя, а прокси-сервера. В такой ситуации нужно проверить значения по двум другим ключам суперглобального массива — $_SERVER['HTTP_CLIENT_IP']
и $_SERVER['HTTP_X_FORWARDED_FOR']
. В них содержатся значения заголовков, которые устанавливаются прокси-сервером и могут иметь реальный IP пользователя.
Создадим функцию, которая определяет клиентский IP посетителя, использующего прокси-сервер. Если IP будет найден, вернем его, иначе возвратим null
:
function getUserIp() { $userIp = null; if (isset($_SERVER['HTTP_CLIENT_IP'])) { $userIp = $_SERVER['HTTP_CLIENT_IP']; } if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); // клиентский IP будет первым в списке, созданным прокси-сервером $userIp = $ips[0]; } if (isset($_SERVER['REMOTE_ADDR'])) { $userIp = $_SERVER['REMOTE_ADDR']; } if (filter_var($userIp, FILTER_VALIDATE_IP)) { return $userIp; } return null; } // Полученный ip будет находиться в переменной $userIp $userIp = getUserIp();
Стоит быть осторожным при работе с заголовками, устанавливаемых прокси-сервером. Это может быть небезопасно по причине того, что эти заголовки можно подделать.
Данные геолокации пользователя
Зная IP, можно получить различные данные геолокации пользователя: страну, город, географические координаты и так далее. Это можно сделать с помощью внешних сервисов, позволяющих получить такую информацию по их API.
Напишем небольшой класс для определения страны, кода страны и города пользователя, просматривающего сайт. А также разберем варианты использования этого класса.
Сперва получим IP текущего посетителя, затем, используя сервис ipstack, извлечем искомую информацию. Скрипт будет работать с IP-адресом, расположенном в $_SERVER['REMOTE_ADDR']
, то есть если пользователь просматривает статью, используя прокси, то сценарий будет использовать IP прокси-сервера.
Для работы с API сервиса нам нужен API-ключ. Чтобы его получить, перейдем на сайт ipstack.com и зарегистрируемся там:

Для демонстрации возможностей сервиса нам достаточно бесплатного тарифа. Нажмем на «GET FREE API KEY»:

Заполним регистрационную форму:

После успешной регистрации в личном кабинете найдем API-ключ и скопируем его. В последующем мы его будем использовать в нашей программе для отправки запросов на API сервиса:

Далее напишем класс PHP, который будет отвечать за получение данных геолокации с ipstack. В статический метод getGeoData
первым параметром будем передавать скопированный нами API-ключ. В качестве второго параметра будет IP-адрес — откроем возможность методу работать с любым IP, а не только с IP текущего пользователя. Первый параметр — обязательный. Если не передавать второй, скрипт возьмет IP из $_SERVER['REMOTE_ADDR']
:
class DemoGeoDataRetriever { public static function getGeoData(string $apiKey, string $ip = null) { // Если не передан API key // или IP не валидный (если он был передан), // не будем делать запрос, вернув null if ( empty($apiKey) || ($ip && !filter_var($ip, FILTER_VALIDATE_IP)) ) { return null; } // Если IP передан в параметре, будем работать с ним, // иначе возьмем IP текущего пользователя $ip = $ip ?? $_SERVER['REMOTE_ADDR']; // Подготовим URL для запроса, вставив в него IP и API-ключ $apiUrl = "http://api.ipstack.com/$ip?access_key=$apiKey"; // Получим JSON-данные $geoData = file_get_contents($apiUrl); // Сконвертируем данные в ассоциативный массив $result = json_decode($geoData, true); // Если запрос не будет удачным, API вернет массив с ключом success, который будет равен false // Когда запрос неуспешен, возращаем null if (isset($result['success']) && !$result['success']) { return null; } // Если все хорошо, вернем результат return $result; } } // Вызовем метод у класса, передав API-ключ, и результат сохраним в переменную $demoGeoDataResult = DemoGeoDataRetriever::getGeoData('ваш_api_ключ');
Теперь у нас есть массив с данными геолокации, и мы можем использовать его по своему усмотрению. Например, можно проверить, из какой страны зашел к нам пользователь, и разделить логику для посетителей из разных стран:
if (!empty($demoGeoDataResult) && isset($demoGeoDataResult['country_code'])) { if ($demoGeoDataResult['country_code'] === 'US') { // код для посетителей из США } else { // код для пользователей остальных стран } }
Либо выбрать нужные нам данные из массива и сгенерировать с ними HTML, используя, к примеру, шаблонизатор Twig.
Шаблон Twig, который будем использовать в примере, будет находиться в файле geo_data.twig
:
<div class='demoGeoLocation'> <ul> {% for key, option in geo_data %} <li><span>{{ key }}:</span> {{ option }}</li> {% endfor %} </ul> </div>
// Настройка Twig: // указание папки для размещения его шаблонов ("templates") $loader = new \Twig\Loader\FilesystemLoader('templates'); // создание объекта для рендеринга шаблонов $view = new \Twig\Environment($loader); // Создадим массив данных, которые хотим распечатать, // присвоив названия, под которыми они будут отображаться $labels = [ 'ip' => 'IP', 'country_name' => 'Название страны', 'country_code' => 'Код страны', 'city' => 'Город' ]; // Получим результат от API рассматриваемого сервиса $demoGeoDataResult = DemoGeoDataRetriever::getGeoData('ваш_api_ключ'); // Если массив с результатом пришел... if (!empty($demoGeoDataResult)) { // ...выберем из него только те данные, которые есть в массиве $labels... $dataToPrint = array_intersect_key($demoGeoDataResult, $labels); // ... и с помощью возможностей Twig сгенерируем HTML, передав новый массив с четырьмя элементами файлу geo_data.twig $twigHtml = $view->render('geo_data.twig', ['geo_data' => $dataToPrint]); // Переменная $twigHtml будет содержать результирующий HTML, который можно распечатать echo $twigHtml; }
Результат последнего примера для IP-адреса 8.8.8.8
(Google) будет выглядеть следующим образом:

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