El patrón de diseño Decorator (aplicado en PHP)

Iba a poner El patrón de diseño decorator en PHP pero dado que los patrones de diseño son independientes del lenguaje preferí poner un título más matizado. Aunque algunos parezcan empeñados en no usar patrones en PHP (a pesar de que desde PHP5 ya esté orientado a objetos) en un proyecto grande serán útiles.

El patrón Decorator se pensó para permitir herencia múltiple sin que el árbol de clases crezca de forma incontrolada. Permite añadir a un objeto funcionalidades de forma dinámica. Piensa en un juego de rol, piensa en cuando vinculabas una matriz de conjuros a un arma en Runequest… vale, es muy friki, pero lo voy a usar de ejemplo para explicar el patrón.

Imagina que haces un videojuego, inspirado en el antes citado Runequest mismamente. Entonces creas la clase espada, que hace 10 puntos de daño y tiene 20 puntos de armadura. Muy bien, ahora le vinculas un hechizo de armadura extra. Tendrías que crear la clase espada_armadura con 10 puntos más de armadura. Hasta ahí, bien: tienes la clase espada, y la clase hija espada_armadura que hereda de espada.

Ahora imagina que también le vinculas un hechizo que duplica el daño. Tendrías que crear la clase espada_daño, pero también la clase espada_armadura_daño, que sería la clase con ambos hechizos. Para dos funcionalidades has tenido que crear 3 clases hijas. Y ahora supón un tercer hechizo que mejora tu posibilidad de éxito un 100%: espada_éxito, espada_éxito_armadura, espada_éxito_daño, espada_éxito_daño_armadura… y las cuatro clases anteriores. Para tres funcionalidades ya vas en 8 clases, si haces el cálculo progresan en potencias de 2, por lo que para 4 funcionalidades tendrías 16 clases, para 5 32

El patrón Decorator nos permite evitar esto a base de delegar funciones. Vamos a poner un ejemplo práctico en PHP solucionando el problema anterior, explicado en los comentarios:


//interfaz arma, común a todas las armas
interface iArma{
  public function ataca();
  public function defiende();
}

//clase espada, que implementa la interfaz arma
class espada implements iArma{
  private $armor = 20;
  private $attack = 10;

  public function ataca(){
    return $this->attack;
  }
  public function defiende(){
    return $this->armor;
  }
}

//creamos la clase abstracta Decorator
abstract class espada_decorator implements iArma{
  protected $_espada;
  public function __construct(iArma $Espada){
    $this->_espada = $Espada;
  }
}

//ahora creamos la funcionalidad con más ataque
class extra_attack extends espada_decorator{
  public function ataca(){
    return $this->_espada->ataca()*2;
  }
}

//ahora la funcionalidad de más defensa
class extra_armor extends espada_decorator{
  public function defiende(){
    return $this->_espada->defiende()+10;
  }
}

//ahora podemos crear un objeto espada con la defensa extra
$espada = new extra_armor(new espada());

//y ahora añadimos el ataque extra
$espada = new extra_attack($espada);

Como puedes ver, de esta forma agregamos a nuestro objeto diversas funcionalidades, creando sólo una clase por funcionalidad en lugar del montón al que nos obligaría el ir creando clases para cara posible combinación.

Twig: genera tus plantillas en php

A raíz de los experimentos con Symfony toca continuar y hablar de Twig. ¿Qué es Twig? Se trata de un motor de plantillas libre para el lenguaje PHP. Si has trabajado alguna vez con JSP o con ASP no te resultará raro.

Synfony incluye dentro del framework este motor (también te lo puedes bajar aparte) , que nos ofrece ciertas comodidades respecto a hacer la plantilla en php  pelo. La primera consiste en poder pasar variables las plantillas, con objeto de que estas sean mostradas en pantalla. Las variables pueden tener atributos o elementos en ellas a los cuales puedes acceder también, utilizando el punto (.) o el subíndice ([]) para el caso de un array. También permite realizar iteraciones si la varible es una colección (como un array) o utilizar el condicional if. Con un ejemplo ser verá más claro:

/*PHP tradicional*/
<h1><?php echo strtoupper($title) ?></h1>
<ul>
<?php foreach($collection as $item){ ?>
<li>Nombre:<a href="<?php echo $item->getUrl();?>"> <?php $item->getName();?></a></li>
<?php }  ?>
</ul> 

