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

PHP 遞迴掃描目錄取得所有檔案(支援副檔名過濾、Tree 結構回傳)

     編輯:PHP 綜合知識

專案常需「掃描上傳目錄產生檔案清單」、「遞迴刪除暫存檔」、「建立檔案索引」。本文提供一個健壯的 scan_dir() 函數,支援副檔名白名單過濾、自動跳過 ./..、回傳巢狀陣列(Tree 結構),並處理權限錯誤與空目錄。

函數完整實作

/**
 * 遞迴掃描目錄,回傳 Tree 結構陣列
 *
 * @param string $dir    絕對或相對路徑
 * @param array  $filter 允許的副檔名白名單(如 ['jpg','png','pdf']),空陣列=不過濾
 * @return array|false   結構化陣列,失敗回傳 false
 */
function scan_dir($dir, $filter = [])
{
    // 1. 基礎驗證
    if (!is_dir($dir) || !is_readable($dir)) {
        trigger_error("scan_dir: 目錄不存在或不可讀:$dir", E_USER_WARNING);
        return false;
    }

    // 2. 讀取項目並移除 . ..
    $items = array_diff(scandir($dir), ['.', '..']);
    if (empty($items)) return [];

    $result = [];
    foreach ($items as $item) {
        $path = $dir . DIRECTORY_SEPARATOR . $item;

        // 3. 子目錄 → 遞迴
        if (is_dir($path)) {
            $sub = scan_dir($path, $filter);
            if ($sub !== false) {
                $result[$item] = $sub; // 以目錄名為鍵,值為子樹
            }
            continue;
        }

        // 4. 檔案 → 副檔名過濾
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        if (!empty($filter) && !in_array($ext, $filter, true)) {
            continue; // 不在白名單,跳過
        }

        // 5. 檔案資訊(可擴充 size、mtime、mime 等)
        $result[] = [
            'name' => $item,
            'path' => $path,
            'ext'  => $ext,
            'size' => filesize($path),
            'time' => filemtime($path),
        ];
    }
    return $result;
}

使用範例

// 1. 掃描所有檔案(不過濾)
$all = scan_dir(__DIR__ . '/uploads');
print_r($all);

/*
Array
(
    [0] => Array ( [name]=>readme.txt [path]=>... [ext]=>txt [size]=>123 [time]=>1700000000 )
    [images] => Array
        (
            [0] => Array ( [name]=>photo.jpg [path]=>... [ext]=>jpg [size]=>45678 [time]=>1700000001 )
            [thumbs] => Array ( [0]=>Array(...) )
        )
)
*/

// 2. 只掃描圖片與 PDF
$docs = scan_dir('/var/www/files', ['jpg','png','gif','pdf']);

// 3. 扁平化輸出(遞迴展開)
function flatten_tree($tree, &$flat = [], $prefix = '')
{
    foreach ($tree as $key => $val) {
        if (is_int($key)) { // 檔案節點
            $val['full_path'] = $prefix . $val['name'];
            $flat[] = $val;
        } else { // 目錄節點
            flatten_tree($val, $flat, $prefix . $key . DIRECTORY_SEPARATOR);
        }
    }
    return $flat;
}

$flat = flatten_tree(scan_dir('/data', ['log']));
// $flat 為單層陣列,每筆含 full_path,適合直接寫入資料庫或 CSV

進階擴充建議

  • 迭代器版本:大目錄(>10 萬檔)建議改用 RecursiveDirectoryIterator + RecursiveIteratorIterator,避免遞迴呼叫堆疊溢位與記憶體峰值。
  • 非同步掃描:CLI 腳本搭配 pcntl_fork 或 symfony/process 多進程平行掃描。
  • 快取結果:將 Tree 結構 json_encode 存入 Redis/檔案,前端樹狀元件直接讀取,避免即時掃描阻塞請求。
  • 錯誤處理:生產環境建議將 trigger_error 改為拋出自訂例外 DirectoryScanException,統一由錯誤處理器記錄日誌。

效能基準(參考:SSD、10 萬檔、5 層深度)

  • 遞迴函數版:約 1.2 秒、峰值記憶體 45 MB
  • SPL 迭代器版:約 0.9 秒、峰值記憶體 12 MB(生成器模式)

根據專案規模選擇實作方式:中小型目錄直接用遞迴函數最簡潔;大型、高併發場景請升級為 SPL 迭代器 + 快取機制。

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