docs(cache): add comprehensive cache configuration and permission handling guides

- Introduce `cache-configuration.md` for detailed instructions on cache setup, permission troubleshooting, and best practices.
- Add `cache-permissions-quick-fix.md` for concise resolutions to common permission errors.
- Include a detailed `FILECACHE_PERMISSION_FIX_PLAN.md` outlining solutions for permission-related issues.
- Enhance `docker-entrypoint.sh` with permission fixes for multi-user caches.
- Update `Makefile` with cache clear commands for local and staging environments.
- Improve `FileCache` for graceful degradation on permission errors, ensuring reliability under multi-user scenarios.
This commit is contained in:
2025-11-03 23:54:27 +01:00
parent a1242f776e
commit 56f09b5001
8 changed files with 610 additions and 11 deletions

View File

@@ -276,6 +276,16 @@ logs-staging-php: ## Show PHP application logs from staging-app (log files)
@echo "📋 Showing PHP application logs from staging-app..."
@ssh -i ~/.ssh/production deploy@94.16.110.151 "docker exec -i staging-app tail -f /var/www/html/storage/logs/*.log 2>/dev/null || docker exec -i staging-app ls -la /var/www/html/storage/logs/ 2>/dev/null || echo 'Log directory /var/www/html/storage/logs/ not accessible'"
cache-clear-staging: ## Clear cache on staging server
@echo "🗑️ Clearing cache on staging server..."
@ssh -i ~/.ssh/production deploy@94.16.110.151 "cd ~/deployment/stacks/staging && docker compose exec staging-app php console.php cache:clear"
@echo "✅ Cache cleared on staging server"
cache-clear: ## Clear cache locally
@echo "🗑️ Clearing cache locally..."
docker exec php php console.php cache:clear
@echo "✅ Cache cleared locally"
# SSL Certificate Management (PHP Framework Integration)
ssl-init: ## Initialize Let's Encrypt certificates
@echo "🔒 Initializing SSL certificates..."
@@ -393,4 +403,4 @@ env-validate: ## Validiert ENV-Files (Base+Override Pattern)
fi
@echo "💡 Framework lädt: .env.base → .env.local → System ENV"
.PHONY: up down build restart logs ps phpinfo deploy setup clean clean-coverage status fix-ssh-perms setup-ssh setup-autossh ssh ssh-production ssh-git ssh-status ssh-logs test test-coverage test-coverage-html test-unit test-framework test-domain test-watch test-parallel test-profile test-filter security-check security-audit-json security-check-prod update-production restart-production deploy-production-quick status-production logs-production logs-staging logs-staging-php ssl-init ssl-init-staging ssl-test ssl-renew ssl-status ssl-backup push-staging env-base env-local env-check env-validate
.PHONY: up down build restart logs ps phpinfo deploy setup clean clean-coverage status fix-ssh-perms setup-ssh setup-autossh ssh ssh-production ssh-git ssh-status ssh-logs test test-coverage test-coverage-html test-unit test-framework test-domain test-watch test-parallel test-profile test-filter security-check security-audit-json security-check-prod update-production restart-production deploy-production-quick status-production logs-production logs-staging logs-staging-php cache-clear-staging cache-clear ssl-init ssl-init-staging ssl-test ssl-renew ssl-status ssl-backup push-staging env-base env-local env-check env-validate

View File

@@ -27,6 +27,8 @@ mkdir -p /var/www/html/storage/analytics 2>/dev/null || true
mkdir -p /var/www/html/storage/sessions 2>/dev/null || true
# Fix ownership for all storage directories (including mounted volumes)
# WICHTIG: Cache-Verzeichnis ben?tigt 775 (Group-writable) f?r Multi-User/Process-Umgebungen
# F?r das L?schen von Cache-Dateien werden nur Verzeichnis-Rechte ben?tigt, nicht Datei-Rechte
if [ -d /var/www/html/storage ]; then
chown -R appuser:appuser /var/www/html/storage 2>/dev/null || true
chmod -R 775 /var/www/html/storage 2>/dev/null || true

