PHP rmdir() 函数

定义和用法

rmdir() 函数用于删除空目录。如果目录不为空,则删除失败。要删除非空目录,需要先递归删除目录中的所有文件和子目录。

rmdir() 函数是文件系统操作中的基础函数,常用于清理临时目录、删除上传目录、或管理缓存目录等场景。

警告:rmdir() 函数会永久删除目录,操作不可逆。在使用前务必确认目录内容,尤其是处理用户输入或动态路径时。建议在删除前进行备份或确认操作。

语法

rmdir(string $directory, ?resource $context = null): bool

参数

参数 描述
directory

必需。要删除的目录的路径。

必须是空目录,否则删除失败。可以是绝对路径或相对路径。

context

可选。流上下文(stream context)资源。

用于指定流的特殊选项,例如删除 FTP 目录时需要。

返回值

返回值 描述
TRUE 目录删除成功
FALSE 目录删除失败(目录不为空、权限不足、目录不存在等)

示例

示例1:基本用法

<?php
// 创建测试目录
$dir = "/tmp/test_rmdir";

if (!is_dir($dir)) {
    mkdir($dir, 0755);
    echo "目录创建成功: $dir<br>";
}

// 删除空目录
if (rmdir($dir)) {
    echo "目录删除成功: $dir<br>";
} else {
    echo "目录删除失败: $dir<br>";
}

// 尝试删除非空目录
$dir2 = "/tmp/test_rmdir2";
if (!is_dir($dir2)) {
    mkdir($dir2, 0755);
    file_put_contents($dir2 . "/test.txt", "测试文件");
    echo "创建非空目录: $dir2<br>";
}

if (rmdir($dir2)) {
    echo "目录删除成功: $dir2<br>";
} else {
    echo "目录删除失败 (因为目录非空): $dir2<br>";
    // 清理
    unlink($dir2 . "/test.txt");
    rmdir($dir2);
}
?>

示例2:递归删除目录(非空目录)

<?php
/**
 * 递归删除目录及其所有内容
 * @param string $dir 要删除的目录路径
 * @return bool 是否成功
 */
function deleteDirectory($dir) {
    // 检查目录是否存在
    if (!is_dir($dir)) {
        return false;
    }

    // 打开目录
    $items = scandir($dir);
    if ($items === false) {
        return false;
    }

    // 遍历目录内容
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }

        $path = $dir . DIRECTORY_SEPARATOR . $item;

        if (is_dir($path)) {
            // 递归删除子目录
            if (!deleteDirectory($path)) {
                return false;
            }
        } else {
            // 删除文件
            if (!unlink($path)) {
                return false;
            }
        }
    }

    // 删除空目录
    return rmdir($dir);
}

// 使用示例
$testDir = "/tmp/recursive_delete_test";
if (!is_dir($testDir)) {
    mkdir($testDir, 0755, true);

    // 创建测试文件和子目录
    file_put_contents($testDir . "/file1.txt", "文件1");
    file_put_contents($testDir . "/file2.txt", "文件2");

    mkdir($testDir . "/subdir1", 0755);
    file_put_contents($testDir . "/subdir1/file3.txt", "文件3");

    mkdir($testDir . "/subdir2", 0755);
    mkdir($testDir . "/subdir2/deepdir", 0755);
    file_put_contents($testDir . "/subdir2/deepdir/file4.txt", "文件4");

    echo "测试目录结构创建完成: $testDir<br>";

    // 递归删除
    if (deleteDirectory($testDir)) {
        echo "目录递归删除成功: $testDir<br>";
    } else {
        echo "目录递归删除失败: $testDir<br>";
    }
} else {
    echo "测试目录已存在,跳过创建<br>";
}
?>

示例3:安全删除目录(带验证和备份)

<?php
/**
 * 安全删除目录,带有验证和可选的备份
 */
class SafeDirectoryRemover {

