
本文旨在解决php使用`ssh2`扩展通过`ssh2.sftp://` uri从sftp服务器下载文件时,本地文件为空的问题。文章将详细解释导致此问题的原因,并提供两种有效的解决方案:一是利用`stream_copy_to_stream`函数进行流数据复制,二是推荐使用更简洁高效的`ssh2_scp_recv`函数(若服务器支持scp),确保文件内容能够正确传输到本地。
在使用PHP的ssh2扩展与SFTP服务器交互时,开发者可能会遇到一个常见问题:通过ssh2.sftp:// URI打开远程文件流并尝试保存到本地时,最终得到的本地文件却是空的。这通常是由于误解了fopen函数在此上下文中的行为所致。
理解问题:为何下载的文件为空?
原始代码片段如下:
$connection = ssh2_connect('{my server ip}', 22);ssh2_auth_password($connection, '{user}', '{password}');$sftp = ssh2_sftp($connection);$file = "test.txt"; // 本地文件名$remote_path = "/public_html/$file"; // 远程文件路径$target_path = "ssh2.sftp://$sftp" . $remote_path; // 远程文件URI$stream = fopen($target_path, 'r'); // 打开远程文件流fopen($file, "w"); // 打开本地文件用于写入fclose($stream); // 关闭远程文件流
这段代码的问题在于,它确实成功打开了远程文件作为可读流($stream),也成功创建了一个本地文件用于写入。然而,它从未执行将数据从远程流传输到本地文件的操作。fopen函数本身并不会进行数据复制,它只是建立了一个文件句柄或流。因此,在没有数据传输的情况下,本地文件自然会保持为空。
解决方案一:使用stream_copy_to_stream正确传输数据
要解决上述问题,我们需要明确地将数据从打开的远程流复制到打开的本地流。PHP提供了stream_copy_to_stream函数,专门用于此目的。
立即学习“PHP免费学习笔记(深入)”;
stream_copy_to_stream(resource $source, resource $dest, ?int $maxlength = null, int $offset = 0): int|false
这个函数将从$source流中读取数据,并将其写入$dest流中,直到$source流到达末尾,或者复制了$maxlength字节的数据。
以下是使用stream_copy_to_stream的正确实现:
代码解析:
ssh2_connect():建立与SSH服务器的连接。ssh2_auth_password():使用用户名和密码进行身份验证。ssh2_sftp():获取SFTP子系统句柄,这是构建ssh2.sftp:// URI所必需的。fopen($sftp_uri, ‘r’):打开远程SFTP文件,返回一个可读的流资源。fopen($local_file_name, ‘w’):在本地创建一个新文件,并返回一个可写的流资源。stream_copy_to_stream($remote_stream, $local_stream):这是核心步骤,它将远程流中的所有数据读取并写入到本地流中。fclose():在操作完成后,务必关闭所有打开的文件流,释放资源。
解决方案二:更简洁高效的ssh2_scp_recv方法
如果你的服务器同时支持SCP(Secure Copy Protocol),那么PHP的ssh2扩展提供了一个更简洁、更直接的函数ssh2_scp_recv来下载文件。SCP通常与SFTP一同提供,并且在许多情况下,它能提供更快的传输速度。
ssh2_scp_recv(resource $session, string $remote_file, string $local_file): bool
这个函数直接将远程文件复制到本地文件,无需手动处理流。
以下是使用ssh2_scp_recv的示例:
代码解析:
ssh2_connect() 和 ssh2_auth_password():与第一种方法相同,用于建立和验证SSH连接。ssh2_scp_recv($connection, $remote_full_path, $local_file_name):这是核心函数,它接收SSH连接资源、远程文件的完整路径和本地文件的保存路径作为参数,然后直接执行文件复制操作。成功返回true,失败返回false。
注意事项:
ssh2_scp_recv函数要求远程文件路径是服务器上的绝对路径或相对于用户主目录的路径。此方法依赖于服务器是否启用了SCP服务。大多数支持SFTP的服务器也会支持SCP,但并非绝对。ssh2_scp_recv通常比手动处理流更为高效,因为它可能在底层使用了更优化的传输机制。
总结
当使用PHP的ssh2扩展从SFTP服务器下载文件时,切记fopen仅是打开文件流,并不会自动传输数据。为了确保文件内容能够正确下载到本地,你需要:
使用stream_copy_to_stream:这是最通用的方法,适用于所有SFTP连接,通过手动复制远程流数据到本地流。使用ssh2_scp_recv:如果服务器支持SCP,这是更简洁高效的选择,只需一行代码即可完成文件下载。
在实际应用中,建议优先考虑ssh2_scp_recv,因为它代码量少、易于理解和维护。如果遇到SCP不支持的情况,再回退到stream_copy_to_stream方法。同时,务必加入适当的错误处理机制,以应对连接失败、认证失败或文件不存在等异常情况。
以上就是PHP SFTP文件传输:解决ssh2.sftp://下载空文件问题的详细内容,更多请关注php中文网其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1327993.html
微信扫一扫
支付宝扫一扫