我正在用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,它运行得很好。所以,我试图连接到的服务器必须有一些不起作用。
答案 0 :(得分:42)
连接到SFTP服务器并且需要连接到根文件夹(例如,用于读取文件夹的内容)时,如果仅使用“/”作为路径,则仍会出现错误。
我找到的解决方案是使用路径“/./”,这是一个引用根文件夹的有效路径。当您登录的用户只能访问其自己的根文件夹且没有完整路径可用时,这非常有用。
因此,当尝试读取根文件夹的内容时,服务器的请求应该是这样的:
$rd = "ssh2.sftp://{$this->sftp}/./";
答案 1 :(得分:17)
对于php版本> 5.6.27使用intval()
$sftpConnection = ssh2_connect($host);
$sftp = ssh2_sftp($sftpConnection);
$fp = fopen("ssh2.sftp://" . intval($sftp) . $remoteFile, "r");
答案 2 :(得分:8)
我遇到了类似的问题。我假设你正在做类似的事情:
$dir = "ssh2.sftp://{$sftp}{$remote_dir}";
$handle = opendir($dir);
当$remote_dir
是来自root的完整路径时,open_dir
有效。如果$remote_dir
只是'/'或'',那么我会像你一样得到'无法打开'错误。
在我的情况下,似乎ssh连接在根文件夹而不是像ftp那样的'home'目录。你提到它在不同的服务器上工作,所以我想知道它是否只是一个配置问题。
答案 3 :(得分: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();
?>
答案 4 :(得分:3)
该页面上的文档包含错误。请看一下这里的示例:http://php.net/ssh2_sftp - 您实际需要做的是在使用fopen()之前使用ssh2_sftp()打开一个特殊的SFTP资源。是的,它看起来就像那样,例如“资源#24”转换为字符串时...有点奇怪,但显然它有效。
另一个警告是SFTP在根目录而不是远程用户的主目录中启动,因此URI中的远程路径应始终是绝对路径。
答案 5 :(得分:1)
我遇到了同样的问题,但我可以解决问题。
在我的情况下,当连接到服务器时,我要去帐户的根目录,由于服务器配置,我无法在那里写。
我已使用fireFTP连接到该帐户,因此我可以看到该帐户的根目录...它是服务器的根目录。
我必须包括整个路径,直到我允许写的文件夹,所以我可以解决问题。
所以,我的建议是使用图形界面(我使用过fireFTP)获取路径,并添加代码的整个路径。
$pathFromAccountRootFolderToMyDestinationFolder = '/Account/Root/Folder/To/My/Folder';
$stream = fopen("ssh2.sftp://".$sftp."/".$pathFromAccountRootFolderToMyDestinationFolder."/myFile.ext", 'r');
希望这会帮助你和其他人有同样的问题!
干杯!
答案 6 :(得分:0)
我最近尝试在PHP上运行SFTP,发现phpseclib更容易使用:
http://phpseclib.sourceforge.net/
如果你有幸不在共享主机上并可以安装你想要的任何扩展,那么PECL扩展会更好,但并非所有人都这么幸运。另外,phpseclib的API看起来更直观,是OOP和所有。
答案 7 :(得分:0)
我的问题是,我在函数中连接并返回内部资源的字符串URL。不幸的是,资源不是在函数上下文中创建的,垃圾收集器正在断开功能端的资源。解决方案:通过引用返回资源,并在更复杂的上下文中手动取消设置。
答案 8 :(得分:0)
通过在(Powershell)服务器上启用sftp支持解决了我的问题
答案 9 :(得分:0)
这是我几年前发现并向php.net发布补丁的ssh2软件包中的错误。它解决了此问题,但需要重建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));
这行代码-因此是该错误-是作为错误#59794的修复程序引入的。该行代码试图从path变量中获取一个包含零件,查询和片段的字符串。 考虑路径变量的这个值:
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, "/" ) );
您可能还需要应用bug#73597的补丁,该bug会在调用php_url_parse()之前从路径字符串中删除“资源ID#”。