Sei sulla pagina 1di 11

Cear un foro PHP y Mysql

En este tutorial crearemos un foro desde cero aprendiendo a separar la programacin del diseo, y modularizando nuestra aplicacin para que sea simple de configurar y de adaptar. La Estructura Primero y antes que nada, debemos preparar la tabla en la base de datos que contendr todos los temas de nuestro foro. Lo que esta tabla tendr, es la informacin de nuestros mensajes, el autor del mismo, y otros datos que servirn para identificar a que Tema pertenece un mensaje. Pero mejor, veamos la estructura propuesta: CREATE TABLE `foro` ( `id` int(7) NOT NULL auto_increment, `autor` varchar(200) NOT NULL default '', `titulo` varchar(200) NOT NULL default '', `mensaje` text NOT NULL, `fecha` datetime NOT NULL default '0000-00-00 00:00:00', `respuestas` int(11) NOT NULL default '0', `identificador` int(7) NOT NULL default '0', `ult_respuesta` datetime default NULL, KEY `id` (`id`) ) TYPE=MyISAM; Veamos en detalle que campos tendr nuestra tabla de Foros: id: Ser el identificador principal de la tabla. Sirve para diferenciar cada uno de los mensajes. autor: El autor del mensaje. titulo: El titulo que tendr el mensaje. Si este mensaje es el iniciador de un tema, ser el que mostrar en el home del Foro. mensaje: El mensaje en si mismo. fecha: Un campo DATETIME que indicar en que fecha se ha publicado este mensaje. respuestas: Si este mensaje es el iniciador de un tema, aqu se acumularn la cantidad de respuestas que reciba. identificador: Este campo guarda el valor del id del mensaje que se est respondiendo. Si el mensaje es iniciador de un tema, entonces este campo valdr cero. ult_respuesta: Si el mensaje es iniciador de tema, aqui se actualizar valor de acuerdo con la fecha de la ltima respuesta que haya recibido. Sirve para poder mantener un orden en los foros. La sentencia SQL anterior, pueden guardarla en un archivo.sql y correrla en su base de datos desde el href="http://phpmyadmin.sourceforge.net/">phpMyAdmin, o si lo prefieren, pueden ingresarla lnea por lnea en un cliente de texto de mySQL ( como el mySQL monitor). Una vez que hayan creado la tabla en su base de datos, entonces podemos avanzar al siguiente paso.

Antes de ponernos a programar cualquier parte del foro, vamos a encargarnos de hacer un pequeo script que realice una tarea que vamos a repetir mucho, y que es conectarnos a la base de datos. Este script lo incluiremos en cada pgina en la que tengamos que acceder a la base de datos: Ejemplo de la pagina de configuracion.php <?php $bd_host = "localhost"; $bd_usuario = "user"; $bd_password = "password"; $bd_base = "nuestra_bd"; $con = mysql_connect($bd_host, $bd_usuario, $bd_password); mysql_select_db($bd_base, $con); ?> Cmo vemos, no hay gran ciencia en este script, tan solo unas variables conteniendo la configuracin de nuestra base de datos, y el cdigo mnimo y necesario para conectarnos y guardar el recurso de conexin en una variable $con que luego utilizaremos cuando hagamos nuestras consultas. Los Templates Antes de dar un paso ms en la explicacin, quiero hacerles unos comentarios respecto al "simple" sistemita de templates que utilizaremos en el foro. Primero, para aquellos que no sepan que es un Template, les recomiendo que lean los artculos de href="http://www.zonaphp.com/index.php?modulo=articulo&accion=leer&id=9">Nok y de href="http://www.zonaphp.com/index.php?modulo=articulo&accion=leer&id=16">Luigi en nuestra seccin de Templates de href="http://www.zonaphp.com/">Zonaphp.com, por lo menos para que tomen una idea de que son y para que sirven. Ahora, mi idea al utilizar templates, fue la de que los usuarios, pudieran modificar a su gusto el aspecto del foro, sin por ello tener que tocar el cdigo de la aplicacin. Esto es algo que el tutorial anterior no tena en cuenta e inclua todo el cdigo HTML de salida dentro del cdigo mismo del foro, lo cual no es siempre recomendable. Lo que haremos en este caso es utilizar archivos .html que dentro contendrn solo diseo ( o sea, cdigo HTML ) y en los lugares en los que deseemos colocar contenido "dinmico", utilizaremos el formato simple para mostrar el contenido de variables, esto es : <?=$variable?>. Para "interpretar" un template, primero lo leemos en memoria utilizando la funcin file() y luego utilizaremos una simple funcin a la que le pasaremos como parmetro el template y las variables que hay que reemplazar. Para muestra, basta un botn: Ejemplo de la pagina de ejemplo.html Nombre: <b><?=$nombre?></b><br> Edad : <b><?=$edad?></b><br>

