xref: /plugin/calendar/get_system_stats.php (revision 1d05cddc261a22328c4671319b0963b94fa1a7e9)
1*1d05cddcSAtari911<?php
2*1d05cddcSAtari911/**
3*1d05cddcSAtari911 * System Stats API Endpoint
4*1d05cddcSAtari911 * Returns real-time CPU and memory usage
5*1d05cddcSAtari911 */
6*1d05cddcSAtari911
7*1d05cddcSAtari911header('Content-Type: application/json');
8*1d05cddcSAtari911header('Cache-Control: no-cache, must-revalidate');
9*1d05cddcSAtari911
10*1d05cddcSAtari911$stats = [
11*1d05cddcSAtari911    'cpu' => 0,
12*1d05cddcSAtari911    'cpu_5min' => 0,
13*1d05cddcSAtari911    'memory' => 0,
14*1d05cddcSAtari911    'timestamp' => time(),
15*1d05cddcSAtari911    'load' => ['1min' => 0, '5min' => 0, '15min' => 0],
16*1d05cddcSAtari911    'uptime' => '',
17*1d05cddcSAtari911    'memory_details' => [],
18*1d05cddcSAtari911    'top_processes' => []
19*1d05cddcSAtari911];
20*1d05cddcSAtari911
21*1d05cddcSAtari911// Get CPU usage and load averages
22*1d05cddcSAtari911if (function_exists('sys_getloadavg')) {
23*1d05cddcSAtari911    $load = sys_getloadavg();
24*1d05cddcSAtari911    if ($load !== false) {
25*1d05cddcSAtari911        // Use 1-minute load average for real-time feel
26*1d05cddcSAtari911        // Normalize to percentage (assuming max load of 2.0 = 100%)
27*1d05cddcSAtari911        $stats['cpu'] = min(100, ($load[0] / 2.0) * 100);
28*1d05cddcSAtari911
29*1d05cddcSAtari911        // 5-minute average for green bar
30*1d05cddcSAtari911        $stats['cpu_5min'] = min(100, ($load[1] / 2.0) * 100);
31*1d05cddcSAtari911
32*1d05cddcSAtari911        // Store all three load averages for tooltip
33*1d05cddcSAtari911        $stats['load'] = [
34*1d05cddcSAtari911            '1min' => round($load[0], 2),
35*1d05cddcSAtari911            '5min' => round($load[1], 2),
36*1d05cddcSAtari911            '15min' => round($load[2], 2)
37*1d05cddcSAtari911        ];
38*1d05cddcSAtari911    }
39*1d05cddcSAtari911}
40*1d05cddcSAtari911
41*1d05cddcSAtari911// Get memory usage
42*1d05cddcSAtari911if (stristr(PHP_OS, 'linux')) {
43*1d05cddcSAtari911    // Linux: Read from /proc/meminfo
44*1d05cddcSAtari911    $meminfo = file_get_contents('/proc/meminfo');
45*1d05cddcSAtari911    if ($meminfo) {
46*1d05cddcSAtari911        preg_match('/MemTotal:\s+(\d+)/', $meminfo, $total);
47*1d05cddcSAtari911        preg_match('/MemAvailable:\s+(\d+)/', $meminfo, $available);
48*1d05cddcSAtari911
49*1d05cddcSAtari911        if (isset($total[1]) && isset($available[1])) {
50*1d05cddcSAtari911            $totalMem = $total[1];
51*1d05cddcSAtari911            $availableMem = $available[1];
52*1d05cddcSAtari911            $usedMem = $totalMem - $availableMem;
53*1d05cddcSAtari911            $stats['memory'] = ($usedMem / $totalMem) * 100;
54*1d05cddcSAtari911        }
55*1d05cddcSAtari911    }
56*1d05cddcSAtari911} elseif (stristr(PHP_OS, 'darwin') || stristr(PHP_OS, 'bsd')) {
57*1d05cddcSAtari911    // macOS/BSD: Use vm_stat
58*1d05cddcSAtari911    $vm_stat = shell_exec('vm_stat');
59*1d05cddcSAtari911    if ($vm_stat) {
60*1d05cddcSAtari911        preg_match('/Pages free:\s+(\d+)\./', $vm_stat, $free);
61*1d05cddcSAtari911        preg_match('/Pages active:\s+(\d+)\./', $vm_stat, $active);
62*1d05cddcSAtari911        preg_match('/Pages inactive:\s+(\d+)\./', $vm_stat, $inactive);
63*1d05cddcSAtari911        preg_match('/Pages wired down:\s+(\d+)\./', $vm_stat, $wired);
64*1d05cddcSAtari911
65*1d05cddcSAtari911        if (isset($free[1], $active[1], $inactive[1], $wired[1])) {
66*1d05cddcSAtari911            $pageSize = 4096; // bytes
67*1d05cddcSAtari911            $totalPages = $free[1] + $active[1] + $inactive[1] + $wired[1];
68*1d05cddcSAtari911            $usedPages = $active[1] + $inactive[1] + $wired[1];
69*1d05cddcSAtari911
70*1d05cddcSAtari911            if ($totalPages > 0) {
71*1d05cddcSAtari911                $stats['memory'] = ($usedPages / $totalPages) * 100;
72*1d05cddcSAtari911            }
73*1d05cddcSAtari911        }
74*1d05cddcSAtari911    }
75*1d05cddcSAtari911} elseif (stristr(PHP_OS, 'win')) {
76*1d05cddcSAtari911    // Windows: Use wmic
77*1d05cddcSAtari911    $wmic = shell_exec('wmic OS get FreePhysicalMemory,TotalVisibleMemorySize /Value');
78*1d05cddcSAtari911    if ($wmic) {
79*1d05cddcSAtari911        preg_match('/FreePhysicalMemory=(\d+)/', $wmic, $free);
80*1d05cddcSAtari911        preg_match('/TotalVisibleMemorySize=(\d+)/', $wmic, $total);
81*1d05cddcSAtari911
82*1d05cddcSAtari911        if (isset($free[1]) && isset($total[1])) {
83*1d05cddcSAtari911            $freeMem = $free[1];
84*1d05cddcSAtari911            $totalMem = $total[1];
85*1d05cddcSAtari911            $usedMem = $totalMem - $freeMem;
86*1d05cddcSAtari911            $stats['memory'] = ($usedMem / $totalMem) * 100;
87*1d05cddcSAtari911        }
88*1d05cddcSAtari911    }
89*1d05cddcSAtari911}
90*1d05cddcSAtari911
91*1d05cddcSAtari911// Fallback: Use PHP memory if system memory unavailable
92*1d05cddcSAtari911if ($stats['memory'] == 0) {
93*1d05cddcSAtari911    $memLimit = ini_get('memory_limit');
94*1d05cddcSAtari911    if ($memLimit != '-1') {
95*1d05cddcSAtari911        $memLimitBytes = return_bytes($memLimit);
96*1d05cddcSAtari911        $memUsage = memory_get_usage(true);
97*1d05cddcSAtari911        $stats['memory'] = ($memUsage / $memLimitBytes) * 100;
98*1d05cddcSAtari911    }
99*1d05cddcSAtari911}
100*1d05cddcSAtari911
101*1d05cddcSAtari911// Get uptime (Linux/Unix)
102*1d05cddcSAtari911if (file_exists('/proc/uptime')) {
103*1d05cddcSAtari911    $uptime = file_get_contents('/proc/uptime');
104*1d05cddcSAtari911    if ($uptime) {
105*1d05cddcSAtari911        $uptimeSeconds = floatval(explode(' ', $uptime)[0]);
106*1d05cddcSAtari911        $days = floor($uptimeSeconds / 86400);
107*1d05cddcSAtari911        $hours = floor(($uptimeSeconds % 86400) / 3600);
108*1d05cddcSAtari911        $minutes = floor(($uptimeSeconds % 3600) / 60);
109*1d05cddcSAtari911        $stats['uptime'] = sprintf('%dd %dh %dm', $days, $hours, $minutes);
110*1d05cddcSAtari911    }
111*1d05cddcSAtari911} elseif (stristr(PHP_OS, 'win')) {
112*1d05cddcSAtari911    // Windows uptime
113*1d05cddcSAtari911    $wmic = shell_exec('wmic os get lastbootuptime');
114*1d05cddcSAtari911    if ($wmic && preg_match('/(\d{14})/', $wmic, $matches)) {
115*1d05cddcSAtari911        $bootTime = DateTime::createFromFormat('YmdHis', $matches[1]);
116*1d05cddcSAtari911        $now = new DateTime();
117*1d05cddcSAtari911        $diff = $now->diff($bootTime);
118*1d05cddcSAtari911        $stats['uptime'] = sprintf('%dd %dh %dm', $diff->days, $diff->h, $diff->i);
119*1d05cddcSAtari911    }
120*1d05cddcSAtari911}
121*1d05cddcSAtari911
122*1d05cddcSAtari911// Get detailed memory info (Linux)
123*1d05cddcSAtari911if (stristr(PHP_OS, 'linux') && file_exists('/proc/meminfo')) {
124*1d05cddcSAtari911    $meminfo = file_get_contents('/proc/meminfo');
125*1d05cddcSAtari911    if ($meminfo) {
126*1d05cddcSAtari911        preg_match('/MemTotal:\s+(\d+)/', $meminfo, $total);
127*1d05cddcSAtari911        preg_match('/MemAvailable:\s+(\d+)/', $meminfo, $available);
128*1d05cddcSAtari911        preg_match('/MemFree:\s+(\d+)/', $meminfo, $free);
129*1d05cddcSAtari911        preg_match('/Buffers:\s+(\d+)/', $meminfo, $buffers);
130*1d05cddcSAtari911        preg_match('/Cached:\s+(\d+)/', $meminfo, $cached);
131*1d05cddcSAtari911
132*1d05cddcSAtari911        if (isset($total[1])) {
133*1d05cddcSAtari911            $totalMB = round($total[1] / 1024, 1);
134*1d05cddcSAtari911            $availableMB = isset($available[1]) ? round($available[1] / 1024, 1) : 0;
135*1d05cddcSAtari911            $usedMB = round(($total[1] - ($available[1] ?? $free[1] ?? 0)) / 1024, 1);
136*1d05cddcSAtari911            $buffersMB = isset($buffers[1]) ? round($buffers[1] / 1024, 1) : 0;
137*1d05cddcSAtari911            $cachedMB = isset($cached[1]) ? round($cached[1] / 1024, 1) : 0;
138*1d05cddcSAtari911
139*1d05cddcSAtari911            $stats['memory_details'] = [
140*1d05cddcSAtari911                'total' => $totalMB . ' MB',
141*1d05cddcSAtari911                'used' => $usedMB . ' MB',
142*1d05cddcSAtari911                'available' => $availableMB . ' MB',
143*1d05cddcSAtari911                'buffers' => $buffersMB . ' MB',
144*1d05cddcSAtari911                'cached' => $cachedMB . ' MB'
145*1d05cddcSAtari911            ];
146*1d05cddcSAtari911        }
147*1d05cddcSAtari911    }
148*1d05cddcSAtari911}
149*1d05cddcSAtari911
150*1d05cddcSAtari911// Get top 5 processes by CPU (Linux/Unix)
151*1d05cddcSAtari911if (stristr(PHP_OS, 'linux') || stristr(PHP_OS, 'darwin')) {
152*1d05cddcSAtari911    $ps = shell_exec('ps aux --sort=-%cpu | head -6 | tail -5 2>/dev/null');
153*1d05cddcSAtari911    if (!$ps) {
154*1d05cddcSAtari911        // Try BSD/macOS format
155*1d05cddcSAtari911        $ps = shell_exec('ps aux -r | head -6 | tail -5 2>/dev/null');
156*1d05cddcSAtari911    }
157*1d05cddcSAtari911    if ($ps) {
158*1d05cddcSAtari911        $lines = explode("\n", trim($ps));
159*1d05cddcSAtari911        foreach ($lines as $line) {
160*1d05cddcSAtari911            if (empty($line)) continue;
161*1d05cddcSAtari911            $parts = preg_split('/\s+/', $line, 11);
162*1d05cddcSAtari911            if (count($parts) >= 11) {
163*1d05cddcSAtari911                $stats['top_processes'][] = [
164*1d05cddcSAtari911                    'cpu' => $parts[2] . '%',
165*1d05cddcSAtari911                    'mem' => $parts[3] . '%',
166*1d05cddcSAtari911                    'command' => substr($parts[10], 0, 30)
167*1d05cddcSAtari911                ];
168*1d05cddcSAtari911            }
169*1d05cddcSAtari911        }
170*1d05cddcSAtari911    }
171*1d05cddcSAtari911} elseif (stristr(PHP_OS, 'win')) {
172*1d05cddcSAtari911    // Windows top processes
173*1d05cddcSAtari911    $wmic = shell_exec('wmic process get Caption,KernelModeTime /format:csv | findstr /V "^$" | sort /R /+1 | more +1 | findstr /N "^" | findstr "^[1-5]:"');
174*1d05cddcSAtari911    if ($wmic) {
175*1d05cddcSAtari911        $lines = explode("\n", trim($wmic));
176*1d05cddcSAtari911        foreach ($lines as $line) {
177*1d05cddcSAtari911            if (preg_match('/^\d+:(.+),(.+),(\d+)/', $line, $matches)) {
178*1d05cddcSAtari911                $stats['top_processes'][] = [
179*1d05cddcSAtari911                    'command' => substr($matches[2], 0, 30),
180*1d05cddcSAtari911                    'cpu' => '-'
181*1d05cddcSAtari911                ];
182*1d05cddcSAtari911            }
183*1d05cddcSAtari911        }
184*1d05cddcSAtari911    }
185*1d05cddcSAtari911}
186*1d05cddcSAtari911
187*1d05cddcSAtari911echo json_encode($stats);
188*1d05cddcSAtari911
189*1d05cddcSAtari911function return_bytes($val) {
190*1d05cddcSAtari911    $val = trim($val);
191*1d05cddcSAtari911    $last = strtolower($val[strlen($val)-1]);
192*1d05cddcSAtari911    $val = (int)$val;
193*1d05cddcSAtari911    switch($last) {
194*1d05cddcSAtari911        case 'g':
195*1d05cddcSAtari911            $val *= 1024;
196*1d05cddcSAtari911        case 'm':
197*1d05cddcSAtari911            $val *= 1024;
198*1d05cddcSAtari911        case 'k':
199*1d05cddcSAtari911            $val *= 1024;
200*1d05cddcSAtari911    }
201*1d05cddcSAtari911    return $val;
202*1d05cddcSAtari911}
203