PHP how to run multi bash command in background - php

To run one command in the background, it works well.
$cmd = 'ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null &';
exec($cmd, $output, $return_var);
Then I need to sleep for some time before the ffmpeg command. I refer to How do I run multiple background commands in bash in a single line? which works well directly in the bash console.
While not works in the below PHP script, which will return when the bash command finishes running.
$cmd = '(sleep 5; ffmpeg -re -i ./97.mp4 -vcodec copy -acodec copy -f flv -y rtmp://example.com/c/190843?auth_key=7e2682b5 > output 2>&1 </dev/null) &';
exec($cmd, $output, $return_var);

I think you also need to handle sleep's stdout/stderr.
( sleep 5 > /dev/null 2>&1; ...; ) &
Or you can put the redirection after ( ... ):
( sleep 5; ffmpeg ...no redir here...; ) < /dev/null > /dev/null 2>&1 &

To run multiple commands from on bash command; concatenate using &&.
For instance:
sleep 5 && echo hello && sleep 2 && echo world
This trick can be particularly useful in cron tasks to be able to sequence multiple items within the same minute, as a different sleep value can be used as an offset before starting the command.

Related

2>&1 and log file at the same time

I'm using this code to run ffmpeg and return when it succeeded or failed using 2> & 1 and $var. The problem is that I would also like to generate a log.txt with the current ffmpeg process. I know it does using 2> log.txt but how do I use both options at the same time?
<?php
$ffmpeg = '"D:\FFMPEG\bin\ffmpeg.exe"' . " -loglevel verbose -n -i https://URLVIDEO -map p:0 -acodec copy -bsf:a aac_adtstoasc -vcodec copy video.mp4 2>&1";
exec($ffmpeg, $output, $var);
if($var){
echo 'error';
}else{
echo 'success';
}
?>
Use 1> log.txt 2>&1.
stdout is redirected to the log file and stderr is appended to stdout.
If I understood correctly, you want both streams to be logged. If so, another option is to use &> e.g. cmd &> log.txt.

PHP: can not exec a script in the background

I have main php script on web-server nginx+php-fpm and try to run another php script in background using GET request from web-browser. Line code in main.php to call detect.php:
exec("/usr/bin/php -f /var/www/detect.php 6 > /dev/null 2>&1 &");
detect.php does not start. I don't have any errors.
If to remove "&":
exec("/usr/bin/php -f /var/www/detect.php 6 > /dev/null 2>&1 ");
detect.php starts successfully.
From shell bash with "&" :
sudo -u www-data /usr/bin/php -f /var/www/detect.php 6 > /dev/null 2>&1 &
Script detect.php starts successfully.
try this and make sure your php path are correct
$dir=dirname(__FILE__);
$file_name="detect.php";
$php_path="/usr/bin/php";
$args = array(6);
$command1="cd $dir";
$command2="$php_path $file_name ".implode(" ",$args) ." > /dev/null 2>/dev/null &";
$final_command=$command1."; ".$command2;
shell_exec($final_command);

php - How to exec in background multiple bash command

I'm trying to run in background two bash command using exec function.
$action[] = "/path/script1 par1 > log1 2>&1";
...
$action[] = "/path/script2 par2 > log2 2>&1";
...
$cmd = "( " .implode(' && ',$action). " ) &";
exec($cmd);
script1 and script2 are bash scripts.
Scripts are properly executed and their output is correctly saved in their log files, but my application hangs. It seems that last & doesn't work.
I have already tried:
$cmd = "bash -c \"" .implode(' && ',$action). "\" &";
If I run a single command, it works in background.
I captured $cmd and if I run:
( /path/script1 par1 > log1 2>&1 && /path/script2 par2 > log2 2>&1 ) &
from command line, it works in background.
I'm using Apache/2.0.52 and PHP/5.2.0 on Red Hat Enterprise Linux AS release 3 (Taroon Update 2)
The answer is hidden in the PHP exec documentation:
If a program is started with this function, in order for it to
continue running in the background, the output of the program must be
redirected to a file or another output stream. Failing to do so will
cause PHP to hang until the execution of the program ends.
Add a redirection to the top level of your command line:
exec( "bash -c \"( ./script1 par1 > log1 2>&1 && ./script2 par2 > log2 2>&1 ) \" >/dev/null 2>&1 & " );
and without bash -c:
exec( "( ./script1 par1 > log1 2>&1 && ./script2 par2 > log2 2>&1 ) >/dev/null 2>&1 & " );
Tested with PHP 5.3.3-7 (command line invocation): Program hangs before adding the redirect operators, and terminates afterwards.

PHP exec or shell_exec not returning process id (PID) on Windows Wamp

