info('Collecting Spam/AV metrics…'); $rpC = '/usr/bin/rspamc'; $rpA = '/usr/bin/rspamadm'; // --- RSPAMD: erst 'stat' (sicher), sonst 'counters' als Fallback --- $ham = $spam = $reject = 0; $stat = trim(@shell_exec("$rpC -h 127.0.0.1:11334 stat 2>/dev/null") ?? ''); if ($stat !== '') { $ham = preg_match('/Messages treated as ham:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0; $spam = preg_match('/Messages treated as spam:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0; $reject = preg_match('/Messages with action reject:\s*(\d+)/i', $stat, $m) ? (int)$m[1] : 0; } else { $cnt = trim(@shell_exec("$rpC -h 127.0.0.1:11334 counters 2>/dev/null") ?? ''); $ham = preg_match('/\bham\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0; $spam = preg_match('/\bspam\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0; $reject = preg_match('/\breject\s*:\s*(\d+)/i', $cnt, $m) ? (int)$m[1] : 0; } // Rspamd Version $rspamdVer = trim(@shell_exec("$rpA --version 2>/dev/null") ?? ''); if ($rspamdVer === '') { $rspamdVer = trim(@shell_exec("dpkg-query -W -f='\${Version}\n' rspamd 2>/dev/null") ?? '–'); } // $clamLine = trim(@shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null') ?? '') ?: '–'; // $clamVer = $clamLine; // // // Versuch, Datum aus der Versionzeile zu ziehen (kein Zugriff auf freshclam.log nötig) // $sigUpdated = null; // if (preg_match('#/([^/]+ [0-9]{2} [0-9:]{8} [0-9]{4})$#', $clamLine, $m)) { // $sigUpdated = $m[1]; // z.B. "Sun Oct 26 09:42:43 2025" // } // --- CLAMAV: Versionzeile inkl. Signaturdatum ausgeben --- $clamLine = trim(@shell_exec('clamd --version 2>/dev/null || clamscan --version 2>/dev/null') ?? '') ?: '–'; $parts = explode('/', $clamLine, 3); $clamVer = $parts[0] ?? 'ClamAV'; $sigUpdated = null; if (isset($parts[2])) { $sigUpdated = trim($parts[2]); } else { // Fallback: journalctl (falls Gruppe adm) $jl = trim(@shell_exec('journalctl -u freshclam -n 50 --no-pager 2>/dev/null | grep -i "Database updated" | tail -n1') ?? ''); if ($jl) $sigUpdated = $jl; } $data = [ 'ts' => time(), 'ham' => $ham, 'spam' => $spam, 'reject' => $reject, 'rspamdVer' => $rspamdVer ?: '–', 'clamVer' => $clamVer, 'sigUpdated' => $sigUpdated, ]; Setting::set('spamav.metrics', $data); Cache::put('dash.spamav', $data, now()->addMinutes(10)); $this->info(sprintf( 'ham=%d spam=%d reject=%d | rspamd=%s | clam=%s', $ham, $spam, $reject, $data['rspamdVer'], $clamVer )); return self::SUCCESS; } } // //namespace App\Console\Commands; // //use Illuminate\Console\Command; //use Illuminate\Support\Facades\Cache; //use App\Models\Setting; // //class SpamAvCollectCommand extends Command //{ // protected $signature = 'spamav:collect'; // protected $description = 'Collect Rspamd/ClamAV metrics and persist to Settings (DB→Redis)'; // // public function handle(): int // { // $this->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; // } //}