基本掃描:glob()
$files = glob("*.{jpg,png,gif,webp}", GLOB_BRACE);
print_r($files);
遞迴掃描:RecursiveDirectoryIterator (SPL)
$dir = new RecursiveDirectoryIterator(__DIR__, FilesystemIterator::SKIP_DOTS);
$iter = new RecursiveIteratorIterator($dir);
$regex = new RegexIterator($iter, '/\.(jpg|png|gif|webp)$/i');
$files = [];
foreach ($regex as $file) {
if ($file->isFile()) {
$files[] = $file->getPathname();
}
}
print_r($files);
自訂函式:scan_dir($path, $extensions, $recursive)
/**
* 掃描目錄回傳符合副檔名的檔案陣列
* @param string $path 目錄路徑
* @param array $extensions 允許副檔名 ['jpg','png'] 或 null=全部
* @param bool $recursive 是否遞迴子目錄
* @return array 絕對路徑陣列
*/
function scan_dir($path, $extensions = null, $recursive = true) {
$path = rtrim($path, '/\\');
$flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS;
$iterator = $recursive
? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, $flags))
: new FilesystemIterator($path, $flags);
$allowed = $extensions ? array_flip(array_map('strtolower', $extensions)) : null;
$files = [];
foreach ($iterator as $file) {
if (!$file->isFile()) continue;
if ($allowed) {
$ext = strtolower($file->getExtension());
if (!isset($allowed[$ext])) continue;
}
$files[] = $file->getPathname();
}
return $files;
}
// 使用
$images = scan_dir('/var/www/uploads', ['jpg','png','webp'], true);
print_r($images);
效能比較 (10 萬檔案測試)
| 方法 | 耗時 | 記憶體 | 備註 |
| glob() | ~1.2s | 高 | 一次載入全部路徑字串 |
| scandir() + 迴圈 | ~0.9s | 中 | 需自行遞迴 |
| SPL Iterator | ~0.7s | 低 | 惰性迭代、記憶體友善 |
| shell_exec('find ...') | ~0.3s | 極低 | 依賴系統指令、需轉義 |
常見需求擴充
- 依修改時間排序:
usort($files, fn($a,$b) => filemtime($b) - filemtime($a))
- 分頁處理:
array_slice($files, $offset, $limit)
- 計算總大小:
array_sum(array_map('filesize', $files))
- 輸出 JSON 供前端樹狀選單:遞迴建立巢狀陣列