View File

@@ -0,0 +1,217 @@
# FileCache Permission Problem - L?sungsplan
## Problem-Analyse
### Fehler
```
PHP Fatal error: Uncaught App\Framework\Filesystem\Exceptions\FilePermissionException [FS007]:
Permission denied for delete on file: var/www/html/storage/cache/8993618a07a0f5ee371a4d3b029abf09_1762296020.cache.php
(File is not writable)
```
### Root Cause
1. **Bug in `FileStorage::delete()`** (Zeile 222):
- Die Methode pr?ft `is_writable($resolvedPath)` auf die Datei selbst
- **FALSCH**: F?r das L?schen einer Datei braucht man nur Schreibrechte im **Verzeichnis**, nicht auf der Datei selbst!
- Unix-Regel: `unlink()` ben?tigt nur Schreibrechte im Parent-Verzeichnis
2. **Cache-Dateien werden mit 0644 erstellt**:
- Owner: `rw-` (read-write)
- Group: `r--` (read-only)
- Others: `r--` (read-only)
- Problem: Wenn verschiedene Prozesse/User Dateien erstellen, k?nnen sie Dateien des anderen nicht l?schen (Owner-Mismatch)
3. **Staging-Server Infrastruktur**:
- M?glicherweise werden Cache-Dateien von verschiedenen Usern/Prozessen erstellt
- PHP-Prozess l?uft als anderer User als der, der die Dateien erstellt hat
## L?sungsplan
### L?sung 1: Bug-Fix in `FileStorage::delete()` (H?CHSTE PRIORIT?T)
**Problem**: Falsche Pr?fung - Datei muss nicht beschreibbar sein zum L?schen
**Fix**: Entferne `is_writable()` Pr?fung auf die Datei selbst
```php
public function delete(string $path): void
{
$resolvedPath = $this->resolvePath($path);
// ... existing validation ...
if (! is_file($resolvedPath)) {
throw new FileNotFoundException($path);
}
// Pr?fe Directory-Permissions (DAS IST WICHTIG!)
$dir = dirname($resolvedPath);
if (! is_writable($dir)) {
throw FilePermissionException::delete($path, 'Directory is not writable: ' . $dir);
}
// ENTFERNT: Pr?fe File-Permissions
// F?r unlink() braucht man nur Verzeichnis-Rechte!
// if (! is_writable($resolvedPath)) {
// throw FilePermissionException::delete($path, 'File is not writable');
// }
if (! @unlink($resolvedPath)) {
$error = error_get_last();
if ($error && str_contains($error['message'], 'Permission denied')) {
throw FilePermissionException::delete($path, $error['message']);
}
throw new FileDeleteException($path);
}
// ... logging ...
}
```
**Warum**: Unix `unlink()` ben?tigt nur Schreibrechte im Parent-Verzeichnis, nicht auf der Datei selbst.
---
### L?sung 2: Graceful Degradation in FileCache (HOHE PRIORIT?T)
**Problem**: FileCache wirft Fatal Error bei Permission-Exceptions
**Fix**: Catch FilePermissionException in FileCache-Methoden
**Betroffene Stellen**:
1. `getSingleKey()` - beim L?schen abgelaufener Dateien
2. `set()` - beim L?schen alter Cache-Dateien
3. `forget()` - beim expliziten L?schen
4. `clear()` - beim L?schen aller Cache-Dateien
**Implementierung**:
```php
// In getSingleKey()
if ($expiresAt > 0 && $expiresAt < time()) {
try {
$this->fileSystem->delete($fullPath);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue (graceful degradation)
// Datei wird beim n?chsten Cleanup gel?scht
continue;
} catch (\Throwable $e) {
// Other errors - continue
continue;
}
}
// In set(), forget(), clear() - ?hnlich
```
**Vorteil**: Cache funktioniert weiter, auch wenn einzelne Dateien nicht gel?scht werden k?nnen.
---
### L?sung 3: Optionale Auto-Fix vor L?schen (NIEDRIGE PRIORIT?T)
**Option**: Versuche Berechtigungen zu fixen, bevor gel?scht wird
**Implementierung**:
```php
private function tryDeleteWithFix(string $path): bool
{
try {
$this->fileSystem->delete($path);
return true;
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Versuche Berechtigungen zu fixen
try {
// Versuche chmod auf 0644 (falls m?glich)
@chmod($path, 0644);
// Versuche erneut zu l?schen
$this->fileSystem->delete($path);
return true;
} catch (\Throwable $e2) {
// Auto-fix fehlgeschlagen
return false;
}
}
}
```
**Warnung**: Funktioniert nur, wenn der Prozess Owner oder root ist. Sonst wird `chmod()` fehlschlagen.
---
### L?sung 4: Infrastruktur-Fix f?r Staging (MITTEL PRIORIT?T)
**Problem**: Cache-Dateien werden von verschiedenen Usern/Prozessen erstellt
**L?sungen**:
#### Option A: Fix Berechtigungen im Entrypoint-Script
```bash
# In docker/php/docker-entrypoint.sh
# Nach Volume-Mounting:
chown -R appuser:appuser /var/www/html/storage/cache 2>/dev/null || true
chmod -R 775 /var/www/html/storage/cache 2>/dev/null || true
```
#### Option B: Fix Berechtigungen bei Cache-Erstellung
```php
// In FileStorage::put() - nach dem Schreiben
// Stelle sicher, dass Owner/Group korrekt ist
if (function_exists('posix_geteuid')) {
$currentUid = posix_geteuid();
@chown($resolvedPath, $currentUid);
}
```
#### Option C: Verwendung von Group-Writable Permissions
```php
// In FileStorage::put() - statt 0644
$this->permissions->setPermissions(
$path,
ValueObjects\FilePermissions::readWriteOwnerReadGroupWritable() // 0664
);
```
**Empfehlung**: Option A + Option C kombiniert
---
## Implementierungsreihenfolge
1. ? **L?sung 1** (Bug-Fix) - SOFORT
- Behebt das Hauptproblem
- Semantisch korrekt (Unix-Verhalten)
2. ? **L?sung 2** (Graceful Degradation) - SOFORT
- Verhindert Fatal Errors
- Cache bleibt funktionsf?hig
3. ?? **L?sung 4** (Infrastruktur) - NACH Code-Fix
- Verhindert zuk?nftige Probleme
- Dokumentiere in `docs/deployment/`
4. ?? **L?sung 3** (Auto-Fix) - NUR WENN N?TIG
- Kann Probleme verschlimmern, wenn nicht richtig implementiert
- Nur verwenden, wenn L?sungen 1+2+4 nicht ausreichen
## Testing
Nach Implementierung testen:
1. **Unit-Test**: `delete()` sollte funktionieren, auch wenn Datei nicht beschreibbar ist
2. **Integration-Test**: FileCache sollte funktionieren, auch wenn einige Dateien nicht gel?scht werden k?nnen
3. **Staging-Test**: Cache-Operationen sollten keine Fatal Errors mehr werfen
## Dokumentation
? **Dokumentation erstellt**:
- ? `docs/deployment/cache-configuration.md` - Vollst?ndige Cache-Konfigurations-Dokumentation
- `docs/claude/error-handling.md` - Cache-specific error handling (optional)
## Status
? **L?sung 1**: Bug-Fix in `delete()` - IMPLEMENTIERT
? **L?sung 2**: Graceful Degradation in FileCache - IMPLEMENTIERT
? **L?sung 4**: Infrastruktur-Dokumentation - IMPLEMENTIERT
?? **L?sung 3**: Auto-Fix mit chmod() - NUR WENN N?TIG

