2016-11-17 24 views
1

我想創建一個簡單的頁面發送事件到網頁,但我不能讓PHP在頁面終止前發送輸出。PHP和事件 - 刷新到客戶端不會發生,直到腳本死亡

我正在使用PHP-FPM和php5.6.27。

這是我簡單的HTML頁面:

<html> 
    <head> 
     <title>test events</title> 
    </head> 
    <body> 
     testing events 
     <ul id="pingEventList" style="float: left"></ul> 
     <ul id="messageEventList" style="float: left"></ul> 
     <script> 
      var evtSource=new EventSource("./s_events.php?auth=e3b164ef33d802c45da829b8f1240d16"); 
      var pingEventList=document.getElementById('pingEventList'); 
      var messageEventList=document.getElementById('messageEventList'); 
      evtSource.onmessage=function (e){ 
       var newElement=document.createElement("li"); 
       newElement.innerHTML="message: "+e.data; 
       messageEventList.appendChild(newElement); 
      }; 
      evtSource.addEventListener("initial", function (e){ 
       var newElement=document.createElement("li"); 
//    var obj=JSON.parse(e.data); 
       newElement.innerHTML="initial info "+e.data; 
       console.log("initial info "+e.data); 
       pingEventList.appendChild(newElement); 
      }, false); 
      evtSource.addEventListener("modified", function (e){ 
       var newElement=document.createElement("li"); 
//    var obj=JSON.parse(e.data); 
       newElement.innerHTML="modified info "+e.data; 
       console.log("modified info "+e.data); 
       pingEventList.appendChild(newElement); 
      }, false); 
      evtSource.onerror=function (e){ 
       console.log("EventSource failed.", e); 
//    while(pingEventList.firstChild){ 
//     pingEventList.removeChild(pingEventList.firstChild); 
//    } 
//    alert("EventSource failed."); 
      }; 
//   evtSource.close(); 
     </script> 
    </body> 
</html> 

,這是我的PHP頁面:

<?php 

@set_time_limit(0); // Disable time limit 
// Prevent buffering 
if(function_exists('apache_setenv')){ 
    @apache_setenv('no-gzip', 1); 
} 
@ini_set('zlib.output_compression', 0); 
@ini_set('implicit_flush', 1); 
while(ob_get_level() !=0){ 
    ob_end_flush(); 
} 
ob_implicit_flush(1); 
ignore_user_abort(false); 
header('Access-Control-Allow-Origin: *'); 
header('Access-Control-Allow-Credentials: true'); 
header('Content-Type: text/event-stream'); 
header('Cache-Control: no-cache'); // recommended to prevent caching of event data. 
header('X-Accel-Buffering: off'); // Disables FastCGI Buffering on Nginx 
$sleep_time   = 1; //0.5 // seconds to sleep after the data has been sent 
$exec_limit_time  = 15; //600; // the time limit of the script in seconds 
$keep_alive_time  = 30; //300; // The interval of sending a signal to keep the connection alive 
$client_reconnect = 1; // the time client to reconnect after connection has lost in seconds 
$keep_alive_start = time(); 
$exec_limit_start = time(); 


$ts_last_used = intval(isset($_SERVER["HTTP_LAST_EVENT_ID"])?$_SERVER["HTTP_LAST_EVENT_ID"]:0); 
echo 'retry:'.($client_reconnect*1000)."\n"; 
$event   = [ 
    'id'  => $ts_last_used++, 
    'event' => 'initial', 
    'data' => "[\ndata:".'INITIAL DATA'."\ndata:]", 
]; 
_send_event_data($event); 
while(1){ 
    // Did the connection fail? 
    if(connection_status() !=CONNECTION_NORMAL){ 
     break; 
    }else{ 
     $event = [ 
      'id'  => $ts_last_used++, 
      'event' => 'modified', 
      'data' => '{"id":"stuff here too"}', 
     ]; 
     _send_event_data($event); 
    } 
    // Sleep for x seconds 
    usleep($sleep_time*1000000); 
    if($exec_limit_start+$exec_limit_time<time()){ 
     break; 
    } 
    if($keep_alive_start+$keep_alive_time<time()){ 
     $keep_alive_start = time(); 
     echo ': '.sha1(mt_rand())."\n\n"; 
    } 
} 
// If this is reached, then the 'break' 
// was triggered from inside the while loop 
// 
// So here we can log, or perform any other tasks 
// we need without actually being dependent on the 
// browser. 

function _send_event_data($info){ 
    global $keep_alive_start; 
    if(isset($info['id'])){ 
     echo 'id:'.$info['id']."\n"; 
    } 
    if(isset($info['event'])){ 
     echo 'event:'.$info['event']."\n"; 
    } 
    echo 'data:'.$info['data']."\n"; 
    if(!isset($info['more_to_come'])||!$info['more_to_come']){ 
     echo "\n"; 
    } 
    $keep_alive_start = time(); 
    @ob_end_flush(); 
    flush(); 
} 

我嘗試了各種可能的解決方案,但我不能弄明白。我還將PHP-FPM更改爲mod_php(我使用apache),以防萬一它是PHP_FPM,但我沒有取得任何成功。

我願意接受建議

+0

錯誤?預期結果? .... –

+0

完全沒有錯誤,頁面只在腳本結束時輸出,而不在腳本運行時輸出。在設置超時之前根本沒有數據發送到客戶端 – Fabrizio

回答

1

我想通了......這是阿帕奇這是保持輸出,這是我對快速CGI usign的php-fpm的新配置:

<IfModule fastcgi_module> 
    #php-fpm 
    AddHandler php5-fcgi .php .html 
    Action php5-fcgi /php5-fcgi 
    Alias /php5-fcgi /usr/local/www/cgi-bin/php5-fcgi 
    FastCgiExternalServer /usr/local/www/cgi-bin/php5-fcgi -flush -socket /var/run/php-fpm.sock -pass-header Authorization -idle-timeout 600 
    <Directory /usr/local/www/cgi-bin> 
     Require all granted 
    </Directory> 
</IfModule> 

是什麼導致-flush被添加到FastCgiExternalServer,現在輸出不再被緩衝,並立即輸出(由於此頁,我能夠找到答案:http://www.jeffgeerling.com/blog/2016/streaming-php-disabling-output-buffering-php-apache-nginx-and-varnish