Layout modularisiert

This commit is contained in:
blaerf 2025-11-28 15:23:25 +01:00
parent 8cd07a73a0
commit 905ce67742
18 changed files with 580 additions and 1772 deletions

View File

@ -12,6 +12,11 @@ use App\Services\Ldap\LdapAuthService;
* - Login-Formular anzeigen * - Login-Formular anzeigen
* - Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD) * - Login-Daten verarbeiten (Authentifizierung gegen LDAP/AD)
* - Logout durchführen * - 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.
*/ */
class AuthController class AuthController
{ {
@ -39,33 +44,36 @@ class AuthController
/** /**
* Zeigt das Login-Formular an. * Zeigt das Login-Formular an.
* Optional kann eine Fehlermeldung übergeben werden, die in der View dargestellt wird. * Optional kann eine Fehlermeldung übergeben werden, die in der View dargestellt wird.
*
* @return array<string, mixed> View-Result für das zentrale Layout
*/ */
public function showLoginForm(?string $errorMessage = null): void public function showLoginForm(?string $errorMessage = null): array
{ {
// Pfad zur Login-View (Template-Datei) ermitteln. // Pfad zur Login-View (Template-Datei) ermitteln.
$viewPath = __DIR__ . '/../../public/views/login.php'; $viewPath = __DIR__ . '/../../public/views/login.php';
// Variable für die View vorbereiten (wird in der eingebundenen Datei verwendet). // Wichtig: Die View erwartet aktuell die Variable $error.
$error = $errorMessage; return [
'view' => $viewPath,
// Falls die View-Datei (noch) nicht existiert, einen Fallback-HTML-Output verwenden. 'data' => [
if (file_exists($viewPath) === false) { 'error' => $errorMessage,
$this->renderInlineLogin($error); ],
return; 'pageTitle' => 'Login',
} // Beim Login ist typischerweise kein Menüpunkt aktiv.
'activeMenu' => null,
// View-Datei einbinden. Variablen aus dieser Methode (z. B. $error) sind dort verfügbar. ];
require $viewPath;
} }
/** /**
* Verarbeitet das Login-Formular: * Verarbeitet das Login-Formular:
* - Liest Benutzername und Passwort aus $_POST * - Liest Benutzername und Passwort aus $_POST
* - Ruft den LdapAuthService zur Authentifizierung auf * - Ruft den LdapAuthService zur Authentifizierung auf
* - Setzt bei Erfolg die Session und leitet zum Dashboard weiter * - Liefert bei Erfolg ein Redirect-Result zum Dashboard
* - Zeigt bei Fehlern erneut das Login-Formular mit Fehlermeldung an * - Liefert bei Fehlern ein View-Result für das Login-Formular mit Fehlermeldung
*
* @return array<string, mixed> View-Result ODER Redirect-Result
*/ */
public function processLogin(): void public function processLogin(): array
{ {
// Formulardaten aus dem POST-Request lesen. // Formulardaten aus dem POST-Request lesen.
$username = trim($_POST['username'] ?? ''); $username = trim($_POST['username'] ?? '');
@ -79,14 +87,14 @@ class AuthController
} catch (\Throwable $exception) { } catch (\Throwable $exception) {
// Technischer Fehler (z. B. LDAP-Server nicht erreichbar, falsche Konfiguration). // Technischer Fehler (z. B. LDAP-Server nicht erreichbar, falsche Konfiguration).
// In diesem Fall wird eine technische Fehlermeldung im Login-Formular angezeigt. // In diesem Fall wird eine technische Fehlermeldung im Login-Formular angezeigt.
$this->showLoginForm('Technischer Fehler bei der Anmeldung: ' . $exception->getMessage()); return $this->showLoginForm(
return; 'Technischer Fehler bei der Anmeldung: ' . $exception->getMessage()
);
} }
// Fachlich fehlgeschlagene Anmeldung (z. B. falsches Passwort). // Fachlich fehlgeschlagene Anmeldung (z. B. falsches Passwort).
if ($authenticated === false) { if ($authenticated === false) {
$this->showLoginForm('Benutzername oder Passwort ist ungültig.'); return $this->showLoginForm('Benutzername oder Passwort ist ungültig.');
return;
} }
// Ab hier ist die Anmeldung erfolgreich. // Ab hier ist die Anmeldung erfolgreich.
@ -96,22 +104,27 @@ class AuthController
$sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user'; $sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user';
// Benutzerinformationen in der Session hinterlegen. // Benutzerinformationen in der Session hinterlegen.
// Diese Daten werden später von requireLogin() ausgewertet. // Diese Daten werden später von requireLogin() bzw. im Layout ausgewertet.
$_SESSION[$sessionKey] = [ $_SESSION[$sessionKey] = [
'username' => $username, 'username' => $username,
'login_at' => date('c'), // ISO-8601 Datum/Zeit der Anmeldung 'login_at' => date('c'), // ISO-8601 Datum/Zeit der Anmeldung
]; ];
// Nach erfolgreicher Anmeldung zum Dashboard weiterleiten. // Nach erfolgreicher Anmeldung zum Dashboard weiterleiten.
header('Location: index.php?route=dashboard'); // Kein direkter header()-Aufruf, sondern ein Redirect-Result
exit; // für die zentrale Steuerung in index.php.
return [
'redirect' => 'index.php?route=dashboard',
];
} }
/** /**
* Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird, * Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird,
* und leitet anschließend zurück auf die Login-Seite. * und liefert anschließend ein Redirect-Result zurück auf die Login-Seite.
*
* @return array<string, mixed> Redirect-Result
*/ */
public function logout(): void public function logout(): array
{ {
// Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen. // Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen.
$sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user'; $sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user';
@ -119,49 +132,9 @@ class AuthController
// Eintrag aus der Session entfernen → Benutzer gilt als ausgeloggt. // Eintrag aus der Session entfernen → Benutzer gilt als ausgeloggt.
unset($_SESSION[$sessionKey]); unset($_SESSION[$sessionKey]);
// Zur Login-Seite zurückleiten. // Redirect-Result zur Login-Seite.
header('Location: index.php?route=login'); return [
exit; 'redirect' => 'index.php?route=login',
} ];
/**
* Fallback-Ausgabe für das Login-Formular, falls noch keine separate View-Datei existiert.
* Gibt direkt HTML aus (inline-Template).
*/
private function renderInlineLogin(?string $errorMessage): void
{
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>AD Admin Tool Login</title>
</head>
<body>
<h1>AD Admin Tool Login</h1>
<?php if ($errorMessage !== null): ?>
<!-- Fehlermeldung ausgeben, HTML-Ausgabe wird dabei sicher maskiert -->
<p style="color: red;"><?php echo htmlspecialchars($errorMessage, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></p>
<?php endif; ?>
<!-- Einfaches Login-Formular, das per POST an die Route "login.submit" gesendet wird -->
<form action="index.php?route=login.submit" method="post">
<div>
<label for="username">Benutzername:</label>
<input type="text" id="username" name="username" required>
</div>
<div>
<label for="password">Passwort:</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit">Anmelden</button>
</form>
</body>
</html>
<?php
} }
} }

