Forms 3
Forms 3
Indice
------
PRIMERA PARTE
Introducción.
Cómo funciona la cosa.
Por donde empezar.
Forms.
Forms simples.
Text, Password y TextArea.
Radio Buttons.
Check Buttons.
Pop-up Lists.
Forms Multiples y el Reset Button.
SEGUNDA PARTE
Que necesitamos para empezar.
Qué son los scripts CGI?
Nuestro Primer Script.
Un script que hace Eco de un Form.
Un procesador de mensajes simple. (guestbook)
-retornar una página estática que no hallamos creado.
-verificar que todos los campos de un form sean completados
y que el email este correctamente especificado.
-Editar un documento HTML e insertar informacion en el mismo.
Puntos importantes al programar scripts.
Imágenes clikeables.
A pesar que este tipo de elementos no está conectado directamente con los
scripts CGI pensé en incluirlos dado que también son una de las formas de
incrementar la interactividad entre el usuario y el web site.
Básicamente una imágen clikeable (es una acepción que inventé, ya fué la que
me pareció más correcta en castellano) es una imágen, un gráfico que cuando es
clikeada en alguna de sus partes envía las coordenadas X e Y de la posición del
mouse en ese momento y el server a partir de ellas genera un enlace con otras
páginas.
El uso más común de este tipo de imágenes es crear barras de herramientas
personalizadas, o regiones en un gráfico que permitan al usuario navegar hasta
un nuevo documento.
Partiendo de una imagen (un .GIF) elegiremos dentro de ella las áreas que
funcionarán como links a otros documentos.
Dichas áreas pueden ser definidas en base a uno o más de los siguientes
elementos.
Entonces una vez cargada la página en nuestro browser, cada vez que clikeemos
en alguna parte de la imagen , el browser enviará las coordenas de la ubicación
en la que nos encontrabamos (esos numeritos que aparecen en la barra de status)
al server, y luego de esperar su proceso, éste último nos devolverá la
respuesta correspondiente.
Este mecanismo (Server-side), induce un cierto retardo (el proceso por parte
del server de nuestro pedido) por lo cual recientemente Netscape introdujo un
un nuevo mecanismo conocido como Client-Side Image Maps el cual veremos a
continuación.
<MAP NAME="barradetareas">
<AREA SHAPE="RECT" COORDS="475,157,611,344" HREF="principal.htm">
<AREA SHAPE="RECT" COORDS="233,182,447,359" HREF="buscar.htm">
<AREA SHAPE="CIRCLE" COORDS="130,54,20" HREF="circulo.htm">
<AREA SHAPE="POLY" COORDS="46,27,57,33,58,23,68,35,46,27" HREF="acarita.htm">
</MAP>
<A HREF="/maps/dibujo.map">
<IMG SRC="/images/barrita.gif" USEMAP="#barradetareas" BORDER=0 ISMAP></A>
Desempaquetando información.
Aunque este tema puede resultar algo "técnico" creo que resulta interesante
incorporarlo al tutorial, ya que nos permite conocer el funcionamiento de esas
"cajas negras" que son las librerías, las cuales hemos utilizado al programar
nuestros scripts.
Sabemos que cuando usamos el método POST toda la información de un form es
"empaquetada" en una variable llamada QUERY_STRING, pero... en qué forma?
Como decíamos estos datos deben ser empaquetados en un único string, esto se
hace poniendo un "&" (ampersand) entre cada variable y reemplazando cada
espacio por un signo "+", con lo cual conseguimos que la variable quede así;
+--------------------------------------------------------------+
¦QUERY_STRING = "nombre=Sebastian&edad=22&equipo="Boca+Juniors"¦
+--------------------------------------------------------------+
Parsers CGI.
La rutina escrita para Perl es un poco (sólo un poco) más clara que su
correspondiente equivalente en C, por lo tanto la utilizaremos para la
explicación del funcionamiento de un parser.
Perl utiliza los llamados "arrays asociativos" que son muy similares
a los arrays que todos conocemos, excepto por la salvedad (y a la vez gran
ventaja) de que los índices no son númericos, sino alfanúmericos.
Cómo es esto ? En esta rutina, todos los campos que se separan son almacenados
en un array asociativo con el nombre @in. Si queremos acceder al contenido
del campo edad, por ejemplo, éste se encuentra en la posición "edad" y el
código empleado es el siguiente.
@in { 'nombre'};
+----------------------------------------------------------------------------+
¦# Perl Routines to Manipulate CGI input ¦
¦# [email protected] ¦
+----------------------------------------------------------------------------¦
¦# ReadParse ¦
¦# Lee datos envíados con POST o GET, los convierte a texto simple,y pone ¦
¦# un campo=valor en cada componente de la lista "@in" ¦
¦# También crea pares de campo/valores en %in, usando '\0' para separar ¦
¦# selecciones múltiples ¦
¦ ¦
¦sub ReadParse { ¦
¦ # Definición de las variables a utilizar. ¦
¦ local (*in) = @_ if @_; ¦
¦ local ($i, $loc, $key, $val); ¦
¦ ¦
¦ # De acuerdo al método de envío almacena en la variable $in el texto. ¦
¦ if ($ENV{'REQUEST_METHOD'} eq "GET") { ¦
¦ $in = $ENV{'QUERY_STRING'}; ¦
¦ } elsif ($ENV{'REQUEST_METHOD'} eq "POST") { ¦
¦ read(STDIN,$in,$ENV{'CONTENT_LENGTH'}); ¦
¦ } ¦
¦ ¦
¦ @in = split(/&/,$in); #separa en un array los contenidos de $in que se¦
¦ encuentran separados por "&" ¦
¦ ¦
¦ foreach $i (0 .. $#in) { ¦
¦ #Convierte los "+" en espacios. ¦
¦ $in[$i] =~ s/\+/ /g; ¦
¦ ¦
¦ # Separa el campo y su contenido . ¦
¦ ($key, $val) = split(/=/,$in[$i],2); # corta en el primer =. ¦
¦ ¦
¦ # Convierte %XX de números hexadecimales a alfanúmericos. ¦
¦ $key =~ s/%(..)/pack("c",hex($1))/ge; ¦
¦ $val =~ s/%(..)/pack("c",hex($1))/ge; ¦
¦ ¦
¦ # Asocia cada campo con su valor. ¦
¦ # usando \0 como separador de elementos múltiples(checkbox por ej) ¦
¦ $in{$key} .= "\0" if (defined($in{$key})); ¦
¦ $in{$key} .= $val; ¦
¦ ¦
¦ } ¦
¦ return 1; ¦
¦} ¦
+----------------------------------------------------------------------------+
Esta no es la única librería que existe para manejar CGI bajo Perl , pero
sí la más utilizada. Según el autor nuevas versiones incorporarán más
facilidades, tales como file uploading y otras.
Locking de archivos.
Cuando dos usuarios quieren leer/escribir un mismo archivo (en realidad los
scripts llamados por ellos) se produce un conflicto, el de saber quien tiene
la prioridad al hacerlo. Una manera de resolver este conflicto es crear un
archivo "lock" cuya sola presencia nos indique que el archivo esta siendo
accedido en ese momento.
Así cuando nuestro script pretenda leer/escribir el archivo, primero consultará
la existencia del "lock", si existe esperará un segundo y volverá a intentar
y en caso de que no exista lo creará y procederá a la consulta.
Un ejemplo comentado en Perl nos mostrará esta técnica:
+-------------------------------------------------------------------+
¦$salir = 'no'; ¦
¦ while ($salir != 'si') { ¦
¦ if (-e "/mini-gb.lock") { ¦
¦ # Si el archivo existe, esperamos 1 segundo. ¦
¦ sleep(1); ¦
¦ } ¦
¦ else { ¦
¦ # Al no existir el archivo, lo creamos y empezamos el proceso.¦
¦ open(LOCK,">/mini-gb.lock"); ¦
¦ close LOCK; ¦
¦ . . . . . . . . .Proceso de nuestro script. . . . . . . . . ¦
¦ ¦
¦ # Destrabamos el archivo (lo eliminamos) ¦
¦ unlink("/guestlock"); ¦
¦ ¦
¦ #Salimos de nuestra rutina ¦
¦ $salir = si; ¦
¦ } ¦
¦ } ¦
+-------------------------------------------------------------------+
Scripts avanzados.
A partir de este punto analizaremos en detalle los requisitos para el manejo
de documentos dinámicos, profundizando en el conocimiento de la forma de
trabajo del protocolo HTTP y los mensajes MIME.
Documentos Dinámicos
Actualmente existen tres métodos (si incluimos el gif multipart) para poder
manejar información dinámicamente, en orden de eficiencia estos son;
+----------------------------------------------------------------------------+
¦Client Pull ¦
¦El server envía un "stream" de información, incluyendo una directiva (en la ¦
¦respuesta HTTP) que dice "vuelva a cargar estos datos en 5 segundos" o "vaya¦
¦y cargue esta URL en 10 segundos". Despúes de que se cumple el tiempo especi¦
¦ficado, el browser hace lo que se le indicó, o sea recargar la página actual¦
¦o conseguir una nueva página. ¦
+----------------------------------------------------------------------------¦
¦Server Push ¦
¦El server envía un "stream" de información y el browser la muestra, pero ¦
¦sigue manteniendo la conexión abierta; cuando el server lo requiera, puede ¦
¦continuar enviando más información para que el browser la muestre, y así ¦
¦sucesivamente.. ¦
+----------------------------------------------------------------------------¦
¦Gif multipart ¦
¦Se trata del método más avanzado (lo vieron en WebTV?) que utiliza un nuevo ¦
¦formato de imagen GIF en donde se incluyen múltiples cuadros separados por ¦
¦comandos de animación, los cuales pueden ser vistos con el browser de ¦
¦Netscape partir de la versión 2.0 ¦
+----------------------------------------------------------------------------+
Client Pull
Para muestra basta un botón, así que de entrada prueben el siguiente código;
Y?? Qué pasó?, por el bien de este tutorial espero que el documento haya sido
recargado por el browser al pasar un segundo.
Esto lo logramos al agregar el tag "META" (el cual permite simular respuestas
HTTP en páginas HTML) que le dice al browser que el server le está enviando
un header con la indicación "Refresh: 1".
Cambiando el valor, cambiamos el tiempo de retardo obviamente.
Observemos que cada directiva "Refresh" es única y por tanto la página NO será
refrescada cada un segundo eternamente, sino una única vez y que al tratarse
de una respuesta HTTP (simulada) la misma debe figurar al comienzo de nuestra
página.
Otra cosa que podemos lograr con este tag es cargar otro URL luego de una
determinada cantidad de tiempo. La sintaxis es la siguiente:
Que hará que el browser luego de diez segundos de haber cargado la primera
página vaya y traiga la que se encuentra referenciada por la variable URL.
Un detalle importante es que debemos utilizar URLs absolutos, es decir incluir
en la definición el "http://..." y no emplear URLs relativos.
Más de uno se habrá dado cuenta de que estos dos documentos se llaman el uno
al otro cada tres segundos, generando una especie de "loop" infinito.
A partir de este ejemplo, podemos inducir varias otras combinaciones tales
como la de un documento que se llame a si mismo cada 0 segundos provocando así
también este tipo de "loops sin fin".
O podríamos hacer una cadena más larga, como la que sigue;
Página 1 +
• Página 2 + Con la cual obtendríamos una especie
¦ Página 3 + de animación aunque por cierto,
¦ Página 4 + bastante pobre.
¦ Página 5
+---------------------------+
Server Push
En contraste con el Client Pull, este mecanismo aprovecha que el server puede
mantener una conexión abierta por un tiempo indefinido, dejando espacio para
que sean enviadas varias respuestas secuencialmente.
Para lograrlo se utiliza un tipo MIME experimental (nuevo, no registrado aún
como standard) llamado "multipart/x-mixed-replace".
Un mensaje MIME multipart está compuesto de un header y una o más partes que
componen la totalidad del mensaje. El header indica como deben ser procesadas
las distintas partes del mensaje y cuales son los separadores de las mismas,
como ejemplo;
Content-Type: multipart/x-mixed-replace;boundary=SeparaPartes
Cuando el cliente encuentra este tipo en el header, hace un refresh del sector
correspondiente cada vez que una nueva parte del mensaje llega,
sobreescribiendo de esta manera la anterior.
Cada parte del mensaje tiene su propio header, el cual indica el tipo de datos
que esa parte contiene, "plain text", un gráfico GIF o HTML por ejemplo.
El header de cada parte siempre se encuentra debajo del separador que
hallamos especificado (en la línea que vimos le pusimos "SeparaPartes" de
nombre al separador , pero podríamos haber utilizado cualquier otro).
--SeparaPartes
El script que sigue es una version reducida del NPH 1.2 creado por Matt Wright
y en él veremos una implementación comentada del mecanismo que acabamos de
describir.
+----------------------------------------------------------------------------+
¦ #!/usr/bin/perl ¦
¦ # Variables ¦
¦ $veces = "1"; ¦
¦ $dirbase = "/WWW/images/animation/"; ¦
¦ @archivos = ("primero.gif","segundo.gif","tercero.gif","primero.gif"); ¦
¦ $tipo = "gif"; ¦
¦ ¦
¦ # Hacemos que el stream de datos fluya sin un buffer para hacerlo mas rapid¦
¦ select (STDOUT); ¦
¦ $| = 1; ¦
¦ ¦
¦ # Comienzo del contenido multipart. ¦
¦ print "Content-Type: multipart/x-mixed-replace;boundary=separador\n\n"; ¦
¦ print "--separador\n"; ¦
¦ ¦
¦ # Este for toma cada imagen de la secuencia, la envía, manda un separador ¦
¦ #y luego envía la siguiente, repitiendolo las veces que indique $veces. ¦
¦ for ($num=1;$num<=$veces;$num++) { ¦
¦ foreach $archi (@archivos) { ¦
¦ print "Content-Type: image/$tipo\n\n"; ¦
¦ open(GIF,"$dirbase$archi"); ¦
¦ print <GIF>; ¦
¦ close(GIF); ¦
¦ print "\n--separador\n"; ¦
¦ } ¦
¦ } ¦
+----------------------------------------------------------------------------+
GIF multipart.
En este caso no tendremos que programar nada y es por lejos la forma más simple
de armar una animación, aunque mantiene la desventaja de ser visualizados
únicamente por el Netscape 2.0 en adelante.
En definitiva se trata de ampliar las posibilidades del formato GIF89A (aquel
que nos permite utilizar backgrounds transparentes).
Los archivos .GIF tienen al comienzo un "header" que indica su tamaño y otros
datos, con programas como el Gif Construction Set ampliaremos este header e
incluíremos líneas con la secuencia de imágenes y comandos de control.
El header de una animación simple quedaría de la siguiente manera:
+-----------------------------+
¦ HEADERGIF89AScreen(320x200) ¦
¦ LOOP ¦
¦ CONTROL ¦
¦ IMAGE320x200,256colours ¦
¦ CONTROL ¦
¦ IMAGE320x200,256colours ¦
¦ CONTROL ¦
¦ IMAGE320x200,256colours ¦
+-----------------------------+
Ya que el Gif Construction Set trae un help bastante completo y es sencillo
de usar no quisiera extenderme más en el tema.
Sugerencia: Leer con el GifCon los .GIF que trae de ejemplo.
Counters.
El archivo ".htaccess".
Este archivo debe estar ubicado en el directorio que se desea proteger y dicha
protección afectará a todos los subdirectorios del mismo, a menos que posean
sus propios archivos ".htaccess".
Dado que se trata de un archivo de texto común podremos actualizarlo con
cualquier editor del que dispongamos.
+-----------------------------------------------+
¦ AutUserFile .htpasswd ¦
¦ AuthGroupFile /dev/null ¦
¦ AuthName Ingrese su user ID y su password. ¦
¦ AuthType Basic ¦
¦ ¦
¦ <Limit GET> ¦
¦ require user usuario1 usuario2 usuario3 ..... ¦
¦ </Limit> ¦
+-----------------------------------------------+
El comando "require" le dice al server cuales son los usuarios que están
autorizados en ese directorio. Este comando puede tomar dos formas, "require
user" para limitar el acceso según usuarios o bien "require group" para
limitar el acceso según grupos de usuarios.
Existen otros comandos que pueden ser implementados en este nivel, como
"allow" y "deny" que permiten otorgar o denegar (respectivamente) el acceso
a un dominio en particular.
El archivo .htpasswd .
Este archivo consiste en una lista de los user ID y sus password encriptadas,
es un archivo de texto común por lo que puede ser movido, copiado o borrado
como cualquier otro.
Por ejemplo:
pedro:WkSK1DE7N8.9.
pablo:hQty39EV1.g56
diego:JeB31vf9PSTgw
susana:EDRfRrfrw43q
Como no podemos crear una password encriptada "a mano" usaremos una herramienta
llamada htpasswd que permite construir este tipo de archivos.
Esta herramienta se usa de la siguiente manera:
Con el tema de las "passwords" damos por terminada la tercera parte de este
documento, lo que sigue es un apéndice con links que me fueron bastante útiles
al momento armarlo, la bibliografía utilizada y algo de vocabulario.
Terminar esta tercera parte fué algo más que un triunfo, (pensar que había
planeado tenerla lista para fines de marzo:), cada vez que agarraba el doc
surgía un tema nuevo, y así.
Releyendo las otras partes me doy cuenta que faltan algunos ítems (oh no..más
laburo :P) o que por lo menos están un poco incompletos, paciencia en cuanto
pueda sale una nueva versión corregida y aumentada.
Lo próximo que tengo en mente en cuanto a tutorials estará basado en el uso de
frames y JavaScript en páginas HTML, una tecnología interesante pero no madura
del todo en este momento, así como también una mini-introducción al lenguaje
Perl, de manera que en algunos meses más empezaré por ese lado.
A propósito, ustedes notarán que desde que empezó esto del tutorial mis
preferencias programáticas han ido cambiando a lo largo del tiempo.
Estos cambios tienen su fundamento; Perl es portable, es fácil de usar y de
aprender, es freeware y además es interpretado de manera que el ciclo edición/
testeo se hace mucho más corto.
Escribir este tutorial fué una tarea bastante grata, aprendí muchísimo tratan
do de explicar algunos conceptos,y como siempre para hacer de esta una tarea
completa espero sus comentarios (de los buenos y de los otros ;), en mi email:
[email protected] ,los cuales serán de gran ayuda en mis proyectos futuros.
Próximos Desarrollos.
El protocolo HTTP y HTTP-NG.
Meta Tags y su uso ( y abuso).
CGI scripts en otros lenguajes (Visual Basic por ejemplo)
HTML/CGI como front/end de nuestros programas.
Introduccion a Java y JavaScript.
Introduccion a Perl y aplicaciones CGI.
PD: Parece que no puedo dejar de escribir, no quería dejar de comentar que las
versiones HTML y Word del tutorial estarán disponibles en breve.
--
APENDICE: Librerías para la Programación de scripts CGI.
Estos son los URL de las librerías utilizadas en los ejemplos de este documento.
http://shani.net:80/~tls/guide/index.html
http://www.stars.com/Vlib/Providers/CGI.html
http://super.sonic.net/ann/delphi/cgicomp/detail.html
http://www.city.net/win-httpd/httpddoc/wincgi.htm
http://www.aspectse.com/Product/dbWeb/dbWeb.html
http://128.172.69.106:8080/cgi-bin/cgis.html
http://users.aol.com/thingtone/workshop/index.htm
Vocabulario - Siglas.
URL: Universal Resource Locator
Una nomenclatura que describe en forma compacta la ubicación de cada
recurso en la Internet y el protocolo utilizado para acceder al mismo.
Bibliografía.