首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Windows 系統信息採集:基於 WMI 查詢 CPU、內存、磁盤、啟動時間

     編輯:PHP 相關知識

Windows 系統信息來源

Windows 通過 WMI (Windows Management Instrumentation) 暴露系統管理數據,PHP 可透過 COM 組件調用 WMI 查詢語言 (WQL) 獲取豐富指標。

完整實現類

<?php
/**
 * Windows 系統信息採集器 (基於 WMI)
 * 需啟用 php_com_dotnet 擴展,且運行用戶有 WMI 查詢權限
 */
class WindowsSysInfo {
    private $wmi;

    public function __construct() {
        if (!class_exists('COM')) {
            throw new Exception('COM 擴展未啟用,請在 php.ini 中開啟 extension=com_dotnet');
        }
        try {
            $locator = new COM('WbemScripting.SWbemLocator');
            $this->wmi = $locator->ConnectServer('.', 'root\\cimv2');
        } catch (com_exception $e) {
            throw new Exception('WMI 連接失敗:' . $e->getMessage());
        }
    }

    public function get(): array {
        return [
            'cpu' => $this->getCpuInfo(),
            'memory' => $this->getMemoryInfo(),
            'swap' => $this->getSwapInfo(),
            'disk' => $this->getDiskInfo(),
            'os' => $this->getOsInfo(),
            'uptime' => $this->getUptime(),
        ];
    }

    /** 通用 WQL 查詢封裝 */
    private function query(string $wql, array $properties = []): array {
        $results = [];
        try {
            $objSet = $this->wmi->ExecQuery($wql);
            foreach ($objSet as $obj) {
                $item = [];
                if (empty($properties)) {
                    // 獲取所有屬性
                    foreach ($obj->Properties_ as $prop) {
                        $item[$prop->Name] = $prop->Value;
                    }
                } else {
                    foreach ($properties as $prop) {
                        $item[$prop] = $obj->$prop ?? null;
                    }
                }
                $results[] = $item;
            }
        } catch (com_exception $e) {
            // 忽略單個查詢失敗
        }
        return $results;
    }

    private function getCpuInfo(): array {
        $data = $this->query(
            'SELECT Name, NumberOfCores, NumberOfLogicalProcessors, L2CacheSize, MaxClockSpeed FROM Win32_Processor',
            ['Name', 'NumberOfCores', 'NumberOfLogicalProcessors', 'L2CacheSize', 'MaxClockSpeed']
        );
        $cpu = ['cores' => 0, 'logical' => 0, 'model' => '', 'cache_mb' => 0, 'max_mhz' => 0];
        foreach ($data as $proc) {
            $cpu['cores'] += $proc['NumberOfCores'] ?? 0;
            $cpu['logical'] += $proc['NumberOfLogicalProcessors'] ?? 0;
            $cpu['model'] = $proc['Name'] ?? 'Unknown';
            $cpu['cache_mb'] = round(($proc['L2CacheSize'] ?? 0) / 1024, 2); // KB -> MB
            $cpu['max_mhz'] = $proc['MaxClockSpeed'] ?? 0;
        }
        return $cpu;
    }

    private function getMemoryInfo(): array {
        $data = $this->query(
            'SELECT TotalVisibleMemorySize, FreePhysicalMemory FROM Win32_OperatingSystem',
            ['TotalVisibleMemorySize', 'FreePhysicalMemory']
        );
        $mem = ['total_mb' => 0, 'free_mb' => 0, 'used_mb' => 0, 'percent' => 0];
        if ($data) {
            $totalKb = $data[0]['TotalVisibleMemorySize'] ?? 0;
            $freeKb = $data[0]['FreePhysicalMemory'] ?? 0;
            $mem['total_mb'] = round($totalKb / 1024, 2);
            $mem['free_mb'] = round($freeKb / 1024, 2);
            $mem['used_mb'] = $mem['total_mb'] - $mem['free_mb'];
            $mem['percent'] = $mem['total_mb'] > 0 ? round($mem['used_mb'] / $mem['total_mb'] * 100, 2) : 0;
        }
        return $mem;
    }

    private function getSwapInfo(): array {
        $data = $this->query(
            'SELECT AllocatedBaseSize, CurrentUsage FROM Win32_PageFileUsage',
            ['AllocatedBaseSize', 'CurrentUsage']
        );
        $swap = ['total_mb' => 0, 'used_mb' => 0, 'free_mb' => 0, 'percent' => 0];
        foreach ($data as $pf) {
            $swap['total_mb'] += round(($pf['AllocatedBaseSize'] ?? 0), 2); // 已是 MB
            $swap['used_mb'] += round(($pf['CurrentUsage'] ?? 0), 2);
        }
        $swap['free_mb'] = $swap['total_mb'] - $swap['used_mb'];
        $swap['percent'] = $swap['total_mb'] > 0 ? round($swap['used_mb'] / $swap['total_mb'] * 100, 2) : 0;
        return $swap;
    }

