首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 刪除目錄下 N 分鐘前建立的檔案:完整實作與效能優化

     編輯:PHP 綜合知識

核心函式:支援遞迴、排除、大目錄

<?php
/**
 * 刪除目錄中建立/修改時間超過 N 分鐘的檔案
 *
 * @param string $dir      目標目錄 (絕對路徑)
 * @param int    $minutes  分鐘閾值
 * @param bool   $recursive 是否遞迴子目錄
 * @param array  $exclude  排除的檔名/副檔名 (如 ['.gitignore', '.log'])
 * @return int 刪除的檔案數
 */
function deleteOldFiles(string $dir, int $minutes, bool $recursive = false, array $exclude = []): int {
    $dir = rtrim(realpath($dir), DIRECTORY_SEPARATOR);
    if (!$dir || !is_dir($dir)) {
        throw new InvalidArgumentException("Directory not found: $dir");
    }

    $cutoff = time() - $minutes * 60;
    $deleted = 0;
    $flags = FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS;
    $iterator = $recursive
        ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, $flags), RecursiveIteratorIterator::CHILD_FIRST)
        : new FilesystemIterator($dir, $flags);

    foreach ($iterator as $file) {
        if (!$file->isFile()) continue;

        // 排除檢查
        $name = $file->getFilename();
        if (in_array($name, $exclude, true)) continue;
        $ext = $file->getExtension();
        if ($ext && in_array($ext, $exclude, true)) continue;

        // 時間判斷:使用 mtime (內容修改時間),ctime (inode 變更) 視需求選擇
        if ($file->getMTime() < $cutoff) {
            if (@unlink($file->getPathname())) {
                $deleted++;
            } else {
                error_log("Delete failed: {$file->getPathname()}");
            }
        }
    }
    return $deleted;
}

// 使用範例
$count = deleteOldFiles('/var/www/uploads/temp', 30, true, ['.gitkeep', 'lock']);
echo "已刪除 $count 個 30 分鐘前的暫存檔\n";

關鍵設計決策解析

選項建議值理由
時間基準getMTime() (修改時間)上傳/寫入完成即更新;getCTime() 受權限變更影響,getATime() 系統常關閉
迭代器FilesystemIterator / RecursiveDirectoryIteratorSPL 原生、記憶體效率高、自動跳過 . ..
遞迴順序CHILD_FIRST先刪檔案再刪目錄(若需清空目錄),避免「目錄非空」錯誤
錯誤處理@unlink() + error_log()單檔失敗不中斷整體,記錄供事後審計
路徑處理realpath() + rtrim(..., DIRECTORY_SEPARATOR)統一分隔符、解析符號連結、防目錄遍歷

進階:定時任務部署

Linux Cron (每 5 分鐘執行)

# /etc/cron.d/cleanup-temp
*/5 * * * * www-data /usr/bin/php /var/www/scripts/cleanup.php >> /var/log/cleanup.log 2>&1
<?php
// cleanup.php
require_once __DIR__ . '/../vendor/autoload.php';
$dirs = [
    '/var/www/uploads/temp' => 30,
    '/var/www/cache' => 60,
    '/tmp/php_sessions' => 1440, // 24h
];
foreach ($dirs as $dir => $min) {
    try {
        $n = deleteOldFiles($dir, $min, true);
        echo "[OK] $dir: deleted $n files\n";
    } catch (Throwable $e) {
        echo "[ERR] $dir: " . $e->getMessage() . "\n";
    }
}

Windows 任務排程器

  1. 建立基本任務 → 觸發:每日重複每 5 分鐘
  2. 動作:啟動程式 php.exe,參數 C:\www\scripts\cleanup.php
  3. 勾選「使用最高權限執行」

大目錄效能優化 (10 萬+ 檔案)

<?php
// 1. 分批處理,避免長時間佔用 CPU/IO
function deleteOldFilesBatched(string $dir, int $minutes, int $batchSize = 500): int {
    $cutoff = time() - $minutes * 60;
    $deleted = 0;
    $iterator = new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS);
    $batch = [];

    foreach ($iterator as $file) {
        if (!$file->isFile() || $file->getMTime() >= $cutoff) continue;
        $batch[] = $file->getPathname();
        if (count($batch) >= $batchSize) {
            $deleted += unlinkBatch($batch);
            $batch = [];
            usleep(10000); // 10ms 讓出 CPU
        }
    }
    if ($batch) $deleted += unlinkBatch($batch);
    return $deleted;
}

function unlinkBatch(array $paths): int {
    $count = 0;
    foreach ($paths as $p) { if (@unlink($p)) $count++; }
    return $count;
}

// 2. 極大目錄改用 find + xargs (系統層面最快)
/*
find /var/www/uploads/temp -type f -mmin +30 -print0 | xargs -0 -r -P4 rm -f
# -P4 並行 4 條刪除
*/

替代方案對比

方案優點缺點適用場景
PHP SPL 迭代器跨平台、可嵌入業務邏輯、易測試大量檔案較慢中小目錄、需業務判斷
shell_exec('find ...')極快、系統原生依賴 Linux、注入風險、難除錯超大目錄、純清理無業務邏輯
系統 tmpwatch / systemd-tmpfiles宣告式、開機自動、標準化僅限臨時目錄、靈活度低/tmp、/var/tmp、快取目錄
Redis 掃描 Key TTL記憶體級、無檔案系統開銷需資料在 RedisSession、Token、暫存資料

安全與審計建議

  • ✅ **白名單目錄**:僅允許預設清單目錄,禁止動態傳入 $dir
  • ✅ **最小權限**:執行腳本的用戶僅擁有目標目錄 rwx,無 sudo
  • ✅ **刪除日誌**:記錄 檔案路徑、mtime、刪除時間、執行 PID
  • ✅ **乾跑模式**:上線前加 $dryRun 參數只列印不刪除
  • ✅ **保護關鍵檔**:$exclude = ['.gitkeep', '.htaccess', 'index.php', 'config.php']
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved