Killing a process with PHP after exec() - php

<?php
$dira = dirname(__DIR__);
$output = exec($dira . "\\htdocs\\PocketMine-MP-stable\\start.cmd");
echo $output
?>
I need to find a way to kill the process after starting it with exec() this is for a

exec returns Once the process terminates. So after exec you cannot kill the process as it Is no longer running. You have to run the process with proc_open And you can then kill it with proc_terminate.
EDIT:
Actualy you can have exec return earlier if you redirect output of the command to a file And append & to the end of the command (or use nohup; Linux only maybe) so it runs in background. But getting the pid to send kill signal to it is only possible by name And that Is not very reliable

You may use posix_kill to kill a process with identifier pid.
Usage
//...
exec($dira . "\\htdocs\\PocketMine-MP-stable\\start.cmd", $output);
$pid = (int)$output[0];
$killed = posix_kill(int $pid , int $sig);
You should see all signals and their codes in your system using: kill
-l
Check my Repl example

Related

How to make a non-blocking php exec call?

I need to echo text to a named pipe (FIFO) in Linux. Even though I'm running in background with '&' and redirecting all output to a /dev/null, the shell_exec call always blocks.
There are tons of answers to pretty much exactly this question all over the internet, and they all basically point to the following php manual section:
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.
And sure enough, when I try the non-blocking approach (of backgrounding and redirecting to /dev/null) with other commands like sleep, php successfully executes without hanging. But for the case of echo-ing to the FIFO, php hangs even though running the same command with bash produces no visible output and immediately returns to the shell.
In bash, I can run:
bash$ { echo yay > fifo & } &> /dev/null
bash$ cat fifo
yay
[1]+ Done echo yay > fifo
but when running the following php file with php echo.php:
<?php
shell_exec("{ echo yay > fifo & } &> /dev/null");
?>
it hangs, unless I first open fifo for reading.
So my question is, why is this blocking, but sleep isn't? In addition, I want to know what is happening behind the scenes: when I put the '&' in the php call, even though the shell_exec call blocks, the echo call clearly doesn't block whatever bash session php invoked it on, because when I CTRL+C out of php, I can read 'yay' from the FIFO (if I don't background the echo command, after CTRL+C the FIFO contains no text). This suggests that perhaps php is waiting on the pid of the echo command before going to the next instruction. Is this true?
I've been trying something similar and in the end came up with this solution:
/**
* This runs a shell command on the server under the current PHP user, that is in CLI mode it is the user you are logged in with.
* If a command is run in the background the method will return the location of the tempfile that captures the output. In that case you will have to manually remove the temporary file.
*/
static public function command($cmd, $show_output = true, $escape_command = false, $run_in_background = false)
{
if ($escape_command)
$cmd = escapeshellcmd($cmd);
$f = trim(`mktemp`);
passthru($cmd . ($show_output ? " | tee $f" : " > $f") . ($run_in_background ? ' &' : ''));
return $run_in_background ? $f : trim(`cat $f ; rm -rf $f`);
}
The trick is to write the output to a temporary file and return that when the command has finished (blocking behavior) or just return the file path (non-blocking behavior). Also, I'm using passthru rather than shell_exec because interactive sessions are not possible with the latter because of the blocking behavior.

How to get process PID from PHP on Windows

I am developing a web-based application and I need to run a Matlab script to process some information.
The problem is that I have a limitation on the maximum number of Matlab processes running at the same time and because of this, I have to get the PID of each process in order to know if any of them has crashed and which one it was.
I have used some methods to get its PID, but for some reason running a simple command like 'notepad.exe' works fine and gets the correct PID, but when I run my script it gets the wrong PID.
One of the methods I tried is this one:
$process = "matlab";
$command = "-sd ".$softExecPath." -r \"analyse('".$videoDataPath."', '".$id_video_data."') \" ";
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->exec($process." ".$command);
$pid = intval($oExec->ProcessID);
And the other one is:
$process = "matlab";
$command = "-sd ".$softExecPath." -r \"analyse('".$videoDataPath."', '".$id_video_data."') \" ";
$command = $process." ".$command;
// use psexec to start in background, pipe stderr to stdout to capture pid
exec("C:/AppServ/www/PsTools/psexec.exe -d -accepteula $command 2>&1", $output);
// capture pid on the 6th line
preg_match('/ID (\d+)/', $output[5], $matches);
$pid = $matches[1];
Both of them get a PID but none of them is the real one.
On Windows, the Matlab program that you call to launch Matlab (the one pointed to by the shortcut in the Start Menu and on the path if you added it) is just a launcher program that goes on to run another matlab.exe which is the actual program, and then returns immediately. The PID you're getting back is that of the launcher program, which'll be gone by the time the real Matlab is doing work.
Two things you can do: You can run the actual matlab.exe program directly by finding it in the bin/win32 or similar platform-specific directory under the Matlab installation. Then you'll get the right PID back. Or you can fiddle with the -wait option to make the launcher program run synchronously, which means it'll block until the child matlab.exe exits, so it'll still show up in the process list while Matlab is running.

Use PHP's proc_open + bypass_shell to run an executable in the background AND retrieve the correct PID?

So, In PHP on Windows: is it possible to both run an executable in the background AND retrieve its PID? I've deduced that it's possible to accomplish both tasks separately, but not together.
Backgrounding the Process
To background a process launched via the SHELL, the command 'start /B "bg" myprog.exe' must be used and the the SHELL process must be closed immediately after.
To do this, many people use pclose( popen( ... ) ) like so pclose( popen( 'start /B "bg" myprog.exe', 'r') ); but to my knowledge it's impossible to retrieve the pid when using popen.
Because it's impossible to get the pid with popen, we must look to proc_open.
Getting the PID
Using proc_open we can retrieve the pid of the exe if and only if bypass_shell is set to true.
If bypass_shell is set to false (the default), Windows returns the pid of the SHELL. For more info see: https://bugs.php.net/bug.php?id=41052
The Problem Explained
The start /B command fails when passed to proc_open when bypass_shell = true because it skips the SHELL and sends the commandline arguments directly to myprog.exe which doesn't know what to do with them.
Conversely, If bypass_shell = false (the default) and proc_close is used to close the SHELL immediately, myprog.exe runs in the background just like when using pclose( popen( ... ) ) BUT the incorrect pid is returned (we get the pid of the SHELL).
So, is backgrounding + correct pid retrieval possible?
If not, what's the next best thing? I need to do this for a PHP script that will be deployed on shared hosting so no third party extensions can be installed. The best I can come up with is taking a snapshot of tasklist before and after launching myprog.exe in the background and then cross-analyzing the results. Note that myprog.exe can be running concurrently.
If it helps, although it shouldn't make a difference, myprog.exe is actually ffmpeg (which comes installed on most shared webhosts).
A Temporary Solution
// background the process
pclose( popen( 'start /B "bg" ffmpeg.exe', 'r') );
// get the pid using tasklist
exec( 'TASKLIST /NH /FO "CSV" /FI "imagename eq ffmpeg.exe" /FI "cputime eq 00:00:00"', $output );
$output = explode( '","', $output[0] );
$pid = $output[1];
this is not exactly an answer for OP's question, since it won't work on windows server, but it will work just fine on any linux server with exec() enabled, so it might help someone ;)
$pidfile = 'myPidFile'; //coule be done better with tempnam(), but for this example will do like that ;)
$outputfile = '/dev/null'; //can be any text file instead of /dev/null. output from executable will be saved there
$cmd = 'sleep 30'; // this would normaly take 30 seconds
exec(sprintf("%s > %s 2>&1 & echo $! > %s", $cmd, $outputfile, $pidfile));
$pid = file_get_contents($pidfile);
echo $pid;
//delete pid file if you want
//unlink($pidfile);

How to terminate a process

I am creating a process using proc_open in one PHP script.
How do i terminate this in another script . I am not able to pass the resource returned by the proc_open.
I also tried using proc_get_status() , it returns the ppid . I don't get the pid of the children .
development env : WAMP
Any inputs is appreciated .
I recommend that you re-examine your model to make certain that you actually have to kill the process from somewhere else. Your code will get increasingly difficult to debug and maintain in all but the most trivial circumstances.
To keep it encapsulated, you can signal the process you wish to terminate and gracefully exit in the process you want to kill. Otherwise, you can use normal IPC to send a message that says: "hey, buddy. shut down, please."
edit: for the 2nd paragraph, you may still end up launching a script to do this. that's fine. what you want to avoid is a kill -9 type of thing. instead, let the process exit gracefully.
To do that in pure PHP, here is the solution:
posix_kill($pid, 15); // SIGTERM = 15
You can use some methond to create process, this method usually returns the PID of the new process.
Does this works for You? :
$process = proc_open('php', $descriptorspec, $pipes, $cwd, $env);
$return_value = proc_close($process);
You're best off using something like this to launch your other process:
$pid = shell_exec("nohup $Command > /dev/null 2>&1 & echo $!");
That there would execute the process, and give you a running process ID.
exec("ps $pid", $pState);
$running = (count($pState) >= 2);
to terminate you can always use
exec("kill $pid");
However, you cant kill processes not owned by the user PHP runs at - if it runs as nobody - you'll start the new process as nobody, and only be able to kill processes running under the user nobody.

