CGI

Un CGI (Common Gateway Interface) es un programa que se ejecuta en el servidor por petición del navegador de un usuario. El CGI produce un resultado, el cual se envía al navegador que provocó la ejecución del programa. Los CGI dan dinamismo a la web. Las páginas web puras (archivos HTML) son archivos de texto y por tanto estáticos. Sin embargo, si en lugar de pedir una página web el navegador ejecuta un programa, éste puede generar la página “al vuelo” y decidir en el momento cómo va a ser la página.

Por ejemplo, imagine una página web que muestre la hora como texto. Está claro que no se puede poner la hora con el editor de páginas web, ya que cada vez que alguien vea la página la hora será distinta. La solución es crear un programa que se ejecute cada vez que alguien quiera ver la página. El programa genera la página web en el momento en que se ejecuta y así coloca la hora correcta. Por ello los CGI añaden dinamismo a las páginas web.

En principio los CGI se pueden realizar con cualquier lenguaje de programación, ya que pueden ser ejecutables (archivos .exe). Sin embargo, lo más recomendable es utilizar un lenguaje de script con facilidades para realizar CGI. Nos referimos al Perl.

La ventaja del Perl es que por su forma y por las bibliotecas y utilidades de que dispone, es ideal para la realización de CGI’s. Puede encontrar información sobre el Perl, en su web oficial www.perl.com.

Si no conoce el Perl, pero sí otros lenguajes de script más populares como el VisualBasic o JavaScript, nuestra recomendación es que utilice el ASP (Active Server Pages) para programar aplicaciones de servidor en entorno Windows; o bien utilice el lenguaje PHP para programar aplicaciones en entorno Linux. Si conoce el Perl, también podrá hacer aplicaciones ASP con PerlScript.

Las aplicaciones CGI son una de las primeras formas de desarrollo de aplicaciones dinámicas para la web, lo que añadido a su estabilidad hace que se trate de un sistema de desarrollo altamente extendido. Sin embargo, debe tener presente también sus pegas, entre las que destacan su lentitud frente a otros sistemas de desarrollo de aplicaciones dinámicas (como PHP o ASP) y sobre todo su mayor consumo de recursos en el servidor (CPU, memoria) al ejecutar un proceso independiente por cada petición.

El directorio cgi-bin

Los CGI no pueden ser colocados en cualquier directorio y esperar que funcionen. Un CGI ha de estar en un directorio que tenga permisos de ejecución de scripts, si se trata de un script en Perl, o de ejecución de archivos exe (que incluye scripts) si se trata de un ejecutable.

El directorio CGI-BIN es el único por defecto preparado para admitir CGI. Dispone de permisos de ejecución y tiene eliminados los permisos de lectura y listado de directorio para proteger mejor las fuentes. Normalmente colocará ahí sus propios CGI. Si aún así desea colocar CGI propios en otros directorios, puede hacerlo siempre que les asigne los permisos adecuados.

El permiso de escritura

Muchos de los CGI en Perl que están disponibles en Internet o que usted pueda crear, necesitarán escribir datos en archivos de texto u otro tipo de bases de datos. Sin embargo, por defecto no hay ni un solo directorio público en la web con permisos de escritura. Deberá asignarlos manualmente.

La recomendación es que sus archivos de datos residan en un directorio no accesible vía web, aunque sí pueda ser leído por los CGI. De esa forma evitará que cualquiera pueda leer sus archivos de datos desde la web. Tanto en entorno Windows como en Linux, disponga de un directorio DATA, que tenga los permisos de escritura asignados, de forma que no deberá hacer nada especial si sigue esta recomendación.

De todas formas, hay CGI disponibles freeware (gratis) en Internet que escriben en archivos que se encuentran en el mismo directorio del script. Esta es una práctica poco recomendable. Para que estos CGI funcionen es necesario que al directorio en el que se encuentran se le asignen permisos de ejecución y de escritura simultáneamente. Y esto constituye un importante agujero de seguridad para su sitio web.

¿Por qué no funcionan los CGI?

La experiencia dice que en la gran mayoría de los casos es por culpa de los permisos. Si el CGI intenta hacer algo para lo que no tiene permiso (normalmente, escribir algún dato), terminará silenciosamente.

En entorno Windows, hay además otras causas como pueden ser la extensión del archivo (que tiene que ser .pl y no .cgi). Asegúrese de que el script no utiliza características de Unix/Linux que no estén en Windows, como el MAIL.

Otra fuente de problemas son las rutas de directorio. En Linux se escriben de la siguiente forma:

$mypath = '/usr/bin/mydir';

Sin embargo, en Windows hay que usar el separador de directorios y comenzar las rutas absolutas por la letra de unidad. Es decir, la ruta anterior podría quedar de esta forma:

$mypath = 'c:usrbinmydir';

Suponiendo que existiese el directorio c:usr. Hay muchos directorios estándar en Linux que no existen en Windows. Cuando utilice rutas de este tipo tenga mucho cuidado con el tipo de comillas que utiliza para la cadena. Si utiliza comillas dobles (a veces es necesario si el path utiliza una variable) entonces debe utilizar \ para evitar la interpolación. Nuestro ejemplo quedaría de la siguiente forma con comillas dobles:

$mypath = "c:\usr\bin\mydir";

Las rutas relativas pueden ser problemáticas en Windows. Le recomendamos para mayor seguridad que utilice siempre rutas de directorio absolutas. Piense en las sentencias de su script que escriben en archivos o leen de ellos como las mayores candidatas a provocar el error.

En Windows no es necesario saber la ruta del intérprete Perl. Basta con que el script tenga la extensión .pl para que el servidor web lo encuentre y lo lance.

Hay veces que el navegador nos juega malas pasadas porque cachea un mal funcionamiento del script y nos da un error sin intentar comunicar con el servidor. Esto puede localizarse por la rapidez con la que el navegador nos da el error. Se recomienda tener a mano varios navegadores (Explorer y Netscape o Mozilla, por ejemplo) y alternarlos para ver si el problema es igual en ambos. En ciertas ocasiones un navegador se empeña en seguir mostrando error cuando el problema ya está resuelto.

El problema de programar CGI es lo difícil que resulta la fase de depuración. Para depurar un script que no funciona le recomendamos:

  • Paciencia. (Esto es lo más importante).
  • Escribir sentencias print para examinar valores de variables.
  • Comentar sentencias hasta que funcione, y luego ir descomentándolas una a una hasta encontrar la que hace fallar el script.

Perl y Windows

Una de las ventajas del Perl es que al ser un lenguaje interpretado es muy portable. Sin embargo, tiene límites. Hay funciones de la biblioteca estándar que sólo existen en sistemas Unix/Linux y no en Windows. Debe tener esto en cuenta, y que no se puede garantizar que los scripts en Perl que encuentre en Internet vayan a funcionar sin cambios en entorno Windows. Hay algunos que sí, pero normalmente es porque están diseñados con idea de portabilidad desde el principio.

Además, los CGI de terceros casi siempre requieren una adaptación previa (customize) para que funcionen. El motivo es que suelen depender de parámetros como rutas de directorios, nombres de archivos, etc. Por suerte, la zona de customización suele estar clara en la mayoría de los scripts, y consiste simplemente en cambiar valores de ciertas variables. La versión de Perl for Win32 es la de Active State.

Tenga en cuenta los siguientes puntos si piensa utilizar scripts en Perl que no están escritos para Windows:

  • En Unix/Linux, el intérprete de un script se lanza según la información de la primera línea, mientras que en Windows es según la extensión del archivo. Por ello, todos los scripts CGI en Perl deben llevar la extensión .pl (y no la extensión .cgi).
  • En Windows no existe el comando MAIL que envía archivos por email. Sin embargo, dispone en entorno Windows del componente ActiveX, ASPEmail, con el que podrá realizar envíos desde ASP. También dispone del aplicativo Blat con el podrá realizar los envíos desde sus scripts.
  • El servidor Web de Microsoft (IIS) es “Non parsed header” (NPH), lo que significa que cuando ejecuta un CGI no envía ninguna cabecera. Muchos scripts para Unix/Linux asumen que el servidor web enviará la cabecera, por lo que tal vez deba retocarlos. Los envíos de información deberían comenzar de esta forma (o con otra cabecera):
    print "HTTP/1.0 200 OKn";
    print "Content-type: text/htmlnn";

El módulo de biblioteca CGI.pm, resuelve estos problemas de forma más elegante, al incluir muchas funciones de ayuda para la programación de CGI’s.

Debido a la menor vinculación del los scripts Perl y de los CGI en general con el entorno Windows, hemos hecho hincapié, en los siguientes apartados que encontrará en esta página, en las utilidades y módulos incorporados para ayudarle en la programación de sus scripts en Perl en entorno Windows.

Blat.exe (envío por correo desde los scripts)

La utilidad freeware Blat.exe es un programa Windows (Win32) que envía correo electrónico, y que funciona con opciones desde la línea de comandos, por lo que es ideal para ser utilizado desde scripts. El modo de funcionamiento es básicamente el siguiente:

  • El mensaje que se quiere mandar por correo debe estar guardado en el disco duro. Por ello, normalmente guardaremos un temporal con el mensaje.
  • Invocamos a blat con los parámetros necesarios. Por ejemplo: system ("blat.exe archivo -t usuario@dominio.com -f desde@dom.com -s "El asunto" ");
  • Borramos el archivo temporal.

Con la versión de Blat 1.8.6b, las opciones disponibles son las siguientes:

Blat <filename> -to <recipient> [optional switches (see below)]
Blat -install <server addr> <sender's addr> [<try>[<port>[<profile>]]][-q]
Blat -profile [-delete | "<default>"] [profile1] [profileN] [-q]
Blat -h [-q]
-install <server addr> <sender's addr> [<try n times> [<port> [<profile>]]]
: set's SMTP server, sender, number of tries and port for profile
(<try n times> and <port> may be replaced by '-').
<filename> : file with the message body ('-' for console input, end with ^Z)
-to <recipient> : recipient list (also -t) (comma separated)
-tf <recipient> : recipient list filename
-subject <subj> : subject line (also -s)
-f <sender> : overrides the default sender address (must be known to server)
-i <addr> : a 'From:' address, not necessarily known to the SMTP server
-cc <recipient> : carbon copy recipient list (also -c) (comma separated)
-cf <file> : cc recipient list filename
-bcc <recipient> : blind carbon copy recipient list (also -c)(comma separated)
-bf <file> : bcc recipient list filename
-organization <organization>: Organization field (also -o and -org)
-body <text> : Message body
-x <X-header: detail> : Custom `X-´ header. eg: -x "X-INFO: Blat is Great!"
-r : Request return receipt.
-d : Request disposition notification.
-h : displays this help.
-q : supresses *all* output.
-debug : Echoes server communications to screen (disables `-q´).
-noh : prevent X-Mailer header from showing homepage of blat
-noh2 : prevent X-Mailer header entirely
-p <profile> : send with SMTP server, user and port defined in <profile>.
-server <addr> : Specify SMTP server to be used. (optionally, addr:port)
-port <port> : port to be used on the server, defaults to SMTP (25)
-hostname <hst>: select the hostname used to send the message
-mime : MIME Quoted-Printable Content-Transfer-Encoding.
-enriched : Send an enriched text message (Content-Type=text/enriched)
-html : Send an HTML message (Content-Type=text/html)
-uuencode : Send (binary) file UUEncoded
-base64 : Send (binary) file using base64 (binary Mime)
-try <n times> : how many time blat should try to send. from '1' to 'INFINITE'
-attach <file> : attach binary file to message (may be repeated)
-attacht <file>: attach text file to message (may be repeated)

Opcionalmente, en vez de -f y -i, pueden usarse las siguientes opciones:

-mailfrom <addr> The RFC 821 MAIL From: statement
-from <addr> The RFC 822 From: statement
-replyto <addr> The RFC 822 Reply-To: statement
-returnpath <addr> The RFC 822 Return-Path: statement
-sender <addr> The RFC 822 Sender: statement

La URL que mantiene actualmente el programa es www.blat.net, donde encontrará más información sobre la sintaxis, uso y ejemplos de este aplicativo para Windows.

La biblioteca CGI.pm

Se trata de un módulo orientado a objetos, de enorme utilidad si uno piensa dedicarse al desarrollo de CGI’s en Perl. Básicamente sustituye con ventaja a la biblioteca cgi-lib. Se puede usar directamente mediante una sentencia use. Lo que sí es imprescindible es estudiar su documentación. A continuación le exponemos un ejemplo de cómo usarlo:

use CGI qw(:standard :nph); #Se incluye el módulo en la forma nph
$query = new CGI; #Creamos un objeto CGI
print $query->header; #Esto envía las cabeceras adecuadas
print $query->start_html(); #Enviamos los tags HTML hasta el <body> incluido
print "<h1>Hola amigos</h1>"; #Esto se muestra en la página web
print $query->end_html(); #Muestra el </body> y el </html>

Puede verse lo sencillo que es crear una página web dinámica. La biblioteca tiene funciones para la creación de formularios, tablas, etc., aunque muchas veces será más cómodo enviar directamente el código HTML mediante un print. Sin embargo, el uso de cookies o la recuperación de variables de entorno como la IP o login del visitante, es cuestión de una simple llamada a un método del objeto CGI.

