diff --git a/README.md b/README.md
index 3080b30..10bf0a4 100644
--- a/README.md
+++ b/README.md
@@ -23,27 +23,31 @@ Strato-taugliche PHP-Webanwendung für die Arbeitszeiterfassung des TC Ingelfing
- Separater CSV-Export für alle Stundenbuchungen
- SQL-Dump-Export und SQL-Dump-Wiederherstellung für vollständige App-Backups
- Separater CSV-Export der Logansicht für Administratoren
+- Admin-Funktion zum Löschen der Audit-Logeinträge
- Admin-Funktion zum Zurücksetzen aller Arbeitsstunden auf 0
- Tabler CSS via CDN für UI, Cards, Tabellen und Formulare
## Strato-Setup
-1. Inhalt von `httpdocs/` auf das Strato-Webverzeichnis hochladen
-2. Optional diese Umgebungsvariablen oder Konfigurationswerte setzen:
+1. Inhalt von `httpdocs/` in das Webverzeichnis der App hochladen
+2. Wenn die App in einem Unterordner wie `/arbeitsstunden/` läuft, muss genau dieser Ordner das Webroot der App enthalten
+3. `config.php` nicht in `httpdocs/`, sondern eine Ebene darüber ablegen
+4. Optional diese Umgebungsvariablen oder Konfigurationswerte setzen:
- `DB_HOST`
- `DB_NAME`
- `DB_USER`
- `DB_PASS`
- `SETUP_KEY` optional, schützt die Ersteinrichtung
-3. PHP 8.1+ und `pdo_mysql` aktivieren
+5. PHP 8.1+ und `pdo_mysql` aktivieren
## Strato Schritte
1. DB in Strato anlegen
-2. `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` setzen
-3. `httpdocs/install.php` öffnen und erstes Admin-Konto anlegen
-4. Danach mit dem neuen Admin einloggen
-5. Falls keine DB konfiguriert ist, nutzt die App Demo-Zugänge nur zum Anzeigen
+2. `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` setzen oder `config.php` oberhalb des Webroots anlegen
+3. Dateien aus `httpdocs/` in den Zielordner der App hochladen, z. B. `https://tc-ingelfingen.de/arbeitsstunden/`
+4. `install.php` über den App-Pfad öffnen, z. B. `/arbeitsstunden/install.php`, und erstes Admin-Konto anlegen
+5. Danach mit dem neuen Admin einloggen
+6. Falls keine DB konfiguriert ist, nutzt die App Demo-Zugänge nur zum Anzeigen
## Datenbank
@@ -88,6 +92,7 @@ Die Anwendung ist so aufgebaut, dass sie mit oder ohne DB läuft. Bei gesetzter
- Alle Arbeitsstunden auf 0 zurücksetzen
- Logansicht mit 50 Einträgen pro Seite
- Logansicht als CSV exportieren
+ - Audit-Logeinträge direkt in der Administration löschen
- Audit-Log für Verwaltungsaktionen sowie Login und Logout
## Listen Und Paginierung
@@ -166,6 +171,7 @@ Hinweis:
- Die aktuelle Implementierung nutzt PHP `mail()` fuer den Versand.
- Wenn das Hosting E-Mails direkt versenden kann, funktioniert der Passwort-Reset auch ohne vollstaendige SMTP-Implementierung.
- Die Datei `config.php` sollte nicht in `httpdocs/`, sondern im Projektwurzelverzeichnis liegen.
+- Bei einem Deployment in einem Unterordner wie `/arbeitsstunden/` liegt `config.php` eine Ebene über diesem Webroot.
## Ersteinrichtung
@@ -185,6 +191,7 @@ Für die Weitergabe an Anwender stehen folgende Anleitungen bereit:
- `httpdocs/install.php` Ersteinrichtung
- `httpdocs/app/bootstrap.php` DB, Login und Business-Logik
- `httpdocs/app/views.php` Tabler-UI
+- `config.php` lokale Konfiguration oberhalb des Webroots
- `config.php.example` Vorlage für DB- und Mail-Konfiguration
- `ANLEITUNG_MITGLIEDER.md` Handout für Mitglieder
- `ANLEITUNG_BEARBEITER.md` Handout für Bearbeiter
diff --git a/config.php b/config.php
index a2a1a1a..ffbadd6 100644
--- a/config.php
+++ b/config.php
@@ -1,9 +1,9 @@
'OpenCode',
+ 'author' => 'Erik Thiele',
'copyright' => 'Copyright 2026 TC-Ingelfingen',
- 'app_version' => '1.0.0',
+ 'app_version' => '1.6.0',
'db' => [
'host' => 'database-5020507124.webspace-host.com',
'name' => 'dbs15701183',
diff --git a/httpdocs/app/bootstrap.php b/httpdocs/app/bootstrap.php
index 1e0c3d8..1888f02 100644
--- a/httpdocs/app/bootstrap.php
+++ b/httpdocs/app/bootstrap.php
@@ -115,6 +115,26 @@ function appUrl(): string
return $scheme . '://' . $host;
}
+function basePath(): string
+{
+ $scriptName = $_SERVER['SCRIPT_NAME'] ?? '/index.php';
+ $dir = rtrim(str_replace('\\', '/', dirname($scriptName)), '/');
+ return $dir === '' ? '' : $dir;
+}
+
+function appPath(string $path = ''): string
+{
+ $base = basePath();
+ if ($path === '') {
+ return $base === '' ? '/' : $base . '/';
+ }
+ if ($path[0] === '?') {
+ return ($base === '' ? '/' : $base . '/') . $path;
+ }
+ $path = ltrim($path, '/');
+ return $base === '' ? '/' . $path : $base . '/' . $path;
+}
+
function sendPasswordResetMail(array $smtpConfig, string $toEmail, string $resetUrl): bool
{
if (($smtpConfig['from_email'] ?? '') === '') {
@@ -497,7 +517,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
addAuditLog($pdo, (int)$found['id'], 'Anmeldung erfolgreich.');
session_regenerate_id(true);
$_SESSION['user'] = ['id' => (int)$found['id'], 'firstname' => $found['firstname'] ?? '', 'lastname' => $found['lastname'] ?? '', 'name' => displayName($found), 'email' => $found['email'], 'role' => $found['role']];
- header('Location: /?page=dashboard');
+ header('Location: ' . appPath('?page=home'));
exit;
}
$error = 'Login fehlgeschlagen.';
@@ -557,7 +577,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt->execute([(int)$resetRow['user_id']]);
addAuditLog($pdo, (int)$resetRow['user_id'], 'Passwort über Reset-Link neu gesetzt.');
$_SESSION['login_notice'] = 'Passwort erfolgreich zurueckgesetzt. Bitte anmelden.';
- header('Location: /?page=login');
+ header('Location: ' . appPath('?page=login'));
exit;
}
}
@@ -827,6 +847,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$error = 'Log-Export ist ohne Datenbank nicht verfuegbar.';
}
+ if ($user && $action === 'clear_audit_logs' && $user['role'] === 'admin') {
+ if ($pdo) {
+ $pdo->exec('TRUNCATE TABLE audit_logs');
+ addAuditLog($pdo, (int)$user['id'], 'Audit-Log geleert.');
+ $notice = 'Logeintraege wurden geloescht.';
+ } else {
+ $error = 'Logeintraege koennen ohne Datenbank nicht geloescht werden.';
+ }
+ }
+
if ($user && $action === 'import_sql_dump' && $user['role'] === 'admin') {
if (!$pdo) {
$error = 'SQL-Wiederherstellung ist ohne Datenbank nicht verfuegbar.';
@@ -928,7 +958,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($user && $action === 'logout') {
addAuditLog($pdo, (int)$user['id'], 'Abmeldung erfolgt.');
session_destroy();
- header('Location: /?page=login');
+ header('Location: ' . appPath('?page=login'));
exit;
}
}
diff --git a/httpdocs/app/views.php b/httpdocs/app/views.php
index 83c76a5..d66e940 100644
--- a/httpdocs/app/views.php
+++ b/httpdocs/app/views.php
@@ -477,7 +477,7 @@ function renderLoginPage(): void
?>
-
+
TC Ingelfingen
Arbeitsstundenverwaltung
@@ -519,7 +519,7 @@ function renderResetPasswordPage(): void
-