kvz.io
24 Jul 2007
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 practicle 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
Update
On recent Ubuntu machines, there’s no need to do any compiling anymore:
$ aptitude install libssh2-1-dev libssh2-php |
You can now test if PHP recognizes it’s new ssh2 extension by running:
$ php -m |grep ssh2 |
It should return: ssh2
If the above works for you (you should see also: «Build process completed successfully»), you can skip to: Great! PHP supports SSH — time to code.
Otherwise we need to compile manually, continue reading here.
Prerequisites
Packages
First let’s install the following packages:
$ aptitude install php5-dev php5-cli php-pear build-essential openssl-dev zlib1g-dev |
That should set us up alright.
libssh2
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 |
Вот и все! Легко, не так ли?
- Update: since December 26th 2008, libssh2 has reached version 1.0. Though I have not tested it: it has been reported to work. So you may want to check sf.net and download the latest stable version.
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 a php.ini file (I’d recommend a separate one: /etc/php5/conf.d/ssh2.ini
). Make sure it reads:
extension=ssh2.so |
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)
Метод 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:
<?php 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); } } } ?> |
Метод 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:
<?php 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:
<?php 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:
<?php $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 streamsetblocking to false.
Can’t get enough?
PHP can send files over ssh!
<?php ssh2_scp_send($con, "/tmp/source.dat", "/tmp/dest.dat", 0644); ?> |
Не работает?
Check the following:
- Did you follow every step of the prerequisites & installation how to in this article?
- On the serverside, ‘PasswordAuthentication yes’ must be enabled in the sshd_config. Default is yes on most servers, but in some cases you will have to turn this on yourself by making sure the following line is in place in the file:
/etc/ssh/sshd_config: PasswordAuthentication yes
If you’ve made any changes, ssh needs a restart
$ /etc/init.d/ssh restart |
Post a comment here if it’s still failing. Don’t forget to paste the error that you’re getting.
make: *** [ssh2.lo] Error 1
If you get the error:
/usr/include/php5/Zend/zend_API.h:361: note: expected char * but argument is of type const unsigned char * make: *** [ssh2.lo] Error 1 |
that’s because of PHP 5.3 incompatibility. Try this patch:
$ mkdir -p /usr/src \ && cd /usr/src \ && wget http://pecl.php.net/get/ssh2-0.11.0.tgz \ && tar xvfz ssh2-0.11.0.tgz \ && cd ssh2-0.11.0 \ && wget http://remi.fedorapeople.org/ssh2-php53.patch \ && patch -p0 < ssh2-php53.patch \ && phpize && ./configure --with-ssh2 \ && make |
make: *** [ssh2fopenwrappers.lo] Error 1
If you get the error:
/tmp/pear/download/ssh2-0.11.0/ssh2_fopen_wrappers.c:49: error: for each function it appears IN.) make: *** [ssh2_fopen_wrappers.lo] Error 1 ERROR: `make' failed |
This is the reported fix (thanks to BuNker).
Альтернативы
There have been some additional developments since the writing of this article. Checkout:
Net_SSH2, PEAR’s SSH wrapper (driver based to support multiple ways of establishing the connection)
SSH2, another wrapper by Jaimie Sirovich
phpseclib, a pure PHP implementation — no additional libraries, binaries, bindings required (against all odds, still pretty fast with mcrypt installed)
http://kvz.io/blog/2007/07/24/make-ssh-connections-with-php/