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

PHP 刪除目錄與檔案完整指南:遞迴刪除、條件清理與最佳實踐

     編輯:PHP 相關知識

前言

在 PHP 專案中,刪除目錄及其內部檔案是常見的檔案系統操作。由於 rmdir() 僅能刪除空目錄,開發者必須先遞迴清空子目錄與檔案。本文整理四種實用的刪除策略,從基礎遞迴到依時間條件清理,並提供生產環境可用的最佳實踐程式碼。

核心概念:遞迴刪除邏輯

所有目錄刪除函數的核心流程一致:

  1. 開啟目錄控制代碼 (opendir())
  2. 遍歷條目 (readdir()),跳過 . 與 ..
  3. 判斷類型:檔案用 unlink(),目錄遞迴呼叫自身
  4. 關閉控制代碼 (closedir())
  5. 最後刪除當前空目錄 (rmdir())

方案一:基礎遞迴函數 (修正版)

原始範例有語法錯誤 (雙層大括號、未使用變數),以下為修正並加入錯誤處理的版本:

<?php
/**
 * 遞迴刪除目錄及其內容
 * @param string $dir 目標目錄絕對路徑
 * @return bool 成功返回 true,失敗拋出異常
 */
function deleteDirectory(string $dir): bool {
    if (!is_dir($dir)) {
        throw new InvalidArgumentException("路徑不存在或非目錄: $dir");
    }

    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($items as $item) {
        if ($item->isFile()) {
            if (!unlink($item->getPathname())) {
                throw new RuntimeException("無法刪除檔案: {$item->getPathname()}");
            }
        } elseif ($item->isDir()) {
            if (!rmdir($item->getPathname())) {
                throw new RuntimeException("無法刪除子目錄: {$item->getPathname()}");
            }
        }
    }

    return rmdir($dir);
}

// 使用範例
try {
    deleteDirectory('/var/www/html/uploads/temp_123');
    echo '目錄刪除成功';
} catch (Exception $e) {
    error_log($e->getMessage());
    echo '刪除失敗: ' . $e->getMessage();
}
?>

優點:使用 SPL 迭代器,程式碼簡潔、自動處理遞迴順序 (CHILD_FIRST 先刪子項)。
注意:需 PHP 5.3+,大量檔案時記憶體佔用較高。

方案二:傳統遞迴函數 (相容舊版 PHP)

若專案運行於 PHP 5.2 或無法使用 SPL,可使用改良版傳統寫法:

<?php
function delDirTraditional(string $dir): bool {
    if (!is_dir($dir)) return false;

    $dh = opendir($dir);
    if (!$dh) return false;

    while (($file = readdir($dh)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $fullPath = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($fullPath)) {
            delDirTraditional($fullPath);
        } else {
            @unlink($fullPath); // 抑制警告,由最終結果判斷
        }
    }
    closedir($dh);
    return @rmdir($dir);
}
?>

方案三:增強版 - 支援檔案/目錄混合輸入

自動判斷傳入路徑是檔案還是目錄,統一刪除介面:

<?php
function removePath(string $path): bool {
    if (!file_exists($path)) return true; // 不存在視為成功

    if (is_file($path) || is_link($path)) {
        return unlink($path);
    }

    // 是目錄
    $items = scandir($path);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') continue;
        if (!removePath($path . DIRECTORY_SEPARATOR . $item)) {
            return false;
        }
    }
    return rmdir($path);
}
?>

方案四:依建立時間清理舊檔案 (適用快取/日誌目錄)

保留最近 N 天的檔案,自動清理過期項目:

<?php
/**
 * 清理指定目錄中超過 $days 天的檔案 (不刪除子目錄結構)
 * @param string $dir 目標目錄
 * @param int $days 保留天數
 * @return int 刪除的檔案數量
 */
function cleanOldFiles(string $dir, int $days = 30): int {
    if (!is_dir($dir)) return 0;

    $deleted = 0;
    $cutoff = time() - ($days * 86400);
    $files = new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS);

    foreach ($files as $file) {
        if ($file->isFile() && $file->getMTime() < $cutoff) {
            if (@unlink($file->getPathname())) {
                $deleted++;
            }
        }
    }
    return $deleted;
}

// 每日定時任務範例:清理 30 天前的上傳暫存檔
// cleanOldFiles('/var/www/html/uploads/tmp', 30);
?>

生產環境最佳實踐

場景建議方案關鍵注意事項
使用者上傳目錄定期清理方案四 + Cron Job僅刪除檔案保留目錄結構;記錄刪除日誌供稽核
暫存目錄完整移除方案一 (SPL)執行前檢查權限;大量檔案考慮分批處理避免超時
部署腳本清理舊版本方案三先備份重要資料;使用絕對路徑防止誤刪
高併發環境加入檔案鎖 (flock)防止多程序同時操作同一目錄導致競態條件

常見錯誤與除錯技巧

  • 權限不足:PHP-FPM 執行身份 (www-data) 需有目錄寫入權限,檢查 ls -la 與 chown。
  • 檔案被佔用:Linux 下用 lsof +D /path/to/dir 找出佔用進程。
  • 遞迴深度過大:極深目錄結構可能觸發 Maximum function nesting level,可調整 xdebug.max_nesting_level 或改用迭代器。
  • 符號連結風險:is_dir() 會跟隨連結,刪除時可能誤刪連結目標,建議加入 is_link() 判斷處理。

結語

PHP 刪除目錄看似簡單,實際部署需考慮權限、效能、錯誤處理與安全性。現代專案優先使用 SPL RecursiveIteratorIterator 方案,程式碼更健壯且符合 PSR 標準。舊專案可用傳統遞迴函數並加入 @ 抑制警告配合錯誤日誌。定期清理任務務必加入執行日誌與失敗通知機制,確保系統穩定運行。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved