目錄遍歷是 PHP 檔案系統操作的基礎技能。本文透過一個可互動的「簡易檔案瀏覽器」範例,示範如何結合 `opendir`、`readdir`、`chdir`、`getcwd` 等原生函式,實現目錄的遞迴瀏覽與上下層導航。程式碼採用 GET 傳遞 Base64 編碼路徑,適合教學或輕量級後台檔案管理雛形。
| 函式 | 用途 |
|---|---|
isset() | 檢查 `$_GET['id']` 是否存在 |
base64_decode() | 還原 URL 傳遞的路徑字串 |
chdir() | 切換當前工作目錄 |
opendir('.') | 開啟當前目錄資料流 |
readdir() | 逐一讀取目錄項目 |
is_dir() | 判斷是否為目錄 |
getcwd() | 取得當前絕對路徑 |
strrpos() | 尋找最後一個路徑分隔符,用於計算上層路徑 |
<?php
// 6.php - 簡易目錄瀏覽器
if (isset($_GET['id'])) {
// 還原路徑:將空格還原為 +,再 Base64 解碼
$s = str_replace(' ', '+', $_GET['id']);
$s = base64_decode($s);
chdir($s); // 切換到目標目錄
}
$handle = opendir('.'); // 開啟當前目錄
while (false !== ($entry = readdir($handle))) {
// 略過 . 與 .. 的特殊處理放在後面
if (is_dir($entry)) {
if ($entry === '.') {
// 當前目錄不顯示連結
continue;
} elseif ($entry === '..') {
// 上一層目錄:取得父目錄路徑
$current = getcwd();
$parent = substr($current, 0, strrpos($current, '\\'));
$encoded = base64_encode($parent);
echo "上一級 <a href='6.php?id=$encoded'>打開</a><br />";
} else {
// 子目錄:組合絕對路徑並編碼
$fullPath = getcwd() . '\\' . $entry;
$encoded = base64_encode($fullPath);
echo "$entry <a href='6.php?id=$encoded'>打開</a><br />";
}
} else {
// 一般檔案
echo "$entry 不是目錄<br />";
}
}
closedir($handle);
?>
URL 傳遞路徑時,直接使用中文或特殊字元會導致解析錯誤。範例採用 base64_encode() 將絕對路徑編碼為安全字串,前端連結攜帶 `id` 參數;後端以 str_replace(' ', '+') 修正 Base64 中 `+` 被 URL 解析為空格的問題,再 base64_decode() 還原。
chdir($path) 讓後續 `opendir('.')` 作用於目標目錄。strrpos(getcwd(), '\\') 找到最後一個反斜線,截取父路徑。getcwd() . '\\' . $entry 組合完整路徑。範例使用反斜線 `\`,適用於 Windows 環境。若部署於 Linux,請將所有 `\` 改為 `/`,或使用常數 `DIRECTORY_SEPARATOR` 寫成跨平台相容代碼:
$parent = substr($current, 0, strrpos($current, DIRECTORY_SEPARATOR)); $fullPath = getcwd() . DIRECTORY_SEPARATOR . $entry;
<?php
$root = isset($_GET['path']) ? base64_decode(str_replace(' ', '+', $_GET['path'])) : __DIR__;
$root = realpath($root); // 規範化路徑,防止遍歷攻擊
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($root, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $file) {
$relative = substr($file->getPathname(), strlen($root) + 1);
$encoded = base64_encode($file->getPathname());
$icon = $file->isDir() ? '📁' : '📄';
echo "$icon $relative <a href='?path=$encoded'>開啟</a><br>";
}
?>
SPL 版本自動處理遞迴、略過 `.` `..`、跨平台路徑,程式碼更簡潔且效能更好,建議新專案優先採用。