<!doctype linuxdoc system>

<article>
<!-- Notas: 
- 1 pagina de articulo, aprox. 6000 caracteres
- Un cuadro al menos cada dos paginas, o un cuadro y una captura
- Capturas con pie de foto
- Para incluir imagen ********* IMAGEN **********+
- 1 sumario por pagina 
-->


<title>Artículo para la revista Linux Actual número 15:
<author>Javier Fernández-Sanguino Peña <url url="jfs@computer.org">
<date>24 julio 2000

<abstract> 
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.

<sect>Introducción
<p>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:

<itemize>
<item>una parte de introducción de información que sirva como alta de
los nuevos usuarios.
<item>una sección de autenticación que permita acceder a los usuarios
reconocidos al área privada del servidor.
<item>una sección de consultas, sólo accesible por los usuarios
reconocidos, que permitirá obtener información de la base de datos
</itemize>

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 *************************


<sect>WWW-SQL
<p>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.
<p>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.

<p>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.
<p>La sintaxis de las marcas reconocidas por WWW-SQL es la siguiente:
<p>
<tt>
<! SQL orden argumento1 argumento2 ... > 
</tt>
<p>La <tt>orden</tt> es cualesquiera de los comandos reconocidos por
el lenguaje, mientras que <tt>argumento1</tt> y <tt>argumento2</tt>
(aunque puede haber más argumentos) son los datos que se le dan a
dicho comando para variar su comportamiento.
<p>Algunas de los comandos más importantes en WWW-SQL  son:
<itemize>

<item><bf>connect</bf>: permite conectarse a un servidor de
base de datos indicando el nombre del servidor y el del usuario (y
contraseña) utilizados para acceder a ésta. Si no se da nombre de
usuario se utilizará uno por defecto.

<item><bf>database</bf>: indica la base de datos del sistema
de base de datos a utilizar, y es absolutamente necesario para llegar
a conectar a una base de datos.

<item><bf>close</bf>: cierra la conexión a la base de datos,
debe ser el último comando a ejecutar.

<item><bf>query</bf>: permite hacer una consulta SQL
cualquiera a la base de datos y devolver los resultados a través de un
elemento que podrá utilizarse para extraerlos.

<item><bf>set</bf>,<bf>setdefault</bf> y
<bf>setexpr</bf>: permite trabajar con variables dentro de
WWW-SQL, asignándolas valores. Se pueden modificar las variables y
comparar a través de un conjunto de operandos que incluyen, incluso,
expresiones regulares.

<item><bf>free</bf>,<bf>fetch</bf> y
<bf>seek</bf>: permite hacer operaciones sobre los elementos
devueltos del resultado de las consultas.

</itemize>

Además, el lenguaje tiene soporte para dos tipos de estructuras de control
(<tt>if.. then...elseif..endif</tt>, y <tt>while..done</tt>),
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:
<tscreen>
<verb>
&lt;!-- Cabeceras HTML --&gt;
&lt;!sql connect&gt;
&lt;!sql database dbname&gt;
&lt;!-- código HTML y órdenes www-sql --&gt;
&lt;!sql close&gt;
&lt;!-- Pie HTML --&gt;
</verb>
</tscreen>


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".

<sect>Desarrollo del servidor.
<p>
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.

<sect1>Alta de usuarios.
<p>
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:
<itemize>
<item>comprobar que los datos tienen el formato adecuado.
<item>introducir estos datos en la base de datos y detectar los
problemas que puedan surgir.
<item>decidir si seguir adelante solicitando más datos y proceder
si es necesario.
</itemize>

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:
<itemize>

<item> seleccionar la empresa en la que está trabajando de una lista
de empresas en la base de datos, para ello genera la lista en tiempo
de ejecución de las que ya existen.

<item>introducir los datos de una nueva empresa que no
esté en la lista mostrada.

</itemize>


************** 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.

<sect1>Autenticación.
<p>
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":
<itemize>
<item>Autenticación basada en el servidor, en el que será éste el
encargado de gestionar las sesiones y autenticar debidamente a los
usuarios. Este tipo de autenticación se puede activar en Apache a
través de ficheros <em>.htaccess</em> con el módulo <em>mod_auth</em>.
<item>Autenticación basada en el cliente, en el que será éste el
encargado de enviar al servidor una "prueba" de que es un cliente
registrado.
</itemize>

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 <em>mod_auth_sql</em>)
para poder utilizar cualquier base de datos en el primer caso.

<!--

Luego es posible comprobarlo siempre en todas las páginas simplemente
insertando el código descrito (esto lo hace automáticamente wml)
-->

<sect2>Uso de <em>cookies</em>.
<p>
La forma de establecer el mecanismo de autenticación en base a una
"prueba" que entrega el cliente es haciendo uso del concepto de
<em>cookies</em>.

