SFTP is a standard and secure protocol through which parties can safely transfer and share data and files. In any case, engaging with an SFTP server programmatically can be challenging. In the following post, we’ll build a full fledged PHP based SFTP client, step by step, so that by the end of the guide, you’ll be able to do it all on your own!
Requirements
First and foremost, you'll need an SFTP server to connect to. If you don't have one, you can get an SFTP endpoint on SFTP To Go in less than 30 seconds.
![](https://sftptogo.com/images/apple-touch-icon.png)
PHP doesn’t come bundled with the SFTP libraries from the get-go, so we’ll need to install the required library, phpseclib.
$ composer require phpseclib/phpseclib
In accordance with the 12 factor app cloud development methodology, you should explicitly define your app’s dependencies, which would make our composer.json file look like this:
{
"require": {
"phpseclib/phpseclib": "^3.0"
}
}
Now the real fun begins!
Creating and dropping SFTP connections
We’ll begin by creating a new class that encapsulates the functionality required for our SFTP client. The public methods we first add allow us to connect to the server using either password authentication or key authentication, and provide the means to disconnect an existing session.
<?php
class SFTPClient
{
private $sftp;
public function __construct($host, $port=22)
{
$this->sftp = new SFTP($host, $port);
if (!$this->sftp->isConnected())
throw new Exception("Failed to connect to ${host} on port ${port}.");
}
// Login with user and password
public function auth_password($username, $password)
{
if (!$this->sftp->login($username, $password))
throw new Exception("Failed to authenticate with username $username " .
"and password.");
}
// Login with SSH agent
public function auth_agent($username)
{
if (!$this->sftp->login($username))
throw new Exception("Failed to authenticate with username $username " .
"and public key.");
}
// Disconnect session
public function disconnect()
{
$this->sftp->disconnect();
}
}
?>
To put our brand new methods to use, we’ll add a main function that instantiates our class and calls the auth_password
function to start a connection, as well as close the connection with the disconnect
function immediately after. We’ll use the environment variable SFTPTOGO_URL
to obtain all the required information for connecting to an SFTP server in a URI format: sftp://user:password@host
. Within our main function, the variable is parsed to extract the username, password, host and optional port.
<?php
function main()
{
$raw_url = getenv('SFTPTOGO_URL');
// Parse URL
$parsed_url = parse_url($raw_url);
if ($parsed_url === false)
{
fwrite(STDERR, "Failed to parse SFTP To Go URL.\n");
exit(1);
}
// Get user name and password
$user = isset($parsed_url['user']) ? $parsed_url['user'] : null;
$pass = isset($parsed_url['pass']) ? $parsed_url['pass'] : null;
// Parse Host and Port
$host = isset($parsed_url['host']) ? $parsed_url['host'] : null;
// Port is always 22
$port = isset($parsed_url['port']) ? $parsed_url['port'] : 22;
fwrite(STDOUT, "Connecting to [${host}] ...\n");
}
main();
?>
Listing Files
Now that we have set up a successful connection, we can add a function to our class and use it to list files on the remote SFTP server. The listFiles
function takes a $remote_dir
argument and returns an array of file names, along with their size and modification timestamp. To call the function, simply pass a path (you can start with .
to traverse the current directory content) and then process the array you get.
<?php
// List remote directory files
function listFiles($remote_dir) {
$tempArray = array();
fwrite(STDOUT, "Listing [${remote_dir}] ...\n\n");
$files = $this->sftp->nlist($remote_dir);
foreach ($files as $file) {
$filetype = $this->sftp->is_dir($file) ? 'dir' : 'file';
$modTime = '';
$size = sprintf("%.2f", $this->sftp->size($file));
if ($filetype == "dir") {
$file .= '/';
$modTime = '';
$size = "PRE";
}
$tempArray[] = $file;
printf("%19s %12s %s\n", $modTime, $size, $file);
}
return $tempArray;
}
?>
Upload File
Now it’s time to upload a file. Use the uploadFile
function and pass two arguments: the path to the local file to upload and the target remote path. A function call would look like this: $client->uploadFile("./local.txt", "./remote.txt");
<?php
// Upload local file to remote file
public function uploadFile($local_file, $remote_file)
{
fwrite(STDOUT, "Uploading [${local_file}] to [${remote_file}] ...\n");
$data_to_send = file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("Could not open local file: $local_file.");
if (!$this->sftp->put($remote_file, $data_to_send))
throw new Exception("Could not send data from file: $local_file.");
}
?>
Download File
Last but not least: Use the downloadFile
function to download a file. Pass the path to the remote file and a local path in which the downloaded file will be stored, to the function. You would call the function like this: $client->downloadFile("./remote.txt", "./download.txt");
<?php
// Download remote file to local file
public function downloadFile($remote_file, $local_file)
{
fwrite(STDOUT, "Downloading [${remote_file}] to [${local_file}] ...\n");
$contents = $this->sftp->get($remote_file);
if ($contents === false)
throw new Exception("Could not open remote file: $remote_file.");
file_put_contents($local_file, $contents);
}
?>
![](https://sftptogo.com/images/apple-touch-icon.png)
The Whole Thing
That’s it! If you would like to run the entire program from start to finish, copy the following code and save it as main.php
:
<?php
use phpseclib3\Net\SFTP;
class SFTPClient
{
private $sftp;
public function __construct($host, $port=22)
{
$this->sftp = new SFTP($host, $port);
if (!$this->sftp->isConnected())
throw new Exception("Failed to connect to ${host} on port ${port}.");
}
// Login with user and password
public function auth_password($username, $password)
{
if (!$this->sftp->login($username, $password))
throw new Exception("Failed to authenticate with username $username " .
"and password.");
}
// Login with SSH agent
public function auth_agent($username)
{
if (!$this->sftp->login($username))
throw new Exception("Failed to authenticate with username $username " .
"and public key.");
}
// Disconnect session
public function disconnect()
{
$this->sftp->disconnect();
}
// List remote directory files
function listFiles($remote_dir) {
$tempArray = array();
fwrite(STDOUT, "Listing [${remote_dir}] ...\n\n");
$files = $this->sftp->nlist($remote_dir);
foreach ($files as $file) {
$filetype = $this->sftp->is_dir($file) ? 'dir' : 'file';
$modTime = '';
$size = sprintf("%.2f", $this->sftp->size($file));
if ($filetype == "dir") {
$file .= '/';
$modTime = '';
$size = "PRE";
}
$tempArray[] = $file;
printf("%19s %12s %s\n", $modTime, $size, $file);
}
return $tempArray;
}
// Upload local file to remote file
public function uploadFile($local_file, $remote_file)
{
fwrite(STDOUT, "Uploading [${local_file}] to [${remote_file}] ...\n");
$data_to_send = file_get_contents($local_file);
if ($data_to_send === false)
throw new Exception("Could not open local file: $local_file.");
if (!$this->sftp->put($remote_file, $data_to_send))
throw new Exception("Could not send data from file: $local_file.");
}
// Download remote file to local file
public function downloadFile($remote_file, $local_file)
{
fwrite(STDOUT, "Downloading [${remote_file}] to [${local_file}] ...\n");
$contents = $this->sftp->get($remote_file);
if ($contents === false)
throw new Exception("Could not open remote file: $remote_file.");
file_put_contents($local_file, $contents);
}
// Delete remote file
public function deleteFile($remote_file){
fwrite(STDOUT, "Deleting [${remote_file}] ...\n");
$this->sftp->delete($remote_file);
}
}
function main()
{
$raw_url = getenv('SFTPTOGO_URL');
// Parse URL
$parsed_url = parse_url($raw_url);
if ($parsed_url === false)
{
fwrite(STDERR, "Failed to parse SFTP To Go URL.\n");
exit(1);
}
// Get user name and password
$user = isset($parsed_url['user']) ? $parsed_url['user'] : null;
$pass = isset($parsed_url['pass']) ? $parsed_url['pass'] : null;
// Parse Host and Port
$host = isset($parsed_url['host']) ? $parsed_url['host'] : null;
// Port is always 22
$port = isset($parsed_url['port']) ? $parsed_url['port'] : 22;
fwrite(STDOUT, "Connecting to [${host}] ...\n");
try
{
$client = new SFTPClient($host, $port);
$client->auth_password($user, $pass);
//*
//* List working directory files
//*
$client->listFiles(".");
//*
//* Upload local file to remote file
//*
$client->uploadFile("./local.txt", "./remote.txt");
//*
//* Download remote file to local file
//*
$client->downloadFile("./remote.txt", "./download.txt");
//*
//* Delete remote file
//*
$client->deleteFile("./remote.txt");
}
catch (Exception $e)
{
echo $e->getMessage() . "\n";
}
}
main();
?>
To run the code, use the command:
php main.php
You can also clone our repo or check out more code samples on Github.