在軟件授權綁定、設備指紋識別、集群節點識別等場景中,需要獲取服務器網卡的物理 MAC 地址。本文提供一個支援 Windows (ipconfig) 和 Linux (ifconfig/ip) 的 PHP 類,通過解析系統命令輸出提取 MAC 地址。
<?php
class GetMacAddr {
private $returnArray = [];
private $macAddr = '';
/**
* 構造函數自動檢測系統並獲取 MAC
* @param string $osType PHP_OS 常量或自定義標識
* @return string MAC 地址或空字符串
*/
public function __construct($osType = PHP_OS) {
switch (strtolower($osType)) {
case 'linux':
case 'unix':
case 'freebsd':
case 'darwin': // macOS
$this->forLinux();
break;
case 'winnt':
case 'windows':
case 'cygwin':
$this->forWindows();
break;
default:
// 嘗試 Linux 命令作為兜底
$this->forLinux();
break;
}
$this->extractMac();
}
// Linux/Unix: ifconfig -a 或 ip link
private function forLinux() {
// 優先使用 ip 命令(現代發行版),回退 ifconfig
@exec("ip link show 2>/dev/null", $this->returnArray);
if (empty($this->returnArray)) {
@exec("ifconfig -a 2>/dev/null", $this->returnArray);
}
}
// Windows: ipconfig /all
private function forWindows() {
@exec("ipconfig /all 2>nul", $this->returnArray);
if (empty($this->returnArray)) {
$sysDir = getenv('SystemRoot') . '\\System32';
@exec("{$sysDir}\\ipconfig.exe /all 2>nul", $this->returnArray);
}
}
// 從命令輸出中提取 MAC 地址(正則匹配)
private function extractMac() {
$pattern = '/([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}/';
foreach ($this->returnArray as $line) {
if (preg_match($pattern, $line, $matches)) {
// 過濾掉 00:00:00:00:00:00 和 ff:ff:ff:ff:ff:ff
$mac = strtolower($matches[0]);
if ($mac !== '00:00:00:00:00:00' && $mac !== 'ff:ff:ff:ff:ff:ff') {
$this->macAddr = $mac;
break;
}
}
}
}
public function getMac() {
return $this->macAddr;
}
public function getAllOutput() {
return $this->returnArray;
}
}
// 使用示例
$mac = new GetMacAddr();
echo "MAC: " . $mac->getMac(); // 如 00:1a:2b:3c:4d:5e
ip link show1: lo:mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 00:1a:2b:3c:4d:5e brd ff:ff:ff:ff:ff:ff
正則匹配 link/ether 後的地址。
ifconfig -aeth0: flags=4163mtu 1500 inet 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255 ether 00:1a:2b:3c:4d:5e txqueuelen 1000 (Ethernet)
匹配 ether 後的地址。
ipconfig /allWindows IP Configuration Ethernet adapter Ethernet0: Physical Address. . . . . . . . . : 00-1A-2B-3C-4D-5E IPv4 Address. . . . . . . . . . . : 192.168.1.100
匹配 Physical Address 後的地址(連字符分隔)。
ifconfig/ipip link:ifconfig 在部分精簡系統(Alpine、容器)中缺失aa:bb:cc:dd:ee:ff2>/dev/null / 2>nul 抑制 stderr| 環境 | 要求 |
|---|---|
| PHP 配置 | disable_functions 不包含 exec/shell_exec |
| 安全模式 | safe_mode = Off (PHP 5.4+ 已移除) |
| 容器/Docker | 需 --cap-add=NET_ADMIN 或宿主網絡模式 --network host |
| 最小權限 | Web 用戶需可執行 ipconfig/ifconfig/ip |
<?php
function getMacLinuxSysfs() {
$netDir = '/sys/class/net';
if (!is_dir($netDir)) return '';
foreach (scandir($netDir) as $iface) {
if ($iface === 'lo' || $iface[0] === '.') continue;
$addrFile = "$netDir/$iface/address";
if (is_readable($addrFile)) {
$mac = trim(file_get_contents($addrFile));
if ($mac !== '00:00:00:00:00:00') {
return $mac;
}
}
}
return '';
}
✅ 無需 exec、無命令注入風險、容器友好、性能極高,Linux 專用首選方案。
ip route get 8.8.8.8 獲取默認路由網卡,提取對應 MAC