4

我有 2 个 PHP 文件。一个文件是 caller.php,另一个是 worker.php

caller.php 将在(linux)系统上启动 worker.php,并且 caller.php 应该立即结束(而 worker.php 仍在服务器上工作)

worker.php 花费了很多时间,它将状态写入数据库或文件。

我希望能够在启动 'php worker.php' 的浏览器中打开 caller.php,关闭浏览器,5 分钟后返回并检查状态..(或脚本将在完成后发送邮件) - 任何想法如何做到这一点?

4

3 回答 3

2

您可以结束客户端连接并继续处理,全部完成。如果处理时间超过 php/httpd 全局配置允许的时间,您可能还需要增加 php 超时。见set_time_limit();

这不完全是您所问的,但我认为这可能是 X/Y 问题,所以在这里我们使用可用于:

  • 向用户显示处理开始页面。
  • 关闭用户连接。
  • 开始更长的处理。

所以基本上这回答了您所描述的需求,而不是“如何做 X?”。

呼叫者

// Ignore user abort and set Connection close header
ignore_user_abort(true);
header("Connection: close");

// Start controlled buffering
ob_start();
echo "<h1>Processing started, come back tomorrow to see results</h1>";

// Get buffer length and manually add it to headers.
$size = ob_get_length();
header("Content-Length: $size");

// Flush buffers, user sees "Processing started" message.
ob_end_flush();
flush();

// At this point connection to client should be closed already.
// Here we start our worker, there is no need to do fork() or 
// anything like that. Client browser is not listening anymore.
// All we need to do is simply start working and start writing
// status logs to somewhere so that client can retrieve status
// with another request, let's say from checkworkerstatus.php
include "worker.php";
$worker = new worker();
$worker->start_long_processing();

不分叉或杀戮callerworker独自奔跑?

没错,那是因为没有必要。

是的,您要求“caller.php 将在(linux)系统上启动 worker.php 并且 caller.php 应立即结束(而 worker.php 仍在服务器上工作)”的行为。但是,如果您不想使用 php 执行 multithreading-singleuser 应用程序,则无需这样做。让用户1.开始一些事情,2.让它继续运行,3.断开用户连接,4 .回到开始用户可以开始更多事情的地方,或者如果已经足够无聊就退出。

当然你可以用任何东西替换之后flush();的所有东西,不同的是客户端不再监听,所以所有输出都会进入名为 /dev/null 的黑洞。例如用这样的东西测试它:

...end_flush();
flush();

// At this point connection to client should be closed already.
echo "Nobody sees this message";
while(rand(0,10) != 1) {
    echo "Nobody sees this message";
    error_log(date("mdyHis")." Still running...");
    sleep(10);
}
...

有关详细信息,请参阅http://php.net/features.connection-handling。如果刷新缓冲区和关闭用户连接似乎有任何问题,
也请阅读http://php.net/function.flush 。
还有另一个问题(有答案)关于为什么 PHP 不支持多线程?

于 2012-07-02T21:08:15.747 回答
1
  1. 调用者运行工作者
  2. Worker 在 /tmp/ 中创建 FIFO 文件并将进度写入其中(您也可以使用套接字)
  3. 调用者读取此文件并显示用户实际进度

如果您将 Apache/nginx 配置好,它将允许同时执行两个 PHP 文件(就像我的一样)。

您应该阅读有关 posix_mkfifo 的信息:http: //php.net/manual/en/function.posix-mkfifo.php(也有使用示例)。

于 2012-07-02T18:47:18.690 回答
1

这可能有点强,但是最快和直接的方法:

  • 调用者使用 <IFRAME> 创建一个 html
  • IFRAME 的 SRC 是工作人员(这里调用者将参数作为 GET 参数传递给工作人员)
  • 工人的第一行在下面的代码中

代码:

ignore_user_abort(true);
set_time_limit(0);

当您关闭浏览器工作程序时(应该)继续工作!

http://www.php.net/manual/en/function.ignore-user-abort.php

于 2012-07-02T19:01:39.360 回答