41

我正在尝试制作一个 PHP 脚本,我已经完成了脚本,但它需要 10 分钟才能完成它设计的过程。这不是问题,但是我认为我必须一直保持页面加载,这很烦人。我可以拥有它以便我开始该过程,然后在 10 分钟后返回并查看它生成的日志文件吗?

4

10 回答 10

50

好吧,你可以使用“ ignore_user_abort (true)”

所以脚本将继续工作(密切关注脚本持续时间,也许添加“ set_time_limit(0)”)

但是这里有一个警告:您将无法使用以下两行停止脚本:

ignore_user_abort(true); 
set_time_limit(0);

除了你可以直接访问服务器并杀死那里的进程!(去过那里,做了一个无限循环,一遍又一遍地调用自己,让服务器尖叫着停下来,被大喊大叫......)

于 2008-11-05T13:09:55.323 回答
26

听起来您应该有一个队列和一个用于处理队列的外部脚本。

例如,您的 PHP 脚本应该将一个条目放入数据库表并立即返回。然后,每分钟运行的 cron 会检查队列并为每个作业派生一个进程。

这里的优点是您不会将 apache 线程锁定 10 分钟。

于 2008-11-05T16:37:29.100 回答
8

在 Windows 下,我对这种过程有很多问题;我的情况有点不同,因为我不关心“脚本”的响应——我希望脚本启动并允许其他页面请求在它忙于工作时通过。

由于某些原因; 我遇到了问题,要么挂起其他请求,要么在大约 60 秒后超时(apache 和 php 都设置为在大约 20 分钟后超时);事实证明,firefox 无论如何都会在 5 分钟后超时(默认情况下),所以在那之后,如果不更改 firefox 中的设置,您将无法知道浏览器发生了什么。

我最终使用进程打开和进程关闭方法在 cli 模式下打开一个 php,如下所示:

pclose(popen("start php myscript.php", "r"));

这将(使用 start )打开 php 进程,然后终止启动进程,让 php 运行所需的时间 - 同样,您需要终止该进程以手动将其关闭。它不需要您设置任何超时,您可以让调用它的当前页面继续并输出更多详细信息。

唯一的问题是,如果您需要向脚本发送任何数据,您要么通过另一个来源进行,要么将其作为参数传递给“命令行”;这不是那么安全。

很好地满足了我们的需要,并确保脚本始终启动并允许运行而不会中断。

于 2008-11-05T14:13:24.710 回答
5

我认为 shell_exec 命令是您正在寻找的。

但是,它在安全模式下被禁用。

关于它的 PHP 手册文章在这里: http: //php.net/shell_exec

这里有一篇关于它的文章:http: //nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

于 2008-11-05T13:08:37.400 回答
4

您可以使用另一个选项,运行脚本 CLI...它将在后台运行,您甚至可以根据需要将其作为 cronjob 运行。

例如

> #!/usr/bin/php -q

<?php

//process logs

?>

这可以设置为 cronjob 并且将不受时间限制地执行....虽然这个示例适用于基于 unix 的操作系统。

仅供参考,我有一个运行无限循环的 php 脚本,该脚本执行一些处理,并且在过去 3 个月中一直在不停地运行。

于 2008-11-06T07:27:33.050 回答
3

您可以使用ignore_user_abort()- 即使您关闭浏览器或转到其他页面,脚本也将继续运行。

于 2008-11-05T13:09:49.100 回答
2

想想Gearman

Gearman 是一个通用应用程序框架,用于将工作分配给多台机器或流程。它允许应用程序并行完成任务、负载平衡处理以及在语言之间调用函数。该框架可用于各种应用程序,从高可用性网站到数据库复制事件的传输。

此扩展提供了用于编写 Gearman 客户端和工作者的类。- 源 php 手册

Gearman官方网站

于 2013-06-25T14:32:07.510 回答
2

除了 bastiandoeen 的回答,您还可以结合ignore_user_abort(true);cUrl request

将请求中止设置为低CURLOPT_TIMEOUT_MS并在连接关闭后继续处理:

function async_curl($background_process=''){

    //-------------get curl contents----------------

    $ch = curl_init($background_process);
    curl_setopt_array($ch, array(
        CURLOPT_HEADER => 0,
        CURLOPT_RETURNTRANSFER =>true,
        CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
        CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
        CURLOPT_VERBOSE => 1,
        CURLOPT_HEADER => 1
    ));
    $out = curl_exec($ch);

    //-------------parse curl contents----------------

    //$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    //$header = substr($out, 0, $header_size);
    //$body = substr($out, $header_size);

    curl_close($ch);

    return true;
}

async_curl('http://example.com/background_process_1.php');

注意

如果您希望 cURL 在不到一秒的时间内超时,您可以使用 CURLOPT_TIMEOUT_MS,尽管“类 Unix 系统”上存在一个错误/“功能”,如果该值小于 1000 毫秒,则会导致 libcurl 立即超时并出现错误“ cURL 错误 (28): 已超时”。这种行为的解释是:

[...]

解决方案是使用 CURLOPT_NOSIGNAL 禁用信号

优点

  • 无需切换方法(兼容windows & linux)
  • 无需通过 headers 和 buffer 实现连接处理(独立于浏览器和 PHP 版本)

缺点

  • 需要卷曲扩展

资源

于 2015-02-21T13:11:38.030 回答
1

祖克。

我很确定这会起作用:

<?php 

pclose(popen('php /path/to/file/server.php &'));
echo "Server started. [OK]"; 

?>

'&' 很重要。它告诉外壳程序不要等待进程退出。

您也可以在您的 php 中使用此代码(如“bastiandoeen”所说)

ignore_user_abort(true); 
set_time_limit(0);

在您的服务器停止命令中:

<?php

$output;
exec('ps aux | grep -ie /path/to/file/server.php | awk \'{print $2}\' | xargs kill -9 ', $output);
    echo "Server stopped. [OK]";

?>
于 2014-01-11T13:46:47.963 回答
-1

只需在任何输出之前调用 StartBuffer(),当您希望客户端关闭连接时调用 EndBuffer()。调用 EndBuffer() 后的代码将在没有客户端连接的服务器上执行。

    私有函数 StartBuffer(){
        @ini_set('zlib.output_compression',0);
        @ini_set('implicit_flush',1);
        @ob_end_clean();
        @set_time_limit(0);
        @ob_implicit_flush(1);
        @ob_start();
    }

    私有函数 EndBuffer(){
        $size = ob_get_length();
        header("内容长度:$size");
        header('连接:关闭');
        ob_flush();ob_implicit_flush(1);
    }

于 2018-07-26T13:46:24.003 回答