PHP如何获取系统的本地IP地址

113

我需要获取计算机的本地IP地址,例如192.*.... 是否可以使用PHP实现?

我需要获得运行该脚本的系统的IP地址,但我不需要外部IP地址,我需要它的本地网络卡地址。

23个回答

129

使用命令行

PHP < 5.3.0

$localIP = getHostByName(php_uname('n'));

PHP >= 5.3.0

$localIP = getHostByName(getHostName());


3
这是适用于我的解决方案,它避免了调用shell、操作系统命令和各种可能会打开安全漏洞或引发后续问题的东西。 - Dario Fumagalli
2
最佳响应通常来自于简单。就像这样。 - m3nda
1
@andras.tim 我喜欢简单的答案,但是当我运行你的脚本时,它没有返回我的机器IP地址,而是返回了我虚拟机中使用的IP地址..这可能是什么问题呢? - Scarl
3
在云托管环境中,这可能无法返回预期结果。因为每个主机都有超过2个IP地址。 - UnixAgain
2
即使存在eth0和wlan0设备并具有它们自己的DHCP分配地址,但对我来说这将返回127.0.0.1。 - Ryan Griggs
显示剩余4条评论

65
$_SERVER['SERVER_ADDR']

14
澄清:一台计算机可以有多个IP地址。此变量仅适用于HTTP,并包含虚拟主机运行的IP地址。鉴于问题表述含糊不清,很难确定这是否是预期答案。 - Álvaro González
1
我认为这是正确的,因为你总是需要分配的IP地址,那个正在响应你的。如果没有,你必须使用@andras.tim的答案,因为它告诉你系统的主要IP地址。 - m3nda
这正是我想要的,因为我的服务器在负载均衡器后面,所以 getHostName 不会返回站点的域名。 - Yep_It's_Me
如果您正在 Docker 容器内运行,则此方法无法正常工作。 - Freedo

36

这是一篇旧帖子,但可以使用以下方法获取:

function getLocalIp()
{ return gethostbyname(trim(`hostname`)); }
例如:
die( getLocalIp() );

在另一个网站上找到它,不要删除trim命令,否则你将获得计算机名称。

反引号(特殊引号): 它能够工作是因为PHP会尝试执行位于这些“特殊引号”(反引号)之间的任何内容作为shell命令,并返回结果输出。

gethostbyname(trim(`hostname`));

非常相似(但更有效率)的方式是:

$exec = exec("hostname"); //the "hostname" is a valid command in both windows and linux
$hostname = trim($exec); //remove any spaces before and after
$ip = gethostbyname($hostname); //resolves the hostname using local hosts resolver or DNS

8
由于使用了特殊引号,当你使用普通引号时它不能正常工作,而且如果你删除修剪命令,它甚至都不能正常工作。我知道这听起来很奇怪,但请不要因此而下票反对答案。请认真阅读答案。 - Codebeat
2
在 PHP 中,反引号(`)被称为执行运算符。在第一个代码块中所做的几乎与 exec 命令相同。请参阅 PHP: Execution Operators - Manual - Christiaan
2
这并不是最好的想法。gethostbyname 返回主机机器的环回 IP(例如 127.0.0.1)是可能且有效的。 - nobody
2
这对我帮助很大,我以为会有像 $_SERVER['REMOTE_ADDR']; 这样简单的 PHP 函数可用,但它并没有起作用,而这个解决方案却适用于我!!! - Pini Cheyni

31

获取本地机器的外部IP地址的可靠方法是查询路由表,尽管我们在PHP中没有直接的方法来做到这一点。

但是我们可以通过将UDP套接字绑定到公共地址并获取其地址,让系统为我们执行此操作:

$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_connect($sock, "8.8.8.8", 53);
socket_getsockname($sock, $name); // $name passed by reference

// This is the local machine's external IP address
$localAddr = $name;

socket_connect 不会引起网络流量,因为它是一个UDP套接字。


3
这个回答比其他的都好太多了。任何对 $_SERVER 数组的依赖都取决于它在 Apache 下运行。这个想法也适用于定时任务。我正在使用它来仅在服务器运行在暂存或生产局域网上时执行某些函数。完美! - Per
这是一个优雅的答案。我将其应用于管理Docker容器的脚本中,以获取我的主机在Docker网络上的IP地址: $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); socket_connect($sock, $this->getDockerMachineIp(), 53); - FatherShawn
我猜它更具可移植性。另外,重要的是要提到在PHP上安装和启用sokcets模块。 - Fabio Montefuscolo
是的,非常感谢 @Arnaud Le Blanc,这对我非常有帮助,我用这种技术得到了我的IP地址。 - Abid Ali

23

如果您的服务器是Linux,请尝试以下操作:

$command="/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'";
$localIP = exec ($command);
echo $localIP;

12
不完全正确。不能保证 eth0 是合适的接口。 - nobody
谢谢,这个对我非常有效。能够设置接口很有帮助! - Rahim Khoja
在我的情况下(WiFi本地网络中的本地IP),我不得不指定wlan0而不是eth0,并将'inet addr:'替换为'inet adr:',可能是由于我系统上使用的语言环境(fr_FR)。除此之外,这个答案就是我正在寻找的解决方案。谢谢! - sylbru
实际上,在我的终端(法语环境)中,'inet adr:' 是有效的,但在 PHP 脚本中,'inet addr:' 才是正确的值(英语环境,我猜)。 - sylbru

16

这要看你所谓的“本地”是指什么:

如果你指的是执行PHP代码的服务器/系统的地址,那么仍有两种途径可以讨论。如果PHP通过Web服务器运行,则可以通过读取$_SERVER['SERVER_ADDR']来获得服务器地址。如果PHP通过命令行界面运行,则可能需要执行ipconfig(Windows)/ifconfig(*nix)并使用grep查找地址。

如果你指的是网站访问者的远程地址,但不是他们的外部IP地址(因为你特别说了192.*),那么你就没办法了。NAT路由的整个目的就是隐藏该地址。你无法识别IP地址后面的单个计算机的本地地址,但是有一些技巧(用户代理,可能是MAC地址)可以帮助区分是否有多台计算机从同一个IP地址访问。


1
最后但并非最不重要的是,ipconfig/ifconfig 很可能会返回多个IP地址:因为一台计算机通常不只有一个地址。很棒的答案。 - Álvaro González
是的,NAT 的整个目的就是隐藏本地 IP。现在请查看 https://www.whatismyip.com/,他们知道你的内部 IP 地址,同时使用手机打开此网站,他们也知道你手机的本地 IP 地址。编辑:我正在使用 JioFi 路由器,在 Android 9 AOSP 基础 ROM 上使用移动数据。 - Rishabh Gusain

12

这很简单,其他回答把事情复杂化了。你只需要使用这种方法就可以获取本地和公共IP地址。

   <?php 
$publicIP = file_get_contents("http://ipecho.net/plain");
echo $publicIP;

$localIp = gethostbyname(gethostname());
echo $localIp;

?>

这对我在Ubuntu上并不起作用,我的wlo1有一个私有的ipv4 IP地址,这就是我需要的,而不是公共的。你的代码提供的是公共IP地址。那肯定不是我所知道的本地IP地址。问题是关于本地IP地址的。 - Dlaw

12

hostname(1) 可以告诉您 IP 地址:hostname --ip-address,或者根据 man 手册上的说法,最好使用 hostname --all-ip-addresses


9
你可以使用下面的 PHP 代码:
$localIP = getHostByName(getHostName());
  
// Displaying the address 
echo $localIP;

如果您想获取系统的IPv4地址,请尝试以下方法:
shell_exec("ip route get 1.2.3.4 | awk '{print $7}'")

7
你可以在Linux主机的CLI中以常规用户身份尝试此操作:
function get_local_ipv4() {
  $out = split(PHP_EOL,shell_exec("/sbin/ifconfig"));
  $local_addrs = array();
  $ifname = 'unknown';
  foreach($out as $str) {
    $matches = array();
    if(preg_match('/^([a-z0-9]+)(:\d{1,2})?(\s)+Link/',$str,$matches)) {
      $ifname = $matches[1];
      if(strlen($matches[2])>0) {
        $ifname .= $matches[2];
      }
    } elseif(preg_match('/inet addr:((?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3})\s/',$str,$matches)) {
      $local_addrs[$ifname] = $matches[1];
    }
  }
  return $local_addrs;
}

$addrs = get_local_ipv4();
var_export($addrs);

输出:

array (
  'eth0' => '192.168.1.1',
  'eth0:0' => '192.168.2.1',
  'lo' => '127.0.0.1',
  'vboxnet0' => '192.168.56.1',
)

array('bond0'=>'10.66.42.83','bond1'=>'主机IP地址','lo'=>'127.0.0.1', ) 我已经得到了这个代码。我将其添加到了PHP文件中。 - Straw Hat
好的回答,谢谢。split()函数自PHP 5.3.0版本起已被弃用,建议使用explode()代替。 - Thanu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接