How to SSH with PHP with Debian and Ubuntu

 

http://fitxers.oriolrius.cat/2160/howto-ssh-php.html

Make SSH connections with PHP

Not everyone knows about PHP‘s capabilities of making SSH connections and executing remote commands, but it can be very useful. I’ve been using it a lot in PHP CLI applications that I run from cronjobs, but initially it was a pain to get it to work. The PHP manual on Secure Shell2 Functions is not very practice or thorough for that matter, so I would like to share my knowledge in this how to, to make it a little less time consuming setting this up.

In this article I’m going to assume that:

  • You’re running Debian / Ubuntu
    If not, you will have to substitute the package manager aptitude with whatever your distribution provides
  • You’re running PHP 5
    If not, just replace php5 with php4 everywhere
  • You have basic knowledge of PHP & server administration
  • You already have PHP installed

Prerequisites

Packages

First let’s install the following packages:

sudo aptitude update
sudo aptitude install php5-dev php5-cli php-pear buid-essential \
openssl-dev zlib1g-dev

That should set us up alright.

libssh2

Now we need libssh2 from sourcefourge. We have to compile this, but no worries, this is all you need to do:

cd /usr/src
wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
tar -zxvf libssh2-0.14.tar.gz
cd libssh2-0.14/
./configure
make all install

That’s it! Easy right? If you want you can check if there’s a newer version at sf.net but 0.14 will do just fine.

Installation

ssh2.so

Next we need to link libssh & PHP together. There’s a PECL module for this so let’s install using:

pecl install -f ssh2

The -f makes sure ssh2 is installed even though there’s not a stable candidate. You could also use the package name: ssh2-beta to overrule this.

Now you need to make sure our new ssh2.so module is loaded by PHP. Edit your php.ini file (for CLI utitilies: /etc/php5/cli/php.ini, for Apache utilities /etc/php5/apache2/php.ini)

extension=ssh2.so

It should be placed beneath the: “Dynamic Extensions” section somewhere around line 515.

 

Great! PHP supports SSH – time to code

You’ve just enabled ssh2 support in PHP. Now how can we make use of this? There are 2 options. SSH supports the: 

  • execute method
    This tells the server’s operating system to execute something and pipe the output back to your script. (recommended)
  • shell method
    This opens an actual shell to the operating system, just as you would normally when logging in with your terminal application. Some routers that don’t have a full POSIX compliant implementation, but run their own application as soon as you login, require this. (advanced)

Method 1: Execute

Best would be to create functions or even a class for the following code, but this is the basic idea and will definitely get you started:

if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")
// log in at server1.example.com on port 22
if(!($con = ssh2_connect("server1.example.com", 22))){
  echo "fail: unable to establish connection\n";
} else {
  // try to authenticate with username root, password secretpassword
  if(!ssh2_auth_password($con, "root", "secretpassword")) {
    echo "fail: unable to authenticate\n";
  } else {
    // allright, we're in!
    echo "okay: logged in...\n";
    
    // execute a command
    if(!($stream = ssh2_exec($con, "ls -al" )) ){
      echo "fail: unable to execute command\n";
    } else{
      // collect returning data from command
      stream_set_blocking( $stream, true );
      $data = "";
      while( $buf = fread($stream,4096) ){
        $data .= $buf;
      }
      fclose($stream);
    }
  }
}

Method 2: Shell

Best would be to create functions or even a class for the following code, but this is the basic idea and will definitely get you started:

if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist")
// log in at server1.example.com on port 22
if(!($con = ssh2_connect("server1.example.com", 22))){
  echo "fail: unable to establish connection\n";
} else {
  // try to authenticate with username root, password secretpassword
  if(!ssh2_auth_password($con, "root", "secretpassword")) {
    echo "fail: unable to authenticate\n";
  } else {
    // allright, we're in!
    echo "okay: logged in...\n";
    
    // create a shell
    if(!($shell = ssh2_shell($con, 'vt102', null, 80, 40, SSH2_TERM_UNIT_CHARS))){
      echo "fail: unable to establish shell\n";
    } else{
      stream_set_blocking( $shell, true );
      // send a command 
      fwrite($shell,"ls -al\n");
      sleep(1);
      
      // & collect returning data
      $data = "";
      while( $buf = fread($shell,,4096) ){
        $data .= $buf;
      }
      fclose($shell);
    }
  }
}

Tips

Sometimes when a server is busy, or a connection is buggy, the buffer may run dry, and the PHP script stops collecting data from a command output (even though the command hasn’t completed yet!). There are a couple of things you could do about that:

ssh2_exec($con, 'ls -al; echo "__COMMAND_FINISHED__"' );

Now, in the loop where you keep checking for the buffer, just see if the COMMAND_FINISHED line is coming by. Because then you know you have all the data. To avoid infinite loops, just limit the loop with a timeout of 10 seconds or so:

$time_start = time();
$data = "";
while( true ){
  $data .= fread($stream, 4096);
  if(strpos($data,"__COMMAND_FINISHED__") !== false){
    echo "okay: command finished\n";
    break;
  }
  if( (time()-$time_start) > 10 ){
    echo "fail: timeout of 10 seconds has been reached\n";
    break;
  }
}

In the example above, you’d better set stream_set_blocking to false.

Can’t get enough?

PHP can send files over ssh!

ssh2_scp_send($con, "/tmp/source.dat", "/tmp/dest.dat", 0644);

Leave a Reply