Las <em>cookies</em> 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 <em>cookies</em> 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
<em>cookies</em> 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: 
<itemize>
<item>Utilizar un protocolo seguro (un servidor https) de forma que el
intercambio de información entre cliente y servidor vaya cifrado y sea
difícil de interceptar.
<item>cifrar la <em>cookie</em> e incluir información en ésta
relacionada con el ordenador que está accediendo (su dirección IP por
ejemplo). De forma que otro cliente no pueda interceptarla y usarla
con éxito.
</itemize>

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 <em>cookie</em> con un valor
determinado (en este caso el DNI) y va a "confiar" en el cliente que
tenga una <em>cookie</em> 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 (<em>dni</em> y
<em>fecha</em>) que son contrastados con la base de datos. Si existe
un usuario con estos mismos datos se le entrega entonces una
<em>cookie</em> 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 ************************


<sect1>Consultas
<p>
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:

<itemize>
<item>Generar una listas de personas registradas por año de promoción.
<item>Generar un listín de las personas registradas con su teléfono y
dirección de correo electrónico.
<item>Buscar una persona determinada en la base de datos.
<item>Generar una lista de personas y empresas en las que trabajan.
<item>Buscar información de las personas que están trabajando en una
determinada empresa.
</itemize>

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 <em>select</em> 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 <em>step</em>) de la
consulta realizado y llamar a la función <em>print_rows</em> 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
<em>ofs</em>) 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 ******************************


<sect>Conclusiones
<p>
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.

<sect>Sumarios
<p>

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.


<sect>Listados
<P>
<!-- incorporar listados de www-sql (problema utilizan <>) -->
<!-- LISTADO x-


PIE LISTADO x: -->

LISTADO 1-
<tscreen>
<verb>
&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Alta de usuario&lt;/TITLE&gt;
&lt;! sql if "$dni" == ""&gt;
&lt;! sql print "Error: Debe dar un DNI"&gt;
&lt;! sql setexpr alta 0&gt;
&lt;! sql else&gt;
&lt;! sql connect localhost jfs&gt;
&lt;! sql database exalumnos&gt;
&lt;! sql query "begin"&gt;
&lt;! 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')"&gt;
&lt;! sql query "end"&gt;
&lt;! sql print "&lt;META http-equiv=\"Set-Cookie\" content=\"dni="$dni;" path=/\"&gt;" &gt;
&lt;! sql print "&lt;META http-equiv=\"Set-Cookie2\" content=\"dni="$dni;" path=/\"&gt;" &gt;
&lt;! sql if "$email" != ""&gt;
&lt;! sql query "begin"&gt;
&lt;! sql query "insert into usa_mail (dni, e_mail) values ( $dni, '$email')"&gt;
&lt;! sql query "end"&gt;
&lt;! sql endif&gt;
&lt;! sql if "$telefono" != ""&gt;
&lt;! sql query "begin"&gt;
&lt;! sql query "insert into usa_tfo (dni, telefono, prefijo) values ( $dni, '$telefono', '$prefijo')"&gt;
&lt;! sql query "end"&gt;
&lt;! sql endif&gt;
&lt;! sql setexpr alta 1&gt;
&lt;! sql if "$trabajo" == "y"&gt;
&lt;! sql print "&lt;META http-equiv=\"refresh\" content=\"1;URL=alta_empresa.html\"&gt;" &gt;
&lt;! sql endif&gt;
&lt;BODY&gt;
&lt;! sql if $alta == 1&gt;
&lt;! sql print "Su solicitud ha sido aceptada."&gt;
&lt;! sql if "$trabajo" == "y"&gt;
&lt;! sql print "&lt;A HREF=\"alta_empresa.html\"&gt;Dé de alta a su empresa&lt;/A&gt;." &gt;
&lt;! sql endif&gt;
&lt;! sql close&gt;
&lt;! sql endif&gt;
&lt;! sql endif&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</verb>
</tscreen>


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

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

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

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

&lt;INPUT TYPE="SUBMIT" VALUE="Dar de Alta"&gt;
&lt;/FORM&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</verb>
</tscreen>


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

LISTADO 3-
<tscreen>
<verb>
#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
&lt;protect&gt;
&lt;! sql connect localhost  jfs &gt;
&lt;! sql database exalumnos &gt;
&lt;! sql query "begin" &gt;
&lt;! sql if $empresa = "" &gt;
&lt;! 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 )" &gt;
&lt;! sql else &gt;
&lt;! sql set nombre "$empresa" &gt;
&lt;! sql endif &gt;
&lt;! sql query "insert into trabaja_en (dni, nombre_empresa, puesto ,departamento)
values ( '$dni', '$nombre', '$puesto', '$departamento')" &gt;
&lt;! sql query "end" &gt;
&lt;! sql print "&lt;H1&gt;Solicitud aceptada&lt;/H1&gt;"&gt;
&lt;! sql print "&lt;P&gt;Se han registrados sus datos asi como los de la empresa en los que trabaja. "&lt;/P&gt;&gt;
&lt;! sql print "&lt;P&gt;Gracias por darse de alta&lt;/P&gt;."&gt;
&lt;! sql close&gt;
&lt;/protect&gt;
</verb>
</tscreen>



