How to terminate a process - php

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.

Related

Killing a process with PHP after exec()

<?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

most simple way to start a new process/thread in PHP

Scenario:
Shared hosting, so no ability to install new extensions + no CRON
A submitted request needs to perform some heavy processes.
I want the answer to the client to go as fast as possible, and the heavy lifting to continue immediately, but not stop the client.
can be on a new thread (if it is possible) also no problem with starting a new process.
What is the best way to do this?
On *nix:
exec('/path/to/executable > /dev/null 2>&1 &');
On Windows:
$WshShell = new COM('WScript.Shell');
$oExec = $WshShell->Run('C:\path\to\executable.exe', 0, false);
Both of these will spawn a new process that will run a-synchronously, completely disconnected from the parent. As long as your host allows you to do it.
You can google by key: php continue processing after closing connection.
The following links that relate to your problem, are:
Continue processing after closing connection
http://php-fpm.org/wiki/Features#fastcgi_finish_request.28.29
http://www.php.net/manual/en/features.connection-handling.php
You can use belong command to continue executing without user aborting
ignore_user_abort(true);
set_time_limit(0);
You use fastcgi_finish_request to alert client to stop the response output. And your scripts will continue to be executed.
An example:
// redirecting...
ignore_user_abort(true);
set_time_limit(0);
header("Location: ".$redirectUrl, true);
header("Connection: close", true);
header("Content-Length: 0", true);
ob_end_flush();
flush();
fastcgi_finish_request(); // important when using php-fpm!
sleep (5); // User won't feel this sleep because he'll already be away
// do some work after user has been redirected
To complement #DaveRandom's answer: you don't actually need to redirect STDERR to STDOUT (with 2>&1).
You need to redirect STDOUT though, if you want to prevent the parent process from hanging waiting for the child to finish. This is required cause exec will return the last line of the output of the child process, therefore, it needs to wait for the child's STDOUT to be closed.
That doesn't mean you need to redirect it to /dev/null. You can redirect it to some other file, or even to some other file descriptor (like STDERR: 1>&2).
exec('/path/to/executable'): will start a new process and wait for it to finish (i.e. blocking the parent process).
exec('/path/to/executable &'): basically the same as the above.
$pid = exec('/path/to/executable > /dev/null & echo $!'): will start a process in the background, with child and parent processes running in parallel. The output of /path/to/executable will be discarded, and $pid will receive the PID of the child process.
Using 2>&1 is actually not necessary, cause exec ignores the STDERR of the child process. It is also probably undesirable cause it will make it harder to find some errors, cause they will be just silently thrown away. If you omit 2>&1, you can pipe the STDERR of the parent process to some log file, that can be checked later when something goes wrong:
php /path/to/script.php 2>> /var/log/script_error.log
By using the above to start the script which triggers the child processes, everything that script.php and any child process write to STDERR will be written to the log file.
There are no threads in PHP. You could cheat by sending back an HTML page that triggers an Ajax call to start the heavy process in a new request. But if it's shared hosting, my guess is that you'll quickly hit the limits on memory, time or CPU usage imposed by your hosting provider.
$WshShell = new COM('WScript.Shell');
$oExec = $WshShell->Run('C:\xampp\php\php.exe C:\xampp\htdocs\test.php -a asdf', 0, true);
Cannot pass argv to test.php.
var_dump($argv);

How can I capture the PID and output of a backgrounded PHP process at the same time?

I have one PHP script that has to start a second script in the background using exec. The parent script needs to capture the PID of this new process, but I also need to capture any potential output of the child script so it can be logged in the database. I can't just have the child script log to the database because I also need to capture fatal errors or anything that might indicate a problem with the script. The PID is used because the parent process needs to be able to check on the child and see when it finished. The child processes are sometimes run as crons, so forking isn't an option here either. I don't want two execution paths to debug if there are problems.
This was my first solution and it can capture the output, but fails to get the correct PID.
// RedirectToLog.php just reads stdin and logs it to the databse.
$cmd="php child.php </dev/null 2>&1 | php RedirectToLog.php >/dev/null 2>&1 & echo $!";
The problem here is that $! is the PID of the last process that was started in the background which ends up being RedirectToLog.php instead of child.php.
My other idea was to attempt to use a FIFO file (pipe).
$cmd1="php RedirectToLog.php </tmp/myFIFO >/dev/null 2>&1 &"
$cmd2="php child.php </dev/null >/tmp/myFIFO 2>&1 & echo $!"
This one didn't work because I couldn't get RedirectToLog to reliably consume the fifo and when it did, sometimes child.php failed to write EOF to the pipe which left both ends waiting on the other and both processes would hang until one was killed.
use proc_open to get full fd connectivity while starting a process. Take the resource returned by proc_open and use proc_get_status to get the pid.
$descriptors = array( ... ); // i suggest you read php.net on this
$pipes = array();
$res = proc_open($cmd,$descriptors,$pipes);
$info = proc_get_status($res);
echo $info['pid'];
I haven't fully grasped all your problems, but this should get you started.
I think you need to use
proc_open &
proc_get_status
I'm guessing the only reason you really want to capture the childs PID is to monitor it. If so, it might be easier to use proc_open. That way you can basically open file handles for stdin, stdout and stderr and monitor everything from the parent.

php process forking and get the child process id

Objective:
My script will download a remote file upon form submission, since the file might be big, I would like to fork off a process and let the user go on with his/her life.
Example of a command:
wget -q --limit-rate=1k --tries=10 "http://helios.gsfc.nasa.gov/image_euv_press.jpg" -O /web/assets/content/image/image_euv_press.jpg
Method tried:
pcntl forking,
$pid = pcntl_fork();
if ( $pid == -1 ) {
exit;
} else if ( $pid ) {
//We are the parent process, the pid is child pid right?
return $pid;
} else {
// We are the child process
exec($command.' > /dev/null');
// > /dev/null &
posix_kill(getmypid(),9);
return;
}
I do get the PID but then there is a risk that the forked process becomes a zombie and since I am using nginx -> php-fpm (tested and confirmed, upon running several times alot of defunct php-fpm processes), I would have to restart the server just to eliminate the zombies, this would leave me to PID exhaustion attack? ( I am guessing)
Background process:
exec($command . ' > /dev/null &');//background process
$proc = passthru ("ps aux | grep '$command'");//search for the command
echo var_dump($proc);
$pid = (int)(next(explode(' ',$proc)));//parse the pid (not implemented)
Question:
the background process method works but it's not clean, is there a better way to fork off a process to download and get that wget command PID so I can kill it later?.
I have tried echoing $! after doing the exec just to get the PID but exec('echo $!') doesnt return anything, i think it's because every exec is a different "space"
I added '> /dev/null 2>/dev/null &' to the end of the command on my terminal it would return something like: [3] 30751, but through php exec, there is no way to capture that returned PID.
Thank you.
While not a direct answer, the following link might help you get it done:
The Mysteries Of Asynchronous Processing With PHP - Part 3
Practical PHP: Process control
As an alternative to PHP's native pctl functions, consider using Gearman:
Gearman provides a generic application framework to farm out work to other machines or processes that are better suited to do the work. It allows you to do work in parallel, to load balance processing, and to call functions between languages. It can be used in a variety of applications, from high-availability web sites to the transport of database replication events.
Try the following command:
exec("ps -C $command -o pid=", $pids);
But I recommend you to use Zend Server Job Queue, which exists for these objectives.
Try adding the "echo $!" to the same execution flow as the launched background process.
I.e. something like this:
shell_exec("$command & echo $!");

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