19

我正在用 PHP 编写一个简单的 SFTP 客户端,因为我们需要通过 n 个远程服务器以编程方式检索文件。我正在使用 PECL SSH2 扩展。

不过,我遇到了路障。php.net 上的文档建议您可以这样做:

$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');

但是,我有一个尝试类似的 ls 方法

public function ls($dir)
{
    $rd = "ssh2.sftp://{$this->sftp}/$dir";
    $handle = opendir($rd);
    if (!is_resource($handle)) {
        throw new SFTPException("Could not open directory.");
    }

    while (false !== ($file = readdir($handle))) {
        if (substr($file, 0, 1) != '.'){
            print $file . "\n";
        }
    }
    closedir($handle);
}

我收到以下错误:

PHP Warning:  opendir(): Unable to open ssh2.sftp://Resource id #5/outgoing on remote host

这是非常有意义的,因为当您将资源转换为字符串时会发生这种情况。文档有错吗?我尝试用主机、用户名和主机替换资源,但也没有用。我知道路径是正确的,因为我可以从命令行运行 SFTP,它工作正常。

有没有其他人尝试过将 SSH2 扩展与 SFTP 一起使用?我在这里遗漏了一些明显的东西吗?

更新:

我在内部的另一台机器上设置了 sftp,它工作得很好。因此,我尝试连接的服务器一定有一些东西无法正常工作。

4

10 回答 10

51

当连接到 SFTP 服务器并且您需要连接到根文件夹(例如,为了读取文件夹的内容)时,仅使用“/”作为路径时仍然会出现错误。

我找到的解决方案是使用路径“/./”,这是一个引用根文件夹的有效路径。当您登录的用户只能访问其自己的根文件夹并且没有完整路径可用时,这很有用。

因此,在尝试读取根文件夹的内容时对服务器的请求应该是这样的:

$rd = "ssh2.sftp://{$this->sftp}/./";
于 2013-04-26T14:05:08.460 回答
24

对于 php 版本 > 5.6.27 使用 intval()

$sftpConnection = ssh2_connect($host);
$sftp = ssh2_sftp($sftpConnection);
$fp = fopen("ssh2.sftp://" . intval($sftp) . $remoteFile, "r");

https://bugs.php.net/bug.php?id=73597

于 2017-02-23T10:00:29.310 回答
7

我有一个类似的问题。我假设您正在做类似的事情:

    $dir = "ssh2.sftp://{$sftp}{$remote_dir}"; 
    $handle = opendir($dir);

什么时候$remote_dir从根目录开始的完整路径才open_dir起作用。如果$remote_dir只是“/”或“”,那么我会像您一样收到“无法打开”错误。

就我而言,似乎 ssh 连接在根文件夹而不是 ftp 的“主”目录。你提到它在不同的服务器上工作,所以我想知道这是否只是一个配置问题。

于 2009-10-23T00:15:59.210 回答
7

在不安装任何扩展等的情况下让 SFTP 在 PHP(甚至在 Windows 上)工作的最简单方法是 PHPSECLIB:http ://phpseclib.sourceforge.net/ 。SSH 的东西完全在 PHP 类中实现。

你使用的是这样的:

<?php
include('Net/SFTP.php');

$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
    exit('Login Failed');
}

echo $sftp->pwd();
?>
于 2011-08-23T09:15:52.833 回答
4

该页面上的文档包含错误。请查看此处的示例:http: //php.net/ssh2_sftp - 您实际需要做的是在使用 fopen() 之前使用 ssh2_sftp() 打开一个特殊的 SFTP 资源。是的,它看起来就像那样,例如“Resource #24”在转换为字符串时......有点奇怪,但显然它有效。

另一个需要注意的是,SFTP 从根目录而不是远程用户的主目录开始,因此 URI 中的远程路径应该始终是绝对路径。

于 2012-05-21T14:36:46.643 回答
1

我只是遇到了同样的问题,但我可以找出问题所在。

就我而言,当连接到服务器时,我要去帐户的根目录,但由于服务器配置,我无法在那里写入。

我已经使用 fireFTP 连接到该帐户,因此我可以看到该帐户的根目录在哪里……它是服务器的根目录。

我必须包含整个路径,直到允许我写入的文件夹,这样我才能解决问题。

因此,我的建议是使用图形界面获取路径(我使用过 fireFTP),并将整个路径添加到您的代码中。


$pathFromAccountRootFolderToMyDestinationFolder = '/Account/Root/Folder/To/My/Folder';
$stream = fopen("ssh2.sftp://".$sftp."/".$pathFromAccountRootFolderToMyDestinationFolder."/myFile.ext", 'r');

希望这将帮助您和其他有同样问题的人!

干杯!

于 2010-03-25T03:22:50.057 回答
0

我最近尝试让 PHP 上的 SFTP 工作,发现 phpseclib 更容易使用:

http://phpseclib.sourceforge.net/

如果您有幸不在共享主机上并且可以安装您想要的任何扩展,那么 PECL 扩展可能会更好,但并非我们所有人都这么幸运。另外,phpseclib 的 API 看起来更直观,是面向对象的。

于 2009-11-23T03:55:41.533 回答
0

我的问题是,我正在连接函数并返回带有资源的字符串 URL。不幸的是,资源是在函数上下文中创建的,垃圾收集器在函数端断开资源。解决方案:通过引用返回资源并在更复杂的上下文中手动取消设置。

于 2016-11-28T23:35:18.500 回答
0

通过在(Powershell)服务器上启用 sftp 支持解决了我的问题

于 2017-03-09T16:00:05.087 回答
0

这是我多年前发现的 ssh2 包中的一个错误,并在 php.net 上发布了一个补丁。它修复了这个问题,但需要重建 ssh2 pecl 包。您可以在此处阅读更多信息:https ://bugs.php.net/bug.php?id=69981 。我在包中的 ssh2_fopen_wrappers.c 文件中包含了一个补丁来解决这个问题。这是我包括的评论:

这是 ssh2_fopen_wrappers.c 中导致此错误的一行代码:(包括注释)

/*
       Find resource->path in the path string, then copy the entire string from the original path.
       This includes ?query#fragment in the path string
*/
    resource->path = estrdup(strstr(path, resource->path));

这行代码——因此也就是这个 bug——是作为 bug #59794 的修复而引入的。那行代码试图从路径变量中获取包含部分、查询和片段的字符串。考虑路径变量的这个值:

ssh2.sftp://Resource id #5/topdir?a=something#heading1

当resource->path 为“/topdir”时,结果是“/topdir?a=something#heading1”被分配给resource->path,就像注释所说的那样。

现在考虑resource->path 为“/”的情况。这行代码执行后,resource->path就变成了“//Resource id#5/topdir#heading1”。这显然不是你想要的。这是一行代码:

 resource->path = estrdup( strstr( strstr( path, "//" ) + 2, "/" ) );

You may also need to apply the patch for bug # 73597 which removes "Resource id #" from the path string before calling php_url_parse().

于 2019-03-20T16:01:03.357 回答