Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/295.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
使用while循环时未加载服务器端PHP事件页_Php_Server Side_Server Sent Events - Fatal编程技术网

使用while循环时未加载服务器端PHP事件页

使用while循环时未加载服务器端PHP事件页,php,server-side,server-sent-events,Php,Server Side,Server Sent Events,我有一个名为handler.php的文件,它从文本文件中读取数据并将其推送到客户端页面 相关客户代码: <script> if(typeof(EventSource) !== "undefined") { var source = new EventSource("handler.php"); source.onmessage = function(event) { var textarea = document.getElementById("sub

我有一个名为handler.php的文件,它从文本文件中读取数据并将其推送到客户端页面

相关客户代码:

<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("handler.php");
    source.onmessage = function(event) {
        var textarea = document.getElementById("subtitles");
        textarea.value += event.data;
        textarea.scrollTop = textarea.scrollHeight;

    };
} else {
    document.getElementById("subtitles").value = "Server-sent events not supported.";
}
</script>
使用循环时,不会加载handler.php,因此不会向客户端发送任何数据。在Chrome开发者网络选项卡中,handler.php显示为“挂起”,然后显示为“取消”。文件本身保持锁定大约30秒

但是,如果我删除while循环(如下所示),则会加载handler.php,并且客户端确实会接收数据(仅接收一次,即使liveData.txt文件不断更新)

无循环的Handler.php:

$id = 0;
$event = 'event1';
$oldValue = null;

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');

try {
    $data = file_get_contents('liveData.txt');
} catch(Exception $e) {
    $data = $e->getMessage();
}

if ($oldValue !== $data) {
    $oldValue = $data;
    echo 'id: '    . $id++  . PHP_EOL;
    echo 'event: ' . $event . PHP_EOL;
    echo 'retry: 2000'      . PHP_EOL;
    echo 'data: '  . json_encode($data) . PHP_EOL;
    echo PHP_EOL;

    @ob_flush();
    @flush();

    }

我使用SSE是因为我只需要单向通信(所以WebSocket可能有点过头了),我真的不想使用轮询。如果我不能解决这个问题,我可能不得不这样做。

我想你对网络的工作方式有问题。PHP代码不会在浏览器中运行——它只是创建一些web服务器通过网络传递给浏览器的东西

一旦从服务器加载了页面,就完成了。您需要实现一些轮询更改的功能

我这样做的一种方法是将页面放入一个循环中,该循环会刷新页面,因此每隔一秒左右就会使用新数据再次获取页面(但如果页面上有很多人,这可能会严重过载服务器)


唯一的另一种解决方案是使用推送技术和javascript框架,该框架可以进行推送并重新填充页面的相关部分,或者在计时器上使用javascript循环来提取数据。

我认为您对web的工作方式有问题。PHP代码不会在浏览器中运行——它只是创建一些web服务器通过网络传递给浏览器的东西

一旦从服务器加载了页面,就完成了。您需要实现一些轮询更改的功能

我这样做的一种方法是将页面放入一个循环中,该循环会刷新页面,因此每隔一秒左右就会使用新数据再次获取页面(但如果页面上有很多人,这可能会严重过载服务器)

唯一的另一种解决方案是使用推送技术和javascript框架,该框架可以进行推送并重新填充页面的相关部分,或者在计时器上使用javascript循环来提取数据

使用循环时,不会加载handler.php,因此客户端不会加载 发送任何数据。在Chrome开发者网络选项卡中,handler.php是 显示为“待定”,然后显示为“已取消”。文件本身保持锁定状态 大约30秒

这是因为在30秒内没有响应时,Web服务器(Apache)或浏览器甚至PHP本身都会取消请求

因此,我猜刷新不起作用,请尝试在不使用
@
函数的情况下主动启动和结束缓冲区,以便在出现错误时获得线索

// Start output buffer
ob_start();

// Write content
echo ''; 

// Flush output buffer
ob_end_flush();
使用循环时,不会加载handler.php,因此客户端不会加载 发送任何数据。在Chrome开发者网络选项卡中,handler.php是 显示为“待定”,然后显示为“已取消”。文件本身保持锁定状态 大约30秒

这是因为在30秒内没有响应时,Web服务器(Apache)或浏览器甚至PHP本身都会取消请求

因此,我猜刷新不起作用,请尝试在不使用
@
函数的情况下主动启动和结束缓冲区,以便在出现错误时获得线索

// Start output buffer
ob_start();

// Write content
echo ''; 

// Flush output buffer
ob_end_flush();

就我所知,SSE连接的客户端看起来很正常-尽管我将
var textarea…..
移动到
onmessage
处理程序之外

更新:我应该仔细查看,但是要监视的事件是
event1
,因此我们需要为该事件设置一个事件侦听器

<script>
    if( typeof( EventSource ) !== "undefined" ) {
        var url = 'handler.php'

        var source = new EventSource( url );
        var textarea = document.getElementById("subtitles");


        source.addEventListener('event1', function(e){
            textarea.value += e.data;
            textarea.scrollTop = textarea.scrollHeight;
            console.info(e.data);
        },false );

    } else {
        document.getElementById("subtitles").value = "Server-sent events not supported.";
    }
</script>

if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('event1',函数(e){
textarea.value+=e.data;
textarea.scrollTop=textarea.scrollHeight;
控制台信息(如数据);
},假);
}否则{
document.getElementById(“subtitles”).value=“不支持服务器发送的事件。”;
}
至于SSE服务器脚本,我倾向于使用这样的方法

<?php
    /* make sure the script does not timeout */
    set_time_limit( 0 );
    ini_set('auto_detect_line_endings', 1);
    ini_set('max_execution_time', '0');

    /* start fresh */
    ob_end_clean();


    /* ultility function for sending SSE messages */
    function sse( $evtname='sse', $data=null, $retry=1000 ){
        if( !is_null( $data ) ){
            echo "event:".$evtname."\r\n";
            echo "retry:".$retry."\r\n";
            echo "data:" . json_encode( $data, JSON_FORCE_OBJECT | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS );
            echo "\r\n\r\n";
        }
    }



    $id = 0;
    $event = 'event1';
    $oldValue = null;

    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('X-Accel-Buffering: no');





    while( true ){
        try {
            $data = @file_get_contents( 'liveData.txt' );
        } catch( Exception $e ) {
            $data = $e->getMessage();
        }

        if( $oldValue !== $data ) {

            /* data has changed or first iteration */
            $oldValue = $data;

            /* send the sse message */
            sse( $event, $data );

            /* make sure all buffers are cleansed */
            if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
            @flush();           
        }



        /* 
            sleep each iteration regardless of whether the data has changed or not.... 
        */
        sleep(1);
    }



    if( @ob_get_level() > 0 ) {
        for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @ob_end_clean();
    }
?>

据我所知,SSE连接的客户端看起来很正常-尽管我将
var textarea….
移到了
onmessage
处理程序之外

更新:我应该仔细查看,但是要监视的事件是
event1
,因此我们需要为该事件设置一个事件侦听器

<script>
    if( typeof( EventSource ) !== "undefined" ) {
        var url = 'handler.php'

        var source = new EventSource( url );
        var textarea = document.getElementById("subtitles");


        source.addEventListener('event1', function(e){
            textarea.value += e.data;
            textarea.scrollTop = textarea.scrollHeight;
            console.info(e.data);
        },false );

    } else {
        document.getElementById("subtitles").value = "Server-sent events not supported.";
    }
</script>

if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('event1',函数(e){
textarea.value+=e.data;
textarea.scrollTop=textarea.scrollHeight;
控制台信息(如数据);
},假);
}否则{
document.getElementById(“subtitles”).value=“不支持服务器发送的事件。”;
}
至于SSE服务器脚本,我倾向于使用这样的方法

