sábado, 21 de febrero de 2009

Manual de PHP 52. Imágenes con líneas y textos.

Trazando segmentos

La función PHP que permite dibujar segmentos rectilíneos es la siguiente:

imageline($nom,x0, y0,x1,y1,$col)

donde: $nom es el nombre de la variable definida mediante imagecreate, x0 e y0 son las coordenadas de uno de los extremos; x1 e y1 son las coordenadas del otro extremo y $col es la variable de color con el que será dibujada la línea.

Colores de fondo

Tal como puedes observar en los primeros ejemplos de esta página, PHP utiliza como fondo de la imagen el primer color definido por la función:

ImageColorAllocate.

Esta opción de PHP nos obliga a definir dos colores distintos para conseguir la visibilidad de las líneas.

Crear transparencias

Si deseamos que un color determinado se comporte como si fuera transparente debemos utilizar la función:

imagecolortransparent ($nom ,$col).

donde: $nom es el nombre de la variable definida mediante imagecreate, y $color es el color que pretendemos hacer transparente.

No olvides estos dos pequeños detalles:

• Si pretendes lograr un fondo transparente debes hacer transparente el primero de los colores definidos.
• Esta función sólo tiene sentido en imágenes PNG que son las únicas que permiten zonas transparentes. Recuerda que JPG no las permite.

Insertando textos

Para insertar textos dentro de una imagen hemos de recurrir a una de estas funciones:

imagechar ($im, n, x, y, $txt, $col)

Requiere que la variable $txt contenga una cadena definida con anterioridad. Mediante esta función se inserta el primer carácter de la cadena con orientación horizontal.

Los parámetros de la función son los siguientes:

$im el nombre de la variable con la que fue definida por imagecreate

n es un número comprendido entre UNO y CINCO que asigna el tamaño de la letra de menor a mayor.

x e y son las coordenadas del punto donde se colocará la esquina superior izquierda del carácter a representar.

$txt es la cadena de texto de la que se extraerá el primer carácter, el único que se verá en la imagen.

$col es el color del carácter a representar.

imagecharup ($im, n, x, y, $txt, $col)

Su funcionamiento es similar al de la función anterior, con la única diferencia de que inserta el carácter con orientación vertical.

Las coordenadas de inserción también se corresponden con las de la esquina superior izquierda del carácter pero, recuerda que ahora estará girado y que, por lo tanto, ese punto coincidirá con parte inferior izquierda de la imagen del carácter.

imagestring ($im, n, x, y, $txt, $col)

Esta función se comporta de forma similar a imagechar. La única diferencia entre ambas es que mientras imagechar inserta sólo el primer carácter, en el caso de imagestring se inserta la cadena completa.

Los parámetros de ambas funciones son los mismos.

Si la cadena desborda los límites de la imagen sólo se visualizará la parte de la misma contenida dentro de éstos.

imagestringup ($im, n, x, y, $txt, $col)

Inserta una cadena completa con orientación vertical y sus parámetros son idénticos a los comentados cuando nos hemos referido a imagecharup.

Tipos de letra

Todas las funciones anteriores utilizan siempre la fuente predefinida por PHP y sólo permiten los cinco tamaños que hemos podido ver en los ejemplos.

Afortunadamente –lo veremos en la página siguiente– PHP también permite usar fuentes TrueType y aplicarlas en la creación de imágenes.


Dibujando segmentos


Aunque presentaremos únicamente el código fuente de una de las imágenes, para hacer la comprobación de las funciones y las diferencias de visualización insertaremos dos ejemplos,
uno en formato PGN y otro en JPG.


Recuerda que las únicas diferencias entre ambos radican en utilizar: Header("Content-type: image/png") o Header("Content-type: image/jpeg") y en las funciones Imagepng ó Imagejpeg.

<?
Header("Content-type: image/png");
$im = imagecreate(200,200);
$fondo=ImageColorAllocate ($im,0,0,255);
$linea=ImageColorAllocate ($im,255,255,255);

imageline($im,0,0,200,200,$linea);

Imagepng($im);
Imagedestroy($im);
?>

Ver img_a1.php
Formato PNG
Ver img_a2.php
Formato JPG


Fondos transparentes


<?
Header("Content-type: image/png");
$im = imagecreate(200,200);
$fondo=ImageColorAllocate ($im,0,0,255);
$linea=ImageColorAllocate ($im,255,0,0);
imagecolortransparent ($im ,$fondo);
imageline($im,0,0,200,200,$linea);
Imagepng($im);
Imagedestroy($im);
?>

Ver img_a3.php
Formato PNG
Ver img_a4.php
Formato JPG



Aquí tienes una página -con un color de fondo- en la que puedes visualizar las diferencias entre los dos formatos.




Insertando caracteres


<?
Header("Content-type: image/png");
$im = imagecreate(150,150);
$t1="Tamaño 1";
$t2="Tamaño 2";
$t3="Tamaño 3";
$t4="Tamaño 4";
$t5="Tamaño 5";
$fondo=imagecolorallocate ($im, 0, 0, 200);
$amarillo=imagecolorallocate ($im, 255, 255,0);
imagechar ($im, 1, 0, 0, $t1, $amarillo);
imagechar ($im, 2, 20, 20, $t2, $amarillo);
imagechar ($im, 3, 40, 40, $t2, $amarillo);
imagechar ($im, 4, 60, 60, $t2, $amarillo);
imagechar ($im, 5, 80, 80, $t2, $amarillo);
Imagepng($im);
imagedestroy($im);
?>

Ver img17.php
Formato PNG
Ver img18.php
Formato JPG

<?
Header("Content-type: image/png");
$im = imagecreate(150,150);
$t1="Tamaño 1";
$t2="Tamaño 2";
$t3="Tamaño 3";
$t4="Tamaño 4";
$t5="Tamaño 5";
$fondo=imagecolorallocate ($im, 0, 0, 200);
$amarillo=imagecolorallocate ($im, 255, 255,0);
imagecharup ($im, 1, 10, 10, $t1, $amarillo);
imagecharup ($im, 2, 20, 20, $t2, $amarillo);
imagecharup ($im, 3, 40, 40, $t2, $amarillo);
imagecharup ($im, 4, 60, 60, $t2, $amarillo);
imagecharup ($im, 5, 80, 80, $t2, $amarillo);
Imagepng($im);
imagedestroy($im);

?>

Ver img19.php
Formato PNG
Ver img20.php
Formato JPG

<?
Header("Content-type: image/png");
$im = imagecreate(150,150);
$t1="Tamaño 1";
$t2="Tamaño 2";
$t3="Tamaño 3";
$t4="Tamaño 4";
$t5="Tamaño 5";
$fondo=imagecolorallocate ($im, 0, 0, 200);
$amarillo=imagecolorallocate ($im, 255, 255,0);
imagestring ($im, 1, 10, 20, $t1, $amarillo);
imagestring ($im, 2, 10, 40, $t2, $amarillo);
imagestring ($im, 3, 10, 60, $t3, $amarillo);
imagestring ($im, 4, 10, 80, $t4, $amarillo);
imagestring ($im, 5, 10, 100, $t5, $amarillo);
Imagepng($im);
imagedestroy($im);
?>



img21.php
Ver img21.php
Formato PNG
Ver img22.php
Formato JPG

<?
Header("Content-type: image/png");
$im = imagecreate(150,150);
$t1="Tamaño 1";
$t2="Tamaño 2";
$t3="Tamaño 3";
$t4="Tamaño 4";
$t5="Tamaño 5";
$fondo=imagecolorallocate ($im, 0, 0, 200);
$amarillo=imagecolorallocate ($im, 255, 255,0);
imagestringup ($im, 1, 10, 100, $t1, $amarillo);
imagestringup ($im, 2, 20, 100, $t2, $amarillo);
imagestringup ($im, 3, 40, 100, $t3, $amarillo);
imagestringup ($im, 4, 60, 100, $t4, $amarillo);
imagestringup ($im, 5, 80, 100, $t5, $amarillo);
Imagepng($im);
imagedestroy($im);
?>

Ver img23.php
Formato PNG
Ver img24.php
Formato JPG







viernes, 20 de febrero de 2009

La Nintendo DSi llega a Europa


Como se puede ver en la propia página de Nintendo, la consola DSi (la sustituta de la actual Nintendo DS) se pondrá a la venta en Europa el día 3 de abril. Ya sabes, si estás pensando en comprarle una nueva consola a tus hijos y puedes esperar unos días....

Entre las ventajas de la nueva consola que se pueden leer en la propia página están la inclusión de una segunda cámara con más efectos y detección (rostros, movimientos supongo que para nuevos juegos), mejoras en el sistema de sonido, posibilidad de reproducir música, unas pantallas más grandes y con mayor resolución y finalmente que son más ligeras y estrechas. Además de ello incluye wifi y un navegador para buscar información por Internet o incluso descargar nuevos juegos desde la propia consola.

La desventaja, el precio, que si como adelantan en algunas páginas web parece que finalmente se sitúa entre los 170 - 180 € hará que la antigua todavía tenga vida durante meses.

jueves, 19 de febrero de 2009

Manual de PHP 51. Imágenes dinámicas: Creación de imágenes

Creación de imágenes dinámicas

Una imagen dinámica es tan sólo un script que contiene las instrucciones para la creación de esa imagen.

Para visualizar una imagen dinámica desde una página web basta con invocar el fichero que contiene el script desde la etiqueta clásica de inserción de imágenes de HTML
<img src="imgxx.php">






donde imgxx.php será el nombre del script que genera la imagen.

Primera etiqueta

Una vez conocidos los formatos que soporta nuestra versión, ya podemos generar imágenes utilizando cualquiera de esos formatos.

Trabajaremos con dos de ellos: JPG y PNG.

La primera instrucción que ha de contener cualquier script que deba generar imágenes ha de ser la siguiente:

Header("Content-type: image/jpeg")

si se trata de crear una imagen JPG o:

Header("Content-type: image/png")

si pretendemos que la imagen tenga formato PNG.

¡Cuidado!

Cualquier etiqueta header (cabecera) ha de incluirse obligatoriamente al comienzo del script antes que ninguna otra instrucción y sin ninguna línea en blanco que la preceda.

Pondremos siempre estas instrucciones inmediatamente debajo de sin que las separe ninguna línea en blanco.

Creación de imágenes

Definida la etiqueta anterior tenemos que: crear la imagen, dibujarla y luego enviarla al navegador para que pueda ser visualizada y, por último, (no es imprescindible pero si muy conveniente) borrarla, con el fin de liberar la memoria del servidor ocupada durante el proceso de generación de la misma.

Estas son las funciones PHP para esos procesos:

$nom = imagecreate(anc,al)

Con esta función se crea una imagen del tamaño indicado en los parámetros anc y al (en pixels) que será recogida en la variable nom.

Esta función es idéntica para cualquier formato de imagen.

Envío de imágenes al navegador

Para enviar imágenes al navegador (visualización) se usan funciones diferentes según el tipo de imagen definida en Header.

Si pretendemos que la imagen tenga formato JPG habremos puesto en Header la indicación jpeg (¡cuidado! observa la sintaxis... jpeg). En este caso la función de visualización será:

Imagejpeg($nom)

Si se tratara de una imagen en formato PNG (recuerda que debe estar definido en Header) la sintaxis sería:

Imagepng($nom)

Eliminando imágenes de la memoria

Para borrar imágenes de la memoria del servidor (que no del navegador) se utiliza la siguiente sintaxis:

Imagedestroy($nom)

Creando colores

PHP permite crear una paleta de colores. Para ello se pueden crear variables de color (con independencia del formato utilizado) mediante la siguiente función:

$color=imagecolorallocate ($nom,R,G,B)

donde la variable recoge el color resultante de mezclar los colores primarios indicados en R, G y B que serán números enteros comprendidos entre 0 y 255 y que especifican la intensidad de las luces roja, verde y azul utilizadas para la obtención del color.

Se pueden definir tantos colores como se deseen tan sólo con utilizar nombres de variables distintos para cada uno de ellos.

Aplicar colores de fondo

Para aplicar un color de fondo a una imagen (no importa el tipo del formato) se utiliza la siguiente función:

Imagefill($nom,x,y,$col)

Aquí $nom es la variable que contiene la imagen, x e y son las coordenadas del punto de la imagen a partir del cual se aplica el relleno y $col el color (previamente definido) que se pretende aplicar a la imagen.

