|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77581 SFTP with files with # (hash) in name do not work
Submitted: 2019-02-07 22:03 UTC Modified: 2019-02-11 22:16 UTC
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: memso at memso dot net Assigned: ramsey (profile)
Status: Verified Package: ssh2 (PECL)
PHP Version: 7.3.2 OS: CentOS 7
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2019-02-07 22:03 UTC] memso at memso dot net
Attempting to use the ssh2.sftp stream methods to access files with a hash (#) in the file name always fails.

This seems to occur with all file stream methods. I've tried stat, fopen and is_file, all act like the file does not exist.

Removing the # or changing it to another character fixes the problem, but I do not have control over a remote SFTP I am downloading from and cannot download their files which have a # in the file name.

Test script:
// Assuming a file named "Some#Test.txt" exists
$ssh2 = ssh2_connect("server", 22);
$sftp = ssh2_sftp($ssh2);
print_r(stat("ssh2.sftp://" . intval($sftp) . "/Some#Test.txt"));

Expected result:
Results for the "Some#Test.txt" file are expected.

Actual result:
"false" is output instead


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2019-02-10 00:28 UTC]
I've not seen intval() used on a resource like this. Should that work to allow the ssh2.sftp stream wrapper to connect to the server?

Have you tried using ssh2_sftp_stat() instead? For example:

print_r(ssh2_sftp_stat($sftp, 'Some#Test.txt'));

That works for me, though I was able to reproduce your particular issue, using the ssh2.sftp stream wrapper.

I don't think this is a bug. stat() uses URL wrappers, and a hash mark in URLs is the start of a fragment, so I think this behaves as expected.

To Reproduce Results:

Start a Docker container for a local SFTP server:

docker run --rm -v "${PWD}/files:/home/foo" -p 2222:22 -d atmoz/sftp:alpine foo:pass:1001

Then create the following files in ${PWD}/files:

touch files/foo.txt
touch files/"Some#Test.txt"

Now, run the following script. It'll try to stat each file twice. Once with ssh2_sftp_stat() and once using stat() with the ssh2.sftp stream wrapper. Note how everything succeeds except the last stat() for Some#Test.txt.

$ssh2 = ssh2_connect('', 2222);

if (ssh2_auth_password($ssh2, 'foo', 'pass')) {
    $sftp = ssh2_sftp($ssh2);

    print_r(ssh2_sftp_stat($sftp, 'foo.txt'));
    print_r(ssh2_sftp_stat($sftp, 'Some#Test.txt'));

} else {
    echo 'Could not authenticate.' . PHP_EOL;
 [2019-02-10 12:31 UTC]
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2019-02-10 12:31 UTC]
> I've not seen intval() used on a resource like this. Should that
> work to allow the ssh2.sftp stream wrapper to connect to the
> server?

It's document this way in the manual[1], and relies on resource to
int conversion to give the unique resource number[2]. 

> I don't think this is a bug.

ACK.  The hash mark has to be properly escaped:

  print_r(stat("ssh2.sftp://" . intval($sftp) . "/Some%23Test.txt"));

[1] <>
[2] <>
 [2019-02-11 18:35 UTC] memso at memso dot net

Your solution does not work. If the SFTP code is supposed to convert URL encoded strings back to real strings before accessing files, it is not doing so.

To make it very clear what is happening, I created 2 files on the SFTP.

Correct file


When I run the following code:
$ssh2 = ssh2_connect("server", 22);
$sftp = ssh2_sftp($ssh2);
print_r(file_get_contents("ssh2.sftp://" . intval($sftp) . "/Some%23Test.txt"));

The result is:
 [2019-02-11 18:43 UTC]
-Status: Not a bug +Status: Open -Assigned To: cmb +Assigned To:
 [2019-02-11 18:43 UTC]
Well, then there is something wrong.
 [2019-02-11 22:16 UTC]
-Status: Open +Status: Verified -Assigned To: +Assigned To: ramsey
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sat Feb 23 01:01:26 2019 UTC