红穆笔记
首頁 語言筆記 PHP 輸出網站目錄樹結構,目錄樹瀏覽器 - 安全地顯示指定文件夾的樹形結構
語言筆記 PHP

PHP 輸出網站目錄樹結構,目錄樹瀏覽器 - 安全地顯示指定文件夾的樹形結構

PHP 输出网站目录树结构,目录树浏览器 - 安全地显示指定文件夹的树形结构

目錄樹瀏覽器 - 安全地顯示指定文件夾的樹形結構

20260320154932124-image

 

使用方法:
1. 將本文件放置於網站根目錄,命名爲 tree.php 或其他名稱
2. 修改下方的 TARGET_BASE 常量,設置您要瀏覽的根文件夾(相對於網站根目錄)
3. 通過瀏覽器訪問:http://您的網站/tree.php
4.可選參數 ?dir=子文件夾路徑 來瀏覽子目錄,例如:?dir=images/icons

安全特性:
- 所有路徑均經過 realpath 驗證,防止目錄遍歷攻擊
- 只允許訪問 TARGET_BASE 目錄及其子目錄
- 輸出使用 htmlspecialchars 轉義,防止 XSS 攻擊

<?php
/**
 * 目錄樹瀏覽器(文本風格)- 使用樹形連線符號代替縮進空格
 * 
 * 使用方法:
 * 1. 將本文件放置於網站根目錄,命名爲 tree.php 或其他名稱
 * 2. 修改下方的 TARGET_BASE 常量,設置您要瀏覽的根文件夾(相對於網站根目錄)
 * 3. 通過瀏覽器訪問:http://您的網站/tree.php
 * 4. 可選參數 ?dir=子文件夾路徑 來瀏覽子目錄,例如:?dir=images/icons
 * 
 * 安全特性:
 * - 所有路徑均經過 realpath 驗證,防止目錄遍歷攻擊
 * - 只允許訪問 TARGET_BASE 目錄及其子目錄
 * - 輸出使用 htmlspecialchars 轉義,防止 XSS 攻擊
 */

// ---------- 配置區域 ----------
// 定義要瀏覽的根文件夾(相對於網站根目錄 $_SERVER['DOCUMENT_ROOT'])
// 例如:'storage' 表示瀏覽 /網站根目錄/storage
define('TARGET_BASE', '');  // 請修改爲您需要顯示的文件夾名稱

// 是否顯示隱藏文件(以點開頭的文件/文件夾)
define('SHOW_HIDDEN', false);

// 圖標定義(仍保留,使輸出更友好)
define('ICON_FOLDER', '📁');
define('ICON_FILE', '📄');
// -----------------------------

// 設置時區與編碼
date_default_timezone_set('Asia/Shanghai');
header('Content-Type: text/html; charset=utf-8');

