PHP Server-Sent Events: trigger custom event from another file - php

I need to notify the client(s) whether some of the clients made changes on the database. I consider it to be a single-directional connection (it's only the server who sends events), so I do not need WebSockets.
The logic is as follows:
Client fetches the common API (let's say /api.php?action=add&payload=...), and with this fetch the change on DB is being made.
After mysqli_result returned true, the server-sent event should be triggered to notify other clients (or their service-workers) about DB changed.
The caveats are:
My SSE logic is placed on a separate file (/sse.php) to not make a mess in API logic and to listen to separate endpoint clientside. So I need to trigger SSE from api.php and push the result from there to all clients.
In sse.php I defined a function for pushing which takes the message from api.php as a param. Whatever I've tried, this function was never called.
I strongly want to avoid making daemons and any kind of infinite loops. But without them, the connection for the clientside listener (eventSource) closes and reopens every 3 seconds.
The current state of this all:
api.php
<?php
header("Access-Control-Allow-Origin: *");
include 'connection.php'; // mysqli credentials and connection object
include_once 'functions.php'; // logics
$action = isset($_GET['a']) ? $_GET['a'] : 'fail';
switch ($action) {
case "add":
$result = api__handle_add(); // adds data to DB and returns stringified success/failure result
require "./sse.php"; // file with SSE logic with ev__ namespace
ev__send_data($result); // this defined function should send message to clients
break;
// ...
case "testquery":
require "./sse.php";
ev__send_data("Test event!!! Ololo");
break;
case "fail": default:
header('HTTP/1.1 403 Forbidden', true, 403);
}
sse.php
<?php
header("Access-Control-Allow-Origin: *");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
header("Connection: keep-alive");
$_fired = false; // flag checking for is anything happening right now
while (1) { // the infinite loop I strongly want to get rid of
if (!$_fired) {
usleep(5000); // nothing to send if nothing is fired, but I should keep the connection alive somehow
} else {
// here I should call 'ev__send_data($message_from_api_php)'
// thus I require this file to `api.php` and try to call 'ev__send_data' from there.
}
ob_flush();
flush();
}
function ev__send_data(string $msg) {
global $_fired;
$_fired = true;
echo "data: $msg". PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
usleep(1000);
$_fired = false;
}
The clientside implementation is typical, with onopen, onerror and onmessage handlers of eventSource. I think I don't need to take it here as it has no differences from thousands of examples I've seen here on SO and at other sources.
To conclude: I want to trigger SSE's from outside SSE-file and pass pieces of data from outside, and I want to get rid of while (1) {} and emit events only when something really happens. I've come across thousands of tutorials and SO topics, and found nothing but typical "tutorial cases" about how to send server time to the client every n seconds and stuff. And I think I don't need WebSockets (considering that my local dev environment is Win10 + XAMPP, my prod environment will be something Linux-like and I don't think I can implement my own WebSocket without third-party dependencies which I don't want to install).
Do I have any chance?
EDIT
I found a little different approach. Now my server event generation depends on boolean flags that were settled in MySQL database in separate flags table. When I need an event to be emitted, API changes definite flag (for the very this example, when one client had submitted some changes in DB, API also makes the query to flags table and sets flag DB_CHANGED to 1). And sse.php makes query to flags table each iteration of the infinite loop (every 5 seconds) and emits events depending on the flags' state, and after emitting, sets the corresponding flag to 0 via one more query. This kinda works.
Example of current sse.php:
<?php
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
require_once "connection.php"; // mysqli connection object
set_time_limit(600);
stream();
function stream() {
global $connection;
while (1) { // oh that infinite loop
$flags = []; // there will be fetched flags from DB
$flags_sqli = $connection->query("SELECT * FROM `flags`");
while ($flag = $flags_sqli->fetch_assoc()) {
$flags[$flag['key_']] = ev__h__to_bool_or_string($flag['value_']);
}
if ($flags['ON_TEST']) {
ev__send_data("Test event!!! Ololo");
ev__update_flag("ON_TEST", "0");
} elseif ($flags['ON_DB_ADD']) {
ev__handle_add();
} else {
echo PHP_EOL; // keep connection alive - push single "end of line"
}
ob_flush();
flush();
sleep(5); // interval per iteration - 5 secs
}
}
function ev__send_data(string $msg) : void {
echo "data: ".date("d-m-Y")." ".date("H:i:s").PHP_EOL;
echo "data: $msg".PHP_EOL;
echo PHP_EOL;
}
function ev__handle_add() : void {
global $connection;
$table = $connection->query('SELECT `value_` FROM `flags` WHERE `key_` = "LAST_ADDED_TABLE"')->fetch_row()[0];
$query = "SELECT * FROM `banners_".$table."` WHERE `id` = (SELECT MAX(`id`) FROM `banners_".$table."`)";
$row = $connection->query($query)->fetch_assoc();
echo "event: db_add_row".PHP_EOL;
echo 'data: { "manager": '.$row['manager_id'].', "banner_name": "'.$row['name'].'", "time": "'.date("d-m-Y").' '.date("H:i:s").'" }'.PHP_EOL;
echo PHP_EOL;
ev__update_flag("ON_DB_ADD", "0");
}
function ev__update_flag(string $key, string $value) {
global $connection;
$query = "UPDATE `flags` SET `value_` = '$value' WHERE `flags`.`key_` = '$key';";
$connection->query($query);
}
function ev__h__to_bool_or_string($value) {
return $value === "0" || $value === "1"
? boolval(intval($value))
: $value;
}
Therefore, I didn't get rid of the infinite loop. Considering that there will be a very few concurrent connections (max 3-5 sessions per one time) (when in prod), this very case should not make performance troubles. But what if it would be some kind of hard-loaded service? As an answer, I want to see optimization tips for the case of Server-Sent Events.

Related

PHP pcntl_alarm - pcntl_signal handler fires late

Problem
The title really says it all. I had a Timeout class that handled timing out using pcntl_alarm(), and during ssh2_* calls, the signal handler simply does not fire when it should.
In its most basic form,
print date('H:i:s'); // A - start waiting, ideally 5 seconds at the most
pcntl_alarm(5);
// SSH attempt to download remote file /dev/random to ensure it blocks *hard*
// (omitted)
print date('H:i:s'); // B - get here once it realizes it's a tripeless-cat scenario
with a signal handler that also outputs the date, I would expect this (rows B and C might be inverted, that does not matter)
"A, at 00:00:00"
"C, at 00:00:05" <-- from the signal handler
"B, at 00:00:05"
but the above will obtain this disappointing result instead:
"A, at 00:00:00"
"C, at 00:01:29" <-- from the signal handler
"B, at 00:01:29"
In other words, the signal handler does fire, but it does so once another, longer, timeout has expired. I can only guess this timeout is inside ssh2_*. Quickly browsing through the source code yielded nothing obvious. What's worse, this ~90 seconds timeout is what I can reproduce by halting a download. In other cases when the firewall dropped the wrong SSH2 packet, I got a stuck process with an effectively infinite timeout.
As the title might reveal, I have already checked other questions and this is definitely not a mis-quoting of SIGALRM (also, the Timeout class worked beautifully). It seems like I need a louder alarm when libssh2 is involved.
Workaround
This modification of the Timeout yields a slightly less precise, but always working system, yet it does so in an awkward, clunky way. I'd really prefer for pcntl_alarm to work in all cases as it's supposed to.
public static function install() {
self::$enabled = function_exists('pcntl_async_signals') && function_exists('posix_kill') && function_exists('pcntl_wait');
if (self::$enabled) {
// Just to be on the safe side
pcntl_async_signals(true);
pcntl_signal(SIGALRM, static function(int $signal, $siginfo) {
// Child just died.
$status = null;
pcntl_wait($status);
static::$expired = true;
});
}
return self::$enabled;
}
public static function wait(int $time) {
if (self::$enabled) {
static::$expired = false;
// arrange for a SIGALRM to be delivered in $time seconds
// pcntl_alarm($time);
$ppid = posix_getpid();
$pid = pcntl_fork();
if ($pid == -1) {
throw new RuntimeException('Could not fork alarming child');
}
if ($pid) {
// save the child's PID
self::$thread = $pid;
return;
}
// we are the child. Send SIGALRM to the parent after requested timeout
sleep($time);
posix_kill($ppid, SIGALRM);
die();
}
}
/**
* Cancel the timeout and verify whether it expired.
**/
public static function expired(): bool {
if (self::$enabled) {
// Have we spawned an alarm?
if (self::$thread) {
// Yes, so kill it.
posix_kill(self::$thread, SIGTERM);
self::$thread = 0;
}
// Maybe.
$status = null;
pcntl_wait($status);
// pcntl_alarm(0);
}
return static::$expired;
}
Question
Can pcntl_alarm() be made to work as expected?

Laravel CRON or Event process respond to api request via long poll - how to re-vitalise the session

I have a poll route on an API on Laravel 5.7 server, where the api user can request any information since the last poll.
The easy part is to respond immediately to a valid request if there is new information return $this->prepareResult($newData);
If there is no new data I am storing a poll request in the database, and a cron utility can then check once a minute for all poll requests and respond to any polls where data has been updated. Alternatively I can create an event listener for data updates and fire off a response to the poll when the data is updated.
I'm stuck with how to restore each session to match the device waiting for the update. I can store or pass the session ID but how do I make sure the CRON task / event processor can respond to the correct IP address just as if it was to the original request. Can php even do this?
I am trying to avoid websockets as will have lots of devices but with limited updates / interactions.
Clients poll for updates, APIs do not push updates.
REST API's are supposed to be stateless, so trying to have the backend keep track goes against REST.
To answer your question specifically, if you do not want to use websockets, the client app is going to have to continue to poll the endpoint till data is available.
Long poll is a valid technique. i think is a bad idea to run poll with session. since session are only for original user. you can run your long poll with php cli. you can check on your middleware to allow cli only for route poll. you can use pthreads
to run your long poll use pthreads via cli. and now pthreads v3 is designed safely and sensibly anywhere but CLI. you can use your cron to trigger your thread every one hour. then in your controller you need to store a $time = time(); to mark your start time of execution. then create dowhile loop to loop your poll process. while condition can be ($time > time()+3600) or other condition. inside loop you need to check is poll exist? if true then run it. then on the bottom of line inside loop you need to sleep for some second, for example 2 second.
on your background.php(this file is execute by cron)
<?php
error_reporting(-1);
ini_set('display_errors', 1);
class Atomic extends Threaded {
public function __construct($data = NULL) {
$this->data = $data;
}
private $data;
private $method;
private $class;
private $config;
}
class Task extends Thread {
public function __construct(Atomic $atomic) {
$this->atomic = $atomic;
}
public function run() {
$this->atomic->synchronized(function($atomic)
{
chdir($atomic->config['root']);
$exec_statement = array(
"php7.2.7",
$atomic->config['index'],
$atomic->class,
$atomic->method
);
echo "Running Command".PHP_EOL. implode(" ", $exec_statement)." at: ".date("Y-m-d H:i:s").PHP_EOL;
$data = shell_exec(implode(" ", $exec_statement));
echo $data.PHP_EOL;
}, $this->atomic);
}
private $atomic;
}
$config = array(
"root" => "/var/www/api.example.com/api/v1.1",
"index" => "index.php",
"interval_execution_time" => 200
);
chdir($config['root']);
$threads = array();
$list_threads = array(
array(
"class" => "Background_workers",
"method" => "send_email",
"total_thread" => 2
),
array(
"class" => "Background_workers",
"method" => "updating_data_user",
"total_thread" => 2
),
array(
"class" => "Background_workers",
"method" => "sending_fcm_broadcast",
"total_thread" => 2
)
);
for ($i=0; $i < count($list_threads); $i++)
{
$total_thread = $list_threads[$i]['total_thread'];
for ($j=0; $j < $total_thread; $j++)
{
$atomic = new Atomic();
$atomic->class = $list_threads[$i]['class'];
$atomic->method = $list_threads[$i]['method'];
$atomic->thread_number = $j;
$atomic->config = $config;
$threads[] = new Task($atomic);
}
}
foreach ($threads as $thread) {
$thread->start();
usleep(200);
}
foreach ($threads as $thread)
$thread->join();
?>
and this on your controller
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Background_workers extends MX_Controller {
public function __construct()
{
parent::__construct();
$this->load->database();
$this->output->enable_profiler(FALSE);
$this->configuration = $this->config->item("configuration_background_worker_module");
}
public function sending_fcm_broadcast() {
$time_run = time();
$time_stop = strtotime("+1 hour");
do{
$time_run = time();
modules::run("Background_worker_module/sending_fcm_broadcast", $this->configuration["fcm_broadcast"]["limit"]);
sleep(2);
}
while ($time_run < $time_stop);
}
}
this is a sample runing code from codeigniter controller.
Long polling requires holding the connection open. That can only happen through an infinite loop of checking to see if the data exists and then adding a sleep.
There is no need to revitalize the session as the response is fired only on a successful data hit.
Note that this method is very CPU and memory intensive as the connection and FPM worker will remain open until a successful data hit. Web sockets is a much better solution regardless of the number of devices and frequency of updates.
You can use notifications. "browser notification" for web clients and FCM and APN notification for mobile clients.
Another option is using SSE (server sent events). It's a connection like socket but over http. Client sends a normal request, and server can just respond to client multiple times and any time if client is available (In the same request that has been sent).

Missing cache items [via phpfastcache] using Server Side Events

I'm using Server-Sent Events, to print messages for user.
In infinite loop, every 10 seconds I check if there is any new item in cache to broadcast:
$messages_to_broadcast = $this->_cache->getItemsByTag('inbox_message');
foreach ($messages_to_broadcast as $key => $_message) {
$_message = $_message->get();
if($_message->recipient == $this->_user_id || $_message->recipient == 0){
if(!is_null($html = \CRM\Engine\MessagingService::getMessageToBroadcast($_message)))
{
echo "event: $_message->type \n";
echo "data:{\n";
echo "data:\"message_html\": \"$html\" \n";
echo "data:}\n\n";
$this->send_keepalive = false;
$this->_cache->deleteItem($key);
}
}
}
At irregular intervals, there is event, which save message to cache:
$_cache_this = self::$_cache->getItem("message_".$_message->id);
if(!$_cache_this->isHit()){
$_cache_this->set($_message)
->expiresAfter(600)
->addTag('inbox_message');
self::$_cache->save($_cache_this);
}
The problem is that while I check in infinite loop for new items in cache, I get empty array. When I reload page, or browser reconnect to Server Side Events stream, item appears in cache. Is there any flush method I'm missing here?
I'm using files as cache method.
\phpFastCache\CacheManager::setDefaultConfig(array(
"path" => DIR_TMP
));
global $cache;
$cache = \phpFastCache\CacheManager::getInstance('files');
In a loop, you have to use the detachItem method of PhpFastCache to force it to get the right value.
Here an example:
while (1) {
$cache = $this->cacheService->getCache();
if (null !== $cache) {
try {
$item = $cache->getItem('my_key');
if ($item->isHit()) {
echo "event: message\ndata: $item->get()\n\n";
}
$cache->detachItem($item);
} catch (InvalidArgumentException | PhpfastcacheInvalidArgumentException $e) {
$this->logger->error(
'There has been an error when getting cache item: '
.$e->getMessage().' - '.$e->getFile().' - '.$e->getLine()
);
}
}
ob_flush();
flush();
if (connection_aborted()) {
break;
}
sleep(1);
}
I open a issue to ask more doc here: https://github.com/PHPSocialNetwork/phpfastcache/issues/687
Phpfastcache is storing (the exact definition is "caching" in fact) the cache item statically in the cache backend object. So effectively you'll need to release the object using detachItem() method or clear() to empty the cache.
As described on this issue, I'll update the Wiki coming soon to clarify that behaviour for perpetual CLI scripts.
It's a while you've asked this, but usually you can only grab the items in cache by tag, haven't seen a method that let's you get all cache entries.
$entries = $cache->getItemsByTag('inbox_message')
$entries will now hold all your items.
Have a look here:
https://github.com/PHPSocialNetwork/phpfastcache/blob/final/docs/examples/tagsMethods.php
where you can see a complete example on usage.

I am trying to implement a pulse into a PHP Ratchet Websocket Application

Hello Stack Overflow,
I am building a browser-based text only multi-player RPG written in PHP with Ratchet as the backbone.
What I have so far: It works very well. I have implemented a simple and effective command interpretor that does a good job of transferring data between the client and server. I'm able to easily perform database operations and instantiate outside classes inside my Server class to use to pass information back to the client.
Where I've gotten stuck: For some reason, my brain broke trying to implement ticks, which in the context of my game, is a set of events that happens every 45 seconds. It's basically the heartbeat of the game, and I can't move forward without having a reliable and graceful implementation of it. The tick needs to do a multitude of things, including (but not limited to): sending messages to players, updating player regen, memory handling, and so on. Generally, all these actions can be coded and placed in an Update class.
But I can't figure out how to get the tick to actually happen. The tick itself, just a function that occurs every 45 seconds inside my react loop, it should start when the server starts. It absolutely needs to be server-side. I could technically implement it client-side and sync with values in a database but I do NOT want to go down that road.
I feel like this should be easier than my brain is making it.
What I've tried:
I've tried running a simple recursive function that constructs my update class on a timer using sleep(45), but again, this needs to start when the server starts, and if I toss an infinite looping function in the construct of my server class, the startup script never gets passed that and the game never starts.
I've tried using the onPeriodicTimer function that comes with react, but I can't figure out how to implement it..
I've tried something crazy like using node js to send a message to my server every 45 seconds and my interpreter catches that particular message and starts the tick process. This is the closest I've gotten to a successful implementation but I'm really hoping to be able to do it without a client having to connect and talk to the server, it seems hackey.
I've tried ZeroMQ to achieve the same goal as above (a client that sends a message to my server that triggers the update) but again, I don't want to have to have a client listener constantly connected for the game to run, and also, zeroMQ is a lot to deal with for something so small.. I had no luck with it.
There has to be a better way to achieve this. Any help would be appreciated.
For reference, here is a basic outline of out my socket application is working. To start, I used the "Hello World" tutorial on the Ratchet website.
So I have a startup.php script that I run to initialize the Server class, which accepts messages from connected clients. onMessage, an interpretor class is instantiated which parses the message out and looks for the command the client passed in a database table which loads the corresponding Class and Method for that command, that data is based back to the onMessage function, the class and method for the command is called, and the result is passed back to the client.
TLDR: How do I add a repeating function to a Ratchet websocket server that can send messages to connected clients every 45 seconds?
Here's the Server class:
class Server implements MessageComponentInterface
{
public $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
//exec("nodejs ../bin/java.js", $output);
}
public function onOpen(ConnectionInterface $conn)
{
$conn->connected_state = 0;
$this->clients->attach($conn);
// Initiate login
$login = new Login('CONN_GETNAME');
if($login->success)
{
$conn->send($login->output);
$conn->connected_state = $login->new_state;
$conn->chData = new Character();
}
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg)
{
if($msg == 'do_tick')
{
echo "a tick happened <br>";
}
else
{
if($from->connected_state == 'CONN_CONNECTED' || $msg == 'chardump')
{
$interpretor = new Interpret($msg);
if($interpretor->success)
{
$action_class_var = $interpretor->class;
$action_method_var = $interpretor->function;
$action_class = new $action_class_var($this->clients, $from, $interpretor->msg);
$action = $action_class->{$action_method_var}();
foreach($this->clients as $client)
{
if($action->to_room)
{
if($from != $client)
{
$client->send($action->to_room);
}
}
if($action->to_global)
{
if($from != $client)
{
$client->send($action->to_global);
}
}
if($action->to_char)
{
$client->send($action->to_char);
}
}
}
else
{
$from->send('Huh?');
}
}
else
{
$login = new Login($from->connected_state, $msg, $from);
$from->connected_state = $login->new_state;
if($login->char_data && count($login->char_data)>0)
{
foreach($login->char_data as $key=>$val)
{
$from->chData->{$key} = $val;
}
}
$from->send($login->output);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
Perhaps an onTick function added to this class that gets called every X seconds? Is that possible?
To broadcast the message to everyone in intervals of 45 seconds (or any other number), you must control the event loop which Ratchet uses.
You need to add a timed event, various vendors call this timed event, timer event, repeatable event, but it always behaves the same - a function fires after X amount of time.
Class that you are after is documented at this link
Alternatively, you can use icicle instead of Ratchet. I personally prefer it, I don't have any particular reason for the preference - both libraries are excellent in my opinion, and it's always nice to have an alternative.
Interestingly enough, you tried to use ZeroMQ - it's a transport layer and it's definitely one of the best libraries / projects I've ever used. It plays nicely with event loops, it's definitely interesting for developing distributed systems, job queues and similar.
Good luck with your game! If you'll have any other questions regarding WS, scaling to multiple machines or similar - feel free to ping me in the comments below this answer.
Thank you, N.B.!
For anyone that might be stuck in a similar situation, I hope this helps someone out. I had trouble even figuring out what terms I should be googling to get to the bottom of my problem, and as evidenced by the comments below my original question, I got flack for not being "specific" enough. Sometimes it's hard to ask a question if you're not entirely sure what you're looking for!
Here is what the game's startup script looks like now, with an implemented "tick" loop that I've tested.
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use React\Socket\Server as Reactor;
use React\EventLoop\Factory as LoopFactory;;
require dirname(__DIR__) . '/vendor/autoload.php';
foreach(new DirectoryIterator(dirname(__DIR__) .'/src/') as $fileInfo)
{
if($fileInfo->isDot() || $fileInfo->isDir())
{
continue;
}
require_once(dirname(__DIR__) . '/src/' . $fileInfo->getFilename());
}
$clients = null;
class Server implements MessageComponentInterface
{
public function __construct(React\EventLoop\LoopInterface $loop)
{
global $clients;
$clients = new \SplObjectStorage;
// Breathe life into the game
$loop->addPeriodicTimer(40, function()
{
$this->doTick();
});
}
public function onOpen(ConnectionInterface $ch)
{
global $clients;
$clients->attach($ch);
$controller = new Controller($ch);
$controller->login();
}
public function onMessage(ConnectionInterface $ch, $args)
{
$controller = new Controller($ch, $args);
if($controller->isLoggedIn())
{
$controller->interpret();
}
else
{
$controller->login();
}
}
public function onClose(ConnectionInterface $conn)
{
global $clients;
$clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
public function doTick()
{
global $clients;
$update = new Update($clients);
}
}
$loop = LoopFactory::create();
$socket = new Reactor($loop);
$socket->listen(9000, 'xx.xx.xx.xxx');
$server = new IoServer(new HttpServer(new WsServer(new Server($loop))), $socket, $loop);
$server->run();

php slim detect client abort (HTTP)

In slim framework V3 how can I detect if the client closed the connection ?
I have tried:
ignore_user_abort(false);
and tried checking connection_status() and connection_aborted() in a loop with no luck.
php 5.6.12
It depends not from Slim but from PHP in general. PHP close connection just after execution script.
If you want create persistance connection you need to look to long polling connection.
http://phptrends.com/dig_in/php-long-polling
It seems one need to output something from php and then call ob_flush() because php only handles errors from the browser. Here's a way to do it without outputing anything, which will work fine for long-polling scenarios:
/* returns ESTABLISHED, CLOSE_WAIT, LAST_ACK, etc */
function getConnectionStatus() {
$remote_ip = $_SERVER['REMOTE_ADDR']?:($_SERVER['HTTP_X_FORWARDED_FOR']?:$_SERVER['HTTP_CLIENT_IP']);
$remote_port=$_SERVER['REMOTE_PORT'];
$cmd="netstat -tn | fgrep ' $remote_ip:$remote_port '";
$pfp=popen($cmd,"r");
$buf = fgets($pfp, 1024);
pclose($pfp);
$buf=preg_replace('!\s+!', ' ', $buf); //remove multiple spaces
$buf=trim($buf);
$buf_r=explode(" ",$buf);
if (count($buf_r)) {
$state=$buf_r[count($buf_r)-1];
return trim($state);
}
return "NOTFOUND";
}
Use it as follows:
while(...) {
/* ... longpolling check code here ...*/
if (getConnectionStatus() != "ESTABLISHED") {
break;
}
}

Categories