/*TWIG*/
<h1>{{ title|upper }}</h1>
<ul>
{% for item in collection %}
<li>
Nombre: <a href="{{item.url}}">{{item.nombre}}</a>
</li>
{% endfor %}
</ul>

¿Cómodo? Desde luego, una vez te has acostumbrado. Pero no es lo único que permite Twig, porque su verdadera potencia se encuentra en la herencia entre plantillas. Esto nos permite crear un modelo de plantilla base que contenga todos los elementos comunes del sitio y definir los bloques que las plantillas descendientes pueden sustituir. Imaginemos esta plantilla base:

<!DOCTYPE html>
<html>
    <head>
        {% block head %}
            <link rel="stylesheet" href="stilos.css" />            
        {% endblock %}
    </head>
    <body>
        <div id="content">
          {% block content %}{% endblock %}
        </div>
    </body>
</html>

Muy bien, ahora en las plantillas hija nos basta usar las etiquetas block para insertar el código que será distinto:

{% extends "base.html" %}

{% block head %}
    {{ parent() }}
    <script type="text/javascript" src="jquery.min.191.js"></script>
{% endblock %}

{% block content %}
    <h1>Índice</h1>
    <p>
        Hola mundo!
    </p>
{% endblock %}

Productivo ¿no? Pues no es todo, Twig incluye autoescape de html en las variables para prevenir ataques XSS. En el primer ejemplo ves como al lado de la variable usé upper, eso es un filtro. Existen múltiples filtros que puedes consultar en la documentación oficial de TWIG, al igual que también varias funciones y las etiquetas propias de Twig con varias funcionalidades.

Instalar Symfony 2.1 en Linux

Bueno, seguimos con el tema de Symfony tras el interludio papal. El caso es que comenzamos este tutorial donde dejamos el anterior ¿anterior? Sí, en cierto modo la entrada sobre instalar Composer sirve de introducción a esto.

En fin, la cosa es tener instalado Composer de forma global en tu equipo y GIT (aunque si te dedicas a programar seguramente ya lo tengas instalado), lo que ya se explicó en la entrada anterior. El caso es que con Composer instalado lo primero es ejecutar desde línea de comandos $ composer create-project symfony/framework-standard-edition directoriodelproyecto 2.1.x-dev obviamente cambiando directoriodelproyecto por el directorio que corresponda. Sin Composer ni GIT esto no furrulará, repito.

Una vez instalado prueba a situarte en el directorio donde has instalado y ejecutar $ php app/check.php, ahí verás la lista de requisitos que debe cumplir tu equipo para ejecutar Symphony. Luego si ejecutas desde ahí $ php app/console verás en la consola una lista con todos los comandos disponibles para las aplicaciones de Symfony 2.

Finalmente, puedes probar en tu navegador el funcionamiento de Symfony. Visita http://localhost/directoriodelproyecto/web/config.php (cambia directoriodelproyecto por lo que corresponda). Puede que te salga un mensaje de error, suele ser por cuestiones de permisos, nada que no se arregle trasteando con la configuración de seguridad.

Instalar Composer en Linux

¿Qué es Composer y por qué debería instalarlo? En fin, es la primera pregunta, desde luego. Composer es un gestor de dependencias para PHP, de uso común en los proyectos realizados con Symfony (sí, me he puesto a trastear con Symfony, aunque ando un poco pez). En todo caso, lo que Composer hace es comprobar la lista de dependencias de cada proyecto y decidir qué librerías hay que instalar, qué versiones de las mismas se instalan y en qué orden. Muy útil sobre todo cuando actualizas tu versión de Symfony, ya que te evita problemas de incompatibilidad con librerías antiguas.

En fin, vamos a meternos ya en harina. ¿Cómo instalo Composer en mi Linux? Bueno, no es muy difícil (no como en el caso de Windows donde es un puto coñazo, pero eso ya lo explicaré otro día). Tienes dos opciones, además: instalar Composer en un proyecto concreto o instalar Composer globalmente.

Para la instalación en un proyecto concreto, desde la consola de comandos sitúate dentro del directorio raíz de ese proyecto y ejecuta $ curl -s https://getcomposer.org/installer | php y, tras ello, si todo ha ido bien, deberías tener en el directorio del proyecto un archivo llamado composer.phar. Para comprobar si está bien instalado ejecuta $ php composer.phar

Las instrucciones anteriores nos sirven para instalar Composer en un proyecto concreto, pero generalmente lo que nos interesará es instalarlo globalmente para usarlo en varios proyectos.

La idea sería la misma, pero en lugar de descargar Composer en el directorio raíz de un proyecto lo deberíais hacer en un directorio ejecutable del sistema, como por ejemplo /usr/local/bin/composer. Después deberíais poder ejecutar el comando composer desde cualquier directorio del sistema y funcionaría. De esta forma además de tenerlo disponible para todos los proyectos también se facilita la actualización de Composer, dado que con la instalación para un proyecto concreto tendrías que ir actualizándolo en cada uno de ellos, mientras que con esta basta con actualizar sólo el global, con el comando $ sudo composer self-update.

En fin, con esto queda explicado cómo instalar Composer, del cual podéis leer aquí la documentación oficial. Próximamente (espero) más sobre Symfony.

Crear gráficas en PHP con Googchart

La librería GoogChart de Google puede descargarse libremente (licencia MIT) desde este enlace y nos permite generar gráficas desde PHP.

El primer paso es añadir la clase GoogChart a nuestro script de PHP tal que así:

include "GoogChart.class.php"; 

Ahora necesitamos varias cosas: Primero generar un objeto de la clase GoogChart, después un array con los colores que tendrán las columnas y luego otro array con los datos a mostrar.

$chart = new GoogChart(); //objeto
$color = array('#333','#666','#999','#ccc'); //colores
$datos = array(enero=>50, febrero=>35, marzo=>89, abril=>45);//datos simples

Con estos datos ya podemos darle valores a nuestro objeto e imprimirlo:

$chart->setChartAttrs( array(
'type' => 'bar-vertical',
'title' => 'Ventas 2012',
'data' => $datos,
'size' => array( 600, 300 ),
'color' => $color,
'labelsXY' => true
));

echo $chart;

A la hora de dar valores al objeto definimos el tipo de gráfica (en este caso barras verticales), el título, los datos, el tamaño (en píxeles), la paleta de colores y si tendrá etiquetas en los ejes. Ahora veamos un ejemplo con datos de varios años:

$datosMultiple = array(
 'Año 2011' => array(
 enero => 30,
 febrero => 20,
 marzo => 45,
 abril => 75
),
 'Año 2012' => array(
 enero => 50,
 febrero => 35,
 marzo => 89,
 abril => 65
 ),
 );

Este array incluye dos arrays de datos donde los nombres sirven como leyenda para la gráfica. El resto del proceso sería igual.

En fin, ahora lo que os queda es miraros los ejemplos que vienen junto al archivo de la clase y experimentar.

CSS3 Box Shadow: sombras sin usar imágenes

Seguimos otra vez con truquillos de CSS3 para vuestra web. Mientras me desquicio usando un teclado de silicona para escribir (cosa incómoda donde las haya) vamos a comentar el uso de la propiedad box-shadow de CSS3. Como siempre, ojo con IE que es puñetero cuando se trata de trabajar con stándares.

En su uso básico box-shadow necesita al menos tres parámetros, si bien acepta hasta cinco.

  • Desplazamiento horizontal: Define la posición horizontal de la sombra respecto al elemento al que se la aplicamos. Si le enviamos un valor positivo la sombra se situará a la derecha del elemento. Si el valor es negativo se situará a la izquierda.
  • Desplazamiento vertical: Define la posición vertical de la sombra. Si recibe un valor positivo la sombra se situará debajo del elemento, y con uno negativo encima.
  • Radio de desenfoque: Cuanto mayor sea, más transparente será la sombra. En caso de 0 la sombra será totalmente nítida. Se trata de un valor opcional y 0 es su valor por defecto.
  • Radio de dispersión: Cuanto mayor sea, mayor dispersión tendrá la sombra. Es opcional y el valor por defecto es cero. En ese caso el tamaño será igual al desenfoque.
  • Color: Finalmente el color que tendrá la sombra. Es el tercer valor obigatorio.
  • Inset: Existe un parámetro más, que es este inset. Si lo incluimos al principio hará que la sombra en lugar de estar en el exterior se sitúe en el interior del elemento..

La sintaxis sería como en este ejemplo:

/*Sombra gris abajo derecha*/
.sgad{
    box-shadow: 5px 5px 2px #666;
}

/*Sombra azulada arriba izquierda muy dispersa*/
.saaid{
    box-shadow: -5px -5px 5px 14px #99C;
}

/*Sombra interna gris*/
.sig{
    box-shadow: inset 0 0 10px #666;
}

Si queréis una buena serie de ejemplos y trucos los podéis encontrar en este enlace. Y recordad, ojo con el Explorer.

Leyendo ficheros CSV con PHP

A petición de Jorge de Saliceta, que lo reclamó en la entrada sobre lectura de ficheros en PHP va la explicación sobre cómo leer ficheros CSV con PHP. No es la primera vez que en este blog hablamos sobre el formato CSV (comma separated values).

Bueno, si te vas a la entrada de lectura de ficheros verás que para la lectura secuencial, línea a línea, usábamos la función fgets(). Bueno, pues existe una función similar, llamada fgetcsv(), pensada para trabajar con archivos de este tipo. En lugar de devolver una cadena de texto como fgets(), esta función lo que devuelve por cada línea recorrida es un array, donde cada valor separado por una coma ocupa una de las posiciones del mismo. Veamos un ejemplo:

//supongamos la siguiente fila en un csv:
//Manolo, Rodríguez, Málaga, Fontanero
//y que está guardado en el archivo prueba.csv
//Aplicaríamos el siguiente código

<?php
$file = fopen("prueba.csv","r");
$result = fgetcsv($file);
fclose($file);
?> 

//esto devolvería un array con el siguiente resultado:
Array
(
[0] => Manolo
[1] => Rodríguez
[2] => Málaga
[3] => Fontanero
) 

Cuestiones a tener en cuenta hay varias. La primera es que si pilla una línea en blanco devolverá una matriz con un sólo campo con el valor NULL. La segunda es que existen varios parámetros que podemos pasar: Obligatorio, desde PHP5, sólo es el archivo a parsear, pero también acepta la longitud máxima de línea (si la sabes pásalo, porque hará que la función vaya más rápido), el delimitador de campo (por defecto, la coma), el «cercado» de campo (por defecto comillas dobles… ya se que lo de cercado no es muy claro, en inglés sería enclosure) y el caracter de escape (por defecto, la barra invertida). Al igual que con fgets() puede haber problemas para detectar los finales de fila en archivos creados en un Mac, y también hay que tener en cuenta que la función tiene en cuenta la configuración local, así que si estás trabajando con UTF8 tenlo en cuenta a la hora de calcular el tamaño máximo de línea o con los archivos codificados en one-byte.

Finalmente os dejo un gran ejemplo del funcionamiento de esta función sacado de la web de php:


<?php
$fila = 1;
if (($gestor = fopen("test.csv", "r")) !== FALSE) {
    while (($datos = fgetcsv($gestor, 1000, ",")) !== FALSE) {
        $numero = count($datos);
        echo "<p> $numero de campos en la línea $fila: <br /></p>\n";
        $fila++;
        for ($c=0; $c < $numero; $c++) {
            echo $datos[$c] . "<br />\n";
        }
    }
    fclose($gestor);
}
?>

Leer ficheros de texto con PHP

Uno de esos posts a petición de un lector: ¿cómo leer un fichero de texto con PHP? Bueno, a día de hoy no es una práctica muy usada, tal vez sea algo que suena más a tiempos pasados, pero hace año y pico en un trabajo por ejemplo tuve que hacerlo (y no veáis la lata que daba tratar los datos cuando una tabla de MySQL habría ahorrado muchísimo trabajo, pero eso es otra historia).

Bueno, para leer un fichero debemos usar la función fopen(), pasándole como primer parámetro la dirección del fichero a abrir y como segundo el modo (para lectura r, para escritura w).

Entonces, para leer fopen(«archivo.txt», «r»), y ahora tenemos dos opciones: cargar todo el contenido de golpe o ir leyendo línea a línea.

Para cargar todo el contenido de golpe la cosa sería más o menos así:

function leer_completo($direccion_fichero){
   $fichero = fopen ($direccion_fichero, "r");   
   $contenido = fread($fichero, filesize($direccion_fichero));
   return $contenido;
} 

Esto devolvería una variable con todo el contenido del fichero. Para la lectura línea a línea en cambio necesitaremos un bucle y la función fgets() en lugar de fread().


<?php
$gestor = @fopen("/tmp/inputfile.txt", "r");
if ($gestor) {
    while (($búfer = fgets($gestor, 4096)) !== false) {
        echo $búfer;
    }
    if (!feof($gestor)) {
        echo "Error: fallo inesperado de fgets()\n";
    }
    fclose($gestor);
}
?>

