Artículo para la revista Linux Actual número 15:

Javier Fernández-Sanguino Peña jfs@computer.org

24 julio 2000


En ésta entrega del desarrollo de bases de datos en Internet con GNU/Linux se van a ver los aspectos específicos del desarrollo de la aplicación que ya se describió en los anteriores.

1. Introducción

Como ya se introdujo en el número anterior, la aplicación concreta que se va a abordar es la creación de una Asociación de Antiguos Alumnos en Internet, para que sea posible, a dichas personas, acceder a través de un cliente universal (un navegador de WWW) a una base de datos con la información relativa a los demás antiguos alumnos.

De esta forma esta base de datos puede servir para que los distintos exalumnos puedan comunicarse entre sí, saber dónde se encuentra trabajando cada uno y así estrechar los lazos que ya en su día se generaron en el Instituto, Escuela o Universidad donde se conocieron.

La aplicación en concreto se dividirá en:

En este artículo se van a ver todos estos aspectos de la aplicación, acompañándolos del listado de código necesario para llevarlos a cabo. Como ya se introdujo en los anteriores artículos, para implementar esta aplicación se va a utilizar WWW-SQL (en su versión para PostgreSQL).

******************** FIGURA 1 *************************

2. WWW-SQL

Ya se vio en el artículo anterior una breve introducción al lenguaje de programación de scripts WWW-SQL en comparación con otras técnicas para programar el acceso a servidores de web desde páginas HTML. Aquí se hará más hincapié en la estructura del lenguaje y en sus posibilidades.

WWW-SQL es un programa CGI diseñado para crear páginas de web desde bases de datos PostgreSQL o MySQL, implementado por James Henstridge. El programa viene acompañado de un completo manual con algunos ejemplos, pero aquí se resumen algunas de sus capacidades.

La función de WWW-SQL es procesar una página HTML e interpretar determinadas órdenes contenidas en ésta, calcular los resultados de ejecución de estas órdenes y devolver la página modificada. Como el lector puede adivinar, las órdenes que va a ofrecer el lenguaje van a estar, fundamentalmente, relacionadas con el acceso a bases de datos.

La sintaxis de las marcas reconocidas por WWW-SQL es la siguiente:

<! SQL orden argumento1 argumento2 ... >

La orden es cualesquiera de los comandos reconocidos por el lenguaje, mientras que argumento1 y argumento2 (aunque puede haber más argumentos) son los datos que se le dan a dicho comando para variar su comportamiento.

Algunas de los comandos más importantes en WWW-SQL son:

Además, el lenguaje tiene soporte para dos tipos de estructuras de control (if.. then...elseif..endif, y while..done), posibilidad de gestionar las variables recibidas a través del CGI script (rellenadas, por ejemplo, desde un formulario), capacidad de gestionar Cookies y algunas estructuras ya implementadas para poder gestionar fácilmente tablas y algunos elementos de formularios (como listas desplegables).

La estructura normal de una página con SQL embebido con este lenguaje tendrá, típicamente, esta estructura:

<!-- Cabeceras HTML -->
<!sql connect>
<!sql database dbname>
<!-- código HTML y órdenes www-sql -->
<!sql close>
<!-- Pie HTML -->

Un programador experimentado podrá echar en falta muchas capacidades como: estructuras de control más potentes, la posibilidad de modularizar el código a través de funciones, etc.. pero WWW-SQL es en realidad la alternativa menos compleja para abordar el desarrollo de los sistemas que aquí se están tratando. Si uno desea un lenguaje más expresivo puede probar con PHP/FI o con PERL embebido.

En cualquier caso, WWW-SQL es la alternativa más interesante cuando se quiere hacer el desarrollo de un prototipo, lo que se llama comúnmente "prueba de concepto".

3. Desarrollo del servidor.

El esquema general del servidor se muestra en la figura 2. Como se puede ver en ésta el servidor se va a dividir, fundamentalmente en dos partes, una parte de contenidos públicos, en los que no se va a restringir el acceso al usuario y una parte de contenidos privados en los que se va a solicitar una autenticación previa.

Por otro lado, es necesario tener alguna forma de que los usuarios nuevos del servidor introduzcan sus datos para darse de alta por primera vez.

***************** FIGURA 2 ***************************

Además, en este tipo de sistemas en los que se va a almacenar información personal, será necesario cuidarse de que los usuarios que se dan de alta son reales. Ésta sería la función de un "certificador" (o notario), que diera fe de que los datos introducidos corresponden a una persona real y que puede pertenecer por pleno derecho a la asociación. Ésta figura y la forma de introducirla no se va a ver en este artículo pues se sale del esquema propuesto de desarrollo. En cualquier caso en esta serie se pretende hacer una exposición del problema técnico existente no del problema también en sus aspectos sociológicos (pero que en cualquier caso no se deben olvidar).

Evidentemente, para que el servidor tenga una cierta uniformidad en cuanto a aspecto, las páginas tendrán que facilitar al desarrollador que "obvie" los aspectos correspondientes a la parte estética y se pueda centrar en el desarrollo de la aplicación. Esto puede hacerse fácilmente haciendo uso de WML (Website Meta Language), este tema es muy interesante pero se sale del ámbito de este artículo.

Como el lector puede suponer, la parte del desarrollo del servidor en la que se va a hacer hincapié es la parte de la programación en el interfaz del acceso a la base de datos, así como la parte de autentificación. Se va a empezar con la entrada de nuevos usuarios, es decir el alta de los mismos, y se podrán empezar a ver algunas de las potencias (y debilidades) de WWW-SQL.

3.1 Alta de usuarios.

El alta de usuarios se hará, como es habitual a través de un formulario de entrada HTML en el que el usuario rellenará los datos y enviará éstos al servidor al pulsar el botón de "Envío".

La función del servidor una vez llevada a cabo esta tarea sería:

El último paso es necesario para que se haga la entrada de los datos en dos partes. Como ya se vio en el esquema entidad relación, en principio todos los usuarios registrados tienen que tener un conjunto de datos, pero hay otros, como teléfono o dirección de correo electrónico, que no tienen por qué estar presentes y finalmente, una tabla (la de empresas y trabajadores en ella) en la que sólo se han de introducir datos si el usuario está trabajando.

Gracias a esto el alta de los usuarios es sencilla, como se muestra en el listado 1. Si el usuario ha introducido el DNI, elemento que se considera imprescindible, se insertarán los datos dados en la base de datos. Si además se han introducido otra serie de datos (como son el número de teléfono y la dirección de correo) se introducirán estos en las tablas correspondientes. Finalmente, si el usuario ha indicado que está trabajando se le dirigirá a la segunda parte de la entrada de datos.

*************** LISTADO 1 ***********************

Como se ve la entrada de los datos básicos no tienen gran complicación, se podría hacer más compleja añadiendo comprobaciones de tipos de datos antes de introducirlos, pero otras funciones, como la detección de problemas de inserción no pueden "interceptarse" en WWW-SQL. Es aquí donde vemos los primeros problemas y debilidades de éste. Todo funciona bien si los datos de entrada son correctos y no se encuentra con casos "extraños". Pero si se da cualquier problema, el error se le mostrará directamente al usuario en la página HTML devuelta, ya que no es posible "interceptarlo". En cualquier caso esta implementación nos sirve como prototipo. Este tipo de errores sólo se pueden mejorar si se reimplementa el interfaz en un lenguaje más versátil que soporte más posibilidades.

La entrada de datos de empresas resulta algo más compleja. Cuando un usuario se da de alta como trabajador y quiere indicar la empresa en la que está trabajando y su puesto, pueden darse dos casos, el caso de que la empresa no exista ya en la base de datos y sea el usuario el encargado de introducir los datos de ésta, o el caso de que la empresa ya exista y el usuario pueda sencillamente seleccionarla.

El interfaz que permite dar de alta estos datos tiene que contemplar ambos casos. Se puede considerar que es el usuario el que tiene que introducir siempre los datos de la empresa en la que trabaja. Pero entonces no podrá "ver" las empresas que ya están en la base de datos, y se dará el caso de que existan múltiples personas que trabajan en la misma empresa pero que no sea "la misma" a efectos de la base de datos. Si sucede esto se está duplicando de forma innecesaria información. También puede suceder que sólo se le deje al usuario seleccionar una empresa de las ya existentes, con lo que se limita la versatilidad del interfaz dado que tiene solicitar a alguien (quizás al administrador) que dé de alta nuevas empresas para que pueda él indicar en el interfaz que está trabajando en ella.

Por ello la opción elegida es la mostrada en el listado 2, en el que la diferencia fundamental con respecto al formulario de entrada de datos personales, es que parte del formulario se construye en base a la información de la base de datos.

Así, por un lado el usuario introduce siempre información de su cargo y departamento. Tiene que haber dos opciones:

************** LISTADO 2 *************************

Tras esto, como se muestra en el listado 3, se procederá a enviar los datos a un programa encargado de tratarlos. Si el usuario ha introducido una nueva empresa, ésta será introducida junto con sus datos en la tabla correspondiente. Y, en cualquier caso, se introducirá la información relativa del puesto y cargo que desempeña la persona dentro de la empresa en la tabla que identifica las relaciones laborales entre personas y empresas.

***************** LISTADO 3 **************************

Una mejora a estos formularios sería ofrecer la posibilidad de realizar entre la lista de las empresas, por ejemplo, búsquedas de cadenas o ser capaz de comprobar que una empresa que se va a introducir se parece "sospechosamente" a otra ya introducida (por ejemplo, porque sea el mismo nombre pero sin acentos). Pero en principio el prototipo es suficientemente funcional. En realidad se puedan hacer muchas mejoras para que luego, en el uso diario, se evite que los usuarios introduzcan empresas distintas que luego, realmente, son la misma.

3.2 Autenticación.

Para lograr limitar el acceso a la información contenida en la base de datos, con el fin de mantener el propósito de la asociación, es necesario que los usuarios sean autenticados antes de acceder a la parte privada del servidor. No interesa que cualquiera pueda acceder a los datos generados de todos los miembros.

¿Cómo se puede saber si quién accede tiene derecho, o no, de consultar los datos? Muy sencillo, sólo aquel que ya ha sido registrado puede hacerlo por lo que se necesita realizar algún tipo de pregunta con la que se puede saber que la persona que está accediendo ha sido registrado previamente. Para hacer la pregunta se puede escoger parte de la información utilizada en el registro, pero ha de ser de tal manera que el que accede, al darla, está demostrando de forma fehaciente su identidad.

Ésta no es la única posibilidad para solventar este tipo de situación. Habitualmente, en los servidores con algún tipo de autenticación de usuarios, se le da la posibilidad a éstos para elegir un nombre de usuario y una clave que se introducen al registrarse. El problema surge, sin embargo, cuando pasa mucho tiempo desde que el usuario se registró y vuelve a acceder. Dándose el caso, frecuente, de que se haya olvidado la contraseña elegida y se tiene que solicitar su envío. Por las condiciones del servicio que se va a implementar es más que posible que se de éste tipo de situación, ya que en principio no tiene mucho sentido realizar consultas diarias.

Para evitar este problema en el diseño planteado, se ha optado por preguntar al usuario información que sólo éste conoce y no vaya a olvidar con facilidad.

Si se estudia la información almacenada en la base de datos sobre cada persona, se puede ver que hay sólo son algunos los campos que sólo vaya a ser conocidos por el que acceder y no puedan estar sujetos a un ataque por "fuerza bruta" (probar todas las combinaciones posibles hasta encontrar una respuestas válida).

