【问题标题】:PHP get real IP (proxy detection)PHP获取真实IP(代理检测)
【发布时间】:2011-07-22 05:24:02
【问题描述】:

我确实可以跟踪用户的“真实”IP,如果他有一个发送真实 IP 标头的代理...有没有更好的解决方案,甚至更多的标头?

由于这个函数在脚本中经常使用,它必须非常快,而且它似乎不在那个星座中:/

我提出了一些建议,但无法实现:

  • 把标题按顺序排列,什么是最“野外”使用的,以便函数快速完成
  • 让 IP 的 pre_match 检测更快

===

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'];
}

【问题讨论】:

  • ereg 已弃用。除此之外..您始终需要存储真实 ip 和“代理”ip,因为用户可以简单地自己添加这些标头。
  • 谢谢,用(可能更快的)preg_match 替换了 ereg 并添加了一个部分来检测,如果字段中有更多 IP,例如:en.wikipedia.org/wiki/X-Forwarded-For
  • 我的真实IP是192.168.0.81。我很好奇它有什么用吗?
  • “在脚本中经常使用”是什么意思?在脚本运行时是否有理由多次运行它?
  • 如果字段中有更多 IP,你会选择什么“IP”?为什么?

标签: php proxy detection


【解决方案1】:

如果代理发送标头,那么您可以获取客户端的原始 IP。如果代理没有,那么你不能。 不幸的是(或者幸运的是,取决于你的观点)它就是这么简单。

我在我们的 Intranet 上所做的是将“intranet.mydomain.com”重定向到网络服务器上的“intranet”,由于内部网络/DNS 配置,后者不使用代理...不知道你想做什么,但这可能有用。

您还可以在浏览器中设置排除列表...

【讨论】:

    【解决方案2】:

    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'];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-16
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 2013-10-02
      • 1970-01-01
      • 2020-05-31
      • 2011-06-08
      相关资源
      最近更新 更多