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

PHP 遞迴掃描目錄樹狀輸出完整範例

     編輯:PHP 相關知識

需求

將指定目錄下所有檔案與子目錄以樹狀結構 (UL/LI) 輸出,支援無限層級遞迴。

完整程式碼

<?php
function listDirTree($path) {
    // 切換工作目錄,確保相對路徑正確
    chdir($path);
    
    $dir = dir($path);
    echo $dir->path . "<br> ";
    echo "<ul style='font-size:9pt;'>";
    
    while (($entry = $dir->read()) !== false) {
        if ($entry === '.' || $entry === '..') continue;
        
        $lastModified = filemtime($entry);
        echo "<li>";
        
        // 判斷目錄/檔案顯示不同圖示
        if (is_dir($entry)) {
            echo "<img src='folder.gif' alt=''>" . $entry;
        } else {
            echo "<img src='file.gif' alt=''>" . $entry;
        }
        
        echo " --- " . date("Y/m/d H:i:s", $lastModified);
        
        // 遞迴處理子目錄
        if (is_dir($path . "/" . $entry)) {
            listDirTree($path . "/" . $entry);
        }
        echo "</li>";
    }
    
    $dir->close();
    echo "</ul>";
}

// 使用範例
$rootPath = "c:/"; // Windows 路徑
echo $rootPath;
listDirTree($rootPath);
?>

改良版:分離邏輯與輸出、支援自訂圖示、最大深度

<?php
function scanDirTree($path, $maxDepth = -1, $currentDepth = 0, $icons = []) {
    $defaultIcons = [
        'dir'  => '📁',
        'file' => '📄',
    ];
    $icons = array_merge($defaultIcons, $icons);
    
    if ($maxDepth >= 0 && $currentDepth > $maxDepth) return '';
    
    $path = rtrim($path, '/\\');
    if (!is_dir($path)) return '';
    
    $html = '';
    if ($currentDepth === 0) {
        $html .= "<ul class='dir-tree'>";
    } else {
        $html .= "<ul>";
    }
    
    $items = scandir($path);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') continue;
        
        $fullPath = $path . DIRECTORY_SEPARATOR . $item;
        $isDir = is_dir($fullPath);
        $icon = $isDir ? $icons['dir'] : $icons['file'];
        $mtime = date('Y-m-d H:i:s', filemtime($fullPath));
        
        $html .= "<li>";
        $html .= "<span class='icon'>$icon</span>";
        $html .= "<span class='name'>" . htmlspecialchars($item) . "</span>";
        $html .= "<span class='meta'>$mtime</span>";
        
        if ($isDir) {
            $html .= scanDirTree($fullPath, $maxDepth, $currentDepth + 1, $icons);
        }
        $html .= "</li>";
    }
    
    $html .= "</ul>";
    return $html;
}

// CSS 樣式
echo "<style>
.dir-tree { margin: 0; padding-left: 20px; list-style: none; font-family: monospace; }
.dir-tree li { margin: 2px 0; }
.dir-tree .icon { margin-right: 6px; }
.dir-tree .meta { color: #666; font-size: 0.85em; margin-left: 10px; }
</style>";

// 使用
echo scanDirTree(__DIR__, 3, 0, ['dir' => '📂', 'file' => '📄']);
?>

現代寫法:RecursiveDirectoryIterator (PHP 5.3+)

<?php
function scanDirModern($path, $maxDepth = -1) {
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );
    
    if ($maxDepth >= 0) {
        $iterator = new LimitIterator($iterator, 0, PHP_INT_MAX); // 配合深度需自行過濾
    }
    
    $html = "<ul class='dir-tree'>";
    $prevDepth = -1;
    
    foreach ($iterator as $file) {
        $depth = $iterator->getDepth();
        if ($maxDepth >= 0 && $depth > $maxDepth) continue;
        
        // 關閉上一層 UL
        while ($prevDepth >= $depth) {
            $html .= "</ul></li>";
            $prevDepth--;
        }
        
        $html .= "<li>";
        $html .= $file->isDir() ? "📂 " : "📄 ";
        $html .= htmlspecialchars($file->getBasename());
        $html .= " <small>(" . date('Y-m-d H:i:s', $file->getMTime()) . ")</small>";
        
        if ($file->isDir()) {
            $html .= "<ul>";
        } else {
            $html .= "</li>";
        }
        $prevDepth = $depth;
    }
    
    // 關閉剩餘 UL
    while ($prevDepth >= 0) {
        $html .= "</ul></li>";
        $prevDepth--;
    }
    $html .= "</ul>";
    return $html;
}
?>

效能與安全提醒

  • 大量檔案:避免一次輸出超大 HTML,考慮分頁、AJAX 懶加載、或僅輸出 JSON 供前端樹狀元件渲染。
  • 符號連結:is_dir() 會跟隨連結,可能導致無限遞迴。使用 $file->isLink() (SPL) 或 is_link() 排除。
  • 權限錯誤:scandir()/RecursiveDirectoryIterator 遇無權限目錄會拋出例外,需 try-catch 或設定 error_reporting。
  • 路徑長度:Windows 260 字元限制,深層目錄可能失效。

總結

遞迴掃描目錄樹的核心邏輯為「讀取項目 → 判斷類型 → 檔案輸出 / 目錄遞迴」。傳統 dir() 相容性佳;現代專案建議使用 RecursiveDirectoryIterator 內建深度控制、過濾、排序功能。輸出端分離 HTML 結構與資料,便於前端框架 (Vue/React) 或樹狀元件 (jstree, Fancytree) 接管渲染。

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