I am currently working on a chat that uses Server-Sent Events to receive the messages. However, I am running into a problem. The server-sent event never connects and stays at pending because the page doesn’t load.
For example:
<?php while(true) { echo "data: This is the message."; sleep(3); ob_flush(); flush(); } ?>
I expect that every 3 seconds, “data: This is the message.” will be outputted. Instead, the page just doesn’t load. However, I need this behavior for server-sent events. Is there a way to fix this?
Edit:
Full Code:
<?php session_start(); require "connect.php"; require "user.php"; session_write_close(); echo $data["number"]; header("Content-Type: text/event-streamnn"); 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 "nn"; } 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 "nn"; $go = false; } } echo " "; ob_flush(); flush(); sleep(2); } while(true); ?>
I would also like to note, that this infinite loop shouldn’t be causing this to happen. This is just how SSE’s are set up usually and it is even done so on the MDN website.
Advertisement
Answer
No doubt by now you have figured this out but on the offchance you have not I used code like the following on a couple of sse scripts and it worked like a charm. The code below is generic and does not feature your sql or recordset processing but the idea is sound(!?)
<?php set_time_limit( 0 ); ini_set('auto_detect_line_endings', 1); ini_set('mysql.connect_timeout','7200'); ini_set('max_execution_time', '0'); date_default_timezone_set( 'Europe/London' ); ob_end_clean(); gc_enable(); header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: GET'); header('Access-Control-Expose-Headers: X-Events'); if( !function_exists('sse_message') ){ function sse_message( $evtname='chat', $data=null, $retry=1000 ){ if( !is_null( $data ) ){ echo "event:".$evtname."rn"; echo "retry:".$retry."rn"; echo "data:" . json_encode( $data, JSON_FORCE_OBJECT|JSON_HEX_QUOT|JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS ); echo "rnrn"; } } } $sleep=1; $c=1; $pdo=new dbpdo();/* wrapper class for PDO that simplifies using PDO */ while( true ){ if( connection_status() != CONNECTION_NORMAL or connection_aborted() ) { break; } /* Infinite loop is running - perform actions you need */ /* Query database */ /* $sql='select * from `table`'; $res=$pdo->query($sql); */ /* Process recordset from db */ /* $payload=array(); foreach( $res as $rs ){ $payload[]=array('message'=>$rs->message); } */ /* prepare sse message */ sse_message( 'chat', array('field'=>'blah blah blah','id'=>'XYZ','payload'=>$payload ) ); /* Send output */ if( @ob_get_level() > 0 ) for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush(); @flush(); /* wait */ sleep( $sleep ); $c++; if( $c % 1000 == 0 ){/* I used this whilst streaming twitter data to try to reduce memory leaks */ gc_collect_cycles(); $c=1; } } if( @ob_get_level() > 0 ) { for( $i=0; $i < @ob_get_level(); $i++ ) @ob_flush(); @ob_end_clean(); } ?>