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

PHP 遞歸掃描目錄並打印文件樹結構(含文件計數、超鏈接、錯誤抑制)

     編輯:PHP 綜合知識

功能特性

  • 遞歸遍歷指定目錄及子目錄
  • 輸出 HTML 結構化文件樹(目錄粗體+超鏈接、文件超鏈接)
  • 縮進顯示層級關係
  • 統計總文件數(不含 . 和 ..)
  • 錯誤抑制與自定義錯誤提示

完整代碼

<?php
/**
 * 遞歸掃描並輸出目錄樹
 * @param string $dir  絕對路徑(需以 / 或 \ 結尾)
 * @param int    $level 當前層級(內部使用,外部調用默認 1)
 * @return int 文件總數
 */
function scanDirTree(string $dir, int $level = 1): int {
    static $fileCount = 0; // 靜態變量跨遞歸累計

    // 1. 打開目錄(抑制警告)
    $handle = @opendir($dir);
    if (!$handle) {
        // 僅頂層報錯,避免遞歸中重複輸出
        if ($level === 1) {
            die("❌ 目錄打開失敗:$dir (請檢查路徑是否存在、權限是否足夠)");
        }
        return $fileCount;
    }

    // 2. 遍歷條目
    while (($entry = readdir($handle)) !== false) {
        // 跳過 . 和 ..
        if ($entry === '.' || $entry === '..') continue;

        $fileCount++;
        $fullPath = $dir . $entry;

        // 3. 輸出縮進
        echo str_repeat(' ', ($level - 1) * 4);

        // 4. 區分目錄/文件
        if (is_dir($fullPath)) {
            // 目錄:粗體 + 可點擊展開(需前端 JS 配合)+ 遞歸
            echo "<strong><a href=\"#\" data-path=\"" . htmlspecialchars($fullPath) . "\">" . htmlspecialchars($entry) . "</a></strong><br>";
            scanDirTree($fullPath . DIRECTORY_SEPARATOR, $level + 1);
        } else {
            // 文件:普通超鏈接
            echo "<a href=\"" . htmlspecialchars($fullPath) . "\" target=\"_blank\">" . htmlspecialchars($entry) . "</a><br>";
        }
    }

    closedir($handle);

    // 5. 頂層輸出統計
    if ($level === 1) {
        echo "<hr><strong>文件總數:$fileCount</strong>";
    }

    return $fileCount;
}

// 使用示例
// 確保路徑以分隔符結尾
$targetDir = 'D:/wamp/www/test/lamp61/';
if (substr($targetDir, -1) !== DIRECTORY_SEPARATOR) {
    $targetDir .= DIRECTORY_SEPARATOR;
}

echo "<h3>目錄樹:$targetDir</h3>";
scanDirTree($targetDir);
?>

增強版:返回結構化數組(供 API/模板使用)

<?php
/**
 * 獲取目錄樹結構數組
 * @return array ['dirs'=>[], 'files'=>[], 'count'=>int]
 */
function getDirTree(string $dir): array {
    $result = ['dirs' => [], 'files' => [], 'count' => 0];
    $handle = @opendir($dir);
    if (!$handle) return $result;

    while (($entry = readdir($handle)) !== false) {
        if ($entry === '.' || $entry === '..') continue;
        $fullPath = $dir . DIRECTORY_SEPARATOR . $entry;
        $result['count']++;

        if (is_dir($fullPath)) {
            $result['dirs'][$entry] = getDirTree($fullPath); // 遞歸
        } else {
            $info = stat($fullPath);
            $result['files'][$entry] = [
                'size'   => $info['size'],
                'mtime'  => $info['mtime'],
                'mime'   => mime_content_type($fullPath) ?: 'unknown',
                'path'   => $fullPath,
            ];
        }
    }
    closedir($handle);
    return $result;
}

// 輸出 JSON 供前端樹形組件(如 zTree, jstree, Element UI Tree)渲染
header('Content-Type: application/json; charset=utf-8');
echo json_encode(getDirTree('/var/www/html'), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

現代替代:SPL 迭代器(更優雅、可過濾)

<?php
$dir = new RecursiveDirectoryIterator('/var/www/html', FilesystemIterator::SKIP_DOTS);
$iter = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);

foreach ($iter as $path => $file) {
    $depth = $iter->getDepth();
    $indent = str_repeat('  ', $depth);
    $type = $file->isDir() ? '[DIR] ' : '[FILE]';
    echo "$indent$type{$file->getFilename()}\n";
}

優勢:內建跳過 ./..、可組合 RegexIterator 過濾擴展名、CallbackFilterIterator 自定義邏輯、自動處理跨平台路徑分隔符。

性能與安全提醒

  • ⚠️ 大目錄遞歸可能耗盡記憶體/超時:生產環境限制最大深度、文件數,或使用生成器 yield 分批輸出。
  • 🔒 路徑遍歷風險:用戶輸入路徑時必須 realpath() 規範化並校驗在允許根目錄內。
  • 🚫 避免直接輸出文件超鏈接:洩露服務器絕對路徑。生產環境應通過受控下載腳本(readfile() + 權限檢查)提供文件訪問。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved