Files
michaelschiemer/docs/FILECACHE_PERMISSION_FIX_PLAN.md
Michael Schiemer 56f09b5001 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.
2025-11-03 23:54:27 +01:00

6.6 KiB

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

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:

// 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:

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

# 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

// 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

// 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