url = "http://{$host}:{$port}/_status?format=xml"; $this->timeout = $timeout; } /** * Returns array of service rows: ['name'=>, 'label'=>, 'hint'=>, 'ok'=>bool] * Only process-type services (type=3) are included. * Returns empty array if Monit is unreachable. */ public function services(): array { $xml = $this->fetch(); if ($xml === null) return []; $labelMap = [ 'postfix' => ['label' => 'Postfix', 'hint' => 'MTA / Versand'], 'dovecot' => ['label' => 'Dovecot', 'hint' => 'IMAP / POP3'], 'mariadb' => ['label' => 'MariaDB', 'hint' => 'Datenbank'], 'redis' => ['label' => 'Redis', 'hint' => 'Cache / Queue'], 'rspamd' => ['label' => 'Rspamd', 'hint' => 'Spamfilter'], 'opendkim' => ['label' => 'OpenDKIM', 'hint' => 'DKIM-Signatur'], 'nginx' => ['label' => 'Nginx', 'hint' => 'Webserver'], ]; $rows = []; foreach ($xml->service as $svc) { if ((int) $svc['type'] !== 3) continue; // nur Prozesse $name = (string) $svc->name; $ok = (int) $svc->status === 0; $meta = $labelMap[$name] ?? ['label' => ucfirst($name), 'hint' => '']; $rows[] = [ 'name' => $name, 'label' => $meta['label'], 'hint' => $meta['hint'], 'ok' => $ok, ]; } return $rows; } public function reachable(): bool { return $this->fetch() !== null; } private function fetch(): ?\SimpleXMLElement { $ctx = stream_context_create(['http' => [ 'timeout' => $this->timeout, 'ignore_errors' => true, ]]); $raw = @file_get_contents($this->url, false, $ctx); if ($raw === false || $raw === '') return null; try { $prev = libxml_use_internal_errors(true); $xml = simplexml_load_string($raw); libxml_use_internal_errors($prev); return $xml instanceof \SimpleXMLElement ? $xml : null; } catch (\Throwable) { return null; } } }