Can't get SFTP to work in PHP
Asked Answered
F

10

19

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.

I have run up against a road block, though. The documentation on php.net suggests that you can do this:

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

However, I have an ls method that attempts to something similar

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.

Has anyone else tried to use the SSH2 extenstion with SFTP? Am I missing something obvious here?

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.

Fingerprint answered 23/9, 2009 at 15:27 Comment(2)
Can you confirm that the ssh2 connection is working? how about using any of the other ssh2 functions?Fiji
ssh2_connect() ssh2_auth_password() ssh2_sftp() are all working correctly. I have a valid connection resource as far as I can tell.Fingerprint
O
55

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.

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}/./";
Oleary answered 26/4, 2013 at 14:5 Comment(4)
This is the correct answer. There was a bug introduced sometime since between PHP 5.2 and 5.4 that broke access to the root directory. Thanks for providing a workaround!Highpressure
You're welcome @BradenAnderson, I've found so many answers here that I thought providing the one that I have was only fairCommentary
I glossed over this a few times, before I realized this was my situation. Thank you for posting this.Tinkle
I finally got around to trying this again. First, I had to get off an old version of the extension that was causing segfaults. Once I got that taken care of it, seems to work great so far! Thank you!Fingerprint
Z
25

For php versions > 5.6.27 use 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

Zerelda answered 23/2, 2017 at 10:0 Comment(3)
Upvoted, same here. I guess PHP doesn't understand it's datatype in newer versions.Geri
This was the solution for me too, using PHP 7.2Gahl
After upgrade of php version, we were able to login/connect but not able to write new files. This helped us, ThanksRedress
D
8

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.

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();
?>
Difficult answered 23/8, 2011 at 9:15 Comment(0)
L
7

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_dir is the full path from root then open_dir works. If $remote_dir is just '/' or '', then I get the 'unable to open' error as you did.

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.

Lizzettelizzie answered 23/10, 2009 at 0:15 Comment(2)
From what I have seen, you are right. It connects to the root directory rather than 'home'. Using the command-line sftp client does connect to 'home'. I may just have to get the absolute path from the client I am trying to connect to.Fingerprint
$dir = 'ssh2.sftp://'.$sftp.'/'.$absolute_path; Using the absolute path instead of the home path is the answer.Doings
N
4

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.

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.

Nettie answered 21/5, 2012 at 14:36 Comment(0)
E
1

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.

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.


$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!

Elli answered 25/3, 2010 at 3:22 Comment(2)
That's a good thought. I have already tried that using FireZilla and WinSCP. I used what they had as the absolute path to no avail, though.Fingerprint
Is there a way to get the real path of user's home directory?Nanete
C
0

I recently tried to get SFTP on PHP working and found that phpseclib was a lot easier to use:

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.

Constitutionally answered 23/11, 2009 at 3:55 Comment(4)
only good for some sftp versions, it is stated in the libraries commentsRetrace
99% of SFTP installs use v3. Actually, I've never come across an SFTP server that didn't support it. Many clients also only support v3. WinSCP for example. Adding support for v6 when v3 works and when no one even uses v6 would simply be a waste of dev resources.Constitutionally
then u are lucky, but when u have to rewrite things from perl to php for many clients, there is always 1% who use different versionRetrace
Maybe you could post a bug report then asking that support for a newer version be supported. The phpseclib devs do seem pretty responsive to tickets like that. You're not gonna get anything in life if you don't ask..Constitutionally
R
0

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.

Roswell answered 28/11, 2016 at 23:35 Comment(0)
S
0

Solved my issue by enabling sftp support on the (Powershell) server

Shire answered 9/3, 2017 at 16:0 Comment(0)
P
0

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:

Here is a line of code from ssh2_fopen_wrappers.c that causes this bug: (comment included)

/*
       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:

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.

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 = 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().

Prevocalic answered 20/3, 2019 at 16:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.