專案常需掃描特定目錄下的所有檔案與子目錄(如建立檔案索引、批次處理、產生網站地圖)。本文提供一個健全的遞迴函式 read_all_dir(),回傳結構化陣列,並處理邊界條件與資源釋放。
<?php
/**
* 遞迴讀取目錄結構
* @param string $dir 絕對或相對路徑
* @return array 結構:['dir' => [路徑 => 子結構], 'file' => [檔案路徑...]]
*/
function read_all_dir(string $dir): array
{
$result = ['dir' => [], 'file' => []];
// 確保路徑存在且可讀
if (!is_dir($dir) || !is_readable($dir)) {
return $result;
}
$handle = opendir($dir);
if ($handle === false) {
return $result;
}
while (($file = readdir($handle)) !== false) {
// 跳過 . 與 ..
if ($file === '.' || $file === '..') {
continue;
}
$cur_path = $dir . DIRECTORY_SEPARATOR . $file;
if (is_dir($cur_path)) {
// 遞迴處理子目錄
$result['dir'][$cur_path] = read_all_dir($cur_path);
} else {
// 收集檔案
$result['file'][] = $cur_path;
}
}
closedir($handle);
return $result;
}
// 使用範例
$tree = read_all_dir(__DIR__ . '/storage');
echo '<pre>';
print_r($tree);
echo '</pre>';
Array
(
[dir] => Array
(
[/var/www/storage/images] => Array
(
[dir] => Array()
[file] => Array
(
[0] => /var/www/storage/images/photo.jpg
[1] => /var/www/storage/images/logo.png
)
)
)
[file] => Array
(
[0] => /var/www/storage/readme.txt
[1] => /var/www/storage/config.ini
)
)
else 區塊加入 pathinfo($cur_path, PATHINFO_EXTENSION) 判斷。$depth = 0, $maxDepth = 10,避免過深導致堆疊溢位。RecursiveDirectoryIterator + RecursiveIteratorIterator,程式碼更簡潔:$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
);
foreach ($iterator as $fileInfo) {
if ($fileInfo->isFile()) {
echo $fileInfo->getPathname() . PHP_EOL;
}
}
yield)逐筆產出。r+x 權限,否則 opendir() 會失敗回傳 false。