PHP ftp_close() 函数

ftp_close() 函数关闭一个已打开的FTP连接并释放相关的资源。

注意:在PHP 4.3.0及更高版本中,可以使用ftp_close()函数,但在PHP 7.0.0及更高版本中,该函数已被ftp_quit()函数作为别名保留。

语法

ftp_close(resource $ftp_stream): bool

参数说明

参数 描述
$ftp_stream 必需。FTP连接的资源标识符,由ftp_connect()ftp_ssl_connect()函数返回。

返回值

  • 成功时返回 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) === false) {
    die("FTP登录失败");
}

echo "FTP连接成功,已登录到服务器\n";

// 执行一些FTP操作
$file_list = ftp_nlist($conn_id, ".");
if ($file_list !== false) {
    echo "当前目录文件列表:\n";
    foreach ($file_list as $file) {
        echo "- $file\n";
    }
}

// 关闭FTP连接
if (ftp_close($conn_id)) {
    echo "FTP连接已成功关闭\n";
} else {
    echo "关闭FTP连接失败\n";
}

// 尝试使用已关闭的连接
// 这会生成警告,因为连接已关闭
// ftp_nlist($conn_id, "."); // 不要取消注释,会出错
?>

示例2:使用SSL安全连接

<?php
// 使用SSL安全连接
$ftp_server = "ftp.example.com";
$ftp_user = "username";
$ftp_pass = "password";

// 建立SSL FTP连接
$conn_id = ftp_ssl_connect($ftp_server);
if ($conn_id === false) {
    die("无法建立SSL FTP连接");
}

// 登录
if (ftp_login($conn_id, $ftp_user, $ftp_pass) === false) {
    ftp_close($conn_id); // 登录失败也关闭连接
    die("SSL FTP登录失败");
}

echo "SSL FTP连接成功\n";

// 上传文件
$local_file = "localfile.txt";
$remote_file = "remotefile.txt";

if (ftp_put($conn_id, $remote_file, $local_file, FTP_BINARY)) {
    echo "文件上传成功\n";
} else {
    echo "文件上传失败\n";
}

// 关闭SSL FTP连接
if (ftp_close($conn_id)) {
    echo "SSL FTP连接已关闭\n";
}
?>

示例3:使用try-catch进行错误处理

<?php
// 使用错误处理
function ftpOperationWithCleanup($server, $user, $pass) {
    $conn_id = null;

    try {
        // 建立连接
        $conn_id = ftp_connect($server);
        if ($conn_id === false) {
            throw new Exception("无法连接到FTP服务器: $server");
        }

        // 登录
        if (ftp_login($conn_id, $user, $pass) === false) {
            throw new Exception("FTP登录失败");
        }

        echo "FTP操作开始...\n";

        // 执行一些操作
        // ...

        // 模拟一个可能出错的操作
        $result = ftp_chdir($conn_id, "/nonexistent/directory");
        if ($result === false) {
            throw new Exception("无法更改目录");
        }

        return true;

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

    } finally {
        // 无论是否出错,都确保关闭连接
        if ($conn_id !== null && is_resource($conn_id)) {
            if (ftp_close($conn_id)) {
                echo "FTP连接已在finally块中关闭\n";
            }
        }
    }
}

// 使用示例
ftpOperationWithCleanup("ftp.example.com", "username", "password");
?>

示例4:连接池管理

<?php
// 简单的FTP连接管理器
class FTPConnectionManager {
    private $connections = [];

    // 获取连接
    public function getConnection($server, $user, $pass) {
        $key = md5($server . $user);

        if (!isset($this->connections[$key])) {
            $conn = ftp_connect($server);
            if ($conn === false) {
                throw new Exception("无法连接到FTP服务器");
            }

            if (!ftp_login($conn, $user, $pass)) {
                ftp_close($conn);
                throw new Exception("FTP登录失败");
            }

            $this->connections[$key] = $conn;
            echo "创建新的FTP连接\n";
        }

        return $this->connections[$key];
    }

    // 关闭所有连接
    public function closeAllConnections() {
        foreach ($this->connections as $key => $conn) {
            if (is_resource($conn)) {
                ftp_close($conn);
                echo "关闭连接: $key\n";
            }
            unset($this->connections[$key]);
        }
        echo "所有FTP连接已关闭\n";
    }

    // 关闭单个连接
    public function closeConnection($server, $user) {
        $key = md5($server . $user);

        if (isset($this->connections[$key])) {
            if (is_resource($this->connections[$key])) {
                ftp_close($this->connections[$key]);
                echo "关闭连接: $key\n";
            }
            unset($this->connections[$key]);
            return true;
        }

        return false;
    }

    // 析构函数:自动关闭所有连接
    public function __destruct() {
        $this->closeAllConnections();
    }
}

// 使用示例
$ftpManager = new FTPConnectionManager();

try {
    // 获取并使用连接
    $conn1 = $ftpManager->getConnection("ftp1.example.com", "user1", "pass1");
    ftp_chdir($conn1, "/public_html");

    $conn2 = $ftpManager->getConnection("ftp2.example.com", "user2", "pass2");
    ftp_nlist($conn2, ".");

    // 关闭特定连接
    $ftpManager->closeConnection("ftp1.example.com", "user1");

    // 使用另一个连接
    $conn3 = $ftpManager->getConnection("ftp1.example.com", "user1", "pass1"); // 会创建新连接

} catch (Exception $e) {
    echo "操作失败: " . $e->getMessage() . "\n";
}

// 对象销毁时会自动关闭所有连接
?>

示例5:自动化FTP任务

<?php
// 自动备份网站到FTP服务器
function backupToFTP($local_dir, $ftp_server, $ftp_user, $ftp_pass, $remote_dir) {
    $conn_id = ftp_connect($ftp_server);
    if ($conn_id === false) {
        return ["success" => false, "message" => "无法连接到FTP服务器"];
    }

    if (!ftp_login($conn_id, $ftp_user, $ftp_pass)) {
        ftp_close($conn_id);
        return ["success" => false, "message" => "FTP登录失败"];
    }

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

    // 检查远程目录是否存在,不存在则创建
    if (!@ftp_chdir($conn_id, $remote_dir)) {
        // 创建目录
        ftp_mkdir($conn_id, $remote_dir);
        ftp_chdir($conn_id, $remote_dir);
    }

    $backup_files = [];

    // 遍历本地目录并上传文件
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($local_dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($iterator as $item) {
        $local_path = $item->getPathname();
        $relative_path = substr($local_path, strlen($local_dir) + 1);
        $remote_path = $relative_path;

        if ($item->isDir()) {
            // 创建远程目录
            @ftp_mkdir($conn_id, $remote_path);
        } else {
            // 上传文件
            if (ftp_put($conn_id, $remote_path, $local_path, FTP_BINARY)) {
                $backup_files[] = $relative_path;
            }
        }
    }

    // 记录备份信息
    $backup_info = [
        'timestamp' => date('Y-m-d H:i:s'),
        'files_count' => count($backup_files),
        'files' => $backup_files
    ];

    $info_file = "backup_info_" . date('Ymd_His') . ".json";
    $temp_file = tempnam(sys_get_temp_dir(), 'ftp_');
    file_put_contents($temp_file, json_encode($backup_info, JSON_PRETTY_PRINT));
    ftp_put($conn_id, $info_file, $temp_file, FTP_BINARY);
    unlink($temp_file);

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

    return [
        "success" => true,
        "message" => "备份完成",
        "files_count" => count($backup_files),
        "info_file" => $info_file
    ];
}

// 使用示例
$result = backupToFTP(
    "/var/www/html",
    "backup.example.com",
    "backupuser",
    "backuppass",
    "/backups/" . date('Y-m-d')
);

if ($result['success']) {
    echo "备份成功!上传了{$result['files_count']}个文件\n";
    echo "备份信息文件: {$result['info_file']}\n";
} else {
    echo "备份失败: {$result['message']}\n";
}
?>

注意事项

重要提示:

  • 关闭连接后,不能再次使用该连接资源
  • PHP脚本执行结束后会自动关闭所有打开的连接,但显式关闭是良好的编程习惯
  • 使用ftp_ssl_connect()建立的SSL连接也使用ftp_close()关闭
  • 在长时间运行的脚本中(如守护进程),及时关闭连接可以避免资源泄漏
  • 使用is_resource($ftp_connection)可以检查连接是否仍然有效

常见问题

在PHP中,ftp_close()ftp_quit()是完全相同的函数。ftp_quit()ftp_close()的别名,两者功能完全一样,可以互换使用。

// 两者功能相同
ftp_close($conn);
ftp_quit($conn); // 别名

  • 资源泄漏:每个未关闭的连接都会占用服务器资源
  • 连接数限制:FTP服务器通常有最大连接数限制
  • 性能问题:大量未关闭的连接会影响服务器性能
  • 安全风险:未授权的连接保持打开状态可能带来安全风险
  • 脚本超时:在某些配置下,未关闭的连接可能导致脚本执行超时

<?php
function isFtpConnectionValid($ftp_conn) {
    // 检查是否是资源类型
    if (!is_resource($ftp_conn)) {
        return false;
    }

    // 尝试执行一个简单的命令
    try {
        $result = @ftp_pwd($ftp_conn);
        return $result !== false;
    } catch (Exception $e) {
        return false;
    }
}

// 使用示例
if (isFtpConnectionValid($conn_id)) {
    echo "连接有效\n";
    // 执行操作
    ftp_close($conn_id); // 使用后关闭
} else {
    echo "连接无效或已关闭\n";
}
?>

相关函数

函数 描述
ftp_connect() 建立FTP连接
ftp_ssl_connect() 建立SSL-FTP连接
ftp_login() 登录FTP服务器
ftp_pasv() 开启或关闭被动模式
ftp_quit() ftp_close()的别名
最佳实践:
  • 始终在完成FTP操作后关闭连接
  • 使用try-catch-finally结构确保连接总是被关闭
  • 对于长时间运行的脚本,考虑使用连接池管理
  • 在类中使用析构函数自动关闭连接
  • 定期检查并清理无效的连接