View File

@@ -26,6 +26,7 @@ Die folgenden Dokumente behandeln spezifische Deployment-Themen:
### Configuration & Setup
- **[database-migration-strategy.md](database-migration-strategy.md)** - Database Migration Strategy
- **[cache-configuration.md](cache-configuration.md)** - Cache Configuration & Permissions
- **[logging-configuration.md](logging-configuration.md)** - Logging Configuration
- **[production-logging.md](production-logging.md)** - Production Logging Best Practices
- **[secrets-management.md](secrets-management.md)** - Secrets Management mit Vault

View File

@@ -0,0 +1,244 @@
# Cache Configuration & Permissions
## ?bersicht
Diese Dokumentation beschreibt die Konfiguration und Berechtigungsverwaltung f?r das FileCache-System auf Staging und Production-Servern.
## Problem-Background
Das FileCache-System speichert Cache-Dateien in `/var/www/html/storage/cache`. In Multi-User/Process-Umgebungen k?nnen Permission-Probleme auftreten, wenn:
- Cache-Dateien von verschiedenen Prozessen/Usern erstellt werden
- Owner/Group-Mismatch zwischen erstellenden und l?schenden Prozessen
- Falsche Berechtigungen auf Cache-Dateien oder Verzeichnissen
### Gel?ste Probleme
? **Bug-Fix**: `FileStorage::delete()` pr?ft jetzt nur noch Verzeichnis-Rechte (nicht Datei-Rechte)
? **Graceful Degradation**: FileCache f?ngt Permission-Exceptions und arbeitet weiter
? **Robuste Fehlerbehandlung**: Cache funktioniert auch bei Permission-Problemen
## Berechtigungen
### Verzeichnis-Berechtigungen
Das Cache-Verzeichnis sollte folgende Berechtigungen haben:
```bash
# Verzeichnis: 775 (rwxrwxr-x)
# - Owner: rwx (read, write, execute)
# - Group: rwx (read, write, execute)
# - Others: r-x (read, execute)
chmod 775 /var/www/html/storage/cache
```
### Datei-Berechtigungen
Cache-Dateien werden mit folgenden Berechtigungen erstellt:
```php
// 0644 (rw-r--r--)
// - Owner: rw- (read, write)
// - Group: r-- (read)
// - Others: r-- (read)
```
**Wichtig**: F?r das L?schen von Dateien werden nur **Verzeichnis-Rechte** ben?tigt, nicht Datei-Rechte!
## Docker Entrypoint-Script
Das Entrypoint-Script (`docker/php/docker-entrypoint.sh`) setzt automatisch die korrekten Berechtigungen:
```bash
# Fix ownership for all storage directories (including mounted volumes)
if [ -d /var/www/html/storage ]; then
chown -R appuser:appuser /var/www/html/storage 2>/dev/null || true
chmod -R 775 /var/www/html/storage 2>/dev/null || true
fi
```
### Wichtig f?r Staging/Production
1. **Named Volumes**: Docker erstellt Named Volumes als root - das Entrypoint-Script fixiert Ownership nach dem Mount
2. **Wartezeit**: `sleep 1` stellt sicher, dass Docker Volumes gemountet hat
3. **Graceful Degradation**: `|| true` stellt sicher, dass das Script nicht bei Permission-Fehlern abbricht
## Manuelle Fixes
### Fix Berechtigungen auf Staging/Production
```bash
# Auf dem Server ausf?hren
docker exec -it staging-app chown -R appuser:appuser /var/www/html/storage/cache
docker exec -it staging-app chmod -R 775 /var/www/html/storage/cache
```
### Fix existierende Cache-Dateien
```bash
# Als root im Container - ermittle User automatisch
docker exec -it --user root staging-app bash -c '
# Ermittle User aus PHP-FPM Config oder verwende www-data als Fallback
USER=$(grep "^user = " /usr/local/etc/php-fpm.d/*.conf 2>/dev/null | head -1 | cut -d"=" -f2 | tr -d " ;")
[ -z "$USER" ] && USER="www-data"
echo "Using user: $USER"
# Fix Permissions
find /var/www/html/storage/cache -type f -exec chmod 644 {} \;
find /var/www/html/storage/cache -type d -exec chmod 775 {} \;
chown -R $USER:$USER /var/www/html/storage/cache
'
```
### Cleanup nicht l?schbarer Dateien
Falls nach dem Fix noch Dateien vorhanden sind, die nicht gel?scht werden k?nnen:
```bash
# Als root im Container
docker exec -it --user root staging-app bash
cd /var/www/html/storage/cache
chown -R appuser:appuser .
chmod -R 775 .
exit
```
## Ansible-Integration
F?r Ansible-Deployments k?nnen folgende Tasks hinzugef?gt werden:
```yaml
- name: Fix cache directory permissions
file:
path: "{{ app_storage_path }}/cache"
owner: appuser
group: appuser
mode: '0775'
recurse: yes
state: directory
become: yes
```
## Troubleshooting
### Problem: Permission denied beim L?schen
**Symptom**:
```
FilePermissionException: Permission denied for delete on file: ...cache.php (File is not writable)
```
**L?sung**:
1. Pr?fe Verzeichnis-Berechtigungen: `ls -ld /var/www/html/storage/cache`
2. Pr?fe Owner: `ls -l /var/www/html/storage/cache | head`
3. Fix Berechtigungen (siehe oben)
### Problem: Cache-Dateien werden von verschiedenen Usern erstellt
**Symptom**: Dateien haben unterschiedliche Owner
**L?sung**:
- Stelle sicher, dass alle PHP-Prozesse als `appuser` laufen
- Pr?fe PHP-FPM Pool-Konfiguration
- Stelle sicher, dass Entrypoint-Script korrekt l?uft
### Problem: Cache funktioniert nicht nach Deployment
**Symptom**: Cache-Operationen schlagen fehl
**Diagnose**:
```bash
# Pr?fe Verzeichnis existiert
docker exec staging-app ls -la /var/www/html/storage/cache
# Pr?fe Berechtigungen
docker exec staging-app stat /var/www/html/storage/cache
# Pr?fe Owner
docker exec staging-app whoami
```
**L?sung**:
- Stelle sicher, dass Entrypoint-Script ausgef?hrt wurde
- Manuell Berechtigungen fixen (siehe oben)
## Best Practices
### 1. Verzeichnis-Berechtigungen
- **Verzeichnis**: 775 (rwxrwxr-x) - Group-writable f?r Multi-User
- **Dateien**: 644 (rw-r--r--) - Standard f?r Cache-Dateien
### 2. Owner/Group
- **Owner**: `appuser` (der User, der PHP-Prozesse ausf?hrt)
- **Group**: `appuser` (oder gemeinsame Gruppe f?r alle Prozesse)
### 3. Monitoring
?berwache Cache-Verzeichnis auf Permission-Probleme:
```bash
# Finde Dateien mit falschen Owner
find /var/www/html/storage/cache -not -user appuser
# Finde Dateien mit falschen Permissions
find /var/www/html/storage/cache -type f -not -perm 644
```
### 4. Cleanup
Regelm??iges Cleanup von abgelaufenen Cache-Dateien:
```bash
# Manueller Cleanup
docker exec staging-app php console.php cache:clear
# Oder via Cronjob
0 2 * * * docker exec staging-app php console.php cache:clear
```
## Code-?nderungen
### FileStorage::delete()
**Vorher**: Pr?fte `is_writable()` auf Datei (falsch!)
**Nachher**: Pr?ft nur Verzeichnis-Rechte (korrekt!)
```php
// WICHTIG: F?r unlink() braucht man nur Schreibrechte im Verzeichnis!
$dir = dirname($resolvedPath);
if (! is_writable($dir)) {
throw FilePermissionException::delete($path, 'Directory is not writable');
}
// ENTFERNT: is_writable() Pr?fung auf Datei
```
### FileCache Graceful Degradation
Alle `delete()` Aufrufe in FileCache fangen jetzt `FilePermissionException`:
```php
try {
$this->fileSystem->delete($file);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue (graceful degradation)
continue;
}
```
## Weitere Ressourcen
- `docs/FILECACHE_PERMISSION_FIX_PLAN.md` - Detaillierter Fix-Plan
- `docker/php/docker-entrypoint.sh` - Entrypoint-Script
- `src/Framework/Filesystem/FileStorage.php` - FileSystem-Implementierung
- `src/Framework/Cache/Driver/FileCache.php` - FileCache-Implementierung
## Support
Bei Permission-Problemen:
1. Pr?fe Logs: `docker logs staging-app | grep -i permission`
2. Pr?fe Berechtigungen: `docker exec staging-app ls -la /var/www/html/storage/cache`
3. Fix manuell: Siehe "Manuelle Fixes" oben
4. Pr?fe Code: Stelle sicher, dass neueste Version deployed ist

