2024-07-28 05:00:06

PHP执行后台进程

我需要在用户操作时执行目录复制,但目录相当大,因此我希望能够在用户不知道完成复制所需时间的情况下执行这样的操作。

任何建议都将不胜感激。


当前回答

如果使用PHP,使用pcntl_fork有一个更简单的方法:

http://www.php.net/manual/en/function.pcntl-fork.php

其他回答

来自PHP官方文档(php.net)

<?php
function execInBackground($cmd) {
    if (substr(php_uname(), 0, 7) == "Windows"){
        pclose(popen("start /B ". $cmd, "r")); 
    }
    else {
        exec($cmd . " > /dev/null &");  
    }
}
?>

假设这是在Linux机器上运行的,我总是这样处理它:

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

这将启动命令$cmd,将命令输出重定向到$outputfile,并将进程id写入$pidfile。

这使您可以轻松地监视进程正在做什么以及它是否仍在运行。

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;
}

下面是在PHP中启动后台进程的函数。在大量阅读和测试不同的方法和参数之后,终于创建了一个在Windows上也能工作的程序。

function LaunchBackgroundProcess($command){
  // Run command Asynchroniously (in a separate thread)
  if(PHP_OS=='WINNT' || PHP_OS=='WIN32' || PHP_OS=='Windows'){
    // Windows
    $command = 'start "" '. $command;
  } else {
    // Linux/UNIX
    $command = $command .' /dev/null &';
  }
  $handle = popen($command, 'r');
  if($handle!==false){
    pclose($handle);
    return true;
  } else {
    return false;
  }
}

注意1:在windows上,不要像其他地方建议的那样使用/B参数。它强制进程运行与start命令本身相同的控制台窗口,导致进程被同步处理。要在单独的线程中(异步地)运行进程,请不要使用/B。

注2:如果命令是带引号的路径,则必须在start ""后加上空双引号。Start命令将第一个带引号的参数解释为窗口标题。

如果使用PHP,使用pcntl_fork有一个更简单的方法:

http://www.php.net/manual/en/function.pcntl-fork.php

感谢这个答案:Symfony process Component是运行后台进程的一个完美工具,它基于proc_*函数,但是使用起来更容易。有关更多信息,请参阅其文档。