我有以下代码:
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。提前谢谢!
答案 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已经关闭,它将退出任何关闭方式 功能,然后移至下一个。
如果您想在用户中止连接时做一些事情,则需要做三件事:
检测用户中止连接。这意味着您必须尝试定期向用户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();