Mediante esta función todos los puntos colindantes con el de coordenadas x,y que tengan su mismo color serán rellenados con el color especificado en la variable $col.

Rectángulos sin relleno

Para dibujar un rectángulo sin relleno (solo las líneas) se utiliza la siguiente función:

imagerectangle($nom, x0, y0, x1, y1, $col)

Donde $nom es el nombre de la imagen, x0, y0 son las coordenadas del vértice superior izquierdo y x1, y1 las coordenadas del vértice inferior derecho y $col el color que pretendemos asignar a las líneas del rectángulo.

El punto (0,0) siempre es la esquina superior izquierda de la imagen y recuerda que si no usas –en las líneas– un color distinto al del fondo no se visualizará el rectángulo.

Rectángulos con relleno

Para dibujar un rectángulo con relleno se utiliza la siguiente función:

imagefilledrectangle( $nom, x0, y0, x1, y1, $col)

Los parámetros son idénticos a los del caso anterior con la única diferencia de que en este caso el rectángulo aparecerá relleno con el color elegido.

Polígonos con relleno

Para colorear el fondo de un polígono son necesarias dos operaciones:
  • Crear un array con las coordenadas de cada uno de sus vértices.
  • Aplicar la función que dibuja polígonos de este tipo.
La creación del array podría hacerse así:

$v=(x0, y0, x1, y1,... xn, yn )

donde se irían introduciendo las coordenadas de los sucesivos vértices del polígono (x e y de cada vértice).

La creación de un polígono de este tipo requiere la siguiente función:

imagefilledpolygon($nom, $vert, nº vert , $col)

donde $nom es el nombre de la imagen, $vert es el array que contiene las coordenadas de los vértices, nº vert es el número de vértices y $col es el color de relleno.

Polígonos sin relleno

Su funcionamiento es idéntico al anterior en tanto requiere que se defina el array de coordenadas de los vértices y los parámetros de la función son los mismos indicados en el caso anterior. Sólo se modifica el nombre de la función que en este caso es:

imagepolygon($nom, $vert, nº vert , $col)

Elipses, circunferencias y arcos

Una misma función nos permite dibujar elipses, circunferencias y arcos. Es la siguiente:

imagearc($nom, Xc, Yc , a, b, Gi, Gf, $col)

Los parámetros de esta función son los siguientes:
  • $nom es el nombre de la imagen.
  • Xc e Yc las coordenadas del centro de la elipse.
  • a es la longitud del eje horizontal de la elipse.
  • b es la longitud del eje vertical de la elipse.
  • Gi es el punto inicial del arco y se expresa en grados sexagesimales.
  • Gf es el punto final del arco también en grados sexagesimales.
  • $col es el color con el que se dibujará la línea.
Respecto a los ángulos, CERO GRADOS coincide con el cero trigonométrico pero el sentido es contrario, es decir, el de las agujas del reloj.

Obviamente, para dibujar una circunferencia basta con hacer iguales los valores de a y de b y fijar los puntos inicial y final en 0º y 360º respectivamente.

Dibujando sobre una imagen de fondo

PHP permite crear imágenes utilizando como fondo una preexistente. Para ello basta con crear una variable indicando el path y el nombre de la imagen, por ejemplo:

$b="./images/cruz.jpg"

El formato de esta imagen debe coincidir con el de la que pretendemos construir.

Una vez definida esta variable bastará sustituir la instrucción de creación de imagen

$nom = imagecreate(x,y)

por:

$nom= imagecreatefrompng ($b)

en el caso de imágenes PNG o por:

$nom= imagecreatefromjpeg ($b)

s
i se tratara de imágenes en formato JPG.

El resultado del cambio en el primero de los casos es este y aquí tienes también la imagen obtenida utilizando un fondo en formato JPG.

Una advertencia al respecto. Como puedes comprobar en los ejemplos, el tamaño de la imagen es el mismo de la utilizada como fondo.


Guardando imágenes

Las imágenes que son creadas mediante la sintaxis anterior no se guardan en servidor.

Si se pretende guardarlas hay que modificar la sintaxis de las etiquetas:

Imagepng($nombre)

o

Imagejpeg($nombre)

añadiendo otro parámetro con el nombre y la extensión del fichero que vamos de guardar. Así por ejemplo:

Imagepng($nombre, "mi_imagen.png")

o

Imagejpeg($nombre, "mi_imagen.jpg")

guardarían en el servidor las imágenes creadas con los nombres mi_imagen.png o mi_imagen.jpg



Una primera imagen


<?
Header("Content-type: image/jpeg");

$im = imagecreate(200,200);

Imagejpeg($im);

Imagedestroy($im);

?>
No dejes NUNCA líneas en blanco entre la etiqueta <? de comienzo del script y la línea que contiene Header

Si escribiéramos el script anterior sustituyendo image/jpeg por image/png e Imagejpeg($im) por Imagepng($im) no visualizaríamos nada.

El formato jpg –a falta de especificaciones– considera la imagen con negro como color de fondo, pero png requiere que ese color sea especificado.






Añadir un color de fondo


<?
Header("Content-type: image/jpeg");

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);

Imagefill ($im, 0, 0, $fondo);

Imagejpeg($im);

Imagedestroy($im);
?>

<?
Header("Content-type: image/png");

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);

Imagefill ($im, 0, 0, $fondo);
Imagepng($im);
Imagedestroy($im);
?>



Dibujar un rectángulo sin relleno

<?
Header("Content-type: image/jpeg");
$im = imagecreate(200,200);
$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255)
;
Imagefill ($im, 0, 0, $fondo);

imagerectangle ($im, 10, 10, 190, 190, $blanco);

Imagejpeg($im);

Imagedestroy($im);

?>

<?
Header("Content-type: image/png");

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);

Imagefill ($im, 0, 0, $fondo);

imagerectangle ($im, 10, 10, 190, 190, $blanco);

Imagepng($im);

Imagedestroy($im);

?>



Dibujando un rectángulo con relleno



<?
Header("Content-type: image/jpeg");

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);

imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

Imagejpeg($im);

Imagedestroy($im);

?>

<?
Header("Content-type: image/png");


$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);

imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

Imagepng($im);

Imagedestroy($im);

?>



Dibujando un polígono relleno



<?
Header("Content-type: image/jpeg");

$esquinas=array(20,100,100,180,180,100,100,20);

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

imagefilledpolygon ($im, $esquinas, 4, $blanco);

Imagejpeg($im);

Imagedestroy($im);

?>

<?
Header("Content-type: image/png");

$esquinas=array(20,100,100,180,180,100,100,20);

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

imagefilledpolygon ($im, $esquinas, 4, $blanco);

Imagepng($im);

Imagedestroy($im);

?>



Dibujando un polígono sin relleno



<?
Header("Content-type: image/jpeg");

$esquinas=array(20,100,100,180,180,100,100,20);

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

imagepolygon ($im, $esquinas, 4, $blanco);

Imagejpeg($im);

Imagedestroy($im);

?>



<?
Header("Content-type: image/png");

$esquinas=array(20,100,100,180,180,100,100,20);

$im = imagecreate(200,200);

$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);

imagepolygon ($im, $esquinas, 4, $blanco);

Imagepng($im);

Imagedestroy($im);

?>



Dibujando circunferencias, elipses y arcos



<?
$esquinas=array(20,100,100,180,180,100,100,20);
$im = imagecreate(200,200);
$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);
imagepolygon ($im, $esquinas, 4, $blanco)
;

imagearc ($im, 100, 100, 160, 160, 0, 360, $fondo);
imagearc ($im, 100, 100, 160, 100, 0, 360, $rojo);

Imagejpeg($im);

Imagedestroy($im);

?>

<?
Header("Content-type: image/png");
$esquinas=array(20,100,100,180,180,100,100,20);
$im = imagecreate(200,200);
$fondo=imagecolorallocate ($im, 0, 0, 200);
$blanco=imagecolorallocate ($im, 255, 255, 255);
$amarillo=imagecolorallocate ($im, 255, 255,0);
Imagefill ($im, 0, 0, $fondo);
imagerectangle ($im, 10, 10, 190, 190, $blanco);
imagefilledrectangle ($im, 20, 20, 180, 180, $amarillo);
imagepolygon ($im, $esquinas, 4, $blanco)
;

imagearc ($im, 100, 100, 160, 160, 0, 360, $fondo);
imagearc ($im, 100, 100, 160, 100, 0, 360, $rojo);

Imagepng($im);

Imagedestroy($im);

?>



Utilizando imágenes dinámicas


En todos los ejemplos anteriores hemos podido visualizar las imágenes con sólo llamarlas desde el navegador, de la misma forma que podríamos visualizar cualquier otra imagen.


Pero las imágenes dinámicas pueden ser insertadas en una página web de la misma forma que cualquier otra imagen.


Aquí tienes un ejemplo donde se recogen en una página web todas las imágenes dinámicas creadas anteriormente.







Manual de PHP 50. Imágenes dinámicas

Imágenes dinámicas

PHP permite la creación dinámica de imágenes. Quiere esto decir que una imagen puede ser presentada en la página web sin necesidad de ser almacenada previamente en el servidor y, además, con un contenido que puede ser modificado en cada instante.

Esta posibilidad que ofrece PHP puede resultar muy útil a la hora de presentar gráficos estadísticos ya que permitiría utilizar valores actuales obtenidos, por ejemplo, de una base de datos.

Requisitos del sistema

El manejo de imágenes dinámicas requiere que esté instalada la librería de PHP llamada php_gd2.dll.

En la versión de PHP que estamos manejando se instala por defecto, pero requiere que la configuración de fichero php.ini tenga activada esta extensión.

Para activarla deberás editar el fichero php.ini, buscar la línea que dice: ;extensions=php_gd2.dll y quitar el punto y coma que lleva delante.

A esto se le llama en el argot descomentar esa línea. Las líneas de comentario en el fichero php.ini empiezan por ese signo de puntación.


Comprobación

Una vez que hayamos modificado php.ini –recuerda que debemos hacerlo con el servidor Apache apagado– activaremos de nuevo Apache y ejecutando info.php encontraremos algo similar a lo que ves en esta tabla:

GD
GD Support enabled
GD Version bundled (2.0.34 compatible)
FreeType Support enabled
FreeType Linkage with freetype
FreeType Version 2.1.9
T1Lib Support enabled
GIF Read Support enabled
GIF Create Support enabled
JPG Support enabled
PNG Support enabled
WBMP Support enabled
XBM Support enabled

Cuando esto ocurra nuestra configuración será la adecuada para utilizar las funciones PHP de este ámbito y estaremos en disposición de poder generar imágenes dinámicas.

Scripts para gráficos estadísticos

Si en algún momento tienes interés en insertar en tus páginas gráficos estadísticos, en esta dirección http://www.aditus.nu/jpgraph/index.php podrás encontrar una interesante colección de scripts listos para usar, con licencia gratuita para usos no comerciales.

Formatos GIF

Aunque son abundantes los materiales que aluden a este formato gráfico -incluso en las páginas oficiales PHP- los formatos GIF sólo funcionan en modo lectura.

Parece ser que existe un conflicto sobre los derechos de propiedad del algoritmo de compresión que se utiliza en los ficheros .gif y eso está obligando a los desarrolladores de PHP a abandonar este tipo de formato.

Formatos PNG

El formato de imágenes PNG (Portable Network Graphic) nos permite seguir disponiendo de un formato gráfico de difusión gratuita con una funcionalidad similar al GIF en lo que se refiere a transparencias y que junto con la posibilidad de usar también el formato JPG va a cubrir las necesidades gráficas de esta utilidad de PHP.


Formatos de imágenes

Pese a que info.php nos devuelve información sobre los tipos de imágenes soportados por la versión en uso de PHP, existe una función que permite determinar cuales de esos tipos son soportados por PHP.

imagetypes()

Devuelve un campo de bits correspondiente a los formatos soportados por la versión de GD que estamos utilizando.

Los formatos de imagen que PHP soporta actualmente son: GIF, JPG, PNG y WBMP.

En la parte derecha tienes el código fuente de un fichero que permite obtener información sobre los formatos soportados por tu versión de PHP.

El conocimiento de estas posibilidades gráficas puede sernos muy útil a la hora de elegir entre los diferentes formatos gráficos disponibles


Formatos soportados

