Manual de uso de CGI
Que es un CGI
CGI (Common Gateway Interface) es el interfaz normalizado
que utilizan los servidores de WWW (httpd) para comunicarse con aplicaciones
externas. El CGI permite al servicio WWW interactuar con otras aplicaciones,
servicios de información o bases de datos.
El CGI especifica como se pasan los datos desde el servicio WWW a una
aplicación externa y como se recuperan los resultados. Como todo en el WWW, el
interfaz CGI es simple pero muy potente.
El CGI define dos mecanismos para pasar datos desde el servicio WWW a una
aplicación externa, el primero utiliza variables de entorno y el segundo la
entrada estandard. La recuperación de resultados se produce siempre a través de
la salida estandard.
El primer método recibe el nombre de método GET y se utiliza principalmente
para búsquedas en documentos por palabra clave. El segundo método, llamado POST,
se utiliza para procesar el contenido de formularios.
Junto con las opciones del servidor el protocolo CGI se basa tambien en los
mecanismos de los clientes para introducir información. A continuación revisamos
estos mecanismos.
ISSEARCH
Introduciendo la directiva <ISSEARCH> en la página
HTML, esta página se convierte en un documento de consulta. Estos documentos se
generan por aplicaciones CGI y en ellos el cliente WWW añade un cuadro de
introducción de texto con el cual se pueden realizar consultas al documento. Las
consultas se resuelven por el CGI que generó la página.
Las consultas ISSEARCH se resuelven por el método GET.
IMAGEMAP
El método IMAGEMAP registra pulsaciones del ratón sobre una
imagen. Por este método es posible conocer la posición de pulsación del ratón en
el cliente WWW.
El uso principal de las imágenes pinchables es la creación de menús gráficos.
EL método IMAGEMAP se gestiona por una aplicación CGI específica que se
incluye en la mayoria de servidores HTTP. En el NCSA HTTPD la aplicación se
denomina imagemap, en CERN HTTPD la aplicación se denomina htimage.
Los CGI que gestionan la información del método IMAGEMAP utilizan mascaras
donde se definen las acciones a ejecutar dependiendo de la posición de la imagen
donde se haya pinchado.
Un ejemplo claro es la barra de menus que tenemos instalada en nuestra BBS,
su configuración es la siguiente:
Formularios
Los formularios son un elemento esencial del CGI. Los
formularios permiten introducir en un cliente WWW información estructurada que
puede utilizarse como datos de entrada de una aplicación CGI. Para el soporte de
formularios el lenguaje HTML permite la definición de de distintos tipos de
campos.
Un formulario en HTML se limita con los marcadores <FORM> y
</FORM>. Un formulario puede incluirse en cualquier parte de un documento
HTML, y sobre un mismo documento pueden insertarse distintos formularios.
La sintaxis del marcador de formulario es la siguiente:
<FORM METHOD="método" ACTION="URL del CGI">
- Método es GET o POST.
- El URL del CGI es el nombre de la aplicación CGI que procesará la
información del formulario.
Campos en formularios
Los formularios en HTML soportan distintos tipos
de campos. La sintaxis general del marcador de campo en HTML es la siguiente:
<INPUT TYPE="tipo" NAME="nombre" VALUE="valor">
Los típos válidos de campos de formulario son los siguientes:
<FORM
ACTION="http://www.infase.es/cgi-bin/mail?sobreve" METHOD=POST>
Estos
controles admiten los modificadores siguientes, ya indicados:
- size. Tamaño del campo.
- width.
- maxlength.
Otros controles tienen una sintaxis especial.
La siguiente contrucción permite crear un control de selección sobre una
lista de opciones predefinidas.
<SELECT NAME="nombre">
<OPTION >Texto de la seleccion 1
<OPTION >Texto de la seleccion 2
El control <OPTION> permite los
modificadores siguientes:
El siguiente control permite introducir texto de cualquier longitud.
<TEXTAREA NAME="nombre">.
Texto que aparecerá en el recuadro. Es opcional.
Este control acepta los atributos específicos
- ROWS. Número de filas.
- COLS. Número de columnas.
Codificación de la información de un formulario
El contenido de un
formulario se codifica para su transmisión entre el cliente y el servidor HTTP,
y de este hasta la aplicación CGI. Esta codificación asocia el contenido de los
campos con el nombre de los mismos.
La sintaxis general de esta codificación es la siguiente:
campo=contenido&campo=contenido&...
Una colección de parejas nombre de campo, contenido del campo
separadas por simbolos '&' y donde los espacios en 'contenido' se sustituyen
por signos '+'.
Para facilitar el proceso de extracción de la información desde este formato,
los servidores de HTTP suelen incluir una libreria de funciones. A modo de
ejemplo, el servidor HTTPD de NCSA define una libreria con las funciones para
extraer las parejas nombre de campo - valor de la información recibida por el
CGI.
Estas funciones se utilizan por las aplicaciones CGI como muestra el
siguiente listado:
typedef struct {
char name[128];
char val[128];
} entry;
int m,x;
cl = getenv("QUERY_STRING");
for(x=0;cl[0] != '\0';x++) {
m=x;
getword(entries[x].val,cl,'&');
plustospace(entries[x].val);
unescape_url(entries[x].val);
getword(entries[x].name,entries[x].val,'=');
}
Método GET
En el método GET la aplicación CGI recibe la información a
través de variables de entorno. El proceso de lanzamiento de una aplicación CGI
con el método GET es el siguiente.
- El cliente WWW solicita un servicio de una aplicación CGI.
- El servidor HTTPD recibe la solicitud y los datos de entrada.
- El servidor crea un entorno y crea variables en el con los datos de
entrada.
- El servidor ejecuta la apliación CGI en este entorno.
- La aplicación CGI procesa las variables de entorno y recupera los datos de
entrada.
- La aplicación CGI se ejecuta produciendo un resultado sobre su salida
estandard.
- EL servidor HTTP redirecciona la salida estandard de la aplicación CGI
hacia el cliente WWW.
- El cliente WWW recibe el resultado de su consulta.
A continuación incluimos el listado de una aplicación CGI que desarrolla el
método GET. Como puede observarse la información pasa a la aplicación CGI a
través de la variable de entorno QUERY_STRING.
/*
* Ejemplo de aplicación CGI operada
* a través de la acción GET
*
* INFASE Comunicaciones S.L. 1995
*
* Basada en scripts originales de NCSA HTTPD
*/
#include
#include
/*
* Funciones de análisis de los datos del formulario
* Las funciones estan definidas en util.c
*/
typedef struct {
char name[128];
char val[128];
} entry;
void getword(char *word, char *line, char stop);
char x2c(char *what);
void unescape_url(char *url);
void plustospace(char *str);
main(int argc, char *argv[]) {
entry entries[10000];
register int x,m=0;
char *cl;
/*
* Imprime la cabecera que indica al servidor HTTP que los
* datos que siguen a continuación son de tipo texto html
*/
printf("Content-type: text/html%c%c",10,10);
/*
* Comprueba que los parámetros del programa se pasan
* por el método GET
* <FORM METHOD="GET" ACTION="/cgi-bin/post">
*/
if(strcmp(getenv("REQUEST_METHOD"),"GET")) {
printf("Esta aplicación debe activarse por el método GET\n");
exit(1);
}
/*
* En el método GET la información pasa al cgi
* a través de la variable de entorno QUERY_STRING
*/
cl = getenv("QUERY_STRING");
if(cl == NULL) {
printf("No hay información para decodificar.\n");
exit(1);
}
/*
* La sintaxis de la información es la siguiente
* campo=contenido&campo=contenido&...
* Los espacios en 'contenido' se sustituyen por signos '+'.
* Las siguientes funciones extraen la información.
*/
for(x=0;cl[0] != '\0';x++) {
m=x;
getword(entries[x].val,cl,'&');
plustospace(entries[x].val);
unescape_url(entries[x].val);
getword(entries[x].name,entries[x].val,'=');
}
/*
* Imprime el resultado del programa a través de la salida
* estándard. En este caso imprime el valor de todos los
* campos rellenados por el usuario. Imprime el resultado
* formateado en HTML.
*/
printf("<H1>Resultados de la consulta");
printf("He recibido las siguientes parejas de valores:<p>%c",10);
printf("<ul>%c",10);
for(x=0; x <= m; x++)
printf("<li> <code>%s = %s%c",entries[x].name,
entries[x].val,10);
printf("%c",10);
}
Método POST
El método POST es el método recomendado para el paso de
información de formulario a una aplicación CGI. En este método la información se
pasa a través de la entrada estandar de la aplicación CGI.
El proceso de lanzamiento de una aplicación CGI con el método POST es el
siguiente.
- El cliente WWW solicita un servicio de una aplicación CGI.
- El servidor HTTPD recibe la solicitud y los datos de entrada.
- El servidor ejecuta la apliación CGI pasandole la información a través de
la entrada estandar.
- La aplicación CGI procesa su entrada estandard y recupera los datos de
entrada.
- La aplicación CGI se ejecuta produciendo un resultado sobre su salida
estandard.
- EL servidor HTTP redirecciona la salida estandard de la aplicación CGI
hacia el cliente WWW.
- El cliente WWW recibe el resultado de su consulta.
/*
* Ejemplo de aplicación CGI operada
* a través de la acción POST
*
* INFASE Comunicaciones S.L. 1995
*
* Basada en scripts originales de NCSA HTTPD
*/
#include <stdio.h>
#include >stdlib.h>
#define MAX_ENTRIES 10000
/*
* Funciones de análisis de los datos del formulario
* Las funciones estan definidas en util.c
*/
typedef struct {
char *name;
char *val;
} entry;
char *makeword(char *line, char stop);
char *fmakeword(FILE *f, char stop, int *len);
char x2c(char *what);
void unescape_url(char *url);
void plustospace(char *str);
main(int argc, char *argv[]) {
entry entries[MAX_ENTRIES];
register int x,m=0;
int cl;
/*
* Imprime la cabecera que indica al servidor HTTP que los
* datos que siguen a continuación son de tipo texto html
*/
printf("Content-type: text/html%c%c",10,10);
/*
* Comprueba que los parámetros del programa se pasan
* por el método POST
* <FORM METHOD="POST" ACTION="/cgi-bin/post">
*/
if(strcmp(getenv("REQUEST_METHOD"),"POST")) {
printf("Esta aplicación debe activarse por el método POST\n");
exit(1);
}
/*
* Comprueba que los datos de entrada corresponden al contenido
* de un formulario
*/
if(strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded")) {
printf("La entrada a la aplicación no es un formulario\n");
exit(1);
}
/*
* Analiza los datos de entrada y los introduce en un vector de
* parejas de valores, siendo el primero el nombre del campo
* y el segundo el valor que contiene. El nombre se declara en la
* definición del formulario. El valor es el introducido por el
* usuario. Todos los campos se tratan como cadenas de caractéres.
*
* El campo <INPUT TYPE="text" NAME="Prueba">
*/
/*
* En el método POST la información pasa al cgi
* a través de la entrada estandar (stdio)
*/
cl = atoi(getenv("CONTENT_LENGTH"));
/*
* La sintaxis de la información es la siguiente
* campo=contenido&campo=contenido&...
* Los espacios en 'contenido' se sustituyen por signos '+'.
* Las siguientes funciones extraen la información.
*/
for(x=0;cl && (!feof(stdin));x++) {
m=x;
entries[x].val = fmakeword(stdin,'&',&cl);
plustospace(entries[x].val);
unescape_url(entries[x].val);
entries[x].name = makeword(entries[x].val,'=');
}
/*
* Imprime el resultado del programa a través de la salida
* estándard. En este caso imprime el valor de todos los
* campos rellenados por el usuario. Imprime el resultado
* formateado en HTML.
*/
printf("<H1>Resultados de la consulta");
printf("He recibido las siguientes parejas de valores:<p>%c",10);
printf("<ul>%c",10);
for(x=0; x <= m; x++)
printf("<li> <code>%s = %s%c",entries[x].name,
entries[x].val,10);
printf("%c",10);
}
Paso de información como argumentos del programa CGI
Existe un tercer
método de paso de información desde el cliente WWW y la aplicación WWW. Este
método es complementario a los métodos POST y GET.
La información, en este método se añade al URL en el cliente WWW. La
información a la derecha del URL se transfiere como argumento de la aplicación
CGI. Podemos utilizar el caracter '?' para separar distintos argumentos la
aplicación CGI.
A continuación a modo de ejemplo incluimos el listado de una aplicación que
procesa la información de URL. Este programa envia por correo electrónico, el
contenido de un formulario a los usuarios indicados en el URL.
La sintaxis del URL es:
<FORM METHOD="POST" ACTION="/cgi-bin/mail?dirección-correo">
'/cgi-bin/mail' es el nombre del URL y 'dirección-correo' es una dirección
válida de correo electrónico.
/*
* CGI para envio de un formulario por correo
*
* sintaxis:
* mail?usuario[,usuario[,usuario ...]]
*
* INFASE Comunicaciones 1995
*/
#include <stdio.h>
#include <stdlib.h>
#define MAX_ENTRIES 10000
typedef struct {
char *name;
char *val;
} entry;
char *makeword(char *line, char stop);
char *fmakeword(FILE *f, char stop, int *len);
char x2c(char *what);
void unescape_url(char *url);
void plustospace(char *str);
void Error(char *msg)
{
printf("<B>ERROR<B><P>\n");
printf("%s",msg);
}
main(int argc, char *argv[]) {
entry entries[MAX_ENTRIES];
register int x,m=0;
int cl;
FILE *phfp;
char cmdstr[300];
int i;
printf("Content-type: text/html%c%c",10,10);
if (argc != 2)
{
printf("número de argumentos erroneo. Debe indicar el
destinatario del mail%c",10);
exit(0);
}
if(strcmp(getenv("REQUEST_METHOD"),"POST")) {
printf("Este script debe referenciarse con METHOD a POST.\n");
exit(1);
}
if(strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded")) {
printf("La entrada no es un formulario");
exit(1);
}
cl = atoi(getenv("CONTENT_LENGTH"));
for(x=0;cl && (!feof(stdin));x++) {
m=x;
entries[x].val = fmakeword(stdin,'&',&cl);
plustospace(entries[x].val);
unescape_url(entries[x].val);
entries[x].name = makeword(entries[x].val,'=');
}
/* envia por correo el mensaje generado */
sprintf(cmdstr,"/bin/mail %s",argv[1]);
phfp = popen(cmdstr,"w");
if (phfp == NULL)
Error("Error al abrir comando mail");
for(x=0; x <= m; x++)
fprintf(phfp,"%s = %s%c",entries[x].name, entries[x].val,10);
fprintf(phfp,"\n.\n");
if ( pclose(phfp) )
Error("Error al cerrar comando mail");
/* devuelve el mensaje de aceptación al usuario */
printf("<H1>Operación procesada");
printf("Su operación ha sido procesada.");
printf("<P>");
printf("<A HREF=\"/\">Volver a la portada");
printf("<HR>");
}
Variables de entorno
Existen distintas variables de entorno que utilizan
el servidor HTTPD y la aplicación CGI para intercambiar información adicional.
Esta información permite al cliente conocer información adicional sobre los
datos de entrada o sobre el estado del servidor.
A continuación incluimos un programa CGI que imprime el contenido de las
variables de entorno.
#!/bin/sh
echo Content-type: text/plain
echo
echo CGI/1.0 test script report:
echo
echo argc is $#. argv is "$*".
echo
echo SERVER_SOFTWARE = $SERVER_SOFTWARE
echo SERVER_NAME = $SERVER_NAME
echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE
echo SERVER_PROTOCOL = $SERVER_PROTOCOL
echo SERVER_PORT = $SERVER_PORT
echo REQUEST_METHOD = $REQUEST_METHOD
echo HTTP_ACCEPT = "$HTTP_ACCEPT"
echo PATH_INFO = "$PATH_INFO"
echo PATH_TRANSLATED = "$PATH_TRANSLATED"
echo SCRIPT_NAME = "$SCRIPT_NAME"
echo QUERY_STRING = "$QUERY_STRING"
echo REMOTE_HOST = $REMOTE_HOST
echo REMOTE_ADDR = $REMOTE_ADDR
echo REMOTE_USER = $REMOTE_USER
echo AUTH_TYPE = $AUTH_TYPE
echo CONTENT_TYPE = $CONTENT_TYPE
echo CONTENT_LENGTH = $CONTENT_LENGTH
Ejemplos CGI
© INFASE Comunicaciones S.L. 1995