info('Collecting Spam/AV metrics…'); // Rspamd counters (kein Root nötig) $out = trim(@shell_exec('rspamc counters 2>/dev/null') ?? ''); $ham = preg_match('/\bham\s*:\s*(\d+)/i', $out, $m1) ? (int)$m1[1] : 0; $spam = preg_match('/\bspam\s*:\s*(\d+)/i', $out, $m2) ? (int)$m2[1] : 0; $reject = preg_match('/\breject\s*:\s*(\d+)/i', $out, $m3) ? (int)$m3[1] : 0; // ClamAV Version + Signatur-Datum robust ohne Datei-Zugriff $clamLine = trim((string) @shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null')); $clamVer = $clamLine !== '' ? $clamLine : '–'; // Aus clamd/clamscan-Output das Datum am Ende herausziehen (Format: ".../Sun Oct 26 09:42:43 2025") $sigUpdated = null; if ($clamLine && preg_match('#/([^/]+\d{4})$#', $clamLine, $m)) { // $m[1] ist z.B. "Sun Oct 26 09:42:43 2025" $sigUpdated = $m[1]; } $data = [ 'ts' => time(), 'ham' => $ham, 'spam' => $spam, 'reject' => $reject, 'rspamdVer' => trim((string) @shell_exec('rspamadm version 2>/dev/null')) ?: '–', 'clamVer' => $clamVer, 'sigUpdated' => $sigUpdated, ]; // Persistieren (DB→Redis) + kurzer UI-Cache Setting::set('spamav.metrics', $data); Cache::put('dash.spamav', $data, 60); $this->info(sprintf( 'ham=%d spam=%d reject=%d | rspamd=%s | clam=%s', $data['ham'], $data['spam'], $data['reject'], $data['rspamdVer'], $data['clamVer'] )); return self::SUCCESS; } }