Sin embargo sí que se pueden escoger parejas de campos que sea más improbable que puedan ser conocidas al mismo tiempo. Por ello se ha elegido dentro del desarrollo que el usuario tenga que responder con dos datos que va a conocer siempre y no olvidará fácilmente y que, por otro lado, es difícil que otra persona pueda conseguir reunir.

Los datos escogidos han sido el DNI y la fecha de nacimiento. La función del interfaz a la hora de autenticar será, por tanto, solicitar éstos al usuario y comprobar si son correctos. Esto es, si hay algún usuario en el que concuerden ambos valores, de forma que se podrá saber quién ha sido el usuario registrado. Evidentemente, ningún sistema de autenticación es perfecto y éste, también, será susceptible de fallos.

En cualquier caso, queda aún pendiente establecer algún mecanismo para que el servidor "sepa" que el usuario ha sido autenticado y no le pregunte esta información cada vez que quiera acceder al área privada.

Hay por lo menos dos mecanismos para hacer éstos, y los dos derivan de el hecho de que las transacciones a través del protocolo HTTP carecen, en principio, del concepto de "estado":

Para facilitar el desarrollo se ha elegido éste último ya que es un mecanismos que se integra muy bien con el esquema de base de datos propuesto. De esta forma se puede encargar la base de datos de guardar también la información relacionada con las sesiones si se desea.

Hay que destacar, sin embargo, que se podría llegar a utilizar autenticación basada en el servidor si se utilizar un módulo de autenticación que funcionara contra una base de datos relacional (SQL). Existe una implementación de un módulo de este tipo que se ha dejado de distribuir con Apache, ya que sólo ofrecía la posibilidad de comunicarse con la base de datos Msql. Se está trabajando, sin embargo, en una implementación genérica (módulo mod_auth_sql) para poder utilizar cualquier base de datos en el primer caso.

Uso de cookies.

La forma de establecer el mecanismo de autenticación en base a una "prueba" que entrega el cliente es haciendo uso del concepto de cookies.

Las cookies fueron una propuesta, inicialmente de Nestcape Communications, para ser capaz de gestionar transacciones con estado en el entorno WWW. El problema fundamental es que no se puede implementar aplicaciones del estilo de "carrito de la compra" porque en ningún lado se podía, en principio, almacenar información de lo que ha hecho el usuario. Este tipo de sesiones deberían soportar, además, que el cliente se desconectara y volviera un tiempo más adelante y siguiera teniendo las mismas cosas seleccionadas "en el carrito". Este mecanismo se especifica con detalle en el estándar de Internet RFC 2109 del 27 de agosto de 1999.

Cada cliente puede guardar un número ilimitado de cookies que no son más que pares de atributo-valor asignado a un dominio concreto y que el cliente almacena, pudiendo guardar más información como comentario, tiempo de vida, etc... El cliente, si tiene el soporte de cookies activado, puede recibir éstas y, posteriormente, deberá darlas cada vez que accede a un servidor dentro del dominio indicado.

Es evidente, sin embargo que existe la posibilidad de ataques a este sistema por parte de elementos que estén "escuchando" la comunicación entre cliente servidor. Si pueden recoger la cookie podrían hacerse "pasar" por otro usuario. Para esto hay dos soluciones:

En cualquier caso, aún a pesar de los problemas de autenticación, en este prototipo se ha optado por utilizar un esquema más sencillo en el que el servidor va a entregar una cookie con un valor determinado (en este caso el DNI) y va a "confiar" en el cliente que tenga una cookie para el dominio donde está ubicado el servidor de la base de datos con un contenido válido en este campo.

Como se puede ver en el listado 4, se hace una consulta a la base de datos con los valores dados en el formulario (dni y fecha) que son contrastados con la base de datos. Si existe un usuario con estos mismos datos se le entrega entonces una cookie a través de la página HTML (tag META: Set-Cookie y Set-Cookie2, se utilizan ambos por compatibilidad).

