檔案管理、程式碼瀏覽、部署腳本都需要「遞迴掃描目錄樹」。本文提供一個極簡的單檔案 PHP 檔案瀏覽器,支援:透過 GET 參數切換目錄、區分檔案/資料夾顯示、點擊資料夾進入、顯示完整路徑,適合快速部署在測試環境除錯使用。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PHP 目錄瀏覽器</title>
<style>
body { font-family: monospace; padding: 20px; }
.dir { color: #2c3e50; font-weight: bold; cursor: pointer; }
.file { color: #27ae60; }
.path { margin-bottom: 10px; padding: 10px; background: #ecf0f1; border-radius: 4px; }
a { text-decoration: none; color: #2980b9; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<?php
// 安全性:限制只能瀏覽指定根目錄下
$ROOT_BASE = realpath(__DIR__ . '/public'); // 修改為你的專案公開目錄
$requestPath = $_GET['dir'] ?? '';
// 解析並驗證路徑
$targetDir = $ROOT_BASE;
if ($requestPath !== '') {
$requestPath = realpath($ROOT_BASE . '/' . $requestPath);
// 防止目錄穿越攻擊
if ($requestPath && strpos($requestPath, $ROOT_BASE) === 0 && is_dir($requestPath)) {
$targetDir = $requestPath;
}
}
$relativePath = substr($targetDir, strlen($ROOT_BASE));
$relativePath = ltrim($relativePath, '/\\');
echo "當前目錄:" . htmlspecialchars($relativePath ?: '/') . "";
// 讀取目錄內容
$items = scandir($targetDir);
$dirs = [];
$files = [];
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$fullPath = $targetDir . DIRECTORY_SEPARATOR . $item;
if (is_dir($fullPath)) {
$dirs[] = $item;
} else {
$files[] = $item;
}
}
// 顯示資料夾(可點擊進入)
if ($dirs) {
echo "";
foreach ($dirs as $dir) {
$newRel = $relativePath ? $relativePath . '/' . $dir : $dir;
echo "- 📁 " . htmlspecialchars($dir) . "
";
}
echo "
";
}
// 顯示檔案
if ($files) {
echo "";
foreach ($files as $file) {
echo "- 📄 " . htmlspecialchars($file) . "
";
}
echo "
";
}
if (!$dirs && !$files) {
echo "(空目錄)
";
}
?>
</body>
</html>
| 函式/技巧 | 用途 |
|---|---|
realpath() | 解析相對路徑為絕對路徑,並驗證存在性 |
strpos($path, $ROOT_BASE) === 0 | 防止目錄穿越(../../etc/passwd) |
scandir() | 一次讀取目錄所有項目,回傳陣列(含 . 與 ..) |
is_dir() | 區分資料夾與檔案 |
DIRECTORY_SEPARATOR | 跨平台路徑分隔符(Windows \、Linux /) |
// 1. 顯示檔案大小與修改時間
$stat = stat($fullPath);
echo " (" . formatBytes($stat['size']) . ", " . date('Y-m-d H:i', $stat['mtime']) . ")";
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$pow = floor(log($bytes, 1024));
$pow = min($pow, count($units) - 1);
return round($bytes / (1024 ** $pow), $precision) . ' ' . $units[$pow];
}
// 2. 檔案類型圖示(依副檔名)
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
$icons = ['php'=>'🐘','js'=>'📜','css'=>'🎨','jpg'=>'🖼','png'=>'🖼','pdf'=>'📕','zip'=>'📦'];
echo $icons[$ext] ?? '📄';
// 3. 搜尋過濾
$keyword = $_GET['q'] ?? '';
if ($keyword && stripos($item, $keyword) === false) continue;
$ALLOWED = ['/var/www/html', '/data/uploads'],拒絕其他路徑。.htaccess 加入 php_flag engine off。這個 50 行的 browser.php 展示了 PHP 目錄操作的核心 API:scandir、is_dir、realpath、路徑安全驗證。實務上建議將此功能封裝為 DirectoryScanner 服務類別,提供 getTree()、findFiles($pattern)、calculateSize() 等方法,供控制器、命令列、API 共用,避免在視圖層混入商業邏輯。