Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
183
rated 0 times [  186] [ 3]  / answers: 1 / hits: 34102  / 14 Years ago, sat, november 13, 2010, 12:00:00

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.


More From » php

 Answers
82

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:




  1. based on hidden <iframe> using server timestamp

  2. 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:




  1. Write into data.txt when new messages are sent

  2. 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:




[#94970] Thursday, November 11, 2010, 14 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
emilee

Total Points: 365
Total Questions: 113
Total Answers: 109

Location: Monaco
Member since Fri, Sep 24, 2021
3 Years ago
;