代码之家  ›  专栏  ›  技术社区  ›  matteo

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

  •  5
  • matteo  · 技术社区  · 12 年前

    我已经阅读并深刻理解了这些内容: 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,即使脚本将继续运行,并且直到最后才会调用关闭函数。事实并非如此。

    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”(如果您实时查看日志,则当客户端断开连接时,myShutdon应立即显示)

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

    1 回复  |  直到 12 年前
        1
  •  5
  •   Community Mohan Dere    5 年前

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


    我看到你的代码有两个问题。第一个是语法错误。你漏掉了周围的单引号 myShutdown 打电话时 register_shutdown_function() 。将行更改为:

    register_shutdown_function('myShutdown');
    

    我看到的第二个问题是缺失 flush() 在之后呼叫 echo s.文件上写着:

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

    但即便如此 冲洗() 无论如何都无济于事。来自 冲洗() :

    flush()可能无法覆盖web服务器的缓冲方案,并且它对浏览器中的任何客户端缓冲都没有影响。它也不会影响PHP的用户空间输出缓冲机制。这意味着您必须同时调用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秒后发送内容(“嗨”),但网络浏览器正在缓冲页面。