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

PHP 遞歸遍歷目錄與刪除非空資料夾完整實作

     編輯:PHP 相關知識

前言

PHP 內建 readdir() 僅能讀取單層目錄。本文提供兩個實用類別:DirLister 遞歸列出所有檔案與子目錄,DirRemover 安全刪除非空資料夾,並包含錯誤處理與輸出格式化。

DirLister:遞歸列出目錄樹

class DirLister {
    private $root_dir;
    private $depth = 0;
    private $file_list = [];
    private $output_html = '';

    public function __construct($dir) {
        $this->root_dir = rtrim($dir, '/\\');
    }

    // 回傳多維陣列:[深度][檔案名...] + 'directory' => 目錄路徑
    public function getList($dir = '') {
        $dir = $dir ?: $this->root_dir;
        $handle = @opendir($dir);
        if (!$handle) {
            throw new RuntimeException("無法開啟目錄: $dir");
        }

        while (false !== ($item = readdir($handle))) {
            if ($item === '.' || $item === '..') continue;
            $path = $dir . DIRECTORY_SEPARATOR . $item;

            if (is_dir($path)) {
                $this->depth++;
                $this->getList($path);
            } else {
                $this->file_list[$this->depth][] = $item;
            }
        }
        $this->file_list[$this->depth]['directory'] = $dir;
        $this->depth--;
        closedir($handle);
        return $this->file_list;
    }

    // 回傳 HTML 巢狀列表 (
  • ...) public function toHtml($dir = '') { $dir = $dir ?: $this->root_dir; $handle = @opendir($dir); if (!$handle) return ''; $this->output_html .= "
      \n"; $this->output_html .= "
    • Directory: " . htmlspecialchars($dir) . "
    • \n"; while (false !== ($item = readdir($handle))) { if ($item === '.' || $item === '..') continue; $path = $dir . DIRECTORY_SEPARATOR . $item; if (is_dir($path)) { $this->depth++; $this->toHtml($path); } else { $this->output_html .= "
    • " . htmlspecialchars($item) . "
    • \n"; } } $this->depth--; closedir($handle); $this->output_html .= "
    \n"; return $this->output_html; } } // 使用範例 $lister = new DirLister('jquery'); echo $lister->toHtml(); // 或取得陣列: print_r($lister->getList());

DirRemover:遞歸刪除非空資料夾

class DirRemover {
    public static function delete($dir) {
        $dir = rtrim($dir, '/\\');
        if (!is_dir($dir)) {
            throw new InvalidArgumentException("目錄不存在: $dir");
        }

        $handle = opendir($dir);
        while (false !== ($file = readdir($handle))) {
            if ($file === '.' || $file === '..') continue;
            $path = $dir . DIRECTORY_SEPARATOR . $file;

            if (is_dir($path)) {
                self::delete($path); // 遞歸刪除子目錄
            } else {
                if (@unlink($path)) {
                    echo "檔案刪除成功: $path
\n"; } else { echo "檔案刪除失敗: $path
\n"; } } } closedir($handle); if (@rmdir($dir)) { echo "目錄刪除成功: $dir
\n"; return true; } else { echo "目錄刪除失敗: $dir
\n"; return false; } } } // 使用範例 try { DirRemover::delete('/var/www/test'); } catch (Exception $e) { echo "錯誤: " . $e->getMessage(); }

現代化改良版 (SPL 迭代器)

PHP 5.3+ 內建 RecursiveDirectoryIterator + RecursiveIteratorIterator 更簡潔高效:

// 列出所有檔案 (含路徑)
$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/path/to/dir', RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::SELF_FIRST
);

foreach ($files as $file) {
    echo $file->isDir() ? "[DIR] " : "[FILE] ";
    echo $file->getPathname() . "\n";
}

// 刪除非空目錄 (需由最深層開始刪除,故用 CHILD_FIRST)
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/path/to/dir', RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::CHILD_FIRST
);

foreach ($iterator as $item) {
    $item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
}
rmdir('/path/to/dir'); // 最後刪除根目錄

效能與安全性比較

方法優點缺點適用場景
自訂遞歸函式邏輯可控、易加入業務邏輯深層目錄可能超出記憶體/堆疊限制需自訂輸出格式、權限檢查
SPL 迭代器內建優化、記憶體效率佳、程式碼極簡較難插入自訂邏輯、錯誤處理需額外 try-catch標準列出/刪除操作
系統指令 (exec rm -rf)速度最快、處理特殊權限安全風險極高、跨平台相容性差極大量檔案、容器環境、已驗證路徑安全

重要安全提醒

  • 路徑驗證:務必使用 realpath() 確認路徑在允許範圍內,防止目錄遍歷攻擊
  • 權限檢查:刪除前確認 PHP 進程擁有寫入權限
  • 避免硬編碼路徑:使用常數或配置檔管理根目錄
  • 大量檔案分批處理:超過萬檔案建議分批、加入 usleep() 避免阻塞
  • 記錄操作日誌:刪除操作務必記錄時間、操作者、目標路徑
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved