14

Как получить IP-адрес клиента в PHP

14

Как мне получить IP-адрес клиента с помощью PHP?

Я хочу зафиксировать пользователя, который зашел на мой сайт, по его IP-адресу.

5 ответ(ов)

5

$_SERVER['REMOTE_ADDR'] может не содержать реальные IP-адреса клиентов, особенно если они подключены через прокси. В таком случае, вы получите IP-адрес прокси-сервера, что может быть именно тем, что вам нужно, в зависимости от вашей задачи с IP-адресами. Например, частный адрес RFC1918 не будет полезен, если вы хотите узнать, откуда исходит ваш трафик, или запомнить, с какого IP-адреса пользователь подключался в последний раз. В этих случаях более уместным будет сохранить публичный IP-адрес прокси или NAT-шлюза.

Существуют различные HTTP-заголовки, такие как X-Forwarded-For, которые могут быть установлены различными прокси-серверами. Проблема заключается в том, что это всего лишь HTTP-заголовки, которые может установить кто угодно. Гарантии о содержимом этих заголовков нет. $_SERVER['REMOTE_ADDR'] — это действительный физический IP-адрес, с которого веб-сервер получил соединение и на который будет отправлен ответ. Все остальные данные являются произвольной и добровольной информацией. Вы можете доверять этим данным только в одном случае: если вы контролируете прокси-сервер, который устанавливает этот заголовок. То есть, следует полагаться на эту информацию только если вы на 100% уверены в том, где и как был установлен заголовок.

Тем не менее, вот пример кода:

if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
    $ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $ip = $_SERVER['REMOTE_ADDR'];
}

Примечание редактора: Использование приведенного выше кода имеет потенциальные проблемы с безопасностью. Клиент может установить любую информацию в HTTP-заголовках (т.е. $_SERVER['HTTP_...) на произвольные значения. Поэтому гораздо надежнее использовать $_SERVER['REMOTE_ADDR'], поскольку это значение не может быть установлено пользователем.

2

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

echo $_SERVER['REMOTE_ADDR'];

$_SERVER['REMOTE_ADDR'] возвращает IP-адрес пользователя, отправившего запрос к вашему серверу. Это полезно для различных задач, таких как ведение логов, ограничение доступа и другие функциональности, связанные с безопасностью.

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

function getUserIP() {
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        // Если есть несколько IP через запятую, берем первый
        $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

echo getUserIP();

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

1

Вот более чистый пример кода, как получить IP-адрес пользователя:

$ip = $_SERVER['HTTP_CLIENT_IP'] 
   ? $_SERVER['HTTP_CLIENT_IP'] 
   : ($_SERVER['HTTP_X_FORWARDED_FOR'] 
        ? $_SERVER['HTTP_X_FORWARDED_FOR'] 
        : $_SERVER['REMOTE_ADDR']);

А вот более короткая версия, использующая оператор Эльвис:

$ip = $_SERVER['HTTP_CLIENT_IP'] 
   ? : ($_SERVER['HTTP_X_FORWARDED_FOR'] 
   ? : $_SERVER['REMOTE_ADDR']);

Также есть версия, использующая isset, чтобы избежать предупреждений (спасибо, @shasi kanth):

$ip = isset($_SERVER['HTTP_CLIENT_IP']) 
    ? $_SERVER['HTTP_CLIENT_IP'] 
    : (isset($_SERVER['HTTP_X_FORWARDED_FOR']) 
      ? $_SERVER['HTTP_X_FORWARDED_FOR'] 
      : $_SERVER['REMOTE_ADDR']);

Этот код поможет вам корректно получить IP-адрес пользователя, учитывая различные сценарии.

1

Эта информация должна содержаться в переменной $_SERVER['REMOTE_ADDR'].

0

Мой любимый подход реализован в Zend Framework 2. Этот фреймворк учитывает свойства $_SERVER, такие как HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP, REMOTE_ADDR, но при этом создает класс, позволяющий определить надежные прокси. Он возвращает один IP-адрес, а не массив, что, на мой взгляд, является наиболее правильным решением.

Вот пример реализации:

class RemoteAddress
{
    /**
     * Использовать ли адреса прокси или нет.
     *
     * По умолчанию этот параметр отключен — IP-адрес в основном необходим для повышения
     * безопасности. HTTP_* ненадежны, так как их можно легко подделать. Этот параметр можно включить
     * для большей гибкости, но если пользователь использует прокси для подключения к доверенным услугам,
     * это его личный риск. Единственным надежным полем для IP-адреса является $_SERVER['REMOTE_ADDR'].
     *
     * @var bool
     */
    protected $useProxy = false;

    /**
     * Список доверенных IP-адресов прокси
     *
     * @var array
     */
    protected $trustedProxies = array();

    /**
     * HTTP-заголовок для анализа на предмет прокси
     *
     * @var string
     */
    protected $proxyHeader = 'HTTP_X_FORWARDED_FOR';

    // [...]

    /**
     * Возвращает IP-адрес клиента.
     *
     * @return string IP-адрес.
     */
    public function getIpAddress()
    {
        $ip = $this->getIpAddressFromProxy();
        if ($ip) {
            return $ip;
        }

        // прямой IP-адрес
        if (isset($_SERVER['REMOTE_ADDR'])) {
            return $_SERVER['REMOTE_ADDR'];
        }

        return '';
    }

    /**
     * Пытается получить IP-адрес для проксированного клиента
     *
     * @see http://tools.ietf.org/html/draft-ietf-appsawg-http-forwarded-10#section-5.2
     * @return false|string
     */
    protected function getIpAddressFromProxy()
    {
        if (!$this->useProxy
            || (isset($_SERVER['REMOTE_ADDR']) && !in_array($_SERVER['REMOTE_ADDR'], $this->trustedProxies))
        ) {
            return false;
        }

        $header = $this->proxyHeader;
        if (!isset($_SERVER[$header]) || empty($_SERVER[$header])) {
            return false;
        }

        // Извлечение IP-адресов
        $ips = explode(',', $_SERVER[$header]);
        // обрезка, чтобы корректно сравнивать с доверенными прокси
        $ips = array_map('trim', $ips);
        // удаление доверенных IP-прокси
        $ips = array_diff($ips, $this->trustedProxies);

        // Остались хоть какие-то?
        if (empty($ips)) {
            return false;
        }

        // Поскольку мы удалили любые известные, доверенные прокси, крайний правый
        // адрес представляет собой первый IP, который мы не знаем — т.е. мы не знаем,
        // является ли он прокси-сервером или клиентом. Следовательно, мы рассматриваем его
        // как исходный IP.
        // @see http://en.wikipedia.org/wiki/X-Forwarded-For
        $ip = array_pop($ips);
        return $ip;
    }

    // [...]
}

Полный код можно найти здесь: https://raw.githubusercontent.com/zendframework/zend-http/master/src/PhpEnvironment/RemoteAddress.php

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь