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:
- Unexpected responses from the server. Sending back a bad packet or having the connection closed, etc.
- Failure response from SSH or SFTP. Everything worked, but the operation itself (like
put
ing a file) failed.
In both cases, whatever method produced an error, will return false.
<?php $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.
<?php $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 error_clear_last(); // 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.
<?php $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) { case 'NET_SFTP_STATUS_NO_SUCH_FILE': throw new FileNotFoundOnSftp(); break; case 'NET_SFTP_STATUS_PERMISSION_DENIED': throw PermissionDenied::forWriting(); break; // this is the catch all failure response case 'NET_SFTP_STATUS_FAILURE': default: }
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.