8. PERL Y LOS FORMULARIOS


8.1. Funcionamiento de un formulario.

La idea básica detrás de un formulario es sencilla: pida información al visitante, obtenga la información, después haga algo con la información. La parte delicada de tratar con los formularios se maneja entre bastidores por el código de Perl.

¿Cómo van los datos de un formulario al servidor?.

Después de que el visitante rellene un formulario, el explorador envía los datos para ser procesados o almacenados. Típicamente, la corriente de los datos del formulario es alimentada en un programa que cambia todos los datos por un formato más legible. El programa de procesamiento puede ser un URL (Universal Resource Locator o Localizador Universal de Recursos) situado en cualquier parte de Internet.

El programa de procesamiento de los datos es usualmente un script de Perl, un script de Shell de UNIX, o un programa compilado residente en el servidor que maneja sus páginas Web.

Los datos procedentes de un formulario fluyen en una corriente que utiliza un formato especial llamado URL encoding (codificación URL). El término procede del hecho de que los datos tienen que ser transformados en un formato que pueda viajar por Internet, lo que originariamente quería decir texto ASCII puro y sencillo que parecía como la dirección típica de la página Web; letras y números, sin espacios, sin puntuaciones caprichosas, y sin hacer cosas raras con las fuentes.

¿Si en un formulario de Web tuvieramos un campo Comentario con el texto "Esta noche me voy a comer las uvas de la suerte" dividido en dos líneas, es decir, una por ejemplo con "Esta noche me voy a comer las uvas " y otra con "de la suerte", cómo se enviaría esta información?. Pues así:

Comentario=Esta+noche+me+voy+a+comer+las+uvas+%OD%OAde+la+suerte

Observa los espacios (se sustituyen por signos más) y el salto de línea (en Ascii se hace con los caracteres 13 y 10 pero en Internet se expresa en hexadecimal con el signo de porcentaje "%" como prefijo). Es fácil. Pues aún hay más: si nuestro formulario tuviera dos campos para unirlos se usa el signo & de esta forma:

campo1=Feliz+Navidad&campo2=1998

Desde luego, codificar los datos es solamente la mitad de la batalla, traducir el URL, los datos codificados en texto legible en el otro lado de la trasnmisión es la otra mitad, y una buena tarea de Perl.

Cada campo tiene un atributo NAME (nombre, de forma que puede saberse de dónde proceden los datos) y un atributo VALUE (valor, contenido del campo). La cadena enviada por el explorador empareja cada NAME del formulario con su VALUE y los conecta con un signo igual: NAME=VALUE. La pareja NAME/VALUE es la construcción básica de datos de los formularios y de los programas de procesamiento de formularios. Los informes CGI más sencillos están realizados con listas de parejas NAME/VALUE.

8.2. Métodos de envío: GET y POST.

El visitante envía al servidor los datos del formulario utilizando uno de los dos métodos: GET o POST.

Con el método GET, el explorador empaqueta los datos del formulario en algo llamado URL encoding (codificación URL) y los agrega al final de una solicitud de aspecto normal para un URL. Por ejemplo, supongamos que en WWW.arrakis.es en el directorio /cgi-bin tenemos el programa Perl de búsqueda (busca.pl) y que nuestro formulario tiene un campo llamado Buscar con el valor "Blas Infante", al hacer clic sobre el botón Entregar (Submit) se enviará lo siguiente:

www.arrakis.es/cgi-bin/busca.pl?buscar=Blas+Infante

Si embargo, el método POST codificará los datos de la misma forma, pero los envía directamente al programa CGI a través de STDIN. El método POST usa la variable de entorno CONTENT_LENGHT (longitud del contenido) para decirle al servidor cuántos bytes debe leer desde STDIN. La corriente de datos puede ser tan larga como se necesite, cosa que no ocurre con el método GET que dependiendo del servidor se permitirán cadenas más o menos cortas. Está limitación hace que POST sea el método más utilizado.

8.3. Variables de entorno (CGI).

Las funciones y los procesos de un servidor pasan datos entre sí a través de variables de entorno. Estas variables actúan de forma muy parecida a la de una fila de buzones de correo. Los procesos y las funciones pasan información a esas variables y después vuelven a otra parte a realizar su tarea.

Las variables CGI de mayor importancia generalmente para comprender el proceso de comunicación explorador/servidor se describen en la tabla siguiente:

QUERY_STRING - Datos de entrada que se agregan a URL para un
método GET.