<?php
    /* make sure the script does not timeout */
    set_time_limit( 0 );
    ini_set('auto_detect_line_endings', 1);
    ini_set('max_execution_time', '0');

    /* start fresh */
    ob_end_clean();


    /* ultility function for sending SSE messages */
    function sse( $evtname='sse', $data=null, $retry=1000 ){
        if( !is_null( $data ) ){
            echo "event:".$evtname."\r\n";
            echo "retry:".$retry."\r\n";
            echo "data:" . json_encode( $data, JSON_FORCE_OBJECT | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS );
            echo "\r\n\r\n";
        }
    }



    $id = 0;
    $event = 'event1';
    $oldValue = null;

    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('X-Accel-Buffering: no');





    while( true ){
        try {
            $data = @file_get_contents( 'liveData.txt' );
        } catch( Exception $e ) {
            $data = $e->getMessage();
        }

        if( $oldValue !== $data ) {

            /* data has changed or first iteration */
            $oldValue = $data;

            /* send the sse message */
            sse( $event, $data );

            /* make sure all buffers are cleansed */
            if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
            @flush();           
        }



        /* 
            sleep each iteration regardless of whether the data has changed or not.... 
        */
        sleep(1);
    }



    if( @ob_get_level() > 0 ) {
        for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush();
        @ob_end_clean();
    }
?>

(代表问题作者发布解决方案)

成功!在进行第n次调试时,我决定回到基础并重新开始。我放弃了循环,将PHP代码减少到最低限度,但保留了RamRaider提供的客户端代码。现在一切都非常好!通过使用retry值,我可以精确地指定推送数据的频率

PHP(服务器端):


Javascript(客户端):


if(typeof(EventSource)!=“未定义”){
var url='handler.php'
var source=新事件源(url);
var textarea=document.getElementById(“字幕”);
source.addEventListener('ev