Tecnologias PUSH usando PHP

Escrito el 30 Enero, 2001 – 14:03 | por storm | 7.990 lecturas

Uno de los grandes problemas del protocolo HTTP es que no funciona en modo PUSH, quien no quiso hacer alguna vez un chat en PHP y se encontro con la desagradable tarea de refrescar el browser cada cierto tiempo. En un articulo sumamente interesante dos destacados gurues del desarrollo web explican como resolver el asunto en forma elegante ademas de ilustrarnos notablemente sobre los aspectos de fondo del tema.
World Domination Series:

Tecnologias PUSH usando PHP

Luis Argerich y Alejandro Mitrou
Aventureros del desarrollo web.

Que es PUSH

El protocolo HTTP establece la forma en la cual se hace practicamente todo en la web empezando por la forma en la cual interactuan web-servers y browsers. El "core" de HTTP establece que el cliente hace un "request" HTTP y el servidor responde con un "response".

Esta metodologia puede resultar muy util en un 90\% de las aplicaciones que pensemos pero puede ser tambien una pesadilla para otro tipo de aplicaciones, por ejemplo consideremos un chat realizado sobre http, cuando el usuario escribe algo la informacion se envia al server como un request http usando "post" para enviar el mensaje, el server puede guardar esto en una base de datos, en un archivo o donde prefiera. Pero que ocurre cuando otros usuarios ingresan un mensaje? El servidor deberia entonces actualizar el chat de todos los demas usuarios para que ls mismos vean los mensajes al tiempo en que los demas los escriben. La operacion por la cual el servidor actualiza el cliente sin un pedido expreso del mismo se lo denomina "PUSH".

Numerosas aplicaciones requieren que el servidor y el cliente funcionen en metodo push, los chats son un claro ejemplo pero hay mucho mas, un sistema de alertas, un sistema de pager, noticias actualizadas en el momento, sistemas de monitoreo de equipos o recursos criticos, etc etc etc.

Lamentablemente el metodo "PUSH" no es parte del protocolo HTTP, Netscape extendio su browser en la decada de los 90 agregando un header experimental HTTP que permitia al server y el browser trabajar en modo PUSH, esto funciono y hoy en dia puede programarse una aplicacion para browsers netscape que funcione de esta forma, lamentablemente no solo la extension no paso a ser parte del protcolo HTTP sino que Microsoft nunca la tuvo en cuenta para su browser por lo cual no es realmente una opcion a considerar hoy en dia.

Habiendo llegado a la conclusion de que el metodo "PUSH" puro no existe debemos considerar distintas alternativas para "emularlo" es decir aparentar que se trabaja en modo "PUSH" cuando en realidad esto no es asi. Le emulacion mas simple consiste en refrescar al browser cada un cierto periodo de tiempo de forma tal que el mismo "busque" informacion nueva a intervalos regulares. Esto puede hacerse en forma sencilla usando JavaScript o bien un meta-tag de refresh de la forma:

En JavaScript:
window.setInterval("location.reload()",5000);

Control dinamico del refresh

Afortunadamente en paginas generadas dinamicamente desde PHP el server puede generar tanto el codigo JavaScript como el meta-tag en forma dinamica por lo cual puede controlar la duracion del intervalo de refresh del browser y variar la misma de acuerdo a la situacion del servidor. En una aplicacion de chat por ejemplo el server puede variar el tiempo de refresh de los clientes en funcion de la cantidad de mensajes por segundo que recibe de forma tal de no refrescar constantemente a los clientes si esto no es necesario y que los mismos no pierdan actualizacion cuando hay muchos mensajes.

Haciendo efectivo el refresh

La emulacion por refresh falla malamente cuando el browser guarda una copia cacheada de la pagina en cuestion y se niega a refrescar la misma devolviendo el resultado del cache. Afortunadamente desde PHP puede controlarse que el browser no cachee la pagina haciendo uso de las siguientes directivas HTTP:

header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
header("Expires: Mon,26 Jul 1997 05:00:00 GMT");

Los headers anteriores funcionan tanto para Netscape como para explorer.

La principal desventaja de este mecanismo es que refrescar la pagina del browser suele traer las siguientes desventajas:

En primer lugar refrescar la pagina en el browser es desagradable para el usuario que ve que la pagina desaparece y vuelve a cargarse o bien que el browser "flashea" si la pagina es muy chica y se carga enseguida.

En segundo lugar porque es necesario regenerar toda la pagina cuando habitualmente solo se quiere actualizar una porcion de la misma?

Ocultando el refresh

