Page 1 of 1
ssh2_exec() and live output???
Posted: Sat Jul 05, 2014 1:25 pm
by Wolf_22
I have some PHP that executes a single Shell app on a Red Hat app server. The Shell command takes a very long time to process because it's an archival routine that archives a bunch of stuff on the system. The thing I'm trying to do is output the results as it's happening on the system (i.e. - the routine takes specific files and archives them based on the CSV it's fed and after it successfully archives each file from each line, it gives some output about what the results of the archive attempt were). Is it possible to do this?
I've managed to get a working example of simple ping on localhost via live output (see below), but using SSH2 to connect and then execute commands against a remote machine and display the results via live output is a completely separate issue. I've scoured Google all over the place and it seems like popen() and flush() are the key but I'm just not sure how to make it work.
The main question is this:
how would I use ssh2_connect() and then output live results of "ls" using popen()? I figure if I can get that to work with live results, then I can handle the rest via trial and error of replacing "ls" with whatever Shell commands I need (such as issuing a command to execute a Shell file).
Code: Select all
<?php
header('Content-Encoding: none;');
set_time_limit(0);
$cmd = "ping 127.0.0.1";
$handle = popen($cmd, "r");
if (ob_get_level() == 0)
ob_start();
while(!feof($handle)) {
$buffer = fgets($handle);
$buffer = trim(htmlspecialchars($buffer));
echo $buffer . "<br />";
echo str_pad('', 4096);
ob_flush();
flush();
usleep(1);
}
pclose($handle);
ob_end_flush();
?>
Any insight into this is appreciated. Maybe I'm going about all this the wrong way... I just thought it'd be cool to have live output like this on the page I'm working on.
Re: ssh2_exec() and live output???
Posted: Sat Jul 05, 2014 4:40 pm
by requinix
It should work basically the same way. What was your code?
Re: ssh2_exec() and live output???
Posted: Sat Jul 05, 2014 7:59 pm
by Weirdan
ssh2_exec returns a stream (just like popen), so like requinix said, it should work the same way.
Re: ssh2_exec() and live output???
Posted: Sat Jul 05, 2014 9:38 pm
by Wolf_22
Thanks for the quick responses, guys. I didn't realize that ssh2_exec() returned the same type of resource as popen(). I thought I read differently but you're definitely correct. I guess I got caught up in all the details (tree in the forest thing).
That aside, here's what I've come up with:
Code: Select all
<?php
//Display live ls output from an app server.
$domain = '<your domain>';
$user = '<your username>';
$pass = '<your password>';
header('Content-Encoding: none;');
set_time_limit(0);
$connection = ssh2_connect($domain, 22);
ssh2_auth_password($connection, $user, $pass);
$handle = ssh2_exec($connection, 'ls ');
//$handle = popen('ls', "r");
if (ob_get_level() == 0)
ob_start();
while(!feof($handle)) {
$buffer = fgets($handle);
$buffer = trim(htmlspecialchars($buffer));
stream_set_blocking($handle, true);
$stream = ssh2_fetch_stream($handle, SSH2_STREAM_STDIO);
$files = explode("\n", stream_get_contents($stream));
//I think I've done something wrong here... The code works, but just not like that "ping" code above that I posted where it returns live output (or "as it's happening").
foreach($files as $file){
echo $file.'<br />';
echo str_pad('', 4096);
ob_flush();
flush();
usleep(1);
}
}
pclose($handle);
ob_end_flush();
?>
It basically works but not "live" like the ping code I posted above... Am I close?
Re: ssh2_exec() and live output???
Posted: Sun Jul 06, 2014 12:41 pm
by Weirdan
stream_get_contents() blocks until it has read all the output. So it doesn't get to the foreach loop until after the command has finished execution.
What you basically need is something like this:
Code: Select all
// pseudo-code, I'm omitting some details here
$h = ssh2_exec();
$out = ssh2_fetch_stream($h);
while (!feof($out)) {
$line = fgets($out);
echo $line;
flush();
sleep(1);
}
fclose($out);
Re: ssh2_exec() and live output???
Posted: Sun Jul 06, 2014 9:53 pm
by Wolf_22
I managed to get something to come back based on your psuedo but it's still not like I think I should be seeing...
Here's what I have:
Code: Select all
<?php
$domain = 'foobar.whatever';
$user = 'user1234';
$pass = 'pass1234';
header('Content-Encoding: none;');
set_time_limit(0);
$connection = ssh2_connect($domain, 22);
ssh2_auth_password($connection, $user, $pass);
$h = ssh2_exec($connection, 'ls ');
$out = ssh2_fetch_stream($h, SSH2_STREAM_STDIO);
if (ob_get_level() == 0)
ob_start();
while (!feof($out)) {
$line = fgets($out);
echo $line;
flush();
sleep(1);
}
fclose($out);
ob_end_flush();
?>
It still looks like it's only displaying after the entire script has finished processing though--maybe I'm chasing after something that can't be done? In my mind, I keep thinking I should be seeing the results of
ls as it happens but it just doesn't work that way from what I can tell, no matter what I do.
Anyway, thanks for trying to help.

