miércoles, 29 de abril de 2009

Manual de PHP 78. MySQL: Imágenes en Tablas

Peculiaridades de las tablas

Las tablas que han de contener imágenes deben tener campos del tipo BLOB, MEDIUMBLOB o LONGBLOB, pudiendo elegir aquel de ellos que más se adecue al tamaño, en bytes, de las imágenes que se desean guardar en la tabla.

Por si te has olvidado de los tipos de campos, aquí tienes un enlace para recordarlos.

En el ejemplo la hemos creado con un campo BLOB insertando también campos para recoger su nombre, su tamaño (en bytes), su formato (el tipo de fichero transferido) así como un campo autoincremental.


Desde este enlace -has de tener activo el servidor MySQL- podrás crear la tabla fotos e insertar automáticamente algunas imágenes de ejemplo.


Transferencia de la imagen

El formulario para realizar la transferencia de la imagen no tiene particularidades. Es un formulario como los de toda la vida. Lo único reseñable sería incluir un campo oculto en el que pudiera especificarse una restricción en cuanto al tamaño máximo permitido para cada imagen y que debe estar acorde con el tipo de campo utilizado en la tabla.


Comprobación del tipo de imagen

Al transferir imágenes jpg ó png el type MIME que recibía el servidor es distinto según el navegador que se utilice para hacer la transferencia.

Aquí más abajo, en el código fuente del script que actualiza la base de datos, tienes los nombres de esos tipos asociados a los navegadores más usuales.

Hay otro aspecto a tener en cuenta. Esa discriminación de tipos se plantea únicamente cuando Apache recibe una transferencia. Cuando se visualiza un contenido las cabeceras tipo de contenido (header("content-type: xx")) pueden ser las mismas para todos los navegadores. Esa es la razón por la que a la hora de incluir el formato en la tabla utilizamos image/jpg, image/gif o image/png.


¿Cómo guardamos la imagen?

La información recibida a través del formulario requiere un ligero retoque antes de incluirla en le campo BLOB de la tabla. Esa reconversión requiere abrir la imagen en modo binario (rb) -parece que solo en el caso de Windows– leer el fichero completo y añadirle \ antes de las comillas mediante addslashes.

Una vez hecho el retoque ya puede guardarse sin más problema.


PNG con transparencias en Internet Explorer

Internet Explorer no permite visualizar de forma automática las transparencias de las imágenes con formato png. Existen en la red algunos recursos que permiten solventar ese problema.

Hemos elegido uno de ellos –pngfix.js- que puedes ver en este enlace.

Se trata de un fichero JavaScript que basta incluir en la cabecera HMTL de la página de la forma que ves en el ejemplo de la parte derecha. Cuando un navegador IE es detectado se ejecuta una función contenida en ese fichero que analiza la página, busca imágenes con extensión png y les aplica la transparencia adecuada.

Por esa razón, es probable que inicialmente (al cargar la página) se visualice la imagen opaca y que, posteriormente, adquiera la transparencia.


Ver las imágenes

La lectura de una imagen utiliza solo dos instrucciones. Incluir la cabecera Header en el que se indica el tipo de contenido (el famoso nombre MIME de la imagen) y luego imprimir el contenido del campo.

Pero (por aquello de que header debe ir incluida en el script antes que cualquier otra salida) si pretendemos incluir en una página algo más que una imagen tendremos que invocar esas dos funciones, de forma independiente, para cada una de ellas.

Por esa razón, en el ejemplo que tienes al final, al desarrollar el ejemplo que permite visualizar todas las imágenes de la tabla hemos tenido que incluir un script que va leyendo la tabla que con contiene las imágenes para extraer los campos informativos y a la hora de ver la imagen hemos de recurrir a la misma técnica que se utilizaba para ver las imágenes dinámicas.

Es decir, poner una etiqueta de imagen de las de HTML pero -en vez de escribir el nombre de la imagen- poniendo incluyendo como nombre el del script que las visualiza y pasándole el número (valor del campo autoincremental) de la imagen que pretendí visualizar.


El problema de los PNG en IE

El JavaScript que asigna la transparencia a las imágenes en formato png las identifica buscando la coincidencia de los tres últimos caracteres del nombre de la imagen con la extensión png.

Cuando se trata de imágenes dinámicas el nombre de la imagen coinciden con el nombre de la llamada al script que se utiliza para su visualización. Por eso, para advertir a JavaScript de que se trata de una imagen png hemos incluido el condicional que puedes ver en el ejemplo. De esa forma, cuando se trata de una imagen en este formato incluimos en la petición una variable con el valor png de forma que pueda ser reconocida por pngfix.js y aplicada la transparencia requerida.


Creación de una tabla ejemplo


Lo primero de todo será disponer de una tabla en la que puedan guardarse imágenes. Aquí tienes un ejemplo.

<?
#el nombre de la tabla
$base="ejemplos";
#definimos otra variable con el NOMBRE QUE QUEREMOS DAR A LA TABLA
$tabla="fotos";
# establecemos la conexión con el servidor
$conexion=mysql_connect ("localhost","pepe","pepa");
#Seleccionamos la BASE DE DATOS en la que PRETENDEMOS CREAR LA TABLA
mysql_select_db ($base, $conexion);

$crear="CREATE TABLE IF NOT EXISTS $tabla (";
$crear.="num_ident INT(10) unsigned NOT NULL AUTO_INCREMENT,";
$crear.="imagen BLOB NOT NULL, ";
$crear.="nombre VARCHAR(255) NOT NULL DEFAULT '',";
$crear.="tamano VARCHAR(15) NOT NULL DEFAULT '',";
$crear.="formato VARCHAR(10) NOT NULL DEFAULT '',";
$crear.="PRIMARY KEY (num_ident))";

