sessions($limit), $this->updateFolders($limit), $this->logs(), ); // Bildvarianten im öffentlichen Abbild, deren Bild es nicht mehr gibt. $verwaist = $this->mirror?->prune() ?? 0; return 0 === $verwaist ? $bericht : $bericht.sprintf(' %d verwaiste Bilddatei(en) aus public/media entfernt.', $verwaist); } /** Sitzungsdateien. Der Garbage Collector von PHP ist auf vielen Hostings abgeschaltet. */ private function sessions(int $limit): int { $removed = 0; foreach (glob($this->projectDir.'/var/sessions/*/sess_*') ?: [] as $file) { if (is_file($file) && (int) @filemtime($file) < $limit && @unlink($file)) { ++$removed; } } return $removed; } /** * Die Arbeitsordner des Archiv-Updates. * * Der jüngste ist der Rückweg aus dem letzten Update, und den lässt diese Aufgabe einen * Monat lang stehen. Wartet ein Update noch auf seinen zweiten Schritt, wird gar nichts * angefasst: dann ist einer dieser Ordner der Stand, auf den zurückgegangen wird. */ private function updateFolders(int $limit): int { if (is_file($this->projectDir.'/'.ArchiveUpdate::MARKE)) { return 0; } $removed = 0; foreach (glob($this->projectDir.'/var/update/*', GLOB_ONLYDIR) ?: [] as $folder) { if ((int) @filemtime($folder) < $limit && $this->removeDirectory($folder)) { ++$removed; } } return $removed; } private function logs(): int { $shortened = 0; foreach ([Updater::LOG_FILE, Scheduler::LOG_FILE] as $relative) { $file = $this->projectDir.'/'.$relative; $raw = @file_get_contents($file); if (!is_string($raw)) { continue; } $lines = array_values(array_filter(explode("\n", $raw))); if (count($lines) <= self::KEEP_LINES) { continue; } if (false !== @file_put_contents($file, implode("\n", array_slice($lines, -self::KEEP_LINES))."\n", LOCK_EX)) { ++$shortened; } } return $shortened; } /** Rekursiv löschen, aber nur unterhalb von `var/` – geprüft, nicht angenommen. */ private function removeDirectory(string $path): bool { $real = realpath($path); $var = realpath($this->projectDir.'/var'); if (false === $real || false === $var || !str_starts_with($real, $var.DIRECTORY_SEPARATOR)) { return false; } $items = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator($real, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST, ); foreach ($items as $item) { $item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname()); } return @rmdir($real); } }