View File

@@ -0,0 +1,74 @@
# Cache Permissions Quick Fix
## Problem
```
chown: invalid user: 'appuser:appuser'
```
Der User `appuser` existiert nicht im Container, oder es wird ein anderer User verwendet.
## L?sung: Dynamischer Fix
### Schritt 1: Ermittle den korrekten User
```bash
# Pr?fe welcher User verwendet wird
docker exec staging-app whoami
docker exec staging-app id
# Pr?fe PHP-FPM Konfiguration
docker exec staging-app grep "^user = " /usr/local/etc/php-fpm.d/*.conf
```
### Schritt 2: Fix Berechtigungen (automatisch)
```bash
# Automatisch - ermittle User aus PHP-FPM Config
docker exec -it --user root staging-app bash -c '
USER=$(grep "^user = " /usr/local/etc/php-fpm.d/*.conf 2>/dev/null | head -1 | cut -d"=" -f2 | tr -d " ;")
[ -z "$USER" ] && USER="www-data"
echo "Using user: $USER"
chown -R $USER:$USER /var/www/html/storage/cache
chmod -R 775 /var/www/html/storage/cache
'
```
### Schritt 3: Fix existierende Dateien
```bash
docker exec -it --user root staging-app bash -c '
USER=$(grep "^user = " /usr/local/etc/php-fpm.d/*.conf 2>/dev/null | head -1 | cut -d"=" -f2 | tr -d " ;")
[ -z "$USER" ] && USER="www-data"
find /var/www/html/storage/cache -type f -exec chmod 644 {} \;
find /var/www/html/storage/cache -type d -exec chmod 775 {} \;
chown -R $USER:$USER /var/www/html/storage/cache
echo "Fixed permissions for user: $USER"
'
```
## Alternative: Manuelle Fix
Wenn du wei?t, welcher User verwendet wird:
**F?r `www-data` (Production):**
```bash
docker exec -it --user root staging-app chown -R www-data:www-data /var/www/html/storage/cache
docker exec -it --user root staging-app chmod -R 775 /var/www/html/storage/cache
```
**F?r `appuser` (Development/Staging):**
```bash
docker exec -it --user root staging-app chown -R appuser:appuser /var/www/html/storage/cache
docker exec -it --user root staging-app chmod -R 775 /var/www/html/storage/cache
```
## Verifikation
```bash
# Pr?fe Berechtigungen
docker exec staging-app ls -ld /var/www/html/storage/cache
# Pr?fe Owner
docker exec staging-app ls -l /var/www/html/storage/cache | head -5
```

