
本文介绍如何在 Laravel Artisan 命令中,基于目录名称(格式为 Y-m-d)精准识别并删除超过指定天数(如 50 天)的旧目录,避免字符串误比较,并确保路径解析与时间判断逻辑正确。
本文介绍如何在 laravel artisan 命令中,基于目录名称(格式为 y-m-d)精准识别并删除超过指定天数(如 50 天)的旧目录,避免字符串误比较,并确保路径解析与时间分析逻辑正确。
在 Laravel 中,若需清理以日期命名的目录(如 collections/2022-01-14),绝不可直接用字符串比较日期(例如 $directory ),因为字符串字典序比较无法等价于时间先后关系(如 <code>'2022-12-01' 成立,但 <code>'2022-10-01' 在字符串比较中反而为 <code>true,导致逻辑错误)。正确做法是提取目录名中的日期部分,解析为 Carbon 实例后进行时间比较。
以下是一个完整、健壮的 Artisan 命令实现示例:
<?php namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Carbon\Carbon;
class CleanupOldCollections extends Command
{
protected $signature = 'collections:cleanup {--days=50 : Number of days to retain}';
protected $description = 'Delete collection directories older than specified days';
public function handle()
{
$cutoffDate = now()->subDays((int) $this->option('days'));
collect(Storage::directories('collections/'))
->each(function ($fullPath) use ($cutoffDate) {
// 提取目录名(去除路径前缀),如 'collections/2022-01-14' → '2022-01-14'
$dirname = basename($fullPath);
// 验证是否符合 Y-m-d 格式(增强健壮性)
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $dirname)) {
$this->warn("Skipping invalid directory name: {$dirname}");
return;
}
try {
$dirDate = Carbon::parse($dirname);
if ($dirDate->lte($cutoffDate)) {
if (Storage::deleteDirectory($fullPath)) {
$this->info("Deleted outdated directory: {$fullPath}");
} else {
$this->error("Failed to delete: {$fullPath}");
}
}
} catch (\Exception $e) {
$this->error("Invalid date in directory '{$dirname}': " . $e->getMessage());
}
});
$this->info('Cleanup completed.');
}
}
✅ 关键要点说明:
- 使用
basename($fullPath)替代Str::after($fullPath, '/'),更可靠地获取目录名(避免多级路径干扰); - 添加正则校验和异常捕获,防止非标准目录名(如
collections/temp或格式错误的2022-1-1)引发崩溃; -
Carbon::parse($dirname)->lte($cutoffDate)确保语义准确:仅当目录日期 早于或等于 截止日期时才删除; -
Storage::deleteDirectory()返回布尔值,建议显式检查结果并记录日志,便于运维排查; - 支持通过
--days=30动态指定保留天数,提升命令复用性。
⚠️ 注意事项:
- 执行前务必在开发环境测试,并备份重要数据;
- 若使用
local以外的磁盘驱动(如s3),请确认deleteDirectory()是否支持该驱动(S3 不支持递归删除,需改用delete()遍历文件); - 生产环境建议添加确认提示(如
$this->confirm('Proceed with deletion?'))或启用--dry-run模式预览待删目录。
通过以上实现,你将获得一个可维护、可扩展且生产就绪的目录自动清理机制。