View File

@ -12,6 +12,9 @@ use App\Services\Snmp\SnmpServerStatusService;
* Zuständig für: * Zuständig für:
* - Abrufen des Serverstatus (über SnmpServerStatusService) * - Abrufen des Serverstatus (über SnmpServerStatusService)
* - Auswählen und Rendern der Dashboard-View * - Auswählen und Rendern der Dashboard-View
*
* NEU:
* - Gibt ein View-Result zurück, das von index.php + Layout gerendert wird.
*/ */
class DashboardController class DashboardController
{ {
@ -42,8 +45,10 @@ class DashboardController
/** /**
* Zeigt das Dashboard an. * Zeigt das Dashboard an.
* Holt die Serverstatus-Daten aus dem SnmpServerStatusService und übergibt sie an die View. * Holt die Serverstatus-Daten aus dem SnmpServerStatusService und übergibt sie an die View.
*
* @return array<string, mixed> View-Result für das zentrale Layout
*/ */
public function show(): void public function show(): array
{ {
// Serverstatus über den SNMP-Service ermitteln. // Serverstatus über den SNMP-Service ermitteln.
// In der aktuellen Version liefert der Service noch Demo-Daten. // In der aktuellen Version liefert der Service noch Demo-Daten.
@ -52,69 +57,15 @@ class DashboardController
// Pfad zur Dashboard-View (Template-Datei) ermitteln. // Pfad zur Dashboard-View (Template-Datei) ermitteln.
$viewPath = __DIR__ . '/../../public/views/dashboard.php'; $viewPath = __DIR__ . '/../../public/views/dashboard.php';
// Falls die View-Datei (noch) nicht existiert, Fallback-HTML direkt aus dem Controller ausgeben. return [
if (file_exists($viewPath) === false) { 'view' => $viewPath,
$this->renderInlineDashboard($serverStatus); 'data' => [
return; // Die View erwartet aktuell $serverStatus.
} 'serverStatus' => $serverStatus,
],
// View-Datei einbinden. Die Variable $serverStatus steht in der View zur Verfügung. 'pageTitle' => 'Dashboard',
require $viewPath; // In der Sidebar soll der Dashboard-Menüpunkt aktiv sein.
} 'activeMenu' => 'dashboard',
];
/**
* Fallback-Dashboard-Ausgabe direkt aus dem Controller (ohne separate View-Datei).
* Nur als Notlösung gedacht, falls die eigentliche View noch nicht vorhanden ist.
*
* @param array<string, mixed> $serverStatus Serverstatus-Daten (Hostname, CPU%, RAM%, etc.)
*/
private function renderInlineDashboard(array $serverStatus): void
{
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>AD Admin Tool Dashboard</title>
</head>
<body>
<h1>Dashboard</h1>
<h2>Serverstatus</h2>
<ul>
<li>
Hostname:
<?php echo htmlspecialchars((string)$serverStatus['hostname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</li>
<li>
Betriebssystem:
<?php echo htmlspecialchars((string)$serverStatus['os'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</li>
<li>
Uptime:
<?php echo htmlspecialchars((string)$serverStatus['uptime'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</li>
<li>
CPU-Auslastung:
<?php echo (int)$serverStatus['cpu_usage']; ?>%
</li>
<li>
RAM-Auslastung:
<?php echo (int)$serverStatus['memory_usage']; ?>%
</li>
<li>
Datenträger C:
<?php echo (int)$serverStatus['disk_usage_c']; ?>%
</li>
<li>
Letzte Aktualisierung:
<?php echo htmlspecialchars((string)$serverStatus['last_update'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</li>
</ul>
<p><a href="index.php?route=logout">Logout</a></p>
</body>
</html>
<?php
} }
} }

View File

@ -18,6 +18,9 @@ use App\Services\Ldap\LdapDirectoryService;
* WICHTIG: * WICHTIG:
* - Es werden aktuell nur Daten angezeigt (Read-only). * - Es werden aktuell nur Daten angezeigt (Read-only).
* - Es findet keine Änderung im Active Directory statt. * - Es findet keine Änderung im Active Directory statt.
*
* NEU:
* - Gibt ein View-Result-Array zurück, das von index.php + Layout gerendert wird.
*/ */
class UserManagementController class UserManagementController
{ {
@ -45,8 +48,10 @@ class UserManagementController
/** /**
* Zeigt Benutzer- und Gruppenliste an. * Zeigt Benutzer- und Gruppenliste an.
* Wird typischerweise über die Route "users" (index.php?route=users) aufgerufen. * Wird typischerweise über die Route "users" (index.php?route=users) aufgerufen.
*
* @return array<string, mixed> View-Result für das zentrale Layout
*/ */
public function show(): void public function show(): array
{ {
// Standardwerte für die View-Variablen vorbereiten. // Standardwerte für die View-Variablen vorbereiten.
$error = null; $error = null;
@ -66,88 +71,16 @@ class UserManagementController
// Pfad zur eigentlichen View-Datei bestimmen. // Pfad zur eigentlichen View-Datei bestimmen.
$viewPath = __DIR__ . '/../../public/views/users.php'; $viewPath = __DIR__ . '/../../public/views/users.php';
// Falls die View-Datei (noch) nicht existiert, Fallback-Ausgabe verwenden. return [
if (file_exists($viewPath) === false) { 'view' => $viewPath,
$this->renderInline($users, $groups, $error); 'data' => [
return; // Die View erwartet aktuell $users, $groups, $error.
} 'users' => $users,
'groups' => $groups,
// Variablen $users, $groups, $error stehen in der View zur Verfügung, 'error' => $error,
// weil sie im aktuellen Scope definiert sind. ],
require $viewPath; 'pageTitle' => 'Benutzer & Gruppen',
} 'activeMenu' => 'users',
];
/**
* Fallback-Ausgabe, falls noch keine View-Datei existiert.
*
* @param array<int, array<string, string>> $users Liste der Benutzer-Datensätze
* @param array<int, array<string, string>> $groups Liste der Gruppen-Datensätze
* @param string|null $error Fehlermeldung (falls vorhanden)
*/
private function renderInline(array $users, array $groups, ?string $error): void
{
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>AD Admin Tool Benutzer &amp; Gruppen</title>
</head>
<body>
<h1>Benutzer &amp; Gruppen</h1>
<?php if ($error !== null): ?>
<!-- Fehlermeldung ausgeben, HTML-sicher maskiert -->
<p style="color: red;"><?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></p>
<?php endif; ?>
<h2>Benutzer</h2>
<table border="1" cellpadding="4" cellspacing="0">
<thead>
<tr>
<th>Benutzername (sAMAccountName)</th>
<th>Anzeigename</th>
<th>E-Mail</th>
</tr>
</thead>
<tbody>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo htmlspecialchars($user['samaccountname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($user['displayname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($user['mail'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2>Gruppen</h2>
<table border="1" cellpadding="4" cellspacing="0">
<thead>
<tr>
<th>Gruppenname (sAMAccountName)</th>
<th>CN</th>
<th>Beschreibung</th>
</tr>
</thead>
<tbody>
<?php foreach ($groups as $group): ?>
<tr>
<td><?php echo htmlspecialchars($group['samaccountname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($group['cn'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
<td><?php echo htmlspecialchars($group['description'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p>
<a href="index.php?route=dashboard">Zurück zum Dashboard</a> |
<a href="index.php?route=logout">Logout</a>
</p>
</body>
</html>
<?php
} }
} }

View File

@ -13,7 +13,6 @@ session_start();
* im Namespace "App\..." verwendet wird. * im Namespace "App\..." verwendet wird.
*/ */
spl_autoload_register( spl_autoload_register(
// Anonyme Funktion, die den Klassennamen prüft und den Dateipfad zur Klasse ermittelt.
static function (string $class): void { static function (string $class): void {
$prefix = 'App\\'; $prefix = 'App\\';
$baseDir = __DIR__ . '/../app/'; $baseDir = __DIR__ . '/../app/';
@ -32,6 +31,8 @@ spl_autoload_register(
} }
); );
require __DIR__ . '/views/layout.php';
// Pfad zur Konfigurationsdatei prüfen und Konfiguration laden // Pfad zur Konfigurationsdatei prüfen und Konfiguration laden
$configPath = __DIR__ . '/../config/config.php'; $configPath = __DIR__ . '/../config/config.php';
if (file_exists($configPath) === false) { if (file_exists($configPath) === false) {
@ -49,7 +50,12 @@ use App\Controllers\AuthController;
use App\Controllers\DashboardController; use App\Controllers\DashboardController;
use App\Controllers\UserManagementController; use App\Controllers\UserManagementController;
// Hilfsfunktion für geschützte Routen /**
* Hilfsfunktion: Prüft, ob ein Benutzer eingeloggt ist.
* Wenn nicht, wird auf die Login-Seite umgeleitet.
*
* @param array<string, mixed> $config
*/
function requireLogin(array $config): void function requireLogin(array $config): void
{ {
// session_key_user aus dem Config-Array lesen. Wenn nicht gesetzt oder null, Standard "admin_user" verwenden. // session_key_user aus dem Config-Array lesen. Wenn nicht gesetzt oder null, Standard "admin_user" verwenden.
@ -63,44 +69,93 @@ function requireLogin(array $config): void
} }
} }
// Route aus dem GET-Parameter lesen. Wenn nicht gesetzt, Standardroute "login" verwenden. /**
$route = $_GET['route'] ?? 'login'; * Hilfsfunktion: Ergebnis-Array eines Controllers nehmen und das Layout rendern.
*
* Erwartetes Format im $result-Array:
* [
* 'view' => string, // Pfad zur Content-View (z. B. public/views/dashboard.php)
* 'data' => array<string, mixed> // Daten für die View
* 'pageTitle' => string, // Seitentitel
* 'activeMenu' => string|null, // Menükennung für Sidebar (z. B. 'dashboard' oder 'users')
* ]
*
* @param array<string, mixed> $result
*/
function handleResult(?array $result): void
{
if ($result === null) {
return;
}
// Neue Instanz der Klasse AuthController erstellen (wird bei Bedarf über den Autoloader geladen). if (isset($result['redirect']) === true) {
header('Location: ' . (string)$result['redirect']);
exit;
}
$contentView = (string)($result['view'] ?? '');
$viewData = (array)($result['data'] ?? []);
$pageTitle = (string)($result['pageTitle'] ?? '');
$activeMenu = $result['activeMenu'] ?? null;
if ($contentView === '' || file_exists($contentView) === false) {
http_response_code(500);
echo 'Interner Fehler: Content-View wurde nicht gefunden.';
exit;
}
// Hier rufen wir jetzt die Layout-Funktion aus layout.php auf
renderLayout($contentView, $viewData, $pageTitle, is_string($activeMenu) ? $activeMenu : null);
}
// Controller instanziieren
$authController = new AuthController($config); $authController = new AuthController($config);
// Neue Instanz der Klasse DashboardController erstellen (wird bei Bedarf über den Autoloader geladen).
$dashboardController = new DashboardController($config); $dashboardController = new DashboardController($config);
// Neue Instanz der Klasse UserManagmentController erstellen (wird bei Bedarf über den Autoloader geladen).
$userManagementController = new UserManagementController($config); $userManagementController = new UserManagementController($config);
// Anhand des Routing-Ziels (route) entscheiden, welcher Code ausgeführt wird. // Route bestimmen
$route = $_GET['route'] ?? 'login';
switch ($route) { switch ($route) {
case 'login': case 'login':
$authController->showLoginForm(); // Wenn bereits eingeloggt, direkt zum Dashboard
$sessionKey = $config['security']['session_key_user'] ?? 'admin_user';
if (isset($_SESSION[$sessionKey]) === true) {
header('Location: index.php?route=dashboard');
exit;
}
// Controller liefert View-Definition + Daten
$result = $authController->showLoginForm();
renderLayout($result);
break; break;
case 'login.submit': case 'login.submit':
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { // POST-Login wird im Controller verarbeitet.
header('Location: index.php?route=login'); // Der Controller entscheidet, ob er redirectet oder ein View-Ergebnis zurückgibt.
exit; $result = $authController->processLogin();
if ($result !== null) {
// z. B. bei Login-Fehler: Login-Seite mit Fehlermeldung anzeigen
renderLayout($result);
} }
$authController->processLogin(); // Bei erfolgreichem Login macht der Controller einen Redirect und beendet das Script.
break; break;
case 'logout': case 'logout':
$authController->logout(); $authController->logout();
// logout() sollte selbst redirecten (z. B. auf route=login)
break; break;
case 'dashboard': case 'dashboard':
requireLogin($config); requireLogin($config);
$dashboardController->show(); $result = $dashboardController->show();
renderLayout($result);
break; break;
case 'users': case 'users':
requireLogin($config); requireLogin($config);
$userManagementController->show(); $result = $userManagementController->show();
renderLayout($result);
break; break;
default: default:
@ -108,3 +163,4 @@ switch ($route) {
echo 'Route nicht gefunden.'; echo 'Route nicht gefunden.';
break; break;
} }

View File

@ -1,792 +1,100 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/** @var array<string, mixed> $serverStatus */ /** @var array<string, mixed> $serverStatus */
?> ?>
<!DOCTYPE html>
<html lang="en">
<head> <div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Server-Dashboard</h1>
</div>
<meta charset="utf-8"> <div class="row">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Dashboard</title> <!-- Hostname -->
<!-- Custom fonts for this template-->
<link href="../vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="../css/sb-admin-2.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="../index.php?route=dashboard">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i>
</div>
<div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - Dashboard -->
<li class="nav-item active">
<a class="nav-link" href="../index.php?route=dashboard">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="../index.php?route=users">
<i class="fas fa-fw fa-users"></i>
<span>Users</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Interface
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo"
aria-expanded="true" aria-controls="collapseTwo">
<i class="fas fa-fw fa-cog"></i>
<span>Components</span>
</a>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Components:</h6>
<a class="collapse-item" href="../buttons.php">Buttons</a>
<a class="collapse-item" href="../cards.php">Cards</a>
</div>
</div>
</li>
<!-- Nav Item - Utilities Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
aria-expanded="true" aria-controls="collapseUtilities">
<i class="fas fa-fw fa-wrench"></i>
<span>Utilities</span>
</a>
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Utilities:</h6>
<a class="collapse-item" href="../utilities-color.php">Colors</a>
<a class="collapse-item" href="../utilities-border.php">Borders</a>
<a class="collapse-item" href="../utilities-animation.php">Animations</a>
<a class="collapse-item" href="../utilities-other.php">Other</a>
</div>
</div>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Addons
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages"
aria-expanded="true" aria-controls="collapsePages">
<i class="fas fa-fw fa-folder"></i>
<span>Pages</span>
</a>
<div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Login Screens:</h6>
<a class="collapse-item" href="login.php">Login</a>
<a class="collapse-item" href="../register.php">Register</a>
<a class="collapse-item" href="../forgot-password.php">Forgot Password</a>
<div class="collapse-divider"></div>
<h6 class="collapse-header">Other Pages:</h6>
<a class="collapse-item" href="../404.php">404 Page</a>
<a class="collapse-item" href="../blank.php">Blank Page</a>
</div>
</div>
</li>
<!-- Nav Item - Charts -->
<li class="nav-item">
<a class="nav-link" href="../charts.php">
<i class="fas fa-fw fa-chart-area"></i>
<span>Charts</span></a>
</li>
<!-- Nav Item - Tables -->
<li class="nav-item">
<a class="nav-link" href="../tables.php">
<i class="fas fa-fw fa-table"></i>
<span>Tables</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
<!-- Sidebar Message -->
<div class="sidebar-card d-none d-lg-flex">
<img class="sidebar-card-illustration mb-2" src="../images/undraw_rocket.svg" alt="...">
<p class="text-center mb-2"><strong>SB Admin Pro</strong> is packed with premium features, components, and more!</p>
<a class="btn btn-success btn-sm" href="https://startbootstrap.com/theme/sb-admin-pro">Upgrade to Pro!</a>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Search -->
<form
class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
aria-label="Search" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-primary" type="button">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Nav Item - Search Dropdown (Visible Only XS) -->
<li class="nav-item dropdown no-arrow d-sm-none">
<a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-search fa-fw"></i>
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in"
aria-labelledby="searchDropdown">
<form class="form-inline mr-auto w-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small"
placeholder="Search for..." aria-label="Search"
aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-primary" type="button">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
</div>
</li>
<!-- Nav Item - Alerts -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-bell fa-fw"></i>
<!-- Counter - Alerts -->
<span class="badge badge-danger badge-counter">3+</span>
</a>
<!-- Dropdown - Alerts -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="alertsDropdown">
<h6 class="dropdown-header">
Alerts Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-primary">
<i class="fas fa-file-alt text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 12, 2019</div>
<span class="font-weight-bold">A new monthly report is ready to download!</span>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-success">
<i class="fas fa-donate text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 7, 2019</div>
$290.29 has been deposited into your account!
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-warning">
<i class="fas fa-exclamation-triangle text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 2, 2019</div>
Spending Alert: We've noticed unusually high spending for your account.
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a>
</div>
</li>
<!-- Nav Item - Messages -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-envelope fa-fw"></i>
<!-- Counter - Messages -->
<span class="badge badge-danger badge-counter">7</span>
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="messagesDropdown">
<h6 class="dropdown-header">
Message Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_1.svg"
alt="...">
<div class="status-indicator bg-success"></div>
</div>
<div class="font-weight-bold">
<div class="text-truncate">Hi there! I am wondering if you can help me with a
problem I've been having.</div>
<div class="small text-gray-500">Emily Fowler · 58m</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_2.svg"
alt="...">
<div class="status-indicator"></div>
</div>
<div>
<div class="text-truncate">I have the photos that you ordered last month, how
would you like them sent to you?</div>
<div class="small text-gray-500">Jae Chun · 1d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_3.svg"
alt="...">
<div class="status-indicator bg-warning"></div>
</div>
<div>
<div class="text-truncate">Last month's report looks great, I am very happy with
the progress so far, keep up the good work!</div>
<div class="small text-gray-500">Morgan Alvarez · 2d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60"
alt="...">
<div class="status-indicator bg-success"></div>
</div>
<div>
<div class="text-truncate">Am I a good boy? The reason I ask is because someone
told me that people say this to all dogs, even if they aren't good...</div>
<div class="small text-gray-500">Chicken the Dog · 2w</div>
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a>
</div>
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">Douglas McGee</span>
<img class="img-profile rounded-circle"
src="../images/undraw_profile.svg">
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="userDropdown">
<a class="dropdown-item" href="#">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i>
Activity Log
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Dashboard</h1>
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i
class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>
</div>
<!-- Content Row -->
<div class="row">
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2"> <div class="card border-left-primary shadow h-100 py-2">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">CPU <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
</div> Hostname
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800"><?php echo (int)$serverStatus['cpu_usage']; ?>%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar"
style=<?php echo"\"width:". (int)$serverStatus['cpu_usage'] . "%\""; ?> aria-valuenow=<?php echo"\"". (int)$serverStatus['cpu_usage'] . "\""; ?> aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div> </div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
<?php echo htmlspecialchars((string)($serverStatus['hostname'] ?? 'n/a'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</div> </div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i> <i class="fas fa-server fa-2x text-gray-300"></i>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Earnings (Monthly) Card Example --> <!-- Betriebssystem -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2"> <div class="card border-left-success shadow h-100 py-2">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">RAM <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
</div> Betriebssystem
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800"><?php echo (int)$serverStatus['memory_usage']; ?>%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar"
style=<?php echo"\"width:". (int)$serverStatus['memory_usage'] . "%\""; ?> aria-valuenow=<?php echo"\"". (int)$serverStatus['memory_usage'] . "\""; ?> aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div> </div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
<?php echo htmlspecialchars((string)($serverStatus['os'] ?? 'n/a'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</div> </div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i> <i class="fas fa-desktop fa-2x text-gray-300"></i>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Earnings (Monthly) Card Example --> <!-- CPU-Auslastung -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">HDD (C:)
</div>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800"><?php echo (int)$serverStatus['disk_usage_c']; ?>%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar"
style=<?php echo"\"width:". (int)$serverStatus['disk_usage_c'] . "%\""; ?> aria-valuenow=<?php echo"\"". (int)$serverStatus['disk_usage_c'] . "\""; ?> aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Pending Requests Card Example -->
<div class="col-xl-3 col-md-6 mb-4"> <div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-warning shadow h-100 py-2"> <div class="card border-left-warning shadow h-100 py-2">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1"> <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
Pending Requests</div> CPU-Auslastung
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div> </div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
<?php echo (int)($serverStatus['cpu_usage'] ?? 0); ?> %
</div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-comments fa-2x text-gray-300"></i> <i class="fas fa-microchip fa-2x text-gray-300"></i>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Content Row --> <!-- RAM-Auslastung -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="row"> <div class="card border-left-info shadow h-100 py-2">
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div
class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Earnings Overview</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body"> <div class="card-body">
<div class="chart-area"> <div class="row no-gutters align-items-center">
<canvas id="myAreaChart"></canvas> <div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">
RAM-Auslastung
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
<?php echo (int)($serverStatus['memory_usage'] ?? 0); ?> %
</div> </div>
</div> </div>
</div> <div class="col-auto">
</div> <i class="fas fa-memory fa-2x text-gray-300"></i>
<!-- Pie Chart -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div
class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Content Row --> </div>
<div class="row">
<!-- Content Column --> <!-- Hier kannst du später Charts, weitere Karten usw. anhängen -->
<div class="col-lg-6 mb-4">
<!-- Project Card Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
</div>
<div class="card-body">
<h4 class="small font-weight-bold">Server Migration <span
class="float-right">20%</span></h4>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Sales Tracking <span
class="float-right">40%</span></h4>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Customer Database <span
class="float-right">60%</span></h4>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: 60%"
aria-valuenow="60" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Payout Details <span
class="float-right">80%</span></h4>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Account Setup <span
class="float-right">Complete!</span></h4>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 100%"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
<!-- Color System -->
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card bg-primary text-white shadow">
<div class="card-body">
Primary
<div class="text-white-50 small">#4e73df</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-success text-white shadow">
<div class="card-body">
Success
<div class="text-white-50 small">#1cc88a</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-info text-white shadow">
<div class="card-body">
Info
<div class="text-white-50 small">#36b9cc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-warning text-white shadow">
<div class="card-body">
Warning
<div class="text-white-50 small">#f6c23e</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-danger text-white shadow">
<div class="card-body">
Danger
<div class="text-white-50 small">#e74a3b</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-secondary text-white shadow">
<div class="card-body">
Secondary
<div class="text-white-50 small">#858796</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-light text-black shadow">
<div class="card-body">
Light
<div class="text-black-50 small">#f8f9fc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-dark text-white shadow">
<div class="card-body">
Dark
<div class="text-white-50 small">#5a5c69</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<!-- Illustrations -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Illustrations</h6>
</div>
<div class="card-body">
<div class="text-center">
<img class="img-fluid px-3 px-sm-4 mt-3 mb-4" style="width: 25rem;"
src="../images/undraw_posting_photo.svg" alt="...">
</div>
<p>Add some quality, svg illustrations to your project courtesy of <a
target="_blank" rel="nofollow" href="https://undraw.co/">unDraw</a>, a
constantly updated collection of beautiful svg images that you can use
completely free and without attribution!</p>
<a target="_blank" rel="nofollow" href="https://undraw.co/">Browse Illustrations on
unDraw &rarr;</a>
</div>
</div>
<!-- Approach -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Development Approach</h6>
</div>
<div class="card-body">
<p>SB Admin 2 makes extensive use of Bootstrap 4 utility classes in order to reduce
CSS bloat and poor page performance. Custom CSS classes are used to create
custom components and custom utility classes.</p>
<p class="mb-0">Before working with this theme, you should become familiar with the
Bootstrap framework, especially the utility classes.</p>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; Your Website 2021</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Logout Modal-->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="login.php">Logout</a>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="../vendor/jquery/jquery.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="../vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="../js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="../vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="../js/demo/chart-area-demo.js"></script>
<script src="../js/demo/chart-pie-demo.js"></script>
</body>
</html>

43
public/views/layout.php Normal file
View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/**
* Zentrales Layout für das AD Admin Tool.
*
* Erwartet (aus index.php übergeben):
* - string $contentView Pfad zur Content-View (z. B. public/views/dashboard.php)
* - array<string, mixed> $viewData Daten-Array für die View
* - string $pageTitle Seitentitel
* - string|null $activeMenu Kennung für die Sidebar (z. B. 'dashboard' oder 'users')
*/
// Daten-Array in einzelne Variablen entpacken,
// sodass die Content-Views direkt mit $users, $groups, $serverStatus, $error etc. arbeiten können.
function renderLayout(string $contentView, array $viewData, string $pageTitle, ?string $activeMenu): void
{
// Daten-Array in einzelne Variablen entpacken
foreach ($viewData as $key => $value) {
if (is_string($key) && $key !== '') {
$cleanKey = preg_replace('/[^a-zA-Z0-9_]/', '', $key);
if ($cleanKey !== '') {
$$cleanKey = $value;
}
}
}
$partialsPath = __DIR__ . '/partials';
require $partialsPath . '/head.php';
require $partialsPath . '/sidebar.php';
require $partialsPath . '/topbar.php';
?>
<!-- Begin Page Content -->
<div class="container-fluid">
<?php require $contentView; ?>
</div>
<!-- /.container-fluid -->
<?php
require $partialsPath . '/footer.php';
require $partialsPath . '/scripts.php';
}

View File

@ -1 +0,0 @@
<?php

View File

@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
/** @var string|null $pageTitle */
$title = $pageTitle ?? 'AD Admin Tool';
?>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title><?php echo htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></title>
<!-- Custom fonts for this template -->
<link href="../../vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template -->
<link href="../../css/sb-admin-2.min.css" rel="stylesheet">

View File

@ -1 +0,0 @@
<?php

View File

@ -1,137 +0,0 @@
<?php
declare(strict_types=1);
/** @var string|null $activeMenu */
$activeMenu = $activeMenu ?? '';
?>
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="../../index.php?route=dashboard">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i>
</div>
<div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - Dashboard -->
<li class="nav-item active">
<a class="nav-link" href="../../index.php?route=dashboard">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="../../index.php?route=users">
<i class="fas fa-fw fa-users"></i>
<span>Users</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Interface
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo"
aria-expanded="true" aria-controls="collapseTwo">
<i class="fas fa-fw fa-cog"></i>
<span>Components</span>
</a>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Components:</h6>
<a class="collapse-item" href="../../buttons.php">Buttons</a>
<a class="collapse-item" href="../../cards.php">Cards</a>
</div>
</div>
</li>
<!-- Nav Item - Utilities Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
aria-expanded="true" aria-controls="collapseUtilities">
<i class="fas fa-fw fa-wrench"></i>
<span>Utilities</span>
</a>
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Utilities:</h6>
<a class="collapse-item" href="../../utilities-color.php">Colors</a>
<a class="collapse-item" href="../../utilities-border.php">Borders</a>
<a class="collapse-item" href="../../utilities-animation.php">Animations</a>
<a class="collapse-item" href="../../utilities-other.php">Other</a>
</div>
</div>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Addons
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages"
aria-expanded="true" aria-controls="collapsePages">
<i class="fas fa-fw fa-folder"></i>
<span>Pages</span>
</a>
<div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Login Screens:</h6>
<a class="collapse-item" href="../login.php">Login</a>
<a class="collapse-item" href="../../register.php">Register</a>
<a class="collapse-item" href="../../forgot-password.php">Forgot Password</a>
<div class="collapse-divider"></div>
<h6 class="collapse-header">Other Pages:</h6>
<a class="collapse-item" href="../../404.php">404 Page</a>
<a class="collapse-item" href="../../blank.php">Blank Page</a>
</div>
</div>
</li>
<!-- Nav Item - Charts -->
<li class="nav-item">
<a class="nav-link" href="../../charts.php">
<i class="fas fa-fw fa-chart-area"></i>
<span>Charts</span></a>
</li>
<!-- Nav Item - Tables -->
<li class="nav-item">
<a class="nav-link" href="../../tables.php">
<i class="fas fa-fw fa-table"></i>
<span>Tables</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
<!-- Sidebar Message -->
<div class="sidebar-card d-none d-lg-flex">
<img class="sidebar-card-illustration mb-2" src="../../images/undraw_rocket.svg" alt="...">
<p class="text-center mb-2"><strong>SB Admin Pro</strong> is packed with premium features, components, and more!</p>
<a class="btn btn-success btn-sm" href="https://startbootstrap.com/theme/sb-admin-pro">Upgrade to Pro!</a>
</div>
</ul>
<!-- End of Sidebar -->

View File

@ -1 +0,0 @@
<?php

View File

@ -1,86 +1,61 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/** /** @var string|null $error */
* @var string|null $error
*/
?> ?>
<!DOCTYPE html> <div class="row justify-content-center">
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Login</title>
<!-- Custom fonts for this template-->
<link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template-->
<link href="css/sb-admin-2.min.css" rel="stylesheet">
</head>
<body class="bg-gradient-primary">
<div class="container">
<!-- Outer Row -->
<div class="row justify-content-center">
<div class="col-xl-10 col-lg-12 col-md-9">
<div class="col-xl-6 col-lg-7 col-md-8">
<div class="card o-hidden border-0 shadow-lg my-5"> <div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0"> <div class="card-body p-0">
<!-- Nested Row within Card Body --> <!-- Nested Row within Card Body -->
<div class="row"> <div class="row">
<div class="col-lg-6 d-none d-lg-block bg-login-image"></div> <div class="col-lg-12">
<div class="col-lg-6">
<div class="p-5"> <div class="p-5">
<div class="text-center"> <div class="text-center mb-4">
<h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1> <h1 class="h4 text-gray-900">Willkommen beim AD Admin Tool</h1>
<p class="text-muted mb-0">
Anmeldung gegen Active Directory per LDAP/LDAPS.
</p>
</div> </div>
<?php if ($error !== null): ?> <?php if ($error !== null): ?>
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> <?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<form class="user" method="post" action="index.php?route=login.submit">
<form class="user" action="index.php?route=login.submit" method="post" novalidate>
<div class="form-group"> <div class="form-group">
<input type="text" name="username" class="form-control form-control-user" <label for="username">Benutzername</label>
id="username" aria-describedby="usernameHelp" <input type="text"
placeholder="Enter Username..."> class="form-control form-control-user"
id="username"
name="username"
placeholder="z. B. admin"
required>
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="password" name="password" class="form-control form-control-user" <label for="password">Passwort</label>
id="password" placeholder="Password"> <input type="password"
</div> class="form-control form-control-user"
<div class="form-group"> id="password"
<div class="custom-control custom-checkbox small"> name="password"
<input type="checkbox" class="custom-control-input" id="customCheck"> placeholder="Passwort"
<label class="custom-control-label" for="customCheck">Remember required>
Me</label>
</div>
</div> </div>
<button type="submit" class="btn btn-primary btn-user btn-block"> <button type="submit" class="btn btn-primary btn-user btn-block">
Anmelden Anmelden
</button> </button>
</form> </form>
<hr> <hr>
<div class="text-center"> <p class="small text-muted mb-0">
<a class="small" href="forgot-password.php">Forgot Password?</a> Die Zugangsdaten werden nicht gespeichert sie werden nur zur Anmeldung am AD verwendet.
</div> </p>
<div class="text-center">
<a class="small" href="register.php">Create an Account!</a>
</div> </div>
</div> </div>
</div> </div>
@ -88,22 +63,4 @@ declare(strict_types=1);
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="vendor/jquery/jquery.min.js"></script>
<script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="js/sb-admin-2.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,24 @@
<?php
// public/views/partials/footer.php
?>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>&copy; AD Admin Tool <?= date('Y') ?></span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div>
<!-- End of Page Wrapper -->

View File

@ -0,0 +1,23 @@
<?php
// public/views/partials/head.php
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>AD Admin Tool<?= isset($pageTitle) ? ' ' . htmlspecialchars($pageTitle, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') : '' ?></title>
<!-- Custom fonts for this template-->
<link href="../../vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<!-- Google Fonts oder lokal, je nach Setup -->
<link href="../../css/sb-admin-2.min.css" rel="stylesheet">
<!-- DataTables CSS (falls benötigt) -->
<link href="../../vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">

View File

@ -0,0 +1,30 @@
<?php
// public/views/partials/scripts.php
?>
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Bootstrap core JavaScript-->
<script src="../../vendor/jquery/jquery.min.js"></script>
<script src="../../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="../../vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="../../js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="../../vendor/chart.js/Chart.min.js"></script>
<script src="../../vendor/datatables/jquery.dataTables.min.js"></script>
<script src="../../vendor/datatables/dataTables.bootstrap4.min.js"></script>
<!-- Page level custom scripts -->
<script src="../../js/demo/datatables-demo.js"></script>
<script src="../../js/demo/chart-area-demo.js"></script>
<script src="../../js/demo/chart-pie-demo.js"></script>
</body>
</html>

View File

@ -0,0 +1,49 @@
<?php
// public/views/partials/sidebar.php
?>
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="../../index.php?route=dashboard">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-tools"></i>
</div>
<div class="sidebar-brand-text mx-3">AD Admin Tool</div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - Dashboard -->
<li class="nav-item<?= (isset($activeMenu) && $activeMenu === 'dashboard') ? ' active' : '' ?>">
<a class="nav-link" href="../../index.php?route=dashboard">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Verzeichnis
</div>
<!-- Nav Item - Benutzer & Gruppen -->
<li class="nav-item<?= (isset($activeMenu) && $activeMenu === 'users') ? ' active' : '' ?>">
<a class="nav-link" href="../../index.php?route=users">
<i class="fas fa-fw fa-users-cog"></i>
<span>Benutzer &amp; Gruppen</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->

View File

@ -0,0 +1,49 @@
<?php
// public/views/partials/topbar.php
?>
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">
<?= isset($currentUsername)
? htmlspecialchars($currentUsername, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
: 'Administrator' ?>
</span>
<img class="img-profile rounded-circle"
src="../../images/undraw_profile.svg">
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="userDropdown">
<a class="dropdown-item" href="../../index.php?route=logout">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">

View File

@ -1,388 +1,30 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/** @var array<int, array<string, string>> $users */ /**
/** @var array<int, array<string, string>> $groups */ * @var array<int, array<string, string>> $users
/** @var string|null $error */ * @var array<int, array<string, string>> $groups
* @var string|null $error
*/
?> ?>
<!DOCTYPE html>
<html lang="en">
<head> <div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800">Benutzer &amp; Gruppen</h1>
</div>
<meta charset="utf-8"> <?php if ($error !== null): ?>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <div class="alert alert-danger" role="alert">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Tables</title>
<!-- Custom fonts for this template -->
<link href="../vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
<link
href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
rel="stylesheet">
<!-- Custom styles for this template -->
<link href="../css/sb-admin-2.min.css" rel="stylesheet">
<!-- Custom styles for this page -->
<link href="../vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body id="page-top">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="../views/dashboard.php">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i>
</div>
<div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - Dashboard -->
<li class="nav-item">
<a class="nav-link" href="../views/dashboard.php">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Interface
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo"
aria-expanded="true" aria-controls="collapseTwo">
<i class="fas fa-fw fa-cog"></i>
<span>Components</span>
</a>
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Components:</h6>
<a class="collapse-item" href="../buttons.php">Buttons</a>
<a class="collapse-item" href="../cards.php">Cards</a>
</div>
</div>
</li>
<!-- Nav Item - Utilities Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
aria-expanded="true" aria-controls="collapseUtilities">
<i class="fas fa-fw fa-wrench"></i>
<span>Utilities</span>
</a>
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Custom Utilities:</h6>
<a class="collapse-item" href="../utilities-color.php">Colors</a>
<a class="collapse-item" href="../utilities-border.php">Borders</a>
<a class="collapse-item" href="../utilities-animation.php">Animations</a>
<a class="collapse-item" href="../utilities-other.php">Other</a>
</div>
</div>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading">
Addons
</div>
<!-- Nav Item - Pages Collapse Menu -->
<li class="nav-item">
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages"
aria-expanded="true" aria-controls="collapsePages">
<i class="fas fa-fw fa-folder"></i>
<span>Pages</span>
</a>
<div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar">
<div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">Login Screens:</h6>
<a class="collapse-item" href="login.php">Login</a>
<a class="collapse-item" href="../register.php">Register</a>
<a class="collapse-item" href="../forgot-password.php">Forgot Password</a>
<div class="collapse-divider"></div>
<h6 class="collapse-header">Other Pages:</h6>
<a class="collapse-item" href="../404.php">404 Page</a>
<a class="collapse-item" href="../blank.php">Blank Page</a>
</div>
</div>
</li>
<!-- Nav Item - Charts -->
<li class="nav-item">
<a class="nav-link" href="../charts.php">
<i class="fas fa-fw fa-chart-area"></i>
<span>Charts</span></a>
</li>
<!-- Nav Item - Tables -->
<li class="nav-item active">
<a class="nav-link" href="../tables.html">
<i class="fas fa-fw fa-table"></i>
<span>Tables</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<!-- Sidebar Toggle (Topbar) -->
<form class="form-inline">
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
</form>
<!-- Topbar Search -->
<form
class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small" placeholder="Search for..."
aria-label="Search" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-primary" type="button">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
<!-- Topbar Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Nav Item - Search Dropdown (Visible Only XS) -->
<li class="nav-item dropdown no-arrow d-sm-none">
<a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-search fa-fw"></i>
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in"
aria-labelledby="searchDropdown">
<form class="form-inline mr-auto w-100 navbar-search">
<div class="input-group">
<input type="text" class="form-control bg-light border-0 small"
placeholder="Search for..." aria-label="Search"
aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-primary" type="button">
<i class="fas fa-search fa-sm"></i>
</button>
</div>
</div>
</form>
</div>
</li>
<!-- Nav Item - Alerts -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-bell fa-fw"></i>
<!-- Counter - Alerts -->
<span class="badge badge-danger badge-counter">3+</span>
</a>
<!-- Dropdown - Alerts -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="alertsDropdown">
<h6 class="dropdown-header">
Alerts Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-primary">
<i class="fas fa-file-alt text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 12, 2019</div>
<span class="font-weight-bold">A new monthly report is ready to download!</span>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-success">
<i class="fas fa-donate text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 7, 2019</div>
$290.29 has been deposited into your account!
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="mr-3">
<div class="icon-circle bg-warning">
<i class="fas fa-exclamation-triangle text-white"></i>
</div>
</div>
<div>
<div class="small text-gray-500">December 2, 2019</div>
Spending Alert: We've noticed unusually high spending for your account.
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a>
</div>
</li>
<!-- Nav Item - Messages -->
<li class="nav-item dropdown no-arrow mx-1">
<a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-envelope fa-fw"></i>
<!-- Counter - Messages -->
<span class="badge badge-danger badge-counter">7</span>
</a>
<!-- Dropdown - Messages -->
<div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="messagesDropdown">
<h6 class="dropdown-header">
Message Center
</h6>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_1.svg"
alt="...">
<div class="status-indicator bg-success"></div>
</div>
<div class="font-weight-bold">
<div class="text-truncate">Hi there! I am wondering if you can help me with a
problem I've been having.</div>
<div class="small text-gray-500">Emily Fowler · 58m</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_2.svg"
alt="...">
<div class="status-indicator"></div>
</div>
<div>
<div class="text-truncate">I have the photos that you ordered last month, how
would you like them sent to you?</div>
<div class="small text-gray-500">Jae Chun · 1d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="../images/undraw_profile_3.svg"
alt="...">
<div class="status-indicator bg-warning"></div>
</div>
<div>
<div class="text-truncate">Last month's report looks great, I am very happy with
the progress so far, keep up the good work!</div>
<div class="small text-gray-500">Morgan Alvarez · 2d</div>
</div>
</a>
<a class="dropdown-item d-flex align-items-center" href="#">
<div class="dropdown-list-image mr-3">
<img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60"
alt="...">
<div class="status-indicator bg-success"></div>
</div>
<div>
<div class="text-truncate">Am I a good boy? The reason I ask is because someone
told me that people say this to all dogs, even if they aren't good...</div>
<div class="small text-gray-500">Chicken the Dog · 2w</div>
</div>
</a>
<a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a>
</div>
</li>
<div class="topbar-divider d-none d-sm-block"></div>
<!-- Nav Item - User Information -->
<li class="nav-item dropdown no-arrow">
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">Douglas McGee</span>
<img class="img-profile rounded-circle"
src="../images/undraw_profile.svg">
</a>
<!-- Dropdown - User Information -->
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in"
aria-labelledby="userDropdown">
<a class="dropdown-item" href="#">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i>
Settings
</a>
<a class="dropdown-item" href="#">
<i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i>
Activity Log
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>
Logout
</a>
</div>
</li>
</ul>
</nav>
<!-- End of Topbar -->
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<h1 class="h3 mb-2 text-gray-800">Benutzer & Gruppen</h1>
<?php if ($error !== null): ?>
<p class="error">
<?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?> <?php echo htmlspecialchars($error, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</p> </div>
<?php endif; ?> <?php endif; ?>
<p class="mb-4">DataTables is a third party plugin that is used to generate the demo table below.
For more information about DataTables, please visit the <a target="_blank"
href="https://datatables.net">official DataTables documentation</a>.</p>
<!-- DataTales Example --> <p class="mb-4">
<div class="card shadow mb-4"> Die folgenden Tabellen zeigen Benutzern und Gruppen, die über LDAP/LDAPS aus dem Active Directory gelesen wurden.
</p>
<!-- Benutzer-Tabelle -->
<div class="card shadow mb-4">
<div class="card-header py-3"> <div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Benutzer</h6> <h6 class="m-0 font-weight-bold text-primary">Benutzer</h6>
</div> </div>
@ -391,32 +33,33 @@ declare(strict_types=1);
<table class="table table-bordered" id="usersTable" width="100%" cellspacing="0"> <table class="table table-bordered" id="usersTable" width="100%" cellspacing="0">
<thead> <thead>
<tr> <tr>
<th>Anmeldename</th> <th>Anmeldename (sAMAccountName)</th>
<th>Anzeigename</th> <th>Anzeigename</th>
<th>E-Mail</th> <th>E-Mail</th>
</tr> </tr>
</thead> </thead>
<tfoot>
<tr>
<th>Anmeldename</th>
<th>Anzeigename</th>
<th>E-Mail</th>
</tr>
</tfoot>
<tbody> <tbody>
<?php foreach ($users as $user): ?> <?php foreach ($users as $user): ?>
<tr> <tr>
<td><?php echo htmlspecialchars($user['samaccountname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> <td>
<td><?php echo htmlspecialchars($user['displayname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> <?php echo htmlspecialchars($user['samaccountname'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
<td><?php echo htmlspecialchars($user['mail'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> </td>
<td>
<?php echo htmlspecialchars($user['displayname'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</td>
<td>
<?php echo htmlspecialchars($user['mail'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
<div class="card shadow mb-4">
<!-- Gruppen-Tabelle -->
<div class="card shadow mb-4">
<div class="card-header py-3"> <div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Gruppen</h6> <h6 class="m-0 font-weight-bold text-primary">Gruppen</h6>
</div> </div>
@ -425,96 +68,27 @@ declare(strict_types=1);
<table class="table table-bordered" id="groupsTable" width="100%" cellspacing="0"> <table class="table table-bordered" id="groupsTable" width="100%" cellspacing="0">
<thead> <thead>
<tr> <tr>
<th>Gruppenname</th> <th>Gruppenname (sAMAccountName)</th>
<th>CN</th> <th>CN</th>
<th>Beschreibung</th> <th>Beschreibung</th>
</tr> </tr>
</thead> </thead>
<tfoot>
<tr>
<th>Gruppenname</th>
<th>CN</th>
<th>Beschreibung</th>
</tr>
</tfoot>
<tbody> <tbody>
<?php foreach ($groups as $group): ?> <?php foreach ($groups as $group): ?>
<tr> <tr>
<td><?php echo htmlspecialchars($group['samaccountname'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> <td>
<td><?php echo htmlspecialchars($group['cn'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> <?php echo htmlspecialchars($group['samaccountname'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
<td><?php echo htmlspecialchars($group['description'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?></td> </td>
<td>
<?php echo htmlspecialchars($group['cn'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</td>
<td>
<?php echo htmlspecialchars($group['description'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
<!-- Footer -->
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; Your Website 2020</span>
</div>
</div>
</footer>
<!-- End of Footer -->
</div>
<!-- End of Content Wrapper -->
</div> </div>
<!-- End of Page Wrapper -->
<!-- Scroll to Top Button-->
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Logout Modal-->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5>
<button class="close" type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Select "Logout" below if you are ready to end your current session.</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<a class="btn btn-primary" href="login.php">Logout</a>
</div>
</div>
</div>
</div>
<!-- Bootstrap core JavaScript-->
<script src="../vendor/jquery/jquery.min.js"></script>
<script src="../vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="../vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="../js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="../vendor/datatables/jquery.dataTables.min.js"></script>
<script src="../vendor/datatables/dataTables.bootstrap4.min.js"></script>
<!-- Page level custom scripts -->
<script src="../js/demo/datatables-demo.js"></script>
</body>
</html>