********************* LISTADO 4 *************************

Una vez hecho esto se puede incluir una comprobación en cada página. Ésta se asegura de que el usuario ha sido autenticado utilizando el código mostrado en el listado 5.

********************* LISTADO 5 ************************

3.3 Consultas

Finalmente, es necesario implementar herramientas para que los usuarios registrados puedan hacer uso de la información almacenada en la base de datos. En realidad aquí hay muchas aplicaciones posibles, pero las que primero se pueden pensar son:

No se van a explicar en detalle todas estas consultas, ya que el hecho de implementarlas en general no es más que el realizar una consulta SQL y mostrar los datos en una tabla.

Por ello se va a mostrar sólo la segunda consulta, el "listín telefónico" generado en base a los datos de la base de datos. Como se puede ver en el listado 6 se hace un select cruzando tres de las tablas de la base de datos para al final sacar un vector con la información personal (nombre y apellidos) y de contacto (número de teléfono y correo electrónico) de la base de datos.

********************* LISTADO 6 ************************

Como se puede ver en el listado lo que se hace es recoger un número limitado de resultados (definido en la variable step) de la consulta realizado y llamar a la función print_rows para que todos estos se impriman en una tabla HTML. El programa, además, es capaz de llamarse a sí mismo incrementando la cuenta (offset, variable ofs) para poder ir recuperando páginas sucesivas de información de la consulta y así no tener que mostrar toda la consulta de golpe.

Como se puede ver en el listado 7 esta misma filosofía de enseñar los resultados de una consulta se puede aplicar a consultas cada vez más complicadas, como puede ser el caso de buscar qué personas están trabajando en una empresa determinada.

****************** LISTADO 7 ******************************

4. Conclusiones

Con este artículo se concluye la implementación de un acceso a una base de datos a través de un interfaz WWW habiendo visto todos los aspectos, al menos superficialmente (con las restricciones que pueda tener una publicación como ésta), de diseño y desarrollo, así como las alternativas posibles de implementación.

Este prototipo es, por supuesto, muy mejorable. Se han visto algunas de las deficiencias de www-psql para tratar situaciones complejas, como podía ser la entrada de datos. Este tipo de situaciones podría evitarse añadiendo programación a los interfaces también en Javascript, pero, en cualquier caso, siempre es necesario que el servidor compruebe que los datos recibidos son correctos (no se puede "fiar" de lo que le llega). Una alternativa más versátil y que podrá enfrentarse mejor a este problema sería reimplementar el interfaz para utilizar PERL embedido o PHP/FI. Ambos van a permitir tener un acceso más transparente a la base de datos, al mismo tiempo que posibilitarían la intercepción de errores y la comprobación de los datos recibidos de una manera mucho más elegante.

En cualquier caso estos temas quedan pendientes para sucesivos artículos. Baste decir que el desarrollo realizado del prototipo ha sido un desarrollo real, que se encuentra en fase de pruebas, para llevar a cabo este tipo de asociación de antiguos alumnos en una Escuela de la Universidad Politécnica de Madrid. El código del desarrollo está a disposición de las personas interesadas, contacte con el autor si lo desea.

También quedaría pendiente la posibilidad de mejorar este servicio, ligándolo a una lista de correo. Esta lista puede servir de medio para comunicar a los distintos usuarios registrados. Puede ser util, por tanto, suscribir o desuscribirles en función de altas y bajas de la base datos. Asismismo, sería posible enviar un resumen periódico de altas y bajas de forma automática a dicha lista.

5. Sumarios

El servicio sirve como punto de encuentro.

WWW-SQL es un CGI que interpreta páginas web.

Un programador puede echar en falta estructuras complejas en WWW-SQL.

El servidor se divide en dos partes.

Se hace hincapié en el acceso a la base de datos.

La entrada de datos se hace a través de un formulario.

