如何让PHP 5.2(作为apache mod_php运行)向客户端发送完整的HTTP响应,然后继续执行操作一分钟?
长篇故事:
我有一个PHP脚本,必须执行一些长数据库请求并发送电子邮件,运行需要45到60秒.该脚本由我无法控制的应用程序调用.我需要应用程序报告从PHP脚本收到的任何错误消息(主要是无效的参数错误).
应用程序的超时延迟小于45秒(我不知道确切的值)因此将PHP脚本的每次执行都注册为错误.因此,我需要PHP尽可能快地将完整的HTTP响应发送到客户端(理想情况下,只要输入参数已经过验证),然后运行数据库和电子邮件处理.
我正在运行mod_php,所以pcntl_fork不可用.我可以通过将要处理的数据保存到数据库并运行实际过程来解决这个问题cron,但我正在寻找一个更短的解决方案.
pov*_*asp 49
我在我的"特殊脚本"工具箱中有这个片段,但它丢失了(当时云不常见),所以我正在搜索它并提出这个问题,惊讶地发现它丢失了,我搜索了更多来了回到这里发布:
<?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');
?>
Run Code Online (Sandbox Code Playgroud)
我实际上在很少的地方使用它.它完全有道理:银行链接正在返回成功支付的请求,我必须调用大量服务并在发生这种情况时处理大量数据.这有时需要10秒以上,但是banklink有固定的超时时间.因此,我承认银联并告诉他出路,并在他已经离开时做我的事情.
Ale*_*sky 26
让处理初始请求的脚本在处理队列中创建一个条目,然后立即返回.然后,创建一个单独的进程(可能通过cron),定期运行队列中待处理的任何作业.
小智 7
可以对自己或任何其他脚本使用"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?¶m=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);
...
Run Code Online (Sandbox Code Playgroud)
现在的子脚本:
// parse HTTP-query somewhere and somehow before this point
// "disable partial output" or
// "enable buffering" to give out all at once later
ob_start();
// "say hello" to client (parent script in this case) disconnection
// before child ends - we need not care about it
ignore_user_abort(1);
// we will work forever
set_time_limit(0);
// we need to say something to parent to stop its waiting
// it could be something useful like client ID or just "OK"
...
echo $reply;
// push buffer to parent
ob_flush();
// parent gets our answer and disconnects
// but we can work "in background" :)
...
Run Code Online (Sandbox Code Playgroud)
主要想法是:
如果你需要与孩子互动 - 你可以使用DB作为"通信媒介":父母可以阅读孩子状态和写命令,孩子可以阅读命令和写状态.如果您需要多个子脚本 - 您应该在用户端保留子ID以区分它们,并在每次要检查相应子项的状态时将该ID发送给父项.
我在这里找到了 - http://linuxportal.ru/forums/index.php/t/22951/
您可以使用 PHP 函数register-shutdown-function在脚本完成与浏览器的对话后执行某些操作。
另请参阅ignore_user_abort - 但如果您使用 register_shutdown_function,则不需要此功能。在同一页面上,set_time_limit(0)将防止您的脚本超时。