將指定目錄下所有檔案與子目錄以樹狀結構 (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;
}
?>
is_dir() 會跟隨連結,可能導致無限遞迴。使用 $file->isLink() (SPL) 或 is_link() 排除。scandir()/RecursiveDirectoryIterator 遇無權限目錄會拋出例外,需 try-catch 或設定 error_reporting。遞迴掃描目錄樹的核心邏輯為「讀取項目 → 判斷類型 → 檔案輸出 / 目錄遞迴」。傳統 dir() 相容性佳;現代專案建議使用 RecursiveDirectoryIterator 內建深度控制、過濾、排序功能。輸出端分離 HTML 結構與資料,便於前端框架 (Vue/React) 或樹狀元件 (jstree, Fancytree) 接管渲染。