<?
if (imagetypes() & IMG_GIF) {
echo "El tipo GIF es soportado<br>";
}else{
echo "El tipo GIF NO ES SOPORTADO<BR>";
}
if (imagetypes() & IMG_PNG) {
echo "El tipo PNG es soportado<br>";
}else{
echo "El tipo PNG NO ES SOPORTADO<BR>";
}
if (imagetypes() & IMG_JPG) {
echo "El tipo JPG es soportado<br>";
}else{
echo "El tipo JPG NO ES SOPORTADO<BR>";
}
if (imagetypes() & IMG_WBMP) {
echo "El tipo WBMP es soportado<br>";
}else{
echo "El tipo WBMP NO ES SOPORTADO<BR>";
}

?>





miércoles, 18 de febrero de 2009

Manual de PHP 49. Ficheros: Correo II, Formatos Mime

Formato de los mensajes de correo electrónico

En la página anterior hemos hablado acerca de la manera de enviar un e-mail y veíamos la forma de insertar el cuarto parámetro de la función mail para incluir algunos elementos de los encabezados MIME.

El formato de los mensajes está especificado en una serie de normas conocidas como el MIME (Multipurpose Internet Mail Extensions) en las que se establecen los contenidos y la sintaxis de las diferentes partes de un mensaje.

Recordemos que la función

mail(dest, asunt, men, cab)

tiene cuatro parámetros y que las especificaciones del MIME aluden a los dos últimos, es decir a men (el cuerpo del mensaje) y cab que es el encabezado del mismo.

Respecto a dest (destinatario) y asunt no se requieren más comentarios que reiterar la necesidad de incluir esos valores (e-mail del destinatario y asunto) bien directamente, como parámetro en la función, o a través de una variable tal como hemos comentado en la página anterior.

Cabeceras de los mensajes

Los diferentes elementos de la cabecera de un mensaje deben insertarse siempre separados por saltos de línea bien pulsando Enter o incluyendo la secuencia \n dentro de la misma de línea.

No pueden incluirse espacios, ni al comiezo de las nuevas líneas ni después de \n, y las comillas –que han de contener todo el encabezado– se abren delante del primero de ellos y no se cierran hasta después de haber escrito el último.

Pueden contener lo siguiente:

Date: xxxxx

Date: debe escribirse con esta sintaxis exactamente.

El parámetro xxxxx es una cadena que contendrá la fecha de envío del mensaje y que puede obtenerse a través de una de las funciones de fecha de PHP tal como puedes ver en el ejemplo.

MIME-Version: 1.0

Este elemento de la cabecera especificará la versión MIME que ha de utilizar el cliente de correo para poder interpretar adecuadamente el contenido de los mensajes.

From: remitente

Este elemento de la cabecera permite indicar el nombre del remitente (remitente) y su dirección e-mail siguiendo la sintaxis que se especifica. El nombre, como un elemento independiente y la dirección e-mail dentro de < >.

¡Cuidado!

No debemos poner comillas ni en el nombre del remitente, ni en la dirección e-mail, ni en la fecha, etcétera.

Respecto a Cc: y Bcc: ; Reply-To: y X-Mailer: son válidos los comentarios que hemos hecho en la página anterior.

Si no se especifica lo contrario, los mensajes se envían como texto sin formato, pero existen opciones que permiten especificar el formato que ha de tener un mensaje.

La especificación de un formato obliga a incluir otro elemento en cabecera del mensaje:

Content-Type:

Este elemento debe ir seguido de la especificación en la que se indique el tipo de contenido. Tiene la sintaxis: tipo/subtipo

El MIME establece un gran variedad de opciones para este propósito. Hablaremos de dos de ellas:

text/plain

El text/plain es la opción por defecto y señala que el contenido del mensaje es de tipo texto (text) y del subtipo sin formato (plain)

text/html

Como la opción anterior, es tipo texto, pero en este caso, el subtipo es html con lo cual el mensaje se visualizará en formato html siempre que el cliente de correo permite esa posibilidad.

Mensajes multiparte

Los tipos anteriores permiten enviar mensajes simples (sin ficheros adjuntos) en uno u otro formato, pero el MIME nos da opciones para insertar dentro de un mismo mensaje elementos de diferentes tipos y subtipos.

Las opciones de mayor interés son las siguientes:

multipart/alternative

Es la forma de especificar que el mensaje tiene varias partes (multipart) de las que el destinatario ha de ver una sola (alternative).

Se podría utilizar en casos en los que sea necesario prever la posibilidad de que un mensaje con formato HTML pueda ser visualizado como texto plano cuando el cliente de correo no soporte HTML.

Podemos hacer un mensaje a medida que se presentará de una forma u otra según el cliente utilizado para leerlo.

multipart/mixed

Cuando en el Content-Type se establece el tipo multiparte y el subtipo mezclado (mixed) será cuando tengamos la posibilidad de adjuntar ficheros al mensaje.

Las diferentes partes de un mensaje deben ir separadas – tanto en modo alternativo como mezclado– y para ello hay que incluir un nuevo elemento en el encabezado. Se trata de un separador al que se llama boundary.

boundary=cadena

Dentro del encabezado y siempre en línea aparte (fíjate que en los ejemplos o está en línea aparte o aparece el \n) debemos incluir el elemento boundary= (sin símbolo de $ delante) y detrás del signo igual una cadena (en este caso entre comillas) que en principio puede ser una cadena cualquiera que no contenga espacios, aunque lo habitual es incluirla con el formato que podemos ver en los ejemplos.

El cuerpo del mensaje

En su formato más simple el cuerpo del mensaje contiene únicamente texto, pero cuando se trata de multipartes deberá contener necesariamente: los separadores de las diferentes partes, los encabezados de cada una de las partes y sus respectivos contenidos.

La secuencia habría de ser de este tipo:
  • Separador
  • Content-type
  • Content-Transfer-Encoding
  • **Content-Disposition
  • **Lectura del fichero
  • **Codificación
  • Inserción en cuerpo
  • Separador
  • .....
  • otra parte
  • ...
  • Separador final
Los apartados señalados con ** sólo se incluirían en el caso de que junto con el mensaje se adjunten ficheros.

Content-type

Los tipos y subtipos más habituales son los siguientes:

Para incluir textos:
los ya mencionados
text/plain
text/html

Para imágenes:
según el tipo de imagen
image/jpeg
image/gif

Para sonidos:
audio/basic

