无法让SFTP在PHP中运行

问题描述 投票:15回答:10

我正在用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,它工作正常。

有没有其他人试图在SFTP上使用SSH2扩展?我错过了一些明显的东西吗?

更新:

我在内部的另一台机器上安装了sftp,它运行得很好。所以,我试图连接到的服务器必须有一些不起作用。

php ssh wrapper sftp
10个回答
42
投票

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

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

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

$rd = "ssh2.sftp://{$this->sftp}/./";

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#59794的修复。该行代码试图从路径变量中获取包含部分,查询和片段的字符串。考虑路径变量的这个值:

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

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

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

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

您可能还需要应用bug#73597的补丁,该补丁在调用php_url_parse()之前从路径字符串中删除“Resource id#”。


18
投票

对于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


8
投票

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

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

$remote_dir是从根的完整路径然后open_dir工作。如果$remote_dir只是'/'或'',那么我会像你那样得到'无法打开'的错误。

在我的情况下,似乎ssh连接在根文件夹而不是像ftp那样的'home'目录。你提到它在不同的服务器上工作,所以我想知道它是否只是一个配置问题。


7
投票

PHPSECLIB:http://phpseclib.sourceforge.net/是让PHP在PHP中工作的最简单方法(即使在Windows上),而不安装任何扩展等。 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();
?>

3
投票

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

另一个警告是SFTP在根目录而不是远程用户的主目录中启动,因此URI中的远程路径应始终是绝对路径。


1
投票

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

在我的情况下,当连接到服务器时,我去了帐户的根目录,由于服务器配置,我无法在那里写。

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

我必须包括整个路径,直到我允许写的文件夹,所以我可以解决问题。

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


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

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

干杯!


0
投票

我最近尝试在PHP上运行SFTP,发现phpseclib更容易使用:

http://phpseclib.sourceforge.net/

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


0
投票

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.