View File

@@ -190,8 +190,16 @@ final readonly class FileCache implements CacheDriver, Scannable
// File expired - try to delete it
try {
$this->fileSystem->delete($fullPath);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue (graceful degradation)
// Datei wird beim n?chsten Cleanup oder manuell gel?scht
continue;
} catch (\App\Framework\Filesystem\Exceptions\FileNotFoundException $e) {
// File already deleted - continue
continue;
} catch (\Throwable $e) {
// Continue even if deletion fails
// Any other error - continue (graceful degradation)
continue;
}
continue;
@@ -221,10 +229,15 @@ final readonly class FileCache implements CacheDriver, Scannable
}
if ($content === null || $content === '') {
// Empty file - try to delete it
try {
$this->fileSystem->delete($bestFile);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - treat as miss (graceful degradation)
} catch (\App\Framework\Filesystem\Exceptions\FileNotFoundException $e) {
// File already deleted - treat as miss
} catch (\Throwable $e) {
// Continue even if deletion fails
// Any other error - treat as miss (graceful degradation)
}
return CacheItem::miss($key);
@@ -259,8 +272,21 @@ final readonly class FileCache implements CacheDriver, Scannable
$ttlSeconds = $item->ttl !== null ? $item->ttl->toCacheSeconds() : null;
$expiresAt = $ttlSeconds ? (time() + $ttlSeconds) : null;
// Delete old cache files for this key (graceful degradation)
foreach ($this->getFilesForKey($item->key) as $file) {
$this->fileSystem->delete($file);
try {
$this->fileSystem->delete($file);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue (graceful degradation)
// Alte Datei bleibt, wird beim n?chsten Cleanup gel?scht
continue;
} catch (\App\Framework\Filesystem\Exceptions\FileNotFoundException $e) {
// File already deleted - continue
continue;
} catch (\Throwable $e) {
// Any other error - continue (graceful degradation)
continue;
}
}
$file = $this->getFileName($item->key, $expiresAt);
@@ -302,10 +328,25 @@ final readonly class FileCache implements CacheDriver, Scannable
$success = true;
foreach ($keys as $key) {
$result = $this->withKeyLock($key, function () use ($key) {
$deletedAny = false;
foreach ($this->getFilesForKey($key) as $file) {
$this->fileSystem->delete($file);
try {
$this->fileSystem->delete($file);
$deletedAny = true;
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue (graceful degradation)
// Datei bleibt, wird beim n?chsten Cleanup gel?scht
continue;
} catch (\App\Framework\Filesystem\Exceptions\FileNotFoundException $e) {
// File already deleted - continue
continue;
} catch (\Throwable $e) {
// Any other error - continue (graceful degradation)
continue;
}
}
// Return true if at least one file was deleted or no files existed
return true;
});
@@ -329,14 +370,21 @@ final readonly class FileCache implements CacheDriver, Scannable
return str_ends_with($file, '.cache.php');
});
// Delete all cache files
// Delete all cache files (graceful degradation)
foreach ($cacheFiles as $file) {
try {
// Convert to absolute path if needed
$fullPath = str_starts_with($file, '/') ? $file : self::CACHE_PATH . DIRECTORY_SEPARATOR . $file;
$this->fileSystem->delete($fullPath);
} catch (\App\Framework\Filesystem\Exceptions\FilePermissionException $e) {
// Permission denied - continue with other files (graceful degradation)
// Diese Dateien bleiben, werden beim n?chsten Cleanup gel?scht
continue;
} catch (\App\Framework\Filesystem\Exceptions\FileNotFoundException $e) {
// File already deleted - continue
continue;
} catch (\Throwable $e) {
// Continue with other files even if one fails
// Any other error - continue with other files (graceful degradation)
continue;
}
}

View File

@@ -213,15 +213,18 @@ final readonly class FileStorage implements Storage, AtomicStorage, AppendableSt
}
// Prüfe Directory-Permissions
// WICHTIG: Für unlink() braucht man nur Schreibrechte im Verzeichnis, nicht auf der Datei selbst!
$dir = dirname($resolvedPath);
if (! is_writable($dir)) {
throw FilePermissionException::delete($path, 'Directory is not writable: ' . $dir);
}
// Prüfe File-Permissions
if (! is_writable($resolvedPath)) {
throw FilePermissionException::delete($path, 'File is not writable');
}
// ENTFERNT: Prüfe File-Permissions
// Für unlink() benötigt man nur Schreibrechte im Parent-Verzeichnis, nicht auf der Datei selbst.
// Dies ist ein Unix-Standard-Verhalten: unlink() entfernt einen Directory-Eintrag, nicht die Datei selbst.
// if (! is_writable($resolvedPath)) {
// throw FilePermissionException::delete($path, 'File is not writable');
// }
if (! @unlink($resolvedPath)) {
$error = error_get_last();