How to SFTP with PHP? - php

I have came across many PHP scripts for web FTP clients. I need to implement a SFTP client as a web application in PHP.
Does PHP support for SFTP? I couldn't find any samples.
Can anyone help me with this?

PHP has ssh2 stream wrappers (disabled by default), so you can use sftp connections with any function that supports stream wrappers by using ssh2.sftp:// for protocol, e.g.
file_get_contents('ssh2.sftp://user:pass#example.com:22/path/to/filename');
or - when also using the ssh2 extension
$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');
See http://php.net/manual/en/wrappers.ssh2.php
On a side note, there is also quite a bunch of questions about this topic already:
https://stackoverflow.com/search?q=sftp+php

The ssh2 functions aren't very good. Hard to use and harder yet to install, using them will guarantee that your code has zero portability. My recommendation would be to use phpseclib, a pure PHP SFTP implementation.

I found that "phpseclib" should help you with this (SFTP and many more features). http://phpseclib.sourceforge.net/
To Put the file to the server, simply call (Code example from http://phpseclib.sourceforge.net/sftp/examples.html#put)
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
// puts a three-byte file named filename.remote on the SFTP server
$sftp->put('filename.remote', 'xxx');
// puts an x-byte file named filename.remote on the SFTP server,
// where x is the size of filename.local
$sftp->put('filename.remote', 'filename.local', NET_SFTP_LOCAL_FILE);

Install Flysystem v1:
composer require league/flysystem-sftp
Then:
use League\Flysystem\Filesystem;
use League\Flysystem\Sftp\SftpAdapter;
$filesystem = new Filesystem(new SftpAdapter([
'host' => 'example.com',
'port' => 22,
'username' => 'username',
'password' => 'password',
'privateKey' => 'path/to/or/contents/of/privatekey',
'root' => '/path/to/root',
'timeout' => 10,
]));
$filesystem->listFiles($path); // get file lists
$filesystem->read($path_to_file); // grab file
$filesystem->put($path); // upload file
....
Read:
https://flysystem.thephpleague.com/v1/docs/
Upgrade to v2:
https://flysystem.thephpleague.com/v2/docs/advanced/upgrade-to-2.0.0/
Install
composer require league/flysystem-sftp:^2.0
Then:
//$filesystem->listFiles($path); // get file lists
$allFiles = $filesystem->listContents($path)
->filter(fn (StorageAttributes $attributes) => $attributes->isFile());
$filesystem->read($path_to_file); // grab file
//$filesystem->put($path); // upload file
$filesystem->write($path);

After messing around with PECL ssh2 I decided to take a look at phpseclib 3 and it worked out of the box. No installation on the server. I used composer to install it and put the code in. It has a ton of useful things and it's free. These are the steps:
Run this composer install on your PHP app folder. I used VS Code and I opened a terminal window (need Composer to be installed on your machine first):
composer require phpseclib/phpseclib:~3.0
Use the basic example from here: https://phpseclib.com/docs/sftp
use phpseclib3\Net\SFTP;
$sftp = new SFTP('localhost');
$sftp->login('username', 'password');
$sftp->put('filename.remote', 'filename.local', SFTP::SOURCE_LOCAL_FILE);
Other useful links: GitHub: https://github.com/phpseclib/phpseclib and website: https://phpseclib.com/

I performed a full-on cop-out and wrote a class which creates a batch file and then calls sftp via a system call. Not the nicest (or fastest) way of doing it but it works for what I need and it didn't require any installation of extra libraries or extensions in PHP.
Could be the way to go if you don't want to use the ssh2 extensions

Related

PHP - SFTP uploading file [duplicate]

I have came across many PHP scripts for web FTP clients. I need to implement a SFTP client as a web application in PHP.
Does PHP support for SFTP? I couldn't find any samples.
Can anyone help me with this?
PHP has ssh2 stream wrappers (disabled by default), so you can use sftp connections with any function that supports stream wrappers by using ssh2.sftp:// for protocol, e.g.
file_get_contents('ssh2.sftp://user:pass#example.com:22/path/to/filename');
or - when also using the ssh2 extension
$connection = ssh2_connect('shell.example.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$stream = fopen("ssh2.sftp://$sftp/path/to/file", 'r');
See http://php.net/manual/en/wrappers.ssh2.php
On a side note, there is also quite a bunch of questions about this topic already:
https://stackoverflow.com/search?q=sftp+php
The ssh2 functions aren't very good. Hard to use and harder yet to install, using them will guarantee that your code has zero portability. My recommendation would be to use phpseclib, a pure PHP SFTP implementation.
I found that "phpseclib" should help you with this (SFTP and many more features). http://phpseclib.sourceforge.net/
To Put the file to the server, simply call (Code example from http://phpseclib.sourceforge.net/sftp/examples.html#put)
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
// puts a three-byte file named filename.remote on the SFTP server
$sftp->put('filename.remote', 'xxx');
// puts an x-byte file named filename.remote on the SFTP server,
// where x is the size of filename.local
$sftp->put('filename.remote', 'filename.local', NET_SFTP_LOCAL_FILE);
Install Flysystem v1:
composer require league/flysystem-sftp
Then:
use League\Flysystem\Filesystem;
use League\Flysystem\Sftp\SftpAdapter;
$filesystem = new Filesystem(new SftpAdapter([
'host' => 'example.com',
'port' => 22,
'username' => 'username',
'password' => 'password',
'privateKey' => 'path/to/or/contents/of/privatekey',
'root' => '/path/to/root',
'timeout' => 10,
]));
$filesystem->listFiles($path); // get file lists
$filesystem->read($path_to_file); // grab file
$filesystem->put($path); // upload file
....
Read:
https://flysystem.thephpleague.com/v1/docs/
Upgrade to v2:
https://flysystem.thephpleague.com/v2/docs/advanced/upgrade-to-2.0.0/
Install
composer require league/flysystem-sftp:^2.0
Then:
//$filesystem->listFiles($path); // get file lists
$allFiles = $filesystem->listContents($path)
->filter(fn (StorageAttributes $attributes) => $attributes->isFile());
$filesystem->read($path_to_file); // grab file
//$filesystem->put($path); // upload file
$filesystem->write($path);
After messing around with PECL ssh2 I decided to take a look at phpseclib 3 and it worked out of the box. No installation on the server. I used composer to install it and put the code in. It has a ton of useful things and it's free. These are the steps:
Run this composer install on your PHP app folder. I used VS Code and I opened a terminal window (need Composer to be installed on your machine first):
composer require phpseclib/phpseclib:~3.0
Use the basic example from here: https://phpseclib.com/docs/sftp
use phpseclib3\Net\SFTP;
$sftp = new SFTP('localhost');
$sftp->login('username', 'password');
$sftp->put('filename.remote', 'filename.local', SFTP::SOURCE_LOCAL_FILE);
Other useful links: GitHub: https://github.com/phpseclib/phpseclib and website: https://phpseclib.com/
I performed a full-on cop-out and wrote a class which creates a batch file and then calls sftp via a system call. Not the nicest (or fastest) way of doing it but it works for what I need and it didn't require any installation of extra libraries or extensions in PHP.
Could be the way to go if you don't want to use the ssh2 extensions

How to get file from SFTP server

I've been working at this for the last 2 days to no avail. I've also searched on StackOverflow for a solution but I couldn't find one that works for me.
I'm trying to pull a .csv file from a SFTP server. I found out you cannot do this with a default installation of PHP. I found 2 solutions.
1) Enable the ssh2_sftp extension in my PHP. I couldn't get this to work. I downloaded the required files, put them in my php/ext folder as directed, and modified the line in php.ini as required. Wouldn't work.
2) Use phpseclib. Couldn't get this to work as you need to use composer with it and composer wont load my php.ini because I have curl enabled?
Are there any other solutions for logging into a sftp server?
Appreciate the help.
Since it sounds like you have root access on the machine you're working with, why not use scp? It's a native php function so long as you have shell_exec enabled, and the user www-data (or whatever you call your httpd user) has shell access.
<?php
$connection = ssh2_connect('your_remote_server', 22); //remote connection
ssh2_auth_password($connection, 'username', 'password'); //authentication
ssh2_scp_recv($connection, '/remoteServer/whatever/yourFile.csv', '/localServer/yourNewFilename.csv'); //remote file -> local file
?>
NOTE
I have used this, but I also store the "username" and "password" in a MySQL database using bcrypt with a minimum cost of 12. More about that Here

PHP SSH2 operations failing when attempting to upload file to server

I am currently struggling with using the SSH2 built-in libraries for PHP (running version 5.5). I am trying to upload a file to an SFTP server as the title states however I keep getting a "stream operation failed" error message.
After attempting to debug the code itself the connection works, the sftp resource is assigned an ID correctly, however when fopen is called for writing the file directly to the remote server it fails.
// open Live environment if we are not in dev
$connection = ssh2_connect($this->_settings['source_host'], 22);
$authSuccess = ssh2_auth_password($connection, $this- >_settings['source_user'], $this->_settings['source_password']);
$sftp = ssh2_sftp($connection);
And finally the fopen() call:
if($operation == 'export') {
$handle = fopen("ssh2.sftp://".$sftp."/remotecopy/IN/".$filename, $mode);
}
I added debug messages in my own code to verify if the data from the _settings array is also used correctly and it is, however I can't explain the stream error.
Message: fopen(): Unable to open ssh2.sftp://Resource id #173/PATH GOES HERE/filename.xxx on remote host
Message: fopen(ssh2.sftp://Resource id #173/PATH GOES HERE/filename.xxx): failed to open stream: operation failed
As a note the file does not exist on the remote host but according to my knowledge 'w' mode in PHP fopen() should create the file if it does not exist.
I can't use the other PHP library as our whole project uses the builtin ssh2 libraries and the person in charged told me to not use it as it works fine everywhere else.
i think you'd have an easier time if you used phpseclib, a pure PHP SFTP implementation. eg.
<?php
include('Net/SFTP.php');
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
// puts a three-byte file named filename.remote on the SFTP server
$sftp->put('filename.remote', 'xxx');
// puts an x-byte file named filename.remote on the SFTP server,
// where x is the size of filename.local
$sftp->put('filename.remote', 'filename.local', NET_SFTP_LOCAL_FILE);
?>
One of the nice things about phpseclib is it's logging so if that doesn't work you can do define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX); after including Net/SFTP.php and then do echo $sftp->getLog() after the point where it fails. That might provide some insight into what's going on if it still isn't working.
The answer was easy, I had incorrectly formatted path on the remote server. After verifying my settings it works just fine.
Thank you all for the hints and help.

How to debug ssh2_sftp_rename?

I'm having trouble with ssh2_sftp_rename, or in general with the SSH2/SFTP wrapper.
We have two SFTP servers. One is a test server, which we've setup by ourself, and one is from a service provider. On the test server, everything works fine while on the provided SFTP we cannot rename a file via PHP. Manual renaming via sftp cli works fine. Our SFTP server uses the protocol version 2.0 and remote software version OpenSSH_6.0p1 Debian-4, while the other one uses protocol version 2.0, remote software version OpenSSH_5.3. So I'd guess they should act the same.
Here's the smallest code snippet for testing, which doesn't work:
<?php
$connection = ssh2_connect('sftp.serviceprovider.com', 22);
ssh2_auth_password($connection, 'username', 'password');
$sftp = ssh2_sftp($connection);
$result = ssh2_sftp_rename($sftp, '/new/foo.xml.gz', '/processed/foo.xml.gz');
var_dump($result);
var_dump(error_get_last());
$result is false and error_get_last() returns NULL. I also tried leaving the beginning slashes or any other combination I can think of, but it just "didn't work": the file is still in the 'new' folder.
So, unfortunately I cannot take a look into the log files of the service provider but I have requested an log excerpt or at least an analysis. But I don't want to wait for their support center to answer my question and try to debug this stuff.
Is there any possibility to debug what ssh2_sftp_rename or renameare doing behind the scenes? Does anyone else experienced something like this and found a solution?
Thanks for any hints,
Matthias
Diagnosing issues with libssh2 is nigh impossible. My recommendation: use phpseclib, a pure PHP SFTP implementation. eg.
<?php
include('Net/SFTP.php');
include('Crypt/RSA.php');
define('NET_SFTP_LOGGING', NET_SFTP_LOG_COMPLEX);
$sftp = new Net_SFTP('www.domain.tld');
if (!$sftp->login('username', 'password')) {
exit('Login Failed');
}
$sftp->rename('filename.remote', 'newname.remote');
echo $sftp->getSFTPLog();
?>
In lieu of seeing the logs my guess would be a permissions issue but the logs should tell us for sure.

Uploading files using SCP using phpseclib

I need to create 2 functions: one to upload files using SFTP and another using SCP. I'm using phpseclib and the put method; I believe I have the SFTP function done.
Now, I'm trying to do the SCP function. Per http://adomas.eu/phpseclib-for-ssh-and-scp-connections-with-php-for-managing-remote-server-and-data-exchange/, it seems like the following are the things I need to do:
In case of SCP:
1. Including the needed file: include('/path/to/needed/file/Net/SFTP.php');
2. Creating object and making connection:
$sftp = new Net_SFTP('host');
if (!$sftp->login('user', 'password')) { exit('Login Failed'); }
3. Reading contents of a file: $contents=$sftp->get('/file/on/remote/host.txt');
4. Copying file over sftp with php from remote to local host: $sftp->get('/file/on/remote/host.txt', '/file/on/local/host.txt');
5. Copying file over sftp with php from local to remote host: $sftp->put('/file/on/remote/host.txt', '/file/on/local/host.txt');
6. Writing contents to remote file: $sftp->get('/file/on/remote/host.txt', 'contents to write');
I need to do #5, but it looks like what I did for SFTP. SFTP and SCP aren't the same, right? Is the same code correct? If not, how do I do SCP?
As noted by neubert, phpseclib has SCP support now through the Net_SCP class.
You instantiate an Net_SCP object by passing it a Net_SSH2 or Net_SSH1 object in the constructor, and can then use the get() and put() methods to download or upload files via SCP.
Here's a simple example script showing me SCPing a file from my local machine to a remote AWS instance.
<?php
set_include_path(get_include_path() .
PATH_SEPARATOR .
'/home/mark/phpseclib');
require_once('Crypt/RSA.php');
require_once('Net/SSH2.php');
require_once('Net/SCP.php');
$key = new Crypt_RSA();
if (!$key->loadKey(file_get_contents('my_aws_key.pem')))
{
throw new Exception("Failed to load key");
}
$ssh = new Net_SSH2('54.72.223.123');
if (!$ssh->login('ubuntu', $key))
{
throw new Exception("Failed to login");
}
$scp = new Net_SCP($ssh);
if (!$scp->put('my_remote_file_name',
'my_local_file_name',
NET_SCP_LOCAL_FILE))
{
throw new Exception("Failed to send file");
}
?>
phpseclib recently added SCP support:
https://github.com/phpseclib/phpseclib/blob/master/phpseclib/Net/SCP.php
Yes, the SCP is completely different protocol to the SFTP.
The phpseclib now supports the SCP in recent versions (since version 0.3.5, released in June 2013).
Alternatively, use the PHP PECL SSH2 functions for SCP upload/download:
https://www.php.net/manual/en/ref.ssh2.php

Categories