PHPSecLib SFTP Error Handling

In the marketing world, the de facto way to send data around is a file. Usually via SFTP — five years ago it was almost 100% FTP. Occasionally a third party tool will have an API, but clients will almost always only deliver things like product feeds or first party revenue data via a file.

So I do a lot of work with SFTP and, specifically, phpseclib, a pure PHP implementation of SSH2 and SFTP (and some other impressive things).

PHPSecLib has a some what interesting approach to how it deals with errors, which falls into two categories:

  1. Unexpected responses from the server. Sending back a bad packet or having the connection closed, etc.
  2. Failure response from SSH or SFTP. Everything worked, but the operation itself (like puting a file) failed.

In both cases, whatever method produced an error, will return false.

$result = $sftp->put(/* ... */);
if (false === $result) {
    // what happened?!

Unexpected Responses or Events

As mentioned above, this might be the server sending back an unexpected packet or something like the connection closing. In phpseclib 2.X these generate an E_USER_ERROR warning.

Important note: this is changing in 3.X, these types of errors will throw exceptions.

To see if something like this happened combining the shutup operator, @, with error_get_last works fairly well.


$result = @$sftp->put(/* ... */);
if (false !== $result) {
    // hooray it worked!

$err = error_get_last();
if ($err) {
    // unexpected response, etc

    // clear out the error so we don't see it again
    // this is PHP 7+ only

    // maybe throw something here that makes sense the app in question
    throw new PHPSecLibError($err['message']);

Failure Responses from SSH/SFTP

Rather than triggering warnings, these errors log what happened on the SFTP object. These logs are a string representation of the status code and a message on its meaning.

There are a lot of status codes, but in practice quite a few SFTP servers only implement version 3 of the SFTP spec. That only has eight possible status codes.

Use getLastSFTPError to see why an operation failed and handle the status code as the application needs.

$result = @$sftp->put(/* ... */);
if (false !== $result) {
    // hooray it worked!

$last = $sftp->getLastSFTPError();
list($statusCode,) = explode(':', $last, 2);

// pick what needs to be handled specifically or generically
switch ($statusCode) {
        throw new FileNotFoundOnSftp();
        throw PermissionDenied::forWriting();
    // this is the catch all failure response

Thoughts on PHPSecLib’s Error Handling

The most beautiful thing a library can do with its error handling is be consistent. PHPSecLib is consistent, and that makes dealing with it easy enough.

Is the above verbose? Absolutely, but it also makes a lot of sense. The only real exceptional situation to phpseclib is an unexpected response from the server or a connection closed — something it can’t do anything about. Everything else is only worth an exception if the caller deems it to be.