Re: ssh2_exec() and live output???
Posted: Mon Jul 07, 2014 8:32 am
by Weirdan
If you're using ob_*, you also need ob_flush() before the flush().
Keep in mind that some browsers may have it's own buffering (I know for sure that IE did) that you can't flush directly. For those you would need to add some junk data, just to make their buffers overflow.
Re: ssh2_exec() and live output???
Posted: Mon Jul 07, 2014 4:48 pm
by Wolf_22
Here's what I have now:
Code: Select all
<?php
$domain = '<whatever>';
$user = '<username>';
$pass = '<password>';
header('Content-Encoding: none;');
set_time_limit(0);
$connection = ssh2_connect($domain, 22);
if(ssh2_auth_password($connection, $user, $pass)){//If authentication is successful...
//$h = ssh2_exec($connection, 'ls');
$h = ssh2_exec($connection, 'man ping');
$out = ssh2_fetch_stream($h, SSH2_STREAM_STDIO);
if (ob_get_level() == 0)
ob_start();
while (!feof($out)) {
$line = fgets($out);
echo $line.'<br />';
echo str_pad('', 4096);
ob_flush();
flush();
sleep(1);
}
fclose($out);
ob_end_flush();
}
?>
2 questions:
1.) The while logic displays contents every second, regardless of whether the issued command truly takes that amount of time to process against the app server. The ping code toward the top didn't do this... For example, issuing the "ping" command took however long it needed to be done (and displayed, live) but if I swapped it with something like "dir", the results were displayed instantaneously because that command didn't require the amount of time that ping needed to send the ping requests. I guess what I'm curious about here is whether or not it's possible to require something like the sleep logic if and only if it's necessary? In other words, the current logic seems to be more so "mimicking" live output... Thoughts?
2.) When I change the newest code above to issue a "man ls" or something involving a man command, the words are displayed with extra letters... (I.e. - repeated letters in the man page headings such as "NNAAMMEE", etc.) Is this an encoding issue? If so, should I expect this with all the output that is returned that has words, etc. or is this something unique with the man page headings? It doesn't appear to be happening with *all* of the text--just specific parts of the man page output. If it does have something to do with encoding, what kind of encoding should I set the output to be? As you can see, right now I'm not using any encoding--I did this just to get something going.
Thanks for the heads-up about the ob_flush() statement. That got things going.
(Any feedback about the above is appreciated and thanks for sticking with me on this.)
Re: ssh2_exec() and live output???
Posted: Mon Jul 07, 2014 9:04 pm
by Weirdan
1. Possible, but quite complex comparing to what you have now. stream_select() should do the trick. However you could resort to decreasing the timeout instead, like your ping code did (by using usleep(1) instead of sleep(1)).
2. That's man-specific. It's a way to get bold text on a teletype (so your terminal emulator is considered pretty dumb by man): type a letter, shift back, type it again.
Re: ssh2_exec() and live output???
Posted: Tue Jul 08, 2014 2:59 pm
by pickle
What about redirecting output to a file, then using file_get_contents() in a loop?