Para vídeo:
video/mpeg

Para ejecutables, comprimidos y otros ficheros adjuntos:
application/octet-stream

En cualquier caso, si quieres utilizar algún otro tipo de archivo puedes consultar en la web las especificaciones del MIME.

Aparte de tipo/subtipo puede añadirse a Content-type -en el caso de texto- separado por punto y coma, la especificación del tipo de alfabeto (charset=) seguida del tipo de codificación (te sugerimos el "ISO-8859-1" que hace alusión al alfabeto latino).

Cuando se trata de ficheros adjuntos deberemos poner, después del punto y coma, name= seguido del nombre y extensión del fichero que se adjunta.

Content-Transfer-Encoding

Este apartado del encabezado puede especificar una de los siguientes codificaciones:

7BIT
8BIT
BASE64
BINARY
QUOTED-PRINTABLE

La transferencia codificada en 7bit representa la codificación habitual en el formato ASCII de 7 bits.
No permite caracteres ASCII con un código mayor que 127.

Quoted-printable constituye una de las alternativas al formato ASCII de 7 bits.

Esta codificación suele usarse cuando la mayoría de los caracteres del mensaje puede escribirse con formato US ASCII de 7 bits.

Prevé que los caracteres con códigos ASCII superiores 127 se expresen mediante un mecanismo especial.

Evita, entre otras cosas, que las letras con tilde y algunos otros caracteres especiales se visualicen incorrectamente. Es la forma de codificación más recomendable para textos.

La codificación en base64 convierte cadenas binarias en cadenas de texto, con lo cual pueden ser enviadas de forma más segura. Es la forma de codificación habitual de las imágenes y los ficheros exe, zip, etcétera.

Content-Disposition

Se utiliza únicamente cuando se insertan ficheros adjuntos.

Permite dos opciones: inline o attachment.

Inline permite que los contenidos se visualicen junto con el cuerpo del mensaje mientras que con attachment sólo aparecerían como ficheros adjuntos.

Por lo que hemos podido comprobar Outlook Express no suele respetar esa condición y presenta siempre las imágenes en el mensaje. Sin embargo, sí funciona en los correos web.

Este elemento del encabezado lleva -separada por punto y coma- una segunda parte.

El filename=, donde se puede especificar entre comillas un nombre y una extensión (igual o distinta de la original) con la que se denominará al fichero en el mensaje recibido.

Lectura del fichero

Cuando se trata de insertar un fichero el proceso es el típico de lectura de ficheros, es decir:
  • Hay que crear el identificador de recurso del fichero en modo lectura.
  • Recoger en una variable el buffer de lectura.
  • Cerrar el fichero.
Codificación

Una vez recogido en el fichero a transmitir en una variable, el paso siguiente es codificar esa variable.

Utilizaremos la codificación más habitual y flexible –base64– que requerirá el uso de dos nuevas funciones PHP:

base64_encode
chunk_split

Mediante la primera se realiza la codificación propiamente dicha mientras que la segunda organiza el fichero codificado en trozos, de 76 caracteres cada uno, insertando detrás de cada uno un salto de línea.

Si analizas un mensaje de correo que contenga un fichero adjunto –propiedades, ver codificación–, podrás ver esa fragmentación tan cuidada -un montón de líneas de texto muy raro- perfectamente alineadas por los márgenes por efecto de chunk_split.

Inserción en el cuerpo

La fase final del proceso es la de agrupar los diferentes trozos en una sola variable, que será la que se insertará como parámetro texto en la función e-mail.

¡Cuidado!

La inserción de ficheros adjuntos requiere que éstos estén disponibles en el servidor por lo que, antes de enviarlos, habrá que subirlos al servidor utilizando un proceso como el que hemos analizado cuando hablábamos de Transferencia de ficheros.

Sobre los ejemplos

Hemos incluido dos ejemplos relativos al envío de ficheros en formato HTML y con ficheros adjuntos.

No entraremos en el estudio detallado del MIME.

Quedaremos únicamente en sus aspectos funcionales en cuanto a los requerimientos de formato, separadores, etc.

Quizá te parezca obsesivo el hincapié que hacemos en los ejemplos sobre los detalles de la sintaxis.

Nuestra insistencia se debe al carácter sumamente estricto de la especificación MIME, donde un simple salto de línea puede ser la causa de que script deje de funcionar.

Algunas funciones PHP que incorporamos en estos ejemplos


Podrás ver en estos ejemplos algunas funciones raras que vamos a comentar seguidamente:


uniqid(pre,bol)


Genera un identificador único basado en la hora actual del sistema expresada en microsegundos y con una longitud de 13 caracteres.


El parámetro pre permite establecer una cadena o número (puede ser una cadena vacía) que se antepone al identificador generado por la función.


Opcionalmente permite el segundo parámetro bol que debe ser un valor booleano (TRUE ó FALSE) o también 0 ó 1.


Cuando este parámetro es TRUE añade al final de la cadena generada anteriormente otra subcadena numérica -generada aleatoriamente- de nueve dígitos, que refuerza la unicidad del identificador.



eregi_replace(busca, reemplaza, cadena)


Busca en la cadena especificada en el parámetro cadena (que puede ser una cadena o una variable que contenga una cadena) las subcadenas especificadas en busca (pueden ser expresiones regulares) y sustituye esas subcadenas por el contenido del parámetro reemplaza.


Esta función devuelve la cadena modificada.


strip_tags(cadena, excepciones)


Suprime todas las etiquetas HTML contenidas en cadena salvo las que se indiquen en excepciones.


Por ejemplo: strip_tags($cadena, '<i><u><b>') eliminaría todas las etiquetas HTML, salvo las indicadas aquí y sus correspondientes cierres.


Si no se especifican excepciones elimina todas las etiquetas.



base64_encode(cadena)


Devuelve una cadena codificada en base64. Esta codificación se hace para permitir que las informaciones binarias puedan ser correctamente manipuladas por sistemas que no generan correctamente los 8 bits, tal como ocurre frecuentemente en los cuerpos de los mensajes de correo electrónico.


base64_decode(cadena)


Realiza el proceso inverso a la anterior. Decodifica una cadena previamente codificada en base64.


chunk_split(cadena, longitud, separador)


