From c608ed10cf5df1df0fcf87dfdc5ba624a4559f31 Mon Sep 17 00:00:00 2001 From: Andy Miller Date: Mon, 25 Aug 2025 13:27:23 +0100 Subject: [PATCH] implement a better purge strategy Signed-off-by: Andy Miller --- system/blueprints/config/system.yaml | 13 ++++++ system/config/system.yaml | 1 + system/src/Grav/Common/Cache.php | 69 ++++++++++++++++++++++++---- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index ac44f27b3..70ee08879 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -633,6 +633,19 @@ form: help: PLUGIN_ADMIN.CACHE_PREFIX_HELP placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER + cache.purge_max_age_days: + type: text + size: x-small + append: GRAV.NICETIME.DAY_PLURAL + label: PLUGIN_ADMIN.CACHE_PURGE_AGE + help: PLUGIN_ADMIN.CACHE_PURGE_AGE_HELP + validate: + type: number + min: 1 + max: 365 + step: 1 + default: 30 + cache.purge_at: type: cron label: PLUGIN_ADMIN.CACHE_PURGE_JOB diff --git a/system/config/system.yaml b/system/config/system.yaml index 30eabbfbe..984f46771 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -101,6 +101,7 @@ cache: clear_images_by_default: false # By default grav does not include processed images in cache clear, this can be enabled cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.) lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite) + purge_max_age_days: 30 # Maximum age of cache items in days before they are purged gzip: false # GZip compress the page output allow_webserver_gzip: false # If true, `content-encoding: identity` but connection isn't closed before `onShutDown()` event redis: diff --git a/system/src/Grav/Common/Cache.php b/system/src/Grav/Common/Cache.php index 6927c401c..c7afcbe55 100644 --- a/system/src/Grav/Common/Cache.php +++ b/system/src/Grav/Common/Cache.php @@ -170,24 +170,75 @@ class Cache extends Getters } /** - * Deletes the old out of date file-based caches + * Deletes old cache files based on age * * @return int */ public function purgeOldCache() { + // Get the max age for cache files from config (default 30 days) + $max_age_days = $this->config->get('system.cache.purge_max_age_days', 30); + $max_age_seconds = $max_age_days * 86400; // Convert days to seconds + $now = time(); + $count = 0; + + // First, clean up old orphaned cache directories (not the current one) $cache_dir = dirname($this->cache_dir); $current = Utils::basename($this->cache_dir); - $count = 0; - + foreach (new DirectoryIterator($cache_dir) as $file) { $dir = $file->getBasename(); if ($dir === $current || $file->isDot() || $file->isFile()) { continue; } - - Folder::delete($file->getPathname()); - $count++; + + // Check if directory is old and empty or very old (90+ days) + $dir_age = $now - $file->getMTime(); + if ($dir_age > 7776000) { // 90 days + Folder::delete($file->getPathname()); + $count++; + } + } + + // Now clean up old cache files within the current cache directory + if (is_dir($this->cache_dir)) { + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($this->cache_dir, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($iterator as $file) { + if ($file->isFile()) { + $file_age = $now - $file->getMTime(); + if ($file_age > $max_age_seconds) { + @unlink($file->getPathname()); + $count++; + } + } + } + } + + // Also clean up old files in compiled cache + $grav = Grav::instance(); + $compiled_dir = $this->config->get('system.cache.compiled_dir', 'cache://compiled'); + $compiled_path = $grav['locator']->findResource($compiled_dir, true); + + if ($compiled_path && is_dir($compiled_path)) { + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($compiled_path, \RecursiveDirectoryIterator::SKIP_DOTS), + \RecursiveIteratorIterator::CHILD_FIRST + ); + + foreach ($iterator as $file) { + if ($file->isFile()) { + $file_age = $now - $file->getMTime(); + // Compiled files can be kept longer (60 days) + if ($file_age > ($max_age_seconds * 2)) { + @unlink($file->getPathname()); + $count++; + } + } + } } return $count; @@ -632,8 +683,10 @@ class Cache extends Getters { /** @var Cache $cache */ $cache = Grav::instance()['cache']; - $deleted_folders = $cache->purgeOldCache(); - $msg = 'Purged ' . $deleted_folders . ' old cache folders...'; + $deleted_items = $cache->purgeOldCache(); + + $max_age = $cache->config->get('system.cache.purge_max_age_days', 30); + $msg = 'Purged ' . $deleted_items . ' old cache items (files older than ' . $max_age . ' days)'; if ($echo) { echo $msg;