Comet es una técnica de programación que permite a los servidores web enviar datos al cliente sin ninguna necesidad de que éste lo solicite. En aplicaciones AJAX ocurre lo contrario, el cliente (el navegador web) no puede ser notificado en tiempo real por el servidor si se han producido cambios en éste. Es el usuario quien deberá realizar la petición, quizás haciendo clic en un vinculo, botón ó mediante una solicitud periódica a fin de obtener datos del servidor.

En está oportunidad vamos aplicar Comet con PHP y Prototype. Nos basaremos en un iframe oculto. El objetivo es que el cliente no pida al servidor, sino que el servidor envie datos al cliente.

El servidor nos retornará la hora UNIX

  • Necesitaremos un script en PHP que se encargará de la petición HTTP persistente (backend.php).
  • Un archivo HTML, donde irá el código JavaScript necesario y donde mostraremos los datos procedementes del servidor (index.html).
  • La librería Prototype (y un poquito de conocimiento de está librería).

El archivo backend.php

El script backend.php, hará un bucle infinito y devolverá la hora UNIX siempre y cuando el cliente esté conectado.

<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
flush();
//flush -> vacia el búfer de salida de PHP y ademas envia todo lo escrito (echo, print, ect) al navegador 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 php backend</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

<script type="text/javascript">
//Navegadores KHTML no compartes javascripts entre 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);
}
// cargamos objeto comet (esto en realidad es el nombre del iframe)
var comet = window.parent.comet;
</script>

<?php
while(1) { // while (1) permite un bucle infinito
echo '<script type="text/javascript">';
echo 'comet.printServerTime('.time().');';
echo '</script>';
flush();
sleep(1); // un descanso para aliviar el CPU del servidor
}
?>
</body>
</html>

El archivo index.html

Este documento HTML cargará la librería Prototype dentro de las etiquetas <head>, también creamos dentro de <body> un contenedor donde se mostrará el resultado de la petición al servidor, ó sea la hora UNIX: <div id="content"> </div>, y finalmente se creará el objeto Comet que se conectará a nuestro archivo PHP.

El objeto Coment crea etiquetas <iframe> invisibles (esto quizás varie en algunos navegadores). Estos iframes se encargarán de crear el "terreno" (por así decirlo) para la conexión HTTP persistente al archivo/script PHP.

<!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">La hora del servidor se mostrará aqui</div>

<script type="text/javascript">
var comet = {
connection : false,
iframediv : false,

initialize: function() {
if (navigator.appVersion.indexOf("MSIE") != -1) {

// Para navegadores IE
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) {

// Para navegadores KHTML
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 {

// Para otros navegadores (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);

}
},
// esta función será llamada desde backend.php
printServerTime: function (time) {
$('content').innerHTML = time;
},
onUnload: function() {
if (comet.connection) {
comet.connection = false; // se eliminará el iframe para prevenir problemas con IE cuando se recargue la pagina.
}
}
}
Event.observe(window, "load", comet.initialize);
Event.observe(window, "unload", comet.onUnload);
</script>

</body>
</html>

En resumen, mediante JavaScript/Protype creamos en iframe donde aparecerá el contenido generado por backend.php, es este archivo el que mantendrá la conexión abierta con el servidor creando así un canal donde el servidor sea quien envie datos al cliente, en este caso la hora UNIX. Veremos luego un segundo ejemplo y seguiremos explicando al respecto.