diff --git a/.gitignore b/.gitignore index 09376cf..dfc3214 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ /.idea/ /.vscode/ /storage/ -/config.php \ No newline at end of file +/config.php +/phpdoc.xml +/tools/ diff --git a/README.md b/README.md index e1462d5..c2d9162 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ Der komplette Ablauf ist im [Gitea-Workflow](https://git.eckertplayground.de/taa | UI/UX anpassen | Yasin B (@Muchentuchen), Alexander M (@Alexander) | | Blackbox Testing | Torsten J (@tojacobs) | +**Hinweis:** Die Passwortanforderungen (Mindestlänge, Kategorien, keine Teile des Benutzernamens) werden beim Erstellen validiert. Die Validierung ist in `scripts/powershell/create_users_csv.ps1` implementiert und die Mockup-UI (`docs/Mockup/index.html`) zeigt die Anforderungen und prüft sie clientseitig. + --- ## Dokumentation @@ -82,6 +84,35 @@ Dieser Bereich muss von allen Entwicklern gelesen werden, bevor am Projekt gearb --- +## PowerShell Integration (Benutzererstellung) + +Die Weboberfläche nutzt PowerShell-Skripte, um Active Directory Benutzer anzulegen. Damit dies funktioniert, sind folgende Voraussetzungen erforderlich: + +- Der Webserver läuft auf Windows und PHP kann PowerShell ausführen (`powershell` oder `pwsh`). +- Die PowerShell-Module `ActiveDirectory` müssen installiert (RSAT) und verfügbar sein. +- Der Benutzer, unter dem der Webserver läuft, muss ausreichende Rechte besitzen, um `New-ADUser` und `Add-ADGroupMember` auszuführen. +- Im `config/config.php` kann `powershell.dry_run` auf `true` gesetzt werden, um Tests ohne Änderungen durchzuführen. + +Konfigurationsoptionen (in `config/config.php`): +- `powershell.exe`: Name oder Pfad zur PowerShell-Executable (standard `powershell`). +- `powershell.script_dir`: Pfad zu den PowerShell-Skripten (standard `scripts/powershell`). +- `powershell.execution_policy`: Auszuführende ExecutionPolicy (z. B. `Bypass`). +- `powershell.dry_run`: Wenn `true`, werden keine echten AD-Änderungen durchgeführt; das Skript meldet nur, was es tun würde. + +Die grundlegende Funktionalität wurde mit folgenden Komponenten implementiert: +- `public/api/create_user.php`: API-Endpoint zur Erstellung eines einzelnen Benutzers. +- `public/api/create_users_csv.php`: API-Endpoint zur Erstellung mehrerer Benutzer aus CSV. +- `scripts/powershell/create_user.ps1`: PowerShell-Skript zum Erstellen eines einzelnen Benutzers. +- `scripts/powershell/create_users_csv.ps1`: PowerShell-Skript zum Erstellen mehrerer Benutzer aus CSV. + +- `scripts/powershell/check_environment.ps1`: Prüft, ob `ActiveDirectory`-Modul vorhanden ist und zeigt die ausführende Identität an. + +API endpoints: +- `public/api/powershell_check.php`: Ruft `check_environment.ps1` auf und gibt ein JSON-Objekt mit `actor`, `module_installed`, `can_new_aduser` zurück. + +Bitte testen zuerst mit `powershell.dry_run = true` und prüfen sie die resultierenden Meldungen in UI. + + ## Mitwirken Wer etwas ändern oder erweitern möchte: diff --git a/app/Controllers/LogViewerController.php b/app/Controllers/LogViewerController.php new file mode 100644 index 0000000..8f91585 --- /dev/null +++ b/app/Controllers/LogViewerController.php @@ -0,0 +1,123 @@ + */ + private array $config; + + private LoggingService $logger; + private LogViewerService $logViewer; + + /** + * @param array $config + */ + public function __construct(array $config) + { + $this->config = $config; + + $loggingConfig = $config['logging'] ?? []; + $this->logger = new LoggingService($loggingConfig); + $this->logViewer = new LogViewerService($loggingConfig); + } + + /** + * Zeigt den Log Viewer an. + * + * Erwartet optionale GET-Parameter: + * - file (Dateiname, z.B. app.log) + * - level (DEBUG|INFO|WARNING|ERROR) + * - q (Suche) + * - lines (Anzahl Zeilen, Default 200) + * + * @return array + */ + public function show(): array + { + $files = $this->logViewer->listLogFiles(); + + $selectedFile = (string)($_GET['file'] ?? ''); + if ($selectedFile === '' && isset($files[0]['name'])) { + $selectedFile = (string)$files[0]['name']; + } + + $level = (string)($_GET['level'] ?? ''); + $level = strtoupper(trim($level)); + if ($level === '') { + $level = ''; + } + + $q = (string)($_GET['q'] ?? ''); + $q = trim($q); + + $lines = (int)($_GET['lines'] ?? 200); + if ($lines <= 0) { + $lines = 200; + } + if ($lines > 2000) { + $lines = 2000; + } + + $error = null; + $fileMeta = null; + $entries = []; + + try { + if ($selectedFile !== '') { + $fileMeta = $this->logViewer->getFileMeta($selectedFile); + $entries = $this->logViewer->getEntries( + $selectedFile, + $lines, + $level !== '' ? $level : null, + $q !== '' ? $q : null + ); + + if ($fileMeta === null) { + $error = 'Die ausgewählte Log-Datei ist nicht verfügbar.'; + $entries = []; + } + } else { + $error = 'Es wurde keine Log-Datei gefunden.'; + } + } catch (\Throwable $ex) { + $this->logger->logException( + 'LogViewerController: Fehler beim Laden der Logs.', + $ex, + [ + 'route' => 'logs', + 'file' => $selectedFile, + ] + ); + + $error = 'Technischer Fehler beim Laden der Logs. Details stehen im app.log.'; + } + + $viewPath = __DIR__ . '/../../public/views/logs.php'; + + return [ + 'view' => $viewPath, + 'data' => [ + 'loginPage' => false, + 'files' => $files, + 'selectedFile' => $selectedFile, + 'fileMeta' => $fileMeta, + 'entries' => $entries, + 'filterLevel' => $level, + 'searchQuery' => $q, + 'lines' => $lines, + 'error' => $error, + ], + 'pageTitle' => 'Logs', + 'activeMenu' => 'logs', + ]; + } +} diff --git a/app/Controllers/UserManagementController.php b/app/Controllers/UserManagementController.php index 9e35640..c84695e 100644 --- a/app/Controllers/UserManagementController.php +++ b/app/Controllers/UserManagementController.php @@ -100,4 +100,49 @@ class UserManagementController 'activeMenu' => 'users', ]; } + + /** + * Zeigt die Seite zum Erstellen von Benutzern (Einzel/CSV). + * + * @return array + */ + public function create(): array + { + $viewPath = __DIR__ . '/../../public/views/createuser.php'; + + // Use session flash messages if available + $error = null; + $success = null; + if (session_status() !== PHP_SESSION_ACTIVE) { + @session_start(); + } + if (isset($_SESSION['flash_error'])) { + $error = $_SESSION['flash_error']; + unset($_SESSION['flash_error']); + } + if (isset($_SESSION['flash_success'])) { + $success = $_SESSION['flash_success']; + unset($_SESSION['flash_success']); + } + $csvDetails = null; + if (isset($_SESSION['csv_details'])) { + $csvDetails = $_SESSION['csv_details']; + unset($_SESSION['csv_details']); + } + + $powershellDryRun = $this->config['powershell']['dry_run'] ?? false; + + return [ + 'view' => $viewPath, + 'data' => [ + 'error' => $error, + 'success' => $success, + 'loginPage' => false, + 'csvDetails' => $csvDetails, + 'powershellDryRun' => $powershellDryRun, + ], + 'pageTitle' => 'Benutzer erstellen', + 'activeMenu' => 'createuser', + ]; + } } diff --git a/app/Services/Logging/LogViewerService.php b/app/Services/Logging/LogViewerService.php new file mode 100644 index 0000000..31fb1d5 --- /dev/null +++ b/app/Services/Logging/LogViewerService.php @@ -0,0 +1,319 @@ + $loggingConfig Teilkonfiguration "logging" aus config.php + */ + public function __construct(array $loggingConfig) + { + $baseDir = $loggingConfig['log_dir'] ?? (__DIR__ . '/../../../public/logs'); + $this->logDir = rtrim((string)$baseDir, DIRECTORY_SEPARATOR); + } + + /** + * @return array + */ + public function listLogFiles(): array + { + $result = []; + + if (is_dir($this->logDir) === false) { + return $result; + } + + $entries = @scandir($this->logDir); + if ($entries === false) { + return $result; + } + + foreach ($entries as $name) { + if ($name === '.' || $name === '..') { + continue; + } + + // Nur normale Dateien, keine Unterordner. + $fullPath = $this->logDir . DIRECTORY_SEPARATOR . $name; + if (is_file($fullPath) === false) { + continue; + } + + // Safety: nur "logartige" Dateien anzeigen. + $lower = strtolower($name); + if ( + str_ends_with($lower, '.log') === false + && str_ends_with($lower, '.txt') === false + ) { + continue; + } + + $size = @filesize($fullPath); + $mtime = @filemtime($fullPath); + + $result[] = [ + 'name' => $name, + 'size' => is_int($size) ? $size : 0, + 'mtime' => is_int($mtime) ? $mtime : 0, + ]; + } + + // Neueste zuerst + usort( + $result, + static function (array $a, array $b): int { + return ($b['mtime'] ?? 0) <=> ($a['mtime'] ?? 0); + } + ); + + return $result; + } + + /** + * Liefert Metadaten zur ausgewählten Datei (oder null wenn ungültig). + * + * @return array{name:string, size:int, mtime:int}|null + */ + public function getFileMeta(string $fileName): ?array + { + $path = $this->resolveLogFilePath($fileName); + if ($path === null) { + return null; + } + + $size = @filesize($path); + $mtime = @filemtime($path); + + return [ + 'name' => basename($path), + 'size' => is_int($size) ? $size : 0, + 'mtime' => is_int($mtime) ? $mtime : 0, + ]; + } + + /** + * @param string $fileName + * @param int $maxLines + * @param string|null $levelFilter z.B. "ERROR"|"WARNING"|"INFO"|"DEBUG"|null + * @param string|null $search Freitextsuche in message/context/raw + * + * @return array|null, + * raw:string + * }> + */ + public function getEntries(string $fileName, int $maxLines = 200, ?string $levelFilter = null, ?string $search = null): array + { + $path = $this->resolveLogFilePath($fileName); + if ($path === null) { + return []; + } + + $lines = $this->tailLines($path, $maxLines); + + $entries = []; + foreach ($lines as $line) { + $parsed = $this->parseLine($line); + + if ($levelFilter !== null && $levelFilter !== '') { + $lvl = strtoupper((string)($parsed['level'] ?? '')); + if ($lvl !== strtoupper($levelFilter)) { + continue; + } + } + + if ($search !== null && $search !== '') { + $haystack = $parsed['raw'] . ' ' . $parsed['message']; + + if (is_array($parsed['context'])) { + $haystack .= ' ' . (string)json_encode($parsed['context'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } + + if (mb_stripos($haystack, $search) === false) { + continue; + } + } + + $entries[] = $parsed; + } + + return $entries; + } + + /** + * @return string|null Vollständiger Pfad oder null, wenn ungültig/Traversal + */ + private function resolveLogFilePath(string $fileName): ?string + { + $fileName = trim($fileName); + if ($fileName === '') { + return null; + } + + // Keine Pfade erlauben, nur Dateiname + $fileName = basename($fileName); + + $candidate = $this->logDir . DIRECTORY_SEPARATOR . $fileName; + + $realDir = realpath($this->logDir); + $realFile = realpath($candidate); + + if ($realDir === false || $realFile === false) { + return null; + } + + // Muss innerhalb des Log-Verzeichnisses liegen + $realDirNorm = rtrim($realDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + $realFileNorm = $realFile; + + if (str_starts_with($realFileNorm, $realDirNorm) === false) { + return null; + } + + if (is_file($realFileNorm) === false) { + return null; + } + + return $realFileNorm; + } + + /** + * Tail-Implementierung: liest die letzten $maxLines Zeilen. + * + * @return array + */ + private function tailLines(string $filePath, int $maxLines): array + { + $maxLines = max(1, min(2000, $maxLines)); + + $fh = @fopen($filePath, 'rb'); + if ($fh === false) { + return []; + } + + $chunkSize = 8192; + $buffer = ''; + $pos = -1; + $linesFound = 0; + + // ans Ende springen + @fseek($fh, 0, SEEK_END); + $fileSize = (int)@ftell($fh); + if ($fileSize <= 0) { + @fclose($fh); + return []; + } + + while ($linesFound <= $maxLines && -$pos < $fileSize) { + $readSize = $chunkSize; + if (-$pos + $chunkSize > $fileSize) { + $readSize = $fileSize - (-$pos); + } + + @fseek($fh, $pos - $readSize + 1, SEEK_END); + $chunk = (string)@fread($fh, $readSize); + + $buffer = $chunk . $buffer; + $linesFound = substr_count($buffer, "\n"); + + $pos -= $readSize; + } + + @fclose($fh); + + $lines = preg_split("/\r\n|\n|\r/", $buffer); + if (is_array($lines) === false) { + return []; + } + + // ggf. letzte leere Zeile raus + if (end($lines) === '') { + array_pop($lines); + } + + // letzte maxLines + $lines = array_slice($lines, -$maxLines); + + // Leere Zeilen am Anfang/Ende tolerieren, aber nicht komplett aufblasen + $clean = []; + foreach ($lines as $line) { + $line = (string)$line; + if ($line === '') { + continue; + } + $clean[] = $line; + } + + return $clean; + } + + /** + * @return array{ + * ts:string|null, + * level:string|null, + * message:string, + * context:array|null, + * raw:string + * } + */ + private function parseLine(string $line): array + { + $raw = $line; + + $ts = null; + $level = null; + $message = $line; + $context = null; + + // Basis: [timestamp] LEVEL ... + if (preg_match('/^\[(?[0-9\-:\s]{19})\]\s+(?[A-Z]+)\s+(?.*)$/', $line, $m) === 1) { + $ts = (string)$m['ts']; + $level = (string)$m['lvl']; + $rest = (string)$m['rest']; + + // Versuch: Context ist am Ende ein JSON-Objekt, das mit "{" beginnt und mit "}" endet. + $ctxCandidate = null; + + $lastBracePos = strrpos($rest, '{'); + if ($lastBracePos !== false) { + $maybeJson = substr($rest, $lastBracePos); + $maybeJson = trim($maybeJson); + + if ($maybeJson !== '' && str_starts_with($maybeJson, '{') && str_ends_with($maybeJson, '}')) { + $decoded = json_decode($maybeJson, true); + if (is_array($decoded)) { + $ctxCandidate = $decoded; + $rest = trim(substr($rest, 0, $lastBracePos)); + } + } + } + + $context = $ctxCandidate; + $message = $rest; + } + + return [ + 'ts' => $ts, + 'level' => $level, + 'message' => $message, + 'context' => $context, + 'raw' => $raw, + ]; + } +} diff --git a/app/Services/Snmp/SnmpServerStatusService.php b/app/Services/Snmp/SnmpServerStatusService.php index b75907e..9e4d5b9 100644 --- a/app/Services/Snmp/SnmpServerStatusService.php +++ b/app/Services/Snmp/SnmpServerStatusService.php @@ -67,7 +67,12 @@ class SnmpServerStatusService // Hilfsfunktion: SNMP-Werte bereinigen (z.B. "INTEGER: 123" -> 123) $cleanSnmpValue = fn($v) => (int)filter_var($v, FILTER_SANITIZE_NUMBER_INT); - // --- 2. Uptime abfragen --- + // --- 2. Hostname abfragen (dynamisch, nicht hardcoded) --- + $hostnameOid = $oids['hostname'] ?? '1.3.6.1.2.1.1.5.0'; // sysName OID + $hostnameResult = @snmpget($host, $community, $hostnameOid, $timeout, $retries); + $hostnameFromSnmp = $hostnameResult ? trim(str_ireplace('STRING:', '', $hostnameResult), ' "') : $host; + + // --- 3. Uptime abfragen --- $uptimeOid = $oids['uptime'] ?? '1.3.6.1.2.1.1.3.0'; $uptimeResult = @snmpget($host, $community, $uptimeOid, $timeout, $retries); if ($uptimeResult === false) { @@ -86,7 +91,7 @@ class SnmpServerStatusService (int)($uptimeSeconds % 60) ); - // --- 3. CPU (Durchschnitt über alle Kerne) --- + // --- 4. CPU (Durchschnitt über alle Kerne) --- $cpuTable = $oids['cpu_table'] ?? '1.3.6.1.2.1.25.3.3.1.2'; $cpuValues = @snmpwalk($host, $community, $cpuTable, $timeout, $retries); @@ -97,7 +102,7 @@ class SnmpServerStatusService $cpuValues = array_map($cleanSnmpValue, $cpuValues); $cpuAvg = (int)round(array_sum($cpuValues) / count($cpuValues)); - // --- 4. Storage-Tabellen (RAM + Disks) --- + // --- 5. Storage-Tabellen (RAM + Disks) --- $descrOid = $oids['storage_descr'] ?? '1.3.6.1.2.1.25.2.3.1.3'; $unitsOid = $oids['storage_units'] ?? '1.3.6.1.2.1.25.2.3.1.4'; $sizeOid = $oids['storage_size'] ?? '1.3.6.1.2.1.25.2.3.1.5'; @@ -118,7 +123,7 @@ class SnmpServerStatusService $size = array_map($cleanSnmpValue, $size); $used = array_map($cleanSnmpValue, $used); - // --- 5. RAM mit Fallback-Logik --- + // --- 6. RAM mit Fallback-Logik --- $ramPercent = null; $memTotalBytes = null; @@ -163,7 +168,7 @@ class SnmpServerStatusService throw new RuntimeException("Konnte 'Physical Memory' in der SNMP Storage-Tabelle nicht finden."); } - // --- 6. Disk C: / Root mit Fallback-Logik --- + // --- 7. Disk C: / Root mit Fallback-Logik --- $diskCPercent = null; // Heuristik 1: Suche nach C:\ @@ -212,9 +217,9 @@ class SnmpServerStatusService throw new RuntimeException("Konnte Laufwerk 'C:\\' oder Root-Partition in der SNMP Storage-Tabelle nicht finden."); } - // --- 7. Status-Array zusammenbauen --- + // --- 8. Status-Array zusammenbauen --- $status = [ - 'hostname' => $host, + 'hostname' => $hostnameFromSnmp, 'os' => 'Windows Server', // TODO: OS dynamisch per SNMP abfragen (OID 1.3.6.1.2.1.1.1.0) 'uptime' => $uptimeFormatted, 'cpu_usage' => $cpuAvg, diff --git a/config/config.php b/config/config.php index aebf7fe..b68f721 100644 --- a/config/config.php +++ b/config/config.php @@ -36,6 +36,7 @@ return [ // Platzhalter für OIDs – später können wir die auf echte Werte setzen 'oids' => [ + 'hostname' => '1.3.6.1.2.1.1.5.0', // sysName - Hostname des Servers 'uptime' => '1.3.6.1.2.1.1.3.0', // CPU pro Kern @@ -59,4 +60,16 @@ return [ // Minimale Stufe: debug, info, warning, error 'min_level' => 'info', ], + 'powershell' => [ + // Executable name: 'powershell' on Windows, 'pwsh' for PowerShell core. + 'exe' => 'powershell', + // Script directory where the PS1 scripts live (relative to config dir) + 'script_dir' => __DIR__ . '/../scripts/powershell', + // Execution policy to pass to the PowerShell invocation + 'execution_policy' => 'Bypass', + // Default OU. IIS only has write access there. + 'default_ou' => 'OU=WebAppUsers,DC=ITFA-PROJ-DOM,DC=local', + // For testing; if true, the scripts will run in dry-run mode (no real AD changes) + 'dry_run' => false, + ], ]; diff --git a/docs/Mockup/index.html b/docs/Mockup/index.html index be042cd..e097688 100644 --- a/docs/Mockup/index.html +++ b/docs/Mockup/index.html @@ -262,6 +262,10 @@ background-color: var(--color-secondary); } + + /* Password hint and invalid input styles */ + .password-hint { display:block; margin-top: 6px; font-size: 0.9rem; color: #6c757d; } + .invalid { border: 1px solid #c0152f; background-color: rgba(192,21,47,0.04); } @@ -280,6 +284,7 @@
+ Das Passwort muss mindestens 7 Zeichen lang sein, darf keine größeren Teile des Benutzernamens enthalten und muss Zeichen aus mindestens 3 von 4 Kategorien enthalten: Großbuchstaben, Kleinbuchstaben, Ziffern, Sonderzeichen.
@@ -377,14 +382,60 @@ } } + function validatePasswordJS(password, sam) { + const errors = []; + if (!password || password.length < 7) { + errors.push('Passwort muss mindestens 7 Zeichen lang sein.'); + } + let categories = 0; + if (/[A-Z]/.test(password)) categories++; + if (/[a-z]/.test(password)) categories++; + if (/\d/.test(password)) categories++; + if (/[^A-Za-z0-9]/.test(password)) categories++; + if (categories < 3) { + errors.push('Passwort muss Zeichen aus mindestens 3 von 4 Kategorien enthalten.'); + } + if (sam) { + const pwLower = password.toLowerCase(); + const samLower = sam.toLowerCase(); + if (pwLower.includes(samLower)) { + errors.push('Passwort darf den Benutzernamen nicht enthalten.'); + } else { + const minLen = 4; + if (samLower.length >= minLen) { + outer: for (let len = minLen; len <= samLower.length; len++) { + for (let s = 0; s <= samLower.length - len; s++) { + const sub = samLower.substr(s, len); + if (pwLower.includes(sub)) { + errors.push('Passwort darf keine größeren Teile des Benutzernamens enthalten.'); + break outer; + } + } + } + } + } + } + return errors; + } + document.getElementById('adForm').addEventListener('submit', (e) => { e.preventDefault(); - + + const firstname = document.getElementById('firstname').value.trim(); + const lastname = document.getElementById('lastname').value.trim(); + const samGuess = (firstname + lastname).replace(/\s+/g, ''); + const password = document.getElementById('password').value; + const pwErrors = validatePasswordJS(password, samGuess); + if (pwErrors.length > 0) { + alert('Passwort ungültig:\n' + pwErrors.join('\n')); + return; + } + const formData = { - firstname: document.getElementById('firstname').value, - lastname: document.getElementById('lastname').value, + firstname: firstname, + lastname: lastname, group: document.getElementById('group').value, - password: document.getElementById('password').value, + password: password, customFields: {} }; @@ -442,6 +493,9 @@ // Datenzeilen erstellen (mit editierbaren Inputs) tableBody.innerHTML = ''; + const pwdHeaderIndex = headers.findIndex(h => /pass(word)?/i.test(h)); + const samHeaderIndex = headers.findIndex(h => /(sam(accountname)?)|samaccountname/i.test(h)); + let foundInvalid = false; for (let i = 1; i < csvData.length; i++) { const row = csvData[i]; const tr = document.createElement('tr'); @@ -454,6 +508,10 @@ input.dataset.col = index; input.addEventListener('input', (e) => { csvData[i][index] = e.target.value; + // live re-validate if this is password or sam column + if (index === pwdHeaderIndex || index === samHeaderIndex) { + validateCsvPasswords(headers); + } }); td.appendChild(input); tr.appendChild(td); @@ -461,10 +519,53 @@ tableBody.appendChild(tr); } + // Validate password column if present + function validateCsvPasswords(headersLocal) { + const pwdIdx = pwdHeaderIndex; + const samIdx = samHeaderIndex; + foundInvalid = false; + // Clear previous highlights/messages + const rows = tableBody.querySelectorAll('tr'); + rows.forEach((r, idx) => { + r.querySelectorAll('input').forEach(inp => inp.classList.remove('invalid')); + }); + + if (pwdIdx >= 0) { + for (let r = 0; r < rows.length; r++) { + const inputs = rows[r].querySelectorAll('input'); + const pwdVal = inputs[pwdIdx] ? inputs[pwdIdx].value : ''; + const samVal = (samIdx >= 0 && inputs[samIdx]) ? inputs[samIdx].value : ''; + const errs = validatePasswordJS(pwdVal, samVal); + if (errs.length > 0) { + foundInvalid = true; + if (inputs[pwdIdx]) inputs[pwdIdx].classList.add('invalid'); + } + } + } + + const previewInfo = previewDiv.querySelector('.preview-info'); + if (!previewInfo) return; + if (foundInvalid) { + previewInfo.innerHTML = 'Hinweis: Einige Passwörter entsprechen nicht den Anforderungen. Bitte korrigieren Sie diese in der Tabelle bevor Sie importieren.'; + } else { + previewInfo.innerHTML = 'Hinweis: Sie können die Werte direkt in der Tabelle bearbeiten, bevor Sie importieren.'; + } + } + + // initial validation run + validateCsvPasswords(headers); + previewDiv.style.display = 'block'; } function importCSVData() { + // Prevent import if any password entries are invalid (highlighted) + const invalids = document.querySelectorAll('#csvTableBody input.invalid'); + if (invalids.length > 0) { + alert('Import abgebrochen: Es gibt ungültige Passwörter in der CSV-Vorschau. Bitte korrigieren Sie diese zuerst.'); + return; + } + console.log('Importierte CSV-Daten:', csvData); alert(`${csvData.length - 1} Benutzer erfolgreich importiert!\n\nDaten in der Konsole (F12) einsehen.`); cancelCSVPreview(); diff --git a/docs/api/classes/App-Controllers-AuthController.html b/docs/api/classes/App-Controllers-AuthController.html new file mode 100644 index 0000000..ba48213 --- /dev/null +++ b/docs/api/classes/App-Controllers-AuthController.html @@ -0,0 +1,721 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
+

Documentation

+ + + + + +
+ +
+
+ + + + +
+
+ + +
+

+ AuthController + + +
+ in package + +
+ + +

+ +
+ + +
+ + + +

Zuständig für alles rund um den Login: +- Login-Formular anzeigen +- Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD) +- Logout durchführen

+ + +

NEU:

+
    +
  • Statt direkt HTML auszugeben oder header()-Redirects zu setzen, +liefert der Controller "View-Results" zurück, die von index.php +und einem zentralen Layout verarbeitet werden.
  • +
+
+ + + + + + + +

+ Table of Contents + + +

+ + + + + + + + + +

+ Properties + + +

+
+
+ $config + +  : array<string, mixed> +
+ +
+ $ldapAuthService + +  : LdapAuthService +
+ +
+ $logger + +  : LoggingService +
+ +
+ +

+ Methods + + +

+
+
+ __construct() + +  : mixed +
+
Übergibt die Konfiguration an den Controller und initialisiert den LDAP-Authentifizierungsservice.
+ +
+ logout() + +  : array<string, mixed> +
+
Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird, +und liefert anschließend ein Redirect-Result zurück auf die Login-Seite.
+ +
+ processLogin() + +  : array<string, mixed> +
+
Verarbeitet das Login-Formular: +- Liest Benutzername und Passwort aus $_POST +- Ruft den LdapAuthService zur Authentifizierung auf +- Liefert bei Erfolg ein Redirect-Result zum Dashboard +- Liefert bei Fehlern ein View-Result für das Login-Formular mit Fehlermeldung
+ +
+ showLoginForm() + +  : array<string, mixed> +
+
Zeigt das Login-Formular an.
+ +
+ + + + + + +
+

+ Properties + + +

+
+

+ $config + + + + +

+ + + + + + private + array<string, mixed> + $config + + + +

Konfigurationswerte der Anwendung (aus config.php)

+
+ + + + + + + +
+
+

+ $ldapAuthService + + + + +

+ + + + + + private + LdapAuthService + $ldapAuthService + + + +

Service, der die eigentliche LDAP/AD-Authentifizierung übernimmt

+
+ + + + + + + +
+ +
+ +
+

+ Methods + + +

+
+

+ __construct() + + +

+ + +

Übergibt die Konfiguration an den Controller und initialisiert den LDAP-Authentifizierungsservice.

+ + + public + __construct(array<string, mixed> $config) : mixed + +
+
+ + +
Parameters
+
+
+ $config + : array<string, mixed> +
+
+

Vollständige Konfiguration aus config.php

+
+ +
+
+ + + + + + +
+
+

+ logout() + + +

+ + +

Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird, +und liefert anschließend ein Redirect-Result zurück auf die Login-Seite.

+ + + public + logout() : array<string, mixed> + +
+
+ + + + + + + +
+
Return values
+ array<string, mixed> + — +

Redirect-Result

+
+ +
+ +
+
+

+ processLogin() + + +

+ + +

Verarbeitet das Login-Formular: +- Liest Benutzername und Passwort aus $_POST +- Ruft den LdapAuthService zur Authentifizierung auf +- Liefert bei Erfolg ein Redirect-Result zum Dashboard +- Liefert bei Fehlern ein View-Result für das Login-Formular mit Fehlermeldung

+ + + public + processLogin() : array<string, mixed> + +
+
+ + + + + + + +
+
Return values
+ array<string, mixed> + — +

View-Result ODER Redirect-Result

+
+ +
+ +
+
+

+ showLoginForm() + + +

+ + +

Zeigt das Login-Formular an.

+ + + public + showLoginForm([string|null $errorMessage = null ]) : array<string, mixed> + +
+
+ +

Optional kann eine Fehlermeldung übergeben werden, die in der View dargestellt wird.

+
+ +
Parameters
+
+
+ $errorMessage + : string|null + = null
+
+ +
+
+ + + + + +
+
Return values
+ array<string, mixed> + — +

View-Result für das zentrale Layout

+
+ +
+ +
+
+ +
+
+
+
+

+        
+ +
+
+ + + +
+
+
+ +
+ On this page + + +
+ +
+
+
+
+
+

Search results

+ +
+
+
    +
    +
    +
    +
    + + +
    + + + + + + + + diff --git a/docs/api/classes/App-Controllers-DashboardController.html b/docs/api/classes/App-Controllers-DashboardController.html new file mode 100644 index 0000000..234ec02 --- /dev/null +++ b/docs/api/classes/App-Controllers-DashboardController.html @@ -0,0 +1,537 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
    +

    Documentation

    + + + + + +
    + +
    +
    + + + + +
    +
    + + +
    +

    + DashboardController + + +
    + in package + +
    + + +

    + +
    + + +
    + + + +

    Controller für das Dashboard.

    + + +

    Zeigt Serverstatus-Metriken über SNMP an:

    +
      +
    • Initial Load: Server-seitiger Service-Aufruf (sofortige Daten)
    • +
    • Live-Updates: Client-seitiges JavaScript-Polling alle 5s
    • +
    +
    + + + + + + + +

    + Table of Contents + + +

    + + + + + + + + + +

    + Properties + + +

    +
    +
    + $config + +  : array<string|int, mixed> +
    + +
    + $snmpService + +  : SnmpServerStatusService +
    + +
    + +

    + Methods + + +

    +
    +
    + __construct() + +  : mixed +
    + +
    + show() + +  : array<string|int, mixed> +
    +
    Zeigt das Dashboard an.
    + +
    + + + + + + +
    +

    + Properties + + +

    +
    +

    + $config + + + + +

    + + + + + + private + array<string|int, mixed> + $config + + + + + + + + + + +
    + +
    + +
    +

    + Methods + + +

    +
    +

    + __construct() + + +

    + + + + + public + __construct(array<string|int, mixed> $config) : mixed + +
    +
    + + +
    Parameters
    +
    +
    + $config + : array<string|int, mixed> +
    +
    + +
    +
    + + + + + + +
    +
    +

    + show() + + +

    + + +

    Zeigt das Dashboard an.

    + + + public + show() : array<string|int, mixed> + +
    +
    + +

    Beim initialen Laden wird der Service aufgerufen, um sofort Daten anzuzeigen. +Live-Updates erfolgen anschließend via JavaScript-Polling (api/snmp_status.php alle 5s).

    +
    + + + + + + +
    +
    Return values
    + array<string|int, mixed> +
    + +
    +
    + +
    +
    +
    +
    +
    
    +        
    + +
    +
    + + + +
    +
    +
    + +
    + On this page + + +
    + +
    +
    +
    +
    +
    +

    Search results

    + +
    +
    +
      +
      +
      +
      +
      + + +
      + + + + + + + + diff --git a/docs/api/classes/App-Controllers-UserManagementController.html b/docs/api/classes/App-Controllers-UserManagementController.html new file mode 100644 index 0000000..68909c8 --- /dev/null +++ b/docs/api/classes/App-Controllers-UserManagementController.html @@ -0,0 +1,650 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
      +

      Documentation

      + + + + + +
      + +
      +
      + + + + +
      +
      + + +
      +

      + UserManagementController + + +
      + in package + +
      + + +

      + +
      + + +
      + + + +

      Controller für die Benutzer- und Gruppenanzeige.

      + + +

      Aufgaben:

      +
        +
      • holt über den LdapDirectoryService die Listen von Benutzern und Gruppen
      • +
      • behandelt technische Fehler und bereitet eine Fehlermeldung für die View auf
      • +
      • gibt die Daten an eine View-Datei (public/views/users.php) weiter
      • +
      +

      WICHTIG:

      +
        +
      • Es werden aktuell nur Daten angezeigt (Read-only).
      • +
      • Es findet keine Änderung im Active Directory statt.
      • +
      +

      NEU:

      +
        +
      • Gibt ein View-Result-Array zurück, das von index.php + Layout gerendert wird.
      • +
      +
      + + + + + + + +

      + Table of Contents + + +

      + + + + + + + + + +

      + Properties + + +

      +
      +
      + $config + +  : array<string, mixed> +
      + +
      + $directoryService + +  : LdapDirectoryService +
      + +
      + $logger + +  : LoggingService +
      + +
      + +

      + Methods + + +

      +
      +
      + __construct() + +  : mixed +
      + +
      + create() + +  : array<string, mixed> +
      +
      Zeigt die Seite zum Erstellen von Benutzern (Einzel/CSV).
      + +
      + show() + +  : array<string, mixed> +
      +
      Zeigt Benutzer- und Gruppenliste an.
      + +
      + + + + + + +
      +

      + Properties + + +

      +
      +

      + $config + + + + +

      + + + + + + private + array<string, mixed> + $config + + + +

      Vollständige Anwendungskonfiguration (aus config.php)

      +
      + + + + + + + +
      + + +
      + +
      +

      + Methods + + +

      +
      +

      + __construct() + + +

      + + + + + public + __construct(array<string, mixed> $config) : mixed + +
      +
      + + +
      Parameters
      +
      +
      + $config + : array<string, mixed> +
      +
      +

      Vollständige Konfiguration aus config.php

      +
      + +
      +
      + + + + + + +
      +
      +

      + create() + + +

      + + +

      Zeigt die Seite zum Erstellen von Benutzern (Einzel/CSV).

      + + + public + create() : array<string, mixed> + +
      +
      + + + + + + + +
      +
      Return values
      + array<string, mixed> +
      + +
      +
      +

      + show() + + +

      + + +

      Zeigt Benutzer- und Gruppenliste an.

      + + + public + show() : array<string, mixed> + +
      +
      + +

      Wird typischerweise über die Route "users" (index.php?route=users) aufgerufen.

      +
      + + + + + + +
      +
      Return values
      + array<string, mixed> + — +

      View-Result für das zentrale Layout

      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      
      +        
      + +
      +
      + + + +
      +
      +
      + +
      + On this page + + +
      + +
      +
      +
      +
      +
      +

      Search results

      + +
      +
      +
        +
        +
        +
        +
        + + +
        + + + + + + + + diff --git a/docs/api/classes/App-Services-Ldap-LdapAuthService.html b/docs/api/classes/App-Services-Ldap-LdapAuthService.html new file mode 100644 index 0000000..c2416d6 --- /dev/null +++ b/docs/api/classes/App-Services-Ldap-LdapAuthService.html @@ -0,0 +1,584 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
        +

        Documentation

        + + + + + +
        + +
        +
        + + + + +
        +
        + + +
        +

        + LdapAuthService + + +
        + in package + +
        + + +

        + +
        + + +
        + + + +

        Service zur Authentifizierung von Benutzern gegen ein Active Directory per LDAP/LDAPS.

        + + +

        Bekommt Benutzername und Passwort und liefert:

        +
          +
        • true -> Anmeldedaten sind gültig
        • +
        • false -> Anmeldedaten sind fachlich ungültig (z. B. falsches Passwort) +Technische Fehler (z. B. falsche Konfiguration, keine Verbindung) werden als Exception geworfen.
        • +
        +
        + + + + + + + +

        + Table of Contents + + +

        + + + + + + + + + +

        + Properties + + +

        +
        +
        + $config + +  : array<string, mixed> +
        + +
        + $connectionHelper + +  : LdapConnectionHelper +
        + +
        + +

        + Methods + + +

        +
        +
        + __construct() + +  : mixed +
        +
        Erwartet den Teilbereich "ldap" aus der allgemeinen Konfiguration (config.php).
        + +
        + authenticate() + +  : bool +
        +
        Führt die eigentliche LDAP/AD-Authentifizierung durch.
        + +
        + + + + + + +
        +

        + Properties + + +

        +
        +

        + $config + + + + +

        + + + + + + private + array<string, mixed> + $config + + + +

        LDAP-spezifische Konfiguration (Server, Port, Domain-Suffix, Timeout, etc.)

        +
        + + + + + + + +
        + +
        + +
        +

        + Methods + + +

        +
        +

        + __construct() + + +

        + + +

        Erwartet den Teilbereich "ldap" aus der allgemeinen Konfiguration (config.php).

        + + + public + __construct(array<string, mixed> $ldapConfig) : mixed + +
        +
        + + +
        Parameters
        +
        +
        + $ldapConfig + : array<string, mixed> +
        +
        +

        Konfiguration für die LDAP-Verbindung

        +
        + +
        +
        + + + + + + +
        +
        +

        + authenticate() + + +

        + + +

        Führt die eigentliche LDAP/AD-Authentifizierung durch.

        + + + public + authenticate(string $username, string $password) : bool + +
        +
        + + +
        Parameters
        +
        +
        + $username + : string +
        +
        +

        Benutzername (ohne Domain-Suffix, z. B. "administrator")

        +
        + +
        +
        + $password + : string +
        +
        +

        Passwort im Klartext (wird direkt an ldap_bind übergeben)

        +
        + +
        +
        + + +
        + Tags + + +
        +
        +
        + throws +
        +
        + RuntimeException + +

        bei technischen Problemen (z. B. fehlende Konfiguration, Verbindungsfehler)

        +
        + +
        +
        + + + +
        +
        Return values
        + bool + — +

        true bei erfolgreicher Anmeldung, false bei fachlich ungültigen Anmeldedaten

        +
        + +
        + +
        +
        + +
        +
        +
        +
        +
        
        +        
        + +
        +
        + + + +
        +
        +
        + +
        + On this page + + +
        + +
        +
        +
        +
        +
        +

        Search results

        + +
        +
        +
          +
          +
          +
          +
          + + +
          + + + + + + + + diff --git a/docs/api/classes/App-Services-Ldap-LdapConnectionHelper.html b/docs/api/classes/App-Services-Ldap-LdapConnectionHelper.html new file mode 100644 index 0000000..8e02747 --- /dev/null +++ b/docs/api/classes/App-Services-Ldap-LdapConnectionHelper.html @@ -0,0 +1,524 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
          +

          Documentation

          + + + + + +
          + +
          +
          + + + + +
          +
          + + +
          +

          + LdapConnectionHelper + + +
          + in package + +
          + + +

          + +
          + + +
          + + + +

          Hilfsklasse zum Aufbau einer LDAP/LDAPS-Verbindung.

          + + +

          Aufgaben:

          +
            +
          • liest Server, Port und Timeout aus der LDAP-Konfiguration
          • +
          • erstellt eine LDAP-Verbindung
          • +
          • setzt die notwendigen Optionen (Protokollversion, Netzwerk-Timeout)
          • +
          +

          Wichtig:

          +
            +
          • Diese Klasse führt KEIN ldap_bind durch.
          • +
          • Das Bind (mit Benutzer- oder Service-Konto) erfolgt in den Fach-Services +wie LdapAuthService oder LdapDirectoryService.
          • +
          +
          + + + + + + + +

          + Table of Contents + + +

          + + + + + + + + + +

          + Properties + + +

          +
          +
          + $config + +  : array<string, mixed> +
          + +
          + +

          + Methods + + +

          +
          +
          + __construct() + +  : mixed +
          + +
          + createConnection() + +  : resource +
          +
          Erstellt eine LDAP-Verbindung mit gesetzten Optionen (Protokollversion, Timeout), +aber ohne Bind. Den Bind führen die aufrufenden Services durch.
          + +
          + + + + + + +
          +

          + Properties + + +

          +
          +

          + $config + + + + +

          + + + + + + private + array<string, mixed> + $config + + + +

          LDAP-spezifische Konfiguration (server, port, timeout, etc.)

          +
          + + + + + + + +
          +
          + +
          +

          + Methods + + +

          +
          +

          + __construct() + + +

          + + + + + public + __construct(array<string, mixed> $ldapConfig) : mixed + +
          +
          + + +
          Parameters
          +
          +
          + $ldapConfig + : array<string, mixed> +
          +
          +

          Teilbereich "ldap" aus der config.php

          +
          + +
          +
          + + + + + + +
          +
          +

          + createConnection() + + +

          + + +

          Erstellt eine LDAP-Verbindung mit gesetzten Optionen (Protokollversion, Timeout), +aber ohne Bind. Den Bind führen die aufrufenden Services durch.

          + + + public + createConnection() : resource + +
          +
          + + + + +
          + Tags + + +
          +
          +
          + throws +
          +
          + RuntimeException + +

          wenn der Server nicht konfiguriert ist oder die Verbindung scheitert

          +
          + +
          +
          + + + +
          +
          Return values
          + resource + — +

          LDAP-Verbindungs-Handle

          +
          + +
          + +
          +
          + +
          +
          +
          +
          +
          
          +        
          + +
          +
          + + + +
          +
          +
          + +
          + On this page + + +
          + +
          +
          +
          +
          +
          +

          Search results

          + +
          +
          +
            +
            +
            +
            +
            + + +
            + + + + + + + + diff --git a/docs/api/classes/App-Services-Ldap-LdapDirectoryService.html b/docs/api/classes/App-Services-Ldap-LdapDirectoryService.html new file mode 100644 index 0000000..5d19682 --- /dev/null +++ b/docs/api/classes/App-Services-Ldap-LdapDirectoryService.html @@ -0,0 +1,711 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
            +

            Documentation

            + + + + + +
            + +
            +
            + + + + +
            +
            + + +
            +

            + LdapDirectoryService + + +
            + in package + +
            + + +

            + +
            + + +
            + + + +

            Service zum Lesen von Objekten aus dem Active Directory.

            + + +

            Aktueller Umfang:

            +
              +
            • Liste von Benutzern (sAMAccountName, displayName, mail)
            • +
            • Liste von Gruppen (sAMAccountName, cn, description)
            • +
            +

            Technische Details:

            +
              +
            • Verwendet ein technisches Konto (bind_dn + bind_password) für Lesezugriffe
            • +
            • Nutzt LdapConnectionHelper zum Aufbau der Verbindung
            • +
            +
            + + + + + + + +

            + Table of Contents + + +

            + + + + + + + + + +

            + Properties + + +

            +
            +
            + $config + +  : array<string, mixed> +
            + +
            + $connectionHelper + +  : LdapConnectionHelper +
            + +
            + +

            + Methods + + +

            +
            +
            + __construct() + +  : mixed +
            + +
            + getGroups() + +  : array<int, array<string, string>> +
            +
            Liefert eine Liste von Gruppen aus dem AD.
            + +
            + getUsers() + +  : array<int, array<string, string>> +
            +
            Liefert eine Liste von Benutzern aus dem AD.
            + +
            + connect() + +  : resource +
            +
            Stellt eine LDAP-Verbindung her und bindet sich mit dem technischen Konto.
            + +
            + + + + + + +
            +

            + Properties + + +

            +
            +

            + $config + + + + +

            + + + + + + private + array<string, mixed> + $config + + + +

            LDAP-Konfiguration (inkl. base_dn, bind_dn, bind_password)

            +
            + + + + + + + +
            +
            +

            + $connectionHelper + + + + +

            + + + + + + private + LdapConnectionHelper + $connectionHelper + + + +

            Zentrale Hilfsklasse für den Aufbau von LDAP-Verbindungen

            +
            + + + + + + + +
            +
            + +
            +

            + Methods + + +

            +
            +

            + __construct() + + +

            + + + + + public + __construct(array<string, mixed> $ldapConfig) : mixed + +
            +
            + + +
            Parameters
            +
            +
            + $ldapConfig + : array<string, mixed> +
            +
            +

            Teilbereich "ldap" aus der config.php

            +
            + +
            +
            + + + + + + +
            +
            +

            + getGroups() + + +

            + + +

            Liefert eine Liste von Gruppen aus dem AD.

            + + + public + getGroups() : array<int, array<string, string>> + +
            +
            + + + + +
            + Tags + + +
            +
            +
            + throws +
            +
            + RuntimeException + +

            bei Konfigurations- oder Verbindungsproblemen

            +
            + +
            +
            + + + +
            +
            Return values
            + array<int, array<string, string>> + — +

            Liste von Gruppen-Datensätzen

            +
            + +
            + +
            +
            +

            + getUsers() + + +

            + + +

            Liefert eine Liste von Benutzern aus dem AD.

            + + + public + getUsers() : array<int, array<string, string>> + +
            +
            + + + + +
            + Tags + + +
            +
            +
            + throws +
            +
            + RuntimeException + +

            bei Konfigurations- oder Verbindungsproblemen

            +
            + +
            +
            + + + +
            +
            Return values
            + array<int, array<string, string>> + — +

            Liste von Benutzer-Datensätzen +[ +[ +'samaccountname' => 'user1', +'displayname' => 'User Eins', +'mail' => 'user1@example.local', +], +... +]

            +
            + +
            + +
            +
            +

            + connect() + + +

            + + +

            Stellt eine LDAP-Verbindung her und bindet sich mit dem technischen Konto.

            + + + private + connect() : resource + +
            +
            + + + + +
            + Tags + + +
            +
            +
            + throws +
            +
            + RuntimeException + +

            wenn Bind-Daten fehlen oder der Bind fehlschlägt

            +
            + +
            +
            + + + +
            +
            Return values
            + resource + — +

            LDAP-Verbindungs-Handle

            +
            + +
            + +
            +
            + +
            +
            +
            +
            +
            
            +        
            + +
            +
            + + + +
            +
            +
            + +
            + On this page + + +
            + +
            +
            +
            +
            +
            +

            Search results

            + +
            +
            +
              +
              +
              +
              +
              + + +
              + + + + + + + + diff --git a/docs/api/classes/App-Services-Logging-LoggingService.html b/docs/api/classes/App-Services-Logging-LoggingService.html new file mode 100644 index 0000000..63b4096 --- /dev/null +++ b/docs/api/classes/App-Services-Logging-LoggingService.html @@ -0,0 +1,790 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
              +

              Documentation

              + + + + + +
              + +
              +
              + + + + +
              +
              + + +
              +

              + LoggingService + + +
              + in package + +
              + + +

              + +
              + + +
              + + + +

              Einfacher File-Logger für die AdminTool-Anwendung.

              + + +

              Ziele:

              +
                +
              • Technische Details werden in eine Log-Datei unter public/logs/ geschrieben.
              • +
              • In der Weboberfläche erscheinen nur verständliche, fachliche Fehlermeldungen.
              • +
              +
              + + + + + + + +

              + Table of Contents + + +

              + + + + + + + +

              + Constants + + +

              +
              +
              + LEVEL_MAP + +  = ['debug' => 100, 'info' => 200, 'warning' => 300, 'error' => 400] +
              +
              Zuordnung der Log-Level zu numerischen Werten zur Filterung.
              + +
              + + +

              + Properties + + +

              +
              +
              + $logDir + +  : string +
              + +
              + $logFile + +  : string +
              + +
              + $minLevel + +  : int +
              + +
              + +

              + Methods + + +

              +
              +
              + __construct() + +  : mixed +
              + +
              + log() + +  : void +
              +
              Allgemeiner Log-Eintrag.
              + +
              + logException() + +  : void +
              +
              Komfortmethode, um Exceptions strukturiert zu loggen.
              + +
              + ensureLogDirectoryExists() + +  : void +
              +
              Stellt sicher, dass das Log-Verzeichnis existiert.
              + +
              + + + + +
              +

              + Constants + + +

              +
              +

              + LEVEL_MAP + + +

              + + + +

              Zuordnung der Log-Level zu numerischen Werten zur Filterung.

              + + + + private + array<string, int> + LEVEL_MAP + = ['debug' => 100, 'info' => 200, 'warning' => 300, 'error' => 400] + + + + + + + + + +
              +
              + + +
              +

              + Properties + + +

              +
              +

              + $logDir + + + + +

              + + + + + + private + string + $logDir + + + +

              Vollständiger Pfad zum Log-Verzeichnis

              +
              + + + + + + + +
              +
              +

              + $logFile + + + + +

              + + + + + + private + string + $logFile + + + +

              Dateiname der Log-Datei

              +
              + + + + + + + +
              +
              +

              + $minLevel + + + + +

              + + + + + + private + int + $minLevel + + + +

              Minimale Log-Stufe, ab der geschrieben wird.

              +
              + + + + + + + +
              +
              + +
              +

              + Methods + + +

              +
              +

              + __construct() + + +

              + + + + + public + __construct(array<string, mixed> $config) : mixed + +
              +
              + + +
              Parameters
              +
              +
              + $config + : array<string, mixed> +
              +
              +

              Teilkonfiguration "logging" aus config.php

              +
              + +
              +
              + + + + + + +
              +
              +

              + log() + + +

              + + +

              Allgemeiner Log-Eintrag.

              + + + public + log(string $level, string $message[, array<string, mixed> $context = [] ]) : void + +
              +
              + + +
              Parameters
              +
              +
              + $level + : string +
              +
              +

              Log-Level (debug|info|warning|error)

              +
              + +
              +
              + $message + : string +
              +
              +

              Nachrichtentext

              +
              + +
              +
              + $context + : array<string, mixed> + = []
              +
              +

              Zusätzliche Kontextinformationen

              +
              + +
              +
              + + + + + + +
              +
              +

              + logException() + + +

              + + +

              Komfortmethode, um Exceptions strukturiert zu loggen.

              + + + public + logException(string $message, Throwable $exception[, array<string, mixed> $context = [] ]) : void + +
              +
              + + +
              Parameters
              +
              +
              + $message + : string +
              +
              +

              Kurzer Kontexttext zur Exception

              +
              + +
              +
              + $exception + : Throwable +
              +
              +

              Die geworfene Exception

              +
              + +
              +
              + $context + : array<string, mixed> + = []
              +
              +

              Zusätzlicher Kontext (Route, Benutzername, Remote-IP, ...)

              +
              + +
              +
              + + + + + + +
              +
              +

              + ensureLogDirectoryExists() + + +

              + + +

              Stellt sicher, dass das Log-Verzeichnis existiert.

              + + + private + ensureLogDirectoryExists() : void + +
              +
              + + + + + + + + +
              +
              + +
              +
              +
              +
              +
              
              +        
              + +
              +
              + + + +
              +
              +
              + +
              + On this page + + +
              + +
              +
              +
              +
              +
              +

              Search results

              + +
              +
              +
                +
                +
                +
                +
                + + +
                + + + + + + + + diff --git a/docs/api/classes/App-Services-Snmp-SnmpServerStatusService.html b/docs/api/classes/App-Services-Snmp-SnmpServerStatusService.html new file mode 100644 index 0000000..773ffb4 --- /dev/null +++ b/docs/api/classes/App-Services-Snmp-SnmpServerStatusService.html @@ -0,0 +1,521 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                +

                Documentation

                + + + + + +
                + +
                +
                + + + + +
                +
                + + +
                +

                + SnmpServerStatusService + + +
                + in package + +
                + + +

                + +
                + + +
                + + + +

                Service zur Ermittlung des Serverstatus per SNMP.

                + + +

                Features:

                +
                  +
                • Robuste Fehlerbehandlung mit aussagekräftigen Exceptions
                • +
                • Intelligente Fallback-Logik bei fehlenden oder unerwarteten OID-Beschreibungen
                • +
                • Unterstützung für Windows (C:) und Linux (/) Systeme
                • +
                • Detailliertes Logging über Exceptions
                • +
                +

                Wird vom DashboardController beim initialen Laden aufgerufen. +Das Live-Polling erfolgt über das API-Endpunkt (public/api/snmp_status.php).

                +
                + + + + + + + +

                + Table of Contents + + +

                + + + + + + + + + +

                + Properties + + +

                +
                +
                + $config + +  : array<string, mixed> +
                + +
                + +

                + Methods + + +

                +
                +
                + __construct() + +  : mixed +
                +
                Erwartet den Teilbereich "snmp" aus der allgemeinen Konfiguration (config.php).
                + +
                + getServerStatus() + +  : array<string, mixed> +
                +
                Liefert den aktuellen Serverstatus zurück.
                + +
                + + + + + + +
                +

                + Properties + + +

                +
                +

                + $config + + + + +

                + + + + + + private + array<string, mixed> + $config + + + +

                SNMP-Konfiguration (Host, Community, Timeout, OIDs, etc.)

                +
                + + + + + + + +
                +
                + +
                +

                + Methods + + +

                +
                +

                + __construct() + + +

                + + +

                Erwartet den Teilbereich "snmp" aus der allgemeinen Konfiguration (config.php).

                + + + public + __construct(array<string, mixed> $snmpConfig) : mixed + +
                +
                + + +
                Parameters
                +
                +
                + $snmpConfig + : array<string, mixed> +
                +
                +

                Konfiguration für die SNMP-Abfragen

                +
                + +
                +
                + + + + + + +
                +
                +

                + getServerStatus() + + +

                + + +

                Liefert den aktuellen Serverstatus zurück.

                + + + public + getServerStatus() : array<string, mixed> + +
                +
                + + + + +
                + Tags + + +
                +
                +
                + throws +
                +
                + RuntimeException + +

                wenn die SNMP-Konfiguration unvollständig ist oder Abfragen fehlschlagen

                +
                + +
                +
                + + + +
                +
                Return values
                + array<string, mixed> + — +

                Assoziatives Array mit Statuswerten (Hostname, CPU%, RAM%, etc.)

                +
                + +
                + +
                +
                + +
                +
                +
                +
                +
                
                +        
                + +
                +
                + + + +
                +
                +
                + +
                + On this page + + +
                + +
                +
                +
                +
                +
                +

                Search results

                + +
                +
                +
                  +
                  +
                  +
                  +
                  + + +
                  + + + + + + + + diff --git a/docs/api/css/base.css b/docs/api/css/base.css new file mode 100644 index 0000000..030ba07 --- /dev/null +++ b/docs/api/css/base.css @@ -0,0 +1,1236 @@ + + +:root { + /* Typography */ + --font-primary: 'Open Sans', Helvetica, Arial, sans-serif; + --font-secondary: 'Open Sans', Helvetica, Arial, sans-serif; + --font-monospace: 'Source Code Pro', monospace; + --line-height--primary: 1.6; + --letter-spacing--primary: .05rem; + --text-base-size: 1em; + --text-scale-ratio: 1.2; + + --text-xxs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-xs: calc(var(--text-base-size) / var(--text-scale-ratio) / var(--text-scale-ratio)); + --text-sm: calc(var(--text-base-size) / var(--text-scale-ratio)); + --text-md: var(--text-base-size); + --text-lg: calc(var(--text-base-size) * var(--text-scale-ratio)); + --text-xl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + --text-xxxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); + + --color-hue-red: 4; + --color-hue-pink: 340; + --color-hue-purple: 291; + --color-hue-deep-purple: 262; + --color-hue-indigo: 231; + --color-hue-blue: 207; + --color-hue-light-blue: 199; + --color-hue-cyan: 187; + --color-hue-teal: 174; + --color-hue-green: 122; + --color-hue-phpdocumentor-green: 96; + --color-hue-light-green: 88; + --color-hue-lime: 66; + --color-hue-yellow: 54; + --color-hue-amber: 45; + --color-hue-orange: 36; + --color-hue-deep-orange: 14; + --color-hue-brown: 16; + + /* Colors */ + --primary-color-hue: var(--color-hue-phpdocumentor-green, --color-hue-phpdocumentor-green); + --primary-color-saturation: 57%; + --primary-color: hsl(var(--primary-color-hue), var(--primary-color-saturation), 60%); + --primary-color-darken: hsl(var(--primary-color-hue), var(--primary-color-saturation), 40%); + --primary-color-darker: hsl(var(--primary-color-hue), var(--primary-color-saturation), 25%); + --primary-color-darkest: hsl(var(--primary-color-hue), var(--primary-color-saturation), 10%); + --primary-color-lighten: hsl(var(--primary-color-hue), calc(var(--primary-color-saturation) - 20%), 85%); + --primary-color-lighter: hsl(var(--primary-color-hue), calc(var(--primary-color-saturation) - 45%), 97.5%); + --dark-gray: #d1d1d1; + --light-gray: #f0f0f0; + + --text-color: var(--primary-color-darkest); + + --header-height: var(--spacing-xxxxl); + --header-bg-color: var(--primary-color); + --code-background-color: var(--primary-color-lighter); + --code-border-color: --primary-color-lighten; + --button-border-color: var(--primary-color-darken); + --button-color: transparent; + --button-color-primary: var(--primary-color); + --button-text-color: #555; + --button-text-color-primary: white; + --popover-background-color: rgba(255, 255, 255, 0.75); + --link-color-primary: var(--primary-color-darker); + --link-hover-color-primary: var(--primary-color-darkest); + --form-field-border-color: var(--dark-gray); + --form-field-color: #fff; + --admonition-success-color: var(--primary-color); + --admonition-border-color: silver; + --table-separator-color: var(--primary-color-lighten); + --title-text-color: var(--primary-color); + + --sidebar-border-color: var(--primary-color-lighten); + + /* Grid */ + --container-width: 1400px; + + /* Spacing */ + --spacing-base-size: 1rem; + --spacing-scale-ratio: 1.5; + + --spacing-xxxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xxs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-xs: calc(var(--spacing-base-size) / var(--spacing-scale-ratio) / var(--spacing-scale-ratio)); + --spacing-sm: calc(var(--spacing-base-size) / var(--spacing-scale-ratio)); + --spacing-md: var(--spacing-base-size); + --spacing-lg: calc(var(--spacing-base-size) * var(--spacing-scale-ratio)); + --spacing-xl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + --spacing-xxxxl: calc(var(--spacing-base-size) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio) * var(--spacing-scale-ratio)); + + --border-radius-base-size: 3px; +} + +/* Base Styles +-------------------------------------------------- */ +body { + background-color: #fff; + color: var(--text-color); + font-family: var(--font-primary); + font-size: var(--text-md); + letter-spacing: var(--letter-spacing--primary); + line-height: var(--line-height--primary); + width: 100%; +} + +.phpdocumentor h1, +.phpdocumentor h2, +.phpdocumentor h3, +.phpdocumentor h4, +.phpdocumentor h5, +.phpdocumentor h6 { + margin-bottom: var(--spacing-lg); + margin-top: var(--spacing-lg); + font-weight: 600; +} + +.phpdocumentor h1 { + font-size: var(--text-xxxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.2; + margin-top: 0; +} + +.phpdocumentor h2 { + font-size: var(--text-xxxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.25; +} + +.phpdocumentor h3 { + font-size: var(--text-xxl); + letter-spacing: var(--letter-spacing--primary); + line-height: 1.3; +} + +.phpdocumentor h4 { + font-size: var(--text-xl); + letter-spacing: calc(var(--letter-spacing--primary) / 2); + line-height: 1.35; + margin-bottom: var(--spacing-md); +} + +.phpdocumentor h5 { + font-size: var(--text-lg); + letter-spacing: calc(var(--letter-spacing--primary) / 4); + line-height: 1.5; + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} + +.phpdocumentor h6 { + font-size: var(--text-md); + letter-spacing: 0; + line-height: var(--line-height--primary); + margin-bottom: var(--spacing-md); + margin-top: var(--spacing-md); +} +.phpdocumentor h1 .headerlink, +.phpdocumentor h2 .headerlink, +.phpdocumentor h3 .headerlink, +.phpdocumentor h4 .headerlink, +.phpdocumentor h5 .headerlink, +.phpdocumentor h6 .headerlink +{ + display: none; +} + +@media (min-width: 550px) { + .phpdocumentor h1 .headerlink, + .phpdocumentor h2 .headerlink, + .phpdocumentor h3 .headerlink, + .phpdocumentor h4 .headerlink, + .phpdocumentor h5 .headerlink, + .phpdocumentor h6 .headerlink { + display: inline; + transition: all .3s ease-in-out; + opacity: 0; + text-decoration: none; + color: silver; + font-size: 80%; + } + + .phpdocumentor h1:hover .headerlink, + .phpdocumentor h2:hover .headerlink, + .phpdocumentor h3:hover .headerlink, + .phpdocumentor h4:hover .headerlink, + .phpdocumentor h5:hover .headerlink, + .phpdocumentor h6:hover .headerlink { + opacity: 1; + } +} +.phpdocumentor p { + margin-top: 0; + margin-bottom: var(--spacing-md); +} +.phpdocumentor figure { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor figcaption { + text-align: center; + font-style: italic; + font-size: 80%; +} + +.phpdocumentor-uml-diagram svg { + max-width: 100%; + height: auto !important; +} +.phpdocumentor-line { + border-top: 1px solid #E1E1E1; + border-width: 0; + margin-bottom: var(--spacing-xxl); + margin-top: var(--spacing-xxl); +} +.phpdocumentor-section { + box-sizing: border-box; + margin: 0 auto; + max-width: var(--container-width); + padding: 0 var(--spacing-sm); + position: relative; + width: 100%; +} + +@media (min-width: 550px) { + .phpdocumentor-section { + padding: 0 var(--spacing-lg); + } +} + +@media (min-width: 1200px) { + .phpdocumentor-section { + padding: 0; + width: 95%; + } +} +.phpdocumentor-column { + box-sizing: border-box; + float: left; + width: 100%; +} + +@media (min-width: 550px) { + .phpdocumentor-column { + margin-left: 4%; + } + + .phpdocumentor-column:first-child { + margin-left: 0; + } + + .-one.phpdocumentor-column { + width: 4.66666666667%; + } + + .-two.phpdocumentor-column { + width: 13.3333333333%; + } + + .-three.phpdocumentor-column { + width: 22%; + } + + .-four.phpdocumentor-column { + width: 30.6666666667%; + } + + .-five.phpdocumentor-column { + width: 39.3333333333%; + } + + .-six.phpdocumentor-column { + width: 48%; + } + + .-seven.phpdocumentor-column { + width: 56.6666666667%; + } + + .-eight.phpdocumentor-column { + width: 65.3333333333%; + } + + .-nine.phpdocumentor-column { + width: 74.0%; + } + + .-ten.phpdocumentor-column { + width: 82.6666666667%; + } + + .-eleven.phpdocumentor-column { + width: 91.3333333333%; + } + + .-twelve.phpdocumentor-column { + margin-left: 0; + width: 100%; + } + + .-one-third.phpdocumentor-column { + width: 30.6666666667%; + } + + .-two-thirds.phpdocumentor-column { + width: 65.3333333333%; + } + + .-one-half.phpdocumentor-column { + width: 48%; + } + + /* Offsets */ + .-offset-by-one.phpdocumentor-column { + margin-left: 8.66666666667%; + } + + .-offset-by-two.phpdocumentor-column { + margin-left: 17.3333333333%; + } + + .-offset-by-three.phpdocumentor-column { + margin-left: 26%; + } + + .-offset-by-four.phpdocumentor-column { + margin-left: 34.6666666667%; + } + + .-offset-by-five.phpdocumentor-column { + margin-left: 43.3333333333%; + } + + .-offset-by-six.phpdocumentor-column { + margin-left: 52%; + } + + .-offset-by-seven.phpdocumentor-column { + margin-left: 60.6666666667%; + } + + .-offset-by-eight.phpdocumentor-column { + margin-left: 69.3333333333%; + } + + .-offset-by-nine.phpdocumentor-column { + margin-left: 78.0%; + } + + .-offset-by-ten.phpdocumentor-column { + margin-left: 86.6666666667%; + } + + .-offset-by-eleven.phpdocumentor-column { + margin-left: 95.3333333333%; + } + + .-offset-by-one-third.phpdocumentor-column { + margin-left: 34.6666666667%; + } + + .-offset-by-two-thirds.phpdocumentor-column { + margin-left: 69.3333333333%; + } + + .-offset-by-one-half.phpdocumentor-column { + margin-left: 52%; + } +} +.phpdocumentor a { + color: var(--link-color-primary); +} + +.phpdocumentor a:hover { + color: var(--link-hover-color-primary); +} +.phpdocumentor-button { + background-color: var(--button-color); + border: 1px solid var(--button-border-color); + border-radius: var(--border-radius-base-size); + box-sizing: border-box; + color: var(--button-text-color); + cursor: pointer; + display: inline-block; + font-size: var(--text-sm); + font-weight: 600; + height: 38px; + letter-spacing: .1rem; + line-height: 38px; + padding: 0 var(--spacing-xxl); + text-align: center; + text-decoration: none; + text-transform: uppercase; + white-space: nowrap; + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-button .-wide { + width: 100%; +} + +.phpdocumentor-button:hover, +.phpdocumentor-button:focus { + border-color: #888; + color: #333; + outline: 0; +} + +.phpdocumentor-button.-primary { + background-color: var(--button-color-primary); + border-color: var(--button-color-primary); + color: var(--button-text-color-primary); +} + +.phpdocumentor-button.-primary:hover, +.phpdocumentor-button.-primary:focus { + background-color: var(--link-color-primary); + border-color: var(--link-color-primary); + color: var(--button-text-color-primary); +} +.phpdocumentor form { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-field { + background-color: var(--form-field-color); + border: 1px solid var(--form-field-border-color); + border-radius: var(--border-radius-base-size); + box-shadow: none; + box-sizing: border-box; + height: 38px; + padding: var(--spacing-xxxs) var(--spacing-xxs); /* The 6px vertically centers text on FF, ignored by Webkit */ + margin-bottom: var(--spacing-md); +} + +/* Removes awkward default styles on some inputs for iOS */ +input[type="email"], +input[type="number"], +input[type="search"], +input[type="text"], +input[type="tel"], +input[type="url"], +input[type="password"], +textarea { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; +} + +.phpdocumentor-textarea { + min-height: 65px; + padding-bottom: var(--spacing-xxxs); + padding-top: var(--spacing-xxxs); +} + +.phpdocumentor-field:focus { + border: 1px solid var(--button-color-primary); + outline: 0; +} + +label.phpdocumentor-label { + display: block; + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor-fieldset { + border-width: 0; + padding: 0; +} + +input[type="checkbox"].phpdocumentor-field, +input[type="radio"].phpdocumentor-field { + display: inline; +} +.phpdocumentor-column ul, +div.phpdocumentor-list > ul, +ul.phpdocumentor-list { + list-style: circle; +} + +.phpdocumentor-column ol, +div.phpdocumentor-list > ol, +ol.phpdocumentor-list { + list-style: decimal; +} + + +.phpdocumentor-column ul, +div.phpdocumentor-list > ul, +ol.phpdocumentor-list, +ul.phpdocumentor-list { + margin-top: 0; + padding-left: var(--spacing-lg); + margin-bottom: var(--spacing-sm); +} + +.phpdocumentor-column ul.-clean, +div.phpdocumentor-list > ul.-clean, +ul.phpdocumentor-list.-clean { + list-style: none; + padding-left: 0; +} + +dl { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-column ul ul, +div.phpdocumentor-list > ul ul, +ul.phpdocumentor-list ul.phpdocumentor-list, +ul.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ol.phpdocumentor-list, +ol.phpdocumentor-list ul.phpdocumentor-list { + font-size: var(--text-sm); + margin: 0 0 0 calc(var(--spacing-xs) * 2); +} + +.phpdocumentor-column ul li, +.phpdocumentor-list li { + padding-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dt { + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dd { + margin-bottom: var(--spacing-md); +} +.phpdocumentor pre { + margin-bottom: var(--spacing-md); +} + +.phpdocumentor-code { + font-family: var(--font-monospace); + background: var(--code-background-color); + border: 1px solid var(--code-border-color); + border-radius: var(--border-radius-base-size); + font-size: var(--text-sm); + padding: var(--spacing-sm) var(--spacing-md); + width: 100%; + box-sizing: border-box; +} + +.phpdocumentor-code.-dark { + background: var(--primary-color-darkest); + color: var(--light-gray); + box-shadow: 0 2px 3px var(--dark-gray); +} + +pre > .phpdocumentor-code { + display: block; + white-space: pre; +} +.phpdocumentor blockquote { + border-left: 4px solid var(--primary-color-darken); + margin: var(--spacing-md) 0; + padding: var(--spacing-xs) var(--spacing-sm); + color: var(--primary-color-darker); + font-style: italic; +} + +.phpdocumentor blockquote p:last-of-type { + margin-bottom: 0; +} +.phpdocumentor table { + margin-bottom: var(--spacing-md); +} + +th.phpdocumentor-heading, +td.phpdocumentor-cell { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) var(--spacing-md); + text-align: left; +} + +th.phpdocumentor-heading:first-child, +td.phpdocumentor-cell:first-child { + padding-left: 0; +} + +th.phpdocumentor-heading:last-child, +td.phpdocumentor-cell:last-child { + padding-right: 0; +} +.phpdocumentor-label-line { + display: flex; + flex-direction: row; + gap: 1rem +} + +.phpdocumentor-label { + background: #f6f6f6; + border-radius: .25rem; + font-size: 80%; + display: inline-block; + overflow: hidden +} + +/* +It would be better if the phpdocumentor-element class were to become a flex element with a gap, but for #3337 that +is too big a fix and needs to be done in a new design iteration. +*/ +.phpdocumentor-signature + .phpdocumentor-label-line .phpdocumentor-label { + margin-top: var(--spacing-sm); +} + +.phpdocumentor-label span { + display: inline-block; + padding: .125rem .5rem; +} + +.phpdocumentor-label--success span:last-of-type { + background: #abe1ab; +} + +.phpdocumentor-header { + display: flex; + flex-direction: row; + align-items: stretch; + flex-wrap: wrap; + justify-content: space-between; + height: auto; + padding: var(--spacing-md) var(--spacing-md); +} + +.phpdocumentor-header__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-header__menu-icon { + font-size: 2rem; + color: var(--primary-color); +} + +.phpdocumentor-header__menu-button:checked ~ .phpdocumentor-topnav { + max-height: 250px; + padding-top: var(--spacing-md); +} + +@media (min-width: 1000px) { + .phpdocumentor-header { + flex-direction: row; + padding: var(--spacing-lg) var(--spacing-lg); + min-height: var(--header-height); + } + + .phpdocumentor-header__menu-icon { + display: none; + } +} + +@media (min-width: 1000px) { + .phpdocumentor-header { + padding-top: 0; + padding-bottom: 0; + } +} +@media (min-width: 1200px) { + .phpdocumentor-header { + padding: 0; + } +} +.phpdocumentor-title { + box-sizing: border-box; + color: var(--title-text-color); + font-size: var(--text-xxl); + letter-spacing: .05rem; + font-weight: normal; + width: auto; + margin: 0; + display: flex; + align-items: center; +} + +.phpdocumentor-title.-without-divider { + border: none; +} + +.phpdocumentor-title__link { + transition: all .3s ease-out; + display: flex; + color: var(--title-text-color); + text-decoration: none; + font-weight: normal; + white-space: nowrap; + transform: scale(.75); + transform-origin: left; +} + +.phpdocumentor-title__link:hover { + transform: perspective(15rem) translateX(.5rem); + font-weight: 600; +} + +@media (min-width: 1000px) { + .phpdocumentor-title { + width: 22%; + border-right: var(--sidebar-border-color) solid 1px; + } + + .phpdocumentor-title__link { + transform-origin: left; + } +} + +@media (min-width: 1000px) { + .phpdocumentor-title__link { + transform: scale(.85); + } +} + +@media (min-width: 1200px) { + .phpdocumentor-title__link { + transform: scale(1); + } +} +.phpdocumentor-topnav { + display: flex; + align-items: center; + margin: 0; + max-height: 0; + overflow: hidden; + transition: max-height 0.2s ease-out; + flex-basis: 100%; +} + +.phpdocumentor-topnav__menu { + text-align: right; + list-style: none; + margin: 0; + padding: 0; + flex: 1; + display: flex; + flex-flow: row wrap; + justify-content: center; +} + +.phpdocumentor-topnav__menu-item { + margin: 0; + width: 100%; + display: inline-block; + text-align: center; + padding: var(--spacing-sm) 0 +} + +.phpdocumentor-topnav__menu-item.-social { + width: auto; + padding: var(--spacing-sm) +} + +.phpdocumentor-topnav__menu-item a { + display: inline-block; + color: var(--text-color); + text-decoration: none; + font-size: var(--text-lg); + transition: all .3s ease-out; + border-bottom: 1px dotted transparent; + line-height: 1; +} + +.phpdocumentor-topnav__menu-item a:hover { + transform: perspective(15rem) translateY(.1rem); + border-bottom: 1px dotted var(--text-color); +} + +@media (min-width: 1000px) { + .phpdocumentor-topnav { + max-height: none; + overflow: visible; + flex-basis: auto; + } + + .phpdocumentor-topnav__menu { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + } + + .phpdocumentor-topnav__menu-item, + .phpdocumentor-topnav__menu-item.-social { + width: auto; + display: inline; + text-align: right; + padding: 0 0 0 var(--spacing-md) + } +} +.phpdocumentor-sidebar { + margin: 0; + overflow: hidden; + max-height: 0; +} + +.phpdocumentor .phpdocumentor-sidebar .phpdocumentor-list { + padding: var(--spacing-xs) var(--spacing-md); + list-style: none; + margin: 0; +} + +.phpdocumentor .phpdocumentor-sidebar li { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + padding: 0 0 var(--spacing-xxxs) var(--spacing-md); +} + +.phpdocumentor .phpdocumentor-sidebar abbr, +.phpdocumentor .phpdocumentor-sidebar a { + text-decoration: none; + border-bottom: none; + color: var(--text-color); + font-size: var(--text-md); + padding-left: 0; + transition: padding-left .4s ease-out; +} + +.phpdocumentor .phpdocumentor-sidebar a:hover, +.phpdocumentor .phpdocumentor-sidebar a.-active { + padding-left: 5px; + font-weight: 600; +} + +.phpdocumentor .phpdocumentor-sidebar__category > * { + border-left: 1px solid var(--primary-color-lighten); +} + +.phpdocumentor .phpdocumentor-sidebar__category { + margin-bottom: var(--spacing-lg); +} + +.phpdocumentor .phpdocumentor-sidebar__category-header { + font-size: var(--text-md); + margin-top: 0; + margin-bottom: var(--spacing-xs); + color: var(--link-color-primary); + font-weight: 600; + border-left: 0; +} + +.phpdocumentor .phpdocumentor-sidebar__root-package, +.phpdocumentor .phpdocumentor-sidebar__root-namespace { + font-size: var(--text-md); + margin: 0; + padding-top: var(--spacing-xs); + padding-left: var(--spacing-md); + color: var(--text-color); + font-weight: normal; +} + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + border-right: var(--sidebar-border-color) solid 1px; + } +} + +.phpdocumentor-sidebar__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-sidebar__menu-icon { + font-size: var(--text-md); + font-weight: 600; + background: var(--primary-color); + color: white; + margin: 0 0 var(--spacing-lg); + display: block; + padding: var(--spacing-sm); + text-align: center; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: .15rem; +} + +.phpdocumentor-sidebar__menu-button:checked ~ .phpdocumentor-sidebar { + max-height: 100%; + padding-top: var(--spacing-md); +} + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + overflow: visible; + max-height: 100%; + } + + .phpdocumentor-sidebar__menu-icon { + display: none; + } +} +.phpdocumentor-admonition { + border: 1px solid var(--admonition-border-color); + border-radius: var(--border-radius-base-size); + border-color: var(--primary-color-lighten); + background-color: var(--primary-color-lighter); + padding: var(--spacing-lg); + margin: var(--spacing-lg) 0; + display: flex; + flex-direction: row; + align-items: flex-start; +} + +.phpdocumentor-admonition p:last-of-type { + margin-bottom: 0; +} + +.phpdocumentor-admonition--success, +.phpdocumentor-admonition.-success { + border-color: var(--admonition-success-color); +} + +.phpdocumentor-admonition__icon { + margin-right: var(--spacing-md); + color: var(--primary-color); + max-width: 3rem; +} +.phpdocumentor ul.phpdocumentor-breadcrumbs { + font-size: var(--text-md); + list-style: none; + margin: 0; + padding: 0; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs a { + color: var(--text-color); + text-decoration: none; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs > li { + display: inline-block; + margin: 0; +} + +.phpdocumentor ul.phpdocumentor-breadcrumbs > li + li:before { + color: var(--dark-gray); + content: "\\\A0"; + padding: 0; +} +.phpdocumentor .phpdocumentor-back-to-top { + position: fixed; + bottom: 2rem; + font-size: 2.5rem; + opacity: .25; + transition: all .3s ease-in-out; + right: 2rem; +} + +.phpdocumentor .phpdocumentor-back-to-top:hover { + color: var(--link-color-primary); + opacity: 1; +} +.phpdocumentor-search { + position: relative; + display: none; /** disable by default for non-js flow */ + opacity: .3; /** white-out default for loading indication */ + transition: opacity .3s, background .3s; + margin: var(--spacing-sm) 0; + flex: 1; + min-width: 100%; +} + +.phpdocumentor-search label { + display: flex; + align-items: center; + flex: 1; +} + +.phpdocumentor-search__icon { + color: var(--primary-color); + margin-right: var(--spacing-sm); + width: 1rem; + height: 1rem; +} + +.phpdocumentor-search--enabled { + display: flex; +} + +.phpdocumentor-search--active { + opacity: 1; +} + +.phpdocumentor-search input:disabled { + background-color: lightgray; +} + +.phpdocumentor-search__field:focus, +.phpdocumentor-search__field { + margin-bottom: 0; + border: 0; + border-bottom: 2px solid var(--primary-color); + padding: 0; + border-radius: 0; + flex: 1; +} + +@media (min-width: 1000px) { + .phpdocumentor-search { + min-width: auto; + max-width: 20rem; + margin: 0 0 0 auto; + } +} +.phpdocumentor-search-results { + backdrop-filter: blur(5px); + background: var(--popover-background-color); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + padding: 0; + opacity: 1; + pointer-events: all; + + transition: opacity .3s, background .3s; +} + +.phpdocumentor-search-results--hidden { + background: transparent; + backdrop-filter: blur(0); + opacity: 0; + pointer-events: none; +} + +.phpdocumentor-search-results__dialog { + width: 100%; + background: white; + max-height: 100%; + display: flex; + flex-direction: column; +} + +.phpdocumentor-search-results__body { + overflow: auto; +} + +.phpdocumentor-search-results__header { + padding: var(--spacing-lg); + display: flex; + justify-content: space-between; + background: var(--primary-color-darken); + color: white; + align-items: center; +} + +.phpdocumentor-search-results__close { + font-size: var(--text-xl); + background: none; + border: none; + padding: 0; + margin: 0; +} + +.phpdocumentor .phpdocumentor-search-results__title { + font-size: var(--text-xl); + margin-bottom: 0; +} + +.phpdocumentor-search-results__entries { + list-style: none; + padding: 0 var(--spacing-lg); + margin: 0; +} + +.phpdocumentor-search-results__entry { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) 0; + text-align: left; +} + +.phpdocumentor-search-results__entry a { + display: block; +} + +.phpdocumentor-search-results__entry small { + margin-top: var(--spacing-xs); + margin-bottom: var(--spacing-md); + color: var(--primary-color-darker); + display: block; + word-break: break-word; +} + +.phpdocumentor-search-results__entry h3 { + font-size: var(--text-lg); + margin: 0; +} + +@media (min-width: 550px) { + .phpdocumentor-search-results { + padding: 0 var(--spacing-lg); + } + + .phpdocumentor-search-results__entry h3 { + font-size: var(--text-xxl); + } + + .phpdocumentor-search-results__dialog { + margin: var(--spacing-xl) auto; + max-width: 40rem; + background: white; + border: 1px solid silver; + box-shadow: 0 2px 5px silver; + max-height: 40rem; + border-radius: 3px; + } +} +.phpdocumentor-modal { + position: fixed; + width: 100vw; + height: 100vh; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; +} + +.phpdocumentor-modal__open { + visibility: visible; + opacity: 1; + transition-delay: 0s; +} + +.phpdocumentor-modal-bg { + position: absolute; + background: gray; + opacity: 50%; + width: 100%; + height: 100%; +} + +.phpdocumentor-modal-container { + border-radius: 1em; + background: #fff; + position: relative; + padding: 2em; + box-sizing: border-box; + max-width:100vw; +} + +.phpdocumentor-modal__close { + position: absolute; + right: 0.75em; + top: 0.75em; + outline: none; + appearance: none; + color: var(--primary-color); + background: none; + border: 0px; + font-weight: bold; + cursor: pointer; +} +.phpdocumentor-on-this-page__sidebar { + display: none; +} + +.phpdocumentor-on-this-page__title { + display: block; + font-weight: bold; + margin-bottom: var(--spacing-sm); + color: var(--link-color-primary); +} + +@media (min-width: 1000px) { + .phpdocumentor-on-this-page__sidebar { + display: block; + position: relative; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar, + [scrollbars]::-webkit-scrollbar { + height: 8px; + width: 8px; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar-corner, + [scrollbars]::-webkit-scrollbar-corner { + background: 0; + } + + .phpdocumentor-on-this-page__content::-webkit-scrollbar-thumb, + [scrollbars]::-webkit-scrollbar-thumb { + background: rgba(128,134,139,0.26); + border-radius: 8px; + } + + .phpdocumentor-on-this-page__content { + position: sticky; + height: calc(100vh - var(--header-height)); + overflow-y: auto; + border-left: 1px solid var(--sidebar-border-color); + padding-left: var(--spacing-lg); + font-size: 90%; + top: -1px; /* Needed for the javascript to make the .-stuck trick work */ + flex: 0 1 auto; + width: 15vw; + } + + .phpdocumentor-on-this-page__content.-stuck { + height: 100vh; + } + + .phpdocumentor-on-this-page__content li { + word-break: break-all; + line-height: normal; + } + + .phpdocumentor-on-this-page__content li.-deprecated { + text-decoration: line-through; + } +} + +/* Used for screen readers and such */ +.visually-hidden { + display: none; +} + +.float-right { + float: right; +} + +.float-left { + float: left; +} diff --git a/docs/api/css/normalize.css b/docs/api/css/normalize.css new file mode 100644 index 0000000..653dc00 --- /dev/null +++ b/docs/api/css/normalize.css @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none !important; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: var(--font-monospace); + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/docs/api/css/template.css b/docs/api/css/template.css new file mode 100644 index 0000000..21919c0 --- /dev/null +++ b/docs/api/css/template.css @@ -0,0 +1,279 @@ + +.phpdocumentor-content { + position: relative; + display: flex; + gap: var(--spacing-md); +} + +.phpdocumentor-content > section:first-of-type { + width: 75%; + flex: 1 1 auto; +} + +@media (min-width: 1900px) { + .phpdocumentor-content > section:first-of-type { + width: 100%; + flex: 1 1 auto; + } +} + +.phpdocumentor .phpdocumentor-content__title { + margin-top: 0; +} +.phpdocumentor-summary { + font-style: italic; +} +.phpdocumentor-description { + margin-bottom: var(--spacing-md); +} +.phpdocumentor-element { + position: relative; +} + +.phpdocumentor-element .phpdocumentor-element { + border: 1px solid var(--primary-color-lighten); + margin-bottom: var(--spacing-md); + padding: var(--spacing-xs); + border-radius: 5px; +} + +.phpdocumentor-element.-deprecated .phpdocumentor-element__name { + text-decoration: line-through; +} + +@media (min-width: 550px) { + .phpdocumentor-element .phpdocumentor-element { + margin-bottom: var(--spacing-lg); + padding: var(--spacing-md); + } +} + +.phpdocumentor-element__modifier { + font-size: var(--text-xxs); + padding: calc(var(--spacing-base-size) / 4) calc(var(--spacing-base-size) / 2); + color: var(--text-color); + background-color: var(--light-gray); + border-radius: 3px; + text-transform: uppercase; +} + +.phpdocumentor .phpdocumentor-elements__header { + margin-top: var(--spacing-xxl); + margin-bottom: var(--spacing-lg); +} + +.phpdocumentor .phpdocumentor-element__name { + line-height: 1; + margin-top: 0; + font-weight: 300; + font-size: var(--text-lg); + word-break: break-all; + margin-bottom: var(--spacing-sm); +} + +@media (min-width: 550px) { + .phpdocumentor .phpdocumentor-element__name { + font-size: var(--text-xl); + margin-bottom: var(--spacing-xs); + } +} + +@media (min-width: 1200px) { + .phpdocumentor .phpdocumentor-element__name { + margin-bottom: var(--spacing-md); + } +} + +.phpdocumentor-element__package, +.phpdocumentor-element__extends, +.phpdocumentor-element__implements { + display: block; + font-size: var(--text-xxs); + font-weight: normal; + opacity: .7; +} + +.phpdocumentor-element__package .phpdocumentor-breadcrumbs { + display: inline; +} +.phpdocumentor .phpdocumentor-signature { + display: block; + font-size: var(--text-sm); + border: 1px solid #f0f0f0; + margin-bottom: calc(var(--spacing-sm)); +} + +.phpdocumentor .phpdocumentor-signature.-deprecated .phpdocumentor-signature__name { + text-decoration: line-through; +} + +@media (min-width: 550px) { + .phpdocumentor .phpdocumentor-signature { + margin-left: calc(var(--spacing-xl) * -1); + width: calc(100% + var(--spacing-xl)); + } +} + +.phpdocumentor-table-of-contents { +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry { + margin-bottom: var(--spacing-xxs); + margin-left: 2rem; + display: flex; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry > a { + flex: 0 1 auto; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry > a.-deprecated { + text-decoration: line-through; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry > span { + flex: 1; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry:after { + content: ''; + height: 12px; + width: 12px; + left: 16px; + position: absolute; +} +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-private:after { + background: url('data:image/svg+xml;utf8,') no-repeat; +} +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-protected:after { + left: 13px; + background: url('data:image/svg+xml;utf8,') no-repeat; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry:before { + width: 1.25rem; + height: 1.25rem; + line-height: 1.25rem; + background: transparent url('data:image/svg+xml;utf8,') no-repeat center center; + content: ''; + position: absolute; + left: 0; + border-radius: 50%; + font-weight: 600; + color: white; + text-align: center; + font-size: .75rem; + margin-top: .2rem; +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-method:before { + content: 'M'; + color: ''; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-function:before { + content: 'M'; + color: ' 96'; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-property:before { + content: 'P' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-constant:before { + content: 'C'; + background-color: transparent; + background-image: url('data:image/svg+xml;utf8,'); +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-class:before { + content: 'C' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-interface:before { + content: 'I' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-trait:before { + content: 'T' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-namespace:before { + content: 'N' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-package:before { + content: 'P' +} + +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-enum:before { + content: 'E' +} + +.phpdocumentor-table-of-contents dd { + font-style: italic; + margin-left: 2rem; +} +.phpdocumentor-element-found-in { + display: none; +} + +@media (min-width: 550px) { + .phpdocumentor-element-found-in { + display: block; + font-size: var(--text-sm); + color: gray; + margin-bottom: 1rem; + } +} + +@media (min-width: 1200px) { + .phpdocumentor-element-found-in { + position: absolute; + top: var(--spacing-sm); + right: var(--spacing-sm); + font-size: var(--text-sm); + margin-bottom: 0; + } +} + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source { + flex: 0 1 auto; + display: inline-flex; +} + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source:after { + width: 1.25rem; + height: 1.25rem; + line-height: 1.25rem; + background: transparent url('data:image/svg+xml;utf8,') no-repeat center center; + content: ''; + left: 0; + border-radius: 50%; + font-weight: 600; + text-align: center; + font-size: .75rem; + margin-top: .2rem; +} +.phpdocumentor-class-graph { + width: 100%; height: 600px; border:1px solid black; overflow: hidden +} + +.phpdocumentor-class-graph__graph { + width: 100%; +} +.phpdocumentor-tag-list__definition { + display: flex; +} + +.phpdocumentor-tag-link { + margin-right: var(--spacing-sm); +} +.phpdocumentor-uml-diagram svg { + cursor: zoom-in; +} \ No newline at end of file diff --git a/docs/api/files/app-controllers-authcontroller.html b/docs/api/files/app-controllers-authcontroller.html new file mode 100644 index 0000000..4c3bec3 --- /dev/null +++ b/docs/api/files/app-controllers-authcontroller.html @@ -0,0 +1,280 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                  +

                  Documentation

                  + + + + + +
                  + +
                  +
                  + + + + +
                  +
                  +
                    +
                  + +
                  +

                  AuthController.php

                  + + + + + + + + +

                  + Table of Contents + + +

                  + + + + +

                  + Classes + + +

                  +
                  +
                  AuthController
                  Zuständig für alles rund um den Login: +- Login-Formular anzeigen +- Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD) +- Logout durchführen
                  + + + + + + + + + + + + +
                  +
                  +
                  +
                  +
                  
                  +        
                  + +
                  +
                  + + + +
                  +
                  +
                  + +
                  + On this page + +
                    +
                  • Table Of Contents
                  • +
                  • + +
                  • + + +
                  +
                  + +
                  +
                  +
                  +
                  +
                  +

                  Search results

                  + +
                  +
                  +
                    +
                    +
                    +
                    +
                    + + +
                    + + + + + + + + diff --git a/docs/api/files/app-controllers-dashboardcontroller.html b/docs/api/files/app-controllers-dashboardcontroller.html new file mode 100644 index 0000000..d75c765 --- /dev/null +++ b/docs/api/files/app-controllers-dashboardcontroller.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                    +

                    Documentation

                    + + + + + +
                    + +
                    +
                    + + + + +
                    +
                    +
                      +
                    + +
                    +

                    DashboardController.php

                    + + + + + + + + +

                    + Table of Contents + + +

                    + + + + +

                    + Classes + + +

                    +
                    +
                    DashboardController
                    Controller für das Dashboard.
                    + + + + + + + + + + + + +
                    +
                    +
                    +
                    +
                    
                    +        
                    + +
                    +
                    + + + +
                    +
                    +
                    + +
                    + On this page + +
                      +
                    • Table Of Contents
                    • +
                    • + +
                    • + + +
                    +
                    + +
                    +
                    +
                    +
                    +
                    +

                    Search results

                    + +
                    +
                    +
                      +
                      +
                      +
                      +
                      + + +
                      + + + + + + + + diff --git a/docs/api/files/app-controllers-usermanagementcontroller.html b/docs/api/files/app-controllers-usermanagementcontroller.html new file mode 100644 index 0000000..658c676 --- /dev/null +++ b/docs/api/files/app-controllers-usermanagementcontroller.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                      +

                      Documentation

                      + + + + + +
                      + +
                      +
                      + + + + +
                      +
                      +
                        +
                      + +
                      +

                      UserManagementController.php

                      + + + + + + + + +

                      + Table of Contents + + +

                      + + + + +

                      + Classes + + +

                      +
                      +
                      UserManagementController
                      Controller für die Benutzer- und Gruppenanzeige.
                      + + + + + + + + + + + + +
                      +
                      +
                      +
                      +
                      
                      +        
                      + +
                      +
                      + + + +
                      +
                      +
                      + +
                      + On this page + +
                        +
                      • Table Of Contents
                      • +
                      • + +
                      • + + +
                      +
                      + +
                      +
                      +
                      +
                      +
                      +

                      Search results

                      + +
                      +
                      +
                        +
                        +
                        +
                        +
                        + + +
                        + + + + + + + + diff --git a/docs/api/files/app-services-ldap-ldapauthservice.html b/docs/api/files/app-services-ldap-ldapauthservice.html new file mode 100644 index 0000000..201b4b6 --- /dev/null +++ b/docs/api/files/app-services-ldap-ldapauthservice.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                        +

                        Documentation

                        + + + + + +
                        + +
                        +
                        + + + + +
                        +
                        +
                          +
                        + +
                        +

                        LdapAuthService.php

                        + + + + + + + + +

                        + Table of Contents + + +

                        + + + + +

                        + Classes + + +

                        +
                        +
                        LdapAuthService
                        Service zur Authentifizierung von Benutzern gegen ein Active Directory per LDAP/LDAPS.
                        + + + + + + + + + + + + +
                        +
                        +
                        +
                        +
                        
                        +        
                        + +
                        +
                        + + + +
                        +
                        +
                        + +
                        + On this page + +
                          +
                        • Table Of Contents
                        • +
                        • + +
                        • + + +
                        +
                        + +
                        +
                        +
                        +
                        +
                        +

                        Search results

                        + +
                        +
                        +
                          +
                          +
                          +
                          +
                          + + +
                          + + + + + + + + diff --git a/docs/api/files/app-services-ldap-ldapconnectionhelper.html b/docs/api/files/app-services-ldap-ldapconnectionhelper.html new file mode 100644 index 0000000..be77cf8 --- /dev/null +++ b/docs/api/files/app-services-ldap-ldapconnectionhelper.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                          +

                          Documentation

                          + + + + + +
                          + +
                          +
                          + + + + +
                          +
                          +
                            +
                          + +
                          +

                          LdapConnectionHelper.php

                          + + + + + + + + +

                          + Table of Contents + + +

                          + + + + +

                          + Classes + + +

                          +
                          +
                          LdapConnectionHelper
                          Hilfsklasse zum Aufbau einer LDAP/LDAPS-Verbindung.
                          + + + + + + + + + + + + +
                          +
                          +
                          +
                          +
                          
                          +        
                          + +
                          +
                          + + + +
                          +
                          +
                          + +
                          + On this page + +
                            +
                          • Table Of Contents
                          • +
                          • + +
                          • + + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          +

                          Search results

                          + +
                          +
                          +
                            +
                            +
                            +
                            +
                            + + +
                            + + + + + + + + diff --git a/docs/api/files/app-services-ldap-ldapdirectoryservice.html b/docs/api/files/app-services-ldap-ldapdirectoryservice.html new file mode 100644 index 0000000..69fbd82 --- /dev/null +++ b/docs/api/files/app-services-ldap-ldapdirectoryservice.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                            +

                            Documentation

                            + + + + + +
                            + +
                            +
                            + + + + +
                            +
                            +
                              +
                            + +
                            +

                            LdapDirectoryService.php

                            + + + + + + + + +

                            + Table of Contents + + +

                            + + + + +

                            + Classes + + +

                            +
                            +
                            LdapDirectoryService
                            Service zum Lesen von Objekten aus dem Active Directory.
                            + + + + + + + + + + + + +
                            +
                            +
                            +
                            +
                            
                            +        
                            + +
                            +
                            + + + +
                            +
                            +
                            + +
                            + On this page + +
                              +
                            • Table Of Contents
                            • +
                            • + +
                            • + + +
                            +
                            + +
                            +
                            +
                            +
                            +
                            +

                            Search results

                            + +
                            +
                            +
                              +
                              +
                              +
                              +
                              + + +
                              + + + + + + + + diff --git a/docs/api/files/app-services-logging-loggingservice.html b/docs/api/files/app-services-logging-loggingservice.html new file mode 100644 index 0000000..7383759 --- /dev/null +++ b/docs/api/files/app-services-logging-loggingservice.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                              +

                              Documentation

                              + + + + + +
                              + +
                              +
                              + + + + +
                              +
                              +
                                +
                              + +
                              +

                              LoggingService.php

                              + + + + + + + + +

                              + Table of Contents + + +

                              + + + + +

                              + Classes + + +

                              +
                              +
                              LoggingService
                              Einfacher File-Logger für die AdminTool-Anwendung.
                              + + + + + + + + + + + + +
                              +
                              +
                              +
                              +
                              
                              +        
                              + +
                              +
                              + + + +
                              +
                              +
                              + +
                              + On this page + +
                                +
                              • Table Of Contents
                              • +
                              • + +
                              • + + +
                              +
                              + +
                              +
                              +
                              +
                              +
                              +

                              Search results

                              + +
                              +
                              +
                                +
                                +
                                +
                                +
                                + + +
                                + + + + + + + + diff --git a/docs/api/files/app-services-snmp-snmpserverstatusservice.html b/docs/api/files/app-services-snmp-snmpserverstatusservice.html new file mode 100644 index 0000000..89e34ad --- /dev/null +++ b/docs/api/files/app-services-snmp-snmpserverstatusservice.html @@ -0,0 +1,277 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                +

                                Documentation

                                + + + + + +
                                + +
                                +
                                + + + + +
                                +
                                +
                                  +
                                + +
                                +

                                SnmpServerStatusService.php

                                + + + + + + + + +

                                + Table of Contents + + +

                                + + + + +

                                + Classes + + +

                                +
                                +
                                SnmpServerStatusService
                                Service zur Ermittlung des Serverstatus per SNMP.
                                + + + + + + + + + + + + +
                                +
                                +
                                +
                                +
                                
                                +        
                                + +
                                +
                                + + + +
                                +
                                +
                                + +
                                + On this page + +
                                  +
                                • Table Of Contents
                                • +
                                • + +
                                • + + +
                                +
                                + +
                                +
                                +
                                +
                                +
                                +

                                Search results

                                + +
                                +
                                +
                                  +
                                  +
                                  +
                                  +
                                  + + +
                                  + + + + + + + + diff --git a/docs/api/graphs/classes.html b/docs/api/graphs/classes.html new file mode 100644 index 0000000..db70187 --- /dev/null +++ b/docs/api/graphs/classes.html @@ -0,0 +1,120 @@ + + + + + Documentation + + + + + + + + + +
                                  +

                                  Documentation

                                  + + + + + +
                                  + +
                                  +
                                  + + + + +
                                  +
                                  + +
                                  + +
                                  +
                                  +
                                  +
                                  +

                                  Search results

                                  + +
                                  +
                                  +
                                    +
                                    +
                                    +
                                    +
                                    + + +
                                    + + + + + + + + diff --git a/docs/api/index.html b/docs/api/index.html new file mode 100644 index 0000000..dd2aea5 --- /dev/null +++ b/docs/api/index.html @@ -0,0 +1,163 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                    +

                                    Documentation

                                    + + + + + +
                                    + +
                                    +
                                    + + + + +
                                    +
                                    +

                                    Documentation

                                    + + + +

                                    + Table of Contents + + +

                                    + +

                                    + Packages + + +

                                    +
                                    +
                                    Application
                                    +
                                    + +

                                    + Namespaces + + +

                                    +
                                    +
                                    App
                                    +
                                    + + + + + + + + + + + + + +
                                    +
                                    +
                                    +
                                    +
                                    +

                                    Search results

                                    + +
                                    +
                                    +
                                      +
                                      +
                                      +
                                      +
                                      + + +
                                      + + + + + + + + diff --git a/docs/api/indices/files.html b/docs/api/indices/files.html new file mode 100644 index 0000000..dd0045e --- /dev/null +++ b/docs/api/indices/files.html @@ -0,0 +1,148 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                      +

                                      Documentation

                                      + + + + + +
                                      + +
                                      +
                                      + + + + + +
                                      +
                                      +
                                      +

                                      Search results

                                      + +
                                      +
                                      +
                                        +
                                        +
                                        +
                                        +
                                        + + +
                                        + + + + + + + + diff --git a/docs/api/js/search.js b/docs/api/js/search.js new file mode 100644 index 0000000..093d6d0 --- /dev/null +++ b/docs/api/js/search.js @@ -0,0 +1,173 @@ +// Search module for phpDocumentor +// +// This module is a wrapper around fuse.js that will use a given index and attach itself to a +// search form and to a search results pane identified by the following data attributes: +// +// 1. data-search-form +// 2. data-search-results +// +// The data-search-form is expected to have a single input element of type 'search' that will trigger searching for +// a series of results, were the data-search-results pane is expected to have a direct UL child that will be populated +// with rendered results. +// +// The search has various stages, upon loading this stage the data-search-form receives the CSS class +// 'phpdocumentor-search--enabled'; this indicates that JS is allowed and indices are being loaded. It is recommended +// to hide the form by default and show it when it receives this class to achieve progressive enhancement for this +// feature. +// +// After loading this module, it is expected to load a search index asynchronously, for example: +// +// +// +// In this script the generated index should attach itself to the search module using the `appendIndex` function. By +// doing it like this the page will continue loading, unhindered by the loading of the search. +// +// After the page has fully loaded, and all these deferred indexes loaded, the initialization of the search module will +// be called and the form will receive the class 'phpdocumentor-search--active', indicating search is ready. At this +// point, the input field will also have it's 'disabled' attribute removed. +var Search = (function () { + var fuse; + var index = []; + var options = { + shouldSort: true, + threshold: 0.6, + location: 0, + distance: 100, + maxPatternLength: 32, + minMatchCharLength: 1, + keys: [ + "fqsen", + "name", + "summary", + "url" + ] + }; + + // Credit David Walsh (https://davidwalsh.name/javascript-debounce-function) + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + function debounce(func, wait, immediate) { + var timeout; + + return function executedFunction() { + var context = this; + var args = arguments; + + var later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; + } + + function close() { + // Start scroll prevention: https://css-tricks.com/prevent-page-scrolling-when-a-modal-is-open/ + const scrollY = document.body.style.top; + document.body.style.position = ''; + document.body.style.top = ''; + window.scrollTo(0, parseInt(scrollY || '0') * -1); + // End scroll prevention + + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + + form.classList.toggle('phpdocumentor-search--has-results', false); + searchResults.classList.add('phpdocumentor-search-results--hidden'); + var searchField = document.querySelector('[data-search-form] input[type="search"]'); + searchField.blur(); + } + + function search(event) { + // Start scroll prevention: https://css-tricks.com/prevent-page-scrolling-when-a-modal-is-open/ + document.body.style.position = 'fixed'; + document.body.style.top = `-${window.scrollY}px`; + // End scroll prevention + + // prevent enter's from autosubmitting + event.stopPropagation(); + + var form = document.querySelector('[data-search-form]'); + var searchResults = document.querySelector('[data-search-results]'); + var searchResultEntries = document.querySelector('[data-search-results] .phpdocumentor-search-results__entries'); + + searchResultEntries.innerHTML = ''; + + if (!event.target.value) { + close(); + return; + } + + form.classList.toggle('phpdocumentor-search--has-results', true); + searchResults.classList.remove('phpdocumentor-search-results--hidden'); + var results = fuse.search(event.target.value, {limit: 25}); + + results.forEach(function (result) { + var entry = document.createElement("li"); + entry.classList.add("phpdocumentor-search-results__entry"); + entry.innerHTML += '

                                        ' + result.name + "

                                        \n"; + entry.innerHTML += '' + result.fqsen + "\n"; + entry.innerHTML += '
                                        ' + result.summary + '
                                        '; + searchResultEntries.appendChild(entry) + }); + } + + function appendIndex(added) { + index = index.concat(added); + + // re-initialize search engine when appending an index after initialisation + if (typeof fuse !== 'undefined') { + fuse = new Fuse(index, options); + } + } + + function init() { + fuse = new Fuse(index, options); + + var form = document.querySelector('[data-search-form]'); + var searchField = document.querySelector('[data-search-form] input[type="search"]'); + + var closeButton = document.querySelector('.phpdocumentor-search-results__close'); + closeButton.addEventListener('click', function() { close() }.bind(this)); + + var searchResults = document.querySelector('[data-search-results]'); + searchResults.addEventListener('click', function() { close() }.bind(this)); + + form.classList.add('phpdocumentor-search--active'); + + searchField.setAttribute('placeholder', 'Search (Press "/" to focus)'); + searchField.removeAttribute('disabled'); + searchField.addEventListener('keyup', debounce(search, 300)); + + window.addEventListener('keyup', function (event) { + if (event.key === '/') { + searchField.focus(); + } + if (event.code === 'Escape') { + close(); + } + }.bind(this)); + } + + return { + appendIndex, + init + } +})(); + +window.addEventListener('DOMContentLoaded', function () { + var form = document.querySelector('[data-search-form]'); + + // When JS is supported; show search box. Must be before including the search for it to take effect immediately + form.classList.add('phpdocumentor-search--enabled'); +}); + +window.addEventListener('load', function () { + Search.init(); +}); diff --git a/docs/api/js/searchIndex.js b/docs/api/js/searchIndex.js new file mode 100644 index 0000000..7fe2aef --- /dev/null +++ b/docs/api/js/searchIndex.js @@ -0,0 +1,284 @@ +Search.appendIndex( + [ + { + "fqsen": "\\App\\Controllers\\AuthController", + "name": "AuthController", + "summary": "Zust\u00E4ndig\u0020f\u00FCr\u0020alles\u0020rund\u0020um\u0020den\u0020Login\u003A\n\u002D\u0020Login\u002DFormular\u0020anzeigen\n\u002D\u0020Login\u002DDaten\u0020verarbeiten\u0020\u0028Authentifizierung\u0020gegen\u0020LDAP\/AD\u0029\n\u002D\u0020Logout\u0020durchf\u00FChren", + "url": "classes/App-Controllers-AuthController.html" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "\u00DCbergibt\u0020die\u0020Konfiguration\u0020an\u0020den\u0020Controller\u0020und\u0020initialisiert\u0020den\u0020LDAP\u002DAuthentifizierungsservice.", + "url": "classes/App-Controllers-AuthController.html#method___construct" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003AshowLoginForm\u0028\u0029", + "name": "showLoginForm", + "summary": "Zeigt\u0020das\u0020Login\u002DFormular\u0020an.", + "url": "classes/App-Controllers-AuthController.html#method_showLoginForm" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003AprocessLogin\u0028\u0029", + "name": "processLogin", + "summary": "Verarbeitet\u0020das\u0020Login\u002DFormular\u003A\n\u002D\u0020Liest\u0020Benutzername\u0020und\u0020Passwort\u0020aus\u0020\u0024_POST\n\u002D\u0020Ruft\u0020den\u0020LdapAuthService\u0020zur\u0020Authentifizierung\u0020auf\n\u002D\u0020Liefert\u0020bei\u0020Erfolg\u0020ein\u0020Redirect\u002DResult\u0020zum\u0020Dashboard\n\u002D\u0020Liefert\u0020bei\u0020Fehlern\u0020ein\u0020View\u002DResult\u0020f\u00FCr\u0020das\u0020Login\u002DFormular\u0020mit\u0020Fehlermeldung", + "url": "classes/App-Controllers-AuthController.html#method_processLogin" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003Alogout\u0028\u0029", + "name": "logout", + "summary": "Meldet\u0020den\u0020aktuell\u0020eingeloggten\u0020Benutzer\u0020ab,\u0020indem\u0020der\u0020entsprechende\u0020Session\u002DEintrag\u0020entfernt\u0020wird,\nund\u0020liefert\u0020anschlie\u00DFend\u0020ein\u0020Redirect\u002DResult\u0020zur\u00FCck\u0020auf\u0020die\u0020Login\u002DSeite.", + "url": "classes/App-Controllers-AuthController.html#method_logout" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Controllers-AuthController.html#property_config" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003A\u0024ldapAuthService", + "name": "ldapAuthService", + "summary": "", + "url": "classes/App-Controllers-AuthController.html#property_ldapAuthService" + }, { + "fqsen": "\\App\\Controllers\\AuthController\u003A\u003A\u0024logger", + "name": "logger", + "summary": "", + "url": "classes/App-Controllers-AuthController.html#property_logger" + }, { + "fqsen": "\\App\\Controllers\\DashboardController", + "name": "DashboardController", + "summary": "Controller\u0020f\u00FCr\u0020das\u0020Dashboard.", + "url": "classes/App-Controllers-DashboardController.html" + }, { + "fqsen": "\\App\\Controllers\\DashboardController\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "", + "url": "classes/App-Controllers-DashboardController.html#method___construct" + }, { + "fqsen": "\\App\\Controllers\\DashboardController\u003A\u003Ashow\u0028\u0029", + "name": "show", + "summary": "Zeigt\u0020das\u0020Dashboard\u0020an.", + "url": "classes/App-Controllers-DashboardController.html#method_show" + }, { + "fqsen": "\\App\\Controllers\\DashboardController\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Controllers-DashboardController.html#property_config" + }, { + "fqsen": "\\App\\Controllers\\DashboardController\u003A\u003A\u0024snmpService", + "name": "snmpService", + "summary": "", + "url": "classes/App-Controllers-DashboardController.html#property_snmpService" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController", + "name": "UserManagementController", + "summary": "Controller\u0020f\u00FCr\u0020die\u0020Benutzer\u002D\u0020und\u0020Gruppenanzeige.", + "url": "classes/App-Controllers-UserManagementController.html" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "", + "url": "classes/App-Controllers-UserManagementController.html#method___construct" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003Ashow\u0028\u0029", + "name": "show", + "summary": "Zeigt\u0020Benutzer\u002D\u0020und\u0020Gruppenliste\u0020an.", + "url": "classes/App-Controllers-UserManagementController.html#method_show" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003Acreate\u0028\u0029", + "name": "create", + "summary": "Zeigt\u0020die\u0020Seite\u0020zum\u0020Erstellen\u0020von\u0020Benutzern\u0020\u0028Einzel\/CSV\u0029.", + "url": "classes/App-Controllers-UserManagementController.html#method_create" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Controllers-UserManagementController.html#property_config" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003A\u0024directoryService", + "name": "directoryService", + "summary": "", + "url": "classes/App-Controllers-UserManagementController.html#property_directoryService" + }, { + "fqsen": "\\App\\Controllers\\UserManagementController\u003A\u003A\u0024logger", + "name": "logger", + "summary": "", + "url": "classes/App-Controllers-UserManagementController.html#property_logger" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapAuthService", + "name": "LdapAuthService", + "summary": "Service\u0020zur\u0020Authentifizierung\u0020von\u0020Benutzern\u0020gegen\u0020ein\u0020Active\u0020Directory\u0020per\u0020LDAP\/LDAPS.", + "url": "classes/App-Services-Ldap-LdapAuthService.html" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapAuthService\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Erwartet\u0020den\u0020Teilbereich\u0020\u0022ldap\u0022\u0020aus\u0020der\u0020allgemeinen\u0020Konfiguration\u0020\u0028config.php\u0029.", + "url": "classes/App-Services-Ldap-LdapAuthService.html#method___construct" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapAuthService\u003A\u003Aauthenticate\u0028\u0029", + "name": "authenticate", + "summary": "F\u00FChrt\u0020die\u0020eigentliche\u0020LDAP\/AD\u002DAuthentifizierung\u0020durch.", + "url": "classes/App-Services-Ldap-LdapAuthService.html#method_authenticate" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapAuthService\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Services-Ldap-LdapAuthService.html#property_config" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapAuthService\u003A\u003A\u0024connectionHelper", + "name": "connectionHelper", + "summary": "", + "url": "classes/App-Services-Ldap-LdapAuthService.html#property_connectionHelper" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapConnectionHelper", + "name": "LdapConnectionHelper", + "summary": "Hilfsklasse\u0020zum\u0020Aufbau\u0020einer\u0020LDAP\/LDAPS\u002DVerbindung.", + "url": "classes/App-Services-Ldap-LdapConnectionHelper.html" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapConnectionHelper\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "", + "url": "classes/App-Services-Ldap-LdapConnectionHelper.html#method___construct" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapConnectionHelper\u003A\u003AcreateConnection\u0028\u0029", + "name": "createConnection", + "summary": "Erstellt\u0020eine\u0020LDAP\u002DVerbindung\u0020mit\u0020gesetzten\u0020Optionen\u0020\u0028Protokollversion,\u0020Timeout\u0029,\naber\u0020ohne\u0020Bind.\u0020Den\u0020Bind\u0020f\u00FChren\u0020die\u0020aufrufenden\u0020Services\u0020durch.", + "url": "classes/App-Services-Ldap-LdapConnectionHelper.html#method_createConnection" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapConnectionHelper\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Services-Ldap-LdapConnectionHelper.html#property_config" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService", + "name": "LdapDirectoryService", + "summary": "Service\u0020zum\u0020Lesen\u0020von\u0020Objekten\u0020aus\u0020dem\u0020Active\u0020Directory.", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#method___construct" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003Aconnect\u0028\u0029", + "name": "connect", + "summary": "Stellt\u0020eine\u0020LDAP\u002DVerbindung\u0020her\u0020und\u0020bindet\u0020sich\u0020mit\u0020dem\u0020technischen\u0020Konto.", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#method_connect" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003AgetUsers\u0028\u0029", + "name": "getUsers", + "summary": "Liefert\u0020eine\u0020Liste\u0020von\u0020Benutzern\u0020aus\u0020dem\u0020AD.", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#method_getUsers" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003AgetGroups\u0028\u0029", + "name": "getGroups", + "summary": "Liefert\u0020eine\u0020Liste\u0020von\u0020Gruppen\u0020aus\u0020dem\u0020AD.", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#method_getGroups" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#property_config" + }, { + "fqsen": "\\App\\Services\\Ldap\\LdapDirectoryService\u003A\u003A\u0024connectionHelper", + "name": "connectionHelper", + "summary": "", + "url": "classes/App-Services-Ldap-LdapDirectoryService.html#property_connectionHelper" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService", + "name": "LoggingService", + "summary": "Einfacher\u0020File\u002DLogger\u0020f\u00FCr\u0020die\u0020AdminTool\u002DAnwendung.", + "url": "classes/App-Services-Logging-LoggingService.html" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "", + "url": "classes/App-Services-Logging-LoggingService.html#method___construct" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003AensureLogDirectoryExists\u0028\u0029", + "name": "ensureLogDirectoryExists", + "summary": "Stellt\u0020sicher,\u0020dass\u0020das\u0020Log\u002DVerzeichnis\u0020existiert.", + "url": "classes/App-Services-Logging-LoggingService.html#method_ensureLogDirectoryExists" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003Alog\u0028\u0029", + "name": "log", + "summary": "Allgemeiner\u0020Log\u002DEintrag.", + "url": "classes/App-Services-Logging-LoggingService.html#method_log" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003AlogException\u0028\u0029", + "name": "logException", + "summary": "Komfortmethode,\u0020um\u0020Exceptions\u0020strukturiert\u0020zu\u0020loggen.", + "url": "classes/App-Services-Logging-LoggingService.html#method_logException" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003ALEVEL_MAP", + "name": "LEVEL_MAP", + "summary": "Zuordnung\u0020der\u0020Log\u002DLevel\u0020zu\u0020numerischen\u0020Werten\u0020zur\u0020Filterung.", + "url": "classes/App-Services-Logging-LoggingService.html#constant_LEVEL_MAP" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003A\u0024logDir", + "name": "logDir", + "summary": "", + "url": "classes/App-Services-Logging-LoggingService.html#property_logDir" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003A\u0024logFile", + "name": "logFile", + "summary": "", + "url": "classes/App-Services-Logging-LoggingService.html#property_logFile" + }, { + "fqsen": "\\App\\Services\\Logging\\LoggingService\u003A\u003A\u0024minLevel", + "name": "minLevel", + "summary": "", + "url": "classes/App-Services-Logging-LoggingService.html#property_minLevel" + }, { + "fqsen": "\\App\\Services\\Snmp\\SnmpServerStatusService", + "name": "SnmpServerStatusService", + "summary": "Service\u0020zur\u0020Ermittlung\u0020des\u0020Serverstatus\u0020per\u0020SNMP.", + "url": "classes/App-Services-Snmp-SnmpServerStatusService.html" + }, { + "fqsen": "\\App\\Services\\Snmp\\SnmpServerStatusService\u003A\u003A__construct\u0028\u0029", + "name": "__construct", + "summary": "Erwartet\u0020den\u0020Teilbereich\u0020\u0022snmp\u0022\u0020aus\u0020der\u0020allgemeinen\u0020Konfiguration\u0020\u0028config.php\u0029.", + "url": "classes/App-Services-Snmp-SnmpServerStatusService.html#method___construct" + }, { + "fqsen": "\\App\\Services\\Snmp\\SnmpServerStatusService\u003A\u003AgetServerStatus\u0028\u0029", + "name": "getServerStatus", + "summary": "Liefert\u0020den\u0020aktuellen\u0020Serverstatus\u0020zur\u00FCck.", + "url": "classes/App-Services-Snmp-SnmpServerStatusService.html#method_getServerStatus" + }, { + "fqsen": "\\App\\Services\\Snmp\\SnmpServerStatusService\u003A\u003A\u0024config", + "name": "config", + "summary": "", + "url": "classes/App-Services-Snmp-SnmpServerStatusService.html#property_config" + }, { + "fqsen": "\\", + "name": "\\", + "summary": "", + "url": "namespaces/default.html" + }, { + "fqsen": "\\App\\Controllers", + "name": "Controllers", + "summary": "", + "url": "namespaces/app-controllers.html" + }, { + "fqsen": "\\App", + "name": "App", + "summary": "", + "url": "namespaces/app.html" + }, { + "fqsen": "\\App\\Services\\Ldap", + "name": "Ldap", + "summary": "", + "url": "namespaces/app-services-ldap.html" + }, { + "fqsen": "\\App\\Services", + "name": "Services", + "summary": "", + "url": "namespaces/app-services.html" + }, { + "fqsen": "\\App\\Services\\Logging", + "name": "Logging", + "summary": "", + "url": "namespaces/app-services-logging.html" + }, { + "fqsen": "\\App\\Services\\Snmp", + "name": "Snmp", + "summary": "", + "url": "namespaces/app-services-snmp.html" + } ] +); diff --git a/docs/api/js/template.js b/docs/api/js/template.js new file mode 100644 index 0000000..83931d2 --- /dev/null +++ b/docs/api/js/template.js @@ -0,0 +1,34 @@ +(function(){ + window.addEventListener('load', () => { + const el = document.querySelector('.phpdocumentor-on-this-page__content') + if (!el) { + return; + } + + const observer = new IntersectionObserver( + ([e]) => { + e.target.classList.toggle("-stuck", e.intersectionRatio < 1); + }, + {threshold: [1]} + ); + + observer.observe(el); + }) +})(); +function openSvg(svg) { + // convert to a valid XML source + const as_text = new XMLSerializer().serializeToString(svg); + // store in a Blob + const blob = new Blob([as_text], { type: "image/svg+xml" }); + // create an URI pointing to that blob + const url = URL.createObjectURL(blob); + const win = open(url); + // so the Garbage Collector can collect the blob + win.onload = (evt) => URL.revokeObjectURL(url); +}; + + +var svgs = document.querySelectorAll(".phpdocumentor-uml-diagram svg"); +for( var i=0,il = svgs.length; i< il; i ++ ) { + svgs[i].onclick = (evt) => openSvg(evt.target); +} \ No newline at end of file diff --git a/docs/api/namespaces/app-controllers.html b/docs/api/namespaces/app-controllers.html new file mode 100644 index 0000000..336a0c1 --- /dev/null +++ b/docs/api/namespaces/app-controllers.html @@ -0,0 +1,274 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                        +

                                        Documentation

                                        + + + + + +
                                        + +
                                        +
                                        + + + + +
                                        +
                                        + + +
                                        +

                                        Controllers

                                        + + +

                                        + Table of Contents + + +

                                        + + + + +

                                        + Classes + + +

                                        +
                                        +
                                        AuthController
                                        Zuständig für alles rund um den Login: +- Login-Formular anzeigen +- Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD) +- Logout durchführen
                                        DashboardController
                                        Controller für das Dashboard.
                                        UserManagementController
                                        Controller für die Benutzer- und Gruppenanzeige.
                                        + + + + + + + + + + + +
                                        +
                                        +
                                        +
                                        +
                                        
                                        +        
                                        + +
                                        +
                                        + + + +
                                        +
                                        +
                                        + +
                                        + On this page + +
                                          +
                                        • Table Of Contents
                                        • +
                                        • + +
                                        • + + +
                                        +
                                        + +
                                        +
                                        +
                                        +
                                        +
                                        +

                                        Search results

                                        + +
                                        +
                                        +
                                          +
                                          +
                                          +
                                          +
                                          + + +
                                          + + + + + + + + diff --git a/docs/api/namespaces/app-services-ldap.html b/docs/api/namespaces/app-services-ldap.html new file mode 100644 index 0000000..5ad1455 --- /dev/null +++ b/docs/api/namespaces/app-services-ldap.html @@ -0,0 +1,272 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                          +

                                          Documentation

                                          + + + + + +
                                          + +
                                          +
                                          + + + + +
                                          +
                                          + + +
                                          +

                                          Ldap

                                          + + +

                                          + Table of Contents + + +

                                          + + + + +

                                          + Classes + + +

                                          +
                                          +
                                          LdapAuthService
                                          Service zur Authentifizierung von Benutzern gegen ein Active Directory per LDAP/LDAPS.
                                          LdapConnectionHelper
                                          Hilfsklasse zum Aufbau einer LDAP/LDAPS-Verbindung.
                                          LdapDirectoryService
                                          Service zum Lesen von Objekten aus dem Active Directory.
                                          + + + + + + + + + + + +
                                          +
                                          +
                                          +
                                          +
                                          
                                          +        
                                          + +
                                          +
                                          + + + +
                                          +
                                          +
                                          + +
                                          + On this page + +
                                            +
                                          • Table Of Contents
                                          • +
                                          • + +
                                          • + + +
                                          +
                                          + +
                                          +
                                          +
                                          +
                                          +
                                          +

                                          Search results

                                          + +
                                          +
                                          +
                                            +
                                            +
                                            +
                                            +
                                            + + +
                                            + + + + + + + + diff --git a/docs/api/namespaces/app-services-logging.html b/docs/api/namespaces/app-services-logging.html new file mode 100644 index 0000000..c5ad076 --- /dev/null +++ b/docs/api/namespaces/app-services-logging.html @@ -0,0 +1,272 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                            +

                                            Documentation

                                            + + + + + +
                                            + +
                                            +
                                            + + + + +
                                            +
                                            + + +
                                            +

                                            Logging

                                            + + +

                                            + Table of Contents + + +

                                            + + + + +

                                            + Classes + + +

                                            +
                                            +
                                            LoggingService
                                            Einfacher File-Logger für die AdminTool-Anwendung.
                                            + + + + + + + + + + + +
                                            +
                                            +
                                            +
                                            +
                                            
                                            +        
                                            + +
                                            +
                                            + + + +
                                            +
                                            +
                                            + +
                                            + On this page + +
                                              +
                                            • Table Of Contents
                                            • +
                                            • + +
                                            • + + +
                                            +
                                            + +
                                            +
                                            +
                                            +
                                            +
                                            +

                                            Search results

                                            + +
                                            +
                                            +
                                              +
                                              +
                                              +
                                              +
                                              + + +
                                              + + + + + + + + diff --git a/docs/api/namespaces/app-services-snmp.html b/docs/api/namespaces/app-services-snmp.html new file mode 100644 index 0000000..6efe1b2 --- /dev/null +++ b/docs/api/namespaces/app-services-snmp.html @@ -0,0 +1,272 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                              +

                                              Documentation

                                              + + + + + +
                                              + +
                                              +
                                              + + + + +
                                              +
                                              + + +
                                              +

                                              Snmp

                                              + + +

                                              + Table of Contents + + +

                                              + + + + +

                                              + Classes + + +

                                              +
                                              +
                                              SnmpServerStatusService
                                              Service zur Ermittlung des Serverstatus per SNMP.
                                              + + + + + + + + + + + +
                                              +
                                              +
                                              +
                                              +
                                              
                                              +        
                                              + +
                                              +
                                              + + + +
                                              +
                                              +
                                              + +
                                              + On this page + +
                                                +
                                              • Table Of Contents
                                              • +
                                              • + +
                                              • + + +
                                              +
                                              + +
                                              +
                                              +
                                              +
                                              +
                                              +

                                              Search results

                                              + +
                                              +
                                              +
                                                +
                                                +
                                                +
                                                +
                                                + + +
                                                + + + + + + + + diff --git a/docs/api/namespaces/app-services.html b/docs/api/namespaces/app-services.html new file mode 100644 index 0000000..ed9a155 --- /dev/null +++ b/docs/api/namespaces/app-services.html @@ -0,0 +1,273 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                                +

                                                Documentation

                                                + + + + + +
                                                + +
                                                +
                                                + + + + +
                                                +
                                                + + +
                                                +

                                                Services

                                                + + +

                                                + Table of Contents + + +

                                                + + +

                                                + Namespaces + + +

                                                +
                                                +
                                                Ldap
                                                +
                                                Logging
                                                +
                                                Snmp
                                                +
                                                + + + + + + + + + + + + + +
                                                +
                                                +
                                                +
                                                +
                                                
                                                +        
                                                + +
                                                +
                                                + + + +
                                                +
                                                +
                                                + +
                                                + On this page + +
                                                  +
                                                • Table Of Contents
                                                • +
                                                • +
                                                    +
                                                  +
                                                • + + +
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                +

                                                Search results

                                                + +
                                                +
                                                +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + +
                                                  + + + + + + + + diff --git a/docs/api/namespaces/app.html b/docs/api/namespaces/app.html new file mode 100644 index 0000000..85e13b4 --- /dev/null +++ b/docs/api/namespaces/app.html @@ -0,0 +1,271 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                                  +

                                                  Documentation

                                                  + + + + + +
                                                  + +
                                                  +
                                                  + + + + +
                                                  +
                                                  +
                                                    +
                                                  + +
                                                  +

                                                  App

                                                  + + +

                                                  + Table of Contents + + +

                                                  + + +

                                                  + Namespaces + + +

                                                  +
                                                  +
                                                  Controllers
                                                  +
                                                  Services
                                                  +
                                                  + + + + + + + + + + + + + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  
                                                  +        
                                                  + +
                                                  +
                                                  + + + +
                                                  +
                                                  +
                                                  + +
                                                  + On this page + +
                                                    +
                                                  • Table Of Contents
                                                  • +
                                                  • +
                                                      +
                                                    +
                                                  • + + +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +

                                                  Search results

                                                  + +
                                                  +
                                                  +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    + + +
                                                    + + + + + + + + diff --git a/docs/api/namespaces/default.html b/docs/api/namespaces/default.html new file mode 100644 index 0000000..7837ef2 --- /dev/null +++ b/docs/api/namespaces/default.html @@ -0,0 +1,270 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                                    +

                                                    Documentation

                                                    + + + + + +
                                                    + +
                                                    +
                                                    + + + + +
                                                    +
                                                    +
                                                      +
                                                    + +
                                                    +

                                                    API Documentation

                                                    + + +

                                                    + Table of Contents + + +

                                                    + + +

                                                    + Namespaces + + +

                                                    +
                                                    +
                                                    App
                                                    +
                                                    + + + + + + + + + + + + + +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    
                                                    +        
                                                    + +
                                                    +
                                                    + + + +
                                                    +
                                                    +
                                                    + +
                                                    + On this page + +
                                                      +
                                                    • Table Of Contents
                                                    • +
                                                    • +
                                                        +
                                                      +
                                                    • + + +
                                                    +
                                                    + +
                                                    +
                                                    +
                                                    +
                                                    +
                                                    +

                                                    Search results

                                                    + +
                                                    +
                                                    +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      + + +
                                                      + + + + + + + + diff --git a/docs/api/packages/Application.html b/docs/api/packages/Application.html new file mode 100644 index 0000000..c722a30 --- /dev/null +++ b/docs/api/packages/Application.html @@ -0,0 +1,273 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                                      +

                                                      Documentation

                                                      + + + + + +
                                                      + +
                                                      +
                                                      + + + + +
                                                      +
                                                      +
                                                        +
                                                      + +
                                                      +

                                                      Application

                                                      + + +

                                                      + Table of Contents + + +

                                                      + + + + +

                                                      + Classes + + +

                                                      +
                                                      +
                                                      AuthController
                                                      Zuständig für alles rund um den Login: +- Login-Formular anzeigen +- Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD) +- Logout durchführen
                                                      DashboardController
                                                      Controller für das Dashboard.
                                                      UserManagementController
                                                      Controller für die Benutzer- und Gruppenanzeige.
                                                      LdapAuthService
                                                      Service zur Authentifizierung von Benutzern gegen ein Active Directory per LDAP/LDAPS.
                                                      LdapConnectionHelper
                                                      Hilfsklasse zum Aufbau einer LDAP/LDAPS-Verbindung.
                                                      LdapDirectoryService
                                                      Service zum Lesen von Objekten aus dem Active Directory.
                                                      LoggingService
                                                      Einfacher File-Logger für die AdminTool-Anwendung.
                                                      SnmpServerStatusService
                                                      Service zur Ermittlung des Serverstatus per SNMP.
                                                      + + + + + + + + + + + +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      
                                                      +        
                                                      + +
                                                      +
                                                      + + + +
                                                      +
                                                      +
                                                      + +
                                                      + On this page + +
                                                        +
                                                      • Table Of Contents
                                                      • +
                                                      • + +
                                                      • + + +
                                                      +
                                                      + +
                                                      +
                                                      +
                                                      +
                                                      +
                                                      +

                                                      Search results

                                                      + +
                                                      +
                                                      +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        + + +
                                                        + + + + + + + + diff --git a/docs/api/packages/default.html b/docs/api/packages/default.html new file mode 100644 index 0000000..d38f909 --- /dev/null +++ b/docs/api/packages/default.html @@ -0,0 +1,270 @@ + + + + + Documentation + + + + + + + + + + + + + + + + + + + + + +
                                                        +

                                                        Documentation

                                                        + + + + + +
                                                        + +
                                                        +
                                                        + + + + +
                                                        +
                                                        +
                                                          +
                                                        + +
                                                        +

                                                        API Documentation

                                                        + + +

                                                        + Table of Contents + + +

                                                        + +

                                                        + Packages + + +

                                                        +
                                                        +
                                                        Application
                                                        +
                                                        + + + + + + + + + + + + + + +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        
                                                        +        
                                                        + +
                                                        +
                                                        + + + +
                                                        +
                                                        +
                                                        + +
                                                        + On this page + +
                                                          +
                                                        • Table Of Contents
                                                        • +
                                                        • +
                                                            +
                                                          +
                                                        • + + +
                                                        +
                                                        + +
                                                        +
                                                        +
                                                        +
                                                        +
                                                        +

                                                        Search results

                                                        + +
                                                        +
                                                        +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          + + +
                                                          + + + + + + + + diff --git a/docs/api/reports/deprecated.html b/docs/api/reports/deprecated.html new file mode 100644 index 0000000..e056915 --- /dev/null +++ b/docs/api/reports/deprecated.html @@ -0,0 +1,136 @@ + + + + + Documentation » Deprecated elements + + + + + + + + + + + + + + + + + + + + + + +
                                                          +

                                                          Documentation

                                                          + + + + + +
                                                          + +
                                                          +
                                                          + + + + +
                                                          +
                                                          + + +
                                                          +

                                                          Deprecated

                                                          + + +
                                                          + No deprecated elements have been found in this project. +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +
                                                          +

                                                          Search results

                                                          + +
                                                          +
                                                          +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            + + +
                                                            + + + + + + + + diff --git a/docs/api/reports/errors.html b/docs/api/reports/errors.html new file mode 100644 index 0000000..337e02d --- /dev/null +++ b/docs/api/reports/errors.html @@ -0,0 +1,135 @@ + + + + + Documentation » Compilation errors + + + + + + + + + + + + + + + + + + + + + + +
                                                            +

                                                            Documentation

                                                            + + + + + +
                                                            + +
                                                            +
                                                            + + + + +
                                                            +
                                                            + + +
                                                            +

                                                            Errors

                                                            + + +
                                                            No errors have been found in this project.
                                                            + +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +
                                                            +

                                                            Search results

                                                            + +
                                                            +
                                                            +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              + + +
                                                              + + + + + + + + diff --git a/docs/api/reports/markers.html b/docs/api/reports/markers.html new file mode 100644 index 0000000..978b5cb --- /dev/null +++ b/docs/api/reports/markers.html @@ -0,0 +1,158 @@ + + + + + Documentation » Markers + + + + + + + + + + + + + + + + + + + + + + +
                                                              +

                                                              Documentation

                                                              + + + + + +
                                                              + +
                                                              +
                                                              + + + + +
                                                              +
                                                              + + +
                                                              +

                                                              Markers

                                                              + +

                                                              Table of Contents

                                                              + + + + + +
                                                              app/Services/Snmp/SnmpServerStatusService.php1
                                                              + + +

                                                              SnmpServerStatusService.php

                                                              + + + + + + + + + + + + + + + +
                                                              TypeLineDescription
                                                              TODO223OS dynamisch per SNMP abfragen (OID 1.3.6.1.2.1.1.1.0)
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +
                                                              +

                                                              Search results

                                                              + +
                                                              +
                                                              +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                + + +
                                                                + + + + + + + + diff --git a/public/api/create_user.php b/public/api/create_user.php new file mode 100644 index 0000000..5a57722 --- /dev/null +++ b/public/api/create_user.php @@ -0,0 +1,164 @@ += $minLen) { + $samLen = mb_strlen($samLower); + for ($len = $minLen; $len <= $samLen; $len++) { + for ($start = 0; $start <= $samLen - $len; $start++) { + $sub = mb_substr($samLower, $start, $len); + if (mb_strpos($pwLower, $sub) !== false) { + $errors[] = 'Passwort darf keine größeren Teile des Benutzernamens enthalten.'; + break 2; + } + } + } + } + } + return $errors; +} + +$pwErrors = validate_password_php($pass, $sam); +if (count($pwErrors) > 0) { + $_SESSION['flash_error'] = 'Ungültiges Passwort: ' . implode(' | ', $pwErrors) . "\n\nHinweis: $passwordHint"; + header('Location: ../index.php?route=createuser'); + exit; +} + +if ($ou === '') { + $defaultOu = (string)($config['powershell']['default_ou'] ?? ''); + if ($defaultOu !== '') { + $ou = $defaultOu; + } +} + + +// Build payload +$payload = [ + 'samaccountname' => $sam, + 'displayname' => $display, + 'mail' => $mail, + 'password' => $pass, + 'ou' => $ou, + 'groups' => $groups, + 'dry_run' => (bool)($config['powershell']['dry_run'] ?? false), +]; + +// Write payload to temp file +$tmpFile = tempnam(sys_get_temp_dir(), 'create_user_') . '.json'; +file_put_contents($tmpFile, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + +// Build PS script path +$scriptDir = $config['powershell']['script_dir'] ?? __DIR__ . '/../../scripts/powershell'; +$script = $scriptDir . DIRECTORY_SEPARATOR . 'create_user.ps1'; + +$exe = $config['powershell']['exe'] ?? 'powershell'; +$executionPolicy = $config['powershell']['execution_policy'] ?? 'Bypass'; + +$cmd = sprintf( + '%s -NoProfile -NonInteractive -ExecutionPolicy %s -File "%s" -InputFile "%s"', + $exe, + $executionPolicy, + $script, + $tmpFile +); + +// Execute and capture output and exit code +$output = []; +$returnVar = null; +if (!file_exists($script)) { + $_SESSION['flash_error'] = 'PowerShell-Skript nicht gefunden: ' . $script; + @unlink($tmpFile); + header('Location: ../index.php?route=createuser'); + exit; +} + +// Try to locate the PowerShell executable +$exePathCheck = shell_exec(sprintf('where %s 2>NUL', escapeshellarg($exe))); +if ($exePathCheck === null) { + // 'where' returns null when command fails; continue anyways, exec will fail if not found +} + +exec($cmd . ' 2>&1', $output, $returnVar); +$json = implode("\n", $output); + +// Optional: write raw output into logs for debugging +@file_put_contents(__DIR__ . '/../logs/create_user_output.log', date('Y-m-d H:i:s') . ' CMD: ' . $cmd . "\n" . $json . "\n\n", FILE_APPEND | LOCK_EX); + +@unlink($tmpFile); + +// Try to parse JSON output +$result = null; +if ($json !== '') { + $decoded = json_decode($json, true); + if (is_array($decoded)) { + $result = $decoded; + } +} + +if ($result === null) { + $_SESSION['flash_error'] = 'Unbekannter Fehler beim Ausführen des PowerShell-Skripts: ' . ($json ?: 'Keine Ausgabe'); + header('Location: ../index.php?route=createuser'); + exit; +} + +if (!empty($result['success'])) { + $_SESSION['flash_success'] = $result['message'] ?? 'Benutzer erfolgreich erstellt.'; +} else { + $_SESSION['flash_error'] = $result['message'] ?? 'Fehler beim Erstellen des Benutzers.'; +} + +header('Location: ../index.php?route=createuser'); +exit; diff --git a/public/api/create_users_csv.php b/public/api/create_users_csv.php new file mode 100644 index 0000000..216f903 --- /dev/null +++ b/public/api/create_users_csv.php @@ -0,0 +1,111 @@ + $tmpFile, + 'delimiter' => $delimiter, + 'has_header' => (bool)((int)$hasHeader), + 'dry_run' => (bool)($config['powershell']['dry_run'] ?? false), + 'default_ou' => (string)($config['powershell']['default_ou'] ?? ''), +]; + +// Save options as JSON as the input to the PS script +$metaFile = tempnam(sys_get_temp_dir(), 'create_users_meta_') . '.json'; +file_put_contents($metaFile, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + +$scriptDir = $config['powershell']['script_dir'] ?? __DIR__ . '/../../scripts/powershell'; +$script = $scriptDir . DIRECTORY_SEPARATOR . 'create_users_csv.ps1'; +$exe = $config['powershell']['exe'] ?? 'powershell'; +$executionPolicy = $config['powershell']['execution_policy'] ?? 'Bypass'; + +$cmd = sprintf( + '%s -NoProfile -NonInteractive -ExecutionPolicy %s -File "%s" -InputFile "%s"', + $exe, + $executionPolicy, + $script, + $metaFile +); + +$output = []; +$returnVar = null; +if (!file_exists($script)) { + $_SESSION['flash_error'] = 'PowerShell-Skript nicht gefunden: ' . $script; + @unlink($tmpFile); + @unlink($metaFile); + header('Location: ../index.php?route=createuser'); + exit; +} + +exec($cmd . ' 2>&1', $output, $returnVar); +$json = implode("\n", $output); + +@unlink($tmpFile); +@unlink($metaFile); + +// Optional: log the CSV script command and raw output to help debugging +@file_put_contents(__DIR__ . '/../logs/create_users_csv_output.log', date('Y-m-d H:i:s') . ' CMD: ' . $cmd . "\n" . $json . "\n\n", FILE_APPEND | LOCK_EX); + +$result = null; +if ($json !== '') { + $decoded = json_decode($json, true); + if (is_array($decoded)) { + $result = $decoded; + } +} + +if ($result === null) { + $_SESSION['flash_error'] = 'Unbekannter Fehler beim Ausführen des PowerShell-Skripts: ' . ($json ?: 'Keine Ausgabe'); + header('Location: ../index.php?route=createuser'); + exit; +} + +if (!empty($result['success'])) { + $_SESSION['flash_success'] = $result['message'] ?? 'CSV verarbeitet.'; + if (!empty($result['details'])) { + $_SESSION['csv_details'] = $result['details']; + } +} else { + $_SESSION['flash_error'] = $result['message'] ?? 'Fehler beim Verarbeiten der CSV.'; +} + +header('Location: ../index.php?route=createuser'); +exit; diff --git a/public/api/powershell_check.php b/public/api/powershell_check.php new file mode 100644 index 0000000..bd10313 --- /dev/null +++ b/public/api/powershell_check.php @@ -0,0 +1,45 @@ + false, 'message' => 'Not authenticated']); + exit; +} + +$scriptDir = $config['powershell']['script_dir'] ?? __DIR__ . '/../../scripts/powershell'; +$script = $scriptDir . DIRECTORY_SEPARATOR . 'check_environment.ps1'; +$exe = $config['powershell']['exe'] ?? 'powershell'; +$executionPolicy = $config['powershell']['execution_policy'] ?? 'Bypass'; + +if (!file_exists($script)) { + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Script not found: ' . $script]); + exit; +} + +$cmd = sprintf('%s -NoProfile -NonInteractive -ExecutionPolicy %s -File "%s"', $exe, $executionPolicy, $script); + +$output = []; +$returnVar = null; +exec($cmd . ' 2>&1', $output, $returnVar); +$json = implode("\n", $output); + +// Attempt to parse JSON +$decoded = json_decode($json, true); +if ($decoded === null) { + header('Content-Type: application/json'); + echo json_encode(['success' => false, 'message' => 'Invalid JSON output', 'raw' => $json]); + exit; +} + +header('Content-Type: application/json'); +echo json_encode($decoded); +exit; diff --git a/public/api/snmp_status.php b/public/api/snmp_status.php index 4d26b23..5045a25 100644 --- a/public/api/snmp_status.php +++ b/public/api/snmp_status.php @@ -6,16 +6,12 @@ declare(strict_types=1); * * Nur authentifizierte Admins dürfen auf diesen Endpunkt zugreifen. * Wird alle 5s vom JavaScript im Dashboard aufgerufen. - * - * Sicherheit: Session-Validierung + Admin-Rollenprüfung. - * Performance: Datei-basiertes Caching (10 Sekunden) um SNMP-Last zu reduzieren. - * Logging: Alle Fehler und wichtigen Daten werden in `public/logs/snmp_api.log` geschrieben. */ session_start(); // === Authentifizierung + Autorisierung === -$sessionKeyUser = 'admin_user'; // aus config +$sessionKeyUser = 'admin_user'; if (!isset($_SESSION[$sessionKeyUser])) { http_response_code(401); header('Content-Type: application/json; charset=utf-8'); @@ -40,19 +36,15 @@ function log_msg(string $msg): void { function rotate_log_if_needed(): void { global $logFile; - $maxSize = 500 * 1024; // 500 KB (anpassbar) - + $maxSize = 500 * 1024; // 500 KB if (file_exists($logFile) && filesize($logFile) > $maxSize) { - $backupFile = $logFile . '.old'; - @rename($logFile, $backupFile); - log_msg('=== Log rotiert (alte Datei: .old) ==='); + @rename($logFile, $logFile . '.old'); + log_msg('=== Log rotiert ==='); } } - $configPath = __DIR__ . '/../../config/config.php'; if (!is_readable($configPath)) { - log_msg('ERROR: config.php nicht lesbar'); echo json_encode(['error' => 'config_not_found']); exit; } @@ -62,10 +54,7 @@ $snmp = $config['snmp'] ?? []; rotate_log_if_needed(); -log_msg('--- SNMP-Abfrage gestartet ---'); - // === Cache-Logik (Datei) === -// Cache-Datei wird nach 10 Sekunden als ungültig betrachtet $cacheDir = sys_get_temp_dir(); $cacheFile = $cacheDir . DIRECTORY_SEPARATOR . 'snmp_status_cache.json'; $cacheTTL = 10; // Sekunden @@ -73,53 +62,54 @@ $cacheTTL = 10; // Sekunden if (file_exists($cacheFile)) { $cacheAge = time() - filemtime($cacheFile); if ($cacheAge < $cacheTTL) { - // Cache ist noch gültig $cached = file_get_contents($cacheFile); if ($cached !== false) { - log_msg("Cache HIT (Alter: {$cacheAge}s)"); echo $cached; exit; } - } else { - log_msg("Cache abgelaufen (Alter: {$cacheAge}s), neue Abfrage"); } } +// === SNMP Setup === $host = $snmp['host'] ?? '127.0.0.1'; $community = $snmp['community'] ?? 'public'; -$timeout = (int)($snmp['timeout'] ?? 2); + +// Timeout von Sekunden in Mikrosekunden umrechnen (wichtig für PHP snmp Funktionen) +$timeoutSec = (int)($snmp['timeout'] ?? 2); +$timeoutMicro = $timeoutSec * 1_000_000; $retries = (int)($snmp['retries'] ?? 1); -log_msg("SNMP-Host: $host, Community: $community, Timeout: {$timeout}s"); - if (!function_exists('snmpget')) { - log_msg('ERROR: SNMP-Erweiterung nicht installiert'); echo json_encode(['error' => 'snmp_extension_missing']); exit; } -snmp_set_quick_print(true); +// Grundeinstellungen snmp_set_oid_output_format(SNMP_OID_OUTPUT_NUMERIC); -// Hilfsfunktion: sichere snmpget-Rückgabe (numeric oder null) -function sget(string $host, string $community, string $oid, int $timeout, int $retries) -{ +// Hilfsfunktion: sichere snmpget-Rückgabe +function sget(string $host, string $community, string $oid, int $timeout, int $retries) { $v = @snmpget($host, $community, $oid, $timeout, $retries); if ($v === false || $v === null) return null; return is_string($v) ? trim($v) : $v; } -// System-Uptime (TimeTicks) +// --- 1. Uptime --- +// Wir deaktivieren quick_print, damit wir das Format "Timeticks: (12345) 1 day..." erhalten. +// Nur so können wir die echten Ticks in der Klammer zuverlässig parsen. +snmp_set_quick_print(false); + $uptimeOid = $snmp['oids']['uptime'] ?? '1.3.6.1.2.1.1.3.0'; -$upticksRaw = @sget($host, $community, $uptimeOid, $timeout, $retries); -$upticks = $upticksRaw !== null ? (int)preg_replace('/[^0-9]/', '', (string)$upticksRaw) : null; +$uptimeRaw = @sget($host, $community, $uptimeOid, $timeoutMicro, $retries); +$upticks = null; -log_msg("Uptime OID: $uptimeOid, Raw: " . ($upticksRaw ?? 'null')); +// Regex sucht nach Zahl in Klammern: (12345678) +if ($uptimeRaw && preg_match('/\((.*?)\)/', (string)$uptimeRaw, $matches)) { + $upticks = (int)$matches[1]; +} -function format_uptime(?int $ticks): ?string -{ +function format_uptime(?int $ticks): ?string { if ($ticks === null) return null; - // ticks sind Hundertstel-Sekunden $seconds = (int)floor($ticks / 100); $days = intdiv($seconds, 86400); $seconds -= $days * 86400; @@ -127,166 +117,131 @@ function format_uptime(?int $ticks): ?string $seconds -= $hours * 3600; $minutes = intdiv($seconds, 60); $seconds -= $minutes * 60; + $parts = []; if ($days) $parts[] = $days . ' Tage'; - if ($hours) $parts[] = $hours . ' Std'; - if ($minutes) $parts[] = $minutes . ' Min'; - $parts[] = $seconds . ' Sek'; - return implode(' ', $parts); + $parts[] = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds); + return implode(', ', $parts); } $uptimeStr = format_uptime($upticks); -// CPU: ersten Eintrag aus der CPU-Tabelle lesen +// Für den Rest aktivieren wir quick_print wieder, um "saubere" Werte zu bekommen +snmp_set_quick_print(true); + + +// --- 2. CPU (Walk über alle Kerne) --- $cpuTable = $snmp['oids']['cpu_table'] ?? '1.3.6.1.2.1.25.3.3.1.2'; -$cpuOid = $cpuTable . '.1'; -$cpuRaw = @sget($host, $community, $cpuOid, $timeout, $retries); -$cpu = $cpuRaw !== null ? (float)preg_replace('/[^0-9.]/', '', (string)$cpuRaw) : null; +$cpuValues = @snmpwalk($host, $community, $cpuTable, $timeoutMicro, $retries); -log_msg("CPU OID: $cpuOid, Raw: " . ($cpuRaw ?? 'null') . ", Parsed: " . ($cpu ?? 'null')); +$cpuUsage = 0; +if (is_array($cpuValues) && count($cpuValues) > 0) { + $totalLoad = 0; + $coreCount = 0; + foreach ($cpuValues as $val) { + $v = (int)filter_var($val, FILTER_SANITIZE_NUMBER_INT); + $totalLoad += $v; + $coreCount++; + } + if ($coreCount > 0) { + $cpuUsage = round($totalLoad / $coreCount, 2); + } +} -// Storage-Tabellen: Versuche, C: (Windows) oder Root ("/") zu finden + +// --- 3. Storage (Disk & RAM) --- $descrOid = $snmp['oids']['storage_descr'] ?? '1.3.6.1.2.1.25.2.3.1.3'; $unitsOid = $snmp['oids']['storage_units'] ?? '1.3.6.1.2.1.25.2.3.1.4'; -$sizeOid = $snmp['oids']['storage_size'] ?? '1.3.6.1.2.1.25.2.3.1.5'; -$usedOid = $snmp['oids']['storage_used'] ?? '1.3.6.1.2.1.25.2.3.1.6'; +$sizeOid = $snmp['oids']['storage_size'] ?? '1.3.6.1.2.1.25.2.3.1.5'; +$usedOid = $snmp['oids']['storage_used'] ?? '1.3.6.1.2.1.25.2.3.1.6'; -log_msg("Starte Storage-Walk - Descr: $descrOid, Units: $unitsOid, Size: $sizeOid, Used: $usedOid"); - -$descrWalk = @snmprealwalk($host, $community, $descrOid); -$unitsWalk = @snmprealwalk($host, $community, $unitsOid); -$sizeWalk = @snmprealwalk($host, $community, $sizeOid); -$usedWalk = @snmprealwalk($host, $community, $usedOid); - -if (!is_array($descrWalk)) { - log_msg('WARNING: snmprealwalk für Beschreibungen fehlgeschlagen'); - $descrWalk = []; -} -if (!is_array($unitsWalk)) { - log_msg('WARNING: snmprealwalk für Units fehlgeschlagen'); - $unitsWalk = []; -} -if (!is_array($sizeWalk)) { - log_msg('WARNING: snmprealwalk für Größe fehlgeschlagen'); - $sizeWalk = []; -} -if (!is_array($usedWalk)) { - log_msg('WARNING: snmprealwalk für Used fehlgeschlagen'); - $usedWalk = []; -} - -log_msg('Storage-Einträge gefunden: ' . count($descrWalk)); +$descrWalk = @snmprealwalk($host, $community, $descrOid, $timeoutMicro, $retries); +$unitsWalk = @snmprealwalk($host, $community, $unitsOid, $timeoutMicro, $retries); +$sizeWalk = @snmprealwalk($host, $community, $sizeOid, $timeoutMicro, $retries); +$usedWalk = @snmprealwalk($host, $community, $usedOid, $timeoutMicro, $retries); $diskPercent = null; $memPercent = null; -$storageEntries = []; +$storageEntries = []; // Fallback-Liste -// Sammeln aller Storage-Einträge für Debug-Logging -if (is_array($descrWalk) && count($descrWalk) > 0) { +if (is_array($descrWalk)) { foreach ($descrWalk as $descrOidFull => $descrRaw) { - // Index extrahieren if (!preg_match('/\.(\d+)$/', $descrOidFull, $m)) continue; $idx = $m[1]; - $descr = trim((string)$descrRaw, ' "'); - // Suche nach passenden Einträgen in anderen Walks mit gleichem Index - $units = null; - $size = null; - $used = null; + // Bereinigen + $descr = trim(str_ireplace('STRING:', '', (string)$descrRaw), ' "'); - foreach ($unitsWalk as $oid => $val) { - if (preg_match('/\.(\d+)$/', $oid, $m2) && $m2[1] === $idx) { - $units = (int)preg_replace('/[^0-9]/', '', (string)$val); - break; + // Helper zum Finden der Werte + $findVal = function($walkArr, $idx) { + if(!is_array($walkArr)) return null; + foreach ($walkArr as $oid => $val) { + if (preg_match('/\.(\d+)$/', $oid, $m2) && $m2[1] === $idx) { + return (int)filter_var($val, FILTER_SANITIZE_NUMBER_INT); + } } - } - - foreach ($sizeWalk as $oid => $val) { - if (preg_match('/\.(\d+)$/', $oid, $m2) && $m2[1] === $idx) { - $size = (int)preg_replace('/[^0-9]/', '', (string)$val); - break; - } - } - - foreach ($usedWalk as $oid => $val) { - if (preg_match('/\.(\d+)$/', $oid, $m2) && $m2[1] === $idx) { - $used = (int)preg_replace('/[^0-9]/', '', (string)$val); - break; - } - } + return null; + }; - log_msg("Storage[$idx]: Desc='$descr', Size=$size, Used=$used, Units=$units"); + $units = $findVal($unitsWalk, $idx); + $size = $findVal($sizeWalk, $idx); + $used = $findVal($usedWalk, $idx); - if ($size === null || $units === null || $used === null || $size === 0 || $units === 0) { - log_msg("Storage[$idx]: SKIP (fehlende oder ungültige Daten)"); - continue; - } + if ($size === null || $units === null || $used === null || $size === 0) continue; $totalBytes = $size * $units; $usedBytes = $used * $units; - $percent = $totalBytes > 0 ? ($usedBytes / $totalBytes) * 100 : 0; + $percent = ($totalBytes > 0) ? ($usedBytes / $totalBytes) * 100 : 0; - $storageEntries[] = [ - 'idx' => $idx, - 'descr' => $descr, - 'percent' => $percent, - 'totalGB' => $totalBytes / (1024 ** 3), - 'usedGB' => $usedBytes / (1024 ** 3), - ]; + $storageEntries[] = ['idx' => $idx, 'descr' => $descr, 'percent' => $percent, 'totalGB' => $totalBytes / (1024**3)]; - // Heuristik 1: Suche nach C: oder Root $lower = strtolower($descr); - if ($diskPercent === null && (strpos($lower, 'c:') !== false || strpos($lower, 'c:\\') !== false || strpos($lower, 'c:/') !== false || $lower === '/' || strpos($lower, 'root') !== false)) { - $diskPercent = $percent; - log_msg("Datenträger erkannt (Index $idx): $descr → $percent%"); + + // DISK C: oder Root + if ($diskPercent === null) { + if (str_starts_with($lower, 'c:') || str_starts_with($lower, 'c:\\') || $lower === '/' || str_contains($lower, 'root')) { + $diskPercent = $percent; + } } - // Heuristik 2: Suche nach Physical Memory - if ($memPercent === null && ((strpos($lower, 'physical') !== false && strpos($lower, 'memory') !== false) || strpos($lower, 'ram') !== false || strpos($lower, 'physical memory') !== false)) { - $memPercent = $percent; - log_msg("Speicher erkannt (Index $idx): $descr → $percent%"); + // RAM + if ($memPercent === null) { + if (str_contains($lower, 'physical memory') || str_contains($lower, 'ram')) { + $memPercent = $percent; + } } } } -// Fallback 1: Wenn keine Disk gefunden, nimm den größten Storage-Eintrag > 1GB +// Fallback Disk: Größter Speicher > 5GB if ($diskPercent === null && count($storageEntries) > 0) { - log_msg('Fallback: Suche Disk (größter Eintrag > 1GB)'); usort($storageEntries, fn($a, $b) => $b['totalGB'] <=> $a['totalGB']); - foreach ($storageEntries as $entry) { - if ($entry['totalGB'] > 1) { + foreach($storageEntries as $entry) { + if ($entry['totalGB'] > 5) { $diskPercent = $entry['percent']; - log_msg('Fallback Disk gefunden (Index ' . $entry['idx'] . '): ' . $entry['descr'] . ' → ' . $diskPercent . '%'); break; } } } -// Fallback 2: Wenn kein Speicher gefunden, nimm den kleinsten Eintrag (meist Physical Memory) -if ($memPercent === null && count($storageEntries) > 0) { - log_msg('Fallback: Suche Memory (kleinster Eintrag)'); - usort($storageEntries, fn($a, $b) => $a['totalGB'] <=> $b['totalGB']); - $memPercent = $storageEntries[0]['percent']; - log_msg('Fallback Memory gefunden (Index ' . $storageEntries[0]['idx'] . '): ' . $storageEntries[0]['descr'] . ' → ' . $memPercent . '%'); -} +// --- 4. Hostname --- +$hostnameOid = '1.3.6.1.2.1.1.5.0'; +$hostname = @sget($host, $community, $hostnameOid, $timeoutMicro, $retries); +if($hostname) $hostname = trim(str_ireplace('STRING:', '', $hostname), ' "'); +// --- Ergebnis --- $result = [ - 'hostname' => @sget($host, $community, '1.3.6.1.2.1.1.5.0', $timeout, $retries) ?? null, - 'uptime' => $uptimeStr, - 'upticks' => $upticks, - 'cpu_usage' => $cpu, - 'memory_usage' => $memPercent !== null ? round($memPercent, 2) : null, - 'disk_usage_c' => $diskPercent !== null ? round($diskPercent, 2) : null, - 'last_update' => time(), + 'hostname' => $hostname ?? 'n/a', + 'uptime' => $uptimeStr, + 'upticks' => $upticks, + 'cpu_usage' => $cpuUsage, + 'memory_usage' => $memPercent !== null ? round($memPercent, 2) : 0, + 'disk_usage_c' => $diskPercent !== null ? round($diskPercent, 2) : 0, + 'last_update' => time(), ]; -log_msg('RESULT: CPU=' . $result['cpu_usage'] . ', Mem=' . $result['memory_usage'] . ', Disk=' . $result['disk_usage_c']); +log_msg('RESULT: UptimeRaw='.($uptimeRaw??'null').' CPU=' . $result['cpu_usage'] . ' Mem=' . $result['memory_usage']); $resultJson = json_encode($result); - -// === Cache schreiben === @file_put_contents($cacheFile, $resultJson); -log_msg('Cache geschrieben, TTL: ' . $cacheTTL . 's'); - -echo $resultJson; -exit; +echo $resultJson; \ No newline at end of file diff --git a/public/css/sb-admin-2.css b/public/css/sb-admin-2.css index fb96fb4..9a91a3b 100644 --- a/public/css/sb-admin-2.css +++ b/public/css/sb-admin-2.css @@ -11,27 +11,27 @@ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ :root { - --blue: #4e73df; - --indigo: #6610f2; - --purple: #6f42c1; - --pink: #e83e8c; - --red: #e74a3b; - --orange: #fd7e14; - --yellow: #f6c23e; - --green: #1cc88a; - --teal: #20c9a6; - --cyan: #36b9cc; + --blue: #3b82f6; + --indigo: #6366f1; + --purple: #8b5cf6; + --pink: #ec4899; + --red: #ef4444; + --orange: #f97316; + --yellow: #f59e0b; + --green: #10b981; + --teal: #14b8a6; + --cyan: #06b6d4; --white: #fff; - --gray: #858796; - --gray-dark: #5a5c69; - --primary: #4e73df; - --secondary: #858796; - --success: #1cc88a; - --info: #36b9cc; - --warning: #f6c23e; - --danger: #e74a3b; - --light: #f8f9fc; - --dark: #5a5c69; + --gray: #9ca3af; + --gray-dark: #374151; + --primary: #3b82f6; + --secondary: #6b7280; + --success: #10b981; + --info: #06b6d4; + --warning: #f59e0b; + --danger: #ef4444; + --light: #1f2937; + --dark: #111827; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; @@ -64,9 +64,9 @@ body { font-size: 1rem; font-weight: 400; line-height: 1.5; - color: #858796; + color: #ffffff; text-align: left; - background-color: #fff; + background-color: #0f172a; } [tabindex="-1"]:focus:not(:focus-visible) { @@ -159,13 +159,13 @@ sup { } a { - color: #4e73df; + color: #60a5fa; text-decoration: none; background-color: transparent; } a:hover { - color: #224abe; + color: #3b82f6; text-decoration: underline; } @@ -364,6 +364,7 @@ h1, h2, h3, h4, h5, h6, margin-bottom: 0.5rem; font-weight: 400; line-height: 1.2; + color: #f8fafc; } h1, .h1 { @@ -1485,23 +1486,23 @@ pre code { .table { width: 100%; margin-bottom: 1rem; - color: #858796; + color: #ffffff; } .table th, .table td { padding: 0.75rem; vertical-align: top; - border-top: 1px solid #e3e6f0; + border-top: 1px solid #334155; } .table thead th { vertical-align: bottom; - border-bottom: 2px solid #e3e6f0; + border-bottom: 2px solid #334155; } .table tbody + tbody { - border-top: 2px solid #e3e6f0; + border-top: 2px solid #334155; } .table-sm th, @@ -1510,12 +1511,12 @@ pre code { } .table-bordered { - border: 1px solid #e3e6f0; + border: 1px solid #334155; } .table-bordered th, .table-bordered td { - border: 1px solid #e3e6f0; + border: 1px solid #334155; } .table-bordered thead th, @@ -1531,12 +1532,12 @@ pre code { } .table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(0, 0, 0, 0.05); + background-color: rgba(255, 255, 255, 0.05); } .table-hover tbody tr:hover { - color: #858796; - background-color: rgba(0, 0, 0, 0.075); + color: #ffffff; + background-color: rgba(255, 255, 255, 0.1); } .table-primary, @@ -1737,9 +1738,9 @@ pre code { } .table .thead-light th { - color: #6e707e; - background-color: #eaecf4; - border-color: #e3e6f0; + color: #e2e8f0; + background-color: #1e293b; + border-color: #334155; } .table-dark { @@ -1833,10 +1834,10 @@ pre code { font-size: 1rem; font-weight: 400; line-height: 1.5; - color: #6e707e; - background-color: #fff; + color: #ffffff; + background-color: #1e293b; background-clip: padding-box; - border: 1px solid #d1d3e2; + border: 1px solid #334155; border-radius: 0.35rem; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @@ -1858,15 +1859,15 @@ pre code { } .form-control:focus { - color: #6e707e; - background-color: #fff; - border-color: #bac8f3; + color: #ffffff; + background-color: #1e293b; + border-color: #3b82f6; outline: 0; - box-shadow: 0 0 0 0.2rem rgba(78, 115, 223, 0.25); + box-shadow: 0 0 0 0.2rem rgba(59, 130, 246, 0.25); } .form-control::-webkit-input-placeholder { - color: #858796; + color: #64748b; opacity: 1; } @@ -3024,12 +3025,12 @@ input[type="button"].btn-block { padding: 0.5rem 0; margin: 0.125rem 0 0; font-size: 0.85rem; - color: #858796; + color: #f8fafc; text-align: left; list-style: none; - background-color: #fff; + background-color: #1e293b; background-clip: padding-box; - border: 1px solid #e3e6f0; + border: 1px solid #334155; border-radius: 0.35rem; } @@ -3182,7 +3183,7 @@ input[type="button"].btn-block { height: 0; margin: 0.5rem 0; overflow: hidden; - border-top: 1px solid #eaecf4; + border-top: 1px solid #334155; } .dropdown-item { @@ -3191,7 +3192,7 @@ input[type="button"].btn-block { padding: 0.25rem 1.5rem; clear: both; font-weight: 400; - color: #3a3b45; + color: #e2e8f0; text-align: inherit; white-space: nowrap; background-color: transparent; @@ -3199,19 +3200,19 @@ input[type="button"].btn-block { } .dropdown-item:hover, .dropdown-item:focus { - color: #2e2f37; + color: #ffffff; text-decoration: none; - background-color: #eaecf4; + background-color: #334155; } .dropdown-item.active, .dropdown-item:active { color: #fff; text-decoration: none; - background-color: #4e73df; + background-color: #3b82f6; } .dropdown-item.disabled, .dropdown-item:disabled { - color: #b7b9cc; + color: #94a3b8; pointer-events: none; background-color: transparent; } @@ -4489,9 +4490,9 @@ input[type="button"].btn-block { flex-direction: column; min-width: 0; word-wrap: break-word; - background-color: #fff; + background-color: #1e293b; background-clip: border-box; - border: 1px solid #e3e6f0; + border: 1px solid #334155; border-radius: 0.35rem; } @@ -4552,8 +4553,8 @@ input[type="button"].btn-block { .card-header { padding: 0.75rem 1.25rem; margin-bottom: 0; - background-color: #f8f9fc; - border-bottom: 1px solid #e3e6f0; + background-color: #0f172a; + border-bottom: 1px solid #334155; } .card-header:first-child { @@ -4562,8 +4563,8 @@ input[type="button"].btn-block { .card-footer { padding: 0.75rem 1.25rem; - background-color: #f8f9fc; - border-top: 1px solid #e3e6f0; + background-color: #0f172a; + border-top: 1px solid #334155; } .card-footer:last-child { @@ -6491,7 +6492,7 @@ button.bg-dark:focus { } .bg-white { - background-color: #fff !important; + background-color: #1e293b !important; } .bg-transparent { @@ -6499,15 +6500,15 @@ button.bg-dark:focus { } .border { - border: 1px solid #e3e6f0 !important; + border: 1px solid #334155 !important; } .border-top { - border-top: 1px solid #e3e6f0 !important; + border-top: 1px solid #334155 !important; } .border-right { - border-right: 1px solid #e3e6f0 !important; + border-right: 1px solid #334155 !important; } .border-bottom { @@ -9660,7 +9661,7 @@ a.text-dark:hover, a.text-dark:focus { } .text-muted { - color: #858796 !important; + color: #cbd5e1 !important; } .text-black-50 { @@ -9797,7 +9798,7 @@ a:focus { } #wrapper #content-wrapper { - background-color: #f8f9fc; + background-color: #0f172a; width: 100%; overflow-x: hidden; } @@ -9900,8 +9901,8 @@ a:focus { } .bg-gradient-primary { - background-color: #4e73df; - background-image: linear-gradient(180deg, #4e73df 10%, #224abe 100%); + background-color: #1e3a8a; + background-image: linear-gradient(180deg, #1e40af 0%, #1e3a8a 50%, #172554 100%); background-size: cover; } @@ -9996,39 +9997,39 @@ a:focus { } .text-gray-100 { - color: #f8f9fc !important; + color: #ffffff !important; } .text-gray-200 { - color: #eaecf4 !important; + color: #f8fafc !important; } .text-gray-300 { - color: #dddfeb !important; + color: #f1f5f9 !important; } .text-gray-400 { - color: #d1d3e2 !important; + color: #e2e8f0 !important; } .text-gray-500 { - color: #b7b9cc !important; + color: #cbd5e1 !important; } .text-gray-600 { - color: #858796 !important; + color: #cbd5e1 !important; } .text-gray-700 { - color: #6e707e !important; + color: #e2e8f0 !important; } .text-gray-800 { - color: #5a5c69 !important; + color: #f1f5f9 !important; } .text-gray-900 { - color: #3a3b45 !important; + color: #ffffff !important; } .icon-circle { @@ -10169,6 +10170,8 @@ a:focus { .topbar { height: 4.375rem; + background-color: #1e293b; + border-bottom: 1px solid #334155; } .topbar #sidebarToggleTop { @@ -10388,7 +10391,7 @@ a:focus { padding: 0.5rem 1rem; margin: 0 0.5rem; display: block; - color: #3a3b45; + color: #cbd5e1; text-decoration: none; border-radius: 0.35rem; white-space: nowrap; @@ -10396,17 +10399,17 @@ a:focus { .sidebar .nav-item .collapse .collapse-inner .collapse-item:hover, .sidebar .nav-item .collapsing .collapse-inner .collapse-item:hover { - background-color: #eaecf4; + background-color: #334155; } .sidebar .nav-item .collapse .collapse-inner .collapse-item:active, .sidebar .nav-item .collapsing .collapse-inner .collapse-item:active { - background-color: #dddfeb; + background-color: #475569; } .sidebar .nav-item .collapse .collapse-inner .collapse-item.active, .sidebar .nav-item .collapsing .collapse-inner .collapse-item.active { - color: #4e73df; + color: #3b82f6; font-weight: 700; } @@ -11269,11 +11272,13 @@ form.user .btn-user { footer.sticky-footer { padding: 2rem 0; flex-shrink: 0; + background-color: #0f172a; } footer.sticky-footer .copyright { line-height: 1; font-size: 0.8rem; + color: #94a3b8; } body.sidebar-toggled footer.sticky-footer { diff --git a/public/index.php b/public/index.php index 70dbe3c..0357052 100644 --- a/public/index.php +++ b/public/index.php @@ -74,6 +74,8 @@ use App\Controllers\AuthController; use App\Controllers\DashboardController; use App\Controllers\UserManagementController; use App\Services\Logging\LoggingService; +use App\Controllers\LogViewerController; + // Globalen Logger initialisieren, damit auch Fehler außerhalb der Controller // (z. B. in index.php selbst) sauber protokolliert werden. @@ -199,6 +201,8 @@ function handleResult(?array $result): void $authController = new AuthController($config); $dashboardController = new DashboardController($config); $userManagementController = new UserManagementController($config); +$logViewerController = new LogViewerController($config); + // Route aus dem Query-Parameter lesen. Standardroute ist "login", // sodass nicht angemeldete Benutzer automatisch auf die Login-Seite geführt werden. @@ -240,6 +244,18 @@ switch ($route) { handleResult($result); break; + case 'createuser': + requireLogin($config); + $result = $userManagementController->create(); + handleResult($result); + break; + + case 'logs': + requireLogin($config); + $result = $logViewerController->show(); + handleResult($result); + break; + default: http_response_code(404); echo 'Route nicht gefunden.'; diff --git a/public/views/createuser.php b/public/views/createuser.php new file mode 100644 index 0000000..47bcfc8 --- /dev/null +++ b/public/views/createuser.php @@ -0,0 +1,496 @@ + + +
                                                                +

                                                                Benutzer erstellen

                                                                +
                                                                + + + + + + + + + + + + + +

                                                                Hier können Sie einzelne Active-Directory-Benutzer anlegen oder eine CSV-Datei hochladen, um mehrere Benutzer gleichzeitig zu erstellen. Sie können die CSV in der Vorschau bearbeiten bevor Sie die Erstellung auslösen.

                                                                + +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                Einzelner Benutzer
                                                                +
                                                                +
                                                                +
                                                                +
                                                                + + +
                                                                + +
                                                                + + +
                                                                + +
                                                                + + +
                                                                + +
                                                                + + + Das Passwort muss mindestens 7 Zeichen lang sein, darf keine größeren Teile des Benutzernamens enthalten und muss Zeichen aus mindestens 3 von 4 Kategorien enthalten: Großbuchstaben, Kleinbuchstaben, Ziffern, Sonderzeichen. +
                                                                + +
                                                                + + +
                                                                + + +
                                                                + +
                                                                +
                                                                +
                                                                + +
                                                                +
                                                                +
                                                                +
                                                                Mehrere Benutzer via CSV
                                                                +
                                                                +
                                                                +

                                                                Die CSV-Datei sollte eine Kopfzeile mit folgenden Spalten enthalten: samaccountname,displayname,mail,password,groups. Gruppen können komma-getrennt sein. Nach dem Hochladen erscheint der Inhalt in der Vorschau, dort kann er vor dem Absenden editiert werden.

                                                                + +
                                                                +
                                                                + + +
                                                                + +
                                                                + + +
                                                                + +
                                                                + + +
                                                                + +
                                                                + + +
                                                                + + + + + +
                                                                +
                                                                + + + +
                                                                +
                                                                Beim Laden werden Änderungen in der Vorschau verworfen und die Originaldatei neu eingelesen.
                                                                +
                                                                +
                                                                + + Tipp: Wenn Sie die CSV im Textfeld bearbeiten, wird der bearbeitete Text an den Server gesendet. +
                                                                +
                                                                +
                                                                +
                                                                + + +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                CSV Verarbeitungsergebnisse
                                                                +
                                                                +
                                                                +
                                                                + + + + + + + + + + + + + + + + + +
                                                                AnmeldenameStatusHinweis
                                                                +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                + + +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                Hinweise
                                                                +
                                                                +
                                                                +
                                                                  +
                                                                • Die tatsächliche Erstellung von AD-Benutzern wird serverseitig durchgeführt. Diese View sendet Daten an die Endpunkte /api/create_user.php und /api/create_users_csv.php.
                                                                • +
                                                                • Stellen Sie sicher, dass der Webserver die nötigen Rechte hat und die LDAP/AD-Verbindung korrekt konfiguriert ist.
                                                                • +
                                                                • Für Sicherheit: prüfen Sie bitte CSRF-Schutz und Validierung auf der Serverseite.
                                                                • +
                                                                +
                                                                +
                                                                +
                                                                +
                                                                + + + + diff --git a/public/views/dashboard.php b/public/views/dashboard.php index d2c2026..13c2ad2 100644 --- a/public/views/dashboard.php +++ b/public/views/dashboard.php @@ -12,6 +12,22 @@ declare(strict_types=1); /** @var array $serverStatus */ ?> + +

                                                                Server-Dashboard

                                                                @@ -106,11 +122,11 @@ declare(strict_types=1);
                                                                -
                                                                +
                                                                -
                                                                +
                                                                Datenträger C: / Root
                                                                @@ -127,11 +143,11 @@ declare(strict_types=1);
                                                                -
                                                                +
                                                                -
                                                                +
                                                                System Uptime
                                                                @@ -153,6 +169,7 @@ declare(strict_types=1); - + + - + - + - - - + + + - - - + + + diff --git a/public/views/partials/sidebar.php b/public/views/partials/sidebar.php index ea97dd7..ed8761c 100644 --- a/public/views/partials/sidebar.php +++ b/public/views/partials/sidebar.php @@ -49,6 +49,24 @@ Benutzer & Gruppen + + + + + + + + + diff --git a/public/views/users.php b/public/views/users.php index e95e779..295c63b 100644 --- a/public/views/users.php +++ b/public/views/users.php @@ -25,6 +25,10 @@ declare(strict_types=1);

                                                                Benutzer & Gruppen

                                                                + + +  Benutzer erstellen +
                                                                diff --git a/scripts/powershell/README.md b/scripts/powershell/README.md new file mode 100644 index 0000000..fa46501 --- /dev/null +++ b/scripts/powershell/README.md @@ -0,0 +1,42 @@ +This directory contains PowerShell scripts used by the PHP AdminTool for Active Directory user creation. + +Usage (single user): +1. Create a JSON payload file (for example `payload.json`) with contents: +``` +{ + "samaccountname": "testuser", + "displayname": "Test User", + "mail": "testuser@example.local", + "password": "P@ssw0rd1234", + "ou": "OU=Users,DC=example,DC=local", + "groups": "Users,IT-Staff", + "dry_run": true +} +``` +2. Run the script from PowerShell as a user with permission to create AD users (or use `dry_run` true to test): + +``` +powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File .\create_user.ps1 -InputFile C:\temp\payload.json +``` + +Usage (CSV): +1. Create a CSV file with header `samaccountname,displayname,mail,password,ou,groups` (or no header and set `has_header: false` in meta JSON). +2. Create a meta JSON file containing the CSV path and options: +``` +{ + "input_file": "C:\temp\users.csv", + "delimiter": ",", + "has_header": true, + "dry_run": true +} +``` +3. Run the CSV script: +``` +powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File .\create_users_csv.ps1 -InputFile C:\temp\meta.json +``` + +Notes: +- Ensure the `ActiveDirectory` PowerShell module is installed on the host system (RSAT). +- Test with `dry_run` set to `true` first to verify results without modifying AD. +- The scripts return a compact JSON object on stdout which the PHP backend expects. +- Run the webserver (IIS) as a user that has sufficient rights to run the `New-ADUser` and `Add-ADGroupMember` commands when `dry_run` is disabled. diff --git a/scripts/powershell/check_environment.ps1 b/scripts/powershell/check_environment.ps1 new file mode 100644 index 0000000..811cdea --- /dev/null +++ b/scripts/powershell/check_environment.ps1 @@ -0,0 +1,17 @@ +# Returns JSON with information about the environment and AD module availability +Try { + $actor = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name +} Catch { + $actor = $null +} + +# Does the ActiveDirectory module exist? +$module = Get-Module -ListAvailable -Name ActiveDirectory -ErrorAction SilentlyContinue +$hasModule = $module -ne $null + +# Is New-ADUser available? +$canNewAdUser = (Get-Command New-ADUser -ErrorAction SilentlyContinue) -ne $null + +$output = @{ success = $true; actor = $actor; module_installed = $hasModule; can_new_aduser = $canNewAdUser } +Write-Output ($output | ConvertTo-Json -Compress) +exit 0 diff --git a/scripts/powershell/create_user.ps1 b/scripts/powershell/create_user.ps1 new file mode 100644 index 0000000..011468b --- /dev/null +++ b/scripts/powershell/create_user.ps1 @@ -0,0 +1,153 @@ +param( + [Parameter(Mandatory=$true)] + [string]$InputFile +) + +# Read input JSON +try { + $json = Get-Content -Raw -Path $InputFile -ErrorAction Stop + $payload = $json | ConvertFrom-Json +} catch { + $err = $_.Exception.Message + Write-Output (@{ success = $false; message = "Failed to read/parse input JSON: $err" } | ConvertTo-Json -Compress) + exit 1 +} + +# Default result +$actor = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name +$result = @{ success = $false; message = "Unspecified error"; actor = $actor } + +# Validate +if (-not $payload.samaccountname -or -not $payload.password) { + $result.message = "Required fields: samaccountname and password" + Write-Output ($result | ConvertTo-Json -Compress) + exit 1 +} + +# Convert to strings +$sam = [string]$payload.samaccountname +$display = [string]($payload.displayname) +$mail = [string]($payload.mail) +$pass = [string]$payload.password +$ou = [string]($payload.ou) +$groups = [string]($payload.groups) +$dryRun = [bool]($payload.dry_run -as [bool]) +# Password hint and validation helper (German) +$passwordHint = @" +Das sollten die Anforderungen an das Passwort sein: + +- mindestens 7 Zeichen +- darf den Benutzer-/Accountnamen nicht enthalten (bzw. keine zu großen Teile davon) +- muss Zeichen aus mindestens 3 von 4 Kategorien enthalten: + 1) Großbuchstaben (A–Z) + 2) Kleinbuchstaben (a–z) + 3) Ziffern (0–9) + 4) Sonderzeichen (alles, was kein Buchstabe/Zahl ist, z. B. ! ? # _ - . , usw.) +"@ + +function Test-PasswordRequirements { + param( + [string]$Password, + [string]$SamAccountName + ) + + $errors = @() + + if ([string]::IsNullOrEmpty($Password) -or $Password.Length -lt 7) { + $errors += 'Passwort muss mindestens 7 Zeichen lang sein.' + } + + $categories = 0 + if ($Password -match '[A-Z]') { $categories++ } + if ($Password -match '[a-z]') { $categories++ } + if ($Password -match '\d') { $categories++ } + if ($Password -match '[^A-Za-z0-9]') { $categories++ } + if ($categories -lt 3) { + $errors += 'Passwort muss Zeichen aus mindestens 3 von 4 Kategorien enthalten (Groß, Klein, Ziffern, Sonderzeichen).' + } + + if (-not [string]::IsNullOrEmpty($SamAccountName)) { + $pwLower = $Password.ToLowerInvariant() + $samLower = $SamAccountName.ToLowerInvariant() + + if ($pwLower -like "*${samLower}*") { + $errors += 'Passwort darf den Benutzernamen nicht enthalten.' + } else { + $minLen = 4 + if ($samLower.Length -ge $minLen) { + for ($len = $minLen; $len -le $samLower.Length; $len++) { + for ($start = 0; $start -le $samLower.Length - $len; $start++) { + $sub = $samLower.Substring($start, $len) + if ($pwLower -like "*${sub}*") { + $errors += 'Passwort darf keine größeren Teile des Benutzernamens enthalten.' + break 2 + } + } + } + } + } + } + + return $errors +} +# Ensure ActiveDirectory module available +try { + Import-Module ActiveDirectory -ErrorAction Stop +} catch { + $result.message = "ActiveDirectory PowerShell module not available: $($_.Exception.Message)" + Write-Output ($result | ConvertTo-Json -Compress) + exit 1 +} + +# Build New-ADUser parameters +$props = @{ + Name = if ($display -and $display -ne '') { $display } else { $sam } + SamAccountName = $sam + Enabled = $true +} + +if ($mail -and $mail -ne '') { $props['EmailAddress'] = $mail } +if ($ou -and $ou -ne '') { $props['Path'] = $ou } + +# Validate password before continuing +$pwErrors = Test-PasswordRequirements -Password $pass -SamAccountName $sam +if ($pwErrors.Count -gt 0) { + $result.message = 'Invalid password: ' + ($pwErrors -join ' | ') + $result.hint = $passwordHint + Write-Output ($result | ConvertTo-Json -Compress) + exit 1 +} + +# Build secure password +$securePass = ConvertTo-SecureString $pass -AsPlainText -Force +$props['AccountPassword'] = $securePass + +# Execute +if ($dryRun) { + $result.success = $true + $result.message = "DRY RUN: would create user $($sam)" + Write-Output ($result | ConvertTo-Json -Compress) + exit 0 +} + +try { + # Create the AD user + New-ADUser @props -ErrorAction Stop + + # Add to groups, if provided + if ($groups -and $groups -ne '') { + $groupList = $groups -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } + foreach ($g in $groupList) { + Add-ADGroupMember -Identity $g -Members $sam -ErrorAction Stop + } + } + + $result.success = $true + $result.message = "User $($sam) created successfully" + Write-Output ($result | ConvertTo-Json -Compress) + exit 0 +} catch { + $result.message = "Error creating user $($sam): $($_.Exception.Message)" + Write-Output ($result | ConvertTo-Json -Compress) + exit 1 +} diff --git a/scripts/powershell/create_users_csv.ps1 b/scripts/powershell/create_users_csv.ps1 new file mode 100644 index 0000000..009bd8f --- /dev/null +++ b/scripts/powershell/create_users_csv.ps1 @@ -0,0 +1,176 @@ +param( + [Parameter(Mandatory=$true)] + [string]$InputFile +) + +# Read meta JSON +try { + $json = Get-Content -Raw -Path $InputFile -ErrorAction Stop + $meta = $json | ConvertFrom-Json +} catch { + Write-Output (@{ success = $false; message = "Failed to read/parse meta JSON: $($_.Exception.Message)" } | ConvertTo-Json -Compress) + exit 1 +} + +$csvFile = [string]$meta.input_file +# PowerShell 5.1 doesn't support the null-coalescing operator '??'. +# Use an explicit check here to set the default delimiter. +$delimiter = [string]$meta.delimiter +if ([string]::IsNullOrWhiteSpace($delimiter)) { $delimiter = ',' } +$hasHeader = [bool]($meta.has_header -as [bool]) +$dryRun = [bool]($meta.dry_run -as [bool]) +$defaultOu = [string]$meta.default_ou + + +if (-not (Test-Path -Path $csvFile)) { + Write-Output (@{ success = $false; message = "CSV file not found: $csvFile" } | ConvertTo-Json -Compress) + exit 1 +} + +# Ensure ActiveDirectory module is available +try { + Import-Module ActiveDirectory -ErrorAction Stop +} catch { + Write-Output (@{ success = $false; message = "ActiveDirectory PowerShell module not available: $($_.Exception.Message)" } | ConvertTo-Json -Compress) + exit 1 +} + +# Read CSV +try { + if ($hasHeader) { + $items = Import-Csv -Path $csvFile -Delimiter $delimiter -ErrorAction Stop + } else { + # Use default headers + $headers = 'samaccountname','displayname','mail','password','groups' + $items = Import-Csv -Path $csvFile -Delimiter $delimiter -Header $headers -ErrorAction Stop + } +} catch { + Write-Output (@{ success = $false; message = "Failed to parse CSV: $($_.Exception.Message)" } | ConvertTo-Json -Compress) + exit 1 +} + +$actor = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name +$results = @() +$successCount = 0 +$failCount = 0 + +foreach ($row in $items) { + $sam = $row.samaccountname + $display = $row.displayname + $mail = $row.mail + $pass = $row.password + $groups = $row.groups + + if ([string]::IsNullOrWhiteSpace($ou) -and -not [string]::IsNullOrWhiteSpace($defaultOu)) { + $ou = $defaultOu + } + + # Password hint text (German) + $passwordHint = @" +Das sollten die Anforderungen an das Passwort sein: + +- mindestens 7 Zeichen +- darf den Benutzer-/Accountnamen nicht enthalten (bzw. keine zu großen Teile davon) +- muss Zeichen aus mindestens 3 von 4 Kategorien enthalten: + 1) Großbuchstaben (A–Z) + 2) Kleinbuchstaben (a–z) + 3) Ziffern (0–9) + 4) Sonderzeichen (alles, was kein Buchstabe/Zahl ist, z. B. ! ? # _ - . , usw.) +"@ + + function Test-PasswordRequirements { + param( + [string]$Password, + [string]$SamAccountName + ) + + $errors = @() + + if ([string]::IsNullOrEmpty($Password) -or $Password.Length -lt 7) { + $errors += 'Passwort muss mindestens 7 Zeichen lang sein.' + } + + # Categories: uppercase, lowercase, digit, special + $categories = 0 + if ($Password -match '[A-Z]') { $categories++ } + if ($Password -match '[a-z]') { $categories++ } + if ($Password -match '\d') { $categories++ } + if ($Password -match '[^A-Za-z0-9]') { $categories++ } + if ($categories -lt 3) { + $errors += 'Passwort muss Zeichen aus mindestens 3 von 4 Kategorien enthalten (Groß, Klein, Ziffern, Sonderzeichen).' + } + + # Check for username inclusion or large parts of it (case-insensitive) + if (-not [string]::IsNullOrEmpty($SamAccountName)) { + $pwLower = $Password.ToLowerInvariant() + $samLower = $SamAccountName.ToLowerInvariant() + + if ($pwLower -like "*${samLower}*") { + $errors += 'Passwort darf den Benutzernamen nicht enthalten.' + } else { + # Check for substrings of username of length >= 4 + $minLen = 4 + if ($samLower.Length -ge $minLen) { + for ($len = $minLen; $len -le $samLower.Length; $len++) { + for ($start = 0; $start -le $samLower.Length - $len; $start++) { + $sub = $samLower.Substring($start, $len) + if ($pwLower -like "*${sub}*") { + $errors += 'Passwort darf keine größeren Teile des Benutzernamens enthalten.' + break 2 + } + } + } + } + } + } + + return $errors + } + + if ([string]::IsNullOrWhiteSpace($sam) -or [string]::IsNullOrWhiteSpace($pass)) { + $results += @{ sam = $sam; success = $false; message = 'Missing samaccountname or password' } + $failCount++ + continue + } + + # Validate password according to requirements, also during dry run so issues are visible early + $pwErrors = Test-PasswordRequirements -Password $pass -SamAccountName $sam + if ($pwErrors.Count -gt 0) { + $results += @{ sam = $sam; success = $false; message = ('Invalid password: ' + ($pwErrors -join ' | ')); hint = $passwordHint } + $failCount++ + continue + } + + if ($dryRun) { + $results += @{ sam = $sam; success = $true; message = 'DRY RUN: would create (password validated)' } + $successCount++ + continue + } + + try { + $props = @{ Name = if ($display -and $display -ne '') { $display } else { $sam }; SamAccountName = $sam; Enabled = $true } + if ($mail -and $mail -ne '') { $props['EmailAddress'] = $mail } + if ($ou -and $ou -ne '') { $props['Path'] = $ou } + $securePass = ConvertTo-SecureString $pass -AsPlainText -Force + $props['AccountPassword'] = $securePass + + New-ADUser @props -ErrorAction Stop + + if ($groups -and $groups -ne '') { + $groupList = $groups -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } + foreach ($g in $groupList) { + Add-ADGroupMember -Identity $g -Members $sam -ErrorAction Stop + } + } + + $results += @{ sam = $sam; success = $true; message = 'Created' } + $successCount++ + } catch { + $results += @{ sam = $sam; success = $false; message = $_.Exception.Message } + $failCount++ + } +} + +$output = @{ success = $failCount -eq 0; message = "Created $successCount users, $failCount failures"; details = $results; actor = $actor } +Write-Output ($output | ConvertTo-Json -Compress) +exit 0