在PHP中即发即弃


Fire-and-forget in PHP

最终更新

似乎我确实犯了一个非常简单的错误。因为我已经有了一个流实现,所以我可以不开始从流中读取:D


我正在努力实现即发即弃在PHP中的功能。

从php.net

<?php
ignore_user_abort(true);
header("Content-Length: 4");
header("Connection: Close");
echo "abcd";
flush();
sleep(5);    
echo "Text user should not see"; // because it should have terminated
?>

如果我用浏览器打开脚本,这个工作。(显示"abcd")。但是如果我用file_get_contents或一些库打开它,它将等待~5秒并显示第二个文本。

我正在使用PHP 5.2.11/Apache 2.0


我似乎对我要完成的任务有些困惑。

我不想使用输出缓冲区隐藏输出(这是愚蠢的)。我想让客户端在服务器启动一个可能很长的过程(sleep(5))之前终止,我不希望客户端等待它(这就是"即发即弃"的意思,排序)。使用输出缓冲区只是一个副作用。我在不使用输出缓冲区的情况下修改了示例代码。

我不明白的是:为什么这个脚本的行为不同时,从浏览器访问它与获取它在PHP与file_get_contents("http://dev/test.php")或一些库?我在测试中看到的是,例如stream_get_contents在返回任何输出之前实际上会阻塞5秒,这与我想要的完全相反。

更新2

更多结果:

  • 浏览器响应flush()。我不知道如何在PHP中复制的行为,我的流一直阻塞。
  • 我试过fread,发现它的行为类似于stream_get_contents
  • 指定maxlength没有效果,它仍然会阻塞~5秒。
  • 改变阻塞模式没有效果(除了产生一堆更多的呼叫to stream_get_contents())。它将等待~5秒才返回任何内容。
  • stream_set_read_buffer没有效果(在PHP 5.3.5服务器上测试)

显示文本的第二部分,因为您使用ob_end_flush()ob_end_clean()停止了输出缓冲。当这种情况发生时,PHP会正常输出内容。试试下面的内容:

<?php
ob_start(); // turn on output buffering
print "Text the user will see.";
ob_flush(); // send above output to the user and keep output buffering on
print "Text the user will never see";
ob_end_clean(); // empty the buffer and turn off output buffering. your script should end here.
?>

ob_end_clean()出现在脚本的末尾是很重要的。它清空缓冲区,不将其内容发送给用户,从而保持ob_flush()之后的所有内容隐藏。

如何使用file_get_contents访问脚本?你怎么用浏览器访问它?如果您访问脚本时没有"http://",当然它将永远不会被执行。使用与浏览器中相同的URL

编辑:

浏览器会在连接关闭之前呈现页面。即使你冲水,我也不认为连接是关闭的。你可以启动Wireshark检查一下。Stream_get_contents和file_get_contents将阻塞,直到它们获得所有输出。即使你脸红了,他们也不能确定没有更多的内容。由于内容长度头似乎没有使{file,stream}_get_contents更早返回,因此您可能需要实现自己的缓冲。Fopen, read, fclose

看来我确实犯了一个非常简单的错误。因为我已经有了一个流实现,我可以不开始从流中读取:D

相关文章:
  • 没有找到相关文章