Domicilio : <?=$domicilio?> <hr> Ejemplo de la pagina de ejemplo.php <?php function mostrarTemplate($tema, $variables) { //var_dump($variables); extract($variables); eval("?>".$tema."<?"; } $agenda = array( "0" => array("nombre"=>"Marcelo", "edad"=>"25", "domicilio"=>"VeraCRuz 342" , "1" => array("nombre"=>"Alejandra", "edad"=>"18", "domicilio"=>"Los Olmos 67" , "2" => array("nombre"=>"Micaela", "edad"=>"23", "domicilio"=>"Prof. Mario 8" ); $tpl = implode("", file("ejemplo.html"); foreach($agenda as $registro) { mostrarTemplate($tpl, $registro); } ?> Aqu vemos como, partiendo de los datos que tenemos en un array, los mostramos basndonos en un simple template. La funcin mostrarTemplate toma como parmetros el contenido del template y un array asociativo con los valores a reemplazar. La funcin de PHP extract() se encarga de pasar estos valores al mbito en el que se llama la funcin, en este caso, el mbito de la funcin. Por lo que si tenemos un arreglo del tipo $a = array("clave" => "valor", al ejecutar extract($a), entonces pasaremos a tener una variable disponible, de nombre $variable y con "valor" como contenido. Luego, la funcin eval() se encarga del resto, o sea, de ejecutar todo el cdigo (el del Template) que se le pasa como parmetro. Algunos se preguntarn, porqu no hacemos simplemente un "include" ? La respuesta es muy siemple. Eficiencia. La funcin include implica un acceso a disco, lo cual la hace bastante "costosa" en trminos de eficiencia. As que leyendo el template 1 sola vez en memoria, y luego utilizndolo varias veces, hacemos un mejor uso de los recursos. Teniendo estos temas en cuenta, es que podemos seguir ahora con el desarrollo el Foro. Un Tema por vez Ya teniendo las bases de nuestro foro, el diseo de la tabla en la base de datos y conociendo como funciona nuestro sistema de templates, podemos comenzar a crear la primera pgina, en la que mostraremos todos los temas del foro: Ejemplo de la pagina de index.php

<?php require('configuracion.php'); require('funciones.php'); include('header.html'); /* Pedimos todos los temas iniciales (identificador==0) * y los ordenamos por ult_respuesta */ $sql = "SELECT id, autor, titulo, fecha, respuestas, ult_respuesta "; $sql.= "FROM foro WHERE identificador=0 ORDER BY ult_respuesta DESC"; $rs = mysql_query($sql, $con); if(mysql_num_rows($rs)>0) { // Leemos el contenido de la plantilla de temas $template = implode("", file("temas.html"); include('titulos.html'); while($row = mysql_fetch_assoc($rs)) { $color=($color==""?"#5b69a6":""; $row["color"] = $color; mostrarTemplate($template, $row); } } include('footer.html'); ?> Eso es todo? Si, eso es todo. Ahora revisemos paso a paso lo que hace el script. Primero tenemos una serie de requires e includes. El primero incluye el primer Script que hicimos, que realiza la conexin a la base de datos. El segundo, incluye un archivo.php que contiene funciones importantes del foro, como por ejemplo, mostrarTemplate. El tercero, incluye un header genrico que utilizaremos para darle a todas nuestras pginas, un diseo similar. All podremos colocar un logo del sitio, links importantes, banners, etc. $sql = "SELECT id, autor, titulo, fecha, respuestas, ult_respuesta "; $sql.= "FROM foro WHERE identificador=0 ORDER BY ult_respuesta DESC"; $rs = mysql_query($sql, $con); if(mysql_num_rows($rs)>0) { Aqu lo que hacemos es ejecutar un query en la base de datos, que nos traer todos los mensajes que son iniciadores de un tema, o sea, cuyo identificador est en cero. El resto de los mensajes, que sean respuestas a un tema en particular, tendrn en el campo identificador el valor del mensaje al que responden. A estos temas, le pedimos a la base que los ordene por la fecha de ltima respuesta, de manera descendente, as en nuestro foro, tendremos los mensajes ms recientes primero. Tambin realizamos una decisin, solo mostraremos los temas de nuestro Foro si la cantidad de filas recuperadas desde la base, son mayores a 0.

Luego, dentro del While principal del programa, hacemos toda la "magia" : // Leemos el contenido de la plantilla de temas $template = implode("", file("temas.html"); include('titulos.html'); while($row = mysql_fetch_assoc($rs)) { $color=($color==""?"#5b69a6":""; $row["color"] = $color; mostrarTemplate($template, $row); } Aqu comenzamos a trabajar por primera vez con los templates. Primero leemos el contenido del template en memoria y lo guardamos dentro de la variable $template. Tambin incluimos un archivo, que contiene una fila de la tabla de Temas, con los ttulos de las celdas. EL resto ya lo vimos anteriormente, llamando a la funcin mostrarTemplate mostramos los datos de cada tema. Finalmente, solo agregamos otro archivo HTML, con el cdigo para cerrar la pgina y mostrar algn que otro mensaje de Copyright (o lo que queramos poner). Con esto ya tenemos nuestra pgina inicial del Foro, mostrando los temas que haya. Ahora, vamos a crear el formulario necesario para ingresar nuevos temas o para responder algn tema existente. Participar es la Base El ahorro es la base de la fortuna, suelen decir, y esto se aplica a casi todo. As que, haciendo caso al dicho, podemos utilizar el MISMO formulario para crear un nuevo tema y para contestar un tema en particular. Esto lo vamos a lograr, pasando una variable por el URL, indicando que estamos citando un mensaje anterior, sacando de la base de datos el mensaje que citaremos, y completando el formulario con esos datos. Si la variable no est presente, entonces no hacemos nada y mostramos el formulario. Ejemplo de la pagina de respuesta.php <?php require('funciones.php'); $id = $_GET["id"]; $citar = $_GET["citar"]; $row = array("id" => $id); if($citar==1) { require('configuracion.php'); $sql = "SELECT titulo, mensaje, identificador AS id "; $sql.= "FROM foro WHERE id='$id'"; $rs = mysql_query($sql, $con); if(mysql_num_rows($rs)==1) $row = mysql_fetch_assoc($rs); $row["titulo"] = "Re: ".$row["titulo"]; $row["mensaje"] = "[citar]".$row["mensaje"]."[/citar]";

if($row["id"]==0) $row["id"]=$id; } $template = implode("", file('formulario.html')); include('header.html'); mostrarTemplate($template, $row); include('footer.html'); ?> En el script vemos como primero capturamos de la URL, las variables $id y $citar, y si sta ltima es igual a 1, entonces consultamos en la base de datos toda la informacin del tema que estamos citando, para agregarlo en el arreglo $row, que luego ser pasado al template. Noten como al titulo del mensaje, le anteponemos la cadena "Re:", indicando que es una respuesta, y como al cuerpo del mensaje, si estamos citando, lo rodeamos por un tag [citar] y [/citar]. Esto lo veremos ms adelante. Ejemplo de la pagina de formulario.html <table width="90%" border="0" cellspacing="2" cellpadding="2"> <form name="f" action="agregar.php" method="post"> <input type="hidden" name="identificador" value="<?=$id?>"> <tr> <td width="30%" align="right">Autor </td> <td><input type="text" name="autor"></td> </tr> <tr> <td width="30%" align="right">Titulo</td> <td><input type="text" name="titulo" value="<?=$titulo?>"></td> </tr> <tr> <td width="30%" align="right">Mensaje</td> <td><textarea name="mensaje" cols="50" rows="5"><?=$mensaje?></textarea></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" name="Submit" value="Enviar Mensaje"></td> </tr> </form> </table> Aqu vemos como colocamos las variables dentro de los atributos "value" de los inputs y el textarea. Tambin podemos ver como tenemos un campo escondido, llamado "identificador", que solo tendr un valor asignado, cuando estemos respondiendo a un mensaje, pero que no existir cuando sea un mensaje nuevo. Solo queda ver el script que se encarga de grabar el mensaje en la base de datos, agregar.php. Ejemplo de la pagina de agregar.php <?php require('configuracion.php');

$autor = $_POST["autor"]; $titulo = $_POST["titulo"]; $mensaje = $_POST["mensaje"]; $ident = $_POST["identificador"]; //Hacemos algunas validaciones if(empty($autor)) $autor = "Annimo"; if(empty($titulo)) $titulo = "Sin ttulo"; //Evitamos que el usuario ingrese HTML $mensaje = htmlentities($mensaje); // Grabamos el mensaje en la base. $sql = "INSERT INTO foro (autor, titulo, mensaje, identificador, fecha, ult_respuesta) "; $sql.= "VALUES ('$autor','$titulo','$mensaje','$ident',NOW(),NOW())"; $rs = mysql_query($sql, $con) or die("Error al grabar un mensaje: ".mysql_error); $ult_id = mysql_insert_id($con); /* si es un mensaje en respuesta a otro actualizamos los datos */ if(!empty($ident)) { $sql = "UPDATE foro SET respuestas=respuestas+1, ult_respuesta=NOW()"; $sql.= " WHERE id = '$ident'"; $rs = mysql_query($sql, $con); Header("Location: foro.php?id=$ident#$ult_id"; exit(); } Header("Location: index.php"; ?> En este script, luego de tomar las variables desde el formulario (con el mtodo POST), primero verificamos que exista un nombre de autor y el ttulo del mensaje, caso contrario le asignamos un valor por defecto. Tambin utilizamos la funcin de PHP htmlentities() para convertir todos los caracteres especiales ( >, <, ", &, etc ) en sus respectivas entidades HTML ( &gt;, &lt;, &quote;, &amp. Con esto evitamos que un usuario ingrese cdigo HTML en nuestro Foro (con la respectiva vulnerabilidad que este implica). A continuacin, grabamos el mensaje en la base, y obtenemos, mediante la funcin mysql_insert_id(), el ltimo id autoincremental que le corresponde a este registro. Para qu? Simple. Si este mensaje que acabamos de grabar es el primero del tema, no necesitamos hacer nada, pero si es un mensaje en respuesta a otro ( esto lo averiguamos preguntando por el valor de $identificador), entonces tenemos que actualizar ese primer mensaje, indicando que tiene una respuesta ms, y cambiando la fecha y hora del ltimo mensaje. De esa manera, nos aseguramos que tenemos bien ordenado el foro, con los temas con nuevos mensajes primero. Finalmente, dependiendo del caso, redirigimos al usuario al home del foro, o a la respuesta que acaba de ingresar.

Miles de posibilidades Ya solo nos queda un ltimo paso, y es el de crear la pgina que mostrara un tema y todas las respuestas que haya en l. Para ello, vemos como en el home del foro, llamamos a un script foro.php y le pasamos el id del tema que queremos ver. Luego, solo tenemos que obtener de la base el o los temas, en los que el id sea igual al que pasamos, o que el identificador (el campo que indica que ese mensaje es en respuesta a cierto tema) sea igual al identificador, los ordenamos por fecha y listo, foro al dente. En este caso, el template que utilizaremos para mostrar cada uno de los mensajes, ser una tabla con todos los datos necesarios: el autor del mensaje, el ttulo, la fecha del mensaje, el mensaje en si mismo. Pero tambin agregaremos dos detalles. Primero, un link hacia el formulario que creamos antes, de modo que un usuario pueda citar un mensaje en particular, y segundo, un Anchor (o Ancla) para que al responder a un mensaje, se pueda acceder directamente al mismo por su id en la base de datos. Ejemplo de la pagina de post.html

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="2"> <tr bgcolor="<?=$color?>"> <td width="25%" valign="top"> <b><a name="<?=$id?>"><?=$autor?></a></b><br> <font size="-2">Enviado el : <?=$enviado?></font> </td> <td> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td><strong><font size="-1"> <?=$titulo?> </font></strong> </td> <td width="10%" align="right"> [ <a href="respuesta.php?id=<?=$id?>&citar=1">CITAR</a> ]</td> </tr> </table> <hr align="center" width="100%" size="2" noshade> <?=$mensaje?></td> </tr> <tr> <td colspan="2" height="5"></td> </tr> </table> Ahora, veamos el cdigo PHP que utilizaremos para "parsear" este template: Ejemplo de la pagina de foro.php

<?php require('configuracion.php'); require('funciones.php'); $id = $_GET["id"]; if(empty($id)) Header("Location: index.php"; $sql = "SELECT id, autor, titulo, mensaje, "; $sql.= "DATE_FORMAT(fecha, '%d/%m/%Y %H:%i:%s') as enviado FROM foro "; $sql.= "WHERE id='$id' OR identificador='$id' ORDER BY fecha ASC"; $rs = mysql_query($sql, $con); include('header.html'); if(mysql_num_rows($rs)>0) { include('titulos_post.html'); $template = implode("", file('post.html')); while($row = mysql_fetch_assoc($rs)) { $color=($color==""?"#5b69a6":""; $row["color"] = $color; //manipulamos el mensaje $row["mensaje"] = nl2br($row["mensaje"]); $row["mensaje"] = parsearTags($row["mensaje"]); mostrarTemplate($template, $row); } } include('footer.html'); ?> Como siempre, incluimos la conexin a la base de datos, el archivo de funciones y validamos de que exista la variable $id, ya que de lo contrario, nada podramos hacer y nuestro foro fallara en el Query. Hablando del Query, podemos ver como utilizamos la funcin de mySQL DATE_FORMAT() para convertir el formato por defecto del tipo datetime (AAAA-MM-DD hh:mm:ss) en algo que sea ms comn para nuestro idioma (DD/MM/AAAA hh:mm:ss). Si quieren ms informacin sobre esta funcin, pueden visitar y consultar el manual de mySQL. Lo ms destacado en este script que podemos ver, son dos transformaciones que le hacemos al mensaje, antes de enviarlo al template. Como vemos, primero utilizamos la funcin de PHP nl2br(), que convierte todos los saltos de linea, en tags <br />, de esa manera, los saltos que un usuario ingrese en el textarea, sern agregados correctamente al mostrar el mensaje. Luego, vemos como llamamos a la funcin parsearTags(). Qu hace esta funcin? Veamos: Ejemplo de la pagina de funciones.php <?php function parsearTags($mensaje)

{ $mensaje = str_replace("[citar]", "<blockquote><hr width='100%' size='2'>", $mensaje); $mensaje = str_replace("[/citar]", "<hr width='100%' size='2'></blockquote>", $mensaje); return $mensaje; } ?> Dentro de esta funcin, podemos agregar todas las modificaciones que queremos realizarle al mensaje, antes de mostrarlo en el Foro. En el ejemplo, vemos como hemos implementado el uso de un tag propio, [citar]. El mismo, dentro de la funcin, ser reemplazado por el cdigo HTML necesario para destacar el citado de un mensaje, todo esto gracias a la funcin str_replace() de PHP (ms info en el manual). Este es el tag [citar] que se agrega automticamente, y que notamos cuando respondamos un mensaje. Esta funcin, pueden personalizarla de la manera que deseen, agregando todos los tags que quieran, para ofrecerles a sus usuarios la libertad de darle formato a sus mensajes. Podran, por ejemplo, agregar un nuevo tag, para poner palabras en negritas, o quizs alguna expresin regular que convierta automticamente cualquier URL presente en el mensaje, en un link. Los lmites son los de su imaginacin. Misin Cumplida Cmo intent demostrarles en este pequeo artculo, realizar nuestro primer foro es algo completamente sencillo, si sabemos utilizar mnimamente mySQL y PHP (ms bien, algunas funciones ms que til del PHP). En estas pocas lneas aprendimos: Crear una tabla en MySQL para que contenga los datos de nuestro foro. A conectarnos a MySQL desde nuestro script PHP. A utilizar un sistema de templates casero y simple. La utilizacin de funciones de PHP como: extract(); eval(); implode(); file(); nl2br(); mysql_insert_id(); str_replace(); La utilizacin de la funcin DATE_FORMAT() de MySQL. Cmo trabajar de manera segura con la directiva Register_Globals en OFF, tomando uno a uno los contenidos de las variables, desde sus respectivos arrays $_POST y $_GET. Y varios conceptos ms a la hora de programar nuestros scripts. Ahora, este sistema es muy bsico, como simple. As que de ahora en ms, es campo frtil para que Uds. mismos puedan agregarle todas las caractersticas y funcionalidades que deseen, personalizando el foro a su gusto. Como ideas, puedo mencionarles algunas: Agregar ms tags para que sus usuarios puedan dar formato a sus mensajes. Incorporarle un sistema de usuarios. Contadores de visualizaciones de un tema, para hacer un Ranking de temas ms vistos. La posibilidad de que los usuarios puedan utilizar firmas. Y seguro que a uds. mismos se les deben estar ocurriendo otras muchas buenas ideas para mejorar el Foro. Para aquellos usuarios que sean vagos y no quieran estar un rato con el Copy&Paste,

les dejo el cdigo completo del foro href="http://www.maestrosdelweb.com/editorial/util/foro.zip">para que lo descarguen. Por lo pronto, espero que hayan disfrutado este tutorial, y sigan programando simple, seguro, pero ante todo, bonito Saludoss s Nacho