
本教程旨在解决使用 php `ssh2` 扩展通过 sftp 下载文件时,本地文件为空的问题。文章将详细阐述数据流传输的正确方法,包括使用 `stream_copy_to_stream` 进行数据复制,并介绍更简洁高效的 `ssh2_scp_recv` 替代方案,帮助开发者实现可靠的文件下载功能。
在开发需要与远程服务器进行文件交互的应用程序时,安全地传输文件是一项常见需求。PHP 的 ssh2 扩展为 SSH 和 SFTP 操作提供了强大的功能。然而,在使用 SFTP 下载文件时,一个常见的陷阱是最终得到的本地文件内容为空。本教程将深入探讨导致此问题的根本原因,并提供两种有效的解决方案,以确保文件传输的成功与高效。
问题的核心在于文件处理流程的不完整。当开发者使用 fopen 结合 ssh2.sftp:// URI 打开远程文件以供读取,并随后再次使用 fopen 创建一个本地文件以供写入时,往往会忽略一个关键步骤:在两个已打开的流之间进行数据传输。仅仅打开一个远程流和一个本地流,然后关闭远程流,并不会自动复制文件内容。数据必须明确地从源流中读取,并写入到目标流中。
为了正确地将远程文件内容复制到本地文件,我们需要利用 PHP 的流处理功能。stream_copy_to_stream() 函数专门用于在两个已打开的流之间复制所有剩余的数据,是解决此问题的直接且可靠的方法。
实现步骤:
立即学习“PHP免费学习笔记(深入)”;
示例代码:
<?php
$server_ip = '{你的服务器IP}';
$username = '{你的用户名}';
$password = '{你的密码}';
$remote_file_path = '/public_html/test.txt'; // 远程文件在SFTP服务器上的路径
$local_file_name = 'downloaded_test.txt'; // 本地保存的文件名
// 1. 建立 SSH 连接
$connection = ssh2_connect($server_ip, 22);
if (!$connection) {
die('错误:无法建立 SSH 连接。');
}
// 2. 身份验证
if (!ssh2_auth_password($connection, $username, $password)) {
die('错误:SSH 身份验证失败。');
}
// 3. 初始化 SFTP 子系统
$sftp = ssh2_sftp($connection);
if (!$sftp) {
die('错误:无法初始化 SFTP 子系统。');
}
// 4. 构建远程文件 URI
$target_path = "ssh2.sftp://$sftp" . $remote_file_path;
// 5. 打开远程 SFTP 文件流
$remote_stream = fopen($target_path, 'r');
if (!$remote_stream) {
die("错误:无法打开远程 SFTP 文件流:'$target_path'。");
}
// 6. 打开本地文件流
$local_stream = fopen($local_file_name, 'w');
if (!$local_stream) {
fclose($remote_stream); // 确保在出错时关闭已打开的远程流
die("错误:无法打开本地文件流:'$local_file_name'。请检查目录权限。");
}
// 7. 复制数据
if (stream_copy_to_stream($remote_stream, $local_stream)) {
echo "成功:文件 '$remote_file_path' 已下载并保存为 '$local_file_name'。\n";
} else {
echo "错误:文件复制失败。\n";
}
// 8. 关闭所有流
fclose($local_stream);
fclose($remote_stream);
// SSH 连接在脚本结束时通常会自动关闭。
// 对于 ssh2 扩展,通常不需要显式调用 ssh2_disconnect,除非需要立即释放资源。
?>如果您的服务器同时支持 SCP(Secure Copy Protocol),那么 ssh2 扩展提供了一个更为简洁高效的函数 ssh2_scp_recv()。SCP 通常与 SFTP 同时存在,并且在某些场景下,它的实现可能更直接。ssh2_scp_recv() 函数能够一步完成从远程服务器复制文件到本地的操作,极大地简化了代码。
ssh2_scp_recv() 函数签名:
bool ssh2_scp_recv ( resource $connection , string $remote_file , string $local_file )
参数说明:
示例代码:
<?php
$server_ip = '{你的服务器IP}';
$username = '{你的用户名}';
$password = '{你的密码}';
$remote_file_path = '/public_html/test.txt'; // 远程文件在SFTP服务器上的路径
$local_file_name = 'downloaded_test_scp.txt'; // 本地保存的文件名
// 1. 建立 SSH 连接
$connection = ssh2_connect($server_ip, 22);
if (!$connection) {
die('错误:无法建立 SSH 连接。');
}
// 2. 身份验证
if (!ssh2_auth_password($connection, $username, $password)) {
die('错误:SSH 身份验证失败。');
}
// 3. 使用 ssh2_scp_recv 直接下载文件
if (ssh2_scp_recv($connection, $remote_file_path, $local_file_name)) {
echo "成功:文件 '$remote_file_path' 已通过 SCP 下载并保存为 '$local_file_name'。\n";
} else {
echo "错误:通过 SCP 下载文件失败。\n";
}
// SSH 连接在脚本结束时通常会自动关闭。
?>在实现 SFTP 文件下载功能时,除了核心逻辑,还需要考虑以下几点以确保系统的健壮性和安全性:
通过本教程,我们深入探讨了 PHP 中使用 ssh2 扩展从 SFTP 服务器下载文件时遇到的“空文件”问题,并提供了两种有效的解决方案。无论是通过 stream_copy_to_stream 进行精细的流数据传输,还是利用 ssh2_scp_recv 实现一步到位的简洁下载,关键在于理解数据传输的必要性。遵循最佳实践,包括严谨的错误处理、资源管理和安全措施,将帮助您构建稳定、可靠的 PHP SFTP 文件传输功能。选择哪种方法取决于您的具体需求和服务器支持情况,但两种方法都能确保文件内容完整无缺地传输到本地。
以上就是PHP SFTP 文件下载教程:避免空文件并优化传输的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号