当前位置:首页>php>PHP实现web版本的macOS系统硬件监控工具

PHP实现web版本的macOS系统硬件监控工具

  • 2026-10-11 06:32:54
PHP实现web版本的macOS系统硬件监控工具
启动php网页版本
效果如下:
桌面版本与PHP网页版本同时显示

请在微信客户端打开

PHP部分实现代码:
<?php/** * SysMonitor Web — Background Collector Daemon * * Runs CPU and network sampling in the background so the API endpoint * responds instantly (no blocking `top -l 1` or netstat delta calc). * * Usage:  php collector.php & * Output: writes /tmp/sysmonitor_web_state.json atomically every 1 s. */declare(ticks = 1);$stateFile = '/tmp/sysmonitor_web_state.json';$pidFile   = '/tmp/sysmonitor_web_collector.pid';$interval  = 1;          // seconds between samples// ── Singleton check ──────────────────────────────────────────────────if (file_exists($pidFile)) {    $oldPid = (int) @file_get_contents($pidFile);    if ($oldPid > 0 && posix_kill($oldPid, 0)) {        fwrite(STDERR, "Collector already running (PID $oldPid)\n");        exit(1);    }}@file_put_contents($pidFile, (string) getmypid());// Cleanup on exit$shutdown = function () use ($pidFile) {    @unlink($pidFile);    fwrite(STDERR, "Collector stopped.\n");    exit(0);};pcntl_signal(SIGINT,  function () use ($shutdown) { $shutdown(); });pcntl_signal(SIGTERM, function () use ($shutdown) { $shutdown(); });// ── Initial sample (seeds the state immediately) ─────────────────────fwrite(STDERR, "Collector started (PID " . getmypid() . "), sampling every {$interval}s\n");// ── Main loop ────────────────────────────────────────────────────────$prevNet    = null;$prevNetTs  = 0;while (true) {    $now = microtime(true);    $data = [];    // ── CPU usage via top (blocking ~2 s, but runs in background) ────    $topOut = @shell_exec('top -l 1 -n 0 2>/dev/null');    $cpuUsage = 0;    if ($topOut && preg_match('/CPU usage:\s*([\d.]+)%\s+user,\s*([\d.]+)%\s+sys/', $topOut, $m)) {        $cpuUsage = round((float) $m[1] + (float) $m[2], 1);    }    $cores = (int) @trim(shell_exec('sysctl -n hw.ncpu 2>/dev/null') ?: '0');    $data['cpu'] = ['overall' => $cpuUsage, 'cores' => max($cores, 0)];    // ── Network rate via netstat (delta from previous sample) ────────    $netOut   = @shell_exec('netstat -ibn 2>/dev/null');    $netLines = preg_split('/\r?\n/', $netOut ?: '');    $curNet   = ['in' => 0, 'out' => 0];    foreach ($netLines as $line) {        $parts = preg_split('/\s+/', trim($line));        if (count($parts) < 10) continue;        $name = $parts[0];        if (str_starts_with($name, 'lo') || $name === 'Name') continue;        $curNet['in']  += (int) ($parts[6] ?? 0);        $curNet['out'] += (int) ($parts[9] ?? 0);    }    $rateIn  = 0;    $rateOut = 0;    if ($prevNet && ($now - $prevNetTs) > 0.3) {        $dt = $now - $prevNetTs;        if ($dt > 0) {            $rateIn  = max(0, ($curNet['in']  - $prevNet['in'])  / $dt);            $rateOut = max(0, ($curNet['out'] - $prevNet['out']) / $dt);        }    }    $prevNet   = $curNet;    $prevNetTs = $now;    $data['network'] = [        'rate_in'   => round($rateIn),        'rate_out'  => round($rateOut),        'total_in'  => $curNet['in'],        'total_out' => $curNet['out'],    ];    // ── Atomic write ─────────────────────────────────────────────────    $tmpFile = $stateFile . '.' . getmypid() . '.tmp';    @file_put_contents($tmpFile, json_encode($data), LOCK_EX);    @rename($tmpFile, $stateFile);    // ── Sleep until next interval (account for time spent sampling) ──    $elapsed = microtime(true) - $now;    $sleepMs = max(100, (int)(($interval - $elapsed) * 1_000_000));    usleep($sleepMs);}

最新文章

随机文章