gpt4 book ai didi

PHP connection_aborted() 无法正常工作

转载 作者:行者123 更新时间:2023-12-01 13:00:28 29 4
gpt4 key购买 nike

我有以下代码:

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。提前致谢!

最佳答案

我参加这个聚会有点晚了,但我刚刚遇到了这个问题,并把它弄清楚了。这里发生了很多事情——这里提到了其中的一些:
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() 时 PHP 会做什么。被调用,并且用户中止了连接(例如:点击浏览器中的 STOP 按钮)。

如果 真实 ,脚本将愉快地运行。 flush()基本上什么都不做。

如果 , 作为默认设置,执行将 立即以下列方式停止:
  • 如果 PHP 尚未关闭,它将开始关闭
    过程。
  • 如果 PHP 已经关闭,它将退出任何关闭
    它所在的功能并继续下一个。

  • 析构函数

    如果你想在用户中止连接时做一些事情,你需要做三件事:
  • 检测用户中止连接。这意味着您必须尝试 flush如上所述,定期向用户发送。清除所有输出缓冲区、回显、刷新。

    一种。如果 ignore_connection_aborted是真的,需要手动测试connection_aborted()每次冲洗后。

    湾。如果 ignore_connection_aborted是假的,调用flush将导致关闭过程开始。 然后你必须特别小心不要导致flush从你的关机函数中 ,否则 PHP 将立即停止执行该函数并继续执行下一个关闭函数。

  • 把它们放在一起

    把这一切放在一起,让我们做一个例子来检测用户点击“STOP”并做一些事情。
    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;

    评论解释了一切。你可以摆弄 ignore_user_abort并查看日志以了解这如何改变事情。

    我希望这可以帮助任何遇到 connection_abort 问题的人, register_shutdown_function , 和 __destruct .

    关于PHP connection_aborted() 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6381270/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com