php执行后台进程

tim*_*tim 248 php

我需要在用户操作时执行目录副本,但目录非常大,所以我希望能够执行这样的操作,而无需用户知道副本完成所需的时间.

任何建议将不胜感激.

Mar*_*iek 354

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

exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
Run Code Online (Sandbox Code Playgroud)

这将启动命令$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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这个http://stackoverflow.com/questions/5367261/php-exec-as-background-process-windows-wampserver-environment解释了如何在windows下执行相同操作 (17认同)
  • 我用过这个,但稍微更新了一下,所以我没有把PID写入文件.所以我使用这种格式:<code> exec(sprintf("$ s> $ s 2>&1&echo $ 1",$ cmd,$ outputfile),$ pidArr); </ code>生成的进程PID在$ pidArr [0]中 (12认同)
  • Kaiesh做了一个错字,'$'而不是'%'.更正版本:exec(sprintf("%s>%s 2>&1&echo $!",$ cmd,$ outputfile),$ pidArr) (7认同)
  • 这对我来说似乎破坏了很多。我最终使用了这个:http://symcbean.blogspot.co.uk/2010/02/php-and-long-running-processes.html (3认同)
  • sudo设置是否在没有提示输入密码的情况下运行?任何需要用户输入的命令都不起作用. (2认同)
  • @Kaiesh:它应该是"echo $!" (2认同)
  • 如果要处理退出代码,只需将第一个“%s`”替换为“`(%s; printf \” \\ n $?\“)`”。这会将命令的退出代码放在日志的最后一行。 (2认同)
  • pid 可能已被另一个进程占用。在这种情况下, isRunning() 将返回 true - 同时该过程已真正停止。 (2认同)
  • 将此答案制成一个简单的 composer 包。你可以在 github 上找到它:https://github.com/diversen/background-job (2认同)

Eri*_*win 23

将进程编写为服务器端脚本,无论使用何种语言(php/bash/perl/etc)都很方便,然后从php脚本中的进程控制函数中调用它.

该函数可能检测到标准io是否用作输出流,如果是,那么它将设置返回值..如果不是那么它结束

Proc_Close (Proc_Open ("./command --foo=1 &", Array (), $foo));
Run Code Online (Sandbox Code Playgroud)

我使用"sleep 25s"作为命令从命令行快速测试了它,它就像一个魅力.

(这里找到答案)

  • 这是我可以让它在centos上工作的唯一方法.谢谢! (3认同)

wlf*_*wlf 20

您可能想尝试将此附加到您的命令

>/dev/null 2>/dev/null &
Run Code Online (Sandbox Code Playgroud)

例如.

shell_exec('service named reload >/dev/null 2>/dev/null &');
Run Code Online (Sandbox Code Playgroud)


Cap*_*ous 18

我想在Windows上添加一个非常简单的示例来测试此功能:

创建以下两个文件并将其保存到Web目录:

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>";
?>
Run Code Online (Sandbox Code Playgroud)

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);
?>
Run Code Online (Sandbox Code Playgroud)

授予IUSR权限以写入您在其中创建上述文件的目录

授予IUSR READ和EXECUTE C:\ Windows\System32\cmd.exe的权限

从Web浏览器中点击foreground.php

应将以下内容呈现给浏览器w /输出数组中的当前时间戳和本地资源#:

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

您应该在保存上述文件的同一目录中看到testoutput.php,它应该为空

您应该在保存上述文件的同一目录中看到testprocesses.php,它应该包含以下文本和当前时间戳:

foreground start time = 1266003600
foreground end time = 1266003600
background start time = 1266003600
background end time = 1266003610
Run Code Online (Sandbox Code Playgroud)


小智 10

如果你需要在没有PHP页面等待它完成的情况下在后台执行某些操作,可以使用wget命令"调用"的另一个(后台)PHP脚本.当然,这个后台PHP脚本将以特权执行,就像系统上的任何其他PHP脚本一样.

以下是使用wget from gnuwin32 packages的Windows上的示例.

背景代码(文件test-proc-bg.php)作为一个例子......

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

前台脚本,一个调用...

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

您必须使用popen/pclose才能正常工作.

wget选项:

-q    keeps wget quiet.
-O -  outputs to stdout.
-b    works on background
Run Code Online (Sandbox Code Playgroud)


Alp*_*Dev 7

这是一个在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;
  }
}
Run Code Online (Sandbox Code Playgroud)

注1:在Windows上,不要使用/B其他地方建议的参数.它强制进程与start命令本身一起运行相同的控制台窗口,从而导致进程同步处理.要在单独的线程中运行该进程(异步),请不要使用/B.

注意2:start ""如果命令是带引号的路径,则需要后面的空双引号.startcommand将第一个引用的参数解释为窗口标题.


Mor*_*don 6

好吧,我发现使用的版本更快更容易

shell_exec('screen -dmS $name_of_screen $command'); 
Run Code Online (Sandbox Code Playgroud)

它的工作原理.


Pas*_*l9x 5

使用此功能在后台运行您的程序。它跨平台且完全可定制。

<?php
function startBackgroundProcess(
    $command,
    $stdin = null,
    $redirectStdout = null,
    $redirectStderr = null,
    $cwd = null,
    $env = null,
    $other_options = null
) {
    $descriptorspec = array(
        1 => is_string($redirectStdout) ? array('file', $redirectStdout, 'w') : array('pipe', 'w'),
        2 => is_string($redirectStderr) ? array('file', $redirectStderr, 'w') : array('pipe', 'w'),
    );
    if (is_string($stdin)) {
        $descriptorspec[0] = array('pipe', 'r');
    }
    $proc = proc_open($command, $descriptorspec, $pipes, $cwd, $env, $other_options);
    if (!is_resource($proc)) {
        throw new \Exception("Failed to start background process by command: $command");
    }
    if (is_string($stdin)) {
        fwrite($pipes[0], $stdin);
        fclose($pipes[0]);
    }
    if (!is_string($redirectStdout)) {
        fclose($pipes[1]);
    }
    if (!is_string($redirectStderr)) {
        fclose($pipes[2]);
    }
    return $proc;
}
Run Code Online (Sandbox Code Playgroud)

请注意,命令启动后,默认情况下此函数会关闭正在运行的进程的标准输入和标准输出。您可以通过 $redirectStdout 和 $redirectStderr 参数将进程输出重定向到某个文件。

Windows 用户注意:您不能通过以下方式
将 stdout/stderr 重定向到:nul

startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');
Run Code Online (Sandbox Code Playgroud)

但是,您可以这样做:

startBackgroundProcess('ping yandex.com >nul 2>&1');
Run Code Online (Sandbox Code Playgroud)

*nix 用户注意事项:

1)如果你想获得实际的PID,请使用exec shell命令:

$proc = startBackgroundProcess('exec ping yandex.com -c 15', null, '/dev/null', '/dev/null');
print_r(proc_get_status($proc));
Run Code Online (Sandbox Code Playgroud)

2) 如果您想将一些数据传递到程序的输入,请使用 $stdin 参数:

startBackgroundProcess('cat > input.txt', "Hello world!\n");
Run Code Online (Sandbox Code Playgroud)