    /**
     * 安全删除目录
     * @param string $dir 要删除的目录
     * @param bool $backup 是否先备份
     * @param string $backupDir 备份目录
     * @return array 操作结果
     */
    public static function safeRemove($dir, $backup = false, $backupDir = null) {
        $result = [
            'success' => false,
            'message' => '',
            'backup_path' => null
        ];

        // 验证目录
        if (!is_dir($dir)) {
            $result['message'] = "目录不存在: $dir";
            return $result;
        }

        // 检查目录是否可写
        if (!is_writable($dir)) {
            $result['message'] = "目录不可写: $dir";
            return $result;
        }

        // 备份目录(如果需要)
        if ($backup) {
            $backupPath = self::backupDirectory($dir, $backupDir);
            if ($backupPath) {
                $result['backup_path'] = $backupPath;
            } else {
                $result['message'] = "目录备份失败: $dir";
                return $result;
            }
        }

        // 递归删除目录
        if (self::recursiveRemove($dir)) {
            $result['success'] = true;
            $result['message'] = "目录删除成功: $dir";
        } else {
            $result['message'] = "目录删除失败: $dir";
        }

        return $result;
    }

    /**
     * 备份目录
     */
    private static function backupDirectory($sourceDir, $backupDir = null) {
        if ($backupDir === null) {
            $backupDir = dirname($sourceDir) . '/backups';
        }

        // 创建备份目录
        if (!is_dir($backupDir)) {
            mkdir($backupDir, 0755, true);
        }

        $timestamp = date('Y-m-d_H-i-s');
        $backupName = basename($sourceDir) . '_' . $timestamp;
        $backupPath = $backupDir . '/' . $backupName;

        // 复制目录
        if (self::copyDirectory($sourceDir, $backupPath)) {
            return $backupPath;
        }

        return false;
    }

    /**
     * 复制目录
     */
    private static function copyDirectory($source, $dest) {
        if (!is_dir($source)) {
            return false;
        }

        if (!is_dir($dest)) {
            mkdir($dest, 0755, true);
        }

        $items = scandir($source);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $srcPath = $source . '/' . $item;
            $dstPath = $dest . '/' . $item;

            if (is_dir($srcPath)) {
                if (!self::copyDirectory($srcPath, $dstPath)) {
                    return false;
                }
            } else {
                if (!copy($srcPath, $dstPath)) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * 递归删除目录
     */
    private static function recursiveRemove($dir) {
        if (!is_dir($dir)) {
            return false;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                if (!self::recursiveRemove($path)) {
                    return false;
                }
            } else {
                if (!unlink($path)) {
                    return false;
                }
            }
        }

        return rmdir($dir);
    }

    /**
     * 删除旧备份
     * @param string $backupDir 备份目录
     * @param int $maxAgeDays 最大保留天数
     * @return array 删除结果
     */
    public static function cleanupOldBackups($backupDir, $maxAgeDays = 30) {
        $results = [
            'total' => 0,
            'deleted' => 0,
            'errors' => []
        ];

        if (!is_dir($backupDir)) {
            return $results;
        }

        $items = scandir($backupDir);
        $cutoffTime = time() - ($maxAgeDays * 24 * 60 * 60);

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $backupDir . '/' . $item;
            $results['total']++;

            // 检查文件/目录时间
            $fileTime = filemtime($path);

            if ($fileTime < $cutoffTime) {
                if (is_dir($path)) {
                    if (self::recursiveRemove($path)) {
                        $results['deleted']++;
                    } else {
                        $results['errors'][] = "无法删除旧备份: $path";
                    }
                } else {
                    if (unlink($path)) {
                        $results['deleted']++;
                    } else {
                        $results['errors'][] = "无法删除旧备份文件: $path";
                    }
                }
            }
        }

        return $results;
    }
}

// 使用示例
echo "<h4>安全目录删除示例</h4>";

// 创建测试目录
$testDir = "/tmp/safe_delete_test";
if (!is_dir($testDir)) {
    mkdir($testDir, 0755, true);

    // 创建一些测试文件
    file_put_contents($testDir . "/important.txt", "重要文件");
    mkdir($testDir . "/data", 0755);
    file_put_contents($testDir . "/data/log.txt", "日志内容");

    echo "测试目录创建完成: $testDir<br>";
}

// 安全删除(带备份)
echo "<br>执行安全删除(带备份):<br>";
$result = SafeDirectoryRemover::safeRemove($testDir, true, '/tmp/backups');

