无法让 SFTP 在 PHP 中工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1466737/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can't get SFTP to work in PHP
提问by Chris Kloberdanz
I am writing a simple SFTP client in PHP because we have the need to programatically retrieve files via n remote servers. I am using the PECL SSH2 extension.
我正在用 PHP 编写一个简单的 SFTP 客户端,因为我们需要通过 n 个远程服务器以编程方式检索文件。我正在使用 PECL SSH2 扩展。
I have run up against a road block, though. The documentation on php.net suggests that you can do this:
不过,我遇到了路障。php.net 上的文档建议您可以这样做:
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');
However, I have an ls method that attempts to something similar
但是,我有一个 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);
}
I get the following error:
我收到以下错误:
PHP Warning: opendir(): Unable to open ssh2.sftp://Resource id #5/outgoing on remote host
This makes perfect sense because that's what happens when you cast a resource to string. Is the documentation wrong? I tried replacing the resource with host, username, and host and that didn't work either. I know the path is correct because I can run SFTP from the command line and it works fine.
这是完全有道理的,因为这就是将资源转换为字符串时会发生的情况。文档有错吗?我尝试用主机、用户名和主机替换资源,但也没有用。我知道路径是正确的,因为我可以从命令行运行 SFTP 并且它工作正常。
Has anyone else tried to use the SSH2 extenstion with SFTP? Am I missing something obvious here?
有没有其他人尝试将 SSH2 扩展与 SFTP 一起使用?我在这里遗漏了一些明显的东西吗?
UPDATE:
更新:
I setup sftp on another machine in-house and it works just fine. So, there must be something about the server I am trying to connect to that isn't working.
我在内部的另一台机器上设置了 sftp,它工作得很好。因此,我尝试连接的服务器肯定有问题无法正常工作。
回答by Luis Gustavo Padilla López
When connecting to a SFTP server and you need to connect to the root folder (for instance for reading the content of the folder) you would still get the error when using just "/" as the path.
当连接到 SFTP 服务器并且您需要连接到根文件夹(例如用于读取文件夹的内容)时,仅使用“/”作为路径时仍然会出现错误。
The solution that I found was to use the path "/./", that's a valid path that references to the root folder. This is useful when the user you are logging with has access only to its own root folder and no full path is available.
我找到的解决方案是使用路径“/./”,这是一个引用根文件夹的有效路径。当您登录的用户只能访问其自己的根文件夹并且没有可用的完整路径时,这很有用。
So the request to the server when trying to read the contents of the root folder should be something like this:
所以在尝试读取根文件夹的内容时对服务器的请求应该是这样的:
$rd = "ssh2.sftp://{$this->sftp}/./";
回答by Calin Blaga
For php versions > 5.6.27 use intval()
对于 php 版本 > 5.6.27 使用 intval()
$sftpConnection = ssh2_connect($host);
$sftp = ssh2_sftp($sftpConnection);
$fp = fopen("ssh2.sftp://" . intval($sftp) . $remoteFile, "r");
回答by safoo
I'm having a similar issue. I assume you are doing something similar to this:
我有一个类似的问题。我假设你正在做类似的事情:
$dir = "ssh2.sftp://{$sftp}{$remote_dir}";
$handle = opendir($dir);
When $remote_diris the full path from root then open_dirworks. If $remote_diris just '/' or '', then I get the 'unable to open' error as you did.
什么时候$remote_dir从 root 开始的完整路径open_dir有效。如果$remote_dir只是“/”或“”,那么我会像您一样收到“无法打开”错误。
In my case, it seems ssh connects at the root folder instead of the 'home' directory as ftp does. You mentioned that it worked on a different server, so I wonder if it is just a config issue.
就我而言,ssh 似乎连接在根文件夹而不是像 ftp 那样连接到“home”目录。你提到它在不同的服务器上工作,所以我想知道这是否只是一个配置问题。
回答by Max
the most easiest way to get SFTP working within PHP (even on windows) without installing any extension etc is PHPSECLIB: http://phpseclib.sourceforge.net/. The SSH stuff is completely implemented in a PHP class.
在不安装任何扩展等的情况下让 SFTP 在 PHP 中工作(甚至在 Windows 上)的最简单方法是 PHPSECLIB:http://phpseclib.sourceforge.net/ 。SSH 的东西完全在 PHP 类中实现。
You use is like this:
你使用的是这样的:
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
echo $sftp->pwd();
?>
回答by mojuba
The documentation on that page contains an error. Take a look at the example here instead: http://php.net/ssh2_sftp- what you actually need to do is to open a special SFTP resource using ssh2_sftp() prior to using it with fopen(). And yes, it looks just like that, e.g. "Resource #24" when converted to string... a bit weird but apparently it works.
该页面上的文档包含错误。看看这里的例子:http: //php.net/ssh2_sftp- 你真正需要做的是在使用 fopen() 之前使用 ssh2_sftp() 打开一个特殊的 SFTP 资源。是的,它看起来就像那样,例如“Resource #24”在转换为字符串时......有点奇怪,但显然它有效。
Another caveat is that SFTP starts in the root directory rather than the home directory of the remote user, so your remote path in the URI should always be an absolute one.
另一个警告是 SFTP 在根目录而不是远程用户的主目录中启动,因此 URI 中的远程路径应该始终是绝对路径。
回答by vfn
I just had the same issue, but I could figure out the problem.
我只是遇到了同样的问题,但我可以找出问题所在。
On my case, when connecting to the server, I was going to the root of the account, and due to server configs I wasn't able to write there.
在我的情况下,当连接到服务器时,我要去帐户的根目录,由于服务器配置,我无法在那里写入。
I have connected to the account using a fireFTP, and so I could see where the root of the account was...it was the root of the server.
我已经使用 fireFTP 连接到该帐户,因此我可以看到该帐户的根目录在哪里...它是服务器的根目录。
I had to include the whole path until the folder where I am allowed to write, and so I could solve the issue.
我必须在允许我写入的文件夹之前包含整个路径,这样我才能解决问题。
So, my advice is to get the path using a graphic interface (I have used fireFTP), and add the whole path to your code.
因此,我的建议是使用图形界面(我使用过 fireFTP)获取路径,并将整个路径添加到您的代码中。
$pathFromAccountRootFolderToMyDestinationFolder = '/Account/Root/Folder/To/My/Folder';
$stream = fopen("ssh2.sftp://".$sftp."/".$pathFromAccountRootFolderToMyDestinationFolder."/myFile.ext", 'r');
Hope this will help you and other people with the same issue!
希望这会帮助你和其他有同样问题的人!
Cheers!
干杯!
回答by vfn
I recently tried to get SFTP on PHP working and found that phpseclib was a lot easier to use:
我最近尝试在 PHP 上运行 SFTP,发现 phpseclib 更容易使用:
http://phpseclib.sourceforge.net/
http://phpseclib.sourceforge.net/
If you have the luxury of not being on a shared host and can install whatever extensions you want to maybe the PECL extension would be better but not all of us are so lucky. Plus, phpseclib's API looks a bit more intuitive, being OOP and all.
如果您有幸不在共享主机上,并且可以安装您想要的任何扩展,那么 PECL 扩展可能会更好,但并非所有人都如此幸运。另外,phpseclib 的 API 看起来更直观一点,是面向对象的。
回答by David Lefkon
Solved my issue by enabling sftp support on the (Powershell) server
通过在(Powershell)服务器上启用 sftp 支持解决了我的问题
回答by Ken Pardiac
This is a bug in the ssh2 package that I found years ago and posted a patch to php.net. It fixes this issue but requires a rebuild of the ssh2 pecl package. You can read more here: https://bugs.php.net/bug.php?id=69981. I included a patch there to the ssh2_fopen_wrappers.c file in the package to fix the issue. Here is a comment I included:
这是我多年前发现的 ssh2 包中的一个错误,并发布了一个补丁到 php.net。它修复了这个问题,但需要重建 ssh2 pecl 包。您可以在此处阅读更多信息:https: //bugs.php.net/bug.php?id=69981。我在包中的 ssh2_fopen_wrappers.c 文件中包含了一个补丁来解决这个问题。这是我加入的评论:
Here is a line of code from ssh2_fopen_wrappers.c that causes this bug: (comment included)
这是 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));
This line of code -- and therefore this bug -- was introduced as a fix for bug #59794. That line of code is attempting to get a string containing the part, query and fragment from the path variable. Consider this value for the path variable:
这行代码——也就是这个错误——是作为错误 #59794 的修复而引入的。该行代码试图从路径变量中获取包含部分、查询和片段的字符串。考虑路径变量的这个值:
ssh2.sftp://Resource id #5/topdir?a=something#heading1
When resource->path is "/topdir", the result is that "/topdir?a=something#heading1" gets assigned to resource->path just like the comment says.
当 resource->path 是 "/topdir" 时,结果是 "/topdir?a=something#heading1" 被分配给 resource->path 就像注释所说的那样。
Now consider the case when resource->path is "/". After the line of code is executed, resource->path becomes "//Resource id#5/topdir#heading1". This is clearly not what you want. Here's a line of code that does:
现在考虑资源->路径为“/”的情况。这行代码执行完后,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().
您可能还需要为 bug #73597 应用补丁,它会在调用 php_url_parse() 之前从路径字符串中删除“Resource id #”。
回答by Radenko
My issue was, that I was connecting in function and returning string URL with resource inside. Unfortunatelly resource is than created in function context and garbage collector is disconnecting resource on function end. Solution: return resource by reference and unset it manually in more complex context.
我的问题是,我在函数中连接并返回带有内部资源的字符串 URL。不幸的是,资源不是在函数上下文中创建的,垃圾收集器正在断开函数端的资源。解决方案:通过引用返回资源并在更复杂的上下文中手动取消设置。

