Creando un Foro en PHP y Mysql Con el siguiente manual veremos cómo crear un foro desde cero, aprendiendo a apartar la programación del diseño y gestionando la aplicación para que sea forma simple podamos hacerle configuraciones. Estructuración Inicialmente disponemos a preparar la tabla en la base de datos la cual será la que contendrá todos los datos de nuestro foro. Esta tabla contendrá la información de nuestros mensajes, el autor del mismo y demás información la cual nos será de ayuda para identificar a que temas pertenece un mensaje. Con la siguiente 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; Con los diferentes campos que llevara la tabla: Id: el cual actúa como el principal identificador de la tabla. Con este podemos diferenciar los mensajes. Autor: El autor de los mensajes. Título: Título que llevara el mensaje, si este opera como el iniciador de un tema, este si visualizara en el home de nuestro Foro. Mensaje: El mensaje en sí. Fecha: El cual nos mostrará en qué fecha se publican estos mensajes. Respuestas: Si este actúa como iniciador de un tema, en esta parte se almacenarán el número de respuestas recibidas. Identificador: este se encarga de guardar los valor del id, del mensaje que se está respondiendo, si el mensaje es el que comienza un tema, este campo tendrá valor cero. ult_respuesta: Si este mensaje es el iniciador del tema, se actualizarán los valores de acuerdo con la fecha de la última
respuesta que este haya recibido. Eso es de gran ayuda para mantener el orden en los foros. La sentencia SQL anterior se puede guardar en un archivo.sql y posteriormente correrla en su base de datos desde <ahref="http://phpmyadmin.sourceforge.net/">phpmyadmin, o si gusta también puede ingresar línea por línea en un cliente de texto de mysql.cuando ya se haya creado la tabla en la base de datos, se continua con el siguiente paso. Antes de iniciar a programar cualquier parte del foro, tenemos que hacer un pequeño script el cual se encargara de una actividad la cual se va a repetir mucho, la cual es que se conecte a la base de datos. Este script se incluye en cada página en la que debamos de acceder a la base de datos: Por ejemplo configuracion.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); No hay gran problema en este script, solo algunas variables las cuales contienen la configuración de nuestra base de datos y además el código que se necesita para que podamos realizar la conexión y poder guardar los recursos de conexión en la variable $con que posteriormente se utilizara cuando tengamos que hacer nuestras consultas. Templates Definamos primero que es un Template el cual es un patrón de diseño enmarcado, tiene como característica tener una definición, dentro de una operación de una superclase, de los pasos de un algoritmo, de este modo permite que todos o parte de estos procesos sean redefinidos en las subclases herederas de la mencionada superclase. El objetivo de utilizar templates es el que los usuarios, puedan hacer cambios a placer en el aspecto del foro, sin la necesidad de tocar el código de la aplicación.
Lo que a continuación haremos es usar archivos.html los cuales contienen solo diseño y en las partes en los que queramos poner el contenido "dinámico", vamos a utilizar un formato sencillo para mostrar el contenido de las variables, esto es : <?=$variable. Para poder interpretar a los templates, inicialmente se deben leer en memoria usando la función file () y después utilizar una sencilla función a la cual se le pasara como parámetro el template y las variables que vamos a reemplazar. Como en el siguiente ejemplo: ejemplo.html Nombre: <b><?=$nombre</b><br> Edad : <b><?=$edad</b><br> Domicilio : <?=$domicilio <hr> Ejemplo de la página de ejemplo.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. Mariño 8") ); $tpl = implode("", file("ejemplo.html")); foreach($agenda as $registro) mostrartemplate($tpl, $registro); En este ejemplo se muestra, partiendo de los datos que poseemos en un array, los exponemos basándonos en un sencillo template. La función nombrad mostrar Template toma como referencia los contenidos de los templates y un array asociativo con los valores que se van a reemplazar.
La función de PHP extract() se encarga de pasar valores al espacio en el que se llama la función. Por lo que si tenemos un arreglo de tipo $a = array("clave" => "valor"), al ejecutar extract($a), pasaremos a obtener una variable disponible nombrada $variable la cual tiene un valor de contenido. Después la función eval() se comisionara de ejecutar todo el código (del template) que se le pasa como parámetro. Procedemos al desarrollo del foro Un Tema por vez Una vez teniendo la base del foro, el diseño de la tabla en la base de datos y teniendo el conocimiento de cómo funciona nuestro sistema de templates, podemos iniciar la creación de la primera página, en la que se mostraran todos los temas de nuestro foro: Ejemplo de la página de index.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'); Ahora revisaremos paso a paso lo que ejecuta este script. Tenemos una serie de requires e includes. El inicial es el que contiene el primer Script que realizamos, el cual efectúa la conexión a la base de datos. El segundo contiene un archivo.php que contiene funciones de suma importancia en el foro, por mencionar alguno, mostrartemplate. El tercero es el que incluye un header genérico que usa para poder proporcionar a todas nuestras páginas, un diseño parecido. Ahí se puede colocar un logo del sitio por ejemplo y también 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 nuestra base de datos, que nos traerá todos y cada uno de los mensajes que son los iniciadores de un tema y cuyo identificador se encuentre en cero. Los mensajes restantes que sean respuestas a temas en particular poseerán en el campo identificador el valor del mensaje al que responden. A estos temas, le solicitamos a la base de datos que los ordene por fecha en este caso el de la última respuesta y de forma descendente, de esta forma en el foro tendremos los mensajes más recientes. Solo enseñaremos los temas de nuestro Foro si la cantidad de filas recuperadas desde la base son mayores a 0. Después, adentro del While principal: // 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); Se inicia a trabajar por primera instancia con los templates. Inicialmente procedemos a leer el contenido del template en memoria y después lo guardamos dentro de la variable $template. E incluimos un archivo, el cual contiene una fila de la tabla de Temas, con los títulos de las celdas. Con la función mostrartemplate se muestran los datos de cada tema. Para finalizar, agregaremos otro archivo HTML con el código para cerrar la página y exponer otro mensaje de Copyright. Así ya tenemos la página inicial del Foro en la cual se muestran los temas deseados. Lo que prosigue es la creación de formularios los cuales son necesarios para poder ingresar nuevos tópicos y sirven para responder cierto tema existente. Participar es la Base Vamos a utilizar el mismo formulario para poder crear un nuevo tema y para poder contestar un tema en particular. Esto se obtiene pasando una variable por el URL, e indicando que vamos a citar un mensaje anterior, adquiriendo de la base de datos el mensaje que queremos citar y así completar el formulario con esos datos. Si esta variable no se encuentra, entonces solo se muestra el
formulario. Ejemplo de la página de respuesta.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 podemos ver al primero que capturamos de la URL, las variables $id y $citar y si $citar es igual a 1, debemos consultar en la base de datos todos los datos del tema que citamos, para después agregarlo en el arreglo $row, el cual será trasladado al template. El l título del mensaje se antepone la cadena "Re:", indicando que es una respuesta y como al cuerpo del mensaje, si estamos citando, se le rodea por un tag [citar] y [/citar]. Ejemplo de la página 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> <td width="30%" align="right">titulo</td> <td><input type="text" name="titulo" value="<?=$titulo"></td> <tr>
<td width="30%" align="right">mensaje</td> <td><textarea name="mensaje" cols="50" rows="5"><?=$mensaje</textarea></td> <tr> <td colspan="2" align="center"><input type="submit" name="submit" value="enviar Mensaje"></td> </form> </table> Se puede ver como las variables están dentro de los atributos "value" de los inputs y el textarea. Además tenemos un campo escondido, nombrado "identificador", el cual tendrá un valor ya estipulado, cuando estemos contestando un mensaje, el cual no existirá cuando sea un mensaje nuevo. Solo queda ver el script que tiene como función grabar el mensaje en la base de datos, agregar.php. Ejemplo de la página de agregar.php require('configuracion.php'); $autor = $_POST["autor"]; $titulo = $_POST["titulo"]; $mensaje = $_POST["mensaje"]; $ident = $_POST["identificador"]; //Hacemos algunas validaciones if(empty($autor)) $autor = "Anónimo"; if(empty($titulo)) $titulo = "Sin título"; //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, después de tomar las variables desde el formulario (usando el método POST), verificamos que esté un nombre de autor y el título del mensaje, en caso contrario le establecemos un valor por defecto. Utilizaremos la función de PHP htmlentities() para convertir todos los caracteres especiales ( >, <, ", &,) en sus respectivas entidades HTML ( >, <, "e;, &). Con esto se logra evitar que los usuarios inserten código HTML en nuestro Foro. Lo que sigue será grabar el mensaje en la base y mediante la función 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 más, 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 Vamos al último paso que es el de crear la página que publicara un tema y las respuestas que haya en él. Para esa tarea, vemos como en el home de nuestro foro, mandamos llamar a un script foro.php y le damos el id del tema que deseamos ver. Después tenemos que conseguir de la base el tema, en los que el id sea igual al que pasamos, o también que el identificador (el campo que nos indica que ese mensaje es en respuesta a algún tema) sea el mismo al identificador, y procedemos a ordenarlo por fecha y listo. El template que usamos para mostrar cada uno de los mensajes, va a ser una tabla que incluya todos y cada uno de los datos necesarios como son: el autor del mensaje, el título, la fecha del mensaje, el mensaje mismo. Y de igual forma le agregaremos dos detalles más el primero será un link hacia el formulario que creamos previamente, de forma que el usuario pueda citar un mensaje en particular y por segundo un Anchor (también llamado Ancla) e
esta forma al responder a un mensaje, este acceda directamente al mismo por medio de su id en la base de datos. Ejemplo de la página 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> </table> <hr align="center" width="100%" size="2" noshade> <?=$mensaje</td> <tr> <td colspan="2" height="5"></td> </table> Procedemos a revisar el código PHP que utilizaremos para "parsear" este template: Ejemplo de la página de foro.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'); Siempre debemos incluir la conexión a la base de datos, el archivo de funciones y también validar que exista la variable $id, de lo contrario, nada podríamos hacer y nuestro foro fallaría en el Query. En lo que se refiere al Query, podemos ver como usamos la función de mysql DATE_FORMAT() que nos sirvió para convertir el formato por defecto del tipo datetime ( AAAA-MM-DD hh:mm:ss ) en algo que mucho más común para nuestro idioma ( DD/MM/AAAA hh:mm:ss ). Lo que más podemos destacar más de este script, son las dos transformaciones que le hicimos al mensaje, antes de ser enviado al template. Al iniciar usamos la función de PHP nl2br(), la cual convierte todos los saltos de línea, en tags <br />, de tal forma los saltos que el usuario ingrese en el textarea, son añadidos de forma correcta al exponer el mensaje. Después vimos como llamamos a la función parseartags(). Ejemplo de la página de funciones.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; Con esta función podemos agregar todas las modificaciones que deseamos que haga el mensaje, antes de ser mostrado en el Foro. En el ejemplo podemos notar como se ha implementado el uso de un tag propio, en este caso [citar]. El mismo, adentro de la función, será substituido por el código
HTML para destacar el citado del mensaje, todo esto debido a la función str_replace() de PHP. El tag se agrega de forma automáticamente y el cual notamos cuando se responde un mensaje. Esta función tiene la capacidad de ser personalizada de la forma que quieras, añadiendo todos los tags que desees, para darles a sus usuarios la libertad de darle formato a los mensajes. Por ejemplo podrían agregar un nuevo tag, para poner palabras en negritas, o probablemente cualquier expresión regular que pueda convertir de forma automática cualquier URL que presente en el mensaje o en un link. Misión Cumplida Poder realizar nuestro propio foro es sencillo, si sabemos utilizar correctamente mysql y PHP 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 utilización de funciones de PHP como: extract(); eval(); implode(); file(); nl2br(); mysql_insert_id(); str_replace(); La utilización de la función DATE_FORMAT() de MySQL. Cómo 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 más a la hora de programar nuestros scripts. Ahora, este sistema es muy básico, como simple. Así que de ahora en más, es campo fértil para que Uds. mismos puedan agregarle todas las características y funcionalidades que deseen, personalizando el foro a su gusto. Como ideas, puedo mencionarles algunas: Agregar más 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 más vistos.
La posibilidad de que los usuarios puedan utilizar firmas.