Dec 24

SSH2 & PHP Howto Guide: SSH Connections Made Easy in PHP

Posted by Jaimie Sirovich on Dec. 24th, 2008. 6 comments — voice your opinion.

BECOME AN EGGHEAD. SUBSCRIBE TO OUR RSS FEED OR FOLLOW US ON TWITTER!

Learn to be as nerdy as we are by never missing our latest blog entries. Receive great tips, tricks, and ideas on improving your web site every day! Subscribe via our RSS Feed, follow us, or use the chicklets in the sidebar for more options.
X

PHP doesn't come with native support for making SSH connections via the libssh2 libraries. You must use the PECL SSH2 extensions. Installing them can be tricky, but Kevin van Zonneveld does a great job explaining how to install them over here. So I won't go there. The new version, 0.11.0, also seems to be compiling more reliably for everyone.

Unfortunately, the library is sparsely documented, and still buggy in some places. And most of the comments posted on http://www.php.net/ssh2 are just plain wrong! Kudos to Mike Sullivan for fixing some of the issues with non-blocking I/O (And let's not forget to thank Sara Golemon for writing it to begin with!). I list the most conspicuous problems at the bottom of this blog entry for interested parties. Everyone else can use our wrappers to smooth over some of the kinks and make most common tasks trivial to perform.

Our wrapper is released under GNU license and can be used, for example, as follows:

$php_ssh2 = new SSH2('YOURHOST.COM');
$php_ssh2->loginWithPassword('YOUR_LOGIN', 'YOUR_PASSWORD');
echo $php_ssh2->execCommandBlock('find /cat/food');

All Pertinent Features:

$php_ssh2->execCommandBlockNoOutput()

allows execution of a script ignoring output. Note that without blocking execution manually, 2 ssh2_execs will execute asychronously. So it should also be used for shell scripts that have no output. Why? If you never check for data, it will never block — yes, even in blocking mode! This is subtle … until it clicks.

$php_ssh2->setLogReads($setting = true)

enables or disables read logging on the current SSH2 stream.

$php_ssh2->setLogWrites($setting = true)

enables or disables write logging on the current SSH2 stream.

$php_ssh2->getShell($set_blocking = false, $term_type = 'vt102' ... )

opens a shell for the user — generally not needed and much harder to work with.

$php_ssh2->waitPrompt($prompt_regex = '> $', &$buf = '', $timeout_secs = 0)

waits for a specified prompt $prompt_regex (expressed as a regular expression) for $timeout_secs (or 0 to block forever). Returns true or false, leaves response (whether matching or not) buffer in &$buf parameter.

$php_ssh2->writePrompt($command, $add_newline = true)

writes the specified output to stream. Returns what it was able to write.

The rest of the functions are fairly self-explanatory. Check out the library here —
http://www.seoegghead.com/software/ssh2-php-wrappers.seo

Problems/Gotchas I've Observed in PECL SSH2

1. Non-blocking mode buggy and/or coredumps in versions < 0.11.0. So make sure you upgrade.
2. FreeBSD Ports currently reports a patched "usr/ports/security/pecl-ssh2″ version 0.10.0 as 0.11.0 (Not strictly a PECL SSH2 problem, but worth noting as it caused me grief).
3. stream_set_timeout() does not work at all with SSH2 streams — silently always returns false.
4. stream_select() does not work with SSH2 streams — but prints a warning.
5. One must pass NULL to $pty — not false (like some comments on php.net claim), not "" — otherwise LFs ("\n") will get changed to CRLFs ("\r\n"). Text files will mostly survive this, but binary data will be corrupted! This took us a solid hour to debug and involved a hex-editor.

As a consequence of some of the above, there is no good way to do non-blocking I/O in versions < 0.11.0. Period. No timeouts, no polling, no selecting. If you need non-blocking I/O to work reliably, you must upgrade to 0.11.0.

Tell an amigo:
  • Sphinn
  • Digg
  • Reddit
  • del.icio.us
  • StumbleUpon
  • Facebook



No related posts.

Tags:
, , ,



"6 Wise Comments Banged Out Somewhere On The Internet ..."


Clotho

waitPrompt() should return $buf, not $_r, otherwise execCommandBlock() cannot work.

neverpitch

There's a pure-PHP implementation of SSH2 that's probably going to be easier to use than PECL's ssh2 extension:

http://phpseclib.sourceforge.net/

Clotho

I want to execute a command, which may have output if it is correct, and may have no output if it is not correct.If I use execCommandBlocking(), which has no '@' trick, it cannot determine the end of the buffer. If I use execCommandBlockNoOutput(), which has '@' trick, I cannot get the output.

Therefore I make a new function.

function execCommandBlockAnyOutput($command, $not_used = true)
{
$get_stderr = true;
$prompt_regex = '@';
$buf = ";

$command = SSH2::_generateCommand($command, true, $get_stderr, $prompt_regex);
$stream = $this->execCommand($command, true);

while (!$_r = preg_match("#$prompt_regex#", $buf .= fread($stream, 4096))) {
fflush($stream);
}
return $buf;
}

Clotho

To get result with '@', I improve my code above by changing the line:
$prompt_regex = '@';
to
$prompt_regex = '@end@';

And change the line:
return $buf;
to
$pos = strrpos($buf, $prompt_regex);
return substr($buf, 0, $pos);

macrocode

Thank you for this class!

I am having a difficult time using this to interact with an interactive program on the remote side (in one such case, passwd) and am wondering if you have any suggestions for how to use this class and/or PHP's ssh2 extension to interact WITHOUT the use of PHP's expect extension?

Clotho

Hi macrocode,

I will not interact with passwd. Instead, I will modify /etc/shadow directly. Of course you need to encrypt the password before saving it at /etc/shadow.



Care To Bang On The Keys ... ?

BECOME AN EGGHEAD. SUBSCRIBE TO OUR RSS FEED!

Learn to be as nerdy as we are by never missing our latest blog entries. Receive great tips, tricks, and ideas on improving your web site every day! Subscribe via our RSS Feed or use the chicklets in the sidebar.