Linux下PHP无法执行ifconfig等命令是因www-data用户权限不足,应读取/proc/net/fib_trie获取IPv4地址;Windows下ipconfig乱码需用iconv('GBK','UTF-8//IGNORE')转换;勿用$_SERVER['REMOTE_ADDR']或gethostbyname()获取本机IP,推荐net_get_interfaces()或hostname -I。

Permission denied:exec('ifconfig') 或 shell_exec('ip addr') 失败
这不是 PHP 问题,是 Linux 权限机制在拦你——www-data(或 nginx/apache)这类低权限用户默认被禁止执行网络管理命令。
- 典型报错:
Warning: exec(): Unable to fork [ifconfig]或直接返回空 +Permission denied -
sudo没用:PHP 进程无法交互输密码,且sudoers默认不允许可执行网络命令 - 所有 shell 调用函数都受同一限制:
exec、shell_exec、system、passthru - 真正安全的替代方案是绕过命令行,改读内核暴露的只读文件:
/proc/net/fib_trie(所有用户可读,含全部 IPv4 绑定地址)
示例(提取第一个非回环 IPv4):
function getLocalIP() {
$trie = @file_get_contents('/proc/net/fib_trie');
if (!$trie) return '127.0.0.1';
preg_match_all('/\s+([\d.]+)\s+.*?ipv4_local_addr/', $trie, $matches);
foreach ($matches[1] as $ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && $ip !== '127.0.0.1') {
return $ip;
}
}
return '127.0.0.1';
}
返回乱码:exec('ipconfig') 在 Windows 上输出中文方块
不是 PHP 崩了,是编码对不上——中文 Windows 的 ipconfig 默认输出 GBK,而 PHP 脚本环境基本是 UTF-8,直接 echo 就会显示为问号或方块。
- 别碰
mb_convert_encoding($_SERVER['...'], ...):这些变量本身是纯 ASCII,转码反而引入错误 - 修复方式只有两种:
iconv('GBK', 'UTF-8//IGNORE', $output)(推荐),或强制 cmd 切 UTF-8:chcp 65001 && ipconfig - 正则提取 IP 时,优先匹配 IPv4:
/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,避开 IPv6 和中文字段干扰
返回空或 127.0.0.1:误用 $_SERVER['REMOTE_ADDR'] 或 gethostbyname(gethostname())
这两个是最常踩的坑:$_SERVER['REMOTE_ADDR'] 是客户端 IP,不是服务器本机 IP;gethostbyname(gethostname()) 在 Docker 容器或 /etc/hosts 映射为 127.0.0.1 的环境里必然失效。
立即学习“PHP免费学习笔记(深入)”;
- 查本机 IP,请别碰
$_SERVER里的任何REMOTE_*或HTTP_*字段 - 容器中
gethostbyname()返回127.0.0.1是正常现象,说明主机名没解析到真实网卡 - Linux 下更可靠的是
exec('hostname -I')(注意空格分隔,需trim()+explode()) - PHP 7.4+ 可用
net_get_interfaces()直接取接口列表,过滤掉lo、docker0后拿ipv4[0]
IPv6 地址显示为 ::1 或一堆符号
不是乱码,是浏览器或终端把 IPv6 地址当 UTF-8 字符串渲染失败了——::1 是标准 IPv6 环回地址,fe80::1 是链路本地地址,它们本身合法,只是显示异常。
- 如果业务只要 IPv4,所有提取逻辑必须加
FILTER_FLAG_IPV4校验,别依赖肉眼判断 -
gethostbynamel()可返回 IPv6 地址数组,但需手动遍历并用filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)筛选 - 避免用
$_SERVER['SERVER_ADDR']作本机 IP 判断:它可能为空、可能是 IPv6、也可能被虚拟主机配置覆盖
最麻烦的其实是场景混淆:你要的是监听地址?出口地址?还是绑定在 eth0 上的真实内网 IP?不同需求对应完全不同的获取路径,混用一个函数硬套,十次有九次掉坑里。











