PHP connection_aborted()无法正常工作

时间:2011-06-17 04:16:48

标签: php timeout connection infinite-loop

我有以下代码:

ignore_user_abort(true);
while(!connection_aborted()) {
    // do stuff
}

并且根据PHP文档,这应该运行直到连接关闭,但由于某种原因,它不会,而是在脚本超时之前一直运行。我在网上看过,有些人建议添加

echo chr(0);
flush();

进入循环,但似乎也没有做任何事情。更糟糕的是,如果我把它留作

while(true) {
    // do stuff
}

在客户端断开连接后,PHP仍然继续运行脚本。有谁知道如何使这个工作?是否有我在某处遗漏的php.ini设置?

如果重要,我正在运行PHP 5.3.5。提前谢谢!

5 个答案:

答案 0 :(得分:2)

尝试:

    ignore_user_abort(true);

    echo "Testing connection handling";

    while (1) {
            if (connection_status() != CONNECTION_NORMAL)
                    break;
            sleep(1);
            echo "test";
            flush();
    }

答案 1 :(得分:1)

尝试在ob_flush();之前使用flush();,有些浏览器在添加某些数据之前不会更新页面。

尝试做类似

的事情
<? php
// preceding scripts

ignore_user_abort(true);

$i = 0;

while(!connection_aborted())
{ $i++;
  echo $i;

  echo str_pad('',4096); // yes i know this will increase the overhead but that can be reduced afterwords

  ob_flush();

  flush();

  usleep(30000); // see what happens when u run this on my WAMP this runs perfectly
}

// Ending scripts
?>

Google Chrome实际上存在此代码的问题;它不支持流式传输。

答案 2 :(得分:0)

不幸的是,我有output_buffering = Off,无论如何,我的while循环继续运行,即使客户端关闭浏览器,connection_aborted()也给出0。 还有其他提示吗?

答案 3 :(得分:0)

我参加这个聚会有点晚了,但是我只是遇到了这个问题而已。这里发生了很多事情-这里提到了其中的一些:  PHP doesn't detect connection abort at all

要点:为了使connection_aborted()工作,PHP需要尝试将数据发送到客户端。

输出缓冲区

如前所述,PHP在尝试将数据实际发送到客户端之前不会检测到连接已死。这并不像进行echo那样简单,因为echo会将数据发送到可能存在的任何output buffers,并且在这些缓冲区足够满之前,PHP不会尝试真正的发送。我将不讨论输出缓冲的细节,但是值得一提的是,可以有多个嵌套缓冲区。

无论如何,如果要测试connection_abort(),必须首先结束所有缓冲区:

while (ob_get_level()){ ob_end_clean(); }

现在,无论何时要测试连接是否中止,都必须尝试将数据发送到客户端:

echo "Something.";
flush();

// returns expected value...
// ... but only if ignore_user_abort is false!
connection_aborted(); 

忽略用户中止

这是一个非常重要的设置,它决定了调用上述flush()且用户中止了连接(例如,在其浏览器中单击STOP按钮)时,PHP将执行的操作。

如果 true ,该脚本将轻松运行。 flush()基本上不会执行任何操作。

如果 false (默认设置),则执行立即将以以下方式停止:

  • 如果PHP尚未关闭,它将开始关闭 过程。

  • 如果PHP已经关闭,它将退出任何关闭方式 功能,然后移至下一个。

析构函数

如果您想在用户中止连接时做一些事情,则需要做三件事:

  1. 检测用户中止连接。这意味着您必须尝试定期向用户flush ignore_connection_aborted,如上所述。清除所有输出缓冲区,回显,刷新。

    a。如果connection_aborted()为真,则每次刷新后都需要手动测试ignore_connection_aborted

    b。如果flush为假,则对flush的调用将导致关闭过程开始。 然后必须特别小心,不要在关闭函数中引起class DestructTester { private $fileHandle; public function __construct($fileHandle){ // fileHandle that we log to $this->fileHandle = $fileHandle; // call $this->onShutdown() when PHP is shutting down. register_shutdown_function(array($this, "onShutdown")); } public function onShutdown() { $isAborted = connection_aborted(); fwrite($this->fileHandle, "PHP is shutting down. isAborted: $isAborted\n"); // NOTE // If connection_aborted() AND ignore_user_abort = false, PHP will immediately terminate // this function when it encounters flush. This means your shutdown functions can end // prematurely if: connection is aborted, ignore_user_abort=false, and you try to flush(). echo "Test."; flush(); fwrite($this->fileHandle, "This was written after a flush.\n"); } public function __destruct() { $isAborted = connection_aborted(); fwrite($this->fileHandle, "DestructTester is getting destructed. isAborted: $isAborted\n"); } } // Create a DestructTester // It'll log to our file on PHP shutdown and __destruct(). $fileHandle = fopen("/path/to/destruct-tester-log.txt", "a+"); fwrite($fileHandle, "---BEGINNING TEST---\n"); $dt = new DestructTester($fileHandle); // Set this value to see how the logs end up changing // ignore_user_abort(true); // Remove any buffers so that PHP attempts to send data on flush(); while (ob_get_level()){ ob_get_contents(); ob_end_clean(); } // Let's loop for 10 seconds // If ignore_user_abort=true: // This will continue to run regardless. // If ignore_user_abort=false: // This will immediate terminate when the user disconnects and PHP tries to flush(); // PHP will begin its shutdown process. // In either case, connection_aborted() should subsequently return "true" after the user // has disconnected (hit STOP button in browser), AND after PHP has attempted to flush(). $numSleeps = 0; while ($numSleeps++ < 10) { $connAbortedStr = connection_aborted() ? "YES" : "NO"; $str = "Slept $numSleeps times. Connection aborted: $connAbortedStr"; echo "$str<br>"; // If ignore_user_abort = false, script will terminate right here. // Shutdown functions will being. // Otherwise, script will continue for all 10 loops and then shutdown. flush(); $connAbortedStr = connection_aborted() ? "YES" : "NO"; fwrite($fileHandle, "flush()'d $numSleeps times. Connection aborted is now: $connAbortedStr\n"); sleep(1); } echo "DONE SLEEPING!<br>"; die; ,否则PHP将立即停止执行该函数并继续执行下一个关闭函数。

将它们放在一起

将所有内容放在一起,让我们举个例子来检测用户按下“ STOP”并执行操作。

ignore_user_abort

评论说明了所有内容。您可以摆弄connection_abort,然后查看日志以了解情况如何发生变化。

我希望这对遇到register_shutdown_function__destruct和{{1}}问题的人有所帮助。

答案 4 :(得分:0)

缓冲似乎会导致问题,具体取决于您的服务器设置。

我尝试使用 ob_end_clean 禁用缓冲区,但这还不够,我必须发送一些数据才能使缓冲区完全刷新。这是最终为我工作的最终代码。

set_time_limit(0); // run the delay as long as the user stays connected
ignore_user_abort(false);
ob_end_clean();
echo "\n";
while ($delay-- > 0 && !connection_aborted())
{
    echo str_repeat("\r", 1000) . "<!--sleep-->\n";
    flush();
    sleep(1);
}
ob_start();