0

0

PHP SFTP文件传输:解决ssh2.sftp://下载空文件问题

霞舞

霞舞

发布时间:2025-10-28 10:29:00

|

562人浏览过

|

来源于php中文网

原创

PHP SFTP文件传输:解决ssh2.sftp://下载空文件问题

本文旨在解决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的正确实现:

<?php

// 假设这些变量已正确配置
$server_ip = '{my server ip}';
$username = '{user}';
$password = '{password}';
$remote_file_name = "test.txt"; // 远程服务器上的文件名
$local_file_name = "downloaded_test.txt"; // 本地保存的文件名
$remote_base_path = "/public_html"; // 远程文件所在的目录

// 1. 建立SSH连接
$connection = ssh2_connect($server_ip, 22);
if (!$connection) {
    die("无法连接到服务器。\n");
}

// 2. 进行身份验证
if (!ssh2_auth_password($connection, $username, $password)) {
    die("身份验证失败。\n");
}

// 3. 获取SFTP子系统
$sftp = ssh2_sftp($connection);
if (!$sftp) {
    die("无法初始化SFTP子系统。\n");
}

// 4. 构建远程文件的完整SFTP URI
$remote_full_path = $remote_base_path . '/' . $remote_file_name;
$sftp_uri = "ssh2.sftp://$sftp" . $remote_full_path;

// 5. 打开远程文件流(只读)
$remote_stream = @fopen($sftp_uri, 'r');
if (!$remote_stream) {
    die("无法打开远程文件: " . $remote_full_path . "\n");
}

// 6. 打开本地文件流(写入模式)
$local_stream = @fopen($local_file_name, 'w');
if (!$local_stream) {
    fclose($remote_stream); // 确保关闭已打开的远程流
    die("无法创建本地文件: " . $local_file_name . "\n");
}

// 7. 将数据从远程流复制到本地流
$bytes_copied = stream_copy_to_stream($remote_stream, $local_stream);

// 8. 关闭所有流
fclose($remote_stream);
fclose($local_stream);

if ($bytes_copied !== false) {
    echo "文件 '" . $remote_file_name . "' 已成功下载到本地 '" . $local_file_name . "',共复制了 " . $bytes_copied . " 字节。\n";
} else {
    echo "文件下载失败。\n";
}

?>

代码解析:

启科PHP淘宝客系统
启科PHP淘宝客系统

1、请上传下载到的淘宝客系统安装包并上传到空间根目录中进行解压,解压后将网站文件移动到根目录的位置,然后访问 /install 进行安装。您也可以在本地解压,并以二进制方式将程序上传至您的网站空间。 2、同意启科网络电子商务系统安装协议进入下一步。 3、如果系统检测环境通过,则会提示输入您的数据库服务器地址(一般为本机,即127.0.0.1或者localhost)、数据库账号、数据库密码、数据库名

下载
  • 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的示例:

<?php

// 假设这些变量已正确配置
$server_ip = '{my server ip}';
$username = '{user}';
$password = '{password}';
$remote_file_name = "test.txt"; // 远程服务器上的文件名
$local_file_name = "downloaded_test.txt"; // 本地保存的文件名
$remote_base_path = "/public_html"; // 远程文件所在的目录

// 1. 建立SSH连接
$connection = ssh2_connect($server_ip, 22);
if (!$connection) {
    die("无法连接到服务器。\n");
}

// 2. 进行身份验证
if (!ssh2_auth_password($connection, $username, $password)) {
    die("身份验证失败。\n");
}

// 3. 构建远程文件的完整路径
$remote_full_path = $remote_base_path . '/' . $remote_file_name;

// 4. 使用ssh2_scp_recv直接下载文件
if (ssh2_scp_recv($connection, $remote_full_path, $local_file_name)) {
    echo "文件 '" . $remote_file_name . "' 已成功通过SCP下载到本地 '" . $local_file_name . "'.\n";
} else {
    echo "文件SCP下载失败。\n";
}

// 注意:ssh2_scp_recv内部处理了文件的打开和关闭,无需手动fclose。
// 如果不再需要SSH连接,可以关闭它,尽管PHP脚本结束时会自动清理。
// ssh2_disconnect($connection); // PHP 8.0+ 可用

?>

代码解析:

  • 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仅是打开文件流,并不会自动传输数据。为了确保文件内容能够正确下载到本地,你需要:

  1. 使用stream_copy_to_stream:这是最通用的方法,适用于所有SFTP连接,通过手动复制远程流数据到本地流。
  2. 使用ssh2_scp_recv:如果服务器支持SCP,这是更简洁高效的选择,只需一行代码即可完成文件下载。

在实际应用中,建议优先考虑ssh2_scp_recv,因为它代码量少、易于理解和维护。如果遇到SCP不支持的情况,再回退到stream_copy_to_stream方法。同时,务必加入适当的错误处理机制,以应对连接失败、认证失败或文件不存在等异常情况。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1010

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

181

2023.12.20

fclose函数的用法
fclose函数的用法

fclose是一个C语言和C++中的标准库函数,用于关闭一个已经打开的文件,是文件操作中非常重要的一个函数,用于将文件流与底层文件系统分离,释放相关的资源。更多关于fclose函数的相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

344

2023.11.30

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

334

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

776

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

97

2025.08.19

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 13.4万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.3万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号