#Creamos la cadena, comprobamos si esa instrucción devuelve
# VERDADERO o FALSO
# y dependiendo de ellos insertamos el mensaje de exito o fracaso

if(mysql_db_query ($base,$crear ,$conexion)) {
echo "<h2> Tabla $tabla creada con EXITO </h2><br>";
}else{
echo "<h2> La tabla $tabla NO HA PODIDO CREARSE</h2><br>";
};

# cerramos la conexión... y listo...

mysql_close($conexion);
?>

Formulario para la transferencia de las imágenes

<FORM ENCTYPE="multipart/form-data" ACTION="ejemplo211.php" METHOD="post">
#con este input "oculto" establecemos el limite máximo
# del tamaño del fichero a transferir. En este ejemplo 65.000 bytes
<INPUT type="hidden" name="lim_tamano" value="65000">
<p><b>Selecciona la imagen a transferir<b><br>
<INPUT type="file" name="foto"><br>
<p><b>Título la imagen<b><br>
<INPUT type="text" name="titulo"><br></p>
<p><INPUT type="submit" name="enviar" value="Aceptar"></p>
</FORM>


ejemplo212.php

Ejemplo de transferencia de imagen


Script para actualizar la base de datos

<?
$foto_name= $_FILES['foto']['name'];
$foto_size= $_FILES['foto']['size'];
$foto_type= $_FILES['foto']['type'];
$foto_temporal= $_FILES['foto']['tmp_name'];
$lim_tamano= $_POST['lim_tamano'];
$foto_titulo= $_POST['titulo'];
/* limitamos los formatos de imagen admitidos a:
png que segun del navegador que ulicemos puede ser:
en IE image/x-png en Firefox y Mozilla image/png
jpg que puede tener como tipo
en IE image/pjpeg en Firefox y Mozilla image/jpeg
gif que tiene como tipo image/gif en todos los navegadores
Mira los comentarios al margen sobre la variable $extensión */
if ($foto_type=="image/x-png" OR $foto_type=="image/png"){
$extension="image/png";
}
if ($foto_type=="image/pjpeg" OR $foto_type=="image/jpeg"){
$extension="image/jpeg";
}
if ($foto_type=="image/gif" OR $foto_type=="image/gif"){
$extension="image/gif";
}
# condicionamos la inserción a que la foto tenga nombre,
# un tamaño distinto de cero y menor de límite establecido
# en el formulario y que la variable extensión sea no nula

if ($foto_name != "" AND $foto_size != 0
AND $foto_titulo !='' AND
$foto_size<=$lim_tamano AND $extension !=''){
/*reconversion de la imagen para meter en la tabla
abrimos el fichero temporal en modo
lectura "r" binaria"b"*/
$f1= fopen($foto_temporal,"rb");
#leemos el fichero completo limitando
# la lectura al tamaño de fichero
$foto_reconvertida = fread($f1, $foto_size);
#anteponemos \ a las comillas que pudiera contener el fichero
# para evitar que sean interpretadas como final de cadena
$foto_reconvertida=addslashes($foto_reconvertida);
# abrimos la base de datos y escribimos las intrucciones de inserción
# en el campo BLOB insertaremos la foto_reconvertida
$base="ejemplos";
$tabla="fotos";
$conexion=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $conexion);
$meter="INSERT INTO ".$tabla;
$meter .=" (num_ident, imagen, nombre, tamano, formato) ";
$meter .=" VALUES('','$foto_reconvertida','$foto_titulo',";
$meter .= "$foto_size, '$extension')";
if (@mysql_query($meter,$conexion)){
print "Foto guardada en la tabla";
}else{
print "Ha habido un error al guardar la foto";
}
}else{
echo "<h2>No ha podido transferirse el fichero</h2>";
}
mysql_close();
?>

Script para leer la base de datos

<html>
<head>
<!-- al margen te comentamos la razón por la que -->
<!-- se incluyen estas líneas en rojo -->
<!--[if IE ]>
<script type="text/javascript" src="pngfix.js"></script>
<![endif]-->
</head>
<body>
<?
$base="ejemplos";
$tabla="fotos";
$conexion=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $conexion);
$sacar = "SELECT * FROM ".$tabla;
$resultado = mysql_query($sacar,$conexion);
while ($registro = mysql_fetch_array($resultado)){
print "<center>Titulo de la imagen: ".$registro['nombre']."<br>";
/* la inclusión de este condicional obedece a los problemas que plantea
la visualización de las transparencias
de las imágenes png en Internet Explorer.
Al margen justificamos las razones de su inclusión */
if($registro['formato']=="image/png"){
print "<img src='ver_foto.php?n=".$registro['num_ident']."&v=png'><br>";
}else{
print "<img src='ver_foto.php?n=".$registro['num_ident']."'><br>";
}
print "Tamaño de la imagen: ".$registro['tamano']." bytes
</center>";

}
mysql_close();
?>
</body>
</html>

Script para leer imágenes de la base datos

<?
$numero=$_REQUEST['n'];
$base="ejemplos";
$tabla="fotos";
$conexion=mysql_connect ("localhost","pepe","pepa");
mysql_select_db ($base, $conexion);
$sacar = "SELECT * FROM ".$tabla." WHERE (num_ident=$numero)" ;
$resultado = mysql_query($sacar,$conexion);
while ($registro = mysql_fetch_array($resultado)){
$tipo_foto=$registro['formato'];
header("Content-type: $tipo_foto");
echo $registro['imagen'];
}
mysql_close();
?>


ejemplo209.php
Ver imágenes guardadas



Fuente:




No hay comentarios: