【问题标题】:How to get Real IP from Visitor? [duplicate]如何从访客那里获得真实 IP? [复制]
【发布时间】:2012-11-18 18:15:27
【问题描述】:

我正在使用这个 PHP 代码来获取访问者的 IP 地址:

<?php echo $_SERVER['REMOTE_ADDR']; ?>

但是,当他们使用代理时,我无法从访问者那里获得真实的 IP 地址。。在这种情况下,有什么方法可以获取访问者的 IP 地址吗?

【问题讨论】:

标签: php ip


【解决方案1】:

试试这个 php 代码。

<?PHP

function getUserIP()
{
    // Get real visitor IP behind CloudFlare network
    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
              $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
              $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
    }
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];

    if(filter_var($client, FILTER_VALIDATE_IP))
    {
        $ip = $client;
    }
    elseif(filter_var($forward, FILTER_VALIDATE_IP))
    {
        $ip = $forward;
    }
    else
    {
        $ip = $remote;
    }

    return $ip;
}


$user_ip = getUserIP();

echo $user_ip; // Output IP address [Ex: 177.87.193.134]


?>

【讨论】:

  • 你也应该处理涉及多个代理的情况,为什么不呢?
  • 这很糟糕,因为HTTP_CLIENT_IPHTTP_X_FORWARDED_FOR 可以被伪造。只有REMOTE_ADDR 不能。
  • @Pradeep Kumar Prabaharan,是的。如果您在本地服务器上运行此代码,您将获得本地 ip,即 127.0.0.1 或 ::1
  • 是的,我在实时服务器上得到了输出
  • HTTP_X_FORWARDED_FOR 可以有多个 ip,例如 '1.1.1.1,2.2.2.2' 并且这个函数不处理它。阅读en.wikipedia.org/wiki/X-Forwarded-For
【解决方案2】:

这是我见过的最常见的技术:

function getUserIP() {
    if( array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) ) {
        if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',')>0) {
            $addr = explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']);
            return trim($addr[0]);
        } else {
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
    }
    else {
        return $_SERVER['REMOTE_ADDR'];
    }
}

请注意,它并不能保证您将始终获得正确的用户 IP,因为有很多方法可以隐藏它。

