rmdir() 僅能刪除空目錄,刪除含檔案/子目錄的資料夾需先遞迴清空內容。以下提供三種寫法,從基礎到進階。
<?php
function deleteDirRecursive($dir) {
if (!is_dir($dir)) {
return false;
}
$handle = opendir($dir);
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$path = $dir . DIRECTORY_SEPARATOR . $file;
if (is_dir($path)) {
deleteDirRecursive($path); // 遞迴刪除子目錄
} else {
unlink($path); // 刪除檔案
}
}
closedir($handle);
return rmdir($dir); // 刪除空目錄本身
}
// 使用
if (deleteDirRecursive('./temp')) {
echo '刪除成功';
} else {
echo '刪除失敗';
}
<?php
function deleteDirIterator($dir) {
if (!is_dir($dir)) return false;
foreach (new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS) as $item) {
if ($item->isDir()) {
deleteDirIterator($item->getPathname());
} else {
$item->unlink(); // SplFileInfo::unlink()
}
}
return rmdir($dir);
}
<?php
function deleteDirRecursiveIterator($dir) {
if (!is_dir($dir)) return false;
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST // 關鍵:先處理子項,再處理父目錄
);
foreach ($files as $file) {
if ($file->isDir()) {
rmdir($file->getPathname());
} else {
unlink($file->getPathname());
}
}
return rmdir($dir);
}
| 特性 | 寫法一 opendir | 寫法二 FilesystemIterator | 寫法三 RecursiveIterator |
|---|---|---|---|
| PHP 版本需求 | 4.0+ | 5.3+ | 5.3+ |
| 程式碼長度 | 較長 | 中等 | 最短 |
| 可讀性 | 高(教學用) | 高 | 中(需理解迭代器) |
| 效能 | 基準 | 略好 | 最好(C 層實作) |
| 錯誤處理 | 手動 | 例外處理 | 例外處理 |
| 符號連結處理 | 需自行判斷 | 預設跟隨 | 預設跟隨 |
<?php
function safeDeleteDir($dir) {
$dir = realpath($dir); // 解析符號連結,避免刪除連結目標外的檔案
if (!$dir || !is_dir($dir)) return false;
// 防止刪除系統關鍵目錄
$protected = ['/', '/home', '/var', '/etc', '/usr', __DIR__];
if (in_array($dir, $protected)) {
trigger_error("嘗試刪除受保護目錄: $dir", E_USER_WARNING);
return false;
}
try {
return deleteDirRecursiveIterator($dir);
} catch (Exception $e) {
error_log("刪除目錄失敗 $dir: " . $e->getMessage());
return false;
}
}