< Back
Sep 12, 2018

Download a file over SFTP with phpseclib

I'll admit that the use cases for this one are pretty few. Data that's meant to be processed by PHP is usually publicly accessible or behind a some kind of standardised authentication, either in the form of HTTP Basic Auth or some key-based thing.

If the feed isn't meant to be web-accessible, however, it's possible that you may need to use SFTP to grab the file. And of course, PHP, being the absolute labyrinth of a programming language that it is, has just the utility.

It's called phpseclib, and it's surprisingly well-featured and -documented. (Well, compared with the weird I'm-going-to-say-just-little-enough-that-these-docs-won't-be-useful-oh-and-by-the-way-there's-a-comments-section world of the PHP official documentation, anyway.)

phpseclib includes significantly more functionality than you'll need here, but you can download the whole thing (400 KB) and just include the modules you need. You can require it with Composer, or just download the zip and save it somewhere locally. I've found the latter solution to be a little bit more handleable outside of situations where Composer's an option (say, on a good ol' basic WordPress installation), but the former is obviously more manageable from a dependencies standpoint.

I'm going with the latter.

Installation

Download the zip and extract it into your app somewhere. If you're running a quick script somewhere, it's fine to extract it into the same folder as your index.php or main.php or whatever you call it. For simplicity's sake, I've renamed phpseclib1.0.11 to phpseclib.

It takes a little bit of finangling to include phpseclib modules. The modules call each other, which means that you have to add the phpseclib folder to your include_path, so they know where to look. This is easily done:

set_include_path(get_include_path() . PATH_SEPARATOR . /full/path/to/phplibsec)

If phpseclib is in the same directory as your script, you don't need to use the full path.

Logging into a server with SFTP

Server logins are managed by phpseclib's Net/SFTP module, so you'll want to require that. We're also going to be good little security-minded Internet users and login using an SSH key rather than a password—which requires the Crypt/RSA module as well.

include('Net/SFTP.php');
include('Crypt/RSA.php');

We'll also need some credentials to log in with. We need 1) a host to log into, 2) a user to log in with, and 3) authentication (in this case, a private keyfile, but a password works just as well if your server is set up for it).

// Configure some credentials
$username = 'charles'
$host = 'charlesharri.es'
$keyfile = 'myprivatekey'

// Configure the key
$key = new Crypt_RSA();
$key->setPassword('myextremelysecurepassword');
$key->loadKey(file_get_contents($keyfile));

For my own reference: Could be worthwhile to pull that sensitive information out into its own config file so you don't accidentally push passwords and shit up to Github.

And we're ready to log in!

Log in

Login is as simple as creating a new Net_SFTP object with our host as an argument, and then calling the login method on it with our authentication as arguments.

$sftp = new Net_SFTP($host);
if(!$sftp->login($username, $key)) {
  exit('Login failed.');
}

Once you're logged in, that $sftp object has a ton of methods for CRUDing the files on the server.

Download a file

Going back to our original premise (namely, that there's some data in a feed we're trying to access over SFTP), downloading is probably the way we want to go. phpseclib makes it absurdly easy, with a simple get method doing all of the heavy lifting for us.

Save the file to a variable

With one argument, get defaults to simply returning the data in the file. This makes it trivial to save the file to a variable for further manipulation (e.g. json_decode-ing):

$data = $sftp->get('full/remote/path/to/file');
$json = json_decode($data);

Save the file to the local system

Given two arguments, get allows you to simply write the remote file to a local file, which can be consumed by other scripts or left where it is as a sort of open API.

$sftp->get('/full/remote/path/to/file', 'path/to/local/file');

Conclusion

phpseclib allows you to do pretty much anything you could think to do over SSH, programmatically, and with PHP, which, let's face it, can be a little bit more friendly to handle than hacking together shell scripts with stuff you found on Stack Overflow because you never bothered to learn bash syntax. There'll always be stuff that'll require a for-real SSH session (and no, I'm not talking about exec()) but for basic file manipulation, phpseclib is a great option.

If you're looking for the whole file together, I've put it up as a gist here