I am running a command using shell_exec()
Let's say I have 400 directories and I can not wait for the command to run completely.
Is there a way, I can get the output Asynchronous?
$output = shell_exec('ls');
echo "<pre>$output</pre>";
$cmd = $command;
$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();
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
echo "<pre>";
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
flush();
}
}
echo "</pre>";
The Code above Worked perfectly for me, This is copied from another answer I can no longer find. If you put a ping 127.0.0.1 in the $command it works exactly like it does in a terminal.
Check this: Is there a way to use shell_exec without waiting for the command to complete?
And instead of redirecting to /dev/null you could redirect to a tmp file that you read later.
Related
I'm trying to execute a bash script from php and getting its output in real time.
I am applying the answers found here:
However they are not working for me.
When I invoke the .sh script on this way, it works fine:
<?php
$output = shell_exec("./test.sh");
echo "<pre>$output</pre>";
?>
However, when doing:
<?php
echo '<pre>';
passthru(./test.sh);
echo '</pre>';
?>
or:
<?php
while (# ob_end_flush()); // end all output buffers if any
$proc = popen(./test.sh, 'r');
echo '<pre>';
while (!feof($proc))
{
echo fread($proc, 4096);
# flush();
}
echo '</pre>';
?>
I have no output in my browser.
I also tried to call the variable instead of the script in both cases, I mean:
<?php
$output = shell_exec("./test.sh");
echo '<pre>';
passthru($output);
echo '</pre>';
?>
This is my test.sh script:
#!/bin/bash
whoami
sleep 3
dmesg
Use the following:
<?php
ob_implicit_flush(true);
ob_end_flush();
$cmd = "bash /path/to/test.sh";
$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
);
$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print $s;
}
}
?>
Change test.sh to:
#!/bin/bash
whoami
sleep 3
ls /
Explanation:
dmesg requires permissions. You need to grant webserver's user permissions for that. In my case apache2 is being run via www-data user.
ob_implicit_flush(true): Turns implicit flushing on. Implicit flushing will result in a flush operation after every output call, so that explicit calls to flush() will no longer be needed.
ob_end_flush(): Turns off output buffering, so we see results immediately.
I have a PHP script that calls a Python script which loops through a text file outputting specific lines to the webpage. The PHP script calls the Python script and echoes its output like this...
$output = shell_exec($command);
echo ($output);
The relevant Python code is this...
for myStr in myList:
myObj=re.match(r'(\s|\S)+\[(?P<specificVal>\d+)(\s|\S)+',myStr)
specificVal = int(myObj.group('specificVal'))
if specificVal in range(min,max):
print ('<p>%s</p>' % (myStr))
This works for about a hundred lines then it stops outputting, when there might be as many as a few thousand. Is there a better way to do this, or do I just need to edit some php.ini options? Thank you!
This could have to do with shell_exec() not returning all of the output for some reason. You could try using the more-robust proc_open():
<?php
$fileDescriptors = array(
0 => array("pipe", "r"), // STDIN
1 => array("pipe", "w"), // STDOUT
2 => array("pipe", "w") // STDERR
);
$pipes = array();
flush();
$process = proc_open($command, $fileDescriptors, $pipes, realpath('.'), array());
if (!is_resource($process))
{
error_log("Failed to execute '$command'");
return;
}
while ($data = fgets($pipes[1]))
{
print $data;
flush();
}
You might gain some performance benefit from not calling flush(); on every loop iteration as well.
If this still isn't giving you all of the output, I would be suspicious of a problem in the Python script, and you should post more of it to make it easier to debug.
i'm trying to write a php page that
call for a server program like
gdb
the problem is if i did
<?php
exec(" gdb code", $out);
?>
the PHP call for the command and exist
BUT what i want to do is like open a "terminal" session
where the user enter commands in that program like
gdb code
..
break main
..
run
and after each command i give him the output and he give me the next command
and it won't work if i did it like this
<?php
exec(" gdb code", $out);
exec(" break", $out);
exec(" run", $out);
?>
and the PHP can be run from a browser
and i tried it with pro_open
<?php
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "/var/www/err.log", "a")
);
$cwd = '/var/www';
$env = array('some_option' => 'aeiou');
$StdErr='';
$process = proc_open('/bin/bash', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
fwrite($pipes[0], "gcc code ");
fwrite($pipes[0], " break main");
fflush($pipes[0]);
fclose($pipes[0]);
while(!feof($pipes[1])) {
echo fgets($pipes[1], 1024);
}
echo $StdErr;
fclose($pipes[1]);
$return_value = proc_close($process);
echo "command returned : $return_value\n";
}
and thank you .
Edit just saw you do try it from a browser. There is absolutely no simple way to do this. If you want an interactive session from the browser, you must run a separate daemon process and forward commands to it from PHP (and return output).
This is not simple at all; so if you still feel like doing this.. I would recommend starting with how to create a deamon; and then write a tcp socket server (or other IPC).
Excuse the crappy grammar
I've this shell script running from a PHP site.
In the shell script (Audit shell script),
I have 3 options:
1) Process script
2) Display results
3) Exit
Tried the codes below and doesn't seem to work, the PHP site displayed blanks.
<?php
session_start();
exec('/Desktop/test.sh');
exec('1');
$output = exec('2');
echo "<pre>$output</pre>";
?>
Any help will be greatly appreciated.
<?php
session_start();
// This line executes '/Desktop/test.sh' as if it had been called from the
// command line
// exec('/Desktop/test.sh');
// This line attempts to execute a file called '1', which would have to be
// in the same directory as this script
// exec('1');
// This line attempts to execute a file called '2', which would have to be
// in the same directory as this script, and capture the first line of the
// output in $output
// $output = exec('2');
// I think you want to be doing something more like this - this executes the
// shell script, passing "1" and "2" as arguments, and captures the whole
// output as an array in $output
exec('/Desktop/test.sh "1" "2"', $output);
// Loop the output array and echo it to the browser
echo "<pre>";
foreach ($output as $lineno => $line) echo "Line $lineno: $line\n";
echo "</pre>";
?>
It seems to me that you could do with reading the manual page for exec() properly...
Try using proc_open instead of exec; it gives you more control of process input/output. Something like:
<?php
$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("file", "/dev/null", "a") // stderr is a file to write to
);
$cwd = '/Desktop';
$env = array();
$process = proc_open('/Desktop/test.sh', $descriptorspec, $pipes, $cwd, $env);
if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be sent to /dev/null (ie, discarded)
fwrite($pipes[0], "1\n");
fwrite($pipes[0], "2\n");
fclose($pipes[0]);
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
// It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock
$return_value = proc_close($process);
echo $output;
}
?>
Note: I've lifted this code from the PHP Manual's proc_open page
I execute the following command to make a database backup:
$exec = exec("mysqldump --opt
--user=$database_user
--password=$database_pass
--host=$database_host
$database_name > $output_filename", $out, $status);
To check if mysqldump failed I do:
if ($status == 0) {
// OK
} else {
// Error
// How could I print the error message here ?
}
In case something goes wrong and mysqldump fails, how could I get the error message ?
You can use proc_open (as also suggested by Emil). below is a somewhat more complete example of how to achieve what you want.
$exec_command = "mysqldump --opt
--user=$database_user
--password=$database_pass
--host=$database_host
$database_name"
$descriptorspec = array(
0 => array("pipe", "r"), // stdin pipe
1 => array("file", $output_filename, "w"), // stdout to file
2 => array("pipe", "w") // stderr pipe
);
$proc = proc_open($exec_command, $descriptorspec, $pipes);
fwrite($pipes[0], $input); //writing to std_in
fclose($pipes[0]);
$err_string = stream_get_contents($pipes[2]); //reading from std_err
fclose($pipes[2]);
$return_val = proc_close($proc);
EDIT:
changed output to write to file
You'll need to use proc_open if you want to read stderr. The example in the manual should get you going.
If you are using shell_exec, append 2>&1 to the command, it will redirect STDERR to STDOUT.