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

PHP 遞歸遍歷與刪除目錄下所有檔案:完整實現與安全考量

     編輯:PHP 綜合知識

遞歸處理目錄樹是檔案系統操作的核心技能。本文提供安全、健壯的目錄遍歷與刪除實現,涵蓋邊界條件處理、錯誤捕獲、效能優化。

遞歸刪除目錄完整實現

<?php
/**
 * 遞歸刪除目錄及其所有內容
 * @param string $path 目錄路徑
 * @return bool 成功返回 true
 */
function deleteDirectory(string $path): bool {
    // 1. 路徑標準化
    $path = rtrim($path, '/\\');
    
    // 2. 存在性檢查
    if (!file_exists($path)) {
        trigger_error("目錄不存在: $path", E_USER_WARNING);
        return false;
    }
    
    // 3. 確保是目錄
    if (!is_dir($path)) {
        trigger_error("路徑非目錄: $path", E_USER_WARNING);
        return false;
    }
    
    // 4. 讀取目錄內容 (排除 . 和 ..)
    $items = array_diff(scandir($path), ['.', '..']);
    
    // 5. 遞歸處理每個項目
    foreach ($items as $item) {
        $fullPath = $path . DIRECTORY_SEPARATOR . $item;
        
        if (is_file($fullPath) || is_link($fullPath)) {
            // 檔案或符號連結:直接刪除
            if (!unlink($fullPath)) {
                trigger_error("刪除檔案失敗: $fullPath", E_USER_WARNING);
                return false;
            }
        } elseif (is_dir($fullPath)) {
            // 子目錄:遞歸刪除
            if (!deleteDirectory($fullPath)) {
                return false; // 錯誤已在遞歸層觸發
            }
        }
    }
    
    // 6. 刪除空目錄本身
    return rmdir($path);
}

// 使用範例
deleteDirectory('/var/www/uploads/temp');
?>

遞歸遍歷目錄 (列出所有檔案)

<?php
/**
 * 遞歸遍歷目錄,返回所有檔案路徑
 * @param string $path 起始目錄
 * @param array $options 選項: ['recursive'=>true, 'pattern'=>'/*.php', 'full_path'=>true]
 * @return array 檔案路徑陣列
 */
function scanDirectory(string $path, array $options = []): array {
    $defaults = [
        'recursive' => true,
        'pattern' => null,      // glob 模式
        'full_path' => true,    // 返回完整路徑
        'skip_hidden' => true,  // 跳過隱藏檔
    ];
    $opts = array_merge($defaults, $options);
    
    $path = rtrim($path, '/\\');
    if (!is_dir($path)) return [];
    
    $files = [];
    $items = scandir($path);
    
    foreach ($items as $item) {
        if ($opts['skip_hidden'] && $item[0] === '.') continue;
        if ($item === '.' || $item === '..') continue;
        
        $fullPath = $path . DIRECTORY_SEPARATOR . $item;
        
        if (is_file($fullPath)) {
            if ($opts['pattern'] === null || fnmatch($opts['pattern'], $item)) {
                $files[] = $opts['full_path'] ? $fullPath : $item;
            }
        } elseif (is_dir($fullPath) && $opts['recursive']) {
            $files = array_merge($files, scanDirectory($fullPath, $opts));
        }
    }
    return $files;
}

// 使用範例
$phpFiles = scanDirectory('/var/www/project', ['pattern' => '*.php']);
print_r($phpFiles);
?>

現代化:RecursiveDirectoryIterator (SPL)

<?php
// 刪除目錄 (PHP 5.3+)
function deleteDirectorySPL(string $path): void {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST // 先刪除子項
    );
    foreach ($iterator as $item) {
        $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
    }
    rmdir($path);
}

// 遍歷列印
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/var/www', RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $file) {
    if ($file->isFile()) {
        echo $file->getPathname() . " ({$file->getSize()} bytes)\n";
    }
}
?>

效能與安全比較

方案優點缺點適用場景
自定義遞歸函數完全可控、相容舊版 PHP需自行處理邊界、效能一般教學、特殊邏輯、PHP < 5.3
SPL 迭代器內建優化、記憶體效率高、程式碼簡潔需 PHP 5.3+、行為固定生產環境首選、大目錄樹
系統命令 rm -rf極速、原子性安全風險極高、跨平台差異極謹慎的內部維護腳本

關鍵安全檢查清單

  1. ✅ 路徑標準化與遍歷攻擊防護 realpath() 驗證在允許根目錄下
  2. ✅ 符號連結處理:is_link() 避免跟隨連結刪除目標
  3. ✅ 權限檢查:is_writable() 預檢
  4. ✅ 錯誤處理:try-catch 包裹、詳細日誌
  5. ✅ 空目錄判斷:count(scandir()) === 2 (. 和 ..)
  6. ✅ 刪除確認機制:生產環境需二次確認或軟刪除

遞歸檔案操作威力巨大但風險同在,務必建立完善的測試用例、權限隔離與審計日誌,生產環境優先考慮軟刪除或備份後硬刪除。

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