PHP: how to start a detached process?

11,518

Solution 1

No, detaching can't be done with exec() directly (nor shell_exec() or system(), at least not without changing the command, and using third-party tool which does detach).


If you have the pcntl extension installed, it would be:

function detached_exec($cmd) {
    $pid = pcntl_fork();
    switch($pid) {
         // fork errror
         case -1 : return false;

         // this code runs in child process
         case 0 :
             // obtain a new process group
             posix_setsid();
             // exec the command
             exec($cmd);
             break;

         // return the child pid in father
         default: 
             return $pid;
    }
}

Call it like this:

$pid = detached_exec($cmd);
if($pid === FALSE) {
    echo 'exec failed';
}

// ... do some work ...

// Optionally, kill child process (if no longer required).
posix_kill($pid, SIGINT);
waitpid($pid, $status);

echo 'Child exited with ' . $status;

Solution 2

Provided your current user has sufficient permissions to do so this should be possible with exec and alike:

/*
/ Start your child (otherscript.php)
*/
function startMyScript() {
    exec('nohup php otherscript.php > nohup.out & > /dev/null');
}

/*
/ Kill the script (otherscript.php)
/ NB: only kills one process at the time, otherwise simply expand to 
/ loop over all complete exec() output rows
*/
function stopMyScript() {
    exec('ps a | grep otherscript.php | grep -v grep', $otherProcessInfo);
    $otherProcessInfo = array_filter(explode(' ', $otherProcessInfo[0]));
    $otherProcessId = $otherProcessInfo[0];
    exec("kill $otherProcessId");
}

// ensure child is killed when parent php script / process exits
register_shutdown_function('stopMyScript');

startMyScript();
Share:
11,518
Dalius
Author by

Dalius

Updated on July 22, 2022

Comments

  • Dalius
    Dalius over 1 year

    Currently my solution is:

    exec('php file.php >/dev/null 2>&1 &');
    

    and in file.php

    if (posix_getpid() != posix_getsid(getmypid()))
        posix_setsid();
    

    is there any way I can do this just with exec?

  • Dalius
    Dalius over 10 years
    I do not want to daemonize the process nor do I need to fork it. I just need to start another php process that wouldn't receive SIGINT when the one who created it exits. (I'm not really sure how a daemon is different from a process that is detached from the terminal?)
  • hek2mgl
    hek2mgl over 10 years
    Check my example again. Isn't it what you want? ;) The only difference to a daemon is that the does not run forever but will be killed on fathers exit.
  • Dalius
    Dalius over 10 years
    Basically yes, but try implementing that in a simple function that returns true or false. (It MUST NOT block). And I don't want the new process to be killed, it will exit itself.
  • Dalius
    Dalius over 10 years
    Yes it is :) Though I think it's an overkill to make a fork, so I think I'll stick with detaching the process when it starts.
  • hek2mgl
    hek2mgl over 10 years
    What do you expect exec() does under the hood? It will start a shell (that's why you can use output redirection in commands) You may replace the exec() in child with the actual php code of the child.. (can be a function or a class method, ....) then you'll save the additional shell and the php-cli call and it would be best for performance
  • user229044
    user229044 over 10 years
    Please do not do this ever again: stackoverflow.com/review/suggested-edits/3201462 This is absolutely not how Stack Overflow works. You are way, way out of line, crossing out somebody else's answer and pointing their answer to your own.
  • Philzen
    Philzen over 10 years
    Apologies - no pun intended. I was under the impression S.O. was very serious about not having incorrect information here, thus i merely suggested to remove hek2mgl's info that this couldn't be done with exec() function.
  • user229044
    user229044 over 10 years
    Voting is the way we sort content here.
  • Philzen
    Philzen over 10 years
    @hek2mgl Looking at the example in my answer, could you look into updating/deleting the first sentence in yours? Otherwise your solution looks very clean and feasible :)
  • hek2mgl
    hek2mgl over 10 years
    @Philzen Yours is a working solution but it is more a shell script than a PHP script. The work of detaching the process is not done by the exec() function, it is done by nohup. But in was questioned whether the exec() function can do it. However yours is a good workaround if the pcntl extension isn't installed
  • hek2mgl
    hek2mgl over 10 years
    This is a good workaround if the pcntl extension isn't available +1
  • Philzen
    Philzen over 10 years
    "detaching the process is not done by the exec() function, it is done by nohup" - fair point you have there :)
  • vvolodko
    vvolodko over 9 years
    If parent process won't exit immediately after fork the child process should fork one more time to prevent creating zombie.
  • hek2mgl
    hek2mgl over 9 years
    @vvolodko Thanks for your hint! (and srry for my late reply) Will read through this and update my answer