php php执行后台进程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:18:05  来源:igfitidea点击:

php execute a background process

php

提问by tim

I need to execute a directory copy upon a user action, but the directories are quite large, so I would like to be able to perform such an action without the user being aware of the time it takes for the copy to complete.

我需要根据用户操作执行目录副本,但目录非常大,因此我希望能够在用户不知道完成复制所需的时间的情况下执行此类操作。

Any suggestions would be much appreciated.

任何建议将不胜感激。

回答by Mark Biek

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

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

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.

这将启动命令$cmd,将命令输出重定向到$outputfile,并将进程 ID 写入$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;
}

回答by Eric Goodwin

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.

使用任何方便的语言(php/bash/perl/etc)将流程编写为服务器端脚本,然后从您的 php 脚本中的流程控制函数中调用它。

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

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

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.

我使用“sleep 25s”作为命令从命令行快速测试了这一点,它的效果非常好。

(Answer found here)

答案在这里找到

回答by wlf

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 &');

回答by Captain Obvious

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

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

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

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

foreground.php:

前台.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:

背景.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

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

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

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

Hit foreground.php from a web browser

从 Web 浏览器点击 foreground.php

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

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

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:

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

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

回答by Neven Boyanov

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.

如果您只需要在后台执行某些操作,而无需等待 PHP 页面完成,您可以使用另一个(后台)PHP 脚本,该脚本通过 wget 命令“调用”。当然,这个后台 PHP 脚本将以特权执行,就像您系统上的任何其他 PHP 脚本一样。

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

这是在 Windows 上使用 gnuwin32 包中的 wget 的示例。

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

以后台代码(文件 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

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.

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

The wget options:

wget 选项:

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

回答by Alph.Dev

Here is a function to launch a background process in PHP. Finally created one that actually works on Windows too, after a lot of reading and testing different approaches and parameters.

这是一个在 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;
  }
}

Note 1: On windows, do not use /Bparameter as suggested elsewhere. It forces process to run the same console window as startcommand itself, resulting in the process being processed synchronously. To run the process in a separate thread (asynchronously), do not use /B.

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

Note 2: The empty double quotes after start ""are required if the command is a quoted path. startcommand interprets the first quoted parameter as window title.

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

回答by Morfidon

Well i found a bit faster and easier version to use

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

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

and it works.

它有效。

回答by Pascal9x

Use this function to run your program in background. It cross-platform and fully customizable.

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

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

Note that after command started, by default this function closes the stdin and stdout of running process. You can redirect process output into some file via $redirectStdout and $redirectStderr arguments.

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

Note for windows users:
You cannot redirect stdout/stderr to nulin the following manner:

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

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

However, you can do this:

但是,您可以这样做:

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

Notes for *nix users:

*nix 用户注意事项:

1) Use exec shell command if you want get actual PID:

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

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

2) Use $stdin argument if you want to pass some data to the input of your program:

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

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

回答by Matt Sheppard

Can you arrange to fork off a separate process, and then run your copy in the background? It's been a while since I did any PHP, but the function pcntl-forklooks promising.

你能安排一个单独的进程,然后在后台运行你的副本吗?我已经有一段时间没有使用任何 PHP 了,但是pcntl-fork函数看起来很有希望。

回答by scones

You might try a queuing system like Resque. You then can generate a job, that processes the information and quite fast return with the "processing" image. With this approach you won't know when it is finished though.

您可以尝试使用Resque这样的排队系统。然后,您可以生成一个作业,该作业处理信息并通过“处理”图像快速返回。使用这种方法,您将不知道何时完成。

This solution is intended for larger scale applications, where you don't want your front machines to do the heavy lifting, so they can process user requests. Therefore it might or might not work with physical data like files and folders, but for processing more complicated logic or other asynchronous tasks (ie new registrations mails) it is nice to have and very scalable.

此解决方案适用于更大规模的应用程序,您不希望前端机器承担繁重的工作,因此它们可以处理用户请求。因此,它可能会或可能不会处理物理数据,如文件和文件夹,但对于处理更复杂的逻辑或其他异步任务(即新注册邮件),它是很好的,并且具有很高的可扩展性。