La unica solucion a los dos problemas anteriores pasa por el uso de frames. La solucion mas inteligente al problema pasa por utilizar al menos 3 frames:

  • Un frame invisible (con size=0) que sea el que hacemos refrescar cada "x segundos" que se encarga de chequear si hay informacion nueva en el servidor.
  • Un frame visible donde mostramos la informacion "PUSH" y que refrescamos unicamente cuando efectivamente hay novedades en el servidor.
  • Un frame visible con toda la informacion estatica que no se refresca nunca, habitualmente es el frame mas pesado por lo cual es muy util no refrescarlo nunca.

El proceso es el siguiente:

  1. El frame invisible se recarga
  2. El frame invisible chequea por nuevos datos en el servidor
  3. Si no ha nuevos datos no hacer nada
  4. Si hay nuevos datos entonces refrescar el frame PUSH

El frame invisible puede facilmente refrescar otro frame usando JavaScript generando codigo de la forma "top.framepush.reload();". Como podran notar desde PHP generamos o no codigo JavaScript dependiendo del estado del server lo cual consituye un buen ejemplo de "programa que escribe programas" tema que ha resultado siempre muy atractivo para cualquier programador.

Manos a la obra.

Luego de que hemos establecido toda la teoria es hora de ver un ejemplo en accion, en este ejemplo vamos a construir una pagina que tiene un pequenio frame en donde se muestra el contenido de un archivo "new.txt" y que se actualiza unicamente cuando el archivo es modificado. Para chequear si el archivo fue o no modificado vamos a guardar un md5 del archivo en el frameset y luego cada vez que el frame invisible se refresca obtenemos en Php el nuevo md5 y generamos codigo Javascript que compara el md5 nuevo con el del frameset, si son iguales no hace nada, si son distintos entonces refresca el frame PUSH y ademas actualiza el md5 en el frameset. El codigo es el siguiente:

El frameset.

<script>
var newti;
var ti;
newti=0;
ti=0;
</script>

<frameset border="0" frameborder="0" rows="0,20,80">
<frame noresize scrolling="no" frameborder="0" name="loader" src="loader.php">
<frame noresize scrolling="no" frameborder="0" name="push" src="push.php">
<frame noresize scrolling="no" frameborder="0" name="static" src="static.php">
</frameset>

El frameset define los tres frames uno "loader" de tamanio cero que es invisible, uno "push" que tendra la informacion PUSH y uno "static" con la informacion estatica que querramos mostrar.

El frame loader.

<?
// Aqui verificar si el archivo ha cambiado
$newti=filemtime("./new.txt");
print("Newti: $newti");
?>
<script>
top.newti=<?print($newti);?>
if(top.newti==top.ti) {
top.newti=top.newti;
} else {
top.ti=top.newti;
if(top.push) {
top.push.location.reload();
}
}
</script>
<?
?>
<body onLoad="window.setInterval('location.reload()',3000);"> </body>

El frame loader se autorefresca cada 5 segundos usando JavaScript, ademas verifica usando PHP si ha cambiado o no el archivo news.txt tomando el md5 del mismo, setandolo en una variable JavaScript llamada "newmd5" y luego generando codigo JavaScript para proceder segun haya cambiado o no el archivo.

El frame PUSH.

Noticias
<?
$fil=fopen("./new.txt","r");
$data=fread($fil,filesize("./new.txt"));
fclose($fil);
print("<p>$data</p>");
?>

El frame push simplemente cada vez que se carga (lo decide el loader) toma la informacion del archivo new.txt y la muestra.

El frame estatico.

<p>Datos estaticos lalalala</p>

El frame estatico a fines de esta demostracion solo muestra un mensaje, habitualmente incluye todo el resto de la pagina y puede ser tan complejo como sea necesario.

Conclusion

En este articulo hemos descutido la tecnologia PUSH y como emularla usando HTTP,ademas describimos una solucion eficiente para emular el metodo PUSH sin molestar al usuario y minimizando la cantidad de informacion que se transfiere entre el browser y el usuario. La utilizacion de esta tecnica con el frame oculto que se autorefresca es muy amplia y puede cubrir muchas necesidades hoy en dia dificiles de solucionar en la web.

Los archivos de este articulo pueden downlodearse desde este link php_push.tgz simplemente abriendo estos archivos en un directorio accesible por un apache+php puede verse como funciona el ejemplo. Nota: descomprimir todos los archivos de forma tal que el webserver pueda escribirlos (chmod 777 *) para la prueba sirve.

Nota de redaccion: El metodo fue originalmente presentado por los autores en la nota "Storing data in the client" en phpbuilder.

Luis Argerich
Alejandro Mitrou

You must be logged in to post a comment.

Buscar: