#!/usr/bin/env php bold()->out('Cache Cleanup Tool'); $climate->br(); $cleanupDays = 0; try { $dotenv = Dotenv::createImmutable(__DIR__ . '/..'); $dotenv->load(); $climate->out('Environment variables loaded'); $cleanupDays = $_ENV['CLEANUP_DAYS']; } catch (\Exception $e) { $climate->yellow()->out('Warning: ' . $e->getMessage()); exit(0); } if (!defined('CACHE_DIR')) { define('CACHE_DIR', __DIR__ . '/../cache'); } if ($cleanupDays == 0) { $climate->yellow()->out('CLEANUP_DAYS variable not set or 0. No files will be cleaned.'); exit(0); } $cleanupDays = (int)$cleanupDays; if ($cleanupDays <= 0) { $climate->red()->out('CLEANUP_DAYS must be a positive integer. No files will be cleaned.'); exit(1); }; // Calculate the cutoff timestamp $cutoffTime = time() - ($cleanupDays * 86400); // Check if S3 cache is enabled $s3CacheEnabled = isset($_ENV['S3_CACHE_ENABLED']) && filter_var($_ENV['S3_CACHE_ENABLED'], FILTER_VALIDATE_BOOLEAN); if ($s3CacheEnabled) { // Clean S3 cache cleanS3Cache($climate, $cutoffTime, $cleanupDays); } else { // Clean local disk cache cleanDiskCache($climate, $cutoffTime, $cleanupDays); } /** * Clean cache files from S3 bucket * * @param CLImate $climate CLImate instance for output * @param int $cutoffTime Timestamp to use as cutoff for file age * @param int $cleanupDays Number of days to keep files */ function cleanS3Cache($climate, $cutoffTime, $cleanupDays) { $requiredVars = ['S3_ACCESS_KEY', 'S3_SECRET_KEY', 'S3_BUCKET']; foreach ($requiredVars as $var) { if (!isset($_ENV[$var]) || empty($_ENV[$var])) { $climate->red()->out("$var environment variable is required for S3 cache cleaning."); exit(1); } } $climate->out("S3 cache enabled. Cleaning S3 cache files older than {$cleanupDays} days..."); $clientConfig = [ 'version' => 'latest', 'region' => $_ENV['S3_REGION'] ?? 'us-east-1', 'credentials' => [ 'key' => $_ENV['S3_ACCESS_KEY'], 'secret' => $_ENV['S3_SECRET_KEY'], ] ]; if (!empty($_ENV['S3_ENDPOINT'])) { $clientConfig['endpoint'] = $_ENV['S3_ENDPOINT']; $clientConfig['use_path_style_endpoint'] = true; } try { $s3Client = new S3Client($clientConfig); $bucket = $_ENV['S3_BUCKET']; $prefix = $_ENV['S3_FOLDER'] ?? 'cache/'; $climate->out("Listing objects in bucket: {$bucket} with prefix: {$prefix}"); $objects = []; $marker = null; do { $params = [ 'Bucket' => $bucket, 'Prefix' => $prefix, 'MaxKeys' => 1000 ]; if ($marker) { $params['Marker'] = $marker; } $result = $s3Client->listObjects($params); if (isset($result['Contents'])) { foreach ($result['Contents'] as $object) { if (substr($object['Key'], -3) === '.gz') { $objects[] = $object; } } } $marker = $result['NextMarker'] ?? ($result['IsTruncated'] ? end($result['Contents'])['Key'] : null); } while ($marker); $totalObjects = count($objects); $climate->out("Found {$totalObjects} .gz objects in S3 bucket."); if ($totalObjects === 0) { $climate->out('No .gz objects found in S3 bucket.'); return; } $progress = $climate->progress()->total($totalObjects); $deletedObjects = 0; foreach ($objects as $index => $object) { $progress->current($index + 1); $lastModified = strtotime($object['LastModified']); if ($lastModified < $cutoffTime) { try { $s3Client->deleteObject([ 'Bucket' => $bucket, 'Key' => $object['Key'] ]); $deletedObjects++; } catch (AwsException $e) { $climate->red()->out("Failed to delete: " . $object['Key'] . " - " . $e->getMessage()); } } } $climate->br(); $climate->green()->out("S3 cleanup complete: {$deletedObjects} objects deleted."); } catch (AwsException $e) { $climate->red()->out("AWS Error: " . $e->getMessage()); exit(1); } } /** * Clean cache files from local disk * * @param CLImate $climate CLImate instance for output * @param int $cutoffTime Timestamp to use as cutoff for file age * @param int $cleanupDays Number of days to keep files */ function cleanDiskCache($climate, $cutoffTime, $cleanupDays) { $cacheDir = CACHE_DIR; $climate->out("Cleaning cache files older than {$cleanupDays} days from: {$cacheDir}"); if (!is_dir($cacheDir)) { $climate->red()->out("Cache directory not found: {$cacheDir}"); exit(1); } $gzFiles = glob($cacheDir . '/*.gz'); $totalFiles = count($gzFiles); $deletedFiles = 0; if ($totalFiles === 0) { $climate->out('No .gz files found in cache directory.'); return; } $climate->out("Found {$totalFiles} .gz files in cache directory."); $progress = $climate->progress()->total($totalFiles); foreach ($gzFiles as $index => $file) { $progress->current($index + 1); $fileTime = filemtime($file); if ($fileTime < $cutoffTime) { if (unlink($file)) { $deletedFiles++; } else { $climate->red()->out("Failed to delete: " . basename($file)); } } } $climate->br(); $climate->green()->out("Disk cleanup complete: {$deletedFiles} files deleted."); }