En este caso ya os pego el ejemplo que aparece en la web oficial de php. En ese caso se especifica a fgets() el parámetro del tamaño a leer. Y es que puedes especificarle el tamaño de bloque que debe hacer en cada lectura o, por el contrario, no pasarle ningún parámetro y que lea hasta el final de línea. Esto último puede dar problemas con archivos creados en un Mac, pero se puede solventar activando la opcion en tiempo de ejecución auto_detect_line_endings.

Otro día, si queréis, hablamos de csv, o de escritura… estoy abierto a sugerencias.

Cinco frameworks a tener en cuenta para desarrollo web

Soy evangelista de jQuery, lo sabéis, estoy enamorado, tando de jQuery (sobre todo para frontend), jQueryUI (este mejor para backend) o jQueryMobile. Es fácil de usar, productivo y libre, por lo que merece la pena usarlo. Pero no todo en esta vida es jQuery, por lo que hoy voy a hablar de cinco frameworks que os pueden interesar:

  • backbone.js: Con una documentación muy completa, este proyecto está siendo una de las estrellas de los frameworks javascript de los últimos dos años. Además de un catálogo de eventos y un API bastante entendible, el atractivo de backbone.js es que nos permite implementar el patrón Model-View-Controller en nuestra apliación de javascript. Sí, MVC en el lado del cliente. Piensa todo el código que se aprovechará, y la independencia que ganarás sobre el marcado.
  • Image Mapster:: En este caso nos encontramos con un plugin de jQuery para crear interacción con las imágenes. ¿Quieres un mapa donde haya un enlace sobre cada provincias? ¿quieres unas siluetas en negro que al sobrevolarlas con el ratón muestren la foto de la persona? Echa un ojo a la página de demos y hazte una idea de las posibilidades de este framework.
  • QUnit: Y si arriba hablábamos de implementar el patrón MVC en Javascript ¿por qué no hacer tests unitarios? QUnit es un proyecto de los creadores de jQuery, en principio pensado para testear su propio código, y que han liberado para uso y disfrute de la comunidad.
  • Canvas Query: Usar el elemento Canvas de HTML5 con sintaxis de jQuery. Eso es lo que nos ofrece Canvas Query, una herramienta que facilitará la vida del desarrollador que se lance a trastear con Canvas. Principalmente está pensado para el desarrollo de juegos en HTML5, donde puede tornarse una enorme ayuda a la hora de manipular sprites, jugar con paletas de colores…
  • Junior: Y termino con un framework para la creación de apps móbiles en HTML5. He de decir que ayer me encontré uno que me gustaba más, trasteando por la web, pero que no apunté el nombre… por lo que le he perdido la pista. En todo caso, este Junior puede ser una buena alternativa a jQueryMobile, dándonos una presentación diferente, más atractiva. Implementa varias librerías, como la antes citada backbone.js.

Y una cosa que me pregunto ¿realmente hacen falta tantos frameworks de maquetaciones tipo grid y metro? Los hay a patadas en los últimos tiempos.

Crear un chat con PHP y jQuery

En este caso no se trata de un artículo original, sino de una medio traducción medio interpretación de este original en inglés. Podéis descargaros todo el código desde el enlace.

Se trata de un chat web simple, programado en php y basado en Ajax, haciendo uso de jQuery, con función de login y logout y soporte para varios usuarios.

El tutorial comienza creando un archivo index.php tal cual este:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>  
<title>Chat - Customer Module</title>  
<link type="text/css" rel="stylesheet" href="style.css" />  
</head>  
<div id="wrapper">  
    <div id="menu">  
        <p class="welcome">Welcome, <b></b></p>  
        <p class="logout"><a id="exit" href="#">Exit Chat</a></p>  
        <div style="clear:both"></div>  
    </div>  
    <div id="chatbox"></div>  
    <form name="message" action="">  
        <input name="usermsg" type="text" id="usermsg" size="63" />  
        <input name="submitmsg" type="submit"  id="submitmsg" value="Send" />  
    </form>  
</div>  
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.js"></script>  
<script type="text/javascript">  
// jQuery Document  
$(document).ready(function(){  
});  
</script>  
</body>  
</html>

Como podéis ver se trata de un marcado HTML normal. La referencia a jQuery del código original está anticuada, en este ejemplo ya veréis una apuntando una dirección actualizada. En cuanto a la estructura hay tres grandes divs: el #wrapper, que contiene los otros dos y el formulario de envío de mensaje; el #menu, que sólo es un mensaje de bienvenida y un botón de logout y, finalmente, el #chatbox, que es donde se incluirán los mensajes.

El css sería tal que así:

    /* CSS Document */  
    body {  
        font:12px arial;  
        color: #222;  
        text-align:center;  
        padding:35px; }  
    form, p, span {  
        margin:0;  
        padding:0; }  
    input { font:12px arial; }  
    a {  
        color:#0000FF;  
        text-decoration:none; }  
        a:hover { text-decoration:underline; }  
    #wrapper, #loginform {  
        margin:0 auto;  
        padding-bottom:25px;  
        background:#EBF4FB;  
        width:504px;  
        border:1px solid #ACD8F0; }  
    #loginform { padding-top:18px; }  
        #loginform p { margin: 5px; }  
    #chatbox {  
        text-align:left;  
        margin:0 auto;  
        margin-bottom:25px;  
        padding:10px;  
        background:#fff;  
        height:270px;  
        width:430px;  
        border:1px solid #ACD8F0;  
        overflow:auto; }  
    #usermsg {  
        width:395px;  
        border:1px solid #ACD8F0; }  
    #submit { width: 60px; }  
    .error { color: #ff0000; }  
    #menu { padding:12.5px 25px 12.5px 25px; }  
    .welcome { float:left; }  
    .logout { float:rightright; }  
    .msgln { margin:0 0 2px 0; }  

Poca cosa que comentar, pero entre esto y el marcado ya tenemos la apariencia definida del chat.

Ahora toca el formulario de login en PHP:

    <?  
    session_start();  
    function loginForm(){  
        echo' 
        <div id="loginform"> 
        <form action="index.php" method="post"> 
            <p>Please enter your name to continue:</p> 
            <label for="name">Name:</label> 
            <input type="text" name="name" id="name" /> 
            <input type="submit" name="enter" id="enter" value="Enter" /> 
        </form> 
        </div> 
        ';  
    }  
    if(isset($_POST['enter'])){  
        if($_POST['name'] != ""){  
            $_SESSION['name'] = stripslashes(htmlspecialchars($_POST['name']));  
        }  
        else{  
            echo '<span class="error">Please type in a name</span>';  
        }  
    }  
    ?>     

En este caso se trata de un login simple, no comprueba usuarios registrados en una base de datos. Sobre su funcionamiento hay poco que comentar: nos pide un nombre y lo incluye dentro de una variable de sesión (de ahí la llamada a session_start()). El uso de htmlspecialchars() es para evitar ataques XSS.

Lo siguiente es motrar tanto el nombre de usuario en el Welcome como el formulario si el usuario no está logueado. La idea es dejar el primer archivo, el index.php tal cual este:

    <?php  
    if(!isset($_SESSION['name'])){  
        loginForm();  
    }  
    else{  
    ?>  
    <div id="wrapper">  
        <div id="menu">  
            <p class="welcome">Welcome, <b><?php echo $_SESSION['name']; ?></b></p>  
            <p class="logout"><a id="exit" href="#">Exit Chat</a></p>  
            <div style="clear:both"></div>  
        </div>  
        <div id="chatbox"></div>  
        <form name="message" action="">  
            <input name="usermsg" type="text" id="usermsg" size="63" />  
            <input name="submitmsg" type="submit"  id="submitmsg" value="Send" />  
        </form>  
    </div>  
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>  
    <script type="text/javascript">  
    // jQuery Document  
    $(document).ready(function(){  
    });  
    </script>  
    <?php  
    }  
    ?>  

Bien, ahora vamos con el código de Javascript para la funcionalidad de logout. Dentro del script que ya tenemos creado en nestro código insertamos:

    <script type="text/javascript">  
    // jQuery Document  
    $(document).ready(function(){  
        //If user wants to end session  
        $("#exit").click(function(){  
            var exit = confirm("Are you sure you want to end the session?");  
            if(exit==true){window.location = 'index.php?logout=true';}  
        });  
    });  
    </script>  

Esto no sólo nos permite enviar una llamada por el método GET para desconectar al usuario, sino que también nos sacará una ventana de confirmación antes de hacerlo. Y claro está, tendremos que tocar nuestro código del index.php para comprobar que se ha hecho una petición de logout y destruir la sesión que se había creado en el login:

    if(isset($_GET['logout'])){  
        //Simple exit message  
        $fp = fopen("log.html", 'a');  
        fwrite($fp, "<div class='msgln'><i>User ". $_SESSION['name'] ." has left the chat session.</i><br></div>");  
        fclose($fp);  
        session_destroy();  
        header("Location: index.php"); //Redirect the user  
    }  

Este código, además, escribe en un archivo de logs (más tarde vemos para qué se usará) que el usuario se ha desconectado y redirecciona de nuevo a la página principal.

Lo siguiente es manejar las inserciones de mensajes de los usuarios. Hay que empezar por definir una función de jQuery para enviar los mensajes por el método POST haciendo uso de Ajax. El proceso sería recoger el evento de click del formulario, leer los datos del campo de texto, enviarlos al script de php que los va a tratar y borrar el campo de texto para que quede de nuevo en blanco:

    //If user submits the form  
    $("#submitmsg").click(function(){  
        var clientmsg = $("#usermsg").val();  
        $.post("post.php", {text: clientmsg});  
        $("#usermsg").attr("value", "");  
        return false;  
    });  

Y claro, esto implica crear el archivo post.php para manejar los datos en el lado del servidor. Un archivo que llevaría este código:

    <?  
    session_start();  
    if(isset($_SESSION['name'])){  
        $text = $_POST['text'];  
        $fp = fopen("log.html", 'a');  
        fwrite($fp, "<div class='msgln'>(".date("g:i A").") <b>".$_SESSION['name']."</b>: ".stripslashes(htmlspecialchars($text))."<br></div>");  
        fclose($fp);  
    }  
    ?>  

De nuevo iniciamos sesión, comprobamos que el usuario está logueado, recogemos el texto del mensaje del array $_POST y escribimos el mensaje junto al nombre de usuario en el log del chat.

Finalmente llevamos a la parte de mostrar los mensajes de chat en pantalla. Lo primero es cargar el log del chat dentro del #chatbox si este existe, para ahorrarnos tiempo:

    <div id="chatbox"><?php  
    if(file_exists("log.html") && filesize("log.html") > 0){  
        $handle = fopen("log.html", "r");  
        $contents = fread($handle, filesize("log.html"));  
        fclose($handle);  
        echo $contents;  
    }  
    ?></div>  

Lo siguiente es la carga por Ajax de los datos contenidos en el archivo de log. La cosa se arreglaría con el método de jQuery para Ajax:

    //Load the file containing the chat log  
        function loadLog(){  
            $.ajax({  
                url: "log.html",  
                cache: false,  
                success: function(html){  
                    $("#chatbox").html(html); //Insert chat log into the #chatbox div  
                },  
            });  
        }  

El parámetro url nos indica a qué archivo intentamos acceder por Ajax, cache es para definir si queremos cachear el archivo o no (en este caso, por lógica, no, porque queremos recargarlo en cada llamada) y finalmente la función que se ejecutará en caso de éxito (en este caso insertar el log en el div #chatbowx).

Para añadir autoscrolling, modificas el código anterior añadiendo lo siguiente:

    //Load the file containing the chat log  
    function loadLog(){  
        var oldscrollHeight = $("#chatbox").attr("scrollHeight") - 20; //Scroll height before the request  
        $.ajax({  
            url: "log.html",  
            cache: false,  
            success: function(html){  
                $("#chatbox").html(html); //Insert chat log into the #chatbox div  
                //Auto-scroll  
                var newscrollHeight = $("#chatbox").attr("scrollHeight") - 20; //Scroll height after the request  
                if(newscrollHeight > oldscrollHeight){  
                    $("#chatbox").animate({ scrollTop: newscrollHeight }, 'normal'); //Autoscroll to bottom of div  
                }  
            },  
        });  
    }  

Básicamente consiste en ir modificando el tamaño para ocultar la parte de arriba y ampliar la de abajo. Simple truquillo. Ahora nos falta que el chat se auto recargue, cosa que haremos desde javascript:

setInterval (loadLog, 2500);

Esto lanza la función loadLog cada dos segundos y medio, logrando recargar los datos.

En el artículo orginal además encontraréis al final una serie de artículos con consejos varios para mejorar el código (en inglés) y todo el código completo para descargar.