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

PHP 刪除目錄的三種姿勢:遞歸、系統調用、迭代器對比與最佳實踐

     編輯:PHP 綜合知識

方法一:遞歸函數(經典、可控、跨平台)

<?php
/**
 * 遞歸刪除目錄及所有內容
 * @param string $dir 目錄路徑
 * @return bool
 */
function deleteDirRecursive(string $dir): bool {
    if (!is_dir($dir)) return false;
    
    $items = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST // 先刪子項,再刪父目錄
    );
    
    foreach ($items as $item) {
        if ($item->isDir()) {
            rmdir($item->getPathname());
        } else {
            unlink($item->getPathname());
        }
    }
    return rmdir($dir);
}

// 使用
deleteDirRecursive('/path/to/target_dir');

優點:純 PHP、跨平台、可注入日誌/鉤子、無命令注入風險。
缺點:超大目錄(萬級文件)可能超時/內存壓力。

方法二:系統命令調用(極速、有風險)

<?php
function deleteDirSystem(string $dir): bool {
    $dir = escapeshellarg($dir); // 必須轉義!
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        $cmd = "rmdir /s /q $dir";
    } else {
        $cmd = "rm -rf $dir";
    }
    exec($cmd, $output, $returnVar);
    return $returnVar === 0;
}

⚠️ 嚴重警告:

  • 命令注入:若 $dir 來自用戶輸入且未 escapeshellarg,可導致 rm -rf / 災難。
  • 依賴環境:Windows/Linux 命令不同,容器/最小系統可能無 rm/rmdir。
  • 權限:PHP-FPM 用戶需有執行權限及目錄寫入權。
  • 無回調:無法在刪除前後執行業務邏輯(如資料庫清理)。

建議:生產環境禁用,僅限受控 CLI 腳本、已知安全路徑。

方法三:SPL 迭代器(現代、優雅、內存友好)

<?php
function deleteDirSpl(string $dir): bool {
    if (!is_dir($dir)) return false;
    
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );
    
    foreach ($iterator as $file) {
        $path = $file->getPathname();
        $file->isDir() ? rmdir($path) : unlink($path);
    }
    return rmdir($dir);
}

// 進階:帶進度回調
function deleteDirWithProgress(string $dir, callable $onFileDelete = null): bool {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );
    foreach ($iterator as $file) {
        $path = $file->getPathname();
        if ($file->isDir()) {
            rmdir($path);
        } else {
            unlink($path);
            $onFileDelete?.($path);
        }
    }
    return rmdir($dir);
}

性能與選型建議

場景推薦方法理由
常規 Web 請求(<1000 文件)SPL 迭代器 / 遞歸函數安全、可控、純 PHP
超大目錄(萬級+)CLI 腳本 + SPL + ignore_user_abort + set_time_limit(0)避免 Web 超時,可分批、記錄進度
臨時目錄清理(已知安全路徑)系統命令(謹慎)極速,但需嚴格驗證路徑
需要事務性(刪文件+刷DB)SPL 迭代器 + 回調/事件可在循環中執行業務邏輯

刪除前必做的安全檢查

<?php
function safeDeleteDir(string $dir): bool {
    $realDir = realpath($dir);
    $allowedBase = realpath('/var/www/app/uploads'); // 業務允許的根目錄
    
    // 1. 路徑必須在允許範圍內
    if ($realDir === false || strpos($realDir, $allowedBase) !== 0) {
        error_log("非法刪除嘗試: $dir");
        return false;
    }
    // 2. 防止刪除關鍵目錄
    $protected = ['.', '..', '/', '/var', '/etc', '/home'];
    if (in_array($realDir, $protected, true)) return false;
    
    return deleteDirSpl($realDir);
}
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved