Данные клиента в запросах PHP: IP, браузер, геолокация и другие параметры

Раздел: Веб-разработка на PHP -> Параметры HTTP-запроса и серверные данные

Сбор информации о клиенте: основные подходы

Наиболее надёжный и быстрый способ получить данные клиента в PHP это обращение к суперглобальному массиву $_SERVER. Он содержит ключи, передаваемые веб-сервером: IP‑адрес (REMOTE_ADDR), строку User‑Agent (HTTP_USER_AGENT), язык браузера (HTTP_ACCEPT_LANGUAGE), реферер (HTTP_REFERER) и другие заголовки. Пример базового сбора:

$ip = $_SERVER['REMOTE_ADDR'];
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'не указан';
$language = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'не указан';

Php get client (получить данные клиента в php)

Данный способ подходит для серверов, работающих напрямую с клиентом за одним соединением. Он не требует внешних запросов и модулей, поэтому быстр и универсален. Используется для логирования, персонализации контента, защиты от ботов (базовая проверка User‑Agent).

Как определить IP клиента, если сервер находится за прокси или балансировщиком?

Прямой REMOTE_ADDR показывает адрес последнего прокси. Чтобы получить исходный IP пользователя, нужно проанализировать заголовки X‑Forwarded‑For, X‑Real‑IP или Client‑IP. Пример функции:

function getClientIP() {
    $ipKeys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
    foreach ($ipKeys as $key) {
        if (!empty($_SERVER[$key])) {
            $ipList = explode(',', $_SERVER[$key]);
            $ip = trim($ipList[0]);
            if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip;
        }
    }
    return $_SERVER['REMOTE_ADDR'];
}

Php get url (получить url в php)

Цель: корректное логирование и аналитика в средах с CDN или обратными прокси. Проблема: злоумышленник может подставить произвольный заголовок, поэтому нужна дополнительная проверка доверенных источников (например, проверка IP балансировщика).

Типичная ошибка: полагаться только на X‑Forwarded‑For без валидации. Решение: сверять REMOTE_ADDR со списком доверенных IP своего прокси или использовать встроенную поддержку в конфигурации сервера (например, trusted_proxies в Nginx).

Как извлечь информацию о браузере и операционной системе из строки User‑Agent?

Строка User‑Agent содержит маркеры браузеров и ОС. Можно написать простой парсер на регулярных выражениях. Пример:

function parseUserAgent($ua) {
    $browser = 'Неизвестный';
    $os = 'Неизвестная';
    if (preg_match('/Firefox\/([\d.]+)/', $ua)) $browser = 'Firefox';
    elseif (preg_match('/Chrome\/([\d.]+)/', $ua)) $browser = 'Chrome';
    elseif (preg_match('/Safari\/([\d.]+)/', $ua)) $browser = 'Safari';
    if (preg_match('/Windows NT ([\d.]+)/', $ua, $m)) $os = 'Windows ' . $m[1];
    elseif (preg_match('/Mac OS X ([\d_]+)/', $ua, $m)) $os = 'Mac OS ' . str_replace('_', '.', $m[1]);
    return [$browser, $os];
}

Цель: адаптация интерфейса, загрузка совместимых скриптов, статистика. Проблема: User‑Agent легко подделывается, поэтому не стоит полагаться на него для критических решений.

Типичная ошибка: не учитывать мобильные версии браузеров и строки с множеством продуктов. Решение: использовать библиотеки (например, Mobile_Detect) или следить за порядком проверки регулярных выражений (от более специфичных к общим).

Как определить географическое положение клиента по IP‑адресу?

Для геолокации требуется внешний API или расширение PHP (GeoIP). Пример через ip‑api.com (бесплатный лимит):

$ip = getClientIP(); // функция из предыдущего примера
$response = file_get_contents("http://ip-api.com/json/{$ip}");
$data = json_decode($response, true);
if ($data['status'] === 'success') {
    $country = $data['country'];
    $city = $data['city'];
}

Цель: показывать контент, адаптированный под регион (валюта, язык, таймзона). Проблема: внешний запрос добавляет задержку; приватные/анонимные IP дают неточные данные; лимиты запросов.

Типичная ошибка: блокировать доступ из‑за ошибочной геолокации. Решение: кэшировать результат геолокации (например, в сессии или Memcached) и разрешить пользователю вручную изменить регион.

Как определить предпочитаемый язык пользователя из заголовка Accept‑Language?

Заголовок содержит коды языков с приоритетами (q‑фактор). Пример парсинга:

$langString = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'ru';
preg_match_all('/([a-z]{2}(?:-[A-Z]{2})?)(?:;q=([\d.]+))?/i', $langString, $matches);
$langs = array_combine($matches[1], $matches[2] ?: array_fill(0, count($matches[1]), 1));
arsort($langs);
$preferred = key($langs); // первый язык с наибольшим q

Цель: автоматический выбор языка интерфейса. Проблема: иногда заголовок отсутствует или содержит неожиданные коды.

Типичная ошибка: не учитывать fallback на язык по умолчанию. Решение: после парсинга проверить, поддерживается ли полученный язык приложением; если нет — использовать язык сервера.

Как определить, использует ли клиент мобильное устройство или настольный компьютер?

Мобильные браузеры часто содержат подстроки Mobile, Android и т.д. Пример:

$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
$isMobile = preg_match('/Mobile|Android|iPhone|iPad|iPod|Opera Mini|IEMobile/i', $ua);
if ($isMobile) {
    // показываем мобильную версию
}

Цель: адаптивный дизайн на стороне сервера. Проблема: некоторые планшеты (iPad) не всегда содержат Mobile. Решение: проверять конкретные модели или использовать библиотеку Mobile_Detect.

Типичная ошибка: полагаться только на ширину экрана (CSS) без серверной логики. Решение: комбинировать серверное определение с клиентским (JavaScript) для точности.

Расширенные примеры с пошаговым разбором

Пример 1: Извлечение реального IP с обработкой множества прокси

Код, который безопасно получает IP, игнорируя заголовки от недоверенных источников:

Пример
function getRealIP() {
    $trustedProxies = ['10.0.0.1', '192.168.1.1']; // IP обратных прокси
    $remoteAddr = $_SERVER['REMOTE_ADDR'];
    if (!in_array($remoteAddr, $trustedProxies)) {
        return $remoteAddr;
    }
    // Доверенный прокси — берём из X-Forwarded-For
    $forwarded = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
    $ips = explode(',', $forwarded);
    foreach ($ips as $ip) {
        $ip = trim($ip);
        if (filter_var($ip, FILTER_VALIDATE_IP)) {
            return $ip;
        }
    }
    return $remoteAddr;
}
$clientIP = getRealIP();
echo 'Клиентский IP: ' . $clientIP;
Клиентский IP: 203.0.113.45

В этом примере функция проверяет, является ли REMOTE_ADDR доверенным. Только в этом случае она считывает заголовок X-Forwarded-For, предотвращая подделку со стороны клиента.

Пример 2: Парсинг User-Agent с определением браузера и устройства

Подробный парсер, который определяет браузер, версию, ОС и является ли устройство мобильным:

Пример
$ua = 'Mozilla/5.0 (Linux; Android 12; SM-G998B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.128 Mobile Safari/537.36';
$data = [
    'browser' => 'Unknown',
    'browser_version' => '',
    'os' => 'Unknown',
    'is_mobile' => false
];
if (preg_match('/Chrome\/([\d.]+)/', $ua, $m)) {
    $data['browser'] = 'Chrome';
    $data['browser_version'] = $m[1];
} elseif (preg_match('/Firefox\/([\d.]+)/', $ua, $m)) {
    $data['browser'] = 'Firefox';
    $data['browser_version'] = $m[1];
}
if (preg_match('/Android (\d+(?:\.\d+)?)/', $ua, $m)) {
    $data['os'] = 'Android ' . $m[1];
} elseif (preg_match('/Windows NT (\d+(?:\.\d+)?)/', $ua, $m)) {
    $data['os'] = 'Windows ' . $m[1];
}
if (preg_match('/Mobile|Android|iPhone|iPod|Opera Mini|IEMobile/i', $ua)) {
    $data['is_mobile'] = true;
}
print_r($data);
Array
(
    [browser] => Chrome
    [browser_version] => 108.0.5359.128
    [os] => Android 12
    [is_mobile] => 1
)

Пример 3: Геолокация через IP с кэшированием в файл

Чтобы избежать частых запросов к API, результат сохраняется в файл на сутки:

Пример
function getGeoLocation($ip) {
    $cacheFile = __DIR__ . '/geo_cache/' . md5($ip) . '.json';
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 86400)) {
        return json_decode(file_get_contents($cacheFile), true);
    }
    $data = @json_decode(file_get_contents("http://ip-api.com/json/{$ip}"), true);
    if ($data && $data['status'] === 'success') {
        file_put_contents($cacheFile, json_encode($data));
        return $data;
    }
    return null;
}
$loc = getGeoLocation('8.8.8.8');
echo 'Страна: ' . ($loc['country'] ?? 'неизвестно');
Страна: United States

Кэширование существенно снижает нагрузку на внешний сервис и ускоряет повторные вызовы.

Пример 4: Детальный разбор Accept-Language с учётом качества

Функция, возвращающая отсортированный список языков с приоритетом:

Пример
function parseAcceptLanguage($header) {
    $langs = [];
    preg_match_all('/([a-z]{1,8}(?:-[a-zA-Z]{1,8})?)(?:;q=([\d.]+))?/i', $header, $matches, PREG_SET_ORDER);
    foreach ($matches as $m) {
        $q = isset($m[2]) ? (float)$m[2] : 1.0;
        $langs[$m[1]] = $q;
    }
    arsort($langs);
    return $langs;
}
$header = 'fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5';
$parsed = parseAcceptLanguage($header);
print_r($parsed);
Array
(
    [fr-CH] => 1
    [fr] => 0.9
    [en] => 0.8
    [de] => 0.7
    [*] => 0.5
)

Звёздочка (*) означает любой язык и имеет самый низкий приоритет. Для выбора языка интерфейса достаточно взять первый ключ, поддерживаемый приложением.

Получить данные клиента в PHP - comments

En
Php get client (php)