PHP получает реальный IP (обнаружение прокси)

Я отслеживаю «настоящий» IP-адрес пользователя, если у него есть прокси-сервер, который отправляет заголовок реального IP-адреса... есть ли у кого-нибудь лучшее решение или даже больше заголовков?

Так как эта функция очень часто используется в скрипте, то она должна быть очень быстрой, а в том созвездии ее не видно :/

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

  • расположите заголовки в том порядке, в котором они чаще всего используются «в дикой природе», чтобы функции быстро завершались
  • ускорение обнаружения pre_match для IP

===

function get_real_ip()
{
  $proxy_headers = array(
                          'CLIENT_IP', 
                          'FORWARDED', 
                          'FORWARDED_FOR', 
                          'FORWARDED_FOR_IP', 
                          'HTTP_CLIENT_IP', 
                          'HTTP_FORWARDED', 
                          'HTTP_FORWARDED_FOR', 
                          'HTTP_FORWARDED_FOR_IP', 
                          'HTTP_PC_REMOTE_ADDR', 
                          'HTTP_PROXY_CONNECTION',
                          'HTTP_VIA', 
                          'HTTP_X_FORWARDED', 
                          'HTTP_X_FORWARDED_FOR', 
                          'HTTP_X_FORWARDED_FOR_IP', 
                          'HTTP_X_IMFORWARDS', 
                          'HTTP_XROXY_CONNECTION', 
                          'VIA', 
                          'X_FORWARDED', 
                          'X_FORWARDED_FOR'
                         );

  foreach($proxy_headers as $proxy_header)
  {
    if(isset($_SERVER[$proxy_header]) && preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $_SERVER[$proxy_header])) /* HEADER ist gesetzt und dies ist eine gültige IP */
    {
        return $_SERVER[$proxy_header];
    }
    else if(stristr(',', $_SERVER[$proxy_header]) !== FALSE) /* Behandle mehrere IPs in einer Anfrage(z.B.: X-Forwarded-For: client1, proxy1, proxy2) */
    {
      $proxy_header_temp = trim(array_shift(explode(',', $_SERVER[$proxy_header]))); /* Teile in einzelne IPs, gib die letzte zurück und entferne Leerzeichen */

      if(($pos_temp = stripos($proxy_header_temp, ':')) !== FALSE) $proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp); /* Entferne den Port */

      if(preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $proxy_header_temp) return $proxy_header_temp;
    }
  }

  return $_SERVER['REMOTE_ADDR'];
}

person codex    schedule 24.03.2011    source источник
comment
ereg устарел. Кроме того, вам всегда нужно хранить как реальный IP-адрес, так и IP-адрес прокси-сервера, поскольку пользователи могут просто добавлять эти заголовки самостоятельно.   -  person ThiefMaster    schedule 24.03.2011
comment
Спасибо, заменил ereg на (возможно, более быстрый) preg_match и добавил часть для определения, содержит ли поле больше IP-адресов, например: en.wikipedia.org/wiki/X-Forwarded-For   -  person codex    schedule 24.03.2011
comment
Мой настоящий IP 192.168.0.81. интересно есть ли от него польза?   -  person Your Common Sense    schedule 24.03.2011
comment
что значит очень часто используется в сценарии? есть ли причина запускать его более одного раза во время выполнения скрипта?   -  person Your Common Sense    schedule 24.03.2011
comment
какой IP вы выберете, если в поле больше IP-адресов? Почему?   -  person Your Common Sense    schedule 24.03.2011
comment
он используется через ajax, но теперь есть причина, по которой он не должен быть быстрым и оптимизированным, даже если он используется только один раз ;) @ 192.168.0.81: действительно ли приведенный выше скрипт на веб-сервере говорит вам об этом? что-то не верится :Р   -  person codex    schedule 24.03.2011
comment
как сказано в en.wikipedia.org/wiki/X-Forwarded-For -› существует вероятность того, что в поле заголовка есть серверные IP-адреса, когда он передается через несколько прокси/клиентов, что теперь также обрабатывается   -  person codex    schedule 24.03.2011
comment
что не так с адресом 192.168.0.81? Как вы думаете, почему это невозможно увидеть в выводе скрипта? У тебя есть причина?   -  person Your Common Sense    schedule 24.03.2011
comment
На самом деле оптимизировать нужно только МЕДЛЕННО работающий код. Быстро работающий код уже быстр. Почему вы упомянули вызов ajax? в чем разница между обычным HTTP-запросом и AJAX с точки зрения сервера?   -  person Your Common Sense    schedule 24.03.2011
comment
Вы понимаете, что все эти причудливые HTTP-заголовки не имеют ничего общего с протоколом TCP/IP? Если да, то почему вы называете это IP-адресом, а не HTTP-заголовком?   -  person Your Common Sense    schedule 24.03.2011
comment
Хорошо, есть возможность перенаправить несколько IP-адресов для заголовка. какой вы выберете и почему?   -  person Your Common Sense    schedule 24.03.2011
comment
Хорошо, есть возможность перенаправить несколько IP-адресов для заголовка. какой из них вы собираетесь выбрать и почему? - я выбрал первое, так как определение википедии...   -  person codex    schedule 24.03.2011
comment
что не так с адресом 192.168.0.81? Как вы думаете, почему это невозможно увидеть в выводе скрипта? У тебя есть причина? - как я уже сказал, WEB-сервер (не локальный сервер) и определение диапазонов IP-адресов en.wikipedia .org/wiki/IP_address#IPv4_subnetting :P   -  person codex    schedule 24.03.2011
comment
На самом деле оптимизировать нужно только МЕДЛЕННО работающий код. Быстро работающий код уже быстр. Почему вы упомянули вызов ajax? в чем разница между обычным HTTP-запросом и AJAX с точки зрения сервера? - поскольку эта часть вызывается каждую секунду (на стороне пользователя через AJAX), это будет стоить серверу много ОЗУ/ЦП с большим количеством пользователей....!?!   -  person codex    schedule 24.03.2011
comment
ваша википедия неверна. нигде не определяется ни порядок, ни форма адреса, ни какой-либо другой формат этого необязательного заголовка.   -  person Your Common Sense    schedule 25.03.2011
comment
И что? что, если мой прокси находится в той же частной подсети?   -  person Your Common Sense    schedule 25.03.2011
comment
испытываете ли вы какие-либо проблемы с производительностью в данный момент? определяет ли IP-адрес пользователя единственное, что делает ваш скрипт? если нет - возможно, вам придется оптимизировать значимую часть кода, а не незначительную. почему вы думаете, что этот код будет стоить серверу много оперативной памяти/процессора? как насчет поиска в базе данных с большим количеством пользователей? разве это не остановит ваш сервер намного быстрее, чем эти несколько необязательных строковых операций?   -  person Your Common Sense    schedule 25.03.2011