Se pueden implementar múltiples consultas útiles.

Aquí se completa la implementación del prototipo.

Se puede mejorar utilizando ePERL o PHP/FI.

6. Listados

LISTADO 1-

<HTML>
<HEAD>
<TITLE>Alta de usuario</TITLE>
<! sql if "$dni" == "">
<! sql print "Error: Debe dar un DNI">
<! sql setexpr alta 0>
<! sql else>
<! sql connect localhost jfs>
<! sql database exalumnos>
<! sql query "begin">
<! sql query "insert into persona (dni, nombre_persona, apellidos_persona , calle_persona, ciudad_persona, pais_persona, codigo_postal, graduacion, ingreso, fecha_nacimiento) values ( $dni, '$nombre', '$apellidos','$calle', '$ciudad', '$pais', '$codigo_postal', $fecha_grad, $fecha_ingreso, '?fecha_nac')">
<! sql query "end">
<! sql print "<META http-equiv=\"Set-Cookie\" content=\"dni="$dni;" path=/\">" >
<! sql print "<META http-equiv=\"Set-Cookie2\" content=\"dni="$dni;" path=/\">" >
<! sql if "$email" != "">
<! sql query "begin">
<! sql query "insert into usa_mail (dni, e_mail) values ( $dni, '$email')">
<! sql query "end">
<! sql endif>
<! sql if "$telefono" != "">
<! sql query "begin">
<! sql query "insert into usa_tfo (dni, telefono, prefijo) values ( $dni, '$telefono', '$prefijo')">
<! sql query "end">
<! sql endif>
<! sql setexpr alta 1>
<! sql if "$trabajo" == "y">
<! sql print "<META http-equiv=\"refresh\" content=\"1;URL=alta_empresa.html\">" >
<! sql endif>
<BODY>
<! sql if $alta == 1>
<! sql print "Su solicitud ha sido aceptada.">
<! sql if "$trabajo" == "y">
<! sql print "<A HREF=\"alta_empresa.html\">Dé de alta a su empresa</A>." >
<! sql endif>
<! sql close>
<! sql endif>
<! sql endif>
</BODY>
</HTML>

PIE LISTADO 1: Código para dar de alta a un usuario

LISTADO 2-

#use wml::exalumnos::plantilla title="Dé de alta su empresa" minititle="Alta empresa"
<H1>Dé de alta su empresa en la Base de Datos:</H1>
<BR>
<FORM METHOD="GET" ACTION="alta_empresa.pgsql">
Su puesto dentro de la empresa: <INPUT TYPE="TEXT" NAME="puesto"><BR>
Su departamento dentro de la empresa: <INPUT TYPE="TEXT" NAME="departamento"><BR>
<HR>

<protect>
<! sql connect localhost nobody >
<! sql database exalumnos >
<! sql query "begin" >
<! sql query "declare tmp cursor for select nombre_empresa from empresa" >
<! sql if $NUM_ROWS != 0 >
<! sql query "fetch all in tmp" q1 >
Busque su empresa: <SELECT NAME="empresa">
<OPTION VALUE="" DEFAULT>
<! sql print_rows q1 "<OPTION VALUE=\"@q1.0\">@q1.0">
</SELECT><BR>
<! sql endif >
<! sql free q1 >
<! sql query "end">
</protect>
<STRONG>Sólo si su empresa no está en la lista previa introduzca los datos de ésta:</STRONG><BR>

Nombre de la empresa: <INPUT TYPE="TEXT" NAME="nombre"><BR>
Dirección:
Calle: <INPUT TYPE="TEXT" NAME="calle"><BR>
Ciudad: <INPUT TYPE="TEXT" NAME="ciudad"><BR>
País: <INPUT TYPE="TEXT" NAME="pais"><BR>
Código postal: <INPUT TYPE="TEXT" NAME="codigo_postal"><BR>
Actividad: <INPUT TYPE="TEXT" NAME="actividad"><BR>
Número aproximado de empleados: <INPUT TYPE="TEXT" NAME="empleados"><BR>

