Ponga comentarios en su web

Poner comentarios en una página, puede parecer algo complejo, pero si pensamos que el código para insertar esos comentarios podemos usarlo en todas las páginas que deseemos simplemente añadiendo un par de líneas en el final de nuestra página php, ese trabajo será compensado.

Las dos líneas

El título puede parecer algo "fantasma" pero si una de esas líneas se refiere a la incrustación de un fichero en la página, se puede comprender mejor la afirmación.

$elemento = "tutorial.comentarios";
include("comentarios.php");

Como se puede ver, al tratarse de una instrucción include (php), el número de líneas realmente será la que tenga el fichero que se incluye. La línea anterior crea una variable que será la clave en la búsqueda e inserción de comentarios; a la vez podría servir para usos adicionales, por ejemplo, un contador de visitas.

Una tabla para los comentarios

La tabla tendrá que tener unos campos específicos además del campo de búsqueda antes mencionado. Un campo lo reservaremos para que se identifique el dueño del comentario, otro campo será el típico id que se auto incremente, que nos podría ayudar en las búsquedas, y en la ordenación; la fecha que se insertará con la del sistema, y el comentario en sí... Un añadido que tengo en este sistema de comentarios es un campo que indique que el comentario está activo, por si quisiéramos ocultarlo provisionalmente, o como en esta página para evitar comentarios "basura" como el spam (esto se comentará luego).

En resumen, la creación sería tal que:

CREATE TABLE `comentarios` (
  `id` int(11) NOT NULL auto_increment,
  `Nombre` varchar(255) NOT NULL default '',
  `fecha` timestamp(14) NOT NULL,
  `elemento` varchar(50) NOT NULL default '',
  `comentario` text NOT NULL,
  `activo` tinyint(1) NOT NULL default '1',
  PRIMARY KEY  (`id`)
) TYPE=MyISAM COMMENT='Comentarios de Artículos y Scripts';

Leyendo comentarios...

Vamos a omitir los detalles de la conexión de la base de datos (supongo que el lector sabrá buscar información al respecto), para centrarnos en los pasos importantes; suponiendo que se haya creado la base de datos sin problemas.

Por lo pronto hemos visto una asignación de la variable $elemento, en esta misma página tiene el valor "tutorial.comentarios", así que tan solo necesitamos una consulta a la base de datos tal como sigue:

$sql = "SELECT * FROM comentarios where elemento='$elemento' and activo='1' order by id desc";

Nótese que las condiciones de lectura en la base de datos son que el elemento sea los comentarios de la página actual, y que se encuentre activo. En principio todos los mensajes estarán activos, pero para ocultarlos, tan solo basta con modificar ese valor. Existe la posibilidad de tener el comentario inactivo e implementar algún sistema de activación, ya sea por el webmaster o por el propio usuario respondiendo un mensaje enviado al correo del interesado (este sistema está implementado así).

... y escribiendo.

En realidad lo único que necesitamos para insertar comentarios en nuestro sistema es un simple formulario, con un par de campos: el "$elemento" y el campo del comentario, aunque existen muchas posibilidades adicionales, como un sistema de enriquecimiento del texto con BBCodes, usando editores especiales como en de esta página: Editor de texto.

Luego el destino del formulario debe ser una página que inserte los datos del formulario con una istrucción sql:

$sql = "INSERT INTO comentarios ($campos) VALUES ($valores)";

Aunque parezca demasiado sencillo para ser cierto, un sistema de comentarios no es más que eso, pero un sistema así de sencillo sería demasiado vulnerable, y los visitantes con "dedo flojo" llenarían nuestra base de datos con mensajes vacíos o absurdos... y no hablemos de los robots que pululan por la red enviando spam a todo formulario que detectan.

Valoraciones

Hay muchos sistemas donde también se permite la valoración de la página (como en el caso de este tutorial). En este sistema hemos optado por un sistema con 10 estrellas, que equivalen a una puntuación del 1 al 10.

estrella Hemos partido de una imágen en forma de estrella, sin importar los colores (véase la imagen de la derecha).

Y hemos conseguido crear una imágen así: evaluación con un sencillo script que se ve a continuación...

<?
header
("Content-Type: image/png");

function 
rgbColor($fondo)    {
    
$red hexdec(substr($fondo02));
    
$green hexdec(substr($fondo22));
    
$blue hexdec(substr($fondo42));
    return array(
$red$green$blue);
}
// recibimos los datos:
// n = número de estrellas
// max = grosor de cada estrella (altura y anchura)
// fondo = fondo en formato rrggbb
// fondos = en formato r1g1b1-%_anchura-r2g2b2
//    donde:
//        r1g1b1 = color de fondo del color principal en formato rrggbb
//        %_anchura = porcentaje de la anchura del primer color (r1g1b1)
//        r2g2b2 = color de fondo en formato rrggbb

foreach ($_GET as $dato => $cual)    $$dato $cual;
$_n = (isset($n)) ? (int) $n 1;
$_tam = (isset($max)) ? $max:30;
$largura 30 $_n;
$imagen imagecreatetruecolor($largura30);

if (isset(
$fondo))    {
    
$rgb rgbColor($fondo);
    
$f imagecolorallocate($imagen$rgb[0], $rgb[1], $rgb[2]);
    
imagefill($imagen00$f);
}
elseif (isset(
$fondos))    {
    list (
$fondo1$ancho$fondo2) = explode("-"$fondos);
    
$largo2 $largura $ancho 100;
    
$rgb rgbColor($fondo1);
    
$f imagecolorallocate($imagen$rgb[0], $rgb[1], $rgb[2]);
    
imagefill($imagen00$f);
    
$imagen2 imagecreatetruecolor($largo230);
    
$rgb rgbColor($fondo2);
    
$f imagecolorallocate($imagen2$rgb[0], $rgb[1], $rgb[2]);
    
imagefill($imagen200$f);
    
imagecopy($imagen$imagen20000$largo230);
    
imagedestroy($imagen2);
}
else    {
    
$f imagecolorallocate($imagen000);
    
imagefill($imagen00$f);
}

$estrella imagecreatefrompng("estrella.png");
$rrggbb imagecolorat($estrella1515);
$rr = ($rrggbb >> 16) & 0xFF;
$gg = ($rrggbb >> 8) & 0xFF;
$bb $rrggbb 0xFF;

$color_fondo imagecolorallocate($estrella$rr$gg$bb);
imagecolortransparent($estrella$color_fondo);

for(
$i 0$i $_n$i ++)
    
imagecopy($imagen$estrella$i 300003030);
imagedestroy($estrella);

$rrggbb imagecolorat($imagen00);
$rr = ($rrggbb >> 16) & 0xFF;
$gg = ($rrggbb >> 8) & 0xFF;
$bb $rrggbb 0xFF;
$f imagecolorallocate($imagen$rr$gg$bb);
imagecolortransparent($imagen$f);

if (
$_tam != 30)    {
    
$nueva imagecreatetruecolor($_tam $_n$_tam);
    
$transpa imagecolorallocate($nueva255255255);
    
imagefill($nueva00$transpa);
    
imagecopyresized($nueva$imagen0000$_tam $_n$_tam$largura30);
    
$rrggbb imagecolorat($nueva11);
    
$rr = ($rrggbb >> 16) & 0xFF;
    
$gg = ($rrggbb >> 8) & 0xFF;
    
$bb $rrggbb 0xFF;
    
$color_fondo imagecolorallocate($nueva$rr$gg$bb);
    
imagecolortransparent($nueva$color_fondo);
    
imagepng($nueva);
    
imagedestroy($nueva);
}
else    {
    
imagepng($imagen);
}
imagedestroy($imagen);
?>

Algunas posibilidades para mostrar evaluaciones con el mismo script evaluación. Nótese que pueden existir estrellas con 2 colores.

... y distintas cantidades, tamaño y colores. evaluación.

Evaluando

En esta página se puede evaluar pinchando la estrella que nos interesa. Automáticamente cambiarán los colores de todas las estrellas afectadas. El código es:

function evalua(que)	{
	for (i = 1; i < 11; i ++)
		document.images["e__" + i].src = (i <= que) ?
			"../comentarios/estrellas.php?n=1&fondo=0000ff&max=20":
			"../comentarios/estrellas.php?n=1&fondo=eeeeee&max=20";
	document.forms.comentario.evaluacion.value = que;
}

Y cada estrella declarada de la siguiente manera:

<img
	src="estrellas.php?n=1&fondo=eeeeee&max=20"
	name="e__10"
	alt="evaluar"
	onclick="evalua(10)"
	style="margin: 0"
	title="Sobresaliente"
>

Un apunte importante: Si se usan funciones javascript para evaluar (o para cualquier otra cosa) debe considerarse la posibilidad de que nuestros visitantes tengan javascript desactivado, por lo que se deben tener alternativas como el uso de etiquetas " noscript ".

Seguridad

Será mejor que implementemos un sistema de validación para evitar mensajes vacíos. La mejor forma de validar es en el propio formulario y en la página receptora. Para más información, remito a otro tutorial: El abc de los formularios.

Con un sistema de validación podemos evitar los formularios vacíos, pero no podemos evitar los odiosos mensajes "spam", así que plantearemos otros sistemas de seguridad.

Captcha

Los códigos "captcha" son unos dibujos con letras y/o números que deben ponerse en un campo del formulario. Al tratarse de una imagen no se puede editar, así que es imposible cortar y pegar. Hay muchos ejemplos en la red, y resumiendo, se trata de guardar el valor captcha en una variable de sesión, de tal manera que tenemos que añadir una validación adicional en la recepción del formulario:

$validaCaptcha = ($_SESSION["captcha"] == $_POST["captcha"]);

Si bien es un sistema bastante efectivo, puede existir sistemas de reconocimiento de caracteres que obtengan el código, así que suele añadirse algún sistema de distorsión, o fondos fundidos (como en esta página), y en ocasiones se hace difícil reconocer esos caracteres, por lo que comentaré un sistema para cambiar el código hasta encontrar uno suficientemente legible.

Esta técnica es tan sencilla, como generar la variable de sesión captcha en la misma imágen. El resumen del código de la imagen de esta página (concerniente al código) es:

<?
session_start();
$_captcha = ""; $_ns = "0123456789";
for ($i = 0; $i < 6; $i ++)	$_captcha .= $_ns{rand(0, 9)};
$_SESSION["captcha"] = $_captcha;
// aquí el resto de código y cabecera de la imagen
?>

Ahora solo tenemos que refrescar la imagen (añadiendo algún parámetro adicional). En esta página se hace pinchando en la misma imagen:

<img src="captcha.php" onclick="this.src = 'captcha.php?azar=' + Math.random()" />

Estos códigos nos han dado un buen nivel de seguridad para evitar sistemas maliciosos en nuestro sistema de comentarios, pero siempre encontraremos un pero...

Activación por e-mail

Hasta ahora solo hemos considerado como campos obligatorios el propio mensaje y el código de seguridad (captcha), pero antes comenté algo de "dedos flojos", También puede darse el caso de los que no les importa escribir ese código, pero aprovecharse del anonimato para llenar nuestro sistema de comentarios de basura.

Nos encontramos con un nuevo dilema. No podemos obligar a nadie a dejar en nuestro sistema sus datos personales, así que tendríamos que añadir un nuevo campo en nuestra tabla de comentarios que bien podría llamarse "anonimato".

El sistema se completaría enviándo al interesado, un correo electrónico con una clave asociada a su comentario, y una página donde después de introducir esa clave cambie el campo "activo" de ese mensaje.

Ejemplo de generación de claves

Un sistema parecido al que se usa en este mismo sistema de comentarios es el que sigue:

<?
function generaClave($id)	{
	$p0 = 'KT2bAHW06oRhJxBtmSENVvYGUZlF1waOjyf5zsPIgnCLd9XQpq8Dcu7Miekr';
	$p1 = 'IUp5kmltbBh0OL6vyRGHNCdnSasriux8De2KTMqEFwVP9jWgcY7fXAQ1JoZ';
	$p2 = 'XWc5EqavPRGFCYmZMSVjTi1h6bnsDLz27Ogkl9Jxu8NHrdAopwKfe0tUIQ';
	$p3 = 'sMkt1giNVhLBD5A9PzC7QFvxefdHaumjWncbKEZGIY0Spyq2oJXOTRw6l';
	$p4 = 'sdhZwuq2irRWx8vNTFMPyQBm96fEOtY5aDcp7AeL0SlVG1HXzJgKnjCb';
	$p5 = 'dGrVsznTKcxwYQp5IOAUeWbuRj2vNCh0B6oFM9yatLf8EDiSHJg1mqZ';
	$p6 = 'Sft0FOyCPo8UVJBmpgHTeqsLMwhNGIRdc6xEuiYD7XWvQ2kKZjAb19';
	$p7 = 's7RDQkF2wiCEZrzGYcJaAhHBtVP5NjpO1vb69elKnToLdfSXgImWq';
	$p8 = 'VCKyWigOTX2quPFU7AzGl69trbcRaeZSpNI8MdJs0owk1EmvBHnf';
	$p9 = 'VLWiIK6Jr2ztXd9k8wQUNpYvqgoTSCE5MaecOhxHG0mlZAFbjDR';
	$p10 = '59VwWvA2MKIbULN7CkgmTcGEYPiyZBS6japdrRxof08OzeHDuX';
	$p11 = 'A7eLNsu6xXiwRtJqnMzQ2WPBHcmyphEGk0CjKg1OZvIVa5Tol';

	$clave = '';
	$clave .= $p0[$id % strlen($p0)];
	$clave .= $p1[$id % strlen($p1)];
	$clave .= $p2[$id % strlen($p2)];
	$clave .= $p3[$id % strlen($p3)];
	$clave .= $p4[$id % strlen($p4)];
	$clave .= $p5[$id % strlen($p5)];
	$clave .= $p6[$id % strlen($p6)];
	$clave .= $p7[$id % strlen($p7)];
	$clave .= $p8[$id % strlen($p8)];
	$clave .= $p9[$id % strlen($p9)];
	$clave .= $p10[$id % strlen($p10)];
	$clave .= $p11[$id % strlen($p11)];
	return $clave;
}
?>

En realidad el código se genera por un script php que se muestra a continuación:

function generaClave($id)	{
<?
	$letras = "ABCDEFGHIJKLMNOPQRSTUVWXYZ12567890abcdefghijklmnopqrstuvwxyz";
	$tamClave = rand(10, 20);
	$arrayLetras = str_split($letras);
	for ($i = 0; $i < $tamClave; $i ++)	{
		shuffle($arrayLetras);
		$p = implode("", $arrayLetras);
		echo "\t$"."p$i = '".substr($p, $i)."';\n";
	}
	
	echo "\n\t$"."clave = '';\n";
	for ($i = 0; $i < $tamClave; $i ++)
		echo "\t$"."clave .= $"."p$i"."[$"."id % strlen($"."p$i)];\n";
?>
	return $clave;
}

Claro que también pueden usarse primitivas del propio lenguaje como md5, sha1, crypt, etc.

Limpiando basura

También consideraremos un sistema de limpieza de mensajes no-activados, en un tiempo discreto, digamos un día... y por cierto, el valor del campo "activo", ahora deberá estar inicializado a cero (0 => inactivo)

Podemos incluir una rutina de limpieza de basura desde alguna página de administración o cada vez que se lean o escriban nuevos temas. Un código sencillo sería:

select *, datediff(now(), fecha) as transcurridos from comentarios
	where datediff(now(), fecha)>1 and activo=0;

La sentencia "select" del lenguaje sql sirve para obtener esos datos, así que puede ser útil en una sesión administrativa, pero si queremos hacerlo automáticamente deberiamos usar la sentencia "delete".

delete from comentarios where datediff(now(), fecha)>1 and activo=0;

Dándole vueltas a las gestiones administrativas, debemos tener cuidado de distinguir los comentarios que sólo se quieran tener no-activos de usar otro valor distinto del uno (1) y del cero (0).

Gestiones Administrativas

Para terminar mostramos como hacer el mantenimiento de nuestro siatema de comentarios, desde una página que preferentemente no sea pública, o como en este caso, con algún sistema que restrinja la modificación o borrado de datos mediante algún condicionante...

Un caso básico se puede ver en esta página, cambiando el nombre del gestor. Si usamos admin en vez de anónimo, podemos ver como cambia el avatar del gestor, y el color de la estrella, aunque tan solo se trata de un ejemplo (Los verdaderos privilegios del administrador no deben publcarse nunca... considérese a admin algo así como autorizado).

Tenemos un botón Para actualizar la fecha de revisión de comentarios. que al activarlo servirá para que la siguiente visita a esta página de gestión de comentarios, se muestren en la selección "nuevas" (por defecto), los comentarios realizados a partir de esa última revisión.

Además de la opción mencionada, aparecen los elementos que tienen al menos un comentario (podrían estar ocultos o inactivos)... En el momento que se encuentre algún comentario oculto, se habilita el botón destinado a mostrarlos, con la única opción de des-ocultarlo.

Para terminar, recomiendo no modificar los comentarios, salvo en elementos importantes. Nótese que algunos no son editables.