if ($result['success']) {
    echo "删除成功: " . $result['message'] . "<br>";
    if ($result['backup_path']) {
        echo "备份路径: " . $result['backup_path'] . "<br>";
    }
} else {
    echo "删除失败: " . $result['message'] . "<br>";
}

// 清理旧备份示例
echo "<br>清理旧备份示例:<br>";
$cleanupResult = SafeDirectoryRemover::cleanupOldBackups('/tmp/backups', 1); // 保留1天
echo "总共检查: " . $cleanupResult['total'] . " 个备份<br>";
echo "已删除: " . $cleanupResult['deleted'] . " 个旧备份<br>";
if (count($cleanupResult['errors']) > 0) {
    echo "错误:<br>";
    foreach ($cleanupResult['errors'] as $error) {
        echo "- $error<br>";
    }
}
?>

示例4:使用上下文参数删除FTP目录

<?php
// 删除FTP目录的示例
function removeFtpDirectory($ftpServer, $username, $password, $remoteDir) {
    // 创建FTP连接
    $connId = ftp_connect($ftpServer);

    if (!$connId) {
        return "无法连接到FTP服务器: $ftpServer";
    }

    // 登录FTP
    if (!ftp_login($connId, $username, $password)) {
        ftp_close($connId);
        return "FTP登录失败";
    }

    // 开启被动模式
    ftp_pasv($connId, true);

    // 递归删除FTP目录
    function deleteFtpDirectory($connId, $directory) {
        // 获取目录列表
        $files = ftp_nlist($connId, $directory);

        if ($files === false) {
            return false;
        }

        foreach ($files as $file) {
            // 跳过 . 和 ..
            if ($file === '.' || $file === '..') {
                continue;
            }

            $fullPath = $directory . '/' . basename($file);

            // 检查是文件还是目录
            if (ftp_size($connId, $fullPath) == -1) {
                // 是目录,递归删除
                if (!deleteFtpDirectory($connId, $fullPath)) {
                    return false;
                }
            } else {
                // 是文件,删除文件
                if (!ftp_delete($connId, $fullPath)) {
                    return false;
                }
            }
        }

        // 删除空目录
        return ftp_rmdir($connId, $directory);
    }

    // 删除目录
    if (deleteFtpDirectory($connId, $remoteDir)) {
        ftp_close($connId);
        return "FTP目录删除成功: $remoteDir";
    } else {
        $error = "无法删除FTP目录: $remoteDir";
        ftp_close($connId);
        return $error;
    }
}

// 本地模拟FTP删除(实际使用需要FTP服务器)
echo "<h4>FTP目录删除示例</h4>";
echo "注:此示例需要真实的FTP服务器才能运行<br>";
echo "函数签名: removeFtpDirectory(\$ftpServer, \$username, \$password, \$remoteDir)<br><br>";

// 实际应用:清理临时目录
function cleanupTempDirectory($dir, $maxAgeHours = 24) {
    if (!is_dir($dir)) {
        return ['success' => false, 'message' => "目录不存在: $dir"];
    }

    $cutoffTime = time() - ($maxAgeHours * 60 * 60);
    $stats = [
        'directories_deleted' => 0,
        'files_deleted' => 0,
        'errors' => []
    ];

    $items = scandir($dir);

    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }

        $path = $dir . '/' . $item;
        $fileTime = filemtime($path);

        // 检查是否超过最大时间
        if ($fileTime < $cutoffTime) {
            if (is_dir($path)) {
                // 递归删除旧目录
                if (deleteDirectory($path)) {
                    $stats['directories_deleted']++;
                } else {
                    $stats['errors'][] = "无法删除目录: $path";
                }
            } else {
                // 删除旧文件
                if (unlink($path)) {
                    $stats['files_deleted']++;
                } else {
                    $stats['errors'][] = "无法删除文件: $path";
                }
            }
        }
    }

    return [
        'success' => true,
        'message' => "清理完成,删除 {$stats['directories_deleted']} 个目录和 {$stats['files_deleted']} 个文件",
        'stats' => $stats
    ];
}

// 清理临时目录示例
echo "<h4>临时目录清理示例</h4>";

// 创建一些测试临时文件和目录
$tempDir = "/tmp/cleanup_test";
if (!is_dir($tempDir)) {
    mkdir($tempDir, 0755);
}

// 创建一些文件(模拟不同时间的文件)
file_put_contents($tempDir . "/recent.txt", "新文件");
touch($tempDir . "/recent.txt", time() - 3600); // 1小时前

file_put_contents($tempDir . "/old.txt", "旧文件");
touch($tempDir . "/old.txt", time() - 48 * 3600); // 2天前

mkdir($tempDir . "/old_dir", 0755);
touch($tempDir . "/old_dir", time() - 72 * 3600); // 3天前

echo "临时目录内容创建完成: $tempDir<br>";

// 清理超过24小时的旧文件
$result = cleanupTempDirectory($tempDir, 24);
echo $result['message'] . "<br>";

if (count($result['stats']['errors']) > 0) {
    echo "清理错误:<br>";
    foreach ($result['stats']['errors'] as $error) {
        echo "- $error<br>";
    }
}

// 删除测试目录
if (is_dir($tempDir)) {
    deleteDirectory($tempDir);
}
?>

示例5:错误处理和重试机制

<?php
/**
 * 带有错误处理和重试机制的目录删除
 */
class RobustDirectoryRemover {

    /**
     * 安全删除目录,带有重试机制
     */
    public static function robustRemove($dir, $maxRetries = 3, $delayMs = 100) {
        // 验证目录是否存在
        if (!is_dir($dir)) {
            return [
                'success' => false,
                'message' => "目录不存在: $dir",
                'retries' => 0
            ];
        }

        // 检查目录是否可写
        if (!is_writable($dir)) {
            return [
                'success' => false,
                'message' => "目录不可写: $dir",
                'retries' => 0
            ];
        }

        // 尝试删除(带重试)
        $attempt = 0;
        while ($attempt < $maxRetries) {
            $attempt++;

            try {
                // 清除状态缓存
                clearstatcache();

                // 递归删除目录
                if (self::recursiveRemoveWithRetry($dir, $maxRetries, $delayMs)) {
                    return [
                        'success' => true,
                        'message' => "目录删除成功: $dir (尝试次数: $attempt)",
                        'retries' => $attempt
                    ];
                }

                // 如果失败,等待后重试
                if ($attempt < $maxRetries) {
                    usleep($delayMs * 1000);
                }

            } catch (Exception $e) {
                error_log("删除目录时出错 (尝试 $attempt): " . $e->getMessage());

                if ($attempt < $maxRetries) {
                    usleep($delayMs * 1000);
                }
            }
        }

        return [
            'success' => false,
            'message' => "无法删除目录: $dir (最大重试次数: $maxRetries)",
            'retries' => $attempt
        ];
    }

    /**
     * 递归删除目录(带重试)
     */
    private static function recursiveRemoveWithRetry($dir, $maxRetries, $delayMs) {
        if (!is_dir($dir)) {
            return true;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                // 递归删除子目录
                if (!self::recursiveRemoveWithRetry($path, $maxRetries, $delayMs)) {
                    return false;
                }
            } else {
                // 删除文件(带重试)
                if (!self::retryUnlink($path, $maxRetries, $delayMs)) {
                    return false;
                }
            }
        }