Devuelve una cadena obtenida al insertar en la cadena especificada -a intervalos del número de caracteres especificados en el parámetro numérico longitud- el contenido de una subcadena indicada en el parámetro separador.


Por defecto -cuando no se especifican los parámetros- longitud es igual a 76 caracteres y el separador es la cadena \r\n (retorno y salto de línea).


Esta función se utiliza para convertir al formato especificado en la RFC 2045 (especificación para MIME) las cadenas obtenidas por base64_encode.


Es el formato habitual de los ficheros adjuntos de los e-mail.




Las cabeceras MIME de un mensaje


Aquí tienes un ejemplo con los diferentes elementos del encabezado de un mensaje. Como ves, he incluido todos los elementos dentro de la función mail.

<?
mail("juan@mispruebas.com", "Cabeceras", "Prueba de cabeceras",
"Date: 24 de Junio de 2001
MIME-Version: 1.0
From: Estudiante Perico<perico@mispruebas.com>
Cc:perico@mispruebas.com
Bcc:andres@mispruebas.com
Reply-To: perico@mispruebas.com
X-Mailer: PHP/
".phpversion());

?>
Una forma un poco más depurada del script anterior podría ser esta que incluimos aquí debajo.


Sus particularidades son las siguientes:



  • Recogemos los datos en variables e insertamos en la función mail esas variables

  • La variable $cabecera tiene algunas singularidades:


    • La vamos construyendo añadiendo subcadenas: date, from, etc. etc.

    • En cada subcadena dejamos pegado el contenido a las comillas iniciales

    • Al final de cada subcadena (cada una contiene un elemento del encabezado) insertamos \n para el carácter especial que indica a PHP un salto de línea imprescindible



<?
# datos del mensaje
$destinatario="juan@mispruebas.com";
$titulo="Cabeceras en variables";
$mensaje="Nueva prueba de cabeceras";
$responder="andres@mispruebas.com";
$remite="andres@mispruebas.com";
$remitente="Otra vez Andrés";

# cabeceras
$cabecera ="Date: ".date("l j F Y, G:i")."\n";
$cabecera .="MIME-Version: 1.0\n";
$cabecera .="From: ".$remitente."<".$remite.">\n";
$cabecera .="Return-path: ". $remite."\n";
$cabecera .="X-Mailer: PHP/". phpversion()."\n";


if( mail($destinatario, $titulo, $mensaje,$cabecera)){
echo "mensaje enviado";
}
?>




Mensaje con contenido alternativo



<?
# creamos la variables "salto" para "mayor comodidad
# un salto es la secuencia retorno de carro-nueva línea
# dos saltos es algo similar pero duplicado

$UN_SALTO="\r\n";
$DOS_SALTOS="\r\n\r\n";

# creamos el remitente, etc. y también la que parte que
# contiene el código HTML del mensaje

$destinatario="juan@mispruebas.com";
$titulo="Mensaje alternativo Texto Plano - HTML ";
$mensaje="<html><head></head><body bgcolor='#ff0000'>";
$mensaje .="<font face='Arial' size=6>Prueba HTML</font>";
$mensaje .="</body></html>";

$responder="andres@mispruebas.com";
$remite="andres@mispruebas.com";
$remitente="Andrés Pérez y Pérez";


# creamos el separador de bloques del mensaje
# anteponiento "_separador" aunque podríamos haber puesto "tiburcio"
# generamos un identificador unico utilizando un numero aleatorio
# como "semilla" y luego lo codificamos con la función md5

$separador ="_separador".md5 (uniqid (rand()));

# creamos la variable cabecera con los elementos
# ya utilizados en los ejemplos anteriores y ponemos al final
# de cada elemento UN SALTO DE LINEA

$cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO;
$cabecera .="MIME-Version: 1.0\n";
$cabecera .="From: ".$remitente."<".$remite.">".$UN_SALTO;
$cabecera .= "Return-path: ". $remite.$UN_SALTO;
$cabecera .="Cc:perico@mispruebas.com".$UN_SALTO;
$cabecera .="Reply-To: ".$remite.$UN_SALTO;
$cabecera .="X-Mailer: PHP/". phpversion().$UN_SALTO;


# AQUÍ DEFINIMOS EL CONTENIDO MULTIPART, fíjate que lo acabamos con ";"

$cabecera .="Content-Type: multipart/alternative;".$UN_SALTO;

# insertamos BOUNDARY (fíjate que dejo un espacio
# en BLANCO DELANTE y ponemos al FINAL los DOS SALTOS DE LINEA

$cabecera .=" boundary=$separador".$DOS_SALTOS;

# colocamos el primer separador(con los dos guiones delante)
# antes de insertar la primera parte del mensaje
# que es el texto plano para el caso de que el cliente de correo
# no soporte HTML

$texto_plano ="--$separador".$UN_SALTO;

# especificamos el tipo de contenido y la codificación
# e inserto DOS SALTOS AL FINAL ya que ahi acaba la cabecera de esta parte

$texto_plano .="Content-Type:text/plain; charset=\"ISO-8859-1\"".$UN_SALTO;
$texto_plano .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS;


# cambiamos las etiquetas "<br>" por saltos de línea
# y luego quitamos todas las etiquetas HTML del cuerpo del mensaje
# ya que el texto plano no debe llevar ese tipo de etiquetas

$extractor= strip_tags(eregi_replace("<br>", $UN_SALTO, $mensaje));

$texto_plano .=$extractor;

# insertamos un nuevo separador para señalar el final
# de la primera parte del mensaje y el comienzo de la segunda

# en este caso ponemos UN SALTO delante del separador ya que de lo contrario
# al componer el mensaje se uniría con la cadena texto_plano anterior
# que no tiene SALTO DE LINEA AL FINAL

$texto_html =$UN_SALTO."--$separador".$UN_SALTO;

# especificamos el encabezado HTML para el siguiente bloque
# y ponemos en la ultima línea los DOS SALTOS DE LINEA

$texto_html .="Content-Type:text/html; charset=\"ISO-8859-1\"".$UN_SALTO;
$texto_html .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS;
#añado la cadena que contiene el mensaje
$texto_html .= $mensaje;

# insertamos SOLAMENTE un SALTO DE LINEA
# estamos al funal del mensaje

$texto_html .=$UN_SALTO;

# unimos ambas cadenas para crear el cuerpo del mensaje

$mensaje=$texto_plano.$texto_html;

# enviamos el mensaje utilizando


if( mail($destinatario, $titulo, $mensaje,$cabecera)){
echo "mensaje enviado ";
}

?>


Mensaje con ficheros adjuntos




<?
# definimos estas variables igual que en el ejemplo anterior

$UN_SALTO="\r\n";
$DOS_SALTOS="\r\n\r\n";

#incluimos en varias, asunto, un texto en HTML
# remitente, etc. etc.

$destinatario="perico@mispruebas.com";
$titulo="Mensaje con dos fichero adjuntos";
$mensaje="<html><head></head><body bgcolor=\"#ff0000\">";
$mensaje .="<font face=\"Arial\" size=6>Prueba HTML </font>";
$mensaje .="</body></html>";
$responder="andres@mispruebas.com";
$remite="andres@mispruebas.com";
$remitente="Andrés otra vez";


# definimos el separador de parte
# con el mismo procedimiento del ejemplo anterior

$separador = "_separador_de_trozos_".md5 (uniqid (rand()));

# insertamos los datos de la cabecera del mensaje

$cabecera = "Date: ".date("l j F Y, G:i").$UN_SALTO;
$cabecera .= "MIME-Version: 1.0".$UN_SALTO;
$cabecera .= "From: ".$remitente."<".$remite.">".$UN_SALTO;
$cabecera .= "Return-path: ". $remite.$UN_SALTO;
$cabecera .= "Reply-To: ".$remite.$UN_SALTO;
$cabecera .="X-Mailer: PHP/". phpversion().$UN_SALTO;


# especificamos el tipo de contenido mutipart/mixed
# ya que ahora insertaremos ficheros de distinto tipo

$cabecera .= "Content-Type: multipart/mixed;".$UN_SALTO;

# insertamos el valor de boundary haciéndola igual a $separador
# y acabamos con DOS SALTOS porque es el FINAL DE LA CABECERA

$cabecera .= " boundary=$separador".$DOS_SALTOS;

/* Parte primera del envio -Mensaje en formato HTML
================================================

Separador inicial
------------------------------- */
$texto ="--$separador".$UN_SALTO;

/* Encabezado parcial
------------------ */
/* especificamos que este primer elemento
será texto y que irá codificado en formato 7 bits */

$texto .="Content-Type: text/html; charset=\"ISO-8859-1\"".$UN_SALTO;
$texto .="Content-Transfer-Encoding: 7bit".$DOS_SALTOS;


/* Contenido de esta parte del mensaje
-----------------------------------*/
# ya teniamos escrito el texto del mensaje más arriba
# simplemente lo añadimos a la cadena de texto

$texto .= $mensaje;

#la variable $texto recoge esta parte del documento
# la uniremos al final con las siguientes

/* Separador de partes
-------------------- */

$adj1 = $UN_SALTO."--$separador".$UN_SALTO;

/* Parte segunda de mensaje -Fichero adjunto nº 1
==================================================== */

/* Encabezado parcial
------------------ */
# especificamos el tipo de contenido image/jpeg
# ya que ese será el documento que vamos a enviar
# ponemos el nombre del fichero (debemos tenerlo en el servidor
# con ese mismo nombre)
# establecemos in line como disposición para que pueda ser visualizado
# directamente en el cuerpo del mensajes
# en filename le asignamos el nombre con el que queremos que sea
# recibido por el destinatario
# por ultimo especificamos la codificacion como base64

$adj1 .="Content-Type: image/jpeg;";
$adj1 .=" name=\"casa08.jpg\"".$UN_SALTO;
$adj1 .="Content-Disposition: inline; ";
$adj1 .="filename=\"leoncio.jpg\"".$UN_SALTO;
$adj1 .="Content-Transfer-Encoding: base64".$DOS_SALTOS;


/* Lectura previa del fichero a adjuntar
------------------------------------------ */
# abrimos el fichero en modo lectura (r)
# y leemos todo su contenido midiendo previamente
# su longitud con filesize
# recogemos en $buff el contenido del fichero
# y cerramos después

$fp = fopen("casa08.jpg", "r");
$buff = fread($fp, filesize("casa08.jpg"));
fclose($fp)
;

/* Codificación del fichero a adjuntar
------------------------------------------ */
# codificamos en base 64 y troceamos en lineas de 76 caracteres
# y añadimos el resultado a la variable adj1

$adj1 .=chunk_split(base64_encode($buff));

/* Separador de partes
-------------------- */

$adj2 = $UN_SALTO."--$separador".$UN_SALTO;

/* Tercera parte de mensaje -Fichero adjunto nº 2
==================================================== */

/* Encabezado parcial
------------------ */
# los contenidos del encabezado son similares al caso anterior
# con la salvedad de que el contenido es ahora
# application/octet-stream ya que contiene un fichero ejecutable
# y la disposicion es attachment, no tiene sentido tratar
# de visualizar un fichero zip

$adj2 .="Content-Type: application/octet-stream;";
$adj2 .=" name=\"apachito.zip\"".$UN_SALTO;
$adj2 .="Content-Disposition: attachment;
filename=\"apachito.zip\""
.$UN_SALTO;
$adj2 .="Content-Transfer-Encoding: base64".$DOS_SALTOS;


/* Lectura previa del fichero a adjuntar
------------------------------------------ */
# abrimos el fichero en modo lectura (r)
# y leemos todo su contenido midiendo previamente
# su longitud con filesize
# recogemos en $buff el contenido del fichero
# y cerramos después

$fp = fopen("apachito.zip", "r");
$buff = fread($fp, filesize("apachito.zip"));
fclose($fp)
;

/* Codificación del fichero a adjuntar
------------------------------------------ */

$adj2 .=chunk_split(base64_encode($buff));

/* Separador final YA NO HAY MAS PARTES
---------------------------------------- */

$adj2 .=$UN_SALTO."--$separador".$UN_SALTO;

/* Unión de todas las PARTES
---------------------------------------- */
# unimos en la variable mensaje todos los elementos
# y lo hacemos por el orden en el que fueron creados

$mensaje=$texto.$adj1.$adj2;

/* Envio del mensaje
---------------------------------------- */

if(mail($destinatario, $titulo, $mensaje,$cabecera)){
echo "mensaje enviado";
}

?>