REQUEST_METHOD - Expresa el método usado: GET o POST.

CONTENT_LENGHT - Número de bytes de la corriente de datos a leer
para una solicitud con el método POST.

8.4. Más sobre formularios HTML.

<FORM>...</FORM>.Define el comienzo y final de un formulario.

ACTION="URL". Es el nombre del archivo del script o del programa que manejará los datos desde un formulario.

METHOD="GET" o "POST". Así se indica cómo se mueven los datos desde el formulario hasta el script que los maneja.

Ejemplo: <FORM ACTION="cgi-bin/formecho.pl/" METHOD="POST">

8.4.1. Elementos de un formulario.

<INPUT> Define campos de un formulario. Tiene un atributo NAME para asignar un nombre al campo y un atributo TYPE para definir el tipo de entrada del campo:

TYPE="TEXT" Texto.
TYPE="PASSWORD" Contraseña.
TYPE="CHECKBOX" Casilla de verificación.
TYPE="RADIO" Botón de opción.
TYPE="SUBMIT" Botón de envío de datos.
TYPE="RESET" Botón de borrado de formulario.
TYPE="HIDDEN" Campo oculto.

Otros atributos de INPUT son:

VALUE="Valor" Con las casillas de verificación y los botones de
opción especifica la opción seleccionada. En el
botón SUBMIT personaliza la etiqueta del botón.

SIZE="Tamaño" Longitud en caracteres del cuadro de entrada para
los tipos TEXT y PASSWORD.

MAXLEGHT="Tamaño" Longitud en caracteres máxima del campo para los
tipos TEXT y PASSWORD.

<SELECT></SELECT> Define una lista de elementos para selección.

NAME="Nombre" Nombre del campo.

SIZE="1,2" 1=Cuadro emergente 2=Cuadro desplazable >2=Cuadro
desplazable con entrada en blanco.

MULTIPLE Permite seleccionar más de una opción al
mismo tiempo.

<OPTION> Etiqueta para identificar el texto de un
elemento de una lista de opciones.

<OPTION SELECTED> Opción por defecto.

<TEXTAREA></TEXTAREA> Define un cuadro de texto de varias líneas.

NAME="Nombre" Nombre del campo.

ROWS="Filas" Número de filas.

COLS="Columnas" Número de columnas.

8.4.2. Ejemplo de formulario.

<HTML>
<HEAD>
<TITLE>Incidencias de los usuarios de PCs.</TITLE>
<BODY BGCOLOR="#75E5F0" TEXT="#000000">
<H1>Incidencias de los usuarios de PCs.</H1>
<H3>Si tiene problemas o necesita de los servicios del departamento</H3><P>
<H3>de micro rellene y envie este formulario.</H3>
<FORM ACTION="http://www.some.site/cgi-bin/avisos.pl" METHOD="GET">
<PRE>
<INPUT TYPE="HIDDEN" NAME="AAFormID" VALUE="Avisos">
Nombre: <INPUT TYPE="TEXT" NAME="Nombre" SIZE="20" MAXLEGHT="20"><P>
Centro Directivo: <SELECT NAME="Centro" SIZE="0">
<OPTION VALUE="Gabinete Consejera"> Gabinete Consejera
<OPTION VALUE="Viceconsejeria"> Viceconsejeria
<OPTION VALUE="S.G.T."> S.G.T.
<OPTION VALUE="S.G.E."> S.G.E.
<OPTION VALUE="Presupuestos"> Presupuestos
<OPTION VALUE="Patrimonio"> Patrimonio
<OPTION VALUE="Intervencion General"> Intervencion General
<OPTION VALUE="Tesoreria"> Tesoreria
<OPTION VALUE="Fondos Europeos"> Fondos Europeos
<OPTION VALUE="Tributos"> Tributos
<OPTION VALUE="Relaciones financieras"> Relaciones Financieras
<OPTION VALUE="Informatica"> Informatica
<OPTION VALUE="Otro departamento"> Otro departamento
</SELECT><P>
Telefono: <INPUT TYPE="TEXT" NAME="Telefono" SIZE="5" MAXLEGHT="5"><P>
Incidencia: <INPUT TYPE="RADIO" NAME="Tipo" VALUE="Averia" CHECKED> Averia
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Programa"> Programa
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Configuracion"> Configuracion
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Informacion" > Informacion
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Otro" > Otros<P>
Descripcion: <INPUT TYPE="TEXT" NAME="Incidencia" SIZE="40" MAXLEGHT="40"><P>
<INPUT TYPE="SUBMIT" VALUE="Enviar al Servicio de Informatica">
<INPUT TYPE="RESET" VALUE="Borrar">
</PRE>
</FORM>
</BODY>
</HTML>

8.4.3. Ejemplo de un analizador de cadenas codificadas URL.

Suponiendo que en el formulario anterior hubieramos tecleado los siguientes datos:

Nombre = "Manuel"
Centro = "Informatica"
Telefono ="64022"
Tipo = "Averia"
Incidencia = "No arranca PC"

la cadena URL que se enviará al servidor después de pulsar sobre el botón "Enviar al servicio de informática" será:

?AAFormID=Avisos&Nombre=Manuel&Centro=Informatica&Telefono=64022
&Tipo=Averia&Incidencia=No%20arranca%20PC

Con este envío y ayudados de un programa en Perl podemos analizar la cadena URL y crear un formulario que nos presente los datos de una forma más inteligible, por ejemplo en HTML para ser visualizado por un navegador (formula1.pl):

# Analizador de cadenas codificadas URL
# Ejecutar perl formula1.pl formula1.txt >formula2.htm

print "<HTML>\n<HEAD><TITLE>Form Data</TITLE></HEAD>\n";
print "<BODY>\n<H3>Form Data</H3>\n";
while (<>) {
if (/AAFormID=/) {
chop();
@url = split(/&/);
foreach (@url) {
tr/+/ /;
s/=/ = /;
s/%(..)/pack("C",hex($1))/ge;
print "$_<BR>\n";
}
print "<P><HR>\n";
}
}
print "</BODY>\n</HTML>\n";
close;

# Si no entiendes parte de este código estudia el capítulo de los
# modelos de búsqueda.

8.4.4. MIME y Perl.

MIME, Multipurpose Internet Mail Extensions (Extensiones del correo de internet para aplicaciones diversas) son especificaciones para los tipos de archivos que se mueven por Internet. La finalidad de MIME es permitir a los ordenadores de las diversas plataformas y a las configuraciones pasa información entre sí y que comprendan cómo procesar la información con la menor cantidad de confusión y molestia. Existen distintos tipos de MIME para textos, imágenes, vídeo, audio, mensajes, aplicaciones y otras más.

HTML es texto, y su tipo MIME es text/html.

¿Cómo se apoyan los servidores en MIME?.

Después de recibir una solicitud para enviar un archivo, el servidor comprueba la extensión del archivo para determinar el tipo MIME del archivo. Extensiones como .HTM, .HTML, .GIF, .JPG, .MID y otras más son conocidas en el ámbito de Internet y es importante saber que no se pueden cambiar arbitrariamente estas extensiones por otras inventadas. La razón de que tenga esa limitación es que el servidor confia en la utilización esperada de las extensiones para determinar el tipo de archivo.

8.5. Las cabeceras HTTP.

Los archivos deben estar "bien vestidos" con el fin de que puedan moverse por Internet. Todas las solicitudes desde un explorador a un servidor y, a la inversa, todos los archivos o respuesta en forma parecida a un archivo desde un servidor al explorador, tienen una parte de identificación de los datos llamada cabecera pegada delante (a la cabeza) del archivo.

8.5.1. Cabeceras de solicitud.

La primera pieza de la información que envía el explorador al servidor como parte de la solicitud es una cabecera de solicitud Method. Esta cabecera consiste en sólo una línea de texto que contiene tres elementos en un formato especial y separados por un espacio.

Method URL Versión

Method es el método usado en la etiqueta <FORM> del HTML: POST o GET.

URL especifica la situación o dirección del documento solicitado.

Versión es el nivel más alto del protocolo HTTP que entiende el explorador.

Ejemplo: GET http://www.cancana.es/index.html HTTP 1.0

Con esta cabecera, el servidor ya sabe lo que tiene qué hacer, aunque después de esta cabecera pueden ir otras adicionales para proporcionar más información al servidor o para solicitar un trabajo especial del mismo.

Luego, cuando responde el servidor a un usuario de la WWW también agrega cabeceras de respuesta delante de los archivos que le envía, cediendo el turno al navegador en la interpretación y ejecución de las mismas.

Los programas CGI no tratan directamente con las cabeceras de solicitud que proceden del explorador. El servidor incorpora la información de la cabecera en las variables CGI y un programa CGI (un programa en Perl) comprueba el contenido de la variable para buscar los datos.