        // 删除空目录(带重试)
        return self::retryRmdir($dir, $maxRetries, $delayMs);
    }

    /**
     * 重试删除文件
     */
    private static function retryUnlink($file, $maxRetries, $delayMs) {
        $attempt = 0;

        while ($attempt < $maxRetries) {
            $attempt++;

            if (unlink($file)) {
                return true;
            }

            if ($attempt < $maxRetries) {
                usleep($delayMs * 1000);
                clearstatcache();
            }
        }

        return false;
    }

    /**
     * 重试删除目录
     */
    private static function retryRmdir($dir, $maxRetries, $delayMs) {
        $attempt = 0;

        while ($attempt < $maxRetries) {
            $attempt++;

            if (rmdir($dir)) {
                return true;
            }

            if ($attempt < $maxRetries) {
                usleep($delayMs * 1000);
                clearstatcache();
            }
        }

        return false;
    }

    /**
     * 批量删除目录
     */
    public static function batchRemove(array $dirs, $maxRetries = 3) {
        $results = [];

        foreach ($dirs as $index => $dir) {
            $results[$index] = self::robustRemove($dir, $maxRetries);
        }

        return $results;
    }

    /**
     * 删除目录,但保留某些文件/目录
     */
    public static function removeWithExclusions($dir, $exclusions = []) {
        if (!is_dir($dir)) {
            return false;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            // 检查是否在排除列表中
            if (in_array($item, $exclusions)) {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                if (!self::removeWithExclusions($path, $exclusions)) {
                    return false;
                }
            } else {
                if (!unlink($path)) {
                    return false;
                }
            }
        }

        // 检查目录是否为空(排除排除项)
        $remainingItems = array_diff(scandir($dir), ['.', '..']);
        $remainingItems = array_diff($remainingItems, $exclusions);

        if (empty($remainingItems)) {
            return rmdir($dir);
        }

        return true;
    }
}

// 使用示例
echo "<h4>健壮的目录删除示例</h4>";

// 创建测试目录结构
$testDir = "/tmp/robust_remove_test";
if (!is_dir($testDir)) {
    mkdir($testDir, 0755, true);

    // 创建一些文件和子目录
    for ($i = 1; $i <= 5; $i++) {
        file_put_contents($testDir . "/file{$i}.txt", "文件{$i}内容");
    }

    mkdir($testDir . "/subdir", 0755);
    file_put_contents($testDir . "/subdir/deep.txt", "深层文件");

    echo "测试目录创建完成: $testDir<br>";
}

// 健壮删除
echo "<br>执行健壮删除:<br>";
$result = RobustDirectoryRemover::robustRemove($testDir, 3, 100);

if ($result['success']) {
    echo "删除成功: " . $result['message'] . "<br>";
} else {
    echo "删除失败: " . $result['message'] . "<br>";
}

// 批量删除示例
echo "<br>批量删除示例:<br>";
$dirs = [
    '/tmp/batch1',
    '/tmp/batch2',
    '/tmp/batch3'
];

// 创建测试目录
foreach ($dirs as $dir) {
    if (!is_dir($dir)) {
        mkdir($dir, 0755);
        file_put_contents($dir . "/test.txt", "测试");
    }
}

$batchResults = RobustDirectoryRemover::batchRemove($dirs);
foreach ($batchResults as $index => $result) {
    echo "删除 {$dirs[$index]}: " . ($result['success'] ? '成功' : '失败') . "<br>";
}

// 排除删除示例
echo "<br>排除删除示例:<br>";
$excludeDir = "/tmp/exclude_test";
if (!is_dir($excludeDir)) {
    mkdir($excludeDir, 0755);

    // 创建一些文件和目录
    file_put_contents($excludeDir . "/delete_me.txt", "删除我");
    file_put_contents($excludeDir . "/keep_me.txt", "保留我");
    mkdir($excludeDir . "/delete_dir", 0755);
    mkdir($excludeDir . "/keep_dir", 0755);

    // 删除但保留特定文件/目录
    $exclusions = ['keep_me.txt', 'keep_dir'];
    if (RobustDirectoryRemover::removeWithExclusions($excludeDir, $exclusions)) {
        echo "排除删除执行完成<br>";

        // 检查结果
        $remaining = scandir($excludeDir);
        $remaining = array_diff($remaining, ['.', '..']);

        echo "保留的项目: " . implode(', ', $remaining) . "<br>";

        // 清理
        deleteDirectory($excludeDir);
    }
}
?>

示例6:跨平台目录删除工具

<?php
/**
 * 跨平台的目录删除工具类
 */
class CrossPlatformDirectoryRemover {

    /**
     * 删除目录(处理平台差异)
     */
    public static function remove($dir) {
        $dir = self::normalizePath($dir);

        if (!is_dir($dir)) {
            return false;
        }

        // 递归删除目录内容
        return self::recursiveRemove($dir);
    }

    /**
     * 标准化路径
     */
    private static function normalizePath($path) {
        // 统一路径分隔符
        $path = str_replace('\\', '/', $path);

        // 处理多个连续的路径分隔符
        $path = preg_replace('#/+#', '/', $path);

        return $path;
    }

    /**
     * 递归删除目录
     */
    private static function recursiveRemove($dir) {
        if (!is_dir($dir)) {
            return false;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                if (!self::recursiveRemove($path)) {
                    return false;
                }
            } else {
                if (!unlink($path)) {
                    return false;
                }
            }
        }

        return rmdir($dir);
    }

    /**
     * 删除目录但保留结构(只删除文件)
     */
    public static function removeFilesOnly($dir) {
        if (!is_dir($dir)) {
            return false;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                // 递归处理子目录
                self::removeFilesOnly($path);
            } else {
                // 只删除文件
                unlink($path);
            }
        }

        return true;
    }

    /**
     * 删除空目录(清理空目录结构)
     */
    public static function removeEmptyDirectories($dir) {
        if (!is_dir($dir)) {
            return false;
        }

        $items = scandir($dir);
        if ($items === false) {
            return false;
        }

        $hasContent = false;

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                // 递归处理子目录
                if (self::removeEmptyDirectories($path)) {
                    // 子目录被删除,继续检查
                } else {
                    $hasContent = true;
                }
            } else {
                $hasContent = true;
            }
        }

        // 如果目录没有内容,删除它
        if (!$hasContent) {
            return rmdir($dir);
        }

        return false;
    }

    /**
     * 获取目录大小后删除
     */
    public static function removeWithSizeCheck($dir, $maxSizeMB = null) {
        if (!is_dir($dir)) {
            return [
                'success' => false,
                'message' => "目录不存在: $dir",
                'size_before' => 0
            ];
        }

        // 计算目录大小
        $size = self::getDirectorySize($dir);
        $sizeMB = round($size / (1024 * 1024), 2);

        // 检查大小限制
        if ($maxSizeMB !== null && $sizeMB > $maxSizeMB) {
            return [
                'success' => false,
                'message' => "目录大小 {$sizeMB}MB 超过限制 {$maxSizeMB}MB",
                'size_before' => $sizeMB
            ];
        }

        // 删除目录
        if (self::remove($dir)) {
            return [
                'success' => true,
                'message' => "目录删除成功,释放 {$sizeMB}MB 空间",
                'size_before' => $sizeMB
            ];
        } else {
            return [
                'success' => false,
                'message' => "目录删除失败",
                'size_before' => $sizeMB
            ];
        }
    }

    /**
     * 计算目录大小
     */
    private static function getDirectorySize($dir) {
        $size = 0;

        if (!is_dir($dir)) {
            return $size;
        }

        $items = scandir($dir);
        if ($items === false) {
            return $size;
        }

        foreach ($items as $item) {
            if ($item === '.' || $item === '..') {
                continue;
            }

            $path = $dir . '/' . $item;

            if (is_dir($path)) {
                $size += self::getDirectorySize($path);
            } else {
                $size += filesize($path);
            }
        }

        return $size;
    }
}

// 使用示例
echo "<h4>跨平台目录删除示例</h4>";

// 1. 基本删除
$testDir1 = "/tmp/cross_test1";
if (!is_dir($testDir1)) {
    mkdir($testDir1, 0755, true);
    file_put_contents($testDir1 . "/test.txt", "测试内容");
}

$result1 = CrossPlatformDirectoryRemover::remove($testDir1);
echo "基本删除: " . ($result1 ? '成功' : '失败') . "<br>";

// 2. 只删除文件
$testDir2 = "/tmp/cross_test2";
if (!is_dir($testDir2)) {
    mkdir($testDir2, 0755, true);
    file_put_contents($testDir2 . "/file1.txt", "文件1");
    file_put_contents($testDir2 . "/file2.txt", "文件2");
    mkdir($testDir2 . "/subdir", 0755);
    file_put_contents($testDir2 . "/subdir/file3.txt", "文件3");
}

