【问题标题】:How do I get the external IP of my server using PHP?如何使用 PHP 获取服务器的外部 IP?
【发布时间】:2011-12-16 02:22:34
【问题描述】:

我经常听到有人说要使用“$_SERVER['SERVER_ADDR']”,但这会返回我服务器的 LAN IP(例如 192.168.1.100)。我想要外部IP。

【问题讨论】:

    标签: php ip


    【解决方案1】:

    如果您使用的是路由器,则无法通过传统 PHP 获取您的 ISP 指定的基础 IP 地址。获取外部 IP 的一种方法是找到一个服务,该服务将为您获取它并将地址回显给您。我找到了一个方便的服务。 http://ipecho.net/

    你可以使用:

    $realIP = file_get_contents("http://ipecho.net/plain");
    

    【讨论】:

    • 使用 ipecho.net 比解析 HTML 响应要好得多。此答案应被视为新接受的答案。
    • 前两句相互矛盾。不能有“没有办法”,然后是“唯一的办法”。此外,“ONLY”是一个非常强烈的词。
    【解决方案2】:

    只需查询返回您的 IP 地址的主机:

    $externalContent = file_get_contents('http://checkip.dyndns.com/');
    preg_match('/Current IP Address: \[?([:.0-9a-fA-F]+)\]?/', $externalContent, $m);
    $externalIp = $m[1];
    

    或者,设置一个只回显 IP 的服务,并像这样使用它:

    $externalIp = file_get_contents('http://yourdomain.example/ip/');
    

    通过简单地回显远程 IP 地址自行设置服务,或花钱请人托管。未经许可,请勿不要使用他人的服务器。以前,此答案与我的一项服务相关联,该服务现在每秒被多次点击。

    请注意,在具有一个或多个NATs 的 IP 网络中,您可能有多个外部 IP 地址。这只会给你其中之一。

    此外,此解决方案当然取决于可用的远程主机。但是,由于没有广泛实施的标准(没有 ISP,只有一些家庭路由器实施UPnP),没有其他方法可以获取您的外部 IP 地址。即使您可以与本地 NAT 通信,您也无法确定它后面是否有另一个 NAT。

    【讨论】:

    • 哦,是的,如果该网站离线怎么办?没错,你会被拧死的。
    • @WTP 好吧,你当然可以回退到另一个地址。但总的来说,如果您位于 NAT 或其他类型的隧道之后,则没有其他方法。
    • 如果您的应用程序中存在远程 IP 地址至关重要的功能,则应在某处的配置中设置它,而不是通过外部服务。
    • 这是“可悲的事实”。忘记超全局变量、环境变量或与主机相关的 IP,进行“真实”联系是获得实际 IP 的唯一方法。
    • @François [ 允许使用括号来分隔 IPv6 地址。最后的< 确实是可选的,如果格式发生变化,它会使代码更加健壮。
    【解决方案3】:

    我将添加一个解决方案,因为其他解决方案不太适合我,因为他们:

    • 需要在具有域名的服务器上运行,例如gethostbyname()(如果你考虑一下,如果你先验地知道,你实际上并没有问题)
    • 不能在 CLI 上使用(依赖 $_SERVER 中的某些内容由 Web 服务器设置)
    • 假设ifconfig输出的特定格式,可以包括多个非公共接口
    • 依赖于解析某人的网站(谁可能会消失,更改 URL,更改格式,开始对你撒谎等等,所有这些都没有通知)

    这是我的建议:

    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    $res = socket_connect($sock, '8.8.8.8', 53);
    // You might want error checking code here based on the value of $res
    socket_getsockname($sock, $addr);
    socket_shutdown($sock);
    socket_close($sock);
    
    echo $addr; // Ta-da! The IP address you're connecting from
    

    IP 地址有一个Google public DNS 服务器。我相信他们会在附近运行一段时间。你在那里使用什么地址并不重要,只要它是属于不介意随机连接尝试太多的人的公共 IP 地址(也许是你自己?)。

    这是基于我在 Python 中遇到类似问题时遇到的 answer


    P.S.:如果你的机器和互联网之间发生巫术,我不确定上述方法的效果如何。

    【讨论】:

    • 最佳选择! :)
    • 这应该被接受,其他解决方案也有效,但我怀疑它们在 10 年后仍然存在。谷歌肯定会存在一段时间......
    • 对不起,这并没有像上面的 ip6.me 版本那样给我公共地址。
    • 这给了我我的内部地址:(
    【解决方案4】:

    您可以从ip6.me 之类的服务中解析它:

    <?php
    
    // Pull contents from ip6.me
    $file = file_get_contents('http://ip6.me/');
    
    // Trim IP based on HTML formatting
    $pos = strpos( $file, '+3' ) + 3;
    $ip = substr( $file, $pos, strlen( $file ) );
    
    // Trim IP based on HTML formatting
    $pos = strpos( $ip, '</' );
    $ip = substr( $ip, 0, $pos );
    
    // Output the IP address of your box
    echo "My IP address is $ip";
    
    // Debug only -- all lines following can be removed
    echo "\r\n<br/>\r\n<br/>Full results from ip6.me:\r\n<br/>";
    echo $file;
    

    【讨论】:

    • 如 ip6.me 页面上的描述,您应该改用ip4.me 站点,因为在这种情况下,您(您客户的)浏览器可能没有 IPv6 连接并显示Page not found。跨度>
    【解决方案5】:

    你可以试试这个:

    $ip = gethostbyname('www.example.com');
    echo $ip;
    

    获取与您的域名关联的 IP 地址。

    【讨论】:

    • 这是不正确的,因为它正在获取您正在 ping 的域的 IP 地址,看起来像?
    • 它是正确的。不知道为什么会有这么多令人费解的答案。看来这应该是公认的。对于可移植性: $ip = gethostbyname($_SERVER['HTTP_HOST']);
    【解决方案6】:

    我知道这个问题已经很久很久了,但我在谷歌上搜索同样的东西并想添加我自己的“hack”。为此,您的 webrequest 必须来自外部 IP 地址,或者您必须将 $own_url 更改为对其自身执行外部请求的 url。

    关键是,如果您让脚本向自己发出请求,而不是获得它的外部 IP 地址。

    <?php
    if (isset($_GET['ip'])) {
        die($_SERVER['REMOTE_ADDR']);
    }
    $own_url = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
    $ExternalIP = file_get_contents($own_url.'?ip=1');
    echo $ExternalIP;
    ?>
    

    【讨论】:

    • 如果您的域名服务器像 Cloudflare、CloudDNS 等,这将不起作用。它将从主云域名服务器返回 IP,而不是您的服务器。
    【解决方案7】:

    我认为其他答案中有很多代码,但我的答案很短,但是您需要在shell中执行命令才能获取ip...

    但它又短又快,我认为...

    php 执行 bash > bash 运行 > bash 获取 ip > php 获取 ip

    echo shell_exec( "dig +short myip.opendns.com @resolver1.opendns.com");
    

    对不起我的英语,我希望它对你有帮助......

    参考:How can I get my external IP address in a shell script?

    【讨论】:

      【解决方案8】:

      这是一个旧线程,但为了它的价值,我添加了一个我使用的简单函数。它使用外部服务(这似乎是不可避免的),但它也提供备份服务和本地缓存以避免重复的 HTTP 调用。

      /*
      USAGE
      $ip = this_servers_public_ip(); // Get public IP, and store it locally for subsequent calls.
      $ip = this_servers_public_ip(true); // Force remote query and refresh local cache if exists.
      */
      function this_servers_public_ip($purge=false) {
          $local = sys_get_temp_dir().'/this.servers.public.ip';
          if ( $purge===true && realpath($local) ) {
              unlink($local);
          }
          if ( realpath($local) ) {
              return file_get_contents($local);
          }
          // Primary IP checker query.
          $ip = trim( file_get_contents('https://checkip.amazonaws.com') );
          if ( (filter_var($ip, FILTER_VALIDATE_IP) !== false) ) {
              file_put_contents($local,$ip);
              return $ip;
          }
          // Secondary IP checker query.
          $ip_json = trim( file_get_contents('https://ipinfo.io/json') );
          $ip_arr = json_decode($ip_json,true);
          $ip=$ip_arr['ip'];
          if ( (filter_var($ip, FILTER_VALIDATE_IP) !== false) ) {
              file_put_contents($local,$ip);
              return $ip;
          }
          return false; // Something went terribly wrong.
      }
      

      【讨论】:

      • 这看起来很棒!谢谢!
      【解决方案9】:

      如果您的服务器有域名,您可以 ping 或使用:

      $sMyServerIP = gethostbyname('yourdomain.com');
      echo $sMyServerIP;
      

      它将返回您的外部 IP 地址。

      【讨论】:

        【解决方案10】:

        假设您的 PHP 在 Linux 服务器上运行,您可以使用 PHP 的 exec 函数调用 ifconfig。这将提供公共 IP,而无需联系某些外部网站/服务。例如:

        $command = "ifconfig";  /// see notes below
        $interface = "eth0";    // 
        exec($command, $output);
        $output = implode("\n",$output);
        if ( preg_match('/'.preg_quote($interface).'(.+?)[\r\n]{2,}/s', $output, $ifaddrsMatch)
                && preg_match_all('/inet(6)? addr\s*\:\s*([a-z0-9\.\:\/]+)/is', $ifaddrsMatch[1], $ipMatches, PREG_SET_ORDER) )
        {
            foreach ( $ipMatches as $ipMatch ) 
                echo 'public IPv'.($ipMatch[1]==6?'6':'4').': '.$ipMatch[2].'<br>';
        }
        

        请注意,有时作为 $command 您必须指定 ifconfig 的完整路径。你可以通过执行找到这个

        ifconfig 在哪里

        来自 shell 提示符。此外,$interface 应该设置为您的服务器的主网络接口的名称,该接口具有到 WAN 的链接。

        在 Windows 上,你当然可以做类似的事情,使用 ipconfig 而不是 ifconfig(以及相应的调整正则表达式)。

        【讨论】:

          【解决方案11】:

          您也可以通过基于主机名或服务器名的 DNS A 记录获取 IP:

          $dnsARecord = dns_get_record($_SERVER['HTTP_HOST'],DNS_A);
          if ( $dnsARecord ) echo 'IPv4: '.$dnsARecord[0]['ip'];
          $dnsARecord = dns_get_record($_SERVER['HTTP_HOST'],DNS_AAAA);
          if ( $dnsARecord ) echo 'IPv6: '.$dnsARecord[0]['ip'];
          

          如果两者之一不能满足您的需求,您也可以使用 SERVER_NAME 而不是 HTTP_HOST。

          但是,这是假设您的服务器已根据 DNS 正确配置。情况可能并非总是如此。使用 ifconfig 查看我的其他答案可能更好。

          【讨论】:

            【解决方案12】:

            你试过了吗:

            gethostbyname(php_uname('n'));
            

            ?

            【讨论】:

            • php_uname('n') 在大多数情况下返回 internal IP 地址,即基于 LAN。 OP 要求一个外部
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-10-09
            • 2011-01-21
            • 2014-05-31
            • 1970-01-01
            • 2018-08-27
            • 2021-05-12
            • 1970-01-01
            相关资源
            最近更新 更多