8.5.2. Cabeceras de respuesta.

El servidor utiliza cabeceras de respuesta para comunicarle al explorador las particularidades sobre el archivo entrante: su tipo, su longitud, los datos modificados últimamente y así sucesivamente.

Los programas CGI son archivos, pero no se envían sino que se ejecutan en el servidor. Los programas CGI devuelven típicamente información al explorador enviando un archivo o produciendo una serie de comandos print, que le parecen un archivo al explorador, a STDOUT.

Con el fin de hacerle fluir a través de Internet hasta el explorador, el archivo necesita una cabecera. Debido a la forma en que trabaja el CGI, el programa tiene que crear su propia cabecera de respuesta para devolver un mensaje al explorador.

Para una respuesta en el formato de página HTML la cabecera será:

Content-type: text/html

Y para una respuesta usando un simple mensaje de texto:

Content-type: text/plain

Después de una cabecera de respuesta hay que añadir una línea en blanco. Con Perl se hará:

Print "Content-type: text/html\n\n"; # ¡ Con dos "\n" seguidos !
Print "<HTML><HEAD><TITLE>Título de la página</TITLE></HEAD>\n";
Print "<BODY>Contenido de la página</BODY></HTML>\n";

8.6. Perl y Unix.

Los pasos para ejecutar Perl en un servidor Unix son:

1º. Insertar un mensaje dentro del script para indicarle a UNIX donde debe encontrar el intérprete de Perl que ejecuta el script. Debe estar en la primera línea del archivo.

Ejemplo: #!/usr/local/bin/perl

2º. Convierta el script Perl en texto UNIX. En UNIX las líneas terminan con el carácter de alimentación de línea (10 ASCII, llamado LF). En DOS, el símbolo de terminación es el de retroceso de carro (CR) + alimentación de línea (LF), es decir, (13 ASCII + 10 ASCII).

Con los programas FTP la conversión suele realizarse de forma automática pero puede hacerla también con el siguiente programa en Perl:

Ejemplo (crlftolf.pl):

# Para ejecutar teclear: PERL crlftolf.pl <dos.pl> unix.pl

binmode(STDOUT);
while (<STDIN>) {
chop;
print "$_\n";
}

3º. Transferir el script al directorio designado por el Proveedor de Servicios Internet (PSI) para sus programas CGI.

4º. Cambie la propiedad del modo de operar del script de forma que UNIX sepa que el script puede ejecutarse directamente.

Teclear:

chmod 755 script.pl (Para conceder permiso de ejecución a scripts)
chmod 766 directorio (Para conceder permiso de L/E a un directorio)

5º. Cambie a continuación los derechos de acceso para el script para que permita a sus visitantes en la web que ejecuten el script como un programa CGI.

8.7. Ejemplo Completo: Formulario, Perl, Instalación y Ejecución.

En el ejemplo siguiente vamos a crear un formulario HTML y un script que lee los datos del formulario, devuelve un mensaje informando de su recepción y envía los datos vía correo electrónico a la cuenta incidencias@ceh.junta-andalucia.es:

1º. Crear el formulario siguiente (incidenc.htm):

