Reputation: 24073
I'm trying to invoke a long-running shell command inside a PHP CLI script with exec()
. But I can't for the life of me figure out how to interrupt the PHP script and kill the spawned child process(s). It seems like as soon as I call exec()
, my signal handler is ignored. The following code works as I would expect; if I send SIGTERM to the process, it echoes SIGTERM
and exits immediately.
<?php
declare(ticks = 1);
function sig_handler($signo) {
switch ($signo) {
case SIGTERM:
echo 'SIGTERM' . PHP_EOL;
flush();
break;
default:
}
}
pcntl_signal(SIGTERM, 'sig_handler', false);
sleep(60);
?>
However, if I replace sleep(60);
with exec('sleep 60');
, I don't reach my signal handler until the sleep finishes. I have two questions:
exec
(or shell_exec
or proc_open
)?exec
?Upvotes: 5
Views: 5543
Reputation: 111339
The documentation does say that:
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.
(Emphasis mine.) I guess the hanging applies to signal handlers, too.
To be able to control the child process it looks like you have to execute them in the old-fashioned way, with fork+exec:
switch ($pid = pcntl_fork()) {
case -1: // failed to create process
die('Fork failed');
case 0: // child
pcntl_exec($path,$args);
die('Exec failed');
}
Once the parent process has the child's process id in $pid
, it could send SIGINT to the child with posix_kill($pid, SIGINT)
.
Update: apparently you could also use proc_open
and proc_terminate
.
Upvotes: 5