PHP on a windows machine; Start process in background

I'm looking for the best, or any way really to start a process from php in the background so I can kill it later in the script.
Right now, I'm using: shell_exec($Command);
The problem with this is it waits for the program to close.
I want something that will have the same effect as nohup when I execute the shell command. This will allow me to run the process in the background, so that later in the script it can be closed. I need to close it because this script will run on a regular basis and the program can't be open when this runs.
I've thought of generating a .bat file to run the command in the background, but even then, how do I kill the process later?
The code I've seen for linux is:
$PID = shell_exec("nohup $Command > /dev/null & echo $!");
// Later on to kill it
exec("kill -KILL $PID");
EDIT: Turns out I don't need to kill the process
shell_exec('start /B "C:\Path\to\program.exe"');
The /B parameter is key here.
I can't seem to find where I found this anymore. But this works for me.
Will this function from the PHP Manual help?
function runAsynchronously($path,$arguments) {
$WshShell = new COM("WScript.Shell");
$oShellLink = $WshShell->CreateShortcut("temp.lnk");
$oShellLink->TargetPath = $path;
$oShellLink->Arguments = $arguments;
$oShellLink->WorkingDirectory = dirname($path);
$oShellLink->WindowStyle = 1;
$oShellLink->Save();
$oExec = $WshShell->Run("temp.lnk", 7, false);
unset($WshShell,$oShellLink,$oExec);
unlink("temp.lnk");
}
Tried to achieve the same on a Windows 2000 server with PHP 5.2.8.
None of the solutions worked for me. PHP kept waiting for the response.
Found the solution to be :
$cmd = "E:\PHP_folder_path\php.exe E:\some_folder_path\backgroundProcess.php";
pclose(popen("start /B ". $cmd, "a")); // mode = "a" since I had some logs to edit
From the php manual for exec:
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.
ie pipe the output into a file and php won't wait for it:
exec('myprog > output.txt');
From memory, I believe there is a control character that you can prepend (like you do with #) to the exec family of commands that also prevents execution from pausing - can't remember what it is though.
Edit Found it! On unix, programs executed with & prepended will run in the background. Sorry, doesn't help you much.
On my Windows 10 and Windows Server 2012 machines, the only solution that worked reliably within pclose/popen was to invoke powershell's Start-Process command, as in:
pclose(popen('powershell.exe "Start-Process foo.bat -WindowStyle Hidden"','r'));
Or more verbosely if you want to supply arguments and redirect outputs:
pclose(popen('powershell.exe "Start-Process foo.bat
-ArgumentList \'bar\',\'bat\'
-WindowStyle Hidden
-RedirectStandardOutput \'.\\console.out\'
-RedirectStandardError \'.\\console.err\'"','r'));

Categories