Automating Backup Tasks Remotely with PHP and PECL SSH2 extension

* About SSH2.php

* Introduction

We sleep better at night when scripts are faithfully taking care of our backups and automating various other annoyances that us humans tend to forget about at the worst possible times.

But this can be frustrating to set up for every web site we have, especially when they are on different servers at various web hosts. It is also difficult to monitor.

What if one of the scripts were to fail unpredictably for whatever reason on a remote server, and you do not even notice?

Enter automation with a few PHP scripts and the SSH2 extension. This lets us automate everything from one server with the power of the PHP scripting language.

* PECL SSH2 Installation

First, lets install PECL SSH2:

For Unix and Linux:

Official instructions can be found in the PHP site:

With newer versions of PECL SSH, this command line seems to work well:

pecl install ssh2-beta

But if it does not work, Kevin van Zonneveld has a great write up here: ...

For Windows:

Installing on Windows is very easy. Either follow the directions on the PHP site (less easy), or install WAMP (piece of cake) and enable SSH2 under:

PHP > PHP extensions > php_ssh2

This code fragment is needed if you do not want it enabled in php.ini, and was also necessary for the installation of WAMP I tested with, regardless of what was set in php.ini.

If you get the message "ERROR: PECL ssh2 must be installed" despite enabling php_ssh2 in WAMP, you will need to use this code:

if (!extension_loaded('ssh2')) {
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
} else {

* SSH2 wrapper library

Next, lets load up my library located at:


Proceed to login using password authentication. This is OK if we have the backup machine secured, but if you prefer take some time to implement public key authentication:

$s = new SSH2('MYSERVER');
$s->loginWithPassword('MYLOGIN', 'MYPASSWORD');
$_buf = $s->execCommandBlocking('tar cvf - /www/foo_com/');
file_put_contents('foo_com_backup_' . date('Ymd'), $_buf);


Of course this little setup is not limited to backups. It is perfectly suited to work in a UNIX-expect-ish way for the most mundane or complex tasks.

For example, we might want to periodically log in to check for a file:

$s->loginWithPassword('MYLOGIN', 'MYPASSWORD');
$buf = $s->execCommandBlocking('ls -l /some_directory *.core');

if ($buf) { ... }

You may also read prompts and make decisions with waitPrompt function.

$s->waitPrompt('? ', $_buffer, 10);

if (strstr($_buffer, 'delete all')) {
} else {

That means "wait for a question mark prompt for 10 seconds and give me the output in $_buffer variable. Without waiting 10 seconds it would block forever if there was some unexpected output.

Then writePrompt call sends a 'Y' or an 'N' with a new line character to respond depending on some program logic.

Fairly complex tasks can be automated like this in PHP. And while PHP has expect bindings, I find it a whole lot easier to just use PHP.

I may fashion it to be submitted for PEAR eventually. It will be submitting it to PHPClasses too. For now Please do let me know if you find any bugs!

* About SSH2.php

Of course you may use the SSH2 extension functions yourselves instead of using this wrapper class, but lets discuss some caveats:

1. Blocking timeouts and select() are entirely unsupported by PECL SSH2. That is OK. We can live without it.

I worked around it in this class with non-blocking polling until timeout to simulate the same. Except it also seems that non-blocking I/O also does not work reliably in older versions of the PECL extension. The script will warn you when you set a timeout, if this is the case.

2. I did some sensible stream redirection behind the scenes via the shell to eliminate the need to read from stderr separately. Doing so via PHP without calling select() and limited non-blocking support would be difficult and it makes reading and parsing even more difficult.

Look at the _generateCommand function to see what was done. Please let me know if you see any holes in its logic or bugs.

Lastly, I do not see a straightforward way to ensure that a series of commands complete successfully without echoing a sentinel value and blocking for its output (or any output, really). Use the function execCommandBlockNoOutput to do that.

Examples on many sites use sleep(), but that is not a good idea, since you are assuming the command is executed in that time. Eventually you will be wrong!

For example:

$do_something = // ... some logic
if ($do_something) {

It is not perfect, but it does make automation pretty easy.

That is all for now. Thank you for reading. Check out our blog if you get a chance. I will be releasing some other good stuff in the next few months.





© 2008 All rights reserved. Privacy policy | Terms of use