PIE LISTADO 3: Alta de una empresa

LISTADO 4-
<tscreen>
<verb>
&lt;HTML&gt;
&lt;HEAD&gt;
&lt;TITLE&gt;Acceso de usuario&lt;/TITLE&gt;

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

&lt;/HEAD&gt;
&lt;BODY&gt;

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

&lt;/BODY&gt;
&lt;/HTML&gt;
</verb>
</tscreen>


PIE LISTADO 4:  Autenticación de un usuario


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

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

LISTADO 6
<tscreen>
<verb>
#use wml::exalumnos::plantilla title="Listin de antiguos alumnos" autorizacion
&lt;H1&gt;Listín de antiguos alumnos&lt;/H1&gt;
&lt;protect&gt;
&lt;! sql connect localhost nobody &gt;
&lt;! sql database exalumnos &gt;
&lt;! sql setdefault ofs 0 &gt;
&lt;! sql setdefault step 10 &gt;
&lt;! sql query "begin" &gt;
&lt;! 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" &gt;
&lt;! sql if $ofs != 0 &gt;
&lt;! sql query "move $ofs in tmp" &gt;
&lt;! sql endif &gt;
&lt;! sql query "fetch $step in tmp" q1 &gt;
&lt;! sql if $NUM_ROWS != 0 &gt;
&lt;table&gt;
&lt;tr&gt; &lt;th&gt;Nombre&lt;/th&gt; &lt;th&gt;Apellidos&lt;/th&gt; &lt;th&gt;Número de teléfono&lt;/th&gt; &lt;th&gt;Correo electrónico&lt;/th&gt;&lt;/tr&gt;
&lt;! sql print_rows q1 "&lt;tr&gt; &lt;td&gt;@q1.0&lt;/td&gt; &lt;td&gt;@q1.1&lt;/td&gt; &lt;td&gt;&lt;CENTER&gt;@q1.2&lt;CENTER&gt;&lt;/td&gt; &lt;td&gt;@q1.3&lt;/td&gt;&lt;/tr&gt;\n" &gt;
&lt;/table&gt;
&lt;! sql if $step-1 &lt; $ofs &gt;
&lt;! sql print "&lt;a href=\"listin.pgsql\?ofs=" &gt;
&lt;! sql eval $ofs - $step &gt;
&lt;! sql print "\"&gt;"&gt;Anterior&lt;/a&gt;
&lt;! sql else &gt;
Anterior
&lt;! sql endif &gt;
&lt;! sql if $NUM_ROWS = $step &gt;
&lt;! sql print "&lt;a href=\"listin.pgsql\?ofs=" &gt;
&lt;! sql eval $ofs + $step &gt;
&lt;! sql print "\"&gt;"&gt;Siguiente&lt;/a&gt;
&lt;! sql else &gt;
Siguiente
&lt;! sql endif &gt;
&lt;/center&gt;
&lt;! sql endif &gt;
&lt;! sql free q1 &gt;
&lt;! sql query "end" &gt;
&lt;! sql close &gt;
&lt;/protect&gt;
</verb>
</tscreen>


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

LISTADO 7-

<tscreen>
<verb>
#use wml::exalumnos::plantilla title="Búsqueda de antiguos alumnos en empresas" autorizacion
&lt;H1&gt;Búsqueda de antiguos alumnos en la empresa
&lt;! sql print "$empresa"&gt;
&lt;/H1&gt;
&lt;protect&gt;
&lt;! sql connect localhost nobody &gt;
&lt;! sql database exalumnos &gt;
&lt;! sql setdefault ofs 0 &gt;
&lt;! sql query "begin" &gt;
&lt;! 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')) &gt;0 order by apellidos_persona" &gt;

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


PIE LISTADO 7: Búsqueda de personas en empresas


<sect>Capturas
<p>

<itemize>
<item>Figura 1 - entidadrel.png  Pie: Esquema entidad relación del proyecto-
<label id="entidadrel"><img src="figures/entidadrel.png">

<item>Figura 2 - esq-servidor.png. Pie: Esquema simplificado del
servidor a diseñar.
<label id="esqservidor"><img src="figures/esq-servidor.png">

<item>Figura 3 - cap-servidor.png. Pie: Página de alta de un usuario
en el servidor.
<label id="capservidor"><img src="figures/cap-servidor.png">


</itemize>


<sect>Notas de maquetación
<p>

Por favor, el esquema entidad relación <bf>ha de verse</bf>,
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.

<sect>Notas de coordinación
<p>

</article>