【讨论】:

  • 赞成。这是正确处理HTTP_X_FORWARDED_FOR 标头的少数解决方案之一,如果请求通过一个或多个代理(根据en.wikipedia.org/wiki/X-Forwarded-For#Format),该标头可能包含逗号分隔的列表(根据en.wikipedia.org/wiki/X-Forwarded-For#Format
  • 由于可以欺骗HTTP_X_FORWARDED_FOR 标头,因此最好使用filter_var(trim($addr), FILTER_VALIDATE_IP) 对其进行测试,以确保在返回它之前至少有一个有效的IP 地址。
  • 这是放在functions.php还是wp-config.php中?
  • @Garconis 没有人在这里没有提到过 WordPress
【解决方案3】:

这是我的方法:

 function getRealUserIp(){
    switch(true){
      case (!empty($_SERVER['HTTP_X_REAL_IP'])) : return $_SERVER['HTTP_X_REAL_IP'];
      case (!empty($_SERVER['HTTP_CLIENT_IP'])) : return $_SERVER['HTTP_CLIENT_IP'];
      case (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) : return $_SERVER['HTTP_X_FORWARDED_FOR'];
      default : return $_SERVER['REMOTE_ADDR'];
    }
 }

使用方法:

$ip = getRealUserIp();

【讨论】:

  • 这是一个非常奇怪和令人困惑的 switch 语句用法。 codethinked.com/dont-be-clever
  • 您认为究竟有什么令人困惑的地方?对我来说,这很清楚!
  • 这很令人困惑,因为这正是 if/elseif 的用途。
  • 如果您发现自己在使用 switch(true),请停止并使用 if 语句。这怎么可能被认为比公认的 if/else 更清楚?
  • 我认为这里switch语句的优势(?)是它在大多数语言中的预处理方式可以作为跳转表运行,并且在大数据或频繁使用的情况下,可以节省关于加工。但是,如果它不打算以高频率运行,则不应为了处理速度而牺牲清晰度。
【解决方案4】:

代理可能会发送 HTTP_X_FORWARDED_FOR 标头,但即使这样也是可选的。

另外请记住,访问者可能会共享 IP 地址;大学网络、大公司和第三世界/低预算 ISP 倾向于与许多用户共享 IP。

【讨论】:

  • 标头“规范”可以处理多个代理,ips链将在标头值中以逗号分隔
  • 只有一个音符。第三世界的 ISP 则相反。他们为每次登录创建动态 ip。所以每个用户有多个 ip,而不是多个用户一个 ip。
【解决方案5】:

应用此代码获取 IP 地址:

    if (getenv('HTTP_X_FORWARDED_FOR')) { $pipaddress = getenv('HTTP_X_FORWARDED_FOR');
 $ipaddress = getenv('REMOTE_ADDR'); 
    echo "Your Proxy IP address is : ".$pipaddress. "(via $ipaddress)" ; } 
    else { $ipaddress = getenv('REMOTE_ADDR'); echo "Your IP address is : $ipaddress"; }
    ------------------------------------------------------------------------

【讨论】:

    【解决方案6】:

    这是我的功能。

    好处:

    • 在 $_SERVER 不可用时工作。
    • 过滤私有和/或保留 IP;
    • 处理 X_FORWARDED_FOR 中所有转发的 IP
    • 与 CloudFlare 兼容
    • 如果没有找到有效的 IP,可以设置一个默认值!
    • 简短而简单!

    /**
     * Get real user ip
     *
     * Usage sample:
     * GetRealUserIp();
     * GetRealUserIp('ERROR',FILTER_FLAG_NO_RES_RANGE);
     * 
     * @param string $default default return value if no valid ip found
     * @param int    $filter_options filter options. default is FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
     *
     * @return string real user ip
     */
    
    function GetRealUserIp($default = NULL, $filter_options = 12582912) {
        $HTTP_X_FORWARDED_FOR = isset($_SERVER)? $_SERVER["HTTP_X_FORWARDED_FOR"]:getenv('HTTP_X_FORWARDED_FOR');
        $HTTP_CLIENT_IP = isset($_SERVER)?$_SERVER["HTTP_CLIENT_IP"]:getenv('HTTP_CLIENT_IP');
        $HTTP_CF_CONNECTING_IP = isset($_SERVER)?$_SERVER["HTTP_CF_CONNECTING_IP"]:getenv('HTTP_CF_CONNECTING_IP');
        $REMOTE_ADDR = isset($_SERVER)?$_SERVER["REMOTE_ADDR"]:getenv('REMOTE_ADDR');
    
        $all_ips = explode(",", "$HTTP_X_FORWARDED_FOR,$HTTP_CLIENT_IP,$HTTP_CF_CONNECTING_IP,$REMOTE_ADDR");
        foreach ($all_ips as $ip) {
            if ($ip = filter_var($ip, FILTER_VALIDATE_IP, $filter_options))
                break;
        }
        return $ip?$ip:$default;
    }
    

    【讨论】:

      【解决方案7】:

      如果Proxy是你信任的,你可以试试:(假设Proxy IP是151.101.2.10

      <?php
      
      $trustProxyIPs = ['151.101.2.10'];
      
      $clientIP  = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
      
      if (in_array($clientIP, $trustProxyIPs)) {
      
          $headers = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR'];
      
          foreach ($headers as $key => $header) {
      
              if (isset($_SERVER[$header]) && filter_var($_SERVER[$header], FILTER_VALIDATE_IP)) {
      
                  $clientIP = $_SERVER[$header];
      
                  break;
              }
          }
      }
      
      echo $clientIP;
      

      这将防止直接请求的客户端伪造转发标头,并通过受信任的代理获取真实 IP。

      【讨论】:

        【解决方案8】:

        是的,$_SERVER["HTTP_X_FORWARDED_FOR"] 是我在 nginx 服务器上的代理下查看我的 ip 的方式。

        但最好的办法是在代理下请求的页面上运行phpinfo(),这样您就可以查看所有可用变量并查看带有您真实 IP 的变量。

        【讨论】:

          【解决方案9】:

          这适用于 Windows 和 Linux!不管是本地主机还是在线..

              function getIP() {
              $ip = $_SERVER['SERVER_ADDR'];
          
              if (PHP_OS == 'WINNT'){
                  $ip = getHostByName(getHostName());
              }
          
              if (PHP_OS == 'Linux'){
                  $command="/sbin/ifconfig";
                  exec($command, $output);
                  // var_dump($output);
                  $pattern = '/inet addr:?([^ ]+)/';
          
                  $ip = array();
                  foreach ($output as $key => $subject) {
                      $result = preg_match_all($pattern, $subject, $subpattern);
                      if ($result == 1) {
                          if ($subpattern[1][0] != "127.0.0.1")
                          $ip = $subpattern[1][0];
                      }
                  //var_dump($subpattern);
                  }
              }
              return $ip;
          }
          

          【讨论】:

          • 这并不是每次都有效,因为操作系统比 Win 和 Linux 多。看看这个:stackoverflow.com/a/738893/2127296
          • 你是对的,该解决方案只适用于 linux 并获胜。 :)
          • 这将返回服务器的 IP 地址。不是访客的。该问题要求提供访问者的 IP 地址。
          • 投反对票,因为这会返回 SERVER 的 IP 地址,而不是 VISITOR 的 IP 地址。
          • 除了如其他所说的返回服务器IP,而问题显然不同,它使用exec(),并且没有理由太复杂。获取访问者的IP并不需要这么多。即使你用它来获取服务器IP,也应该是3行短代码,涵盖windows服务器和linux。
          猜你喜欢
          • 1970-01-01
          • 2013-03-28
          • 1970-01-01
          • 2011-01-23
          • 1970-01-01
          • 2011-11-11
          • 1970-01-01
          相关资源
          最近更新 更多