Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
发送HTTP响应后继续执行PHP_Php_Fork - Fatal编程技术网

发送HTTP响应后继续执行PHP

发送HTTP响应后继续执行PHP,php,fork,Php,Fork,如何让PHP5.2(以apache mod_PHP运行)向客户机发送完整的HTTP响应,然后继续执行操作一分钟 长话短说: 我有一个PHP脚本,它必须执行一些长数据库请求并发送电子邮件,运行需要45到60秒。此脚本由我无法控制的应用程序调用。我需要应用程序报告从PHP脚本收到的任何错误消息(大部分是无效的参数错误) 应用程序的超时延迟小于45秒(我不知道确切的值),因此将PHP脚本的每次执行都注册为错误。因此,我需要PHP尽可能快地将完整的HTTP响应发送到客户端(理想情况下,输入参数一经验证,

如何让PHP5.2(以apache mod_PHP运行)向客户机发送完整的HTTP响应,然后继续执行操作一分钟

长话短说:

我有一个PHP脚本,它必须执行一些长数据库请求并发送电子邮件,运行需要45到60秒。此脚本由我无法控制的应用程序调用。我需要应用程序报告从PHP脚本收到的任何错误消息(大部分是无效的参数错误)

应用程序的超时延迟小于45秒(我不知道确切的值),因此将PHP脚本的每次执行都注册为错误。因此,我需要PHP尽可能快地将完整的HTTP响应发送到客户端(理想情况下,输入参数一经验证,就立即发送),然后运行数据库和电子邮件处理


我正在运行mod_php,因此
pcntl_fork
不可用。我可以通过将要处理的数据保存到数据库并从
cron
运行实际的进程来解决这个问题,但我正在寻找一个较短的解决方案。

在文件服务器上调用脚本,让它像在命令行被触发一样执行怎么样?您可以使用PHP实现这一点。

让处理初始请求的脚本在处理队列中创建一个条目,然后立即返回。然后,创建一个单独的进程(可能通过cron),定期运行队列中挂起的任何作业。

您可以使用PHP函数,在脚本完成与浏览器的对话后执行某些操作


另请参见-但如果使用register\u shutdown\u函数,则不需要此函数。在同一页上,
set\u time\u limit(0)
将阻止您的脚本超时。

Bah,我误解了您的要求。看起来他们实际上是:

  • 脚本从您不控制的外部源接收输入
  • 脚本处理和验证输入,并让外部应用知道它们是否正常,然后终止会话
  • 脚本启动了一个长期运行的过程
在这种情况下,那么可以使用外部作业队列和/或cron。验证输入后,将作业详细信息插入队列,然后退出。然后可以运行另一个脚本,从队列中获取作业详细信息,并启动较长的流程。亚历克斯·霍万斯基的想法是正确的


对不起,我承认我第一次略读了一点。

您可以将这些函数拆分为三个脚本。 1.启动进程并通过exec或
命令调用第二个进程,这也可以通过http调用运行。
2.第二个将运行数据库处理,最后将启动最后一个

3.最后一个将发送电子邮件

您需要的是这种设置


我建议在最后生成一个新的异步请求,而不是与用户一起继续这个过程

您可以使用此处的答案生成其他请求:

使用队列、exec或cron对这个简单的任务来说是一种过分的杀伤力。 没有理由不停留在同一个脚本中。 这种组合对我来说非常有效:

        ignore_user_abort(true);
        $response = "some response"; 
        header("Connection: close");
        header("Content-Length: " . mb_strlen($response));
        echo $response;
        flush(); // releasing the browser from waiting
        // continue the script with the slow processing here...
请阅读以下内容: 一个人可以使用“http fork”对自己或任何其他脚本进行编辑。我的意思是这样的:

// parent sript, called by user request from browser

// create socket for calling child script
$socketToChild = fsockopen("localhost", 80);

// HTTP-packet building; header first
$msgToChild = "POST /sript.php?&param=value&<more params> HTTP/1.0\n";
$msgToChild .= "Host: localhost\n";
$postData = "Any data for child as POST-query";
$msgToChild .= "Content-Length: ".strlen($postData)."\n\n";

// header done, glue with data
$msgToChild .= $postData;

// send packet no oneself www-server - new process will be created to handle our query
fwrite($socketToChild, $msgToChild);

// wait and read answer from child
$data = fread($socketToChild, $dataSize);

// close connection to child
fclose($socketToChild);
...
其主要思想是:

  • 用户请求调用的父脚本
  • parent调用同一服务器(或任何其他服务器)上的子脚本(与parent或其他脚本相同),并向它们提供请求数据
  • 家长对用户说ok并结束
  • 孩子工作
如果您需要与子级交互,您可以使用DB作为“通信媒介”:父级可以读取子级状态和写入命令,子级可以读取命令和写入状态。如果您需要为几个子脚本使用该id,那么您应该在用户端保留子id以区分它们,并在每次希望检查相应子脚本的状态时将该id发送给父脚本

我在这里发现-

我的“特殊脚本”工具箱中有这个片段,但它丢失了(云在当时并不常见),所以我在搜索它并提出了这个问题,惊讶地发现它丢失了,我搜索了更多,然后回到这里发布它:

<?php
 ob_end_clean();
 header("Connection: close");
 ignore_user_abort(); // optional
 ob_start();
 echo ('Text the user will see');
 $size = ob_get_length();
 header("Content-Length: $size");
 ob_end_flush(); // Strange behaviour, will not work
 flush();            // Unless both are called !
 session_write_close(); // Added a line suggested in the comment
 // Do processing here 
 sleep(30);
 echo('Text user will never see');
?>


实际上,我在很少的地方使用它。这完全是有道理的:一个银行链接正在返回一个成功支付的请求,我必须调用许多服务,并在这种情况下处理大量数据。这有时需要超过10秒,但banklink有固定的超时时间。因此,我向banklink表示感谢,并向他指出出路,在他已经离开后,我会做我的事情。

您可以在服务器和服务器之间创建http请求。(不需要浏览器)。 创建后台http请求的秘诀是设置非常小的超时,因此响应被忽略

这是一个工作函数,我用于该pupose:

五月 31 PHP异步后台请求 在PHP中创建异步请求的另一种方法(模拟后台模式)

有关更多信息,请查看

在Apache
php.ini
config文件中,确保禁用了输出缓冲:

output_buffering = off

可以使用cURL,超时时间很短。这将是您的主文件:

<?php>
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://example.com/processor.php");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10);      //just some very short timeout
    curl_exec($ch);
    curl_close($ch);
?>

这是您的处理器文件:

<?php
    ignore_user_abort(true);                       //very important!
    for($x = 0; $x < 10; $x++)                     //do some very time-consuming task
        sleep(10);
?>

如您所见,上层脚本将在短时间后超时(本例中为10毫秒)。
CURLOPT\u TIMEOUT\u MS
可能不会像这样工作,在这种情况下,它相当于
curl\u setopt($ch,CURLOPT\u TIMEOUT,1)

因此,当处理器文件被访问时,无论用户(即调用文件)中止连接,它都将执行其任务


当然,您也可以在页面之间传递GET或POST参数。

对不起,这看起来像是对PHP语言的完全误用,而不是误用
<?php>
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "http://example.com/processor.php");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10);      //just some very short timeout
    curl_exec($ch);
    curl_close($ch);
?>
<?php
    ignore_user_abort(true);                       //very important!
    for($x = 0; $x < 10; $x++)                     //do some very time-consuming task
        sleep(10);
?>