Código HTML de incidenc.htm:

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html; charset=iso-8859-1">
<TITLE>Incidencias de los usuarios de PCs.</TITLE>
<BODY>
<H1>Incidencias de los usuarios de PCs.</H1>
<H3>Si tiene problemas o necesita de los servicios del departamento</H3><P>
<H3>de micro rellene y envie este formulario.</H3>
<FORM ACTION="//sello00/cgi-bin/avisos.pl" METHOD="POST">
<PRE>
<INPUT TYPE="HIDDEN" NAME="AAFormID" VALUE="Avisos">
Nombre: <INPUT TYPE="TEXT" NAME="Nombre" SIZE="20" MAXLEGHT="20"><P>
Centro Directivo: <SELECT NAME="Centro" SIZE="0">
<OPTION VALUE="Gabinete Consejera"> Gabinete Consejera
<OPTION VALUE="Viceconsejeria"> Viceconsejeria
<OPTION VALUE="S.G.T."> S.G.T.
<OPTION VALUE="S.G.E."> S.G.E.
<OPTION VALUE="Presupuestos"> Presupuestos
<OPTION VALUE="Patrimonio"> Patrimonio
<OPTION VALUE="Intervencion General"> Intervencion General
<OPTION VALUE="Tesoreria"> Tesoreria
<OPTION VALUE="Fondos Europeos"> Fondos Europeos
<OPTION VALUE="Tributos"> Tributos
<OPTION VALUE="Relaciones financieras"> Relaciones Financieras
<OPTION VALUE="Informatica"> Informatica
<OPTION VALUE="Otro departamento"> Otro departamento
</SELECT><P>
Telefono: <INPUT TYPE="TEXT" NAME="Telefono" SIZE="5" MAXLEGHT="5"><P>
Incidencia: <INPUT TYPE="RADIO" NAME="Tipo" VALUE="Averia" CHECKED> Averia
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Programa"> Instalacion programa
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Configuracion"> Configuracion
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Informacion" > Informacion
<INPUT TYPE="RADIO" NAME="Tipo" VALUE="Otro" > Otros<P>
N. Inventario: <INPUT TYPE="TEXT" NAME="Inventario" SIZE="5" MAXLEGHT="5"><P>
Descripcion: <TEXTAREA NAME="Descripcion" ROWS="2" COLS="50"></TEXTAREA><P>
</PRE>
<INPUT TYPE="SUBMIT" VALUE="Enviar al Servicio de Informatica">
<INPUT TYPE="RESET" VALUE="Borrar">
</FORM>
</BODY></HTML>


2º. Crear el script
(avisos.pl):

#!/usr/local/bin/perl
# avisos.pl -- Devuelve datos via email

$email = "asuarez\@ceh.junta-andalucia.es";

read(STDIN, $formdat, $ENV{'CONTENT_LENGTH'});

open(MAILOUT, "| mail -s \"Incidencias de usuarios para micro\" $email") ||
die "No puedo ejecutar programa de correo.";

@namevals = split(/&/,$formdat);
foreach (@namevals) {
tr/+/ /;
s/=/ = /;
s/%(..)/pack("C",hex($1))/ge;
print MAILOUT "$_\n";
}
close(MAILOUT);

print "Content-type: text/html\n\n";

print "<HTML><HEAD>\n";
print "<TITLE>Servicio de Informatica: Recepcion de incidencias</TITLE>\n";
print "</HEAD><BODY>\n";
print "<H3>Datos de la incidencia recibida</H3>\n";
print "<HR>\n";
print "Sus datos han sido recibidos correctamente. Gracias por su colaboracion.<BR>\n";
print "<P><HR>\n";
print "</BODY>\n</HTML>\n";

8.8. Ejemplos: Datos de formularios y ficheros secuenciales.

Ejemplo (formula2.pl):

# formula2.pl: Lee cadena URL, genera html y almacena en archivo plano.
# Ejecutar perl formula2.pl formula1.txt >formula3.htm

print "<HTML>\n<HEAD><TITLE>Form Data</TITLE></HEAD>\n";
print "<BODY>\n<H3>Form Data</H3>\n";
open (DATOS, ">>formula2.dat");
while (<>) {
if (/AAFormID=/) {
chop();
@url = split(/&/);
foreach (@url) {
tr/+/ /;
s/=/ = /;
s/%(..)/pack("C",hex($1))/ge;
print DATOS $_, "\n";
print "$_<BR>\n";
}
print "<P><HR>\n";
}
}
print "</BODY>\n</HTML>\n";
close;
#fin

Ejemplo (formula3.pl):

# formula3.pl: Lee cadena URL, genera html y almacena en archivo plano.
# Los campos son separados por comas y delimitados por comillas.
# Ejecutar perl formula3.pl formula1.txt >formula3.htm

print "<HTML>\n<HEAD><TITLE>Datos del formulario</TITLE></HEAD>\n";
print "<BODY>\n<H3>Datos del formulario</H3>\n";
open (DATOS, ">>formula3.dat");
$comillas = pack(C,34);
$primeravez = 0;
$cadena = "";
while (<>) {
if (/AAFormID=/) {
chop();
@url = split(/&/);
foreach (@url) {

tr/+/ /;
s/%(..)/pack("C",hex($1))/ge;
/=/;

if ($primeravez==0) {
$cadena = $comillas.$'.$comillas;
$primeravez = 1;
} else {
$cadena = $cadena.",".$comillas.$'.$comillas;
}

}
print $cadena."\n";
print DATOS $cadena."\n";
print "<P><HR>\n";
}
}
print "</BODY>\n</HTML>\n";
close;
#fin