diff --git a/.gitignore b/.gitignore
index af96255..ce93d1d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
www/secret.php
www/_user.php
-www/files/*
-!www/files/.gitkeep
+www/_files/*
+!www/_files/.gitkeep
diff --git a/README.md b/README.md
index a86a35d..747fb2c 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,14 @@ Dieses Projekt stellt eine einfache Verwaltungsoberfläche für digitale Visiten
* **PHP/Apache**-Weboberfläche in www/ mit Frontend (card.php, download.php) und Backend (admin.php plus _sql.php, _func.php, _user.php).
* **MariaDB** (Docker) hält Tabellen für Identitäten, Felder, UUIDs, Berechtigungen, Dateien und Loginversuche (db/init/001_schema.sql).
-* **Docker Compose** startet Webserver und Datenbank; www/ wird in den Apache-Container gemountet, www/files/ spiegelt das Upload-Verzeichnis /var/www/files/.
-* **Uploadverzeichnis** www/files/ liegt außerhalb des Document Roots und ist als .gitkeep im Repository abgelegt, damit Hochladungen später von download.php referenziert werden.
+* **Docker Compose** startet Webserver und Datenbank; www/ wird in den Apache-Container gemountet, www/_files/ spiegelt das Upload-Verzeichnis /var/www/html/_files/.
+* **Uploadverzeichnis** www/_files/ liegt außerhalb des Document Roots und ist als .gitkeep im Repository abgelegt, damit Hochladungen später von download.php referenziert werden.
## Installation & erster Start
1. Repository clonen.
2. www/secret.php vom Beispiel kopieren (secret.php.example) und Datenbankzugang konfigurieren, damit _sql.php sich verbinden kann.
-3. mkdir -p www/files (oder md www/files unter Windows) ausführen und darauf achten, dass die .gitkeep-Datei vorhanden ist, damit der Ordner beim Containerstart genutzt wird.
+3. mkdir -p www/_files (oder md www/_files unter Windows) ausführen und darauf achten, dass die .gitkeep-Datei vorhanden ist, damit der Ordner beim Containerstart genutzt wird.
4. docker-compose up --build im Projektverzeichnis ausführen, um Apache und MariaDB zu starten.
5. http://localhost/admin.php öffnen; die Standardanmeldedaten stehen in www/_user.php (admin / password) und sollten sofort geändert werden.
@@ -22,7 +22,7 @@ Dieses Projekt stellt eine einfache Verwaltungsoberfläche für digitale Visiten
* Login schützt das Dashboard; nach drei gescheiterten Versuchen wird eine IP für eine Stunde gesperrt (admin_login_attempts).
* Das Dashboard zeigt alle Identitäten sowie UUID-Token. Neue Identitäten erstellt man über ?action=identity_create.
* Jedes Identity kann beliebige Felder (identity_fields) enthalten. Der Typ kann single, multi, file oder url sein.
-* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in www/files/. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in files.
+* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in www/_files/. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in files.
* Wenn ein Feld auf Typ file gesetzt ist, zeigt die Auswahl nur Uploads der aktuellen Identität (per files.identity_id). Die ausgewählte Datei-ID wird im Feldwert gespeichert, damit später nur diese Datei angezeigt oder heruntergeladen wird.
* UUID-Token (access_tokens) verbinden eine Identität mit einer eindeutigen Zeichenfolge, können optional Auslaufdaten und Notizen erhalten und dürfen **nur einmal** existieren. Tokenrechte (token_permissions) bestimmen, welche Feldschlüssel Besucher:innen sehen.
@@ -48,13 +48,13 @@ Dieses Projekt stellt eine einfache Verwaltungsoberfläche für digitale Visiten
* **UUIDs sind einmalige Zugriffstoken** und sollten nicht doppelt vergeben oder offen weitergegeben werden, wenn geschützte Daten hinterlegt sind.
* **Admin-Zugang**: Bitte www/_user.php durch eigene Credentials ersetzen oder ein robusteres Auth-Verfahren implementieren.
* **Loginversuche** werden nach drei Fehlversuchen eine Stunde gesperrt (registerFailedLogin, isIpLocked, clearLoginAttempts).
-* **Datei-Uploads** liegen im Verzeichnis www/files/ (Container: /var/www/files/) und dürfen ausschließlich über download.php mit gültigem Token ausgeliefert werden. Der Ordner sollte nicht direkt vom Webserver referenziert werden.
+* **Datei-Uploads** liegen im Verzeichnis www/_files/ (Container: /var/www/html/_files/) und dürfen ausschließlich über download.php mit gültigem Token ausgeliefert werden. Der Ordner sollte nicht direkt vom Webserver referenziert werden.
## Weiterentwicklung & Pflege
1. **Stil & Branding**: Die Inline-CSS im card.php-Head kann durch ein eigenes Template ersetzt oder ausgelagert werden.
2. **Dateien & Automatisierung**: UUIDs und zugehörige Dateien lassen sich per API oder QR-Code verteilen. Die Download-Logik kann um Freigabezeitfenster erweitert werden.
3. **Tests & Validierung**: Neue Felder brauchen eventuell Frontend-Validierung; Dateiuploads sollten auf MIME-Type, Größe und erlaubte Endungen geprüft werden.
-4. **Deployment**: Docker Compose genügt lokal. In Produktion empfiehlt sich ein Reverse Proxy, HTTPS und regelmäßige Backups des MariaDB-Volumes (db_data). Auch www/files/ sollte gesichert werden, da dort alle Uploads gespeichert werden.
+4. **Deployment**: Docker Compose genügt lokal. In Produktion empfiehlt sich ein Reverse Proxy, HTTPS und regelmäßige Backups des MariaDB-Volumes (db_data). Auch www/_files/ sollte gesichert werden, da dort alle Uploads gespeichert werden.
> Hinweis: UUIDs repräsentieren digitale Visitenkarten und sind **einmalig**. Jeder Besuch über eine UUID dokumentiert genau eine Karte, deren Sichtbarkeit über Tokenrechte und Datei-Zuordnungen kontrolliert wird.
diff --git a/www/admin.php b/www/admin.php
index 8d246f7..a248594 100644
--- a/www/admin.php
+++ b/www/admin.php
@@ -287,7 +287,7 @@ if ($action === 'identity_edit') {
}
if ($filesInput && $hasSelection) {
- $uploadDir = __DIR__ . '/../files/';
+ $uploadDir = __DIR__ . '/_files/';
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
$fileUploadErrors[] = 'Upload-Verzeichnis kann nicht erstellt werden.';
} else {
diff --git a/www/download.php b/www/download.php
index 988f7b8..5009777 100644
--- a/www/download.php
+++ b/www/download.php
@@ -51,10 +51,10 @@ if (!$file) {
/**
* Dateipfad
*/
-$basePath = '/var/www/files/';
-$path = realpath($basePath . $file['stored_name']);
+$basePath = realpath(__DIR__ . '/_files');
+$path = $basePath ? realpath($basePath . '/' . $file['stored_name']) : null;
-if (!$path || !str_starts_with($path, $basePath) || !is_file($path)) {
+if (!$path || !$basePath || !str_starts_with($path, $basePath) || !is_file($path)) {
http_response_code(404);
exit('Datei fehlt');
}