2024-07-28 05:00:06

PHP执行后台进程

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

任何建议都将不胜感激。


当前回答

与其启动后台进程,不如创建一个触发器文件,并让像cron或autosys这样的调度程序定期执行一个寻找触发器文件并对其进行操作的脚本?触发器可以包含指令甚至原始命令(更好的方法是将其变成shell脚本)。

其他回答

我找到了一个更快更简单的版本

shell_exec('screen -dmS $name_of_screen $command'); 

这很有效。

一个适用于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;
                        }
                    }
            }

PHP脚本不同于其他桌面应用程序开发语言。在桌面应用程序语言中,我们可以设置守护线程来运行后台进程,但在PHP中,当用户请求一个页面时,进程就会发生。但是,可以使用php脚本运行的服务器的cron作业功能来设置后台作业。

我只想添加一个非常简单的例子来测试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>";
?>

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

赋予IUSR写入创建上述文件的目录的权限

赋予IUSR读取和执行C:\Windows\System32\cmd.exe的权限

在浏览器中点击前台。php

下面的代码应该在输出数组中使用当前时间戳和本地资源#呈现给浏览器:

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

您应该看到testoutput.php位于与上面文件保存的相同目录中,并且它应该为空

你应该看到testprocesses.php位于与上面文件相同的目录中,它应该包含以下带有当前时间戳的文本:

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

对于我们这些使用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,因为上面的链接已经不存在了。