i want to run a command in console then 'echo' it via a log file. i wrote following code. but it doesnt work. if i put command direct in 'popen' it waits first the page load..
what can be done ?
shell_exec("nohup $cmd > out.log 2>&1");
if( ($fp = popen("tail out.log" , "r")) ) {
while( strpos($txt, "FINISH") == false){
$txt = fread($fp, 1024);
echo $txt;
flush();
}
}
Related
This PHP snippet should execute a simple command via SSH (stripped down to minimal working example):
$sshconn = ssh2_connect($HostAddr, 22);
ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
$stdout = ssh2_exec($sshconn, 'echo hello');
if ($stdout !== false)
{
stream_set_blocking($stdout, true);
while (!feof($stdout))
{
$proc_stdout = fgets($stdout, 3E6);
if ($proc_stdout !== false) echo $proc_stdout;
}
fclose($stdout);
}
Works great as long as there is any output to stdout. However, if stdout remains empty, the loop turns into an endless loop.
$stdout = ssh2_exec($sshconn, 'echo hello >&2');
How do I read the stdout properly if
stdout may be empty
but stdout may also very large (several Gigabytes, impossible to slurp into a variable by a single call to stream_get_contents or the like).
Addendum: My real world code that hangs executes mysqldump with an unknown parameter. Obviously, echo -n >&2 works as expected, although its stdout is also empty.
If anyone stumbles upon this too: stderr has to be read too.
$sshconn = ssh2_connect($HostAddr, 22);
ssh2_auth_pubkey_file($sshconn, $user, $sshkey . '.pub', $sshkey);
$stdout = ssh2_exec($sshconn, 'echo Hello >&2');
if ($stdout !== false)
{
$stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
stream_set_blocking($stdout, false);
stream_set_blocking($stderr, false);
while (!feof($stdout))
{
$proc_stdout = fgets($stdout, 3E6);
if ($proc_stdout !== false) echo $proc_stdout;
$proc_stderr = fgets($stderr, 3E6);
if ($proc_stderr !== false) fwrite(STDERR, $stderr);
}
fclose($stdout); fclose($stderr);
}
The disadvantage of this is that the SSH connection is no longer usable afterwards (a further ssh2_exec cannot be executed).
A possible solution is to keep both streams blocking and read stdout and stderr non-interleaved:
$stdout = ssh2_exec($sshconn, 'echo Hello >&2');
$stderr = ssh2_fetch_stream($stdout, SSH2_STREAM_STDERR);
stream_set_blocking($stdout, true);
stream_set_blocking($stderr, true);
while ($content = fread($stdout, 3E6)) echo $content;
while ($content = fread($stderr, 3E6)) fwrite(STDERR, $content);
I invite anyone who knows how to have the streams interleaved and keep the SSH connection usable to post another answer.
I'm trying to create an interactive website that can open game servers and stop them for personal use, (and some close friends). I am trying to get a server to start on my linux machine, output the real-time results of the log file to the browser, and be able to stop the process and the output. I'm running into a problem where the output will load, but when i click on the button to stop the server/php script, it will continue to wait for another line to display. Once another line is displayed, everything works normally and the process is ended on the linux machine and the php script is stopped. Currently I am forced to ssh into my linux box, and append something to the log file to get the script to stop and the server processes to end.
What can i do to fit these needs? I have also noticed i am unable to access any other page while the php script is running, is there a fix for this? Below are some things i have tried. I also need to be able to pass commands to the process to control the server through the web browser. I am using the apache2 web server.
Example 1:
<?php
session_start();
if (isset($_POST['test'])) {
shell_exec('pkill -f ./starbound_server');
$continueLoop = false;
}
?>
<!DOCTYPE html>
<head>
</head>
<body>
<form method="post">
<p>
<button name="test">Run ctl+c</button>
</p>
</form>
<?php
if (!isset($_POST['test'])) {
shell_exec('cd /home/steam/steaamcmd/STEAM/starbound/linux64/ && ./starbound_server > /var/www/html/sb.txt &');
//shell_exec('ping 192.168.0.20 > sb.txt &');
set_time_limit(0);
}
//$file = fopen('test.txt', 'r') or die("UNABLE TO OPEN");
//echo nl2br(fread($file, filesize("test.txt")));
function follow($file) {
$continueLoop = true;
$size = 0;
while ($continueLoop) {
clearstatcache();
$currentSize = filesize($file);
if ($size == $currentSize) {
sleep(.3);
continue;
}
$fh = fopen($file, "r");
fseek($fh, $size);
while ($d = fgets($fh)) {
echo "$d <br>";
}
fclose($fh);
$size = $currentSize;
if (isset($_POST['test'])) {
$continueLoop = false;
}
//if (!isset($firstRun)) {
// echo "<br><br>First Run<br><br>";
// $firstRun = "ran";
//}
flush();
ob_flush();
}
}
if (!isset($_POST['test'])) {
follow("/var/www/html/sb.txt");
} else {
echo "Processes terminated";
}
?>
Example 2:
<?php
session_start();
if (isset($_POST['test'])) {
flush();
ob_flush();
shell_exec('pkill -f ./starbound_server');
$continueLoop = false;
}
?>
<!DOCTYPE html>
<head>
</head>
<body>
<form method="post">
<p>
<button name="test">Run ctl+c</button>
</p>
</form>
<?php
if (!isset($_POST['test'])) {
shell_exec('cd /home/steam/steaamcmd/STEAM/starbound/linux64/ && ./starbound_server > /var/www/html/sb.txt &');
$handle = popen("tail -f /var/www/html/sb.txt 2>&1", 'r');
while(!feof($handle)) {
flush();
ob_flush();
$buffer = fgets($handle);
echo "$buffer\n";
echo "TEST";
flush();
ob_flush();
}
pclose($handle);
} else {
shell_exec("echo 'end' >> /var/www/html/sb.txt");
echo "closed";
}
?>
Example 3:
<!DOCTYPE html>
<head>
</head>
<body>
<?php
$cmd = "cd /home/steam/steaamcmd/STEAM/starbound/linux64/ && ./starbound_server";
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
flush();
ob_implicit_flush(true);
ob_end_flush();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
flush();
}
}
echo "</pre>";
proc_close($process);
?>
</body>
Ealier I used function in a seperate file that could be call by script for cron.
function processExists($file = false) {
$exists = false;
$file = $file ? $file : basename(__FILE__);
$command = "ps -ef | grep -v grep | grep $file";
exec($command, $pids);
if (count($pids) > 1) {
$exists = true;
}
return $exists;
}
It could be executed from any php script as:
if (processExists(basename(__FILE__))) {
echo 'Process in already running ';
exit(0);
}
For some reason it doesn't work in Debian6.
Now I add in the beginning of every script:
$fh = fopen(__FILE__, 'r');
if (!flock($fh, LOCK_EX | LOCK_NB)) {
echo 'Script is already running!!!' . "\n";
exit(0);
}
It causes duplication of code in every script I tried to create function in a seperate file to call from any php script when neccessary, for example something like this:
function stopIfRunning($file)
{
$fh = fopen($file, 'r');
if(!flock($fh, LOCK_EX | LOCK_NB)) {
echo 'Script is already running!!!' . "\n";
exit(0);
}
}
And calling from php script:
stopIfRunning(__FILE__);
But it doesn't work in this case. Could you please explain why it doesn't work in this case?
If you need to make sure the service is running, use Daemontools or Monit.
And personally, I would use plain Bash, not PHP, if custom implementation needed.
BTW, you can easily debug your ps command in terminal.
FILE it is name of running file.
stopIfRunning(__FILE__);
function stopIfRunning($file)
{
$fh = fopen($file, 'r');
....
}
Here you tried open this executed file for lock.
It seems the problem is with $fh on stopIfRunning function. If the file with with functiona changed it with:
$fh = null;
function stopIfRunning($file)
{
global $fh;
echo $file, "\n";
$fh = fopen($file, 'r');
if (!$fh) {
echo 'Failed to open file', "\n";
}
if(!flock($fh, LOCK_EX | LOCK_NB)) {
echo 'Script is already running!!!' . "\n";
exit(0);
}
}
And call it in the file that should be launched using cron:
stopIfRunning(__FILE__);
Here global variable is used, which is not good. It would be great if somebody suggest a solution without global variable.
I have this shell program that I want to execute by php. The problem is that it can potentially take a long time, and as of that I need it to have real-time updating to the user's browser.
I read that I may need to use popen() to do that, but I am sort of (ok, I really am :P) a PHP noob and can't figure out how I may be able to do it.
Would appreciate any help!
if( ($fp = popen("your command", "r")) ) {
while( !feof($fp) ){
echo fread($fp, 1024);
flush(); // you have to flush buffer
}
fclose($fp);
}
there is a dirty easy option
`yourcommand 1>&2`;
redirecting the stdout to the stderr.
there are two possible behaviors:
Non Block, where you need to do something else between flushs (#GameBit show how to do it).
With Block, where you wait until the called command finish, in this case look passthru function
I used this solution. It works fine for me.
$commandString = "myexe";
# Uncomment this line if you want to execute the command in background on Windows
# $commandString = "start /b $commandString";
$exec = popen($commandString, "r");
# echo "Async Code Test";
while($output = fgets($exec, 2048))
{
echo "$output <br>\n";
ob_flush();
flush();
}
pclose($exec);
try this code (tested on Windows machine + wamp server)
header('Content-Encoding: none;');
set_time_limit(0);
$handle = popen("<<< Your Shell Command >>>", "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();
sleep(1);
}
pclose($handle);
ob_end_flush();
I'm trying to run a bash script using shell_exec but It doesnt seem to work. (Nothing seems to happen) I'm using nginx and the latest php5-cgi. Heres what the php file looks like:
<?php
$startserver = "./startserver.sh";
$startserver = shell_exec($startserver);
$getprocess = "pidof hlds_amd";
$pid = shell_exec($getprocess);
$fh = fopen('closeserver.sh', 'w');
$command = "kill -9 $pid";
fwrite($fh, $command);
fclose($fh);
$string = "at -f closeserver.sh now + 1 hour";
$closer = shell_exec($string);
?>
and this is what the bash script looks like:
#!/bin/bash
cd /home/kraffs/srcds
./hlds_run -game cstrike -autoupdate +maxplayers 12 +map de_dust2 > hlds.log 2>&1 &
Theres no errors in the phpscript and the file gets created just fine but $startserver doesnt seem to get executed and $pid is empty. Did I miss something in the php file or do I need to change permissions for an user? Thanks for your help.
replace shell_exec, with below function and try again
<?php
function runcmd($EXEC_CMD)
$handle = popen ($EXEC_CMD, 'r');
$output = "";
if ($handle) {
while(! feof ($handle)) {
$read = fgets ($handle);
$output .= $read;
}
pclose($handle);
}
return $output;
}
?>