<INPUT TYPE="SUBMIT" VALUE="Dar de Alta">
</FORM>
</BODY>
</HTML>

PIE LISTADO 2: Formulario para darse de alta en una empresa

LISTADO 3-

#use wml::exalumnos::plantilla title="Alta de su empresa" autorizacion
# aquí se usa la cookie que se ha puesto antes para poner el valor a
# trabaja_en empresa
<protect>
<! sql connect localhost  jfs >
<! sql database exalumnos >
<! sql query "begin" >
<! sql if $empresa = "" >
<! sql query "insert into empresa (nombre_empresa,
calle_empresa, ciudad_empresa, pais_empresa, codigo_postal,actividad, num_empleados)
values ( '$nombre', '$calle', '$ciudad', '$pais',
'$codigo_postal', '$actividad', $empleados )" >
<! sql else >
<! sql set nombre "$empresa" >
<! sql endif >
<! sql query "insert into trabaja_en (dni, nombre_empresa, puesto ,departamento)
values ( '$dni', '$nombre', '$puesto', '$departamento')" >
<! sql query "end" >
<! sql print "<H1>Solicitud aceptada</H1>">
<! sql print "<P>Se han registrados sus datos asi como los de la empresa en los que trabaja. "</P>>
<! sql print "<P>Gracias por darse de alta</P>.">
<! sql close>
</protect>

PIE LISTADO 3: Alta de una empresa

LISTADO 4-

<HTML>
<HEAD>
<TITLE>Acceso de usuario</TITLE>

<! sql setdefault dni 0 >
<! sql if $dni == 0 >
<! sql print "<META http-equiv=\"refresh\" content=\"1;URL=respuesta/rechazado.html\">" >
<! sql setexpr aceptado 0 >
<! sql else >
<! sql connect localhost nobody >
<! sql database exalumnos >
<! sql query "begin" >
<! sql query "declare tmp cursor for select * from persona where dni=$dni and fecha_nacimiento='?fecha'" >
<! sql query "fetch 10 in tmp" q1 >
<! sql query "end" >
<! sql free q1 >
<! sql if $NUM_ROWS != 0 >
<! sql print "<META http-equiv=\"refresh\"content=\"1;URL=respuesta/aceptado.html\">" >
<! sql print "<META http-equiv=\"Set-Cookie\" content=\"dni=$dni;path=/\">" >
<! sql print "<META http-equiv=\"Set-Cookie2\" content=\"dni=$dni;path=/\">" >
<! sql setexpr aceptado 1 >
<! sql else >
<! sql print "<META http-equiv=\"refresh\" content=\"1;URL=respuesta/rechazado.html\">" >
<! sql setexpr aceptado 0 >
<! sql close>
<! sql endif >
<! sql endif >

</HEAD>
<BODY>

<! sql if $aceptado == 0 >
<! sql print "Lo siento su petición ha sido <A HREF=\"respuesta/rechazado.html\">rechazada</A>." >
<! sql else >
<! sql print "Su petición ha sido <A HREF=\"respuesta/aceptado.html\">aceptada</A>." >
<! sql endif >

</BODY>
</HTML>

PIE LISTADO 4: Autenticación de un usuario

LISTADO 5-

<! sql setdefault dni 0 >
<! sql if \$dni == 0 >
<H1>Error</H1>
<P>No conozco su DNI. Vaya a la <A HREF=\"$(USER)/alta.html\">página de altas</A> si aún no se ha dado de alta o a la <A HREF=\"$(USER)/acceso.html\">página de acceso</A> si no ha sido autentificado por el servidor.</P>
<protect>
<! sql else >
</protect>

PIE LISTADO 5: Autenticación del usuario en base a la cookie recibida.

LISTADO 6