// 基礎路徑:網站根目錄下的目標文件夾
$basePath = rtrim($_SERVER['DOCUMENT_ROOT'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . TARGET_BASE;
$baseReal = realpath($basePath);

// 檢查基目錄是否存在且可讀
if ($baseReal === false) {
    die("<h2>錯誤:基目錄不存在或不可讀</h2><p>請檢查配置:<code>" . htmlspecialchars($basePath) . "</code></p>");
}

// 獲取請求的子目錄參數,並清理
$requestDir = isset($_GET['dir']) ? trim($_GET['dir'], '/\\ ') : '';
$requestDir = str_replace(['../', '..\\'], '', $requestDir); // 額外過濾,但主要依賴 realpath

// 構建完整目標路徑
if ($requestDir !== '') {
    // 替換目錄分隔符爲系統分隔符
    $requestDir = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $requestDir);
    $targetPath = $baseReal . DIRECTORY_SEPARATOR . $requestDir;
} else {
    $targetPath = $baseReal;
}

// 獲取目標路徑的真實路徑(必須存在)
$targetReal = realpath($targetPath);
if ($targetReal === false) {
    die("<h2>錯誤:請求的路徑不存在或無法訪問</h2><p>路徑:" . htmlspecialchars($targetPath) . "</p>");
}

// 安全檢查:確保目標路徑在基目錄之下
$baseRealWithSep = $baseReal . DIRECTORY_SEPARATOR;
if (strpos($targetReal . DIRECTORY_SEPARATOR, $baseRealWithSep) !== 0 && $targetReal !== $baseReal) {
    die("<h2>錯誤:無權訪問指定目錄</h2>");
}

// 獲取當前目錄相對於基目錄的路徑(用於URL)
$relativePath = ($targetReal === $baseReal) ? '' : substr($targetReal, strlen($baseReal) + 1);
$relativePathForUrl = str_replace(DIRECTORY_SEPARATOR, '/', $relativePath);

/**
 * 遞歸生成文本風格的目錄樹(帶連線符號)
 *
 * @param string $path      絕對路徑
 * @param string $prefix    前綴字符串(用於遞歸構建連線)
 * @return array            每行文本組成的數組
 */
function buildTreeLines($path, $prefix = '') {
    $lines = [];
    $items = @scandir($path);
    if ($items === false) {
        return ['<無法讀取目錄>'];
    }

    // 過濾掉 . 和 ..
    $items = array_diff($items, ['.', '..']);
    
    // 如果不顯示隱藏文件,過濾以點開頭的項目
    if (!SHOW_HIDDEN) {
        $items = array_filter($items, function($item) {
            return $item[0] !== '.';
        });
    }

    // 自然排序:文件夾在前,文件在後,各自按名稱排序
    $folders = [];
    $files   = [];
    foreach ($items as $item) {
        $fullPath = $path . DIRECTORY_SEPARATOR . $item;
        if (is_dir($fullPath)) {
            $folders[] = $item;
        } else {
            $files[] = $item;
        }
    }
    natcasesort($folders);
    natcasesort($files);
    $sortedItems = array_merge($folders, $files);

    $count = count($sortedItems);
    $i = 0;
    foreach ($sortedItems as $item) {
        $i++;
        $isLast = ($i === $count);
        $fullPath = $path . DIRECTORY_SEPARATOR . $item;
        $safeName = htmlspecialchars($item);
        
        // 選擇連接符
        $connector = $isLast ? '└── ' : '├── ';
        
        if (is_dir($fullPath)) {
            // 文件夾行
            $lines[] = $prefix . $connector . ICON_FOLDER . ' ' . $safeName;
            // 遞歸子文件夾,生成新的前綴
            $subPrefix = $prefix . ($isLast ? '    ' : '│   ');
            $subLines = buildTreeLines($fullPath, $subPrefix);
            $lines = array_merge($lines, $subLines);
        } else {
            // 文件行:附加文件大小
            $size = filesize($fullPath);
            $sizeFormatted = formatBytes($size);
            $lines[] = $prefix . $connector . ICON_FILE . ' ' . $safeName . ' (' . $sizeFormatted . ')';
        }
    }
    return $lines;
}

/**
 * 格式化字節數
 */
function formatBytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= (1 << (10 * $pow));
    return round($bytes, $precision) . ' ' . $units[$pow];
}

/**
 * 獲取父目錄的相對路徑(用於返回上一級)
 */
function getParentRelative($currentRelative) {
    if (empty($currentRelative)) {
        return null; // 已經在根目錄,無上級
    }
    $parts = explode(DIRECTORY_SEPARATOR, $currentRelative);
    array_pop($parts);
    return implode(DIRECTORY_SEPARATOR, $parts);
}

// 生成當前目錄的文本樹行數組
$treeLines = buildTreeLines($targetReal);
$treeText = implode("\n", $treeLines);

