PHP ftp_delete() 函数

ftp_delete() 函数用于删除FTP服务器上的一个文件。

警告:此操作不可逆!删除的文件无法通过FTP恢复,请谨慎使用。

语法

ftp_delete(resource $ftp_stream, string $remote_file): bool

参数说明

参数 描述
$ftp_stream 必需。FTP连接的资源标识符,由ftp_connect()ftp_ssl_connect()函数返回。
$remote_file 必需。要删除的远程文件的路径。

返回值

  • 成功时返回 true
  • 失败时返回 false

示例

示例1:基本使用

删除FTP服务器上的一个文件:

<?php
// FTP服务器信息
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";

// 建立FTP连接
$conn_id = ftp_connect($ftp_server);
if ($conn_id === false) {
    die("无法连接到FTP服务器");
}

// 登录FTP服务器
if (!ftp_login($conn_id, $ftp_user, $ftp_pass)) {
    ftp_close($conn_id);
    die("FTP登录失败");
}

// 要删除的文件
$remote_file = "public_html/old_file.txt";

// 检查文件是否存在
if (ftp_size($conn_id, $remote_file) != -1) {
    echo "找到文件: {$remote_file}\n";

    // 删除文件
    if (ftp_delete($conn_id, $remote_file)) {
        echo "文件删除成功\n";
    } else {
        echo "文件删除失败\n";
        // 可能是权限问题或文件被锁定
    }
} else {
    echo "文件不存在: {$remote_file}\n";
}

// 关闭连接
ftp_close($conn_id);
?>

示例2:安全删除(带确认)

<?php
/**
 * 安全删除FTP文件(带确认机制)
 */
function safeFtpDelete($ftp_conn, $remote_file, $require_confirmation = true) {
    // 检查连接是否有效
    if (!is_resource($ftp_conn)) {
        throw new Exception("无效的FTP连接");
    }

    // 检查文件是否存在
    $file_size = ftp_size($ftp_conn, $remote_file);
    if ($file_size == -1) {
        throw new Exception("文件不存在: {$remote_file}");
    }

    // 获取文件信息
    $file_info = [];
    $raw_list = ftp_rawlist($ftp_conn, $remote_file);
    if (!empty($raw_list)) {
        $file_info = $raw_list[0];
    }

    // 显示文件信息
    echo "=== 文件删除确认 ===\n";
    echo "文件路径: {$remote_file}\n";
    echo "文件大小: " . formatBytes($file_size) . "\n";
    echo "文件信息: {$file_info}\n";

    // 如果需要确认
    if ($require_confirmation) {
        echo "确认删除?(输入 'yes' 确认): ";
        $handle = fopen("php://stdin", "r");
        $confirm = trim(fgets($handle));
        fclose($handle);

        if (strtolower($confirm) !== 'yes') {
            echo "操作取消\n";
            return false;
        }
    }

    // 执行删除
    if (ftp_delete($ftp_conn, $remote_file)) {
        echo "文件删除成功\n";
        return true;
    } else {
        throw new Exception("删除操作失败,可能是权限不足");
    }
}

// 辅助函数:格式化文件大小
function formatBytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= pow(1024, $pow);
    return round($bytes, $precision) . ' ' . $units[$pow];
}

// 使用示例
$conn = ftp_connect("ftp.example.com");
if ($conn && ftp_login($conn, "user", "pass")) {
    try {
        safeFtpDelete($conn, "public_html/test_file.txt", true);
    } catch (Exception $e) {
        echo "错误: " . $e->getMessage() . "\n";
    }
    ftp_close($conn);
}
?>

示例3:批量删除文件

<?php
/**
 * 批量删除匹配特定模式的文件
 */
function batchDeleteFiles($ftp_conn, $directory, $pattern = null, $recursive = false) {
    $deleted_count = 0;
    $failed_count = 0;

    // 获取文件列表
    $files = ftp_nlist($ftp_conn, $directory);
    if ($files === false) {
        throw new Exception("无法读取目录: {$directory}");
    }

    foreach ($files as $file) {
        $remote_path = $directory . '/' . basename($file);

        // 跳过当前目录和上级目录
        if ($file == '.' || $file == '..') {
            continue;
        }

        // 检查是否为目录
        $is_dir = (ftp_size($ftp_conn, $remote_path) == -1 && ftp_rawlist($ftp_conn, $remote_path) !== false);

        if ($is_dir && $recursive) {
            // 递归处理子目录
            $result = batchDeleteFiles($ftp_conn, $remote_path, $pattern, true);
            $deleted_count += $result['deleted'];
            $failed_count += $result['failed'];

            // 可选:删除空目录
            // ftp_rmdir($ftp_conn, $remote_path);

        } elseif (!$is_dir) {
            // 检查是否匹配模式
            $should_delete = true;
            if ($pattern) {
                $should_delete = fnmatch($pattern, basename($file));
            }

            if ($should_delete) {
                echo "删除文件: {$remote_path}\n";

                if (ftp_delete($ftp_conn, $remote_path)) {
                    $deleted_count++;
                    echo "  成功\n";
                } else {
                    $failed_count++;
                    echo "  失败\n";
                }
            }
        }
    }

    return [
        'deleted' => $deleted_count,
        'failed' => $failed_count
    ];
}

