| Programación
CGI
En este tutorial crearemos un script CGI
que envíe un correo y devuelva una página que indique
que el correo ha sido enviado. Sin embargo, los conceptos serán
bastante geniales para permitir que el script pueda ser adaptado
a cualquier proyecto donde sea necesario enviar un correo desde
un script. También veremos brevemente como examinar las áreas
de texto línea por línea.
Como siempre, cuando empezamos, necesitaremos
un formulario.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD
HTML//EN">
<html>
<!--Javier Pérez Delgado (jperez@ctv.es) All Rights Reserved
-->
<head>
<link rev=made href="mailto:jperez@ctv.es">
<title>Enviar correo desde un script CGI</title>
</head>
<body>
<P>Este formulario encía correo a la dirección
de la persona mostrada.</P>
<form method="POST" action="http://www.ctv.es/USERS/cgi-bin/mail.pl">
<P>Tu dirección: <INPUT NAME="De" SIZE=36></P>
<P>Tu URL: <INPUT NAME="xurl" SIZE=36></P>
<P>Subject: <INPUT NAME="subject" SIZE=40></P>
<P>Mensaje:</P>
<P><TEXTAREA name="body" rows=10 cols=60></TEXTAREA></P>
<P><input type="submit" value="Enviar mansaje">
<input type="reset" value="Borrar todo"></P>
</FORM>
</P>
</body>
</html>
Ahora pasaremos al script. Como siempre deberá
empezar con una llamada al perl, algunos comentarios y una llamada
a la rutina ReadParse, en la librería cgi-lib.pl. También
haremos verificaciones de que el cuerpo del mensaje no está
vacío, y de que la dirección contiene una arroba (@).
Otra validación será para comprobar que de pasan argumentos,
lo pondremos porque la gente tiene tendencia a llamar a los scripts
de correo sin argumentos (eg: no desde un formulario), no entiendo
por qué. Para comprobar que no hay argumentos, simplemente
examinaremos si el vector %in que la librería cgi-lib.pl
nos devuelve tiene alguna tecla. Recuerda, que ningún argumento,
significa que no nos han pasado nada, sin embargo, alguien puede
pasar los argumentos en blanco, de aquí las dos comprobaciones.
La manera de comprobar los valores de las teclas del vector es usar
la función keys(). Esta función espera un array asociativo
como argumento. Simplemente comprobaremos que devuelve algo, imprimiendo
un mensaje de error si no hay teclas. El código pude ser
este:
if (!keys(%in)) {
# niguna tecla ha sido pasada, imprimir mensaje de error, y si es
apropiado salir.
}
Date cuenta de que el signo '!' al principio
de la llamada a keys(), significa 'no' o negación. Quiere
decir que si keys() no devuelve nada (falso), será negado
para que sea cierto y el if se ejecute. Ahora que hemos validado
las entradas, y se pueden realizar más comprobaciones, necesitaremos
enviar la carta. Para ello necesitaremos un programa que acepte
una carta del stdin. Luego usaremos sendmail en el ejemplo. Si no
estás en un entorno Unix, necesitarás otro programa
apropiado para hacerlo. Como no conozco otro tipo de sistemas, no
puedo hacer ninguna recomendación.
Usar este programa será similar a
escribir en un fichero. Necesitamos abrir el programa para aceptar
la entrada, escribir al FILEHANDLE. Abrir un programa que espera
entradas por el stdin es bastante fácil em Perl. Además,
es muy fácil pasar el argumento de la línea de comandos.
En este ejemplo, abriremos sendmail, y diremos que busque en la
carta la dirección de destino.
open(MAIL,"|/usr/lib/sendmail -t");
Como se puede observar, es igual que una
llamada a fichero, pero los símbolos '>' o '<' han
sido sustituidos por un '|' (tubería). Esto indica que lo
que hay detrás de la tubería es un ejecutable, y que
lo que imprimamos en este FILEHANDLE se deberá pasar como
entrada a el programa ejecutable.
Nota: No he comprobado si la operación
anterior terminó con éxito, pero deberíamos
hacerlo. La manera más sencilla de hacerlo, es apoyarnos
en que el comando open devuelve true cuando ha tenido éxito.
Solo debemos hacer un OR entre el comando open y otro comando conociendo
que ese comando será ejecutado si el open falla. El ejemplo
de abajo realiza un OR con el comando die. Este comando imprime
un mensaje de error y sale del programa.
open(MAIL,"|/usr/lib/sendmail -t")
|| die "La llamada a sendmail ha fallado";
El imprimir la carta funciona como esperamos.
Recuerda, sin embargo, que estamos imprimiendo un trozo de e-mail,
por lo que deberemos poner las cabeceras adecuadas, un línea
en blanco y el cuerpo del mensaje. Puedes echar un vistazo a un
e-Mail que hayas recibido y comprobar las cabeceras. Describiré
abajo lo más importante. Los comentarios serán de
ayuda.
# Esta es la línea 'para'. Si tenemos
el nombre y la dirección, escribiremos
# primero el nombre y luego la dirección entre <>
print MAIL "To: $in{'De'}\n";
# Esta es la línea 'De'. Pondremos
el mismo nombre en la línea 'De' y en la 'para'
# Recuerda que no hay seguridad comprobando el email, por ello estas
líneas
# pueden ser falsificadas. NO FALSIFIQUES EL EMAIL, no es divertido
y en algunos lugares
# es un delito.
print MAIL "From: $in{De}\n";
# Esta es la línea 'contestar a'.
Esta línea se incluye debido a que algunos programas
# son bastante tontos y no siempre responden a la línea 'De'.
# Al menos respetarán esta línea.
print MAIL "Reply-To: $in{De}\n";
# Lo siguiente son cabeceras X. Son creadas
por el usuario y pueden contener
# todo lo que desees. Incluyo una línea de descripción
# también he escrito las líneas REMOTE_HOST, REMOTE_ADDR,
y REMOTE_USER para
# ayudar al seguimiento (traking) de la carta.
# Solo escribo la línea X-URL si el usuario ha dado una url.
Este tipo
# de comprobación probablemente hecha también en el
X-Remote-Host y X-Remote-User
print MAIL "X-mailer: Mail.pl, a cgi-bin
script at http://www.ctv.es/users/jperez/www/tutor/ /index.html\n";
print MAIL "X-Remote-Host: $ENV{'REMOTE_HOST'} ($ENV{'REMOTE_ADDR'})\n";
print MAIL "X-Remote-User: $ENV{'REMOTE_USER'}\n";
print MAIL "X-disclaimer: La línea De: puede estar falsificada
";
print MAIL "No confiar en un 100% sobre la integridad de este
mail. ";
print MAIL "No somos responsables de este correo de ninguna
manera\n";
if ($in{xurl} ne "") {
print MAIL "X-URL: $in{xurl}\n";
}
# Finalmente escribimos la famosa línea
del asunto.
# Presatr atención en la segunda nueva línea. Esta
es la línea
# que va a separar el encabezado del cuerpo del mensaje.
print MAIL "Subject: $in{subject} (WWW generated email)\n\n";
# Ahora vamos a escribir elcuerpo del mensaje.
print MAIL $in{'body'};
Solo quedan dos cosas. Primero debemos cerrar
la conexión con sendmail. Segundo debemos imprimir una página
enseñando al usuario la carta que envía.
Para cerrar la conexión, usaremos
el comando close, justo como en cualquier otro manejador:
close(MAIL);
Imprimir la respuesta no es diferente a las
otras páginas generadas dinámicamente que ya hemos
creado anteriormente. Deberemos dividir el campo TEXTAREA en líneas
colocando un <BR> al final de cada una. Esto se hace principalmente
para demostrar como se divide un campo de texto. Recuerda sin embargo
que html no respeta las nuevas líneas. Con ello se consigue
el poder hacer los párrafos de manera más clara, pero
el beneficio de hacerlo es cuestionable.
El valor del campo body (cuerpo del mensaje),
no es más que un conjunto de frases separadas con un retorno
de carro. Podemos usar la función split() para separarlas.
Esta función necesita dos parámetros: la cadena o
carácter para separar y la variable a separar, y retorna
un array con los elementos separados. Usaremos split en un bucle
foreach:
foreach $l (split('\n',$in{'body'})) {
print "$l<BR>\n";
}
Como se puede ver separa la variable $in{'body'}
en partes cada nueva línea, y la imprime seguida de un <BR>. |