#use wml::exalumnos::plantilla title="Listin de antiguos alumnos" autorizacion
<H1>Listín de antiguos alumnos</H1>
<protect>
<! sql connect localhost nobody >
<! sql database exalumnos >
<! sql setdefault ofs 0 >
<! sql setdefault step 10 >
<! sql query "begin" >
<! sql query "declare tmp cursor for select nombre_persona, apellidos_persona, telefono, e_mail  from persona, usa_tfo, usa_mail where persona.dni=usa_tfo.dni and persona.dni=usa_mail.dni order by apellidos_persona" >
<! sql if $ofs != 0 >
<! sql query "move $ofs in tmp" >
<! sql endif >
<! sql query "fetch $step in tmp" q1 >
<! sql if $NUM_ROWS != 0 >
<table>
<tr> <th>Nombre</th> <th>Apellidos</th> <th>Número de teléfono</th> <th>Correo electrónico</th></tr>
<! sql print_rows q1 "<tr> <td>@q1.0</td> <td>@q1.1</td> <td><CENTER>@q1.2<CENTER></td> <td>@q1.3</td></tr>\n" >
</table>
<! sql if $step-1 < $ofs >
<! sql print "<a href=\"listin.pgsql\?ofs=" >
<! sql eval $ofs - $step >
<! sql print "\">">Anterior</a>
<! sql else >
Anterior
<! sql endif >
<! sql if $NUM_ROWS = $step >
<! sql print "<a href=\"listin.pgsql\?ofs=" >
<! sql eval $ofs + $step >
<! sql print "\">">Siguiente</a>
<! sql else >
Siguiente
<! sql endif >
</center>
<! sql endif >
<! sql free q1 >
<! sql query "end" >
<! sql close >
</protect>

PIE LISTADO 6: Listín de los usuarios de la base de datos.

LISTADO 7-

#use wml::exalumnos::plantilla title="Búsqueda de antiguos alumnos en empresas" autorizacion
<H1>Búsqueda de antiguos alumnos en la empresa
<! sql print "$empresa">
</H1>
<protect>
<! sql connect localhost nobody >
<! sql database exalumnos >
<! sql setdefault ofs 0 >
<! sql query "begin" >
<! sql query "declare tmp cursor for select nombre_persona, apellidos_persona from persona, trabaja_en where persona.dni=trabaja_en.dni and strpos(upper(trabaja_en.nombre_empresa),upper('$empresa')) >0 order by apellidos_persona" >

<! sql if $ofs != 0 >
<! sql query "move $ofs in tmp" >
<! sql endif >
<! sql query "fetch 10 in tmp" q1 >
<! sql if $NUM_ROWS != 0 >
<table>
<tr> <th>Nombre</th> <th>Apellidos</th></tr>
<! sql print_rows q1 "<tr> <td>@q1.0</td> <td>@q1.1</td>\n" >
</table>
<br>
<! sql if 9 < $ofs >
<! sql print "<a href=\"busca_trabajadores.pgsql\?empresa=$empresa&ofs=" >
<! sql eval $ofs - 10 >
<! sql print "\">">Anterior</a>
<! sql else >
Anterior
<! sql endif >
<! sql if $NUM_ROWS = 10 >
<! sql print "<a href=\"busca_trabajadores.pgsql\?empresa=$empresa&ofs=" >
<! sql eval $ofs + 10 ><! sql print "\">">Siguiente</a>
<! sql else >
Siguiente
<! sql endif >
<! sql else >
<P>No se ha encontrado ningún trabajador de esa empresa</P>.
<! sql endif >
<! sql free q1 >
<! sql query "end" >
<! sql close >
</protect>

PIE LISTADO 7: Búsqueda de personas en empresas

7. Capturas

8. Notas de maquetación

Por favor, el esquema entidad relación ha de verse, en el número 14 no se leía nada de éste, por esto (y porque me han llegado varios mails de queja al respecto) la vuelvo a incluir en este artículo.

9. Notas de coordinación