发送HTTP响应后继续执行PHP
如何让PHP5.2(以apache mod_PHP运行)向客户机发送完整的HTTP响应,然后继续执行操作一分钟 长话短说: 我有一个PHP脚本,它必须执行一些长数据库请求并发送电子邮件,运行需要45到60秒。此脚本由我无法控制的应用程序调用。我需要应用程序报告从PHP脚本收到的任何错误消息(大部分是无效的参数错误) 应用程序的超时延迟小于45秒(我不知道确切的值),因此将PHP脚本的每次执行都注册为错误。因此,我需要PHP尽可能快地将完整的HTTP响应发送到客户端(理想情况下,输入参数一经验证,就立即发送),然后运行数据库和电子邮件处理发送HTTP响应后继续执行PHP,php,fork,Php,Fork,如何让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,我误解了您的要求。看起来他们实际上是:
- 脚本从您不控制的外部源接收输入
- 脚本处理和验证输入,并让外部应用知道它们是否正常,然后终止会话
- 脚本启动了一个长期运行的过程
对不起,我承认我第一次略读了一点。您可以将这些函数拆分为三个脚本。 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?¶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);
...
其主要思想是:
- 用户请求调用的父脚本李>
- 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中创建异步请求的另一种方法(模拟后台模式)
有关更多信息,请查看
在Apachephp.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);
?>