| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- <?php
- // +----------------------------------------------------------------------
- // | saiadmin [ saiadmin快速开发框架 ]
- // +----------------------------------------------------------------------
- // | Author: sai <1430792918@qq.com>
- // +----------------------------------------------------------------------
- namespace plugin\saiadmin\utils;
- /**
- * 服务器监控信息
- */
- class ServerMonitor
- {
- private $cache = [];
- private $cacheTime = 2; // 缓存时间(秒)
- /**
- * 获取缓存数据
- * @param string $key
- * @return mixed|null
- */
- private function getCache(string $key)
- {
- if (isset($this->cache[$key]) && (time() - $this->cache[$key]['time']) < $this->cacheTime) {
- return $this->cache[$key]['data'];
- }
- return null;
- }
- /**
- * 设置缓存数据
- * @param string $key
- * @param mixed $data
- */
- private function setCache(string $key, $data)
- {
- $this->cache[$key] = [
- 'time' => time(),
- 'data' => $data
- ];
- }
- /**
- * 获取Windows系统信息
- * @return array
- */
- private function getWindowsSystemInfo(): array
- {
- $cacheKey = 'windows_system_info';
- $cached = $this->getCache($cacheKey);
- if ($cached !== null) {
- return $cached;
- }
- // 设置默认值
- $defaultData = [
- 'cpu_usage' => 0,
- 'cpu_name' => 'Unknown',
- 'cpu_cores' => 1,
- 'cpu_logical_cores' => 1,
- 'cpu_l3_cache' => 0,
- 'cpu_l2_cache' => 0,
- 'total_memory' => 0,
- 'available_memory' => 0
- ];
- try {
- $data = $defaultData;
- $usePowerShell = true;
- // 尝试使用 PowerShell 获取信息
- if ($usePowerShell) {
- // 使用 PowerShell 获取 CPU 信息
- $cpuInfo = shell_exec('powershell -NoProfile -NonInteractive -Command "Get-WmiObject -Class Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, L2CacheSize, L3CacheSize | ConvertTo-Json"');
- // 使用 PowerShell 获取 CPU 使用率
- $cpuUsage = shell_exec('powershell -NoProfile -NonInteractive -Command "Get-Counter -Counter \'\\Processor(_Total)\\% Processor Time\' -SampleInterval 1 -MaxSamples 1 | Select-Object -ExpandProperty CounterSamples | Select-Object -ExpandProperty CookedValue"');
- // 检查 PowerShell 命令是否成功
- if ($cpuInfo && $cpuUsage !== null) {
- $cpuData = json_decode($cpuInfo, true);
- if ($cpuData) {
- $data['cpu_name'] = $cpuData['Name'] ?? 'Unknown';
- $data['cpu_cores'] = intval($cpuData['NumberOfCores'] ?? 1);
- $data['cpu_logical_cores'] = intval($cpuData['NumberOfLogicalProcessors'] ?? 1);
- $data['cpu_l2_cache'] = intval($cpuData['L2CacheSize'] ?? 0);
- $data['cpu_l3_cache'] = intval($cpuData['L3CacheSize'] ?? 0);
- $data['cpu_usage'] = round(floatval($cpuUsage), 2);
- }
- } else {
- $usePowerShell = false;
- }
- }
- // 如果 PowerShell 失败,回退到使用 systeminfo
- if (!$usePowerShell) {
- $systemInfo = shell_exec('systeminfo');
- if ($systemInfo) {
- // 解析 CPU 信息
- if (preg_match('/Processor\(s\):\s+([^\n]+)/', $systemInfo, $matches)) {
- $data['cpu_name'] = trim($matches[1]);
- }
-
- if (preg_match('/Number of Processors:\s+(\d+)/', $systemInfo, $matches)) {
- $data['cpu_cores'] = intval($matches[1]);
- $data['cpu_logical_cores'] = intval($matches[1]);
- }
- // 获取 CPU 使用率(使用 tasklist 作为备选方案)
- $tasklist = shell_exec('tasklist /FI "IMAGENAME eq System" /FO CSV /NH');
- if ($tasklist) {
- $data['cpu_usage'] = 0; // 暂时设为0,因为 tasklist 不提供 CPU 使用率
- }
- }
- }
- // 获取内存信息
- $systemInfo = shell_exec('systeminfo');
- if ($systemInfo) {
- if (preg_match('/Total Physical Memory:\s+([\d,]+)/', $systemInfo, $matches)) {
- $memory = str_replace(',', '', $matches[1]);
- $data['total_memory'] = intval($memory) * 1024 * 1024; // Convert to bytes
- }
- if (preg_match('/Available Physical Memory:\s+([\d,]+)/', $systemInfo, $matches)) {
- $memory = str_replace(',', '', $matches[1]);
- $data['available_memory'] = intval($memory) * 1024 * 1024; // Convert to bytes
- }
- }
- // 验证数据
- foreach ($data as $key => $value) {
- if ($key !== 'cpu_name' && (!is_numeric($value) || $value < 0)) {
- $data[$key] = $defaultData[$key];
- }
- }
- $this->setCache($cacheKey, $data);
- return $data;
- } catch (\Throwable $e) {
- error_log("ServerMonitor error: " . $e->getMessage());
- }
- return $defaultData;
- }
- /**
- * 获取cpu信息
- * @return array
- */
- public function getCpuInfo(): array
- {
- try {
- if (PHP_OS == 'Linux') {
- $cpu = $this->getCpuUsage();
- preg_match('/(\d+)/', shell_exec('cat /proc/cpuinfo | grep "cache size"') ?? '', $cache);
- if (count($cache) == 0) {
- // aarch64 有可能是arm架构
- $cache = trim(shell_exec("lscpu | grep L3 | awk '{print \$NF}'") ?? '');
- if ($cache == '') {
- $cache = trim(shell_exec("lscpu | grep L2 | awk '{print \$NF}'") ?? '');
- }
- if ($cache != '') {
- $cache = [0, intval(str_replace(['K', 'B'], '', strtoupper($cache)))];
- }
- }
- } elseif (PHP_OS == 'Darwin') { // macOS
- $cpu = trim(shell_exec("ps -A -o %cpu | awk '{s+=$1} END {print s}'"));
- $cpu = sprintf("%.2f",intval($cpu) / shell_exec("sysctl -n hw.ncpu"));
- $cache = shell_exec("sysctl -n hw.l3cachesize");
- if ($cache == '') {
- $cache = shell_exec("sysctl -n hw.l2cachesize");
- }
- if ($cache != '') {
- $cache = [0, intval($cache)];
- }
- } else {
- $info = $this->getWindowsSystemInfo();
- $cache = $info['cpu_l3_cache'] ?: $info['cpu_l2_cache'];
- return [
- 'name' => $info['cpu_name'],
- 'cores' => '物理核心数:' . $info['cpu_cores'] . '个,逻辑核心数:' . $info['cpu_logical_cores'] . '个',
- 'cache' => $cache ? $cache / 1024 : 0,
- 'usage' => $info['cpu_usage'],
- 'free' => sprintf("%.2f", round(100 - $info['cpu_usage'], 2))
- ];
- }
- return [
- 'name' => $this->getCpuName(),
- 'cores' => '物理核心数:' . $this->getCpuPhysicsCores() . '个,逻辑核心数:' . $this->getCpuLogicCores() . '个',
- 'cache' => $cache[1] ? $cache[1] / 1024 : 0,
- 'usage' => $cpu,
- 'free' => sprintf("%.2f",round(100 - $cpu, 2))
- ];
- } catch (\Throwable $e) {
- $res = '无法获取';
- echo $e->getMessage(), "\n";
- return [
- 'name' => $res,
- 'cores' => $res,
- 'cache' => $res,
- 'usage' => $res,
- 'free' => $res,
- ];
- }
- }
- /**
- * 获取CPU名称
- * @return string
- */
- public function getCpuName(): string
- {
- if (PHP_OS == 'Linux') {
- preg_match('/^\s+\d\s+(.+)/', shell_exec('cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c') ?? '', $matches);
- if (count($matches) == 0) {
- // aarch64 有可能是arm架构
- $name = trim(shell_exec("lscpu| grep Architecture | awk '{print $2}'") ?? '');
- if ($name != '') {
- $mfMhz = trim(shell_exec("lscpu| grep 'MHz' | awk '{print \$NF}' | head -n1") ?? '');
- $mfGhz = trim(shell_exec("lscpu| grep 'GHz' | awk '{print \$NF}' | head -n1") ?? '');
- if ($mfMhz == '' && $mfGhz == '') {
- return $name;
- } else if ($mfGhz != '') {
- return $name . ' @ ' . $mfGhz . 'GHz';
- } else if ($mfMhz != '') {
- return $name . ' @ ' . round(intval($mfMhz) / 1000, 2) . 'GHz';
- }
- } else {
- return '未知';
- }
- }
- return $matches[1] ?? "未知";
- } elseif (PHP_OS == 'Darwin') { // macOS
- $name = shell_exec("sysctl -n machdep.cpu.brand_string");
- return trim($name);
- } else {
- $info = $this->getWindowsSystemInfo();
- return $info['cpu_name'];
- }
- }
- /**
- * 获取cpu物理核心数
- */
- public function getCpuPhysicsCores(): string
- {
- if (PHP_OS == 'Linux') {
- $num = str_replace("\n", '', shell_exec('cat /proc/cpuinfo |grep "physical id"|sort |uniq|wc -l'));
- return intval($num) == 0 ? '1' : $num;
- } elseif (PHP_OS == 'Darwin') { // macOS
- $num = shell_exec('sysctl -n hw.physicalcpu');
- return trim(strval($num));
- } else {
- $info = $this->getWindowsSystemInfo();
- return strval($info['cpu_cores']);
- }
- }
- /**
- * 获取cpu逻辑核心数
- */
- public function getCpuLogicCores(): string
- {
- if (PHP_OS == 'Linux') {
- return str_replace("\n", '', shell_exec('cat /proc/cpuinfo |grep "processor"|wc -l'));
- } elseif (PHP_OS == 'Darwin') { // macOS
- return trim(strval(shell_exec('sysctl -n hw.logicalcpu')));
- } else {
- $info = $this->getWindowsSystemInfo();
- return strval($info['cpu_logical_cores']);
- }
- }
- /**
- * 获取CPU使用率
- * @return string
- */
- public function getCpuUsage(): string
- {
- if (PHP_OS == 'Linux') {
- $start = $this->calculationCpu();
- sleep(1);
- $end = $this->calculationCpu();
- $totalStart = $start['total'];
- $totalEnd = $end['total'];
- $timeStart = $start['time'];
- $timeEnd = $end['time'];
- return sprintf('%.2f', ($timeEnd - $timeStart) / ($totalEnd - $totalStart) * 100);
- } elseif (PHP_OS == 'Darwin') { // macOS
- $usage = shell_exec("ps -A -o %cpu | awk '{s+=$1} END {print s}'");
- return sprintf('%.2f', $usage / shell_exec("sysctl -n hw.ncpu"));
- } else {
- $info = $this->getWindowsSystemInfo();
- return sprintf('%.2f', $info['cpu_usage']);
- }
- }
- /**
- * 计算CPU
- * @return array
- */
- protected function calculationCpu(): array
- {
- $mode = '/(cpu)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)[\s]+([0-9]+)/';
- $string = shell_exec('cat /proc/stat | grep cpu');
- preg_match_all($mode, $string, $matches);
- $total = $matches[2][0] + $matches[3][0] + $matches[4][0] + $matches[5][0] + $matches[6][0] + $matches[7][0] + $matches[8][0] + $matches[9][0];
- $time = $matches[2][0] + $matches[3][0] + $matches[4][0] + $matches[6][0] + $matches[7][0] + $matches[8][0] + $matches[9][0];
- return ['total' => $total, 'time' => $time];
- }
- /**
- * 获取内存信息
- * @return array
- */
- public function getMemInfo(): array
- {
- if (PHP_OS == 'Linux') {
- $string = shell_exec('cat /proc/meminfo | grep MemTotal');
- preg_match('/(\d+)/', $string, $total);
- $result['total'] = sprintf('%.2f', $total[1] / 1024 / 1024);
- $string = shell_exec('cat /proc/meminfo | grep MemAvailable');
- preg_match('/(\d+)/', $string, $available);
- $result['free'] = sprintf('%.2f', $available[1] / 1024 / 1024);
- $result['usage'] = sprintf('%.2f', ($total[1] - $available[1]) / 1024 / 1024);
- $result['php'] = round(memory_get_usage() / 1024 / 1024, 2);
- $result['rate'] = sprintf(
- '%.2f',
- (sprintf('%.2f', $result['usage']) / sprintf('%.2f', $result['total'])) * 100
- );
- } elseif (PHP_OS == 'Darwin') { // macOS
- $result['total'] = round(intval(shell_exec('sysctl -n hw.memsize')) / 1024 / 1024 / 1024, 2);
- $free = shell_exec('vm_stat | grep "Pages free"');
- preg_match('/(\d+)/', $free, $matches);
- $result['free'] = round(intval($matches[1]) * 4096 / 1024 / 1024 / 1024, 2);
- $result['usage'] = round($result['total'] - $result['free'], 2);
- $result['php'] = round(memory_get_usage() / 1024 / 1024, 2);
- $result['rate'] = sprintf(
- '%.2f',
- (sprintf('%.2f', $result['usage']) / sprintf('%.2f', $result['total'])) * 100
- );
- } else {
- $info = $this->getWindowsSystemInfo();
- $result['total'] = round($info['total_memory'] / 1024 / 1024 / 1024, 2);
- $result['free'] = round($info['available_memory'] / 1024 / 1024 / 1024, 2);
- $result['usage'] = round($result['total'] - $result['free'], 2);
- $result['php'] = round(memory_get_usage() / 1024 / 1024, 2);
-
- // 防止除以0错误
- if ($result['total'] > 0) {
- $result['rate'] = sprintf(
- '%.2f',
- (sprintf('%.2f', $result['usage']) / sprintf('%.2f', $result['total'])) * 100
- );
- } else {
- $result['rate'] = '0.00';
- }
-
- return $result;
- }
- return $result;
- }
- /**
- * 获取PHP及环境信息
- * @return array
- */
- public function getPhpAndEnvInfo(): array
- {
- $result['php_version'] = PHP_VERSION;
- $result['os'] = PHP_OS_FAMILY;
- $result['project_path'] = BASE_PATH;
- return $result;
- }
- }
|