Creando un pequeño sistema de chat

Para esto necesitamos:

  • PHP >= 5.2.0 (incluye función json_encode por defecto)
  • Un archivo para el intercambio de datos – simple archivo de texto (datos.txt).
  • Un script PHP que se encargará de la petición HTTP persistente (peticion.php).
  • Un archivo HTML que cargue el código JavaScript y que muestre los mensajes/datos del servidor (index.html).
  • La biblioteca Prototype.

El script peticion.php

Este script hará dos cosas:

  • Escribir en el archivo datos.txt los nuevos mensajes que envie el cliente.
  • Hacer un bucle infinito siempre y cuando datos.txt no haya sido modificado.
<?php
// dirname -> parte del path correspondiente al directorio
$filename = dirname(__FILE__).'/datos.txt';

// almacenamos un nuevo mensajes en el archivo
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
if ($msg != ''){
//file_put_contents -> escribir una cadena sobre un archivo
file_put_contents($filename,$msg);
die();
}

// bucle infinito mientras los datos del archivo no son modificados
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;

//filemtime -> obtiene la hora de modificación del archivo
$currentmodif = filemtime($filename);
while($currentmodif <= $lastmodif){ // verificar si el archivo de datos ha sido modificado
usleep(10000); // hacemos descansar al CPU por 10ms

//clearstatcache -> limpia la cache de estado de un archivo
clearstatcache();
$currentmodif = filemtime($filename);
}

// devolvemos array en formato json
$response = array();

//file_get_contents -> lee un archivo entero en una cadena
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);

//flush -> vaciar el búfer de salida
flush();
?>

El archivo index.html

Este documento HTML cargará la librería Prototype dentro de las etiquetas <head>, luego en el cuerpo del documento (<body>) creamos un contenedor: <div id="content"></div>, donde se mostrarán los mensajes procedentes de datos.txt. Finalmente, se creará mediante JavaScript un objeto Comet que llamará al script peticion.php para ver los nuevos mensajes del chat.

El objeto comet enviará respuesta AJAX cada vez que un nuevo mensaje se ha recibido y cada vez que un nuevo mensaje se ha enviado. La conexión persistente es usado solo para ver los nuevos mensajes. Usamos un parámetro url (timestamp) para identificar el último mensaje, así el servidor devolverá el contenido de datos.txt solo cuando la fecha/hora de modificación sea mas reciente que la fecha/hora del cliente.

<!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="Enviar" />
</form>
</p>
<script type="text/javascript">
var Comet = Class.create();
Comet.prototype = {
timestamp: 0,
url: './peticion.php',
noerror: true,
initialize: function(){ },
connect: function(){
this.ajax = new Ajax.Request(this.url, {
method: 'get',
parameters: { 'timestamp' : this.timestamp },
onSuccess: function(transport) {
// manejamos la respuesta del servidor
var response = transport.responseText.evalJSON();
this.comet.timestamp = response['timestamp'];
this.comet.handleResponse(response);
this.comet.noerror = true;
},
onComplete: function(transport) {
// enviamos nueva petición ajax cuando esta haya finalizado
if (!this.comet.noerror)
// si conexión tuvo problemas, intentar reconectar cada 5 segundos
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>

Anteriormente hicimos un ejemplo de Chat con AJAX + PHP. Donde cada cierto tiempo el cliente pide al servidor información de nuevos mensajes. En esta oportunidad no es así, por que se mantiene una conexión persistente con el servidor de acuerdo a una condición. Eso si cuando se trata de conexiones persistente hay que darle descanso al servidor. Ahora si nosotros cambiamos el archivo datos.txt por una tabla en MySQL(… ó cualquier otro manejador de BD). Entonces debemos avergiuar sobre como mantener conexiones persistentes en base de datos. Que en realidad se puede, pero no es una configuración por defecto en los Hostings. Quizás de manera local podamos hacer pruebas y así tener una idea de como estás técnicas – que comunmente vemos implementadas en servicios como Meebo, Google Talk (web) y más – funcionan. 

Estos dos ejemplos mostrados fueron tomados de Zeitoun.net, los cuales modificamos y testeamos para poder darlo a conocer en nuestra querida lengua.

Fuente original: How to implement COMET with PHP