Ответы (2)


Если прокси-сервер отправляет заголовок, вы можете получить исходный IP-адрес клиента. Если прокси нет, то и вы не сможете. К сожалению (или, может быть, к счастью, в зависимости от вашей точки зрения) это так просто.

Что я сделал в нашей интрасети, так это перенаправил «intranet.mydomain.com» на «интрасеть» на веб-сервере, последний не использует прокси-сервер из-за внутренней конфигурации сети / DNS ... Не знаю, что вы хотите сделать, но это может быть полезно.

Вы также можете установить список исключений в браузере...

person Martin Tournoij    schedule 24.03.2011

проверка регулярного выражения не удастся для адресов ipv6; поэтому я бы предпочел удалить это (или попытаться найти лучший RegEX).

также stripos($proxy_header_temp, ':') приведет к неожиданному поведению, например, для "::1" (localhost, ipv6).

мое предложение с указанными изменениями:

function getIp()
{
    $proxy_headers = array(
        'CLIENT_IP',
        'FORWARDED',
        'FORWARDED_FOR',
        'FORWARDED_FOR_IP',
        'HTTP_CLIENT_IP',
        'HTTP_FORWARDED',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED_FOR_IP',
        'HTTP_PC_REMOTE_ADDR',
        'HTTP_PROXY_CONNECTION',
        'HTTP_VIA',
        'HTTP_X_FORWARDED',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED_FOR_IP',
        'HTTP_X_IMFORWARDS',
        'HTTP_XROXY_CONNECTION',
        'VIA',
        'X_FORWARDED',
        'X_FORWARDED_FOR'
    );
    $regEx = "/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/";
    foreach ($proxy_headers as $proxy_header) {
        if (isset($_SERVER[$proxy_header])) {
            /* HEADER ist gesetzt und dies ist eine gültige IP */
            return $_SERVER[$proxy_header];
        } else if (stristr(',', $_SERVER[$proxy_header]) !== false) {
            // Behandle mehrere IPs in einer Anfrage
            //(z.B.: X-Forwarded-For: client1, proxy1, proxy2)
            $proxy_header_temp = trim(
                array_shift(explode(',', $_SERVER[$proxy_header]))
            ); /* Teile in einzelne IPs, gib die letzte zurück und entferne Leerzeichen */

            // if IPv4 address remove port if exists
            if (preg_match($regEx, $proxy_header_temp)
                && ($pos_temp = stripos($proxy_header_temp, ':')) !== false
            ) {
                $proxy_header_temp = substr($proxy_header_temp, 0, $pos_temp);
            }
            return $proxy_header_temp;
        }
    }

    return $_SERVER['REMOTE_ADDR'];
}
person tufan    schedule 07.11.2014