    private function getDiskInfo(): array {
        $data = $this->query(
            'SELECT DeviceID, Size, FreeSpace, VolumeName FROM Win32_LogicalDisk WHERE DriveType = 3',
            ['DeviceID', 'Size', 'FreeSpace', 'VolumeName']
        );
        $disks = [];
        foreach ($data as $disk) {
            $size = $disk['Size'] ?? 0;
            $free = $disk['FreeSpace'] ?? 0;
            $disks[] = [
                'drive' => $disk['DeviceID'],
                'label' => $disk['VolumeName'] ?? '',
                'total_gb' => round($size / 1024 / 1024 / 1024, 2),
                'free_gb' => round($free / 1024 / 1024 / 1024, 2),
                'used_gb' => round(($size - $free) / 1024 / 1024 / 1024, 2),
                'percent' => $size > 0 ? round(($size - $free) / $size * 100, 2) : 0,
            ];
        }
        return $disks;
    }

    private function getOsInfo(): array {
        $data = $this->query(
            'SELECT Caption, Version, BuildNumber, CSDVersion, InstallDate, SerialNumber FROM Win32_OperatingSystem',
            ['Caption', 'Version', 'BuildNumber', 'CSDVersion', 'InstallDate', 'SerialNumber']
        );
        if (!$data) return ['error' => '無法獲取系統信息'];
        $os = $data[0];
        // InstallDate 格式:20240115083000.000000+480
        $installTime = 0;
        if (!empty($os['InstallDate'])) {
            $dt = $os['InstallDate'];
            $installTime = strtotime(substr($dt, 0, 14));
        }
        return [
            'name' => $os['Caption'] ?? 'Windows',
            'version' => $os['Version'] ?? '',
            'build' => $os['BuildNumber'] ?? '',
            'sp' => $os['CSDVersion'] ?? '',
            'install_date' => $installTime ? date('Y-m-d H:i:s', $installTime) : 'Unknown',
            'serial' => $os['SerialNumber'] ?? '',
        ];
    }

    private function getUptime(): array {
        $data = $this->query(
            'SELECT LastBootUpTime FROM Win32_OperatingSystem',
            ['LastBootUpTime']
        );
        $uptime = ['seconds' => 0, 'human' => 'Unknown', 'boot_time' => 0];
        if ($data && !empty($data[0]['LastBootUpTime'])) {
            // 格式:20240115083000.000000+480
            $dt = $data[0]['LastBootUpTime'];
            $bootTime = strtotime(substr($dt, 0, 14));
            $now = time();
            $seconds = $now - $bootTime;
            $days = floor($seconds / 86400);
            $hours = floor(($seconds % 86400) / 3600);
            $minutes = floor(($seconds % 3600) / 60);
            $uptime = [
                'seconds' => $seconds,
                'human' => sprintf('%d天 %d小時 %d分鐘', $days, $hours, $minutes),
                'boot_time' => $bootTime,
            ];
        }
        return $uptime;
    }
}

// 使用示例
try {
    $sys = new WindowsSysInfo();
    $info = $sys->get();
    echo '<pre>';
    print_r($info);
    echo '</pre>';
} catch (Exception $e) {
    echo '錯誤:' . $e->getMessage();
}
?>

輸出示例

Array
(
    [cpu] => Array
        (
            [cores] => 4
            [logical] => 8
            [model] => Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
            [cache_mb] => 8.00
            [max_mhz] => 1992
        )
    [memory] => Array
        (
            [total_mb] => 16284.00
            [free_mb] => 4521.00
            [used_mb] => 11763.00
            [percent] => 72.24
        )
    [swap] => Array
        (
            [total_mb] => 4096.00
            [used_mb] => 1024.00
            [free_mb] => 3072.00
            [percent] => 25.00
        )
    [disk] => Array
        (
            [0] => Array
                (
                    [drive] => C:
                    [label] => Windows
                    [total_gb] => 476.94
                    [free_gb] => 123.45
                    [used_gb] => 353.49
                    [percent] => 74.12
                )
        )
    [os] => Array
        (
            [name] => Microsoft Windows 10 Pro
            [version] => 10.0.19045
            [build] => 19045
            [sp] => 
            [install_date] => 2023-05-12 14:30:00
            [serial] => 00330-XXXXX-XXXXX-XXXXX
        )
    [uptime] => Array
        (
            [seconds] => 123456
            [human] => 1天 10小時 17分鐘
            [boot_time] => 1705000000
        )
)

啟用 COM 擴展

  1. 打開 php.ini
  2. 找到 ;extension=com_dotnet,去掉分號
  3. 重啟 PHP-FPM / Apache

權限與安全

  • PHP 運行用戶需具備 WMI 查詢權限(通常 Administrators 或 Performance Monitor Users 組)。
  • 生產環境建議建立專用低權限服務帳號,通過 WMI 控制台 (wmimgmt.msc) 授予 root\cimv2 命名空間的「啟用帳號」和「遠程啟用」權限。
  • WMI 查詢較慢(每次數百毫秒),Web 面板務必緩存結果(建議 30-60 秒)。

跨平台統一接口

interface SysInfoProvider {
    public function get(): array;
}

class SysInfoFactory {
    public static function create(): ?SysInfoProvider {
        if (PHP_OS_FAMILY === 'Linux') return new LinuxSysInfo();
        if (stripos(PHP_OS, 'FreeBSD') !== false) return new FreeBsdSysInfo();
        if (PHP_OS_FAMILY === 'Windows') return new WindowsSysInfo();
        return null;
    }
}

// 使用
$provider = SysInfoFactory::create();
if ($provider) {
    $info = $provider->get();
    // 統一處理顯示邏輯
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved