How do I implement basic "Long Polling"? - php

I can find lots of information on how Long Polling works (For example, this, and this), but no simple examples of how to implement this in code.
All I can find is cometd, which relies on the Dojo JS framework, and a fairly complex server system..
Basically, how would I use Apache to serve the requests, and how would I write a simple script (say, in PHP) which would "long-poll" the server for new messages?
The example doesn't have to be scaleable, secure or complete, it just needs to work!

It's simpler than I initially thought.. Basically you have a page that does nothing, until the data you want to send is available (say, a new message arrives).
Here is a really basic example, which sends a simple string after 2-10 seconds. 1 in 3 chance of returning an error 404 (to show error handling in the coming Javascript example)
msgsrv.php
<?php
if(rand(1,3) == 1){
/* Fake an error */
header("HTTP/1.0 404 Not Found");
die();
}
/* Send a string after a random number of seconds (2-10) */
sleep(rand(2,10));
echo("Hi! Have a random number: " . rand(1,10));
?>
Note: With a real site, running this on a regular web-server like Apache will quickly tie up all the "worker threads" and leave it unable to respond to other requests.. There are ways around this, but it is recommended to write a "long-poll server" in something like Python's twisted, which does not rely on one thread per request. cometD is an popular one (which is available in several languages), and Tornado is a new framework made specifically for such tasks (it was built for FriendFeed's long-polling code)... but as a simple example, Apache is more than adequate! This script could easily be written in any language (I chose Apache/PHP as they are very common, and I happened to be running them locally)
Then, in Javascript, you request the above file (msg_srv.php), and wait for a response. When you get one, you act upon the data. Then you request the file and wait again, act upon the data (and repeat)
What follows is an example of such a page.. When the page is loaded, it sends the initial request for the msgsrv.php file.. If it succeeds, we append the message to the #messages div, then after 1 second we call the waitForMsg function again, which triggers the wait.
The 1 second setTimeout() is a really basic rate-limiter, it works fine without this, but if msgsrv.php always returns instantly (with a syntax error, for example) - you flood the browser and it can quickly freeze up. This would better be done checking if the file contains a valid JSON response, and/or keeping a running total of requests-per-minute/second, and pausing appropriately.
If the page errors, it appends the error to the #messages div, waits 15 seconds and then tries again (identical to how we wait 1 second after each message)
The nice thing about this approach is it is very resilient. If the clients internet connection dies, it will timeout, then try and reconnect - this is inherent in how long polling works, no complicated error-handling is required
Anyway, the long_poller.htm code, using the jQuery framework:
<html>
<head>
<title>BargePoller</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css" media="screen">
body{ background:#000;color:#fff;font-size:.9em; }
.msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
.old{ background-color:#246499;}
.new{ background-color:#3B9957;}
.error{ background-color:#992E36;}
</style>
<script type="text/javascript" charset="utf-8">
function addmsg(type, msg){
/* Simple helper to add a div.
type is the name of a CSS class (old/new/error).
msg is the contents of the div */
$("#messages").append(
"<div class='msg "+ type +"'>"+ msg +"</div>"
);
}
function waitForMsg(){
/* This requests the url "msgsrv.php"
When it complete (or errors)*/
$.ajax({
type: "GET",
url: "msgsrv.php",
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});
</script>
</head>
<body>
<div id="messages">
<div class="msg old">
BargePoll message requester!
</div>
</div>
</body>
</html>

I've got a really simple chat example as part of slosh.
Edit: (since everyone's pasting their code in here)
This is the complete JSON-based multi-user chat using long-polling and slosh. This is a demo of how to do the calls, so please ignore the XSS problems. Nobody should deploy this without sanitizing it first.
Notice that the client always has a connection to the server, and as soon as anyone sends a message, everyone should see it roughly instantly.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- Copyright (c) 2008 Dustin Sallings <dustin+html#spy.net> -->
<html lang="en">
<head>
<title>slosh chat</title>
<script type="text/javascript"
src="http://code.jquery.com/jquery-latest.js"></script>
<link title="Default" rel="stylesheet" media="screen" href="style.css" />
</head>
<body>
<h1>Welcome to Slosh Chat</h1>
<div id="messages">
<div>
<span class="from">First!:</span>
<span class="msg">Welcome to chat. Please don't hurt each other.</span>
</div>
</div>
<form method="post" action="#">
<div>Nick: <input id='from' type="text" name="from"/></div>
<div>Message:</div>
<div><textarea id='msg' name="msg"></textarea></div>
<div><input type="submit" value="Say it" id="submit"/></div>
</form>
<script type="text/javascript">
function gotData(json, st) {
var msgs=$('#messages');
$.each(json.res, function(idx, p) {
var from = p.from[0]
var msg = p.msg[0]
msgs.append("<div><span class='from'>" + from + ":</span>" +
" <span class='msg'>" + msg + "</span></div>");
});
// The jQuery wrapped msgs above does not work here.
var msgs=document.getElementById("messages");
msgs.scrollTop = msgs.scrollHeight;
}
function getNewComments() {
$.getJSON('/topics/chat.json', gotData);
}
$(document).ready(function() {
$(document).ajaxStop(getNewComments);
$("form").submit(function() {
$.post('/topics/chat', $('form').serialize());
return false;
});
getNewComments();
});
</script>
</body>
</html>

Tornado is designed for long-polling, and includes a very minimal (few hundred lines of Python) chat app in /examples/chatdemo , including server code and JS client code. It works like this:
Clients use JS to ask for an updates since (number of last message), server URLHandler receives these and adds a callback to respond to the client to a queue.
When the server gets a new message, the onmessage event fires, loops through the callbacks, and sends the messages.
The client-side JS receives the message, adds it to the page, then asks for updates since this new message ID.

I think the client looks like a normal asynchronous AJAX request, but you expect it to take a "long time" to come back.
The server then looks like this.
while (!hasNewData())
usleep(50);
outputNewData();
So, the AJAX request goes to the server, probably including a timestamp of when it was last update so that your hasNewData() knows what data you have already got.
The server then sits in a loop sleeping until new data is available. All the while, your AJAX request is still connected, just hanging there waiting for data.
Finally, when new data is available, the server gives it to your AJAX request and closes the connection.

Here are some classes I use for long-polling in C#. There are basically 6 classes (see below).
Controller: Processes actions required to create a valid response (db operations etc.)
Processor: Manages asynch communication with the web page (itself)
IAsynchProcessor: The service processes instances that implement this interface
Sevice: Processes request objects that implement IAsynchProcessor
Request: The IAsynchProcessor wrapper containing your response (object)
Response: Contains custom objects or fields

This is a nice 5-minute screencast on how to do long polling using PHP & jQuery:
http://screenr.com/SNH
Code is quite similar to dbr's example above.

Here is a simple long-polling example in PHP by Erik Dubbelboer using the Content-type: multipart/x-mixed-replace header:
<?
header('Content-type: multipart/x-mixed-replace; boundary=endofsection');
// Keep in mind that the empty line is important to separate the headers
// from the content.
echo 'Content-type: text/plain
After 5 seconds this will go away and a cat will appear...
--endofsection
';
flush(); // Don't forget to flush the content to the browser.
sleep(5);
echo 'Content-type: image/jpg
';
$stream = fopen('cat.jpg', 'rb');
fpassthru($stream);
fclose($stream);
echo '
--endofsection
';
And here is a demo:
http://dubbelboer.com/multipart.php

I used this to get to grips with Comet, I have also set up Comet using the Java Glassfish server and found lots of other examples by subscribing to cometdaily.com

Take a look at this blog post which has code for a simple chat app in Python/Django/gevent.

Below is a long polling solution I have developed for Inform8 Web. Basically you override the class and implement the loadData method. When the loadData returns a value or the operation times out it will print the result and return.
If the processing of your script may take longer than 30 seconds you may need to alter the set_time_limit() call to something longer.
Apache 2.0 license. Latest version on github
https://github.com/ryanhend/Inform8/blob/master/Inform8-web/src/config/lib/Inform8/longpoll/LongPoller.php
Ryan
abstract class LongPoller {
protected $sleepTime = 5;
protected $timeoutTime = 30;
function __construct() {
}
function setTimeout($timeout) {
$this->timeoutTime = $timeout;
}
function setSleep($sleep) {
$this->sleepTime = $sleepTime;
}
public function run() {
$data = NULL;
$timeout = 0;
set_time_limit($this->timeoutTime + $this->sleepTime + 15);
//Query database for data
while($data == NULL && $timeout < $this->timeoutTime) {
$data = $this->loadData();
if($data == NULL){
//No new orders, flush to notify php still alive
flush();
//Wait for new Messages
sleep($this->sleepTime);
$timeout += $this->sleepTime;
}else{
echo $data;
flush();
}
}
}
protected abstract function loadData();
}

This is one of the scenarios that PHP is a very bad choice for. As previously mentioned, you can tie up all of your Apache workers very quickly doing something like this. PHP is built for start, execute, stop. It's not built for start, wait...execute, stop. You'll bog down your server very quickly and find that you have incredible scaling problems.
That said, you can still do this with PHP and have it not kill your server using the nginx HttpPushStreamModule: http://wiki.nginx.org/HttpPushStreamModule
You setup nginx in front of Apache (or whatever else) and it will take care of holding open the concurrent connections. You just respond with payload by sending data to an internal address which you could do with a background job or just have the messages fired off to people that were waiting whenever the new requests come in. This keeps PHP processes from sitting open during long polling.
This is not exclusive to PHP and can be done using nginx with any backend language. The concurrent open connections load is equal to Node.js so the biggest perk is that it gets you out of NEEDING Node for something like this.
You see a lot of other people mentioning other language libraries for accomplishing long polling and that's with good reason. PHP is just not well built for this type of behavior naturally.

Thanks for the code, dbr. Just a small typo in long_poller.htm around the line
1000 /* ..after 1 seconds */
I think it should be
"1000"); /* ..after 1 seconds */
for it to work.
For those interested, I tried a Django equivalent. Start a new Django project, say lp for long polling:
django-admin.py startproject lp
Call the app msgsrv for message server:
python manage.py startapp msgsrv
Add the following lines to settings.py to have a templates directory:
import os.path
PROJECT_DIR = os.path.dirname(__file__)
TEMPLATE_DIRS = (
os.path.join(PROJECT_DIR, 'templates'),
)
Define your URL patterns in urls.py as such:
from django.views.generic.simple import direct_to_template
from lp.msgsrv.views import retmsg
urlpatterns = patterns('',
(r'^msgsrv\.php$', retmsg),
(r'^long_poller\.htm$', direct_to_template, {'template': 'long_poller.htm'}),
)
And msgsrv/views.py should look like:
from random import randint
from time import sleep
from django.http import HttpResponse, HttpResponseNotFound
def retmsg(request):
if randint(1,3) == 1:
return HttpResponseNotFound('<h1>Page not found</h1>')
else:
sleep(randint(2,10))
return HttpResponse('Hi! Have a random number: %s' % str(randint(1,10)))
Lastly, templates/long_poller.htm should be the same as above with typo corrected. Hope this helps.

Why not consider the web sockets instead of long polling? They are much efficient and easy to setup. However they are supported only in modern browsers. Here is a quick reference.

The WS-I group published something called "Reliable Secure Profile" that has a Glass Fish and .NET implementation that apparently inter-operate well.
With any luck there is a Javascript implementation out there as well.
There is also a Silverlight implementation that uses HTTP Duplex. You can connect javascript to the Silverlight object to get callbacks when a push occurs.
There are also commercial paid versions as well.

For a ASP.NET MVC implementation, look at SignalR which is available on NuGet.. note that the NuGet is often out of date from the Git source which gets very frequent commits.
Read more about SignalR on a blog on by Scott Hanselman

You can try icomet(https://github.com/ideawu/icomet), a C1000K C++ comet server built with libevent. icomet also provides a JavaScript library, it is easy to use as simple as
var comet = new iComet({
sign_url: 'http://' + app_host + '/sign?obj=' + obj,
sub_url: 'http://' + icomet_host + '/sub',
callback: function(msg){
// on server push
alert(msg.content);
}
});
icomet supports a wide range of Browsers and OSes, including Safari(iOS, Mac), IEs(Windows), Firefox, Chrome, etc.

Simplest NodeJS
const http = require('http');
const server = http.createServer((req, res) => {
SomeVeryLongAction(res);
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.listen(8000);
// the long running task - simplified to setTimeout here
// but can be async, wait from websocket service - whatever really
function SomeVeryLongAction(response) {
setTimeout(response.end, 10000);
}
Production wise scenario in Express for exmaple you would get response in the middleware. Do you what you need to do, can scope out all of the long polled methods to Map or something (that is visible to other flows), and invoke <Response> response.end() whenever you are ready. There is nothing special about long polled connections. Rest is just how you normally structure your application.
If you dont know what i mean by scoping out, this should give you idea
const http = require('http');
var responsesArray = [];
const server = http.createServer((req, res) => {
// not dealing with connection
// put it on stack (array in this case)
responsesArray.push(res);
// end this is where normal api flow ends
});
server.on('clientError', (err, socket) => {
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
// and eventually when we are ready to resolve
// that if is there just to ensure you actually
// called endpoint before the timeout kicks in
function SomeVeryLongAction() {
if ( responsesArray.length ) {
let localResponse = responsesArray.shift();
localResponse.end();
}
}
// simulate some action out of endpoint flow
setTimeout(SomeVeryLongAction, 10000);
server.listen(8000);
As you see, you could really respond to all connections, one, do whatever you want. There is id for every request so you should be able to use map and access specific out of api call.

Related

PHP: Longpolling & Comet related

Recently, I am going to make a instant-notification system for my website. I heard COMET is an essential in such cases.
I have been searching about PHP & Comet for a while already, however, the guides & articles I have found seems like just ajax requests in a loop. For example, there is a basic javascript code which gets the value from PHP file every 2 seconds and outputs to HTML. As far as I know, it should be COMET pushing new values to HTML, hence, the loop should be on server side, not client. Half of the articles in my native language was using setInterval() and contact PHP file every X seconds.
So, I have some questions to ask you.
Is there any guides or examples, which doesn't use any external framework like XAJAX/NOLOH that is easy to understand?
What is the performance difference between using COMET in server side, or requesting value from ajax.php every X seconds?
The timed requests I mentioned above can be called as COMET? (ex. Long Polling using jQuery and PHP)
Do I need any extensions to run COMET serverside? (My webhost is using Apache, I personally use Nginx)
You have to use a client-side script (AJAX), because the server has to be polled. The server cannot simply send messages to someone's browser without an open connection.
I'm not too familiar with HTML5 websockets, but I believe this allows you can have a persistent connection with the server, however HTML5 browsers aren't used widely to use this as a solution on a 'public' website.
How long polling works is that an asynchronous request is sent from the browser with a long time-out time (e.g. 30 seconds), when the request arrives at the server, it goes and checks for new messages, but when there are now messages to be displayed, instead of directly outputting the result, it goes into an infinite loop, polling the database e.g. every second (using sleep to postpone the queries), until a message has been found. When a message has been found it terminates the loop and outputs the result. If there have been no messages after 30 seconds, the script times out and sends back an empty request.
So the request can be sent back between 0 and 30 seconds. As soon as the request arrives in the browser, it is handled and a new 30 second request is sent.
As for your questions;
You will need a client-side framework for doing the polling
You cannot use Comet only on server-side. Using longpolling over normal polling (e.g. polling every second) is significant because you make much less server requests
To my understanding; yes
You can use any server-side language, as long as it can keep the connection open while querying for messages.
Also take a look at http://nodejs.org/
I don't know what exactly COMMET is mean. But for this purpose you have many solutions.
One, as you mentioned is long-polling by ajax. is simple. and not requeire new browsers only (HtML5).
One more option is "server-sent -event". It's require browser with HTML5 but it keep connection alive without polling:
client:
if (window.EventSource) {
window.onload = function() {
window.scrollTo(0,1);
setTimeout(
function() {
var source = new EventSource("events.php");
source.onmessage = function (event) {
document.body.innerHTML += event.data + "<br>";
};
}, 1000);
};
} else {
document.write("Please visit this page in a browser that supports EventSource to see the test");
}
server:
if ($_SERVER['HTTP_ACCEPT'] === 'text/event-stream') {
header('Content-Type: text/event-stream');
echo "data: This is the first event\n\n";
flush();
$i = 5;
while (--$i) {
sleep(1);
$time = date('r');
echo "data: The server time is: {$time}\n\n";
flush();
}
} else {
echo 'This demo is for use with an EventSource compatible browser.';
}
goodluck.

Pushing data across browsers (same session)

I've seen pages like facebook where, if you post a message in your newsfeed, it automatically pushes that across your browsers. Or like on this page... if someone has answered a question while you are typing, a bar drops down.
Are they just calling AJAX requests every 30 seconds or whatever? It seems like that would be a resource drain on your server. Is there a way to push something at the browser instead?
There are 3 options here:
Use the new (experimental) browser API (sockets)
Long polling / comet
Using / listening to cookies
Long polling / comet example in PHP / AJAX
// PHP SIDE
$max_wait_time = 30; // at most, 30 seconds
$start_time = microtime(true);
while( $start_time - microtime(true) < $max_wait_time ){
// ...check if something changed (eg, run an SQL query or something)
if($something_changed){
echo 'something changed';
die;
}
// if the user did abort, terminate immediately
if( connection_aborted() ) die;
// sleep for one second. For faster responses, keep
// splitting this suitably (eg, 0.5 of a second...)
usleep(1000000);
}
// JS SIDE
var poll = function(){
jQuery.get('the url', function(){
poll();
});
}
poll();
Cookie example in PHP / JS (you need the jQuery cookie plugin)
<?php
// PHP SIDE
setcookie('test', mt_rand(0,100));
?><!-- HTML/JS SIDE -->
Rand!
Rand=<span><?php echo $_COOKIE['test']; ?></span>
<script type="text/javascript">
var oldrand = <?php echo $_COOKIE['test']; ?>;
setInterval(function(){
var newrand = jQuery.cookie('test');
if( newrand!=oldrand ){
jQuery('span').html(newrand);
oldrand = newrand;
}
}, 500);
</script>
The cookie one is pretty good for several reasons:
it is pretty fast (no AJAX calls)
it is less resource intensive on both client and server side
it consumes less bandwidth / network resources
it is much easier to control
In some cases where cookies cannot work, I'd still advocate the use of cookies as a signal to run an AJAX call, hence you wouldn't need to run a lot of AJAX calls just to wait for a change to happen.
On the other hand, the cookie one won't work when the change is happening by a third party, eg, it won't be suitable at all for chat systems.
Read into the differences between push and pull for more information:
In your example, the AJAX requests every 30 seconds would be a pull request - constantly asking the server if any updates are available, followed by a response.
You can set up a server/website to send push notifications to the client browser - whereby the client sits quietly, and the server sends the data/information to the client as soon as it is available (reducing network traffic etc.).
Push is much better in my opinion.
Yep, you'd have to poll with a looping Ajax script. To keep resource drain down, you might want to send some kind of hash (the timestamp of the last news item for instance) so the server knows if the client is up to date. This way, it can instantly return if there's no changes to push.

How to implement a chat room using Jquery/PHP?

I'm looking to implement a chat room using PHP/Javascript (Jquery) with both group chat and private chat features.
The problem is how to continually update the interface in a natural way and possibly also how to show 'X is typing..' messages in private chat.
The obvious way seems to be that every X seconds/milliseconds the javascript pings the server and fetches a list of new messages between the last ping and now. However, this can make the interface seem a bit unnatural, if suddenly the chat room is flooded with 5 messages. I would rather each message appear as it is typed.
Is there a way for javascript to maintain a continuous connection to the server, the server pushes any new messages to this connection, and javascript adds them to the interface so they appear simultaneously, almost as soon as the server receives them?
I know there are some polling options that require you to install some apache modules etc, but I'm pretty bad of a sysadmin, therefore I'd prefer if there was a very easy to install solution on a shared hosting account, or a php/mysql only solution.
Chat with PHP/AJAX/JSON
I used this book/tutorial to write my chat application:
AJAX and PHP: Building Responsive Web Applications: Chapter 5: AJAX chat and JSON.
It shows how to write a complete chat script from scratch.
Comet based chat
You can also use Comet with PHP.
From: zeitoun:
Comet enables web servers to send data to the client without having any need for the client to request it. Therefor, this technique will produce more responsive applications than classic AJAX. In classic AJAX applications, web browser (client) cannot be notified in real time that the server data model has changed. The user must create a request (for example by clicking on a link) or a periodic AJAX request must happen in order to get new data fro the server.
I'll show you two ways to implement Comet with PHP. For example:
based on hidden <iframe> using server timestamp
based on a classic AJAX non-returning request
The first shows the server date in real time on the clients, the displays a mini-chat.
Method 1: iframe + server timestamp
You need:
a backend PHP script to handle the persistent http request backend.php
a frondend HTML script load Javascript code index.html
the prototype JS library, but you can also use jQuery
The backend script (backend.php) will do an infinite loop and will return the server time as long as the client is connected.
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sun, 5 Mar 2012 05:00:00 GMT");
flush();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet php backend</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<script type="text/javascript">
// KHTML browser don't share javascripts between iframes
var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
if (is_khtml)
{
var prototypejs = document.createElement('script');
prototypejs.setAttribute('type','text/javascript');
prototypejs.setAttribute('src','prototype.js');
var head = document.getElementsByTagName('head');
head[0].appendChild(prototypejs);
}
// load the comet object
var comet = window.parent.comet;
</script>
<?php
while(1) {
echo '<script type="text/javascript">';
echo 'comet.printServerTime('.time().');';
echo '</script>';
flush(); // used to send the echoed data to the client
sleep(1); // a little break to unload the server CPU
}
?>
</body>
</html>
The frontend script (index.html) creates a "comet" javascript object that will connect the backend script to the time container tag.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="prototype.js"></script>
</head>
<body>
<div id="content">The server time will be shown here</div>
<script type="text/javascript">
var comet = {
connection : false,
iframediv : false,
initialize: function() {
if (navigator.appVersion.indexOf("MSIE") != -1) {
// For IE browsers
comet.connection = new ActiveXObject("htmlfile");
comet.connection.open();
comet.connection.write("<html>");
comet.connection.write("<script>document.domain = '"+document.domain+"'");
comet.connection.write("</html>");
comet.connection.close();
comet.iframediv = comet.connection.createElement("div");
comet.connection.appendChild(comet.iframediv);
comet.connection.parentWindow.comet = comet;
comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.php'></iframe>";
} else if (navigator.appVersion.indexOf("KHTML") != -1) {
// for KHTML browsers
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id', 'comet_iframe');
comet.connection.setAttribute('src', './backend.php');
with (comet.connection.style) {
position = "absolute";
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
}
document.body.appendChild(comet.connection);
} else {
// For other browser (Firefox...)
comet.connection = document.createElement('iframe');
comet.connection.setAttribute('id', 'comet_iframe');
with (comet.connection.style) {
left = top = "-100px";
height = width = "1px";
visibility = "hidden";
display = 'none';
}
comet.iframediv = document.createElement('iframe');
comet.iframediv.setAttribute('src', './backend.php');
comet.connection.appendChild(comet.iframediv);
document.body.appendChild(comet.connection);
}
},
// this function will be called from backend.php
printServerTime: function (time) {
$('content').innerHTML = time;
},
onUnload: function() {
if (comet.connection) {
comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
}
}
}
Event.observe(window, "load", comet.initialize);
Event.observe(window, "unload", comet.onUnload);
</script>
</body>
</html>
Method 2: AJAX non-returning request
You need the same as in method 1 + a file for dataexchange (data.txt)
Now, backend.php will do 2 things:
Write into "data.txt" when new messages are sent
Do an infinite loop as long as "data.txt" file is unchanged
<?php
$filename = dirname(__FILE__).'/data.txt';
// store new message in the file
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
if ($msg != '')
{
file_put_contents($filename,$msg);
die();
}
// infinite loop until the data file is not modified
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif) // check if the data file has been modified
{
usleep(10000); // sleep 10ms to unload the CPU
clearstatcache();
$currentmodif = filemtime($filename);
}
// return a json array
$response = array();
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
flush();
?>
The frontend script (index.html) creates the <div id="content"></div> tags hat will contains the chat messages comming from "data.txt" file, and finally it create a "comet" javascript object that will call the backend script in order to watch for new chat messages.
The comet object will send AJAX requests each time a new message has been received and each time a new message is posted. The persistent connection is only used to watch for new messages. A timestamp url parameter is used to identify the last requested message, so that the server will return only when the "data.txt" timestamp is newer that the client timestamp.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Comet demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="prototype.js"></script>
</head>
<body>
<div id="content">
</div>
<p>
<form action="" method="get" onsubmit="comet.doRequest($('word').value);$('word').value='';return false;">
<input type="text" name="word" id="word" value="" />
<input type="submit" name="submit" value="Send" />
</form>
</p>
<script type="text/javascript">
var Comet = Class.create();
Comet.prototype = {
timestamp: 0,
url: './backend.php',
noerror: true,
initialize: function() { },
connect: function()
{
this.ajax = new Ajax.Request(this.url, {
method: 'get',
parameters: { 'timestamp' : this.timestamp },
onSuccess: function(transport) {
// handle the server response
var response = transport.responseText.evalJSON();
this.comet.timestamp = response['timestamp'];
this.comet.handleResponse(response);
this.comet.noerror = true;
},
onComplete: function(transport) {
// send a new ajax request when this request is finished
if (!this.comet.noerror)
// if a connection problem occurs, try to reconnect each 5 seconds
setTimeout(function(){ comet.connect() }, 5000);
else
this.comet.connect();
this.comet.noerror = false;
}
});
this.ajax.comet = this;
},
disconnect: function()
{
},
handleResponse: function(response)
{
$('content').innerHTML += '<div>' + response['msg'] + '</div>';
},
doRequest: function(request)
{
new Ajax.Request(this.url, {
method: 'get',
parameters: { 'msg' : request
});
}
}
var comet = new Comet();
comet.connect();
</script>
</body>
</html>
Alternatively
You can also have a look at other chat applications to see how they did it:
http://hot-things.net/?q=blite - BlaB! Lite is an AJAX based and best viewed with any browser chat system that supports MySQL, SQLite & PostgreSQL databases.
Gmail/Facebook Style jQuery Chat - This jQuery chat module enables you to seamlessly integrate Gmail/Facebook style chat into your existing website.
Writing a JavaScript/PHP Chat Server - A tutorial
CometChat - CometChat runs on standard shared servers. Only PHP + mySQL required.
Polling is not a good idea. You need a solution that use long polling or web sockets.
http://hookbox.org is probably the best tool you can use.
It is a box that lives between the server and the browsers and manages abstractions called channels (think about an IRC channel). It is open source on github: https://github.com/hookbox/hookbox The box is written in Python but it can easily be used with a server written in any language. It also come with a Javascript library that is built on jsio (uses websockets, long-polling, or whatever is the best technology available on the browser) that guarantee that it uses the best technology available in the browsers.In a demo I saw a realtime chat implemented with few line of code.
Hookbox’s purpose is to ease the development of real-time web applications, with an emphasis on tight integration with existing web technology. Put simply, Hookbox is a web-enabled message queue. Browers may directly connect to Hookbox, subscribe to named channels, and publish and receive messages on those channels in real-time. An external application (typically the web application itself) may also publish messages to channels by means of the Hookbox REST interface. All authentication and authorization is performed by an external web application via designated “webhook” callbacks.
Any time a user connects or operates on a channel, ( subscribe, publish, unsubscribe) Hookbox makes an http request to the web application for authorization for the action. Once subscribed to a channel, the user’s browser will receive real-time events that originate either in another browser via the javascript api, or from the web application via the REST api.
They key insight is that all application development with hookbox Happens either in javascript, or in the native language of the web application itself (e.g. PHP.)
You need a server that can run Python BUT you do NOT have to know Python.
If instead you want to use just websockets and PHP this is good starting point: http://blancer.com/tutorials/69066/start-using-html5-websockets-today/
Have you looked at PHPDaemon, which is written with active usage of libevent and pnctl? It has lots of features and even simple chat demo application. Even it has some production implementations.
this could be a good starting point
http://css-tricks.com/jquery-php-chat/
I suggest to implement it with HTML5 WebSockets, with long polling or comet as a fallback for older browsers. WebSockets open a persistent connection to the browser.
There is an open source php implementation of a websocket server.
I suggest you to try Socket.IO together with NodeJS. Socket.IO gives you a nice and very easy client API, works on most modern browsers and uses appropriate transport where possible (Websocket, long polling, etc). NodeJS is a server-side daemon, which holds HTTP connections. Official site of the Socket.IO contains information on how to use them together. Hope it will help you.
I believe the problem you are looking at requires the use of comet web programming. You can find more details on wikipedia, by searching for Comet programming, and on Ajaxian (I'm still new to this site and I can't post more than 1 link in the response).
The problem is that this can't be easily achieved with php on the server side. More details:
using comet with php
Also, if you search on google for 'php comet' you'll find a tutorial to achieve the desired effect.
LATER EDIT
Ape project
Implemented a project using this engine. Is great.
Comet with php
Hope this helps,
Gabriel
This looks promising! Might even be super easy to restyle :)
http://www.php-development.ru/javascripts/ajax-chat.php
Ajax Chat script in Javascript/PHP
Description
Ajax Chat is a light-weight customizable web chat software implemented in JavaScript and PHP. The script does not require Java, Flash, or any other plugins.
Features
Public and private chat.
Login as a registered user or as a guest.
Away status, custom colors, smileys, user gender/status icons.
Ajax Chat can be integrated with a third-party membership system by implementing user authentication routine. Advanced integration options: if user is logged in to the website, he can be logged in to the chat automatically.
*Please note that this is a copy/paste from the original site.
I haven't done it with PHP before but you're best bet would probably be some kind of socket connection. Here's the PHP manual for sockets.
I don't remember who's tutorial it was but I made a chat room like what you want using Flash for the client and Java for the server. I think this link might be where the tutorial was and it may help you out.

Getting PHP from node.js

I am working on using node.js's connection abilities to continiously long poll a php script and I was wondering if anyone knows the thoery behind (maybe even a code sample) linking to php in node.js? I was thinking I need a new client and I add a request for the php page and then I add a response event listener which then fires off a event function which grabs the returned data and throws it back into the server function.
I am, however, a noob and need some initial guidance since their api documentation is not the easiest to read; the English is too wordy and it's white font on a dark background...not nice.
Thanks,
var sys = require('sys'),
http = require('http'),
url = require("url"),
path = require("path"),
events = require("events");
var twitter_client = http.createClient(80, "192.168.23.128");
var tweet_emitter = new events.EventEmitter();
function get_tweets() {
var request = twitter_client.request("GET", "/?url=ajax/session", {"host": "192.168.23.128"});
request.addListener("response", function(response) {
var body = "";
response.addListener("data", function(data) {
body += data;
});
response.addListener("end", function() {
sys.puts(body);
var tweets = JSON.parse(body);
if(tweets.length > 0) {
tweet_emitter.emit("tweets", tweets);
}
});
});
request.end();
}
setInterval(get_tweets, 5000);
http.createServer(function (req, res) {
sys.puts("accessed Server");
res.writeHead(200, {'Content-Type': 'text/plain', "Access-Control-Allow-Origin": "*"});
var t = JSON.stringify({id:"test"});
var listener = tweet_emitter.addListener("tweets", function(tweets) {
res.write(tweets);
});
res.write(t);
res.end();
}).listen(8124);
sys.puts('Server running at http://127.0.0.1:8124/');
This seemed to work. Taken from a mixture of other tutorials
Was just doing some research on this topic, and wanted to drop in an answer for anyone that might be looking to do the same thing.
The comments on the OP made good points as to whether or not this sort of thing would be an efficient use of resources, or a waste of nodes event-based processing abilities. I would say that passing requests on to an Apache/PHP server would be inefficient, because you're essentially doing the same thing as having recurring AJAX request sent to the Apache server. The only difference is you now have a man-in-the-middle sending the requests.
Apache is still serving requests just the same as it always is, it is just serving them to the Node.js server rather than the client. This does not build in any efficiencies, other than taking a bit of load off the client and placing it on the server.
The correct way to do this, as #Paul mentioned, is to use some sort of PHP processor that will allow you to bypass Apache. There's some fancy methods for getting this done using FastCGI and PHP-FPM - they're pretty high level so you might have some trouble integrating them into Node.js on your own.
On the bright side, there's a node module already being built to do just this: node-php. It's pretty young ("omega-alpha-super-beta-proof-of-concept"), but may be able to handle what you're trying to do. If it can't, at least it's a good starting point, and you can fork off to make your own additions

Chat application AJAX polling

In the project I am currently working on, we have the need to develop a web chat application, not a very complex chat, just a way to connect two people to talk about a very specific topic, we don't need any kind of authentication for one of the two users, we don't have to support emoticons, avatars, or stuff like that.
Some project members suggested that we could use XMPP through BOSH, I said that is like trying to catch a fish with a boat's net, and proposed a simpler method, like a simple Ajax/MySQL web chat, but we're worried about the performance hit in the server because of the constant polling of many chats open at the same time.
Has anyone done something like this before? What would you recommend?
You might also want to look into Comet.
It's used by GTalk, Meebo, and many other chat applications. A few years ago when I was experimenting with it, there weren't very many libraries or details about server architecture to implement it, but it looks like there is a lot more stuff out now.
Have a look at the cometd project for more technical information.
What would you recommend?
XMPP through BOSH
There's no need to invent your own message format and transport protocol when somebody else has. If you try, it'll slowly grow to be just as complex as BOSH but without the benefit of third-party library support or standardization.
If you don't like the idea of HTTP-polling, you could have a Flash-movie on the chat page that has a constant connection to some deamon on the server, the Flash-movie would then invoke JavaScript functions on the client to update the chat as new messages comes along. (Unless you want a Flash interface for your chat..)
You might also want to look into Comet.
I thought everyone used cometd for this sort of thing.
BOSH is a standard for transporting XMPP over HTTP. It involves Comet for pushing data to the client.
There is a very good server for handling message pushing from server to browser (dubbed Comet) - Orbited. It's easily integrated with other technologies (Django, Rails, PHP etc.) just like memcached.
You really should check it if you want to handle serious load. Otherwise, simple Ajax polling is the best way.
The trick is to realise that the only time your app needs to invoke CGI on the server is when someone says something. For the regular polls, poll a static page that your CGI script updates whenever there is new chat. Use HEAD requests, compare the timestamps with those last seen, and only do a full GET when those change. I have a simple naive chat application implemented this way, and the load and bandwidth usage is negligible for the few tens of simultaneous users we have.
I did this very same thing a few months back and had fun just playing around with the concepts. I actually used the forever-frame technique instead of polling.
The below code is my "comet" js file that contains the general concepts required to get a "party chat" setup.
function Comet(key) {
var random = key;
var title = 'Comet';
var connection = false;
var iframediv = false;
var browserIsIE = /*#cc_on!#*/false;
var blurStatus = false;
var tmpframe = document.createElement('iframe');
var nl = '\r\n';
this.initialize = function() {
if (browserIsIE) {
connection = new ActiveXObject("htmlfile");
connection.open();
connection.write("<html>");
connection.write("<script>document.domain = '"+document.domain+"'");
connection.write("</html>");
connection.close();
iframediv = connection.createElement("div");
connection.appendChild(iframediv);
connection.parentWindow.comet = comet;
iframediv.innerHTML = "<iframe id='comet_iframe' src='./comet.aspx?key="+random+"'></iframe>";
} else {
connection = document.createElement('iframe');
connection.setAttribute('id', 'comet_iframe');
iframediv = document.createElement('iframe');
iframediv.setAttribute('src', './comet.aspx?key='+random);
connection.appendChild(iframediv);
document.body.appendChild(connection);
}
}
// this function is called from the server to keep the connection alive
this.keepAlive = function () {
if (!browserIsIE) {
mozillaHack();
}
}
// this function is called from the server to update the client
this.updateClient = function (value) {
var outputDiv = document.getElementById('output');
outputDiv.value = value + nl + outputDiv.value;
if (blurStatus == true) {
document.title = value;
}
if (!browserIsIE) {
mozillaHack();
}
}
this.onUnload = function() {
if (connection) {
// this will release the iframe to prevent problems with IE when reloading the page
connection = false;
}
}
this.toggleBlurStatus = function(bool) {
blurStatus = bool;
}
this.resetTitle = function() {
document.title = title;
}
function mozillaHack() {
// this hack will fix the hour glass and loading status for Mozilla browsers
document.body.appendChild(tmpframe);
document.body.removeChild(tmpframe);
}
}
I thought everyone used cometd for this sort of thing.
I agree with John. But there was another question that was not answered.
I have done this but instead of using a database we used a flat file, it did eventually cripple the server, but it wasn't until we has ~450 active users, and if we had done it with a database it probably would have fared better.This was done on a basic hosting account from Godaddy.
Edit: BTW Godaddy sounded less then amused when I got the phone call.
I think polling is the simplest approach and would recommend that first. If the load becomes a problem start, looking into more complicated techniques.
A good discussion on the pros and cons are here -
http://www.infoq.com/news/2007/07/pushvspull
http://ajaxian.com/archives/a-report-on-push-versus-pull
Checkout Speeqe. Its a open-source solution for Web-based chat rooms that uses BOSH and XMPP behind the scenes.
I just found this post, it is old, but polling concept gives troubles for a lot of poeple. So i'll put an implementation example here. But before giving it to you, I should give you an advice that made me mad some time ago :
When you poll, you should take care of sessions behaviour (race conditions). To make it simple : if you open a session, the session file is locked until the session is closed to avoid 2 theads writting different data into it. So, if you need a session to check if a user is logged or so, always close the session before polling.
My demo gives you an example of a polling implementation in PHP. I will not use a database, but a file instead. When you click polling button, you will enter the loop and until the file is modified, you will stay polling. When you fill the form and click Release, what you typed will be saved into the file. Modification time of the file will change so the polling will stop.
Tip: use a tool like Firebug to see what's happen.
Now lets speak in a better langage than my english :
<?php
// For this demo
if (file_exists('poll.txt') == false) {
file_put_contents('poll.txt', '');
}
if (isset($_GET['poll'])) {
// Don't forget to change the default time limit
set_time_limit(120);
date_default_timezone_set('Europe/Paris');
$time = time();
// We loop until you click on the "release" button...
$poll = true;
$number_of_tries = 1;
while ($poll)
{
// Here we simulate a request (last mtime of file could be a creation/update_date field on a base)
clearstatcache();
$mtime = filemtime('poll.txt');
if ($mtime > $time) {
$result = htmlentities(file_get_contents('poll.txt'));
$poll = false;
}
// Of course, else your polling will kill your resources!
$number_of_tries++;
sleep(1);
}
// Outputs result
echo "Number of tries : {$number_of_tries}<br/>{$result}";
die();
}
// Here we catch the release form
if (isset($_GET['release']))
{
$data = '';
if (isset($_GET['data'])) {
$data = $_GET['data'];
}
file_put_contents('poll.txt', $data);
die();
}
?>
<!-- click this button to begin long-polling -->
<input id="poll" type="button" value="Click me to start polling" />
<br/><br/>
Give me some text here :
<br/>
<input id="data" type="text" />
<br/>
<!-- click this button to release long-polling -->
<input id="release" type="button" value="Click me to release polling" disabled="disabled" />
<br/><br/>
Result after releasing polling :
<div id="result"></div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
// Script to launch polling
$('#poll').click(function() {
$('#poll').attr('disabled', 'disabled');
$('#release').removeAttr('disabled');
$.ajax({
url: 'poll.php',
data: {
poll: 'yes' // sets our $_GET['poll']
},
success: function(data) {
$('#result').html(data);
$('#poll').removeAttr('disabled');
$('#release').attr('disabled', 'disabled');
}
});
});
// Script to release polling
$('#release').click(function() {
$.ajax({
url: 'poll.php',
data: {
release: 'yes', // sets our $_GET['release']
data: $('#data').val() // sets our $_GET['data']
}
});
});
</script>
You can try it here

Categories