Tutorial: Crear un contador bonito en PHP
Después de una buena colección de gatillazos, parece que esta vez sí que va en serio y que el 20 de Diciembre se inaugurará la primera línea de Metro de Sevilla, una infraestructura que mi ciudad lleva esperando ya más de 30 años.
Para celebrar tan magno acontecimiento, decidí crear un avatar chulo para la ocasión que lucir en Sevilla21. Ya que estaba, me puse a hacer un contador en PHP, que pusiera, en er vivo y en er directo, el tiempo que queda hasta el día de la inauguración. Algo como esto:
Como veis, un efecto bastante estiloso, con el número de días actualizándose dinámicamente. (Lógicamente, si ves la imagen después del 20-D, saldrá un número negativo).
Aunque me costó un poco ponerlo en pie, crear una imagen de este tipo en PHP resulta bastante sencillo una vez se entera uno de lo básico. Aquí os explicaré como hacerlo, usando la biblioteca GD que suele venir incluida en cualquier versión decente de PHP.
Paso 1: Crear una imagen base
No toda la imagen de arriba se crea en PHP. En realidad, lo único que hace el script en PHP es añadir el número de días a una imagen base, que creé en GIMP:
Haciéndolo así, el script resultante en PHP es mucho más sencillo y corto. Además, puedo usar el mismo contador con otros diseños sin tener que tocar nada, y también, al mantenerse la parte dinámica a lo mínimo posible, se consigue reducir la carga que nuestro script crea en el servidor.
Paso 2: Decidir dónde va nuestro script
Es el momento de decidir dónde vamos a poner la imagen. Por ejemplo, en http://miblog.com/contador/contador.php. Creamos el directorio en nuestro hosting y subimos a él la imagen de base que hemos creado en el paso 1 y la fuente con la que queremos pintar los números (o el mensaje que sea). Yo he usado una fuente TrueType (fichero .ttf); GD admite varios otros tipos, pero en cada caso las funciones a usar son un poco diferentes. Además, las fuentes en TTF son las más comunes, y parece que están soportadas mejor por los PHPs que se instalan normalmente (mi hosting, por ejemplo, no tenía soporte para otro tipo de fuente). Así que os recomiendo usar también una fuente TrueType.
Paso 3: Crear el fichero del script
Cread un fichero .php en vuestro editor de texto favorito (en el ejemplo de arriba, se llamaría contador.php) y copiad en él el siguiente texto, que os servirá como base:
<?php
// Bloque 1: ubicación de cosas
$font = "/ruta/a/la/fuente/Fuente.ttf";
$im = ImageCreateFromPNG("./imagen_base.png");
// Bloque 2: inicialización de la imagen
imageantialias($im, TRUE);
$white = imagecolorallocate ($im, 255, 255, 255); //white background
$black = imagecolorallocate ($im, 0, 0, 0);
$grey = imagecolorallocate ($im, 164, 164, 164);
// Bloque 3: texto a escribir
$to_goal = ceil((mktime (0,0,0,12,20,2008)-time()) / 86400);
$text = "$to_goal";
// Bloque 4: coordenadas del texto
$size=45;
$box = imagettfbbox($size, 0, $font, $text);
$twidth = $box[2];
$tx = (imagesx($im) - $twidth)/2 - 2;
$ty = 65;
// Bloque 5: pintamos el texto
imagettftext($im, $size, 0, $tx+2, $ty+2, $grey, $font, $text);
imagettftext($im, $size, 0, $tx, $ty, $black, $font, $text);
// Bloque 6: devolvemos la imagen
header ("Content-type: image/x-png");
imagepng ($im);
imagedestroy($im);
?>
Este es el fichero que genera mi contador; ahora será el momento de que lo modifiquéis a vuestro gusto. (Tened cuidado de que no haya ningún espacio justo después del ?> que acaba el fichero, ni antes del <?php que lo empieza).
El código del «bloque 1» indica dónde encontrar las dos cosas básicas para construir la imagen final: la imagen de base y la fuente con la que pintar los números. Ambas cosas las subimos ya al servidor en el paso 2. En la primera línea ($font = ...) ponemos el lugar donde está la fuente, que, como os indiqué más arriba, es TrueType (.ttf). En la segunda línea, tendréis que cambiar el nombre de la imagen de base que uséis; yo he usado PNG para este ejemplo, pero hay varias funciones que cargan JPEGs y otros formatos en vez de PNG.
Si la imagen de base está en el mismo directorio que el script, no hace falta escribir toda la ruta; con preceder el nombre de imagen con «./» (la forma Unix de decir «en este mismo directorio») basta. Por desgracia, con la fuente no hay la misma suerte, y para asegurarnos de que funcione hay poner el lugar completo en el que está. Por ejemplo, si la fuente es «Sans.ttf» y la queremos subir a http://miblog.com/contador, lo más seguro es que el valor correcto para $font no sea /contador/Sans.ttf, sino algo más parecido a /home/usuario/www/contador/Sans.ttf. Si acaso no tenemos claro qué valor poner, un modo de averiguarlo es dejar la línea tal cual de momento; cuando ejecutemos el script por primera vez, PHP nos lanzará un error donde se incluirá la ruta completa al script, que podremos copiar y pegar convenientemente.
En las siguientes cuatro líneas (Bloque 2), le indicamos a GD que queremos que nuestra imagen esté suavizada (antialisada), para que el resultado final sea agradable a la vista, y creamos tres variables que referencian a tres colores: el blanco, el negro y el gris. En realidad, sólo usaremos dos (negro y gris), pero GD asume que el primer color que se pide con imagecolorallocate es el de fondo de la imagen. En principio, no debe variar el resultado final, pero es buena costumbre escoger uno más o menos adecuado a la imagen usada como base.
A continuación, escogemos el texto a escribir (Bloque 3). Para ello, hacemos un cálculo en la variable $togoal, que viene a ser calcular la diferencia en segundos entre las doce de la madrugada del 20 de Diciembre de 2008 (dado por mktime) y el tiempo actual, dividir por 86400 (número de segundos en un día) y redondear hacia abajo. En la variable $text se guarda el texto a pintar. Podéis modificar este cálculo, así como la propia asignación de $text, para poner vuestro propio mensaje y contador.
En el siguiente bloque (Bloque 4), escogemos el tamaño del texto ($size), y se hacen algunos cálculos para encontrar las coordenadas en las que pintar nuestro mensaje. De momento, GD no permite centrar automáticamente el mensaje; sólo permite escribirlo justificado a la izquierda, a partir de unas coordenadas fijas. Así que, en primer lugar, calculamos el ancho de nuestro texto usando la función imagettfbbox y lo almacenamos en la función $twidth. La coordenada X en la que escribir ($tx) para que nos quede bien centradito será el ancho de la imagen (imagesx($im)), menos el ancho del mensaje, dividida por dos (este truco funciona siempre); el -2 que aparece es para que el texto quede un poquito a la izquierda de donde le correspondería, para que nos quepa bien la sombra. Aunque, en este caso, la coordenada Y ($ty) tiene un valor fijo, podríamos haber hecho cualquier otro cálculo para encontrar su valor.
Ya casi estamos. En el Bloque 5 se pinta el texto en la imagen propiamente dicha, en las coordenadas $tx y $ty que calculamos en el bloque 4. Para ello, usamos la función imagettftext, que dibuja sobre la imagen ($im) una cadena de texto ($text) con el tamaño, color y coordenadas que le digamos. Lo pintamos dos veces: una en gris, ligeramente desplazado (2 píxeles hacia abajo y hacia la derecha), y luego otra, en su posición correcta, en negro. De esta forma, nos queda el número en negro sobre la sombra gris, como el resto del texto de la imagen de base. Ya tenemos en $im la imagen que queremos devolver al navegador.
Finalmente (Bloque 6), le indicamos al navegador que lo que vamos a devolverle no es una página web, sino una imagen en PNG (header...), y luego volcamos nuestra imagen en formato PNG a la salida (imagepng...) antes de liberar la memoria que usa (imagedestroy...). Es posible devolver otro tipo de imagen (JPG, por ejemplo) cambiando el tipo MIME por el que queramos y usando imagejpeg o algo similar en vez de imagepng al final del fichero.
Es posible que os suene ver las órdenes header siempre al principio de los ficheros PHP. En efecto, normalmente se ponen antes que nada más, pero hay un problema si las usamos para indicar que lo que devolvemos es una imagen. Si tenemos algún error en nuestro script, el PHP escribirá el típico «Parse error en la línea tal», que suele ser muy útil para encontrar el sitio exacto donde está el fallo. Pero, si para entonces ya hemos mandado la orden header, el navegador pensará que lo que le llega no es texto, sino una imagen, y se confundirá. Por ese motivo, no mandamos la cabecera hasta que no nos queda más remedio.
Paso 4: Subir el script al servidor
Ahora es el momento de subir el script a nuestro servidor, junto al fichero de la fuente (.ttf) y la imagen de base. Lo abrimos con nuestro navegador y, si todo ha ido bien, ya podremos ver una imagen. Posiblemente, ahora tendremos que ir haciendo pequeños ajustes (tamaño de fuente, cálculo de $tx y $ty, colores…) para que nos quede de la mejor forma posible; para ello, vamos modificando el script hasta estar contentos del todo con el resultado.
Paso 5 (opcional): Añadir una redirección
Un problema que puede darse es que la imagen que devuelve el contador, aunque es una imagen PNG de pleno derecho, tiene extensión .php. En algunos sitios (los avatares de los foros, por ejemplo), normalmente no dejan enlazar a nada que no tenga una extensión típica de imagen.
Para solucionar este problema, necesitamos ayuda del servidor Web. En particular, si usamos Apache, podemos añadir una redirección que nos cree una imagen «virtual» con extensión PNG (o la que sea), usando ficheros .htaccess. Por ejemplo, si el contador está en http://miblog.com/contador/contador.php y queremos que sea accesible también desde http://miblog.com/contador/contador.png, creamos un fichero .htaccess (o modificamos el que ya haya) en el directorio contador del hosting y escribimos en él lo siguiente (todo es una sola línea):
RedirectMatch permanent contador.png http://miblog.com/contador/contador.php
Obviamente, habrá que cambiar la dirección (miblog.com/contador) por la correcta.
Con esta orden, siempre que alguien pida el fichero «contador.png» en ese directorio, Apache le mandará al fichero PHP que genera nuestro contador. Así, podemos usar http://miblog.com/contador/contador.png en cualquier sitio donde nos lo pidan. Fijaros que, aunque el nombre «virtual» se pone tal cual (contador.png) en la orden RedirectMatch, para especificar el destino hace falta poner el enlace completo (http://miblog...).
Con esto, ya tenemos nuestro contador PHP personalizado y accesible mediante un nombre de imagen (enlazable sin problemas en foros, blogs, etc). Podéis usar el mismo principio para crear banners dinámicos y cualquier otra cosa que se os ocurra; GD es bastante potente y tiene muchas primitivas gráficas con las que dibujar.
Espero que el tutorial os haya sido útil 🙂 Aquí tenéis algunas referencias por si queréis leer más: The Site Wizard, PHP Tutorial, y, por supuesto, la documentación online de GD.
Colgado: octubre 7th, 2008 en Tutoriales.
Tags: contador, dinámica, imagen, php, tutorial