// 使用示例
$conn = ftp_connect("ftp.example.com");
if ($conn && ftp_login($conn, "user", "pass")) {
    try {
        // 删除所有临时文件
        echo "删除临时文件...\n";
        $result = batchDeleteFiles($conn, "public_html/temp", "*.tmp");
        echo "删除完成: {$result['deleted']} 个文件成功,{$result['failed']} 个文件失败\n";

        // 删除所有日志文件(递归)
        echo "\n删除日志文件...\n";
        $result = batchDeleteFiles($conn, "public_html", "*.log", true);
        echo "删除完成: {$result['deleted']} 个文件成功,{$result['failed']} 个文件失败\n";

    } catch (Exception $e) {
        echo "错误: " . $e->getMessage() . "\n";
    }
    ftp_close($conn);
}
?>

示例4:删除前备份文件

<?php
/**
 * 安全删除文件(先备份到本地)
 */
function backupAndDelete($ftp_conn, $remote_file, $local_backup_dir = null) {
    // 如果没有指定本地备份目录,使用临时目录
    if ($local_backup_dir === null) {
        $local_backup_dir = sys_get_temp_dir() . '/ftp_backups/';
    }

    // 创建备份目录
    if (!is_dir($local_backup_dir) && !mkdir($local_backup_dir, 0755, true)) {
        throw new Exception("无法创建备份目录: {$local_backup_dir}");
    }

    // 生成备份文件名
    $timestamp = date('Ymd_His');
    $filename = basename($remote_file);
    $backup_file = $local_backup_dir . $timestamp . '_' . $filename;

    echo "开始备份文件: {$remote_file}\n";

    // 下载文件到本地备份
    if (ftp_get($ftp_conn, $backup_file, $remote_file, FTP_BINARY)) {
        echo "备份成功: {$backup_file}\n";
        echo "文件大小: " . filesize($backup_file) . " 字节\n";

        // 验证备份文件
        if (filesize($backup_file) > 0) {
            // 删除远程文件
            if (ftp_delete($ftp_conn, $remote_file)) {
                echo "远程文件删除成功\n";
                return [
                    'success' => true,
                    'backup_path' => $backup_file,
                    'message' => '文件已备份并删除'
                ];
            } else {
                // 删除失败,保留备份但记录警告
                echo "警告: 远程文件删除失败,但备份已创建\n";
                return [
                    'success' => false,
                    'backup_path' => $backup_file,
                    'message' => '备份成功但删除失败'
                ];
            }
        } else {
            unlink($backup_file); // 删除无效的备份文件
            throw new Exception("备份文件无效(大小为0)");
        }
    } else {
        throw new Exception("备份失败,无法下载文件");
    }
}

// 使用示例
$conn = ftp_connect("ftp.example.com");
if ($conn && ftp_login($conn, "user", "pass")) {
    try {
        $result = backupAndDelete($conn, "public_html/important_file.txt", "/var/backups/ftp/");

        if ($result['success']) {
            echo "操作成功完成\n";
            echo "备份位置: {$result['backup_path']}\n";
        } else {
            echo "操作部分成功: {$result['message']}\n";
            echo "备份位置: {$result['backup_path']}\n";
        }

    } catch (Exception $e) {
        echo "错误: " . $e->getMessage() . "\n";
    }
    ftp_close($conn);
}
?>

示例5:Web界面文件删除

<?php
// Web界面文件删除示例
session_start();

// 模拟FTP配置(实际应从安全配置中读取)
$ftp_config = [
    'server' => 'ftp.example.com',
    'username' => 'webadmin',
    'password' => 'secure_password',
    'root_dir' => '/public_html/'
];

// 处理删除请求
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete') {
    $file_to_delete = isset($_POST['file_path']) ? $_POST['file_path'] : '';

    if (!empty($file_to_delete)) {
        // 安全检查:防止目录遍历攻击
        $file_to_delete = basename($file_to_delete);
        $full_path = $ftp_config['root_dir'] . $file_to_delete;

        $conn = ftp_connect($ftp_config['server']);
        if ($conn && ftp_login($conn, $ftp_config['username'], $ftp_config['password'])) {
            // 验证文件存在且不是目录
            $file_size = ftp_size($conn, $full_path);
            if ($file_size != -1) {
                if (ftp_delete($conn, $full_path)) {
                    $_SESSION['message'] = [
                        'type' => 'success',
                        'text' => "文件 '{$file_to_delete}' 删除成功"
                    ];
                } else {
                    $_SESSION['message'] = [
                        'type' => 'danger',
                        'text' => "文件删除失败"
                    ];
                }
            } else {
                $_SESSION['message'] = [
                    'type' => 'warning',
                    'text' => "文件不存在或无法访问"
                ];
            }
            ftp_close($conn);
        } else {
            $_SESSION['message'] = [
                'type' => 'danger',
                'text' => "FTP连接失败"
            ];
        }
    }

    header('Location: ' . $_SERVER['PHP_SELF']);
    exit;
}

// 获取文件列表
$file_list = [];
$conn = ftp_connect($ftp_config['server']);
if ($conn && ftp_login($conn, $ftp_config['username'], $ftp_config['password'])) {
    $files = ftp_nlist($conn, $ftp_config['root_dir']);
    if ($files !== false) {
        foreach ($files as $file) {
            $filename = basename($file);
            // 只显示文件,不显示目录
            if ($filename != '.' && $filename != '..') {
                $file_size = ftp_size($conn, $ftp_config['root_dir'] . $filename);
                if ($file_size != -1) { // -1 表示可能是目录
                    $file_list[] = [
                        'name' => $filename,
                        'size' => $file_size,
                        'formatted_size' => formatFileSize($file_size)
                    ];
                }
            }
        }
    }
    ftp_close($conn);
}

// 辅助函数:格式化文件大小
function formatFileSize($bytes) {
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' 字节';
    }
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FTP文件管理器</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
    <div class="container mt-4">
        <h1 class="mb-4">FTP文件管理器</h1>

        <?php if (isset($_SESSION['message'])): ?>
            <div class="alert alert-<?php echo $_SESSION['message']['type']; ?>">
                <?php echo $_SESSION['message']['text']; ?>
            </div>
            <?php unset($_SESSION['message']); ?>
        <?php endif; ?>

        <div class="card">
            <div class="card-header">
                <h5 class="mb-0">文件列表</h5>
            </div>
            <div class="card-body">
                <?php if (empty($file_list)): ?>
                    <p class="text-muted">没有找到文件</p>
                <?php else: ?>
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>文件名</th>
                                    <th>大小</th>
                                    <th>操作</th>
                                </tr>
                            </thead>
                            <tbody>
                                <?php foreach ($file_list as $file): ?>
                                    <tr>
                                        <td><i class="fas fa-file me-2"></i> <?php echo htmlspecialchars($file['name']); ?></td>
                                        <td><?php echo $file['formatted_size']; ?></td>
                                        <td>
                                            <button type="button" class="btn btn-sm btn-danger delete-btn"
                                                    data-filename="<?php echo htmlspecialchars($file['name']); ?>">
                                                <i class="fas fa-trash me-1"></i>删除
                                            </button>
                                        </td>
                                    </tr>
                                <?php endforeach; ?>
                            </tbody>
                        </table>
                    </div>
                <?php endif; ?>
            </div>
        </div>

        <!-- 删除确认模态框 -->
        <div class="modal fade" id="deleteModal" tabindex="-1">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">确认删除</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body">
                        <p>确定要删除文件 <span id="filenameToDelete" class="fw-bold"></span> 吗?</p>
                        <p class="text-danger"><i class="fas fa-exclamation-triangle me-1"></i>此操作不可恢复!</p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                        <form method="post" style="display: inline;">
                            <input type="hidden" name="action" value="delete">
                            <input type="hidden" name="file_path" id="deleteFilePath">
                            <button type="submit" class="btn btn-danger">确认删除</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 删除按钮点击事件
            document.querySelectorAll('.delete-btn').forEach(function(btn) {
                btn.addEventListener('click', function() {
                    var filename = this.dataset.filename;
                    document.getElementById('filenameToDelete').textContent = filename;
                    document.getElementById('deleteFilePath').value = filename;

                    var modal = new bootstrap.Modal(document.getElementById('deleteModal'));
                    modal.show();
                });
            });
        });
    </script>
</body>
</html>

注意事项

重要安全警告:

  • ftp_delete() 删除的文件无法通过FTP恢复
  • 确保你有删除文件的权限
  • 避免在生产环境中直接删除关键文件
  • 考虑在删除前备份重要文件
  • 验证文件路径,防止目录遍历攻击
  • 不要删除FTP服务器的系统文件或目录

常见错误及解决方案

错误现象 可能原因 解决方案
删除失败,返回false 文件不存在、权限不足、文件被锁定 检查文件是否存在,确认用户权限,检查文件是否被其他进程使用
删除成功但文件仍在 FTP缓存、权限问题、服务器配置 刷新FTP列表,检查服务器权限设置,联系服务器管理员
误删重要文件 路径错误、脚本逻辑错误 立即停止脚本,检查服务器备份,联系系统管理员
无法删除目录 ftp_delete()只能删除文件 使用ftp_rmdir()删除空目录,先删除目录内所有文件

相关函数

函数 描述
ftp_get() 从FTP服务器下载文件
ftp_put() 上传文件到FTP服务器
ftp_rename() 重命名FTP服务器上的文件或目录
ftp_rmdir() 删除FTP服务器上的空目录
unlink() 删除本地文件
最佳实践:
  • 在删除前始终检查文件是否存在(使用ftp_size()ftp_nlist()
  • 为重要文件实现删除确认机制
  • 考虑在删除前备份文件到本地
  • 记录所有删除操作(时间、文件、操作用户)
  • 在生产环境中限制删除操作的权限
  • 定期清理不需要的备份文件