PHP SSH2 Class with Exception Handling

Standard

SSH2 Wrapper Class

The following class takes some of the ideas used to create a contextual socket, and applied to the setup of a SSH2 stream. Currently, only password authentication is supported, but will be updated shortly. Support for SCP and SFTP will be included at a later time.

SSH2 Usage

[php]

$options = array(
‘host’ => ‘127.0.0.1’,
‘port’ => 22,
‘auth’ =>
array(
‘type’ => SSH2::PASS,
‘username’ => ‘user’,
‘password’ => ‘password’,
‘fingerprint’ => ‘xxxx’,
‘ssh_auth_pub’ => ‘3sg325235y43yre’,
‘ssh_auth_priv’ => ‘3sg325235y43yre’,
‘ssh_auth_priv_key’ => ‘3sg325235y43yre’,
)
);

try{
$ssh = new SSH2($options)->connect();
if($ssh->authenticate()){
/* For devices which support OpenSSH and OpenSSH2 Variants */
$exampleOutput = $ssh->exec(array(‘ls -lSha’, ‘cat ~/.bashrc’));

if(!$exampleOutput ){
echo $ssh->getLastError();
}else{
echo $exampleOutput ;
}

/* For devices which support net-sshd, vt100, etc */
$exampleOutput = $ssh->shell(array(‘ls -lSha’, ‘cat ~/.bashrc’));

if(!$exampleOutput ){
echo $ssh->getLastError();
}else{
echo $exampleOutput ;
}
}

$ssh->disconnect();
}
catch(SSH2FailedToConnectException $e){
print_r($e->getMessage());
}
catch(SSH2FailedToAuthenticate $e){
print_r($e->getMessage());
}
[/php]

Get The SSH2 Class

[php]
class SSH2{
private static $connection;
private $error;

var $port = 22;

const PASS = ‘password';
const PUBKEY = ‘publickey';

public function __construct(Array $options){
foreach($options as $opt => $value){
$this->$opt = $value;
}

return $this;
}

final function xdisconnect($reason, $message, $language) {
printf(“Server disconnected with reason code [%d] and message: %s\n”,
$reason, $message);
}

final function connect(){
$callbacks = array(‘disconnect’ => ‘xdisconnect’);

self::$connection = @ssh2_connect($this->host, $this->port, NULL, $callbacks);
if(self::$connection === FALSE){

throw new SSH2FailedToConnectException($this->host, $this->port);
return false;

}

$this->fingerprint = @ssh2_fingerprint(self::$connection);
return true;
}

// sm business
final function authenticate(){
$method = “ssh2_auth_{$this->auth['type']}”;

if(@$method(self::$connection, $this->auth['username'], $this->auth['password']) === FALSE){
throw new SSH2FailedToAuthenticate($this->host, $this->auth['username'], $this->auth['type']);
return false;
}else{
return true;
}
}

public function exec($cmd){
if(is_array($cmd)){
foreach($cmd as $command){
$stream = @ssh2_exec(self::$connection, $command);
$errorStream = @ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);

/* Enable Blocking */
@stream_set_blocking($errorStream, true);
@stream_set_blocking($stream, true);

/* Grab Response */
$response .= stream_get_contents($stream);
$this->error .= stream_get_contents($errorStream);
}
}
else{
$stream = @ssh2_exec(self::$connection, $cmd);
$errorStream = @ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);

/* Enable Blocking */
@stream_set_blocking($errorStream, true);
@stream_set_blocking($stream, true);

/* Grab Response */
$response .= stream_get_contents($stream);
$this->error .= stream_get_contents($errorStream);
}

if(is_null($response)){
return false;
}

return $response;
}

final function shell($cmd){
$stream = ssh2_shell (self::$connection, ‘vt102′, null, 80, 40, SSH2_TERM_UNIT_CHARS);
$output = NULL;

if(is_array($cmd)){
foreach($cmd as $command){
fwrite($stream, $command.PHP_EOL);
sleep(2);

while(( $res = stream_get_contents($stream, -1)) !== false){
$output .= $res;
if($res == ”){
break;
}
}
}
}
else{
fwrite($stream, $cmd.PHP_EOL);
sleep(2);

while(( $res = stream_get_contents($stream, -1)) !== false){
$output .= $res;
if($res == ”){
break;
}
}

}

fwrite($stream, ‘exit’.PHP_EOL);

return $output;
}

public function disconnect(){
@ssh2_exec(self::$connection, ‘exit’);
}

public function getLastError(){
return $this->error;
}
}

/*
* Thrown if a class tries to access the XML parser’s functionality
*
* @author sixeightzero
* @license http://opensource.org/licenses/gpl-license.php GNU General Public Licence
* @copyright (c) 2011 – Mike Mackintosh
* @version 0.1
* @package Zepnik Framework
*/

final class SSH2FailedToConnectException extends Exception
{
/**
* Sets the error message
*
* @todo Add logger output
*/
public function __construct($host, $port)
{
$message = “Failed to connect to host ‘{$host}’ on port {$port}\n”;

// Call the parent constructor
parent::__construct($message);
}
}

final class SSH2FailedToAuthenticate extends Exception
{
/**
* Sets the error message
*
* @todo Add logger output
*/
public function __construct($host, $username, $type)
{
$message = “Failed to authenticate ‘{$username}’ by ‘{$type}’ on host ‘{$host}’\n”;

// Call the parent constructor
parent::__construct($message);
}
}
[/php]

3 thoughts on “PHP SSH2 Class with Exception Handling

    • Thanks for the suggestion!

      I’ve used phpseclib in the past, but had no luck with netsshd/vt100 based systems such as ScreenOS devices. I’ll take another look and see if there has been any improvement.

  1. grahamillustrator

    I’d try the latest SVN. It fixes a number of issues the latest release version had. If you have any issues try posting on the support forums – the guy’s really helpful and you’d be helping to make an even better product!

Leave a Reply