// 獲取當前目錄名稱(用於顯示)
$currentDisplayName = ($targetReal === $baseReal) ? TARGET_BASE . ' (根)' : basename($targetReal);
?>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>目錄樹瀏覽器(文本風格) - <?php echo htmlspecialchars($currentDisplayName); ?></title>
    <style>
        * {
            box-sizing: border-box;
        }
        body {
            font-family: 'Segoe UI', 'SF Pro Text', 'Helvetica Neue', sans-serif;
            background: #f8f9fa;
            margin: 0;
            padding: 20px;
            color: #2c3e50;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 16px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
            overflow: hidden;
            padding: 25px 30px;
        }
        h1 {
            margin-top: 0;
            font-size: 1.8rem;
            font-weight: 400;
            border-bottom: 1px solid #e9ecef;
            padding-bottom: 15px;
            color: #1e3c5c;
        }
        h1 small {
            font-size: 0.9rem;
            font-weight: 300;
            color: #6c757d;
            margin-left: 10px;
        }
        .path-bar {
            background: #e9ecef;
            border-radius: 30px;
            padding: 10px 20px;
            margin-bottom: 25px;
            display: flex;
            align-items: center;
            flex-wrap: wrap;
            gap: 10px;
            font-size: 0.95rem;
        }
        .path-label {
            font-weight: 600;
            color: #495057;
            margin-right: 5px;
        }
        .path-links {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 5px;
        }
        .path-links a {
            color: #0d6efd;
            text-decoration: none;
            padding: 2px 8px;
            border-radius: 20px;
            background: white;
            border: 1px solid #dee2e6;
            transition: 0.2s;
        }
        .path-links a:hover {
            background: #0d6efd;
            color: white;
            border-color: #0d6efd;
        }
        .path-links span.sep {
            color: #adb5bd;
            margin: 0 2px;
        }
        .nav-form {
            margin-left: auto;
            display: flex;
            gap: 8px;
        }
        .nav-form input {
            padding: 8px 15px;
            border-radius: 30px;
            border: 1px solid #ced4da;
            width: 250px;
            font-size: 0.9rem;
        }
        .nav-form button {
            background: #0d6efd;
            color: white;
            border: none;
            border-radius: 30px;
            padding: 8px 20px;
            cursor: pointer;
            font-weight: 500;
            transition: 0.2s;
        }
        .nav-form button:hover {
            background: #0b5ed7;
        }
        /* 文本樹樣式 */
        .tree-container {
            background: #fefefe;
            border-radius: 12px;
            padding: 20px;
            font-family: 'SF Mono', 'Fira Code', 'Consolas', 'Courier New', monospace;
            font-size: 1rem;
            line-height: 1.5;
            overflow-x: auto;
            border: 1px solid #e9ecef;
            white-space: pre;
            margin: 15px 0;
        }
        .tree-text {
            margin: 0;
            color: #212529;
        }
        .footer {
            margin-top: 30px;
            text-align: center;
            font-size: 0.85rem;
            color: #6c757d;
            border-top: 1px solid #e9ecef;
            padding-top: 15px;
        }
        .footer code {
            background: #e9ecef;
            padding: 2px 6px;
            border-radius: 6px;
        }
        .parent-link {
            display: inline-block;
            background: #e7f3ff;
            color: #0d6efd;
            padding: 8px 18px;
            border-radius: 30px;
            text-decoration: none;
            font-weight: 500;
            border: 1px solid #b8daff;
            transition: 0.2s;
        }
        .parent-link:hover {
            background: #0d6efd;
            color: white;
            border-color: #0d6efd;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>
            📂 目錄樹瀏覽器(文本風格)
            <small><?php echo htmlspecialchars(TARGET_BASE); ?> 及其子目錄</small>
        </h1>

        <!-- 路徑導航 -->
        <div class="path-bar">
            <span class="path-label">當前位置:</span>
            <div class="path-links">
                <a href="?">根目錄</a>
                <?php
                // 生成麪包屑導航
                if (!empty($relativePath)) {
                    $parts = explode(DIRECTORY_SEPARATOR, $relativePath);
                    $cumulative = '';
                    echo '<span class="sep">/</span>';
                    foreach ($parts as $index => $part) {
                        $cumulative .= ($cumulative ? DIRECTORY_SEPARATOR : '') . $part;
                        $safePart = htmlspecialchars($part);
                        $url = '?dir=' . urlencode(str_replace(DIRECTORY_SEPARATOR, '/', $cumulative));
                        if ($index === count($parts) - 1) {
                            echo '<span>' . $safePart . '</span>';
                        } else {
                            echo '<a href="' . $url . '">' . $safePart . '</a><span class="sep">/</span>';
                        }
                    }
                }
                ?>
            </div>

            <!-- 快速跳轉子目錄表單 -->
            <form class="nav-form" method="get" action="">
                <input type="text" name="dir" placeholder="輸入子目錄路徑 (如 images/icons)" value="<?php echo htmlspecialchars($relativePathForUrl); ?>">
                <button type="submit">跳轉</button>
            </form>
        </div>

        <!-- 文本樹輸出 -->
        <div class="tree-container">
            <pre class="tree-text"><?php
                // 輸出根目錄行,然後輸出樹內容
                echo ICON_FOLDER . ' ' . htmlspecialchars($currentDisplayName) . "\n";
                echo $treeText;
            ?></pre>
        </div>

        <!-- 父目錄鏈接與說明 -->
        <div style="margin-top: 20px;">
            <?php
            $parentRelative = getParentRelative($relativePath);
            if ($parentRelative !== null):
                $parentUrl = '?dir=' . urlencode(str_replace(DIRECTORY_SEPARATOR, '/', $parentRelative));
            ?>
                <a href="<?php echo $parentUrl; ?>" class="parent-link">⬆ 返回上一級 (<?php echo htmlspecialchars(basename($parentRelative) ?: '根目錄'); ?>)</a>
            <?php endif; ?>
        </div>

        <div class="footer">
            <p>🔒 安全限制:只能瀏覽 <code><?php echo htmlspecialchars($baseReal); ?></code> 及其子目錄 | 隱藏文件<?php echo SHOW_HIDDEN ? '顯示' : '不顯示'; ?> | 連線符號: ├── └── │</p>
        </div>
    </div>
</body>
</html>
微信赞赏

微信

支付宝赞赏

支付寶

✍️ 作者: 紅穆

網站管理員 · 感謝閱讀,更多精彩內容敬請關注

作者主頁 查看主頁 →

相關文章

PHP ob函数记录

PHP ob函數記錄 語言筆記 PHP

下面3個函數的用法 ob_get_contents(); ob_end_clean(); ob_start(); 可以藉助這幾個函數實現緩衝本地文件,以及執行本地腳本代碼。 使用ob_start()把輸出的代碼存到緩衝區,頁面不會顯示出來; 然後用ob_get_contents得到緩衝區的數據。 o…
👁 141
PHP preg

PHP preg 語言筆記 PHP

preg_match_all 函數用於執行一個全局正則表達式匹配。preg_match_all() 語法int preg_match_all ( string $pattern , string $subject [, array &amp;$matches [, int $flags = PREG…
👁 169
PHP 三元运算符与if的详解

PHP 三元運算符與if的詳解 語言筆記 PHP

三元運算符語條件 ? 結果1 : 結果2 說明:問號前面的位置是判斷的條件,如果滿足條件時結果1,不滿足時結果2。本文對三元運算符和if...else...進行對比詳解,希望對大家有所幫助。今天在改論文在線的時候遇到了一個語句看不懂:$if_summary = $row['IF_SUMMARY']=…
👁 189
PHP强制转换类型

PHP強制轉換類型 語言筆記 PHP PHP採集 PHP與mysql

獲取數據類型1.如果想查看某個表達式的值和類型,用var_dump()。 2.如果只是想得到一個易讀懂的類型的表達方式用於調試,用 gettype()。3.要查看某個類型,不要用 gettype(),而用is_type() 函數。字符串轉換爲數值當一個字符串被當作數字來求值時,根據以下規則來決定結果…
👁 232
php 字符串中是否包含指定字符串的多种方法

php 字符串中是否包含指定字符串的多種方法 語言筆記 PHP

strstrstrstr() 函數搜索一個字符串在另一個字符串中的第一次出現。該函數返回字符串的其餘部分(從匹配點)。如果未找到所搜索的字符串,則返回 false。代碼如下:&lt;?php $email = 'user@example.com'; $domain = strstr($email, …
👁 138

推薦閱讀

美容化妆减肥类网站模板 1047

美容化妝減肥類網站模板 1047 實用收藏 易優模板

一款針對美容、化妝與減肥行業的eyoucms網站模板。設計風格時尚精緻,能夠展示美容服務、化妝造型、減肥項目及品牌故事。有助於美容減肥機構在線上吸引女性客戶,提升品牌知名度。模板展示 安裝說明 網站後臺:/login.php 賬號:admin 密碼:admin 相關文章易優CMS安裝常見問題總結易優…
👁 38
(自适应手机端)网址发布页pbootcms网站模板 1040

(自適應手機端)網址發佈頁pbootcms網站模板 1040 實用收藏 pbootcms模板

一款網址發佈頁PbootCMS網站模板,支持PC與WAP端。設計風格簡潔實用,適合作爲個人或企業的網址導航與信息發佈頁面。有助於快速分享和展示重要鏈接與信息。模板展示 安裝說明 網站後臺:/admin.php 賬號:admin 密碼:admin 解壓密碼:www.4s5.cn相關文章PbootCMS…
👁 54
响应式品牌策划电子商务网站模板 0448

響應式品牌策劃電子商務網站模板 0448 實用收藏 易優模板

此套eyoucms響應式模板適用於品牌策劃與電子商務行業,設計風格創意科技,能夠展示品牌策劃案例、電子商務服務、品牌形象及成功案例。有助於品牌電商公司在線上展示專業實力,吸引企業客戶。模板展示 安裝說明 網站後臺:/login.php 賬號:admin 密碼:admin 相關文章易優CMS安裝常見問…
👁 47
(自适应手机版)幽默笑话网站pbootcms模板 搞笑趣图类网站源码下载 0476

(自適應手機版)幽默笑話網站pbootcms模板 搞笑趣圖類網站源碼下載 0476 實用收藏 pbootcms模板

一款自適應移動端的機械製造與藍色工業機械設備PbootCMS網站模板。設計風格專業工業,適合各類機械設備製造企業展示產品系列。有助於機械公司在線上搭建品牌形象站,吸引工業客戶。模板展示 安裝說明 網站後臺:/admin.php 賬號:admin 密碼:admin 解壓密碼:www.4s5.cn相關文…
👁 56
医疗皮肤健康类网站模板 1048

醫療皮膚健康類網站模板 1048 實用收藏 易優模板

此套eyoucms模板適用於醫療與皮膚健康行業,設計風格專業潔淨,能夠展示皮膚醫療服務、健康管理、專家團隊及成功案例。有助於皮膚健康機構在線上吸引患者,提升品牌專業度。模板展示 安裝說明 網站後臺:/login.php 賬號:admin 密碼:admin 相關文章易優CMS安裝常見問題總結易優CMS…
👁 59
(自适应手机端)网址发布页pbootcms网站模板 1041

(自適應手機端)網址發佈頁pbootcms網站模板 1041 實用收藏 pbootcms模板

一款網址發佈頁PbootCMS網站模板,支持PC與WAP端。設計風格簡潔實用,適合作爲個人或企業的網址導航與信息發佈頁面。有助於快速分享和展示重要鏈接與信息。模板展示 安裝說明 網站後臺:/admin.php 賬號:admin 密碼:admin 解壓密碼:www.4s5.cn相關文章PbootCMS…
👁 54