$result2 = CrossPlatformDirectoryRemover::removeFilesOnly($testDir2);
echo "只删除文件: " . ($result2 ? '成功' : '失败') . "<br>";

// 检查结果
if (is_dir($testDir2)) {
    $items = scandir($testDir2);
    $items = array_diff($items, ['.', '..']);
    echo "保留的目录结构: " . count($items) . " 个项目<br>";

    // 清理
    CrossPlatformDirectoryRemover::remove($testDir2);
}

// 3. 删除空目录
$testDir3 = "/tmp/cross_test3";
if (!is_dir($testDir3)) {
    mkdir($testDir3 . "/level1/level2/level3", 0755, true);
    // 只创建空目录结构
}

// 在level2创建一个文件
file_put_contents($testDir3 . "/level1/level2/test.txt", "测试文件");

$result3 = CrossPlatformDirectoryRemover::removeEmptyDirectories($testDir3);
echo "删除空目录: 执行完成<br>";

// 检查哪些目录被删除
echo "检查目录结构:<br>";
function checkDir($dir, $indent = '') {
    if (is_dir($dir)) {
        echo $indent . basename($dir) . "/<br>";
        $items = scandir($dir);
        foreach ($items as $item) {
            if ($item !== '.' && $item !== '..') {
                checkDir($dir . '/' . $item, $indent . '  ');
            }
        }
    } else {
        echo $indent . basename($dir) . "<br>";
    }
}

checkDir($testDir3);

// 清理
CrossPlatformDirectoryRemover::remove($testDir3);

// 4. 带大小检查的删除
$testDir4 = "/tmp/cross_test4";
if (!is_dir($testDir4)) {
    mkdir($testDir4, 0755, true);

    // 创建一个大文件
    $fp = fopen($testDir4 . "/bigfile.txt", 'w');
    for ($i = 0; $i < 10000; $i++) {
        fwrite($fp, str_repeat('x', 1024)); // 写入10MB数据
    }
    fclose($fp);
}

$result4 = CrossPlatformDirectoryRemover::removeWithSizeCheck($testDir4, 5); // 限制5MB
echo "<br>带大小检查的删除: " . $result4['message'] . "<br>";

if (!$result4['success']) {
    // 如果因为大小限制失败,手动删除
    CrossPlatformDirectoryRemover::remove($testDir4);
}
?>

rmdir() 常见错误代码

错误现象 可能原因 解决方法
Warning: rmdir(): Permission denied PHP进程没有删除目录的权限 检查目录权限,确保PHP进程有写入权限
Warning: rmdir(): Directory not empty 目录不为空,包含文件或子目录 先递归删除目录中的所有内容
Warning: rmdir(): No such file or directory 目录不存在或路径错误 使用 is_dir() 检查目录是否存在
Warning: rmdir(): Operation not permitted 目录正在被使用或受保护 检查目录是否被其他进程锁定,或是否为系统目录
符号链接问题 路径指向符号链接 使用 is_link() 检查,unlink() 删除符号链接
跨设备删除失败 目录跨越不同文件系统 确保递归删除时不会跨越挂载点

最佳实践

  1. 检查目录是否存在:删除前使用 is_dir() 检查,避免不必要的错误
  2. 确保目录为空:rmdir() 只能删除空目录,非空目录需要先递归删除内容
  3. 处理权限问题:确保PHP进程有删除目录的权限
  4. 错误处理:始终检查 rmdir() 的返回值,并提供有意义的错误信息
  5. 备份重要数据:删除重要目录前,考虑先进行备份
  6. 防止误删:在处理用户输入或动态路径时,进行严格的验证
  7. 考虑并发访问:在多进程/多线程环境中,确保目录不被其他进程使用
  8. 平台兼容性:编写跨平台代码时,注意路径分隔符和权限处理的差异

性能优化技巧

批量删除优化

当需要删除多个目录时,按深度逆序排序,先删除最深的目录,可以减少递归调用的开销。

异步删除

对于大型目录的删除,考虑使用队列或异步任务,避免阻塞主进程。

进度反馈

删除大型目录时,提供进度反馈,让用户知道操作正在进行。

选择性删除

只删除需要的内容,避免不必要的文件系统操作。

相关函数