I am on windows 7, using a WampServer, and trying to use FFMPEG.
The encoding works, but I can't get a process id back from either the exec()
method nor the shell_exec() methods.
This is my code :
$cmd = C:\ffmpeg\bin\ffmpeg.exe -i "C:\...\4ch.wav" -ar 44100 -ab 48000 -f mp3 -y "C:\...\enc_4ch.mp3"
This what I was trying to do with shell_exec :
shell_exec("nohup $cmd > /dev/null & echo $!");
And with exec :
exec("nohup " . $this->_command . " > /dev/null 2>/dev/null &") ; // returns null
exec("nohup " . $this->_command . " > /dev/null 2>&1 &"); // also returns null
Please let me know what I do wrong, as I'd like later to use the following method to check if my process is still running :
private function is_process_running($proccess_id)
{
exec("ps $proccess_id", $process_state);
return (count($process_state) >= 2);
}
thank you in advace
You are using echo $! to get the process ID, and that specific command is not available on Windows as it is a unix shell command. The procedure link should work: How to get PID from PHP function exec() in Windows?

How to get PID from PHP function exec() in Windows?

I have always used:
$pid = exec("/usr/local/bin/php file.php $args > /dev/null & echo \$!");
But I am using an XP virtual machine to develop a web app and I have no idea how to get the pid in windows.
I tried this on a cmd:
C:\\wamp\\bin\\php\\php5.2.9-2\\php.exe "file.php args" > NUL & echo $!
And it gets the file executed, but the output is "$!"
How can I get the pid into the var $pid? (using php)
I'm using Pstools which allows you to create a process in the background and capture it's pid:
// use psexec to start in background, pipe stderr to stdout to capture pid
exec("psexec -d $command 2>&1", $output);
// capture pid on the 6th line
preg_match('/ID (\d+)/', $output[5], $matches);
$pid = $matches[1];
It's a little hacky, but it gets the job done
I landed here thanks to google and decided that this ten years old post needs more info based on How to invoke/start a Process in PHP and kill it using Process ID...
Imagine that you want to execute a command (this example uses ffmpeg to stream a file on a windows system to a rtmp server). You could command something like this:
ffmpeg -re -i D:\wicked_video.mkv -c:v libx264 -preset veryfast -b:v 200k -maxrate 400k -bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 -ar 44100 -f flv rtmp://<IP_OF_RMTP_SERVER>/superawesomestreamkey > d:\demo.txt 2> d:\demoerr.txt
The first part is explained here and the last part of that command outputs to files with that name for logging purposes:
> d:\demo.txt 2> d:\demoerr.txt
So lets assume that that command works. You tested it.
To run that command with php you can execute it with exec but it will take time (another subject, check set_time_limit), its a video handled by ffmpeg via php. Not the way to go but it is happening in this case.
You can run the command in background but what is the pid of that Process?
We want to kill it for some reason and psexec gives only the 'process ID" runned by a user. And there is only one user in this case.
We want multiple processes on the same user.
Here is a example to get the pid of a runned process in php:
// the command could be anything:
// $cmd = 'whoami';
// This is a f* one, The point is: exec is nasty.
// $cmd = 'shutdown -r -t 0'; //
// but this is the ffmpeg example that outputs seperate files for sake
$cmd = 'ffmpeg -re -i D:\wicked_video.mkv -c:v libx264 -preset veryfast -b:v 200k -maxrate 400k -bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 -ar 44100 -f flv rtmp://10.237.1.8/show/streamkey1 > d:\demo.txt 2> d:\demoerr.txt';
// we assume the os is windows, pipe read and write
$descriptorspec = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
];
// start task in background, when its a recource, you can get Parent process id
if ( $prog = is_resource( proc_open("start /b " . $cmd, $descriptorspec, $pipes ) ) )
{
// Get Parent process Id
$ppid = proc_get_status($prog);
// this is the 'child' pid
$pid = $ppid['pid'];
// use wmic to get the PID
$output = array_filter( explode(" ", shell_exec("wmic process get parentprocessid,processid | find \"$pid\"" ) ) );
array_pop($output);
// if pid exitst this will not be empty
$pid = end($output);
// outputs the PID of the process
echo $pid;
}
The code above should echo the pid of the 'inBackground' runned process.
Note that you need to save the pid to kill it later if it is still running.
Now you can do this to kill the process: (imagine the pid is 1234)
//'F' to Force kill a process
exec("taskkill /pid 1234 /F");
Here is my first post ever here on stackoverflow,
I hope this will help someone. Have a awesome and not lonely christmas ♪♪
You will have to install an extra extension, but found the solution located at Uniformserver's Wiki.
UPDATE
After some searching you might look into tasklist which coincidently, you may be able to use with the PHP exec command to get what you are after.
Here's a somewhat less "hacky" version of SeanDowney's answer.
PsExec returns the PID of the spawned process as its integer exit code. So all you need is this:
<?php
function spawn($script)
{
#exec('psexec -accepteula -d php.exe ' . $script . ' 2>&1', $output, $pid);
return $pid;
} // spawn
echo spawn('phpinfo.php');
?>
The -accepteula argument is needed only the first time you run PsExec, but if you're distributing your program, each user will be running it for the first time, and it doesn't hurt anything to leave it in for each subsequent execution.
PSTools is a quick and easy install (just unzip PSTools somewhere and add its folder to your path), so there's no good reason not to use this method.

Categories