如何使用 PHP 获取服务器的外部 IP?

发布于 2024-12-12 09:00:55 字数 99 浏览 3 评论 0原文

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

I often hear people say to use "$_SERVER['SERVER_ADDR']", but that returns the LAN IP of my server (e.g. 192.168.1.100). I want the external IP.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

拔了角的鹿 2024-12-19 09:00:55

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

您可以使用:

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

There is NO way to get your underlying IP Address that has been designated by your ISP via conventional PHP if you are using a router. A way to get the external IP is to find a service that will obtain it for you and echo the address back to you. I found a handy service which does just that. http://ipecho.net/

You can use:

$realIP = file_get_contents("http://ipecho.net/plain");
一杆小烟枪 2024-12-19 09:00:55

只需查询返回您的 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 地址自行设置该服务,或付费找人托管它。未经许可,不得使用他人的服务器。以前,这个答案链接到我的一个服务,现在每秒被多次点击。

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

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

Just query a host that returns your IP address:

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

or, set up a service that simply echoes just the IP, and use it like this:

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

Set up the service yourself by simply echoing the remote IP address, or pay someone to host it. Do not use somebody else's server without permission. Previously, this answer linked to a service of mine that's now being hit multiple times a second.

Note that in an IP network with one or more NATs, you may have multiple external IP addresses. This will give you just one of them.

Also, this solution of course depends on the remote host being available. However, since there is no widely implemented standard (no ISP and only some home routers implement UPnP), there is no other way to get your external IP address. Even if you could talk to your local NAT, you couldn't be sure that there isn't another NAT behind it.

洒一地阳光 2024-12-19 09:00:55

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

  • 需要在具有域名的服务器上运行,例如 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 公共 DNS 服务器。我相信他们会在附近运行一段时间。只要它的公共IP地址属于不介意随机连接尝试的人(也许是你自己?),那么你在那里使用什么地址并不重要。

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


PS:我不确定如果你的机器和互联网之间存在魔法,上面的方法效果如何。

I'm going to add a solution because the others weren't quite right for me because they:

  • need to be run on a server with a domain name e.g. gethostbyname() (if you think about it, you don't actually have the problem if you know this a priori)
  • can't be used on the CLI (rely on something in $_SERVER to be set by a web server)
  • assume a specific format of ifconfig output, which can include multiple non-public interfaces
  • depend on parsing someone's website (who may disappear, change the URL, change the format, start lying to you, etc, all without notice)

This is what I would suggest:

$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

The IP address there is a Google public DNS server. I trust they'll be around and running it for a while. It shouldn't really matter what address you use there as long as its a public IP address that belongs to someone who doesn't mind random connection attempts too much (yourself maybe?).

This is based on an answer I came across when I had a similar problem in Python.


P.S.: I'm not sure how well the above would work if there is sorcery going on between your machine and the internet.

为人所爱 2024-12-19 09:00:55

您可以从 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;

You could parse it from a service like 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;
愁杀 2024-12-19 09:00:55

您可以尝试以下操作:

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

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

You could try this:

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

to get the IP address associated with your domain name.

高冷爸爸 2024-12-19 09:00:55

我认为其他答案中有很多关于这个问题的代码,但我的答案很短,但是你需要在shell中执行命令来获取ip...

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

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

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

抱歉我的英语不好,希望对大家有帮助......

参考:如何在 shell 脚本中获取外部 IP 地址?

I think there is much code for this things in others answers, but my answer is short, but you need to execute a command in shell to get the ip...

but it is short and fast, I think that...

php execute bash > bash run > bash get ip > php get ip

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

Sorry my for my english, I hope it help all you...

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

昔梦 2024-12-19 09:00:55

我知道这个问题很老而且答案很长,但我在谷歌上搜索同样的东西并想添加我自己的“黑客”。为此,您的网络请求必须来自外部 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;
?>

I know this question is old and long answered, but I was googling for the same thing and want to add my own "hack". For this to work your webrequest has to come from an external IP address or you have to alter $own_url to a url that does an external request to itself.

The point is, if you let the script do a request to itself than you get it's external IP address.

<?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;
?>
蝶…霜飞 2024-12-19 09:00:55

这是一个旧线程,但就其价值而言,我添加了一个我使用的简单函数。它使用外部服务(这似乎是不可避免的),但它也提供备份服务和本地缓存以避免重复的 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.
}

This is an old thread, but for what it's worth, I'm adding a simple function that I use. It uses outside services (which is inevitable it seems), but it provides a backup service as well, and local caching to avoid repetitive HTTP calls.