El módulo Win32:ODBC para acceso a bases de datos

Este es un excelente módulo, para crear aplicativos CGI en entorno Windows, de acceso a bases de datos ODBC de las que se dispone en su DSN. Para más información, visite la web con su documentación.

Ejemplo:

use Win32::ODBC;
$data = new Win32::ODBC($dsn); #Creamos el objeto
if (not defined($data) ) {
print "Error de conexión con la base de datos";
exit;
}

#Ejecutamos la sentencia SQL. Devuelve undef si va bien.
$res = $data->Sql($sentenciaSQL); if ( defined($res) ) {
print "Error en la sentencia SQL";
exit;
}

$data->FetchRow(); #Sacamos la primera fila del resultado

#%val contiene los nombres de los campos como claves
%val = $data->DataHash;

for $campos (sort keys %val) {
print "$campos "; #Mostramos los nombres de los campos
}
#Este bucle muestra los valores hasta terminar las filas
do {
%val = $data->DataHash;
for $campos (sort keys %val) {
print "$val{$campos} "; #Se muestran los valores
}
print "n";
}
while ( $data->FetchRow());

Utilizar objetos componentes en ActivePerl

ActivePerl puede crear objetos COM, y llamar a sus métodos y propiedades exactamente igual que VisualBasic. Para ello hay que utilizar varios módulos OLE:

use Win32::OLE; #Con esto usamos el módulo OLE principal
use Win32::OLE::Enum; #Para las colecciones

#Creamos el objeto y lo almacenamos en una referencia
$miobj = new OLE "Prog.Id";

#Las propiedades se asignan como si el objeto fuese una referencia a hash
$miobj->{propiedad} = "valor";

#Los métodos se invocan como los métodos normales en Perl
$miobj->metodo;

#Las colecciones las tratamos con una función que las convierte en arrays
#Por ejemplo, DameColeccion devuelve una referencia a un objeto colección
$micoleccion = $miobj->DameColeccion;

#La funcion All() convierte una colección COM en un array
@micoleccion = Win32::OLE::Enum::All($micoleccion);

#Ahora podemos iterar sobre los objetos en la forma habitual en Perl
foreach $obj (@micoleccion) {
$obj->metodo;
}

Otros módulos de la CPAN disponibles

File::Slurp

Sencillo pero muy útil para leer, escribir y modificar archivos de texto orientados a líneas.

Ejemplos:

use File::Slurp; #Con esto usamos el módulo.

#Lee un archivo y coloca todos sus datos en $buffer
$buffer = read_file($archivo);

#Lee el archivo y coloca sus líneas en el array
@lineas = read_file($archivo);

#Lee el directorio y coloca cada archivo o subdirectorio
#que contiene en el array
@items = read_dir($directorio);

#Crea o sobreescribe el archivo con el buffer
overwrite_file($archivo, $buffer);

#Añade el buffer al final del archivo
append_file($archivo, $buffer);

Business::CreditCard

Verifica tarjetas de crédito a nivel algorítmico.

use Business::CreditCard;
validate($numero); #Devuelve 1 si el número de tarjeta es autoconsistente
cardtype($numero); #Devuelve una string con el nombre del tipo de tarjeta
generate_last_digit($numero); #Genera el último dígito

Conjunto de módulos libwww junto con el parche para que funcionen en Win32

Se trata de un conjunto de módulos que proveen de un interface (API) para el acceso a la web. El principal propósito de la biblioteca es suministrar clases y funciones que permitan escribir clientes www. Con la ayuda de estos módulos es muy sencillo escribir scripts que accedan a direcciones web, FTP, etc. Debido a su complejidad y a la gran cantidad de módulos que incorpora (8 conjuntos de módulos), se recomienda su estudio antes de usarla. El sitio oficial es el de Linpro.

Enlaces de interés

Para mayor información sobre los conceptos mostrados en esta página, le relatamos a continuación algunos enlaces a sitios web de interés:

PERL Sitio oficial de PERL.
PERL Sitio oficial de PERL.
Active State Web con aplicativo PERL para Windows.
Linpro Sitio oficial con módulos que proveen de interfaz API para acceso web.
CGI.pm Documentación completa sobre este módulo.
Blat Sitio oficial sobre esta utilidad freeware para envío de mensajes.
Win32::ODBC Documentación completa sobre el módulo ODBC para Windows.