PHP根本没有检测到连接中止

时间:2013-04-13 18:05:50

标签: php connection abort disconnect

我已阅读并深刻理解这些: http://www.php.net/manual/en/features.connection-handling.php http://www.php.net/manual/en/function.register-shutdown-function.php

但是,我已经测试了PHP 5.1.6和5.3,并且事情不像那里描述的那样工作。我观察到的是:

  • connection_status()始终返回true,即使客户端已关闭连接。
  • 在客户端关闭连接后,脚本的执行继续进行,即使ignore_user_abort为0
  • 在脚本到达结束之前,不会运行使用register_shutdown_function()注册的函数。当客户端中止连接时,脚本不会被中断(因此不会调用函数)。

所以基本上PHP根本就没有检测到客户端断开连接。

请注意,这不像ignore_user_abort设置为1:如果是这种情况,那么即使脚本将继续运行,connection_status()也将返回1,并且直到结束才会调用shutdown函数。事实并非如此。

ini_get(“ignore_user_abort”)按预期返回0。

这是PHP中的错误,还是可能是由于某些Apache设置?

如何让PHP按照上述文档中的说明工作?

测试脚本:

<?php

function myShutdown() {
    error_log("myShutdown ".connection_status()." ".ini_get("ignore_user_abort"));
}

register_shutdown_function(myShutdown);

echo "Hi!";
error_log(" *** test/test *** ");
for ($i=0; $i<10; $i++) {
    sleep(1);
    error_log(".");
    echo ".";
}
?>

重现的步骤: - 访问脚本的url - 在10秒钟之前中止客户端上的连接(例如,点击浏览器中的停止按钮)

预期/期望的行为: 日志应显示少于10个点,最后“myShutdown 1 0”(如果您实时查看日志,myShutDown应在客户端断开连接时立即显示)

观察/当前行为: 日志总是显示10个点,最后“myShutdown 0 0”(如果您实时观看,无论客户端断开连接,它都会持续10秒。)

1 个答案:

答案 0 :(得分:5)

首先,我也没能使用基本的ubuntu 12.04 LAMP安装(php5.3)来实现它。但我有一些信息,希望它有所帮助。任何评论或编辑赞赏! :)


我发现您的代码存在两个问题。第一个是语法错误。在调用myShutdown时,您错过register_shutdown_function()周围的单引号。将行更改为:

register_shutdown_function('myShutdown');

我看到的第二个问题是echo之后缺少flush()来电。文档说:

  

在尝试向客户端发送信息之前,PHP不会检测到用户已中止连接。简单地使用echo语句并不能保证发送信息,请参阅flush()。

但即使是flush()也无济于事。来自flush()的文档:

  

flush()可能无法覆盖Web服务器的缓冲方案,并且它对浏览器中的任何客户端缓冲没有影响。它也不会影响PHP的用户空间输出缓冲机制。这意味着如果使用ob输出缓冲区,则必须同时调用ob_flush()和flush()来刷新ob输出缓冲区。

     

多个服务器,尤其是Win32上的服务器,仍会缓冲脚本的输出,直到它终止,然后才将结果传输到浏览器。

     

像mod_gzip这样的Apache服务器模块可能会自行缓冲,这会导致flush()不会立即将数据发送到客户端。

     

即使是浏览器也可以在显示之前缓冲其输入。例如,Netscape缓冲文本,直到它收到行尾或标记的开头,并且在看到最外面的表的标记之前它不会呈现表。

     

某些版本的Microsoft Internet Explorer只会在收到256字节的输出后才开始显示页面,因此您可能需要在刷新之前发送额外的空格以使这些浏览器显示该页面。

在该页面的评论中,有一个建议设置几个标题和apache配置:

apache_setenv('no-gzip', 1); 
ini_set('zlib.output_compression', 0); 
ini_set('implicit_flush', 1); 
然而,即使这对我也不起作用。我使用wiresharek进行了调查,虽然网络服务器在0.0037秒后发送内容('Hi'),但网络浏览器正在缓存页面。