/*
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.
}
小鸟爱天空丶 2024-12-19 09:00:55

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

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

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

If your server have a domain name you can ping it or you can use:

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

It will return your outer IP address.

水波映月 2024-12-19 09:00:55

假设您的 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 (以及相应的调整后的正则表达式)。

Assuming your PHP is running on a Linux server you can call ifconfig using PHP's exec function. This will give public IP without need to contact some external website/service. E.g.:

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

Note that sometimes as $command you have to specify full path of ifconfig. You can find this by executing

whereis ifconfig

from shell prompt. Furthermore $interface should be set to the name of your server's main network interface that has the link to the WAN.

On Windows you can do something similar of course, using ipconfig instead of ifconfig (and corresponding adjusted regex).

独﹏钓一江月 2024-12-19 09:00:55

此外,您还可以通过基于主机名或服务器名称的 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 查看我的其他答案,这可能更好。

Also you could get IP via DNS A record based on hostname or server name:

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

You could also use SERVER_NAME instead of HTTP_HOST if one of the two does not give what you want.

However, this is assuming that your server is configured correctly in correspondence with DNS. This may not always be the case. See my other answer using ifconfig that is perhaps better.

最好是你 2024-12-19 09:00:55

我想在这里添加另一种方式,因为我也想这样做,但这取决于您的网络结构。

如果您的服务器的流量直接到达外部世界,就像在具有专用外部 IP 的专用服务器中一样,那么很可能直接从网络接口获取流量,

echo json_encode(net_get_interfaces(), JSON_PRETTY_PRINT);

但是

{
    "lo": {
        "unicast": [
            {
                "flags": 65609,
                "family": 17
            },
            {
                "flags": 65609,
                "family": 2,
                "address": "127.0.0.1",
                "netmask": "255.0.0.0"
            },
            {
                "flags": 65609,
                "family": 10,
                "address": "::1",
                "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
            }
        ],
        "up": true
    },
    "enp7s0": {
        "unicast": [
            {
                "flags": 69699,
                "family": 17
            },
            {
                "flags": 69699,
                "family": 2,
                "address": "65.21.XX.XXX",
                "netmask": "255.255.255.255",
                "broadcast": "65.21.XX.XXX"
            },
            {
                "flags": 69699,
                "family": 10,
                "address": "2a01:4f9:3b:580d::2",
                "netmask": "ffff:ffff:ffff:ffff::"
            },
            {
                "flags": 69699,
                "family": 10,
                "address": "fe80::fe34:97ff:fe66:3294",
                "netmask": "ffff:ffff:ffff:ffff::"
            }
        ],
        "up": true
    },
    "docker0": {
        "unicast": [
            {
                "flags": 4099,
                "family": 17
            },
            {
                "flags": 4099,
                "family": 2,
                "address": "172.17.0.1",
                "netmask": "255.255.0.0",
                "broadcast": "172.17.255.255"
            }
        ],
        "up": true
    }
}

如果您位于虚拟机或虚拟容器中,并且您的容器的然后,流量由主机路由,或者如果您的流量通过不同的外部计算机路由,通常就像当您位于代理后面时,您只能像前面提到的示例一样从外部查询。

I'd like to add here another way as I was also looking to do this, but it depends on your network structure.

If your server's traffic is reaching the outside world directly like in a dedicated server with a dedicated external IP it's most likely possible to get it directly from the network interfaces

echo json_encode(net_get_interfaces(), JSON_PRETTY_PRINT);

Will yield

{
    "lo": {
        "unicast": [
            {
                "flags": 65609,
                "family": 17
            },
            {
                "flags": 65609,
                "family": 2,
                "address": "127.0.0.1",
                "netmask": "255.0.0.0"
            },
            {
                "flags": 65609,
                "family": 10,
                "address": "::1",
                "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
            }
        ],
        "up": true
    },
    "enp7s0": {
        "unicast": [
            {
                "flags": 69699,
                "family": 17
            },
            {
                "flags": 69699,
                "family": 2,
                "address": "65.21.XX.XXX",
                "netmask": "255.255.255.255",
                "broadcast": "65.21.XX.XXX"
            },
            {
                "flags": 69699,
                "family": 10,
                "address": "2a01:4f9:3b:580d::2",
                "netmask": "ffff:ffff:ffff:ffff::"
            },
            {
                "flags": 69699,
                "family": 10,
                "address": "fe80::fe34:97ff:fe66:3294",
                "netmask": "ffff:ffff:ffff:ffff::"
            }
        ],
        "up": true
    },
    "docker0": {
        "unicast": [
            {
                "flags": 4099,
                "family": 17
            },
            {
                "flags": 4099,
                "family": 2,
                "address": "172.17.0.1",
                "netmask": "255.255.0.0",
                "broadcast": "172.17.255.255"
            }
        ],
        "up": true
    }
}

But if you're in a virtual machine or a virtual container and your container's traffic is then routed by the host machine, or if your traffic is routed through a different external machine generally like when you're behind a proxy you can only query externally like the examples mentioned before.

奢欲 2024-12-19 09:00:55

你尝试过吗:

gethostbyname(php_uname('n'));

Have you tried:

gethostbyname(php_uname('n'));

?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文