2024-07-28 05:00:06

PHP执行后台进程

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

任何建议都将不胜感激。


当前回答

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

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

其他回答

您是否可以安排派生一个单独的进程,然后在后台运行您的副本?我已经有一段时间没有使用PHP了,但是函数pcntl-fork看起来很有前途。

对于我们这些使用Windows的人来说,看看这个:

参考:http://php.net/manual/en/function.exec.php # 43917

我也曾试图在后台运行一个程序 当脚本继续执行时,Windows。这种方法不像 其他解决方案允许您启动任何程序最小化,最大化, 或者根本就没有窗户。llbra@phpbrasil的解决方案确实有效,但它 有时会在桌面上产生一个不需要的窗口 希望隐藏任务运行。

在后台最小化启动Notepad.exe:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("notepad.exe", 7, false); 
?> 

在后台启动一个shell命令:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("cmd /C dir /S %windir%", 0, false); 
?> 

启动MSPaint maximized,等待你关闭它,然后继续脚本:

<?php 
$WshShell = new COM("WScript.Shell"); 
$oExec = $WshShell->Run("mspaint.exe", 3, true); 
?> 

有关Run()方法的更多信息,请访问: http://msdn.microsoft.com/library/en-us/script56/html/wsMthRun.asp

编辑网址:

请访问https://technet.microsoft.com/en-us/library/ee156605.aspx,因为上面的链接已经不存在了。

使用此函数在后台运行程序。它是跨平台的,完全可定制的。

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

注意,在命令启动后,默认情况下,该函数关闭正在运行进程的stdin和stdout。你可以通过$redirectStdout和$redirectStderr参数将进程输出重定向到某个文件中。

windows用户注意: 不能以以下方式将stdout/stderr重定向为null:

startBackgroundProcess('ping yandex.com', null, 'nul', 'nul');

然而,你可以这样做:

startBackgroundProcess('ping yandex.com >nul 2>&1');

*nix用户注意事项:

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

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

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

startBackgroundProcess('cat > input.txt', "Hello world!\n");

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

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

eg.

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

一个适用于Windows和Linux的解决方案。在我的github页面上找到更多信息。

function run_process($cmd,$outputFile = '/dev/null', $append = false){
                    $pid=0;
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                        $cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
                        $handle = popen("start /B ". $cmd, "r");
                        $read = fread($handle, 200); //Read the output 
                        $pid=substr($read,strpos($read,'=')+1);
                        $pid=substr($pid,0,strpos($pid,';') );
                        $pid = (int)$pid;
                        pclose($handle); //Close
                }else{
                    $pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
                }
                    return $pid;
            }
            function is_process_running($pid){
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                        //tasklist /FI "PID eq 6480"
                    $result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
                    if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                        return true;
                    }
                }else{
                    $result = shell_exec(sprintf('ps %d 2>&1', $pid));
                    if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
                        return true;
                    }
                }
                return false;
            }
            function stop_process($pid){
                    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
                            $result = shell_exec('taskkill /PID '.$pid );
                        if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
                            return true;
                        }
                    }else{
                            $result = shell_exec(sprintf('kill %d 2>&1', $pid));
                        if (!preg_match('/No such process/', $result)) {
                            return true;
                        }
                    }
            }