Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/227.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 而服务器发送事件的循环导致页面冻结_Php_Server Sent Events - Fatal编程技术网

Php 而服务器发送事件的循环导致页面冻结

Php 而服务器发送事件的循环导致页面冻结,php,server-sent-events,Php,Server Sent Events,我目前正在使用服务器发送的事件来接收消息的聊天。然而,我遇到了一个问题。服务器发送事件从未连接,并且由于页面未加载而处于挂起状态 例如: <?php while(true) { echo "data: This is the message."; sleep(3); ob_flush(); flush(); } ?> 我预计每3秒钟就会输出一次“数据:这就是消息”。相反,页面只是不加载。但是,对于服

我目前正在使用服务器发送的事件来接收消息的聊天。然而,我遇到了一个问题。服务器发送事件从未连接,并且由于页面未加载而处于挂起状态

例如:

<?php
    while(true) {
        echo "data: This is the message.";
        sleep(3);
        ob_flush();
        flush();
    }
?>

我预计每3秒钟就会输出一次“数据:这就是消息”。相反,页面只是不加载。但是,对于服务器发送的事件,我需要这种行为。有办法解决这个问题吗

编辑:

完整代码:

<?php
   session_start();

    require "connect.php";
    require "user.php";

    session_write_close();

    echo $data["number"];

    header("Content-Type: text/event-stream\n\n");
    header('Cache-Control: no-cache');

    set_time_limit(1200);

    $store = new StdClass(); // STORE LATEST MESSAGES TO COMPARE TO NEW ONES
    $ms = 200; // REFRESH TIMING (in ms)
    $go = true; // MESSAGE CHANGED

    function formateNumber ($n) {
            $areaCode = substr($n, 0, 3);
            $part1 = substr($n, 3, 3);
            $part2 = substr($n, 6, 4);
            return "($areaCode) $part1-$part2";
    }

    function shorten ($str, $mLen, $elp) {
        if (strlen($str) <= $mLen) { 
            return $str;
        } else {
            return rtrim(substr($str, 0, $mLen)) . $elp;
        }
    }

   do {
    $number = $data["number"];
        $sidebarQ = "
            SELECT * 
            FROM (
                SELECT * 
                FROM messages 
                WHERE deleted NOT LIKE '%$number%' 
                AND (
                    `from`='$number' 
                    OR 
                    `to`='$number'
                ) 
                ORDER BY `timestamp` DESC
            ) as mess 
            GROUP BY `id` 
            ORDER BY `timestamp` DESC";
        $query = $mysqli->query($sidebarQ);

        if ($query->num_rows == 0) {
            echo 'data: null' . $number;
            echo "\n\n";
        } else {

            $qr = array();
            while($row = $query->fetch_assoc()) {
                $qr[] = $row;
            }

            foreach ($qr as $c) {
                $id = $c["id"];
                if (!isset($store->{$id})) {
                    $store->{$id} = $c["messageId"];
                    $go = true;
                } else {
                    if ($store->{$id} != $c["messageId"]) {
                        $go = true;
                        $store->{$id} = $c["messageId"];
                    }
                }
            }

            if($go == true) {
                $el = $n = "";

                foreach ($qr as $rows) {
                    $to = $rows["to"];
                    $id = $rows["id"];
                    $choose = $to == $number ? $rows["from"] : $to;
                    $nameQuery = $mysqli->query("SELECT `savedname` FROM `contacts` WHERE `friend`='$choose' AND `number`='$number'");
                    $nameGet = $nameQuery->fetch_assoc();
                    $hasName = $nameQuery->num_rows == 0 ? formateNumber($choose) : $nameGet["savedname"];

                    $new = $mysqli->query("SELECT `id` FROM `messages` WHERE `to`='$number' AND `tostatus`='0' AND `id`='$id'")->num_rows;
                    if ($new > 0) {
                        $n = "<span class='new'>" . $new . "</span>";
                    }

                    $side = "<span style='color:#222'>" . ($to == $number ? "To you:" : "From you:") . "</span>";
                    $el .= "<div class='messageBox sBox" . ($nameQuery->num_rows == 0 ? " noname" : "") . "' onclick=\"GLOBAL.load($id, $choose)\" data-id='$id'><name>$hasName</name><div>$side " . shorten($rows["message"], 25, "...") . "</div>$n</div>";
                }
                echo 'data: '. $el;
                echo "\n\n";

                $go = false;
            }
        }

        echo " ";

        ob_flush();
        flush();
        sleep(2);
    } while(true);
?>


我还想指出,这个无限循环不应该导致这种情况发生。这就是SSE的通常设置方式,甚至在MDN网站上也是如此。

虽然这不是问题的直接答案,但请尝试使用此方法查找错误。。你没有得到错误,但这应该可以帮助你找到它们,也许

基本上,您希望有一个包含主脚本的简单PHP脚本,但此页面允许出现错误。。。下面的例子

index.php/Simple Error Includer

<?php
    ini_set('display_errors',1);
    ini_set('display_startup_errors',1);
    error_reporting(-1);
    require "other.php";
?> 

中的示例毫无疑问,到现在为止,您已经明白了这一点,但很可能您还没有明白,我在几个sse脚本中使用了下面这样的代码,它非常有效。下面的代码是通用的,没有sql或记录集处理功能,但其思想是合理的(!?)


我要冒一次险,说出显而易见的事实

您可以每3秒钟查询一次服务器,让客户端进行等待

这可以通过javascript轻松完成

例如,如果
file.php

<?php
$action='';
if (array_key_exists('action',$_GET))
{$action=$_GET['action'];}
if ($action=='poll')
{
 echo "this message will be sent every 3 sec";
}
else
{
?><HTML><HEAD>
<SCRIPT SRC="http://code.jquery.com/jquery-2.1.3.min.js"></SCRIPT>
<SCRIPT>
function doPoll()
{
    $('#response').append($.get("file.php?action=poll"));
    setTimeout(doPoll, 3000);
}
doPoll();
</SCRIPT>
</HEAD><BODY><DIV id="response"></DIV></BODY></HTML><?php
}

函数doPoll()
{
$('#response').append($.get(“file.php?action=poll”);
设置超时(doPoll,3000);
}
doPoll();

它能像脚本超时一样简单吗

如果PHP脚本运行时间过长,最终会自动终止。当您不希望这种情况发生时,解决方案是不断重置超时

因此,您可能只需要简单的添加:

<?php
    while(true) {
        echo "data: This is the message.";
        set_time_limit(30);
        sleep(3);
        ob_flush();
        flush();
    }
?>

当然,可能不是这样,但我的直觉是这就是问题所在


更新:我在评论中注意到你正在使用一些免费主机。如果他们在
安全模式下运行PHP
,则您无法重置超时。

我注意到这里有一件事是
sleep()
函数与
ob\u start()
结合使用,并且-在完整的代码示例中没有-ob\u start()任何地方,但是有
flush()
ob flush()

你到底在冲什么? 为什么不干脆
ob\u end\u flush()


问题是
sleep()
echo()
,比
sleep()
再比
echo()
再等等。。打开输出缓冲时无效。当输出缓冲不在中间时,睡眠功能按预期工作。事实上,它可能会(而且会)产生意想不到的结果,而这些结果并不是我们想要看到的

似乎睡眠功能干扰了输出。在之后使用睡眠功能确实有效:

<?php
while(true) {
    echo "data: This is the message.";
    ob_flush();
    flush();
    sleep(3);
    }

不要使用循环,试试下面给出的代码,它可以根据您的要求正常工作(我自己测试过)

echo“数据:这是消息。”
$url1=“.php”
标题(“刷新:5;URL=$url1”)

它将每5秒调用一次(在您的情况下,将其设置为3而不是5)并回显输出


希望这能解决您的问题

我建议使用if()语句而不是while。在您的情况下,您的条件始终为真,因此它处于无限循环中。

下面的代码在这里运行良好,还使用Mayhem的str_repeat函数添加4k数据(这通常是php刷新tcp数据包的最小值)


你到底为什么要使用无限循环呢?这就是为什么页面从未加载,怎么可能呢?下面有一些简单的例子。正如你所看到的,在MDN网站上…他们使用无限循环。取出
echo$data[“number”]。如果在设置内容类型标题之前打印某些内容,则会得到默认的内容类型,可能是text/html。在这种情况下,它应该返回数据,因为它使用输出缓冲,但对于每个服务器来说,这有时可能有点棘手。。值得用一个更简单的页面测试输出缓冲代码,然后看看它在这种情况下是否仍然有效这是纯PHP无法做到的。更新需要重新加载页面或AJAX。@EvanCarslake这可以用纯PHP完成,这是输出缓冲的酷之处。。如果您有一个iframe加载带有输出缓冲的PHP,,,您可以使用PHP代码触发更新。。。虽然它并不总是一个干净的解决方案,但它确实有效,而且是一个非常有名的方法。我知道我在这里也会使用flush()来尝试将数据发送到浏览器,而不需要填充PHP和Apache缓冲区。这些缓冲区与您提到的代码空间输出缓冲区不同。其中是
ob\u start()
。。在你的代码里?我问“你冲什么来着?”就是因为这个。从哪里开始输出缓冲?在使用其他缓冲区函数之前,需要在某个地方启动它。我所看到的“start”是
session\u start()
,它与输出缓冲无关。。两个不同的世界。ob_flush()在这里不起任何作用,因为这里没有要刷新的输出缓冲区。编码马虎,但也可能寻址可能在其他地方打开输出缓冲区的库(不在提供的示例中)。关于自己编码,调用
header()
函数后,
set\u time\u limit()
也是一个坏主意。而且,
ob\u flush()
ob\u end\u flush()
不是一回事<代码>刷新()
ob\u flush()<?php
$action='';
if (array_key_exists('action',$_GET))
{$action=$_GET['action'];}
if ($action=='poll')
{
 echo "this message will be sent every 3 sec";
}
else
{
?><HTML><HEAD>
<SCRIPT SRC="http://code.jquery.com/jquery-2.1.3.min.js"></SCRIPT>
<SCRIPT>
function doPoll()
{
    $('#response').append($.get("file.php?action=poll"));
    setTimeout(doPoll, 3000);
}
doPoll();
</SCRIPT>
</HEAD><BODY><DIV id="response"></DIV></BODY></HTML><?php
}
<?php
    while(true) {
        echo "data: This is the message.";
        set_time_limit(30);
        sleep(3);
        ob_flush();
        flush();
    }
?>
<?php
while(true) {
    echo "data: This is the message.";
    ob_flush();
    flush();
    sleep(3);
    }
echo str_repeat(' ', 4096);
while(true)
{
    echo "data: This is the message.";
    flush();
    sleep(3);
}