php execute a background process

Solution 1:

Assuming this is running on a Linux machine, I've always handled it like this:

exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));

This launches the command $cmd, redirects the command output to $outputfile, and writes the process id to $pidfile.

That lets you easily monitor what the process is doing and if it's still running.

function isRunning($pid){
    try{
        $result = shell_exec(sprintf("ps %d", $pid));
        if( count(preg_split("/\n/", $result)) > 2){
            return true;
        }
    }catch(Exception $e){}

    return false;
}

Solution 2:

Write the process as a server-side script in whatever language (php/bash/perl/etc) is handy and then call it from the process control functions in your php script.

The function probably detects if standard io is used as the output stream and if it is then that will set the return value..if not then it ends

proc_close( proc_open( "./command --foo=1 &", array(), $foo ) );

I tested this quickly from the command line using "sleep 25s" as the command and it worked like a charm.

(Answer found here)

Solution 3:

You might want to try to append this to your command

>/dev/null 2>/dev/null &

eg.

shell_exec('service named reload >/dev/null 2>/dev/null &');

Solution 4:

I'd just like to add a very simple example for testing this functionality on Windows:

Create the following two files and save them to a web directory:

foreground.php:

<?php

ini_set("display_errors",1);
error_reporting(E_ALL);

echo "<pre>loading page</pre>";

function run_background_process()
{
    file_put_contents("testprocesses.php","foreground start time = " . time() . "\n");
    echo "<pre>  foreground start time = " . time() . "</pre>";

    // output from the command must be redirected to a file or another output stream 
    // http://ca.php.net/manual/en/function.exec.php

    exec("php background.php > testoutput.php 2>&1 & echo $!", $output);

    echo "<pre>  foreground end time = " . time() . "</pre>";
    file_put_contents("testprocesses.php","foreground end time = " . time() . "\n", FILE_APPEND);
    return $output;
}

echo "<pre>calling run_background_process</pre>";

$output = run_background_process();

echo "<pre>output = "; print_r($output); echo "</pre>";
echo "<pre>end of page</pre>";
?>

background.php:

<?
file_put_contents("testprocesses.php","background start time = " . time() . "\n", FILE_APPEND);
sleep(10);
file_put_contents("testprocesses.php","background end time = " . time() . "\n", FILE_APPEND);
?>

Give IUSR permission to write to the directory in which you created the above files

Give IUSR permission to READ and EXECUTE C:\Windows\System32\cmd.exe

Hit foreground.php from a web browser

The following should be rendered to the browser w/the current timestamps and local resource # in the output array:

loading page
calling run_background_process
  foreground start time = 1266003600
  foreground end time = 1266003600
output = Array
(
    [0] => 15010
)
end of page

You should see testoutput.php in the same directory as the above files were saved, and it should be empty

You should see testprocesses.php in the same directory as the above files were saved, and it should contain the following text w/the current timestamps:

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610

Solution 5:

If you need to just do something in background without the PHP page waiting for it to complete, you could use another (background) PHP script that is "invoked" with wget command. This background PHP script will be executed with privileges, of course, as any other PHP script on your system.

Here is an example on Windows using wget from gnuwin32 packages.

The background code (file test-proc-bg.php) as an exmple ...

sleep(5);   // some delay
file_put_contents('test.txt', date('Y-m-d/H:i:s.u')); // writes time in a file

The foreground script, the one invoking ...

$proc_command = "wget.exe http://localhost/test-proc-bg.php -q -O - -b";
$proc = popen($proc_command, "r");
pclose($proc);

You must use the popen/pclose for this to work properly.

The wget options:

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background