From d509db4bdec13789c04f6f716af83c71fbd69051 Mon Sep 17 00:00:00 2001 From: blaerf Date: Fri, 28 Nov 2025 05:04:44 +0000 Subject: [PATCH 1/7] README.md aktualisiert --- README.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cc6f67b..716eece 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,65 @@ # PHP_AdminTool_Projekt -Admin Tool Projekt für das Fach PHP ---- -Ich (@blaerf) habe mich mal hingesetzt und einen Windows Server 2025 als VM aufgesetzt. Darauf habe ich die Active Directory und IIS Rolle installiert. -Zudem habe ich alles so konfiguriert, dass wir PHP mit IIS nutzen können und per LDAPS auf das AD per PHP zugreifen können. +Dieses Repository enthält das gemeinsame PHP AdminTool, das auf IIS unter Windows betrieben wird und über LDAP/AD, SNMP und PowerShell administrative Aufgaben ermöglicht. Das Projekt wird von mehreren Entwicklern gepflegt und folgt einem klar definierten Workflow, um Qualität, Stabilität und Nachvollziehbarkeit sicherzustellen. -Ich habe mir auch noch Gedanken zum Git-Workflow gemacht und es nieder geschrieben. So können wir sauber und sicher arbeiten. -Eine Ordner Struktur habe ich mir auch überlegt und schon mal angelegt. Alle Infos habe ich soweit im Wiki zusammen getragen. -Meine Tests habe ich, wie im Git-workflow beschrieben, in ein eigenes branch (structure/first-structure) gepackt. +Ein zentraler Bestandteil der Arbeit mit diesem Repository ist der verbindliche Gitea-Workflow im Wiki. -Bitte auch das Wiki beachten und durchlesen! + +**Hinweis:** Der [Gitea-Workflow](https://git.eckertplayground.de/taarly/PHP_AdminTool_Projekt/wiki) ist zwingend zu lesen und einzuhalten. Er legt fest, wie Branches erstellt, gemerged und getestet werden. --- -## Aufgaben: ## +## Überblick + +Das Projekt dient als webbasiertes Administrationswerkzeug und umfasst unter anderem: + +- LDAP/AD‑Anbindung (LDAPS) +- Benutzer- und Gruppenverwaltung +- SNMP‑Auswertungen +- PowerShell‑Integration +- Weboberfläche zur zentralen Administration + +Die Anwendung läuft in zwei Umgebungen: + +- Produktion (`main`): https://itfa.schraubenfuzzi.de +- Test (`develop`): https://test.itfa.schraubenfuzzi.de + +--- + +## Ordnerstruktur (Auszug) + +- `app/` – Anwendungscode +- `public/` – Webroot +- `config/` – Konfigurationen für LDAP, Systemvariablen usw. +- `scripts/` – Hilfs- und Bereitstellungsskripte +- `docs/` – interne Dokumente +- `.gitignore` – ausgeschlossene Dateien + +--- + +## Workflow + +Die Entwicklung folgt einem strengen, verbindlichen Ablauf: + +1. **Feature‑Branch erstellen** (`feature/name`) +2. Feature entwickeln, committen, pushen +3. **PR nach `develop`** für Tests auf der Testinstanz + - wird vom Autor selbst gemerged + - Branch bleibt bestehen +4. Nach bestandenem Test: **PR nach `main`** + - mit Review + - Merge per Squash + - danach wird der Feature‑Branch gelöscht + +Details stehen im Wiki. + +**Wichtiger Hinweis:** +Der komplette Ablauf ist im [Gitea-Workflow](https://git.eckertplayground.de/taarly/PHP_AdminTool_Projekt/wiki) beschrieben und muss befolgt werden. + +--- + +## Aufgaben + | Aufgabe | Benutzer | | :---- | :---- | | Benutzer und Gruppen über LDAP anzeigen | Jens E (@blaerf), Stefan W (@viperion) | @@ -23,4 +69,32 @@ Bitte auch das Wiki beachten und durchlesen! | UI/UX anpassen | Yasin B (@Muchentuchen), Alexander M (@Alexander), Torsten J (@tojacobs) | --- -## Infos gibt es im [Wiki](https://git.eckertplayground.de/taarly/PHP_AdminTool_Projekt/wiki) \ No newline at end of file + +## Dokumentation + +Alle weiteren Informationen wie Regeln, technische Details, Konzepte und Anleitungen befinden sich im Wiki: + +`Wiki → Gitea‑Workflow` +`Wiki → Implementierung / LDAP / IIS / Setup` + +Dieser Bereich muss von allen Entwicklern gelesen werden, bevor am Projekt gearbeitet wird. + +--- + +## Mitwirken + +Wer etwas ändern oder erweitern möchte: + +- Branch vom aktuellen Stand erstellen +- Entwickeln, Committen, Pushen +- PR zuerst nach `develop`, später nach bestandenen Tests nach `main` +- Reviewer zuweisen (für `main`) + +Nur tested und reviewed Code gelangt in die Produktion. + +--- + +## Ziel + +Das AdminTool soll eine wartbare, erweiterbare und zuverlässige Verwaltungsoberfläche bieten, die zentrale Aufgaben des AD‑Umfelds über eine moderne Weboberfläche ermöglicht. + From f5f2ba5b0f8238500e584ed31c1e920221b39dd1 Mon Sep 17 00:00:00 2001 From: tg95 Date: Fri, 28 Nov 2025 05:49:40 +0000 Subject: [PATCH 2/7] =?UTF-8?q?Oids=20hinzugef=C3=BCgt=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Oids in der Config hinzugefügt und den Snmpcontroller angepasst um die Daten des Servers auszulesen. Jens hat das ganze mit überprüft sollte so stimmen Co-authored-by: GraegelTh <165781231+GraegelTh@users.noreply.github.com> Co-authored-by: blaerf Co-authored-by: blaerf Reviewed-on: https://git.eckertplayground.de/taarly/PHP_AdminTool_Projekt/pulls/2 Reviewed-by: blaerf Co-authored-by: tg95 Co-committed-by: tg95 --- app/Services/Snmp/SnmpServerStatusService.php | 130 +++++++++++++++--- config/config.php | 19 ++- 2 files changed, 126 insertions(+), 23 deletions(-) diff --git a/app/Services/Snmp/SnmpServerStatusService.php b/app/Services/Snmp/SnmpServerStatusService.php index 13150ad..56ae54a 100644 --- a/app/Services/Snmp/SnmpServerStatusService.php +++ b/app/Services/Snmp/SnmpServerStatusService.php @@ -29,38 +29,134 @@ class SnmpServerStatusService // SNMP-Konfiguration in der Instanz speichern. $this->config = $snmpConfig; } - /** * Liefert den aktuellen Serverstatus zurück. * - * In dieser Version werden Demo-Daten auf Basis der Konfiguration erzeugt. - * Später können hier echte SNMP-Queries (z. B. über die PHP-SNMP-Extension) verwendet werden. - * * @return array Assoziatives Array mit Statuswerten (Hostname, CPU%, RAM%, etc.) * - * @throws RuntimeException wenn die SNMP-Konfiguration unvollständig ist (z. B. host fehlt) + * @throws RuntimeException wenn die SNMP-Konfiguration unvollständig ist oder Abfragen fehlschlagen */ public function getServerStatus(): array { - // Hostnamen aus der SNMP-Konfiguration lesen. - $host = (string)($this->config['host'] ?? ''); + // --- 1. Konfiguration auslesen --- + $host = (string)($this->config['host'] ?? '127.0.0.1'); + $community = (string)($this->config['community'] ?? ''); + $oids = $this->config['oids'] ?? []; + $timeout = (int)($this->config['timeout'] ?? 1) * 1_000_000; // in Mikrosekunden + $retries = (int)($this->config['retries'] ?? 1); - // Ohne Host ist keine sinnvolle Abfrage möglich -> Konfigurationsfehler. + // --- Prüfungen für essentielle Konfig-Werte --- if ($host === '') { throw new RuntimeException('SNMP-Konfiguration ist unvollständig (host fehlt).'); } + if ($community === '') { + throw new RuntimeException('SNMP-Konfiguration ist unvollständig (community fehlt).'); + } + if (empty($oids)) { + throw new RuntimeException('SNMP-Konfiguration ist unvollständig (oids fehlen).'); + } + + // Helper-Funktion zum Bereinigen von SNMP-Antworten (z.B. "INTEGER: 123" -> 123) + $cleanSnmpValue = fn($v) => (int)filter_var($v, FILTER_SANITIZE_NUMBER_INT); - // TODO: Später hier echte SNMP-Abfragen einbauen (z. B. snmp2_get/snmp2_walk). - // Die OIDs können aus $this->config['oids'] gelesen werden. - // Für den Anfang verwenden wir dieselben Demo-Werte wie vorher im DashboardController. + // --- 2. Uptime abfragen (war vorher nicht implementiert) --- + $uptimeResult = snmpget($host, $community, $oids['uptime'], $timeout, $retries); + if ($uptimeResult === false) { + throw new RuntimeException("SNMP Uptime GET fehlgeschlagen."); + } + // Uptime (timeticks) in ein lesbares Format umwandeln (optional, hier als String) + // Format ist oft "Timeticks: (12345678) 1 day, 10:17:36.78" + // Wir extrahieren den Teil in Klammern (Hundertstelsekunden) + preg_match('/\((.*?)\)/', $uptimeResult, $matches); + $uptimeTicks = (int)($matches[1] ?? 0); + $uptimeSeconds = $uptimeTicks / 100; + $uptimeFormatted = sprintf( + '%d Tage, %02d:%02d:%02d', + floor($uptimeSeconds / 86400), + floor(($uptimeSeconds % 86400) / 3600), + floor(($uptimeSeconds % 3600) / 60), + $uptimeSeconds % 60 + ); + + + // --- 3. CPU --- + $cpuValues = snmpwalk($host, $community, $oids['cpu_table'], $timeout, $retries); + + if (!is_array($cpuValues) || empty($cpuValues)) { + throw new RuntimeException("SNMP CPU WALK fehlgeschlagen."); + } + + $cpuValues = array_map($cleanSnmpValue, $cpuValues); + $cpuAvg = array_sum($cpuValues) / count($cpuValues); + + + // --- 4. Memory --- + $memTotalResult = snmpget($host, $community, $oids['mem_size'], $timeout, $retries); + if($memTotalResult === false) { + throw new RuntimeException("SNMP MemTotal GET fehlgeschlagen."); + } + + // memTotal in Bytes berechnen (korrigierte Reihenfolge von filter/cast) + $memTotal = $cleanSnmpValue($memTotalResult) * 1024; // KB -> Bytes + + // Storage-Tabelle (RAM + Disks) + $descr = snmpwalk($host, $community, $oids['storage_descr'], $timeout, $retries); + $units = snmpwalk($host, $community, $oids['storage_units'], $timeout, $retries); + $size = snmpwalk($host, $community, $oids['storage_size'], $timeout, $retries); + $used = snmpwalk($host, $community, $oids['storage_used'], $timeout, $retries); + + if ($descr === false || $units === false || $size === false || $used === false) { + throw new RuntimeException("SNMP Storage WALK fehlgeschlagen."); + } + + // Werte bereinigen + // Die SNMP-Antwort enthält "STRING: " und Anführungszeichen, die wir entfernen müssen. + $descr = array_map(fn($v) => trim(str_ireplace('STRING:', '', $v), ' "'), $descr); + + $units = array_map($cleanSnmpValue, $units); // Ints + $size = array_map($cleanSnmpValue, $size); // Ints + $used = array_map($cleanSnmpValue, $used); // Ints + + + + // RAM + $ramIndex = array_search("Physical Memory", $descr); + if ($ramIndex === false) { + throw new RuntimeException("Konnte 'Physical Memory' in der SNMP Storage-Tabelle nicht finden."); + } + + $ramUsedBytes = $units[$ramIndex] * $used[$ramIndex]; + $ramPercent = ($memTotal > 0) ? ($ramUsedBytes / $memTotal) * 100 : 0; + + + // --- 5. Disk C: --- + $cIndex = false; + foreach ($descr as $index => $description) { + // str_starts_with prüft, ob der String mit C:\ beginnt + if (str_starts_with($description, 'C:\\')) { + $cIndex = $index; + break; + } + } + + if ($cIndex === false) { + throw new RuntimeException("Konnte Laufwerk 'C:\' in der SNMP Storage-Tabelle nicht finden."); + } + + $cUsed = $units[$cIndex] * $used[$cIndex]; + $cTotal = $units[$cIndex] * $size[$cIndex]; + + $diskCPercent = ($cTotal > 0) ? ($cUsed / $cTotal) * 100 : 0; + + // --- 6. Status-Array zusammenbauen --- $status = [ 'hostname' => $host, - 'os' => 'Windows Server 2025 Datacenter', - 'uptime' => '3 Tage 12 Stunden', - 'cpu_usage' => 23, // CPU-Auslastung in Prozent (Demo) - 'memory_usage' => 62, // RAM-Auslastung in Prozent (Demo) - 'disk_usage_c' => 71, // Datenträger C in Prozent (Demo) - 'last_update' => date('d.m.Y H:i:s'), // Zeitpunkt der letzten Aktualisierung + 'os' => 'Windows Server 2025 Datacenter', // TODO: OS dynamisch abfragen + 'uptime' => $uptimeFormatted, // Fehlende Variable hinzugefügt + 'cpu_usage' => round($cpuAvg), + 'memory_usage' => round($ramPercent), + 'disk_usage_c' => round($diskCPercent), + 'last_update' => date('d.m.Y H:i:s'), ]; return $status; diff --git a/config/config.php b/config/config.php index a17c805..a84872e 100644 --- a/config/config.php +++ b/config/config.php @@ -29,17 +29,24 @@ return [ ], 'snmp' => [ - 'host' => 'itfa-proj-srv.itfa-proj-dom.local', + 'host' => '127.0.0.1', 'community' => 'public_ro', // später: sinnvoller Community-String 'timeout' => 2, // Sekunden 'retries' => 1, // Anzahl Wiederholungen // Platzhalter für OIDs – später können wir die auf echte Werte setzen 'oids' => [ - 'uptime' => '1.3.6.1.2.1.1.3.0', - 'cpu_usage' => '1.3.6.1.4.1.example.cpu.0', - 'memory_usage' => '1.3.6.1.4.1.example.memory.0', - 'disk_c' => '1.3.6.1.4.1.example.diskc.0', - ], + 'uptime' => '1.3.6.1.2.1.1.3.0', + + // CPU pro Kern + 'cpu_table' => '1.3.6.1.2.1.25.3.3.1.2', + + // Memory + 'mem_size' => '1.3.6.1.2.1.25.2.2.0', + 'storage_descr' => '1.3.6.1.2.1.25.2.3.1.3', + 'storage_units' => '1.3.6.1.2.1.25.2.3.1.4', + 'storage_size' => '1.3.6.1.2.1.25.2.3.1.5', + 'storage_used' => '1.3.6.1.2.1.25.2.3.1.6', + ], ], ]; From 7f7cab75e5df5698f21d2abc712650e81d654c87 Mon Sep 17 00:00:00 2001 From: blaerf Date: Fri, 28 Nov 2025 10:41:40 +0100 Subject: [PATCH 3/7] Layout modularisiert --- public/views/layout/footer.php | 1 + public/views/layout/head.php | 22 +++++ public/views/layout/layout.php | 1 + public/views/layout/sidebar.php | 137 ++++++++++++++++++++++++++++++++ public/views/layout/topbar.php | 1 + 5 files changed, 162 insertions(+) create mode 100644 public/views/layout/footer.php create mode 100644 public/views/layout/head.php create mode 100644 public/views/layout/layout.php create mode 100644 public/views/layout/sidebar.php create mode 100644 public/views/layout/topbar.php diff --git a/public/views/layout/footer.php b/public/views/layout/footer.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/public/views/layout/footer.php @@ -0,0 +1 @@ + + + + + + + +<?php echo htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> + + + + + + + diff --git a/public/views/layout/layout.php b/public/views/layout/layout.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/public/views/layout/layout.php @@ -0,0 +1 @@ + + + + + diff --git a/public/views/layout/topbar.php b/public/views/layout/topbar.php new file mode 100644 index 0000000..b3d9bbc --- /dev/null +++ b/public/views/layout/topbar.php @@ -0,0 +1 @@ + Date: Fri, 28 Nov 2025 13:52:07 +0100 Subject: [PATCH 4/7] Pfade angepasst --- public/views/layout/head.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/views/layout/head.php b/public/views/layout/head.php index 5b02021..f1661d1 100644 --- a/public/views/layout/head.php +++ b/public/views/layout/head.php @@ -13,10 +13,10 @@ $title = $pageTitle ?? 'AD Admin Tool'; <?php echo htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> - + - + From 8cd07a73a0b036884a45e41c2c572006f582de4b Mon Sep 17 00:00:00 2001 From: blaerf Date: Fri, 28 Nov 2025 13:54:33 +0100 Subject: [PATCH 5/7] Pfade angepasst --- public/views/layout/sidebar.php | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/public/views/layout/sidebar.php b/public/views/layout/sidebar.php index 95744d3..e025a25 100644 --- a/public/views/layout/sidebar.php +++ b/public/views/layout/sidebar.php @@ -9,7 +9,7 @@ $activeMenu = $activeMenu ?? '';