Post on 16-Mar-2020
DDEPARTAMENTOEPARTAMENTO DEDE I INGENIERÍANGENIERÍA
DEDE S SISTEMASISTEMAS YY A AUTOMÁTICAUTOMÁTICA
EESCUELASCUELA T TÉCNICAÉCNICA S SUPERIORUPERIOR DEDE I INGENIEROSNGENIEROS E.S.I. E.S.I.UUNIVERSIDADNIVERSIDAD DEDE S SEVILLAEVILLA
PPROYECTOROYECTO F FININ DEDE C CARRERAARRERA
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
IINGENIERÍANGENIERÍA DEDE T TELECOMUNICACIÓNELECOMUNICACIÓN
AAUTORUTOR: C: CARLOSARLOS A ALBERTOLBERTO G GARCÍAARCÍA Á ÁLVAREZLVAREZ
TTUTORUTOR: E: EDUARDODUARDO F FERNÁNDEZERNÁNDEZ C CAMACHOAMACHO
SEVILLA, FEBRERO DE 2007
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
2
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
ÍNDICE DEL PROYECTO "SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET"
1. Análisis de Antecedentes............................................................................................. 61.1. Bases de Datos..................................................................................................... 6
1.1.1. MySQL........................................................................................................... 61.1.2. PHP............................................................................................................... 91.1.3. HTML.......................................................................................................... 10
1.2. Métodos Educativos........................................................................................... 111.2.1. Matlab......................................................................................................... 121.2.2. Microsoft Visual Studio .NET.................................................................... 18
2. Análisis de Factibilidad............................................................................................ 213. Objetivos del Proyecto.............................................................................................. 22
3.1. Actualización Automática de Bases de Datos.................................................. 223.2. Requisitos Previos para la Actualización Automática.................................... 22
3.2.1. MySQL Server............................................................................................ 233.2.2. MySQL Control Center.............................................................................. 263.2.3. Apache Web Server.................................................................................... 273.2.4. PHP............................................................................................................ 293.2.5. Groupweb................................................................................................... 33
3.2.5.1. Copia Local del Sitio Web................................................................... 343.2.5.2. Restauración de la Base de Datos..................................................... 34
3.2.5.2.1. Introducción al Comando "mysqldump"....................................343.2.5.2.2. Restauración de la Base de Datos a Través de Mysqldump..... 38
3.2.5.3. Estructura del Sitio Web.................................................................... 403.2.5.4. Relación entre las Tablas de la Base de Datos..................................40
3.3. Control Remoto de Procesos en Tiempo Real Mediante Matlab/Tcp/Ip........453.4. Requisitos Previos para el Control Remoto..................................................... 45
3.4.1. Microsoft Visual .NET................................................................................ 453.4.2. Matlab 6.5.................................................................................................. 46
4. Metodología.............................................................................................................. 474.1. Actualización Automática de Bases de Datos................................................... 47
4.1.1. Paso 1 – Validación.................................................................................... 494.1.2. Paso 2 – Selección de ficheros e Inserción de Rutas................................. 504.1.3. Paso 3 – Selección de Campos de la Actualización................................... 534.1.4. Paso 4 – Compleción de Entradas para Actualización............................ 554.1.5. Fichero de Inclusión General..................................................................... 60
4.2. Control Remoto de Procesos en Tiempo Real mediante Matlab/TCP/IP....... 614.2.1. Estructura General del Sistema de Control Remoto................................ 634.2.2. Servigar..................................................................................................... 64
4.2.2.1. Interfaz Web....................................................................................... 644.2.2.2. Aplicación Servidor en Servigar........................................................ 67
4.2.3. Neoxite....................................................................................................... 694.2.3.1. Bloque Tunning (S-Function)............................................................. 694.2.3.2. Aplicación Matlab............................................................................... 71
3
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4.2.3.3. Aplicación Cliente............................................................................... 724.2.3.4. Aplicación Servidor............................................................................ 74
4.2.4. Ubicación y Puesta a Punto de los Programas......................................... 754.2.5. Ejemplo Completo de Control Remoto...................................................... 77
5. Resultados Experimentales...................................................................................... 865.1. Sistema de Actualización de Bases de Datos.................................................... 865.2. Control Remoto de Una Planta a Través de Una Interfaz Web Usando Matlab...................................................................................................................... 87
6. Concordancia Entre Resultados y Objetivos...........................................................886.1. Sistema de Actualización de Bases de Datos.................................................... 886.2. Control Remoto de Planta Mediante Matlab/TCP/IP.................................... 88
7. Conclusiones............................................................................................................. 897.1. Actualización Automática de Base de Datos.................................................... 897.2. Control Remoto de Sistemas mediante Matlab/Simulink...............................90
8. Futuras Mejoras (Líneas de Investigación)............................................................. 919. Bibliografía............................................................................................................... 9310. Anexos..................................................................................................................... 94
10.1. Contenidos del CD-Rom.................................................................................. 9410.2. Manual de Uso: Sistema de Actualización de Bases de Datos...................... 96
10.2.1. Instalación................................................................................................ 9610.2.2. Usando el Sistema de Actualización de Bases de Datos......................... 96
10.2.2.1. Actualizar Base de Datos.................................................................. 9710.2.2.2. Editar Fichero de Definición de Publicaciones............................... 9810.2.2.3. Crear Copia de Seguridad de la Base de Datos...............................9910.2.2.4. Restaurar Copia de Seguridad de la Base de Datos....................... 99
10.3. Manual de Uso: Sistema de Control Remoto............................................... 10010.3.1. Instalación.............................................................................................. 10010.3.2. Usando el Control Remoto..................................................................... 101
10.4. Código Fuente................................................................................................ 10310.4.1. Sistema de Actualización de Bases de Datos......................................... 103
10.4.1.1. Update.html..................................................................................... 10310.4.1.2. Paso1.php......................................................................................... 10510.4.1.3. Paso2.php........................................................................................ 10610.4.1.4. Paso3.php......................................................................................... 11110.4.1.5. Proc_files.php.................................................................................. 12710.4.1.6. Backup.php...................................................................................... 13010.4.1.7. Pubs_editor.php.............................................................................. 13510.4.1.8. Functions.inc.php............................................................................ 13710.4.1.9. Functions.step3.php........................................................................ 14610.4.1.10. Help.html....................................................................................... 167
10.4.2. Control Remoto de Procesos mediante Matlab/TCP/IP.......................17010.4.2.1. Tunning.aspx.cs.............................................................................. 17010.4.2.2. cp_server_servigar........................................................................ 17610.4.2.3. Tunning.c........................................................................................ 18510.4.2.4. Sendtoservigar.m............................................................................ 19110.4.2.5. cp_client_neoxite............................................................................ 19310.4.2.6. cp_server_neoxite.......................................................................... 198
4
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
5
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
1 ANÁLISIS DE ANTECEDENTES .
1.1 B ASES DE DATOS .Hoy en día las bases de datos son la base de muchos sistemas de almacenamiento de
información. Sin ellas, la información de que se dispone se encontraría desperdigada,
ilocalizable en las situaciones de necesidad, con las consiguientes repercusiones que ello
tiene en una sociedad de la información como es aquella en la que nos encontramos.
Una posible definición de "base de datos" es "conjunto de datos que pertenecen al
mismo contexto almacenados semánticamente para su posterior uso". Las bases de datos
permiten, por tanto, almacenar y clasificar los datos de forma ordenada. Es por ello que se
antojan una herramienta necesaria y de uso obligado en la mayoría de sistemas actuales.
El inconveniente que presentan es su mantenimiento. El tiempo de mantenimiento de
una base de datos aumenta exponencialmente con el volumen de datos a actualizar.
Este inconveniente se agrava si con la misma información hay que actualizar distintas
bases de datos. Es inevitable tener que actualizar una base de datos, pero el problema de
actualizar varias con la misma información (o con información similar) se paliaría en gran
medida si se dispusiera de un sistema con cierta inteligencia que realizara el trasvase de
información de una base de datos a las demás.
Dicho sistema inteligente debe emplear tecnologías específicas que soporten el manejo
de bases de datos. Entre ellas se encuentran MySQL, PHP o HTML, cuyas características
se abordan en los siguientes apartados.
1.1.1 MYSQL.MySQL es un sistema de gestión de base de datos, multihilo y multiusuario.
MySQL es un sistema de administración de bases de datos. Una base de datos es una
colección estructurada de datos. Esta puede ser desde una simple lista de compras a una
galería de pinturas hasta el vasto volumen de información en un red corporativa. Para
agregar, acceder a y procesar datos guardados en un computador, se necesita un
administrador como MySQL Server. Dado que los ordenadores son muy buenos manejando
6
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
grandes cantidades de información, los administradores de bases de datos juegan un papel
central en computación, como aplicaciones independientes o como parte de otras
aplicaciones.
SQL (Standard Query Language) es un lenguaje estandarizado de base de datos
relacionantes, el cual nos permite realizar tablas y obtener datos de ella de manera muy
sencilla. Gracias a él podemos realizar diversos tipos de operaciones sobre una base de
datos.
SQL trabaja con una estructura de dos capas, o sea, con una estructura cliente/servidor.
El cliente comienza el proceso mediante el envío de una consulta, el servidor la recibe, la
procesa y devuelve un resultado. El cliente es el que realiza la mayor parte de la tarea ya
que se encarga de mostrar los datos por pantalla, presentar informes tabulados, imprimir,
guardar, etc, dejando al servidor libre para otras tareas.
MySQL es un sistema de administración relacional de bases de datos. Una base de
datos relacional archiva datos en tablas separadas en vez de colocar todos los datos en un
gran archivo. Esto permite velocidad y flexibilidad. Las tablas están conectadas por
relaciones definidas que hacen posible combinar datos de diferentes tablas sobre pedido.
MySQL es software de código abierto (open source). Fuente abierta significa que es
posible para cualquier persona usarlo y modificarlo. Cualquier persona puede bajar el código
fuente de MySQL y usarlo sin pagar. Cualquier interesado puede estudiar el código fuente y
ajustarlo a sus necesidades. MySQL usa el GPL (GNU General Public License) para definir
qué puede hacer y qué no puede hacer con el software en diferentes situaciones.
Un aspecto importante en el diseño de una base de datos reside en la elección de los
índices y evitando hacer escaneos completos de las tablas.
Los índices son usados para encontrar rápidamente los registros que tengan un
determinado valor en alguna de sus columnas. Sin un índice, MySQL tiene que iniciar la
búsqueda con el primer registro y leer a través de toda la tabla para encontrar los registros
relevantes. Aún en tablas pequeñas, de unos 1000 registros, es por lo menos 100 veces
más rápido leer los datos usando un índice que haciendo una lectura secuencial.
Cuando MySQL trata de responder una consulta, examina una variedad de estadísticas
acerca de los datos, y decide cómo buscar los que deseamos de la manera más rápida. Sin
embargo, como se acaba de mencionar, cuando en una tabla no existen índices en los
cuales pueda auxiliarse MySQL para resolver una consulta, se tendrán que leer todos los
registros de la tabla de manera secuencial. Esto es comúnmente llamado un “escaneo
7
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
completo de una tabla”, y es muchas veces algo que se debe evitar.
En particular, se deben evitar las escaneos completos de tablas por las siguientes
razones:
● Sobrecarga de CPU: El proceso de comprobar cada uno de los registros en una
tabla es insignificante cuando se tienen pocos datos, pero puede convertirse en un
problema a medida que va aumentando la cantidad de registros en nuestra tabla.
Existe una relacion proporcional entre el numero de registros que tiene una tabla y la
cantidad de tiempo que le toma a MySQL revisarla completamente.
● Concurrencia: Mientras MySQL está leyendo los datos de una tabla, éste la
bloquea, de tal manera que nadie más puede escribir en ella, aunque sí pueden
leerla. Cuando MySQL está actualizando o eliminando filas de una tabla, éste la
bloquea, y por lo tanto nadie puede al menos leerla.
● Sobrecarga de disco: En una tabla muy grande, un escaneo completo consume
una gran cantidad de entrada/salida en el disco. Esto puede alentar
significativamente el servidor de bases de datos, especialmente si se tiene un disco
IDE algo antiguo.
En resumen, lo mejor es intentar que los escaneos completos de tablas sean minimos
(especialmente si la aplicación necesita escalabilidad en tamaño, número de usuarios, o
ambos).
Es en estos casos donde la indexación puede ayudar. De manera simple, un índice le
permite a MySQL determinar si un valor dado coincide con cualquier fila en una tabla.
Cuando se indexa una columna en particular, MySQL crea otra estructura de datos (un
índice) que usa para almacenar información extra acerca de los valores en la columna
indexada. Los valores indexados son llamados frecuentemente claves. Aunque ésta es la
manera simple de explicar los índices, realmente es un poco mas complejo, ya que MySQL
almacena todas las claves del índice en una estructura de datos de árbol. Esta estructura de
datos de árbol le permite a MySQL encontrar claves muy rápidamente.
Cuando MySQL determine la existencia de un índice en una columna, lo usará en vez de
hacer un escaneo completo de la tabla. Esto reduce de manera importante los tiempos de
CPU y las operaciones de entrada/salida en disco, a su vez que se mejora la concurrencia
porque MySQL bloqueará la tabla únicamente para obtener las filas que necesite (en base a
lo que encontró en el índice). Cuando tenemos grandes cantidades de datos en nuestras
tablas, la mejora en la obtencion de los datos puede ser muy significativa.
8
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
1.1.2 PHP.PHP es un lenguaje de programación usado generalmente para la creación de
contenidos de sitios web. El nombre es el acrónimo recursivo de "PHP: Hypertext
Preprocessor" (inicialmente "PHP Tools" o "Personal Home Page Tools") y se trata de un
lenguaje interpretado usado para la creación de aplicaciones para servidores, o creación de
contenido dinámico para sitios web.
La interpretación del código en lenguaje PHP y su ejecución se da en el servidor, en el
cual se encuentra almacenado el script, y el cliente sólo recibe el resultado de la ejecución.
Cuando el cliente hace una petición al servidor para que le envíe una página web, generada
por un script PHP, el servidor ejecuta el intérprete de PHP, el cual procesa el script
solicitado que generará el contenido de manera dinámica, pudiendo modificar el contenido a
enviar, y regresa el resultado al servidor, el cual se encarga de regresárselo al cliente.
PHP permite la conexión a diferentes tipos de servidores de bases de datos, entre ellos
el que interesa para el presente proyecto (MySQL).
PHP también tiene la capacidad de ser ejecutado en distintos sistemas operativos, entre
los que se incluyen Windows y Linux (los dos sistemas operativos sobre los que se prueba
el script realizado aquí).
Los principales usos de PHP son los siguientes:
● Programación de páginas web dinámicas, habitualmente en combinación con el
motor de bases de datos MySQL, aunque cuenta con soporte nativo para otros
motores, incluyendo el estándar ODBC, lo que amplía en gran medida sus
posibilidades de conexión.
● Programación en consola, al estilo de Perl o Shell scripting.
● Creación de aplicaciones gráficas independientes del navegador, por medio de la
combinación de PHP y GTK (Gimp Tool Kit), lo que permite desarrollar aplicaciones
de escritorio en los sistemas operativos en que está soportado.
Las ventajes de PHP son que se trata de un lenguaje multiplataforma, posee capacidad
de conexión con la mayoría de los manejadores de bases de datos que se utilizan en la
actualidad, permite leer y manipular datos desde diversas fuentes (incluyendo los datos que
pueden ingresar los usuarios desde formularios HTML), posee capacidad de expandir su
potencial utilizando la enorme cantidad de módulos (también conocidos como "extensiones")
9
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
de que dispone, es libre, se encuentra muy bien documentado y por último nos permite crear
formularios web.
La mayoría de estas ventajas serán explotadas para la realización del script de
actualización de la página web.
1.1.3 HTML.HTML (acrónimo inglés de "HyperText Markup Language") es un lenguaje de marcación
diseñado para estructurar textos y presentarlos en forma de hipertexto, que es el formato
estándar de las páginas web. Gracias a Internet y a los navegadores del tipo Internet
Explorer, Opera, Firefox o Netscape, el HTML se ha convertido en uno de los formatos más
populares que existen para la construcción de documentos y también de los más fáciles de
aprender.
HTML es una aplicación de SGML conforme al estándar internacional ISO 8879. XHTML
es una reformulación de HTML 4 como aplicación XML 1.0, y que supone la base para la
evolución estable de este lenguaje. Además, XHTML permite la compatibilidad con los
agentes de usuario que ya admitían HTML 4 siguiendo un conjunto de reglas.
El lenguaje HTML puede ser creado y editado con cualquier editor de textos básico,
como puede ser el Bloc de Notas de Windows (o Notepad), o cualquier otro editor que
admita texto sin formato como GNU Emacs, Microsoft Wordpad, TextPad, Vim, Notepad++,
etc.
Existen además, otros programas para la realización de sitios Web o edición de código
HTML, como por ejemplo Microsoft FrontPage, el cual tiene un formato básico parecido al
resto de los programas de Office. También existe el famoso software de Macromedia (que
adquirió la empresa Adobe) llamado Dreamweaver, siendo uno de los más utilizados en el
ámbito de diseño y programación Web. Estos programas se les conoce como editores
WYSIWYG o What You See Is What You Get (en español: “lo que ves es lo que obtienes”).
Esto significa que son editores que van mostrando el resultado de lo que se está editando
en tiempo real a medida que se va desarrollando el documento. Ahora bien, esto no significa
una manera distinta de realizar sitios web, sino que una forma un tanto más simple ya que
estos programas, además de tener la opción de trabajar con la vista preliminar, tiene su
propia sección HTML la cual va generando todo el código a medida que se va trabajando.
Combinar estos dos métodos resulta muy interesante, ya que de alguna manera se
10
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
ayudan entre sí. Por ejemplo; si se está editando todo en HTML y de pronto se olvida algún
código o etiqueta, simplemente hay que dirigirse al editor visual o WYSIWYG y continuar ahí
la edición, o viceversa, ya que hay casos en que es más rápido y fácil escribir directamente
el código de alguna característica que se quiera adherirle al sitio, que buscar la opción en el
programa mismo.
HTML utiliza etiquetas o marcas, que consisten en breves instrucciones de comienzo y
final, mediante las cuales se determinan la forma en la que debe aparecer en el navegador
el texto, así como también las imágenes y los demás elementos, en la pantalla del
ordenador.
Toda etiqueta se identifica porque está encerrada entre los signos “menor que” y “mayor
que” (< y >, respectivamente), y algunas tienen atributos que pueden tomar algún valor. En
general las etiquetas se aplicarán de dos formas especiales:
• Se abren y se cierran, como por ejemplo: <b>negrita</b> que se vería en el
navegador como negrita.
• No pueden abrirse y cerrarse, como <hr> que se vería en su navegador como una
línea horizontal (aunque en el nuevo estándar XHTML 1.0 se escribe de la forma <hr
/>, cerrándose de forma correcta en este nuevo estándar, es decir, que para cerrar
una etiqueta que no tiene cierre en HTML, se antepone una barra inclinada al signo
“mayor que”).
• Otras que pueden abrirse y cerrarse, como por ejemplo <p>.
1.2 MÉTODOS EDUCATIVOS .Hoy por hoy, las prácticas de laboratorio son un cuello de botella en cualquier carrera de
ingeniería. La escasez de recursos y la limitación del uso de éstos debido a la gran cantidad
de alumnos que llenan las aulas constituyen un grave impedimento para el aprendizaje de
los alumnos.
Una posible ayuda ante este problema sería poner esta tecnología al alcance del alumno
en cualquier momento y desde cualquier sitio. Las tecnologías de la información que
proporciona internet permiten esto.
El acceso a través de una web al material disponible en los laboratorios permitiría el
acceso a los recursos de forma ordenada y con una mayor eficiencia.
Las ventajas que este tipo de acceso traerían consigo podrían verse reflejadas en, por
11
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
ejemplo, prácticas de control sobre sistemas físicos disponibles en un laboratorio. Los
controladores pueden implementarse en programas específicos de control como pueden ser
LabView o Matlab (a través de Simulink). Conectando de alguna forma estos programas con
una interfaz web que permitiera a los usuarios conectarse desde sus propios hogares
mediante un nombre de usuario y una contraseña, éstos podrían realizar el control de forma
alternativa a la asistencia a clase.
Las ventajas son obvias: si a un alumno le faltase tiempo para realizar las prácticas en el
tiempo asignado en laboratorio, siempre podría ampliar el tiempo disponible realizando
dichas prácticas a través de una interfaz web desde su propia casa.
No obstante, las desventajas tampoco son inexistentes: por una parte, hay que crear
dicha interfaz, añadirle las restricciones necesarias para que los controladores
implementados no produzcan malfuncionamientos en el sistema de pruebas, crear un
sistema de validación de usuarios, etc.
Las tecnologías más comunes para el control de procesos o máquinas en los
laboratorios son Matlab y LabView. Matlab, a través de su herramienta Simulink, permite
implementar controladores para simulación o para pruebas en tiempo real a través del
paquete Real Time Workshop, y es el programa en el que se centrará el presente proyecto.
Por otra parte, puesto que es necesaria la programación de una interfaz, se ha elegido el
paquete de programación Microsoft Visual Studio .NET para la consecución de una interfaz
web basada en ASP que implemente validación de usuarios y permite el control remoto.
1.2.1 MATLAB .Matlab es la abreviatura de "Matrix Laboratory" (laboratorio de matrices). Es un programa
de matemáticas creado por "The MathWorks" en 1984. Está disponible para las plataformas
Unix, Windows y Mac.
Es un software muy usado en universidades, centros de investigación y por ingenieros.
En los últimos años ha incluido muchas más capacidades, como la de programar
directamente procesadores digitales de señales, crear código VHDL y otras.
Matlab es un programa de cálculo numérico, orientado a matrices y vectores. Por tanto,
desde el principio hay que pensar que todo lo que se pretenda hacer con él, será mucho
más rápido y efectivo si se piensa en términos de matrices y vectores.
Posee una interfaz fácil de usar: su ventana principal se divide en tres partes principales:
12
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
el historial de comandos (todos los comandos insertados en la ventana de comandos
ordenados cronológicamente por orden de inserción), el espacio de trabajo (que muestra
todas las variables creadas en el entorno de trabajo de Matlab, así como el espacio ocupado
por las mismas y sus valores) y la ventana de comandos, que es la parte más interesante
para el usuario, ya que es en ella donde se ejecutan las órdenes deseadas y se invocan las
funciones necesarias para realizar los cálculos deseados.
Las capacidades de Matlab se pueden ampliar toolboxes. Cada uno de los toolboxes (o
cajas de herramientas) se han creado con una finalidad concreta. Estos toolboxes son
paquetes de funciones especializadas. Así, se encuentran los siguientes toolboxes:
● Control System Toolbox: este paquete proporciona herramientas para
sistemáticamente analizar, diseñar y afinar (sintonizar) sistemas de control lineales.
Se puede especificar el modelo lineal del sistema, representar sus respuestas
temporal y frecuencial para entender el comportamiento del sistema, sintonizar los
parámetros del controlador utilizando técnicas automatizadas e interactivas, y
verificar los requisitos de rendimiento, tales como tiempo de subida y márgenes de
ganancia/fase. Un conjunto de interfaces gráficas de usuario basadas en flujo de
trabajo (workflow) guían al usuario en cada paso del proceso de diseño y análisis.
● Robust Control Toolbox: la caja de herramientas de control robusto es una
colección de funciones y herramientas que ayudan al usuario a analizar y diseñar
sistemas de control con varias entradas y salidas (MIMO o MultiInput-MultiOutput)
con elementos “inciertos”. Se pueden construir modelos de sistemas LTI inciertos
que contengan tanto parámetros como dinámicas inciertas. Se pueden conseguir
herramientas para analizar los márgenes de estabilidad de sistemas MIMO y el
rendimiento en el peor caso posible.
Este toolbox incluye una selección de herramientas de síntesis de control que
computa controladores que optimizan el rendimiento en el peor caso y que identifica
los valores de los parámetros para el peor caso. Permite simplificar y reducir el orden
los modelos complejos con herramientas de reducción de modelos que minimizan los
límites de error aditivo y multiplicativo. Proporciona herramientas para implementar
métodos de control avanzados como H∞, H2, desigualdades de matrices lineales (LMI
o Linear Matrix Inequalities),...
● Frequency Domain System Identification Toolbox: el toolbox de identificación de
sistemas en el dominio de la frecuencia (FDIDENT) proporciona herramientas
especializadas para identificar sistemas SISO (single-input/single-output) de
13
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
dinámica lineal a partir de respuestas temporales o medidas de la respuesta
frecuencial del sistema. Los métodos del dominio frecuencial sostienen el modelado
en tiempo continuo, que puede ser un fuerte complemento y altamente preciso para
los métodos de tiempo discreto más comúnmente usados. Los métodos del toolbox
se pueden aplicar a problemas tales como el modelado de sistemas electrónicos,
mecánicos y acústicos.
La caja de herramientas de identificación de sistemas en el dominio frecuencial
está construida completamente en Matlab, y todas las funciones se encuentran
disponibles en la ventana de comandos o a través de interfaces gráficas de usuario.
● Fuzzy Logic Toolbox: la caja de herramientas de lógica difusa es una colección de
funciones construidas en el entorno de cálculo numérico Matlab. Proporciona
herramientas para crear y editar sistemas borrosos en el marco de Matlab, o si se
prefiere, integrar el sistemas borrosos en simulaciones con Simulink. Pueden incluso
construirse programas C autónomos que llamen a sistemas borrosos construidos con
Matlab. Este toolbox se basa en herramientas de interfaz gráfica de usuario (GUI)
para ayudar a realizar las tareas, aunque también se puede trabajar desde la línea
de comandos, esto ya es a elección del usuario.
● Higher Order Spectral Analisys Toolbox: se trata de un conjunto de ficheros M que
implementan una variedad de algoritmos de procesamiento de señal avanzados para
la estimación de espectros, olyespectros, bicoherencia, “cross-cumulants” y “auto-
cumulants” (incluyendo correlaciones), y cálculo de distribuciones temporal-
frecuenciales. Basados en estos, también implementa algoritmos para identificación
de sistemas ciegos paramétricos y no paramétricos, estimación de tiempos de
retardo, recuperación de armónicos, enganche de fase, estimación de la dirección de
llegada, estimación de parámetros de modelos no lineales de Volterra y predicción
lineal adaptativa.
● Image Processing Toolbox: este toolbox proporciona un extenso conjunto de
algoritmos estándares de referencia y herramientas gráficas para procesamiento,
análisis, y visualización de imágenes, y para desarrollo de algoritmos. Se pueden
restaurar imágenes degradadas o con ruido, mejorar imágenes para una mayor
comprensión, extraer características, analizar formas y texturas, ... La mayoría de
funciones de esta caja de herramientas están escritas en el lenguaje abierto de
Matlab.
● Model Predective Control Toolbox: esta caja de herramientas permite diseñar,
14
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
analizar y simular modelos de controladores predictivos que están basados en
modelos de plantas creados en Matlab o deducidos de un modelo linealizado de
Simulink. Los modelos de controladores predictivos ayudan a optimizar el
rendimiento de sistemas de control MIMO (varias entradas y varias salidas) que
están sujetos a restricciones en las entradas y las salidas.
● Mu Analisis and Synthesis Toolbox: colección de funciones (comandos)
desarrollados principalmente para el análisis y síntesis de sistemas de control, con
énfasis en la cuantificar los efectos de la incertidumbre. Las μ-Tools porporcionan un
conjunto consistente de estructuras de datos para el tratamiento unificado de
sistemas ya sea en el dominio del tiempo, en el dominio de la frecuencia o en el
espacio de estados. Las μ-Tools también dan a los usuarios de Matlab acceso a
desarrollos recientes en teoría de control, a saber, control óptimo H∞ y técnicas de
análisis y síntesis m. Este paquete permite sofisticados resultados de perturbación
de matricesy técnicas de control óptimo para solventar problemas de diseño de
control. El software de diseño de control, tal como las μ-Tools, proporciona un
vínculo entre la teoría de control y la ingeniería de control.
● NAG Foundation Toolbox: la NAG Foundation Toolbox consta de más de 240
ficheros .M que cubren muchos temas, entre los que se incluyen optimización,
ecuaciones diferenciales ordinarias y parciales, cuadratura y estadística. Esta
'toolbox' también incorpora nueva funciones de gran interés para tareas específicas
como resolución de problemas de valores de contorno, realización de cuadraturas
adaptativas unidimensional y multidimensional, ajuste de curvas y superficies y
acceder directamente a los algoritmos LAPACK para resolución de ecuaciones
lineales.
● Neural Network Toolbox: la caja de herramientas de redes neuronales extiende
Matlab con herramientas para diseñar, implementar, visualizar y simular redes
neuronales. Las redes neuronales son inestimables para las aplicaciones donde el
análisis formal sería difícil o imposible, tales como el reconocimiento de patrones o el
control e identificación de sistemas no lineales. Este toolbox proporciona un
exhaustivo soporte para muchos paradigmas comprobados de redes, así como
interfaces gráficas que posibilitan el diseño y la gestión de las redes. El diseño
extensible, abierto y modular del toolbox simplifica la creación de redes y funciones
personalizadas.
● Nonlinear Control Design Toolbox: permite optimizar el comportamiento de los
15
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
sistemas modelados en Simulink personalizando los parámetros de diseño por medio
de optimizaciones numéricas. Se puede optimizar el rendimiento en bucle cerrado de
sistemas de control, desde controladores PID hasta arquitecturas multi-bucle. Se
pueden expresar fácilmente los requisitos de diseño en términos de tiempo de
subida, tiempo de establecimiento, límites de saturación, rizado,... Permite modificar
los coeficientes de los algoritmos de procesamiento de señal y de comunicación, y
alcanzar características de comportamiento tales como consumo del pico de
potencia, rango de movimiento mecánico o pérdida de paquetes de datos.
En conjunción con Simulink, puede usarse para poner a punto sistemas de control
lineales multi-bucle. Se pueden especificar diversos requisitos en el dominio del
tiempo y la frecuencia (incluyendo ganancia y márgenes de fase) en las gráficas de
respuesta del bucle abierto (y cerrado), y optimizar los parámetros del sistema de
control para hacer cumplir estos requisitos.
● Optimization Toolbox: el toolbox de optimización extiende el entorno de cálculo
técnico de Matlab con herramientas y algoritmos ampliamente utilizados para
optimización estándar y a gran escala. Estos algoritmos resuelven problemas
continuos y discretos con y sin restricciones. Esta caja de herramientas incluye
funciones para programación lineal, programación cuadrática, optimización no lineal,
mínimos cuadrados no lineales, ecuaciones no lineales, optimización multi-objetivo y
programación entera binaria.
● Signal Processing Toolbox: este paquete es una colección de algoritmos
estándares de la industria para procesamiento de señales analógicas y digitales.
Proporciona una interfaz gráfica de usuario para diseño y análisis interactivo y
funciones en línea de comandos para desarrollo de algoritmos avanzados.
● SIMULINK: Simulink es una plataforma para simulación multidominio y diseño
basado en modelo para sistemas dinámicos. Proporciona un entorno gráfico
interactivo y un conjunto personalizable de bloques de librerías, y puede extenderse
para aplicaciones más específicas.
● SIMULINK Real Time Workshop: Real Time Workshop es una extensión de las
capacidades de Simulink y Matlab que automáticamente genera paquetes y compila
código fuente de modelos de Simulink para crear aplicaciones software en tiempo
real sobre una variedad de sistemas. Proporcionando un entorno de generación de
código para conseguir prototipos y desarrollos rápidos, Real Time Workshop es el
fundamento para las capacidades de generación de producción de código. Junto con
16
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
otras herramientas y componentes, RTW (Real Time Workshop) proporciona:
○ Generación de código automática adaptada para diversas plataformas destino.
○ Un camino rápido y directo del diseño del sistema a la implementación.
○ Integración con Matlab y Simulink.
○ Una intefaz de usuario gráfica simple.
○ Una arquitectura abierta y un proceso de construcción extensible.
● Spline Toolbox: se trata de una colección de funciones para ajuste, interpolación,
extrapolación y visualización de datos. Los splines son polinomios suaves a trozos
que pueden ser usados para representar funciones en grandes intervalos, donde no
sería práctico una polinomio de aproximación simple.
● Statistics Toolbox: proporciona a los ingenieros, científicos, investigadores,
analistas financieros y estadísticos un extenso conjunto de herramientas para
evaluar y comprender sus datos. Incluye funciones y herramienta interactivas para
analizar datos históricos, datos de modelado, sistemas simulados, desarrollo de
algoritmos estadísticos, y estadística para aprender y enseñar.
● Symbolic Math Toolbox: esta caja de herramientas combina las matemáticas
simbólicas y las capacidades aritméticas de precisión variable del motor simbólico de
Maple con las capacidades numéricas y de visualización de Matlab. Con este
toolbox, pueden usarse la sintaxis y el lenguaje de Matlab para realizar cálculos
simbólicos. Este toolbox ofrece más de 100 funciones simbólicas para realizar
operaciones de transformación de integrales, de cálculo y algebraicas.
● System Identification Toolbox: el toolbox de identificación de sistema permite
construir y evaluar modelos lineales de sistemas dinámicos a partir de datos de
mediciones entrada-salida. Se pueden usar técnicas en el dominio del tiempo o la
frecuencia para ajustar modelos a datos mono o multi-canales. Esta caja de
herramientas es útil para modelar sistemas dinámicos que no sean fácilmente
representados por los principios básicos, incluyendo subsistemas de motor,
dinámicas de vuelo, procesos de termo-fluidos y sistemas electromecánicos.
Estos conjuntos de herramientas son muy útiles, y como se desprenden de las
características y descripciones anteriores, la mayoría están orientados al control de sistemas
y diseño de controladores, que es la razón principal del desarrollo de este proyecto.
17
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
1.2.2 MICROSOFT VISUAL S TUDIO .NET.Visual Studio .NET es un IDE (Integrated Development Environment) o entorno integrado
de desarrollo desarrollado por Microsoft. Es para el sistema operativo Microsoft Windows y
está pensado, principal pero no exclusivamente, para desarrollar para plataformas Win32.
Un entorno de desarrollo integrado es un programa compuesto por un conjunto de
herramientas para un programador. Puede dedicarse en exclusiva a un sólo lenguaje de
programación o bien, puede utilizarse para varios.
Un IDE es un entorno de programación que ha sido empaquetado como un programa de
aplicación, es decir, consiste en un editor de código, un compilador, un depurador y un
constructor de interfaz gráfica GUI. Los IDEs pueden ser aplicaciones por si solas o pueden
ser parte de aplicaciones existentes. El leguaje Basic por ejemplo puede ser usado dentro
de las aplicaciones de Microsoft Office, lo que hace posible escribir sentencias Basic en
forma de macros para Word.
Los IDEs proveen un marco de trabajo amigable para la mayoría de los lenguajes de
programación tales como C++, Java, C#, Basic, Object Pascal, Velneo, etc.
En este caso, Visual Studio .NET proporciona soporte para los lenguajes de
programación Basic, C++, C# y J#. Además, puede utilizarse para construir aplicaciones
dirigidas a Windows (utilizando Windows Forms), Web (usando ASP.NET y Servicios Web) y
dispositivos portátiles (utilizando .NET Compact Framework).
Visual Studio .NET 2003 incluye una completa gama de funciones, desde modeladores
que ayudan a componer visualmente las aplicaciones empresariales más complejas hasta la
implementación de una aplicación en el más pequeño de los dispositivos. Visual Studio .NET
y la plataforma .NET Framework de Microsoft Windows proporcionan una completa
herramienta para diseñar, desarrollar, depurar e implementar aplicaciones seguras para
Windows y Web.
Los cuatro lenguajes de programación soportados por esta herramienta de programación
se describen someramente a continuación:
● C#: es un lenguaje de programación orientado a objetos desarrollado y
estandarizado por Microsoft como parte de su plataforma .NET, que después fue
aprobado como un estándar por la ECMA e ISO.
Su sintaxis básica deriva de C/C++ y utiliza el modelo de objetos de la plataforma
.NET, el cual es similar al de Java aunque incluye mejoras derivadas de otros
lenguajes (más notablemente de Delphi y Java). C# fue diseñado para combinar el
18
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
control a bajo nivel de lenguajes como C y la velocidad de programación de
lenguajes como Visual Basic.
Aunque C# forma parte de la plataforma .NET, ésta es una interfaz de
programación de aplicaciones; mientras que C# es un lenguaje de programación
independiente diseñado para generar programas sobre dicha plataforma. Aunque
aún no existen, es posible implementar compiladores que no generen programas
para dicha plataforma, sino para una plataforma diferente como Win32 o UNIX.
● Visual Basic.NET (VB.NET): es una versión de Visual Basic enfocada al desarrollo
de aplicaciones .NET. El lenguaje de programación es Visual Basic, que apareció en
el año 1991 como una evolución del QuickBasic que fabricaba Microsoft.
Es un lenguaje de programación orientado a objetos(POO), y como novedades
más importantes en la versión .NET, podemos citar la posibilidad de definir ámbitos
de tipo, clases que pueden derivarse de otras mediante herencia, sobrecarga de
métodos, nuevo control estructurado de excepciones o la creación de aplicaciones
con múltiples hilos de ejecución, además de contar con la extensa librería de .NET,
con la que es posible desarrollar tanto Windows Applications y Web Forms, así como
un extenso número de clientes para bases de datos. Gracias a estas mejoras en lo
que vendría siendo Visual Basic 7.0 los programadores de este lenguaje pueden
desarrollar aplicaciones más robustas que en el pasado con una base sólida
orientada a objetos.
● Visual C++: es el nombre de una herramienta y un lenguaje de programación. La
herramienta forma parte de la suite de programación de Microsoft Visual Studio, que
en su última versión está disponible para su descarga gratuita en la página de
Microsoft para uso no profesional.
El lenguaje de programación utilizado por esta herramienta, de igual nombre está
basado en C++, y es compatible en la mayor parte de su código con este lenguaje, a
la vez que su sintaxis es exactamente igual. En algunas ocasiones esta
incompatibilidad impide que otros compiladores, sobre todo en otros sistemas
operativos, funcionen bien con código desarrollado en este lenguaje.
● Visual J# .NET: es una herramienta para programadores en lenguaje Java que
deseen crear aplicaciones y servicios en Microsoft Windows .NET Framework.
El lenguaje de programación J# es un lenguaje transicional para programadores
del lenguaje de programación Java y del lenguaje J++ de Microsoft, creado con la
19
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
intención de que ambos puedan usar sus conocimientos actuales para crear
aplicaciones en la plataforma .NET de Microsoft. J# se supone compatible con Java,
tanto a nivel código fuente, como binario. En teoría, J# puede ser usado para
transicionar aplicaciones que usan bibliotecas de terceros, aún cuando el código de
éstas no este disponible.
La utilidad de esta suite de programación reside en sus capacidades de programación
web y la facilidad de integrar ASP con código Visual C#. Ésta ha sido la combinación
escogida para el desarrollo de la interfaz web del sistema de control remoto.
El código ASP permite utilizar las etiquetas comunes HTML y además permite
implementar consultas a bases de datos del tipo SQL y realizar consultas al servidor.
Aunque esta opción no se ha explotado en el proyecto, siempre permite una futura mejora y
ampliación de posibilidades (escalabilidad).
El código C# permite dotar al sistema de una mayor funcionalidad que no permite el
lenguaje ASP. Por un lado, proporciona una mayor facilidad, debido principalmente al
soporte de ayuda disponible con Microsoft Visual Studio .NET, ya que éste incluye las
denominadas librerías MSDN, que suponen el pilar de la programación para este paquete.
Las librerías MSDN constituyen la referencia de la programación en este entorno, y puesto
que se trata de un lenguaje de muy alto nivel, ya se encuentran creadas una gran cantidad
de funciones que en conjunción con el lenguaje de programación web ASP permite dotar a
la aplicación de control remoto de una mayor funcionalidad.
Por otra parte, este entorno incluye la mayoría de los lenguajes de programación
ampliamente utilizados en ingeniería. No es de extrañar, por tanto, pensar en la combinación
de Microsoft Visual Studio con Matlab, ya que Matlab posee unas herramientas
denominadas “funciones-S” que permiten al usuario la programación de sus propias
funciones y bloques funcionales en Simulink mediante programación tradicional en lenguaje
C. Por tanto, esto permite el desarrollo de librerías con Microsoft Visual Studio .NET para su
posterior uso con Matlab, con todas las ventajas que esto conlleva. No obstante, hay que ser
cautos en el uso de funciones avanzadas de Visual C# de cara a la construcción de librerías
para Matlab, ya que entonces hay que personalizar el proceso de compilado y construcción
de ejecutables y librerías, para que no se produzcan errores en el proceso de linkado y
generación de ficheros objeto.
20
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
2 ANÁLISIS DE FACTIBILIDAD .En la parte referente a la actualización automática de un sistema de bases de datos, la
factibilidad sería reducida o muy limitada en el caso de un sistema genérico capaz de
actualizar cualquier sistema de bases de datos ante múltiples entradas y de distinta índole.
No es este el caso presente. Se pretende diseñar un sistema de actualización de bases de
datos orientado a una base de datos concreta, la del grupo de control predictivo de la
Universidad de Sevilla. En lo concerniente al apartado de las entradas del sistema, cabe
mencionar que se limitan a ficheros de texto plano con patrones constantes de definición de
campos (esto es, cada campo se encuentra separado del anterior de forma unívoca y
constante para todas las nuevas entradas de la base de datos) y de entradas de la base de
datos (cada entrada se encuentra separada de la anterior de forma unívoca y constante, de
forma similar al caso anterior), así como direcciones de internet que complementen la
información de dichos ficheros y directorios para la búsqueda de documentos del tipo “pdf”
(Portable Document Format) que contengan información relevante acerca de las entradas de
la base de datos.
Esta base de datos tiene unas características concretas, que junto con las
especificaciones concisas de las posibles entradas existentes, posibilita la realización de
esta parte del proyecto.
En la parte referente al control remoto de una planta a través de internet mediante el uso
de Matlab y una interfaz web, la factilidad es limitada, ya que Matlab no permite el
establecimiento de sockets de forma sencilla. Si se intenta abrir un socket con Java, el hilo
principal del programa queda bloqueado, impidiendo el correcto control de la planta. Si se
intenta utilizar Matlab Server, entonces se permiten conexiones sobre la planta a través de
internet, pero cada conexión se realiza en un hilo distinto del programa, lo que implicaría que
el control no se estaría llevando a cabo realmente. No obstante, haciendo uso de las
funciones S, que permiten el uso de funciones programadas en C puede encontrarse una
solución viable, haciendo posible la factibilidad de la otra parte del presente proyecto.
21
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
3 OBJETIVOS DEL PROYECTO.
3.1 ACTUALIZACIÓN AUTOMÁTICA DE B ASES DE DATOS .El objetivo a conseguir con las bases de datos es claro: simplificar el proceso de
actualización de una base de datos a partir de información disponible en otras fuentes (entre
ellas, otra base de datos).
Se ha realizado un sistema con cierta "inteligencia" para la actualización de bases de
datos a partir de distintos elementos de entrada:
● Ficheros de texto con la información de otras bases de datos: normalmente la
correspondencia entre los datos contenidos en estos ficheros y la estructura de la
base de datos destino no es exactamente la misma, por lo que el sistema debe
generar los campos alternativos que sean necesarios y que se puedan obtener a
partir de los facilitados.
● Direcciones web: ofrecen más información para la actualización, complementando
los campos de los ficheros de texto.
● Directorios de ficheros: útiles si la base de datos contiene un registro de ficheros,
como pueden ser los artículos publicados en una determinada revista.
A partir de estos elementos se procederá a la actualización de la base de datos,
teniéndose en cuenta todos ellos para una mejor compleción de la misma.
Otro objetivo colateral de este proyecto es realizar un sistema de actualización flexible,
que permita adaptar el sistema a cualquier otro sistema de bases de datos de forma fácil y
directa. Con esto se ofrece la posibilidad de reusar código y ahorrar tiempo de
programación.
3.2 REQUISITOS PREVIOS PARA LA ACTUALIZACIÓN AUTOMÁTICA .El sistema de pruebas para el script de actualización es la página web del grupo de
control predictivo de la Universidad de Sevilla. Para la gestión de la base de datos y las
posteriores comprobaciones del script, es necesario instalar una determinada batería de
programas, cada uno de ellos con una funcionalidad distinta:
22
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● MySQL Server: gestor de bases de datos open source.
● MySQL Administrator: herramienta de mantenimiento y gestión de bases de datos
SQL.
● Apache Web Server: servidor web para poder visualizar la página web bajo
pruebas.
● PHP: lenguaje de programación que permite la ejecución de código en un servidor
web.
3.2.1 MYSQL S ERVER.MySQL es un gestor de bases de datos open source (o de otra forma, software libre). Es
la herramienta utilizada en el servidor Nyquist para gestionar las bases de datos, y por ello
aquí se explicará someramente una instalación básica, que será suficiente para los objetivos
del proyecto.
La versión aquí utilizada es la estándar 4.1.16, para procesadores x86. El nombre del
fichero necesario para esta instalación es:
mysql-standard-4.1.16-pc-linux-gnu-i686-glibc23.tar.gzEl usuario puede instalar cualquier otra versión. La instalación no variará
significativamente, salvo en los números de la versión utilizada y en el tipo de ésta (max o
standard, generalmente).
Los pasos a seguir para instalación de MySQL Standard Edition a través de un terminal
son los siguientes:
1. Crear un usuario y un grupo para ejecutar MySQL:
# groupadd mysql# useradd -g mysql mysql
2. Descomprimir el archivo que contiene MySQL en el directorio "/usr/local/":
# cd /usr/local# tar -xzf /directorio/mysql-standard-4.1.16-pc-linux-gnu-i686-glibc23.tar.gz
NOTA: "/directorio/" hace referencia a la ubicación en la que se encuentre el
fichero .tar.gz de MySQL. El usuario deberá cambiarlo por el directorio
apropiado.
3. Realizar un enlace simbólico al directorio creado por la descompresión del punto
2:
23
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
# ln -s mysql-standard-4.1.16-pc-linux-gnu-i686-glibc23/ mysqlNOTA: con esto se podrá acceder al directorio donde se ha descomprimido el
fichero simplemente mediante la ruta "/usr/local/mysql/".
4. Ejecutar el script de instalación:
# cd mysql# scripts/mysql_install_db
NOTA: durante el proceso de instalación se mostrarán en el terminal diversos
mensajes informativos. Uno de ellos es de especial importancia: el referente
al cambio de la contraseña del usuario "root", que es el administrador de la
base de datos. En dicho mensaje se recomienda el cambio de la contraseña,
que inicialmente se establece a una contraseña vacía (es decir, ninguna), a
una contraseña particular del usuario. Más adelante se hará una reseña a
este inciso.
5. Cambiar el usuario y grupo de los ficheros:
# chown -R root .# chown -R mysql data# chgrp -R mysql .
NOTA: Estos comandos pueden variar dependiendo de la versión de Linux
utilizada. En el desarrollo de esta beca se utilizó Debian Sarge 3.1, y estos
comandos se ejecutaron satisfactoriamente. Hay que asegurarse de que se
establece la asociación de los grupos bien, puesto que en caso contrario, al
ejecutar MySQL como se indica en el punto 6 se obtendrá un error de
escritura en el directorio "data".
6. Ejecutar MySQL:
# bin/mysqld_safe --user=mysql &NOTA: dependiendo de la versión a instalar de MySQL, habrá que utilizar
"mysql_safe" o "mysqld_safe". En la facilitada, hay que usar "mysqld_safe". Además,
la utilización del ampersand (&) al final tiene su base en que de esta forma no
se bloquea el terminal y se permite seguir ejecutando comandos.
NOTA 2: otra forma de arrancar el servidor y pararlo, respectivamente, se
consigue con los siguientes comandos:
# /usr/local/mysql/support-files/mysql.server start# /usr/local/mysql/support-files/mysql.server stop
7. Ahora que ya se está ejecutando MySQL es un buen momento para cambiar la
contraseña del usuario "root". Se facilitan aquí los comandos específicos para este
24
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
fin:
# ./bin/mysqladmin -u root password 'nuevo-password'# ./bin/mysqladmin -u root -h debian password 'nuevo-password'
Ahora lo que se va a hacer es automatizar el arranque del servidor con el arranque del
sistema. Para ello, se copiará el script de manejo del servidor en la ubicación donde se
encuentren los ficheros de arranque del sistema. Esto se consigue con la siguiente orden:
# cp /usr/local/mysql/support-files/mysql.server /etc/init.dEste script se puede utilizar tanto para arrancar el servidor en el inicio del sistema como
para pararlo al apagar el ordenador. Para ello, se ultimarán estas dos operaciones creando
unos enlaces simbólicos, necesarios para el script:
# cd /etc/rc2.d# ln -s /etc/init.d/mysql.server S20mysql# cd /etc/rc0.d# ln -s /etc/init.d/mysql.server K20mysql
Es conveniente ejecutar el script de inicio y apagado del servidor como el usuario "mysql"
y no como el usuario "root" por razones de seguridad. A tal efecto, se modificará el fichero
"mysql.server" que se ha copiado en "/etc/init.d/". Se ha de buscar la siguiente línea:
$bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file &y se sustituirá por esta otra:
$bindir/mysqld_safe --datadir=$datadir --pid-file=$pid_file --user=mysql &NOTA: en el fichero de la distribución facilitada, esta línea era la línea 199.
Si la instalación básica descrita aquí no proporciona los resultados deseados, se
recomienda consultar el fichero "INSTALL-BINARY" que se encuentra en el directorio creado en
el paso 2 (carpeta de descompresión).
La instalación para el sistema Windows es más sencilla, en tanto que simplemente
dispone de un ejecutable. Para instalarlo, descomprimir el fichero “mysql-4.1.18-win32.zip”
y hacer doble click sobre el instalador “setup.exe”. No se entrará en detalles de la instalación
porque es similar a la instalación para Linux. En todo caso, puede que se altere el orden de
alguno de los pasos, que la mayoría de ellos se realicen de forma gráfica en forma de
ventanas y que otros no tengan sentido (como el hecho de realizar enlaces simbólicos o
programar el autoarranque con el sistema, puesto que se ofrece al usuario la posibilidad de
arrancar el servidor MySQL como un servicio del sistema.
25
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
3.2.2 MYSQL CONTROL CENTER.MySQL Control Center es una herramienta de bastante ayuda en el mantenimiento y
gestión de la base de datos SQL. Permite, entre otras cosas, crear nuevos usuarios,
modificar las tablas existentes y añadir/crear nuevas bases de datos.
La versión aquí utilizada es la 0.9.4, para procesadores x86. El nombre del fichero
necesario para esta instalación es:
mysqlcc-0.9.4-linux-glibc23.tar.gzEl usuario puede instalar cualquier otra versión. La instalación no variará
significativamente.
Los pasos a seguir para instalación de MySQL Control Center a través de un terminal
son los siguientes:
1. Descomprimir el archivo que contiene MySQL Control Center en el directorio
"/usr/local/":
# cd /usr/local# tar -xzf /directorio/mysqlcc-0.9.4-linux-glibc23.tar.gz
NOTA: "/directorio/" hace referencia a la ubicación en la que se encuentre el
fichero .tar.gz de MySQL Control Center. El usuario deberá cambiarlo por el
directorio apropiado.
2. Realizar un enlace simbólico al directorio creado por la descompresión del punto
2:
# ln -s mysqlcc-0.9.4-linux-glibc23/ mysqlccNOTA: con esto se podrá acceder al directorio donde se ha descomprimido el
fichero simplemente mediante la ruta "/usr/local/mysqlcc/".
3. Ejecutar MySQL Control Center:
# cd mysqlcc# ./mysqlcc
4. Aparecerá una ventana con el título "MySQLCC – Register Server". En primera instancia,
nos bastará rellenar los campos existentes con los siguientes datos:
• Name localhost
NOTA: Aquí se debe poner el nombre que se quiere dar a la conexión.
• Host name localhost
NOTA: Aquí se debe poner el nombre de la máquina donde está el
servidor MySQL. Localhost indica al programa que se usará la misma
26
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
computadora donde se está instalando el programa como servidor de
bases de datos, de forma que se conecte a ésta de forma local.
• User name root
NOTA: Aquí se debe especificar el nombre del usuario de MySQL para
conectar con el servidor.
• Password Aquí se debe especificar la contraseña del usuario del campo
anterior. Si se especificó como nombre de usuario "root", entonces caben dos
opciones: 1) dejar en blanco si no se ejecutó el paso 7 en la instalación de
MySQL ó 2) rellenar este campo con la contraseña establecida.
5. Pulsar el botón "Add" (o "Añadir"). Acto seguido, aparecerá una ventana, que es la
ventana principal de MySQL Control Center. En la parte izquierda aparece un menú
titulado "MySQL Servers". En su interior, aparece "localhost", que es la conexión actual. Si
se despliega, aparecerán tres submenús, a saber: "Databases", "Server Administration" y
"User Administration". El primero, "Databases", al desplegarse muestra las bases de datos
existentes; el segundo, "Server Administration" no nos interesa; y el tercero, "User
Administration", sirve para administrar los usuarios que tendrán acceso al servidor
MySQL. Tanto los menús "Databases" como "User Administration" serán útiles más
adelante, en la configuración de la página web.
Si la instalación básica descrita aquí no proporciona los resultados deseados, se
recomienda consultar el fichero "INSTALL.txt" que se encuentra en el directorio creado en el
paso 1 (carpeta de descompresión).
Para la instalación en el sistema Windows se propone otro programa, denominado
MySQL Administrator. Se trata de una evolución de MySQL Control Center, y posee más
posibilidades de modificación y mayor cantidad de opciones que el anterior. Su instalación
también es más sencilla, en tanto que simplemente dispone de un ejecutable. Para
instalarlo, hacer doble click sobre el instalador “mysql-administrator-1.1.9-win.msi”.
3.2.3 APACHE WEB S ERVER .Apache es un servidor gratuito y software libre además. Éste será el que permitirá las
conexiones remotas desde otras máquinas y a su vez permitirá al programador ver las
27
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
páginas en proceso de modificación a través del navegador.
La versión aquí utilizada es la 2.0.55, para procesadores x86. El nombre del fichero
necesario para esta instalación es:
httpd-2.0.55.tar.gzEl usuario puede instalar cualquier otra versión. La instalación no variará
significativamente. En este caso se tendrán que compilar las fuentes del servidor Apache.
Los pasos a seguir para instalación de Apache Server a través de un terminal son los
siguientes:
1. Descomprimir el archivo que contiene Apache Server en el directorio
"/usr/local/src/":
# cd /usr/local/src# tar -zxf /directorio/httpd-2.0.55.tar.gz
NOTA: "/directorio/" hace referencia a la ubicación en la que se encuentre el
fichero .tar.gz de Apache Server. El usuario deberá cambiarlo por el directorio
apropiado.
2. Configurar los fuentes para que la compilación se adapte al sistema y las
necesidades:
# cd httpd-2.0.55# ./configure --prefix=/usr/local/apache2 --enable-so --with-mpm=prefork
NOTA: con esto se compila Apache Server con las opciones por defecto. La
opción "prefix" indica dónde se va a instalar el servidor Apache. La opción
"enable-so" sirve para realizar la carga dinámica de módulos. Es importante
poner esta opción para después cargar dinámicamente php. "with-mpm" es una
opción necesaria para un correcto funcionamiento con php.
3. Compilar los fuentes:
# make4. Instalar Apache Server:
# make install5. Arrancar Apache Server:
# cd /usr/local/apache2/bin# .apachectl start
6. Esto no es un paso de la instalación en sí, sino una comprobación de que
funciona correctamente Apache Server en el sistema. Abrir desde el navegador web
la url:
28
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
http:/localhost/Si la instalación ha tenido éxito, debería mostrarse una página con el siguiente texto al
comienzo:
"If you can see this, it means that the installation of the Apache web server software on this system was successful. You may now add content to this directory and replace this page."
Para proseguir con la siguiente instalación, que corresponde a php, es conveniente parar
el servidor con la siguiente orden:
# ./apachectl stopdonde se ha supuesto que seguimos en el directorio "/usr/local/apache2/bin/".
A continuación se realizará una automatización similar a la que se llevó a cabo con el
servidor MySQL para automatizar el arranque y parada del servidor Apache Server al
encender y apagar el ordenador. Para ello, se debe copiar el script "apachectl" al sitio donde
se encuentran los ficheros de arranque del sistema:
# cp /usr/local/apache2/bin/apachectl /etc/init.dEste script se puede utilizar tanto para arrancar el servidor en el inicio del sistema como
para pararlo al apagar el ordenador. Para ello, se ultimarán estas dos operaciones, creando
unos enlaces simbólicos necesarios para el script:
# cd /etc/rc2.d# ln -s /etc/init.d/apachectl S20apachectl# cd /etc/rc0.d# ln -s /etc/init.d/apachectl K20apachectl
Si la instalación básica descrita aquí no proporciona los resultados deseados, se
recomienda consultar el fichero "INSTALL" que se encuentra en el directorio creado en el paso
1 (carpeta de descompresión).
La versión para Windows se encuentra en el fichero “apache_2.0.55-win32-x86-
no_ssl.msi”. Para instalar Apache para Windows simplemente se ha de hacer doble click
sobre el instalador anterior y proceder con todos los pasos que vaya solicitando el mismo.
Se ofrecerá, al igual que pasaba con MySQL Server iniciar este servidor como un servicio
del sistema. Ésta es la opción recomendada.
3.2.4 PHP.PHP es un lenguaje de programación de páginas web que permite dotarlas de
dinamismo. Este lenguaje permite la comunicación entre los navegadores y los servidores
que alojan las páginas web, permitiendo que aquéllos soliciten determinados datos,
devolviéndoselos éste.
29
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
La versión aquí utilizada es la 4.4.2, para procesadores x86. El nombre del fichero
necesario para esta instalación es:
php-4.4.2.tar.gzEl usuario puede instalar cualquier otra versión. La instalación no variará
significativamente.
Los pasos a seguir para instalación de php a través de un terminal son los siguientes:
1. Descomprimir el archivo que contiene php en el directorio "/usr/local/src/":
# cd /usr/local/src# tar -zxf /directorio/php-4.4.2.tar.gz
NOTA: "/directorio/" hace referencia a la ubicación en la que se encuentre el
fichero .tar.gz de Apache Server. El usuario deberá cambiarlo por el directorio
apropiado.
2. Configurar las fuentes para su posterior instalación:
# cd php-4.4.2#./configure --prefix=/usr/local/php4 --with-mysql=/usr/local/mysql --with-apxs2=/usr/local/apache2/bin/apxs --with-gettext[=DIR]
NOTA: con estas opciones se compilará php con las opciones por defecto.
"with-mysql" incluye el soporte para MySQL, por lo que se le indica el directorio
donde está instalado dicho servidor; "with-apxs2" compila el módulo para
Apache Server 2, por lo que se le indica el directorio donde está instalado
dicha utilidad. Por último, se indica también "with-gettext" porque la página del
grupo de control predictivo hace uso de este módulo, por lo que, o bien se
incluye ahora, o bien se recompilaría php más adelante de nuevo.
3. Compilar php:
# make4. Instalar php:
# make install5. Copiar el fichero de configuración de php donde php espera encontrarlo. Este
directorio es el que se indicó en el paso 2 con la opción prefix añandiéndole el
subdirectorio "/lib/", es decir:
# cp php.ini-dist /usr/local/php4/lib/php.ini6. Hacer que Apache Server reconozca los ficheros con extensión “.php”. Para ello,
añadir en el fichero "/usr/local/apache2/conf/httpd.conf" la siguiente línea:
30
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
AddType application/x-httpd-php .phpNOTA: en la versión facilitada, la línea se debía añadir en la línea 838.
7. Comprobar que la instalación y configuración de php ha sido correcta. Para ello,
abrir un editor de textos (i.e., "gedit") y crear un fichero llamado "prueba.php":
# cd /usr/local/apache2/htdocs/# gedit prueba.php
NOTA: el directorio "/usr/local/apache2/htdocs/" es el directorio en el que busca
Apache Server las páginas del host cuando se indican mediante "localhost".
Por tanto, para referirnos después a ella, habrá que copiar en este directorio
el fichero de prueba, con la finalidad de poder verlo después.
8. Añadir las siguientes líneas al fichero:
<?phpphpinfo();
?>9. Abrir un navegador web e indicar la siguiente url:
http://localhost/prueba.php10. Se debería ver una página mostrando distintas características e información
acerca del sistema.
NOTA: si no se ve esta página, probar a reiniciar el ordenador y volver a cargar la
página. Debido a que Apache Server se encuentra iniciado, puede que no tenga
en cuenta las modificaciones al fichero "httpd.conf" de forma inmediata.
11. Por último, también sería conveniente realizar una pequeña comprobación de que
todo lo anteriormente instalado funciona conjuntamente, es decir, crear una página
que mediante funciones php se conecte al servidor MySQL para obtener una
determinada información a través del servidor Apache. Para ello, editar el fichero
"prueba.php" creado anteriormente e insertar el siguiente contenido:
31
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
<?php// Ejemplo de acceso a base de datos MySQL.// Conseguimos la conexión.$link = @mysql_connect('localhost', 'root', 'root_password');if (!$link) {
exit('<b>Error</b>: No se puede conectar con la base de datos. '.mysql_error());}$ddbb = 'mysql';if (!@mysql_select_db($ddbb)) {
exit("<b>Error</b>: No se encuentra la base de datos '$ddbb'.");}// Ejecutamos una consulta.$sql = 'SELECT * FROM help_keyword';$res = @mysql_query($sql);if (!$res) {
exit("<b>Error</b>: La consulta '$sql' ha fallado. ".mysql_error());}// Mostramos el metadata de la tabla.echo '<table border="1">';echo '<tr> <th>Nombre</th> <th>Tipo</th> <th>Permite NULL</th> </tr>';$numFields = mysql_num_fields($res);for ($i = 0; $i < $numFields; $i ++) {
$meta = mysql_fetch_field($res, $i);echo '<tr>';echo "<td>$meta->name</td>";echo "<td>$meta->type</td>";echo "<td>$meta->not_null</td>";echo '</tr>';
}echo '</table>';echo '<br>';// Mostramos el contenido de la tabla.echo '<table border="1">';echo '<tr>';for ($i = 0; $i < $numFields; $i ++) {
$meta = mysql_fetch_field($res, $i);echo "<th>$meta->name</th>";
}echo '</tr>';while ($row = mysql_fetch_row($res)) {
echo '<tr>';foreach ($row as $col) {
echo "<td>$col</td>";}echo '</tr>';
}echo '</table>';// Liberamos los recursos y cerramos la conexión.mysql_free_result($res);mysql_close($link);
?>NOTA: en la línea que contiene la función "@mysql_connect('localhost', 'root',
'root_password')" se debe sustituir "root_password" por la contraseña del
32
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
administrador ("root") del servidor MySQL.
12. Si todo ha ido bien, se deberían mostrar algunas tablas.
Si la instalación básica descrita aquí no proporciona los resultados deseados, se
recomienda consultar el fichero "INSTALL" que se encuentra en el directorio creado en el paso
1 (carpeta de descompresión).
Con esto ya se encuentra configurado el servidor web al completo. Faltan por pulir
algunos pequeños detalles, pero esto ya depende de las pretensiones del proyecto, de
modo que las modificaciones a realizar se comentarán cuando se estime conveniente.
Para instalar PHP en cualquier versión de Windows se puede hacer mediante el fichero
comprimido “php-5.1.2-Win32.zip”. Esta versión es más moderna que la indicada para
Linux, pero para el sitio empleado para el presente proyecto basta con la versión de Linux.
No obstante, se ha elegido una versión más moderna para Windows. Para instalar PHP en
Windows se ha de descomprimir el fichero anterior y seguir las notas de instalación
indicadas en el fichero “install.txt” que aparece en la carpeta resultante de la
descompresión. Puesto que la versión de Apache instalada es la 2.0.55 el apartado a seguir
es el “2. Installation on Windows systems”, subapartado “Apache 2.0.x on Microsoft
Windows”.
3.2.5 GROUPWEB .La primera de las tareas a realizar es el mantenimiento, actualización y modificación del
sitio web del grupo de control predictivo del departamento de sistemas y automática de la
Escuela Superior de Ingenieros de Sevilla. Esta página es accesible desde la url:
http://nyquist.us.es/groupweb/index.php
Lo primero que se hizo fue una copia de la página web, ya que por razones de seguridad
no era conveniente la modificación "in situ" de la página en el propio servidor. Esto se realizó
mediante una transferencia ftp. Posteriormente, hubo que configurar la página web para su
correcta visualización en el servidor configurado en el apartado 2 de la presente memoria.
El sitio web se encuentra comprimido en el siguiente fichero:
groupweb.rar
33
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
3.2.5.1 COPIA LOCAL DEL S ITIO WEB.En primer lugar, para ser coherentes con las rutas utilizadas por el creador original del
sitio web, se crearon los siguientes directorios:
# mkdir var# cd var# mkdir www# rar x groupweb.rar
Este sitio web hace uso de unas librerías de libre distribución denominadas "phphtmllib".
Por ello, hay que realizar un enlace simbólico al directorio "phphtmllib-2.4.1" que se encuentra
dentro del directorio creado en la descompresión anterior. Para ello, tecleamos lo siguiente:
# cd groupweb# ln -s phphtmllib-2.4.1/ phphtmlib
Este paso es un requisito de una instalación previa de dichas librerías, una especie de
variable de entorno sin la cual no funcionaría correctamente la página web.
Otro paso a realizar es cambiar el directorio en el que Apache Server busca las páginas
web almacenadas. Por defecto, esta ruta es "/usr/local/apache2/htdocs/", y se debe cambiar a
"/var/www/". Para ello, se debe teclear lo siguiente:
# cd /usr/local/apache2/conf# gedit httpd.conf
Buscamos en este fichero la línea que contiene el texto "DocumentRoot
"/usr/local/apache2/htdocs"" y la cambiamos por "DocumentRoot "/var/www""
Nótese que al cambiar el fichero de configuración de Apache Server, será necesario
reiniciar el sistema (o reiniciar el servidor Apache) para que los cambios surtan efecto.
3.2.5.2 RESTAURACIÓN DE LA B ASE DE DATOS .
3.2.5.2.1 INTRODUCCIÓN AL COMANDO "MYSQLDUMP ".
Para realizar una copia de seguridad de la base de datos existen varios comandos
específicos. Estos comandos son:
34
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• mysqlimport• mysqlhotcopy• mysqldump• backup table/restore table• flush table• lock tableEl comando elegido para la copia de seguridad de la base de datos fue "mysqldump", tanto
por su simplicidad como por su eficacia.
El comando "mysqldump" del sistema gestor de la base de datos MySQL sirve para
hacer copias de seguridad. Este comando permite hacer la copia de seguridad de una o
múltiples bases de datos. Además, permite que estas copias de seguridad se puedan
restaurar en distintos tipos de gestores de bases de datos, sin la necesidad de que se trate
de un gestor de MySQL. Esto lo consigue creando unos ficheros que contienen todas las
sentencias SQL necesarias para poder restaurar la tabla, que incluyen desde la sentencia
de creación de la tabla hasta una sentencia "insert" por cada uno de los registros que
forman parte de la misma.
El comando dispone de una amplia variedad de opciones que nos permitirá realizar la
copia de la forma más conveniente para el propósito de la misma. Para poder restaurar la
copia de seguridad, bastará con ejecutar todas las sentencias SQL que se encuentran
dentro del fichero, bien desde la línea de comandos de MySQL o desde la pantalla de
creación de sentencias SQL de cualquier entorno gráfico como puede ser MySQL Control
Center.
Las limitaciones de la restauración dependerán de las opciones que se hayan
especificado a la hora de hacer la copia de seguridad. Por ejemplo, si se incluye la opción
"--add-drop-table" al hacer la copia de seguridad, se podrán restaurar tablas que existen
actualmente en el servidor (borrándolas primero). Por lo que es necesario estudiar primero
los procedimientos que se utilizarán tanto en la copia como en la restauración, para que todo
se haga de la forma correcta.
La sintaxis de este comando es la siguiente:
mysqldump -u [usuario] -p [password] [nombre_base_datos] > [backup.sql]Hay que tener cuidado al realizar una copia de la base de datos, puesto que alguien
puede estar accediendo a la información y estar cambiándola. Para ello, se puede "evitar"
un acceso inoportuno que pueda dejar el fichero volcado en un estado inconsistente a través
de varias opciones, una de las cuales podría ser "--single-transaction", como se indica en el
siguiente ejemplo:
35
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
#mysqldump --single-transaction -u usuario -p password base_de_datos > base_de_datos_backup.sqlLa base de datos así volcada se podría recuperar por medio de sentencias SQL en la
línea de comandos de forma similar:
#mysql -u admin -p pass drupal < drupal_backup.sqlAlgunas de las opciones del comando "mysqldump" se muestran a continuación:
• --add-locks: Añade “LOCK TABLES“ antes y “UNLOCK TABLE“ después de la copia de cada
tabla.
• -A, --all-databases: Copia todas las bases de datos. Es lo mismo que utilizar “--
databases“ seleccionando todas.
• -a,--all: Incluye todas las opciones de creación específicas de MySQL.
• --allow-keywords: Permite la creación de nombres de columnas que son palabras
clave. Esto se realiza poniendo de prefijo a cada nombre de columna el nombre de la
tabla.
• -c, --complete-insert: Utiliza "inserts" incluyendo los nombres de columna en cada
sentencia (incrementa bastante el tamaño del fichero).
• -B, --databases: Para copiar varias bases de datos. En este caso, no se especifican
tablas. El nombre de los argumentos se refiere a los nombres de las bases de datos.
Se incluirá "USE db_name" en la salida antes de cada base de datos.
• --delayed: Inserta las filas con el comando "INSERT DELAYED".
• -e, --extended-insert: Utiliza la sintaxis de "INSERT" multilínea (proporciona sentencias
de "insert" más compactas y rápidas).
• -#, --debug[=option_string]: Utilización de la traza del programa (para depuración).
• --help: Muestra mensaje de ayuda y termina.
• --fields-terminated-by...; --fields-enclosed-by=...; --fields-optionally-enclosed-by=...; --fields-
escaped-by=...; --lines-terminated-by=...: Estas opciones se utilizan con la opción “-T”, y
tienen el mismo significado que la correspondiente cláusula LOAD DATA INFILE.
• -F, --flush-logs: Escribe en disco todos los logs antes de comenzar con la copia.
• -f, --force: Continúa aunque se produzca un error de SQL durante la copia.
• -h, --host=...: Copia los datos del servidor de MySQL especificado. El servidor por
defecto es “localhost”.
36
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• -l, --lock-tables: Bloquea todas las tablas antes de comenzar con la copia. Las
tablas se bloquean con "READ LOCAL" para permitir "inserts" concurrentes en caso de
tablas MyIsam. Cuando se realiza la copia de múltiples bases de datos, “--lock-tables“
bloqueará la copia de cada base de datos por separado, de forma que esta opción
no garantiza que las tablase sean consistentes lógicamente entre distintas bases de
datos. Las tablas en diferentes bases de datos se copiarán en estados
completamente distintos.
• -K, --disable-keys: Se incluirá en la salida "/*!40000 ALTER TABLE tb_name DISABLE KEYS */;" y
"/*!40000 ALTER TABLE tb_name ENABLE KEYS */;". Esto hará que la carga de datos en un
servidor MySQL 4.0 se realice más rápido debido a que los índices se crearán
después de que todos los datos hayan sido restaurados.
• -n, --no-create-db: No se incluirá en la salida "CREATE DATABASE /*!32312 IF NOT EXISTS */
db_name;". Esta línea se incluye si la opción "--databases" o "--all-databases" fue
seleccionada.
• -t, --no-create-info: No incluirá la información de creación de la tabla (sentencia
"CREATE TABLE").
• -d, --no-data: No incluirá ninguna información sobre los registros de la tabla. Esta
opción sirve para crear una copia solamente de la estructura de la base de datos.
• --opt: Lo mismo que "--quick --add-drop-table --add-locks --extended-insert --lock-tables".
Esta opción le debería permitir realizar la copia de seguridad de la base de datos de
la forma más rápida y efectiva.
• -p your_pass, --password[=your_pass]: Contraseña utilizada cuando se conecta con el
servidor. Si no se especifica, "=your_pass", "mysqldump" preguntará la contraseña.
• -P, --port=...: Puerto utilizado para las conexiones TCP/IP.
• --protocol=(TCP | SOCKET | PIPE | MEMORY): Especifica el protocolo de conexión que se
utilizará.
• -q, --quick: No almacena en el buffer la sentencia, la copia directamente a la salida.
Utiliza "mysql_use_result()" para realizarlo.
• -Q, --quote-names: Entrecomilla las tablas y nombres de columna con los caracteres
'''.
37
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• -r, --result-file=...: Redirecciona la salida al fichero especificado. Esta opción se
debería utilizar en MS-DOS, porque previene la conversión de nueva línea '\n' en
nueva línea y retorno de carro '\n\r'.
• --single-transaction: Utiliza el comando "BEGIN" antes de realizar la copia desde el
servidor. Es muy útil con las tablas InnoDB y el nivel de transacción "READ_COMMITTED",
porque en este modo realizará la copia de seguridad en un estado consistente sin
necesidad de bloquear las aplicaciones. Consultar el manual para más detalles.
• -S /path/to/socket, --socket=/path/to/socket: El fichero de sockets que se especifica al
conectar a “localhost” (que es el host predeterminado).
• --tables: Sobreescribe la opción "--databases" (-B).
• -T, --tab=path-to-some-directory: Crea un fichero "table_name.sql" que contiene la
sentencia de creación de SQL, y un fichero "table_name.txt" que contiene los datos de
cada tabla. El formato del fichero '.txt' se realiza de acuerdo con las opciones "--fields-
xxx" y "--lines--xxx". Nota: esta opción sólo funciona si el comando "mysqldump" se
ejecuta en la misma máquina que el demonio "mysqld"; además, el usuario deberá
tener permisos para crear y escribir el fichero en la ubicación especificada.
• -u nombre_usuario, --user=nombre_usuario: El nombre de usuario que se utilizará cuando
se conecte con el servidor, el valor predeterminado es el del usuario actual.
• -v, --verbose: Va mostrando información sobre las acciones que se van realizando
(más lento).
• -w, --where='cláusula where': Sirve para realizar la copia de determinados registros.
• -X, --xml: Realizará la copia de seguridad en un documento xml.
• -x, --first-slave: Bloquea todas las tablas de todas las bases de datos.
3.2.5.2.2 RESTAURACIÓN DE LA B ASE DE DATOS A TRAVÉS DE MYSQLDUMP .
Del análisis de los ficheros del sitio web del grupo de control predictivo se obtuvieron los
datos necesarios para el acceso local a la base de datos. Se procedió a la copia de la base
de datos del sitio con el siguiente comando:
38
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
# mysqldump --single-transaction --user=NOMBRE_USUARIO –-password=PASSWORD--host=NOMBRE_HOST NOMBRE_BASE_DATOS > FICHERO_BACKUP.SQL
Nótese que con esta forma de ejecución del comando no se tiene en cuenta la
posibilidad de que ya exista una base de datos con ese mismo nombre en el lugar de
destino. Para solucionar este problema en caso de existencia de una base de datos con el
mismo nombre que la que se intenta restaurar existen distintas opciones: 1) borrar
manualmente la base de datos antes de restaurar la copia por medio de una herramienta de
administración como MySQL Control Center, 2) borrar manualmente la base de datos a
través de la línea de comandos de MySQL o mediante un script, 3) tener en cuenta al
ejecutar "mysqldump" que existe esta base de datos y añadir la opción "--opt" o "--add-drop-
table" para que al recuperar la base de datos a partir de la copia se borre en primer lugar la
base de datos existente e insertar después la copia.
Con la ejecución del comando anterior, en el fichero "FICHERO_BACKUP.SQL" se hallan
almacenadas todas las sentencias necesarias para poder reconstruir la base de datos en
otro ordenador.
Antes de proceder a la restauración, en el ordenador destino hay que crear el usuario de
MySQL tal y como éste existía en el host original. Para ello, se abre un terminal y se inicia
MySQL Control Center:
# cd /usr/local/mysqlcc/# ./mysqlcc
Una vez abierto MySQL Control Center, pulsar con el botón derecho sobre "User
Administration" y escoger la opción "New User". Los datos a insertar en cada uno de los campos
son los siguientes:
• Username: nombre del usuario
• Host: nombre o dirección del host
• Password: password del usuario
Con esto ya se ha creado el nuevo usuario en la base de datos. Podría pensarse que se
podría recuperar la base de datos empleando a otro usuario. En realidad podría hacerse,
pero entonces habría que modificar los datos almacenados en los ficheros de la página para
que se pudiera realizar la conexión con la base de datos, ya que ésta se encontraría
orientada para el usuario original de MySQL. Por simplicidad, debido a que después habrá
que restaurarla en el servidor "nyquist.us.es", es preferible dar de alta a este nuevo usuario
con la misma configuración que tenía en el servidor “nyquist.us.es” en lugar de realizar las
modificaciones oportunas en los ficheros del sitio.
39
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Para proceder a restaurar la base de datos, el comando a ejecutar sería:
# mysql --user= NOMBRE_USUARIO --password=PASSWORDNOMBRE_BASE_DATOS < FICHERO_BACKUP.SQL
Con esto ya se encuentra el sistema en condiciones de empezar a modificar la base de
datos y lo más importante, poder verla correctamente (nótese que el usuario debe incluir el
nombre de usuario y la clave correspondiente).
3.2.5.3 ESTRUCTURA DEL S ITIO WEB.El sitio web está desarrollado haciendo uso de las librerías "phphtmllib". Para la creación
de cada página se ha usado una plantilla de ejemplo que traen dichas librerías, denominada
"MyLayoutPage". Esta plantilla genera una página web con 4 zonas de contenido bien
diferenciadas: el encabezado, el pie, el menú de la izquierda y el contenido de la página.
Modificando el contenido de cada zona a través de métodos específicos heredados de la
clase padre se construye cada una de las páginas.
3.2.5.4 RELACIÓN ENTRE LAS TABLAS DE LA B ASE DE DATOS .Para la actualización de las tablas de la base de datos había distintas opciones:
1. Introducir cada una de las publicaciones manualmente, a través del menú de
inserción implementado en la propia web.
2. Entender la interrelación entre las tablas y generar un script php que directamente
modifique las tablas pertinentes a partir del contenido de un fichero de texto.
Se escogió la segunda opción, por ser más generalizada y por ser reutilizable en un
futuro si fuera necesario actualizar de forma masiva la base de datos.
La base de datos "Groupweb" consta de 8 tablas, algunas de ellas interrelacionadas
entre sí. Estas tablas son: authors, books, congress, journals, people, pfcs, phds, sent.
• Books: contiene los libros publicados por autores del grupo.
• Journals: contiene los artículos de autores del grupo publicados en revistas.
• Congress: contiene las ponencias en congresos de autores del grupo.
• Pfcs: contiene los proyectos fin de carrera de alumnos que han sido tutelados por
miembros del grupo.
40
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• Phds: contiene las tesis de miembros del grupo de control predictivo.
• Authors: tabla que contiene referencias a los autores de las publicaciones
almacenadas en las cuatro tablas anteriores.
• People: almacena los datos de todas las personas pertenecientes al grupo que han
sido dadas de alta en el sistema de la página web.
• Sent: tabla con un registro por cada publicación enviada a una dirección de correo
electrónico.
A continuación se describirá con más detalle cada una de las tablas así como sus
respectivos campos de información.
Tabla "Books":
Esta tabla almacena en cada registro una publicación en formato libro de un miembro del
grupo. Los campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Title: título del libro.
• Abstract: resumen del contenido del libro.
• Reference: referencia de búsqueda bibliográfica para el buscador de la web del grupo.
Esta referencia se forma con el primer apellido del autor principal, el tipo de publicación
(en este caso libro, que se indica como "BOOK") y el año de publicación.
• Publisher: editorial del libro.
• Year: año de publicación.
• ISBN: número único del libro en el estándar internacional.
• Code: puede ser 1 ó 2 dependiendo del tipo de publicación (libro de actas o libro de
texto, respectivamente).
Tabla "Journals":
Esta tabla almacena en cada registro un artículo de revista de un miembro del grupo. Los
campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
41
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• Title: título del artículo.
• Abstract: resumen del artículo.
• Reference: referencia de búsqueda bibliográfica para el buscador de la web del grupo.
Esta referencia se forma con el primer apellido del autor principal, el tipo de publicación
(en este caso sería una revista, que se indica con las siglas de la misma) y el año de
publicación.
• Journal: revista.
• Year: año de publicación.
• Volume: volumen de la revista.
• Pages: páginas de la revista en las que se publicó el artículo.
Tabla "Congress":
Esta tabla almacena en cada registro una ponencia de congreso de un miembro del
grupo. Los campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Title: título de la ponencia del congreso.
• Abstract: resumen de la ponencia del congreso.
• Reference: referencia de búsqueda bibliográfica para el buscador de la web del grupo.
Esta referencia se forma con el primer apellido del autor principal, el tipo de publicación
(en este caso serían se trata de un congreso, que se indica con las siglas del mismo) y el
año de publicación.
• Booktitle: nombre del congreso.
• Year: año del congreso.
• Month: mes del congreso.
• Address: dirección física del congreso
• Pages: páginas del libro de actas del congreso en que se encuentra publicada la
ponencia.
42
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Tabla "Pfcs":
Esta tabla almacena en cada registro un proyecto fin de carrera de un alumno tutelado
por un miembro del grupo. Los campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Title: título del proyecto fin de carrera.
• Author: autor del proyecto.
• Abstract: resumen del proyecto.
• Datepfc: fecha de publicación del proyecto.
• Reference: referencia de búsqueda bibliográfica para el buscador de la web del grupo.
Esta referencia se forma con el primer apellido del autor principal, el tipo de publicación
(en este caso sería un proyecto fin de carrera, que se indica con las siglas PFC) y el año
de publicación.
Tabla "Phds":
Esta tabla almacena en cada registro una tesis de un miembro del grupo. Los campos
que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Title: título de la tesis.
• Abstract: resumen de la tesis.
• Datephd: fecha de publicación de la tesis.
• Reference: referencia de búsqueda bibliográfica para el buscador de la web del grupo.
Esta referencia se forma con el primer apellido del autor principal, el tipo de publicación
(en este caso sería una tesis, que se indica con las siglas PHD) y el año de publicación.
Tabla "Authors":
Esta tabla almacena tantas entradas por publicación como autores tenga la misma, sea
del tipo que sea. Los campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• People: campo "id" de la tabla "people" para el autor en cuestión (si éste pertenece al
43
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
grupo).
• Name: nombre del autor en caso de que no pertenezca al grupo.
• Publication: campo "id" de la tabla correspondiente a la publicación almacenada.
• Type: el tipo de la publicación (revista=1, congreso=2, etc).
• Numorder: relevancia del autor (autor principal=1, secundario=2, etc).
• Jobcode: solamente se emplea si se trata de un pfc o un phd, con valor "a" en caso
de ser el autor de la publicación o "s" en caso de ser un supervisor.
Tabla "People":
Esta tabla almacena en cada registro un miembro del grupo. Los campos que se han de
rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Name: Nombre del miembro.
• Surname: Apellidos del miembro.
• Login: palabra empleada como "nick" en el sitio web.
• Password: clave para entrar en el sitio web con el login citado anteriormente.
• Bibtextname: Firma bibliográfica del miembro.
Tabla "Sent":
Esta tabla almacena en cada registro un artículo de revista de un miembro del grupo. Los
campos que se han de rellenar son los siguientes:
• Id: campo autoincremental, es la clave de la tabla y sirve para indexar los registros.
• Name: nombre de la persona que solicita un documento.
• Affiliation: afiliación, institución.
• Email: correo electrónico.
• Publication: campo "id" de la publicación solicitada en la tabla en que se encuentre.
• Type: tipo de publicación (revista=1, congreso=2, etc).
44
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
• Date: fecha y hora de la solicitud.
3.3 CONTROL REMOTO DE PROCESOS EN TIEMPO REAL MEDIANTE MATLAB /TCP/IP.El objetivo que se persigue aquí es desarrollar una forma alternativa de control de
procesos a través de internet, utilizando para ello protocolos como TCP/IP.
Hoy en día, la supervisión de procesos a gran escala se lleva a cabo mediante complejos
sistemas SCADA, que proporcionan una alta fiabilidad y seguridad. El problema que tienen
estos sistemas es que la compra de licencias es una limitación debido a su coste.
Una forma más eficiente de controlar procesos de menor envergadura de forma más
simple podría radicar en el control de procesos a través de Matlab (programa de cálculo
matemático de amplio uso en ámbitos universitarios y educativos). Matlab proporciona
herramientas para realizar cálculos a través de interfaces web y realizar conexiones remotas
a sistemas, pero ninguna de estas utilidades cumplen los requisitos que aquí se imponen.
Si bien Matlab permite realizar cálculos de forma remota a través de navegadores web
mediante su herramienta Matlab Server, también es cierto que cada cálculo solicitado
mediante esta herramienta se ejecuta en instancias distintas, de forma que los cálculos
nunca se realizarían para un mismo proceso en estudio, por lo que esta herramienta no es
útil en este caso.
Otra forma de control remoto reside en el modo externo de Simulink. Esta modalidad
permite la conexión desde otro ordenador a un modelo de Simulink, pero solamente permite
una conexión y no sólo eso, sino que además no permite ningún control sobre la conexión
desde ese ordenador, pudiéndose conectar cualquier usuario no deseado.
Es por esto que se necesita de un método para realizar un control sobre una
determinada planta o proceso de forma segura, fiable y controlada.
3.4 REQUISITOS PREVIOS PARA EL CONTROL REMOTO.
3.4.1 MICROSOFT VISUAL .NET.En lo que respecta a la interfaz web para el control remoto es necesaria una distribución
de Microsoft Visual .NET, debido a que ésta se encuentra en un fichero de extensión
45
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
“.aspx”, en el que se halla entremezclado código ASP con Visual C#.
Es válida cualquier versión, no es necesario que sea la última (Microsoft Visual .NET
2003). La instalación a realizar puede ser la típica, ya que no se emplean librerías inusuales.
Recuérdese en la instalación seleccionar también para su instalación “Internet Information
Server”, y configurar adecuadamente el servidor para servir páginas ASP.
3.4.2 MATLAB 6.5.La versión probada de Matlab fue la 6.5. Puesto que esta parte del proyecto simplemente
incluye una librería de función S programada por el autor, no es necesaria una versión
reciente, puesto que utiliza funciones básicas de C. No obstante, la versión con la que se
testeó todo el sistema fue la versión 6.5 y no dio fallo alguno.
La instalación de Matlab puede ser una instalación básica, esto es, no es necesario
instalar todos los paquetes, puesto que no se hace uso de ellos.
46
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4 METODOLOGÍA .
4.1 ACTUALIZACIÓN AUTOMÁTICA DE B ASES DE DATOS .La actualización de la base de datos se lleva a cabo en 4 sencillos pasos:
● En el primero de ellos, el usuario deberá validarse como usuario con los
privilegios adecuados para poder actualizar la base de datos.
● En el segundo, se seleccionarán los ficheros de texto con la información para
actualizar los campos de la base de datos, así como la tabla que actualizará cada
fichero. Aquí también se introducirán las direcciones de las páginas webs que se
emplearán en la actualización, así como los directorios que contienen los
documentos a subir al servidor.
● En el tercero, se especificarán los campos que contiene cada fichero, así como
los caracteres que delimitan un campo de otro y los que separan una entrada de
otra. También se mostrarán aquí las rutas especificadas en el paso anterior (tanto las
de páginas webs como los directorios) que sean válidas y accesibles.
● En el cuarto paso se mostrarán todas las entradas procesadas con toda la
información recogida. Cada entrada se mostrará como un conjunto de campos de
texto, rellenos con la información disponible (vacíos si ésta no se facilitó), un campo
con el documento a subir (junto con un porcentaje de similitud en la búsqueda) y una
casilla de verificación para indicar que la entrada se encuentra completa y se puede
proceder a su actualización. No se deberá salir de este paso hasta que se hayan
completado todas las entradas y se hayan actualizado.
Es posible que en el cuarto paso no se tengan almacenados los datos de una
determinada publicación, como una revista o un congreso. En ese caso, en dicho paso
también se facilitará un formulario para insertar los datos necesarios para que pueda
procederse a una correcta actualización.
En resumen, el esquema a seguir es el siguiente:
47
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
En los siguientes apartados se detallará cada uno de los pasos.
Existe un fichero de funciones general (functions.inc.php) que incluyen cada uno de los
pasos. En este fichero se definen variables cuyo significado se aclarará aquí, puesto que
interpretan un papel fundamental en el caso de que se desee modificar el script para
utilizarlo con otra base de datos:
● $lista_campos_adicionales: array que contiene los nombres de los campos
adicionales (campos fictios necesarios para una actualización colateral). Por ejemplo,
el campo "autores", que no existe como tal en ninguna tabla, pero que se emplea
para actualizar colateralmente la tabla de autores de las publicaciones. Este array se
utilizará para mostrar los nombres de los campos adicionales en las listas
desplegables.
● $tabla_campos_adicionales: array que contiene los nombres de las tablas que
actualizarán los campos adicionales contenidos en "$lista_campos_adicionales". Por
ejemplo, si el campo actualiza la tabla de las tesis, entonces valdrá "phds", o si las
actualiza todas "all". Nótese que el nombre de la tabla debe ir en el mismo orden
que en "$lista_campos_adicionales".
● $var_campos_adicionales: array que contiene los nombres de las variables que
48
Ilustración 1: Flujo del sistema de actualización de bases de datos
Validación
Selección de ficheros de actualizaciónInserción de rutas adicionales
Selección de campos de actualización
Compleción de entrada para actualizaciónProceder con actualización
¿Quedan entradas por procesar?Sí
No
Fin
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
almacenan los campos adicionales. Por ejemplo, el campo "autores" se almacena en
la variable "$authors", por lo que en "$var_campos_adicionales" se introduce
"authors".
● $lista_campos_undef: array que contiene los nombres de otros campos que no se
utilizan para actualizar la base de datos en sí, pero que son necesarios por alguna
razón. Por ejemplo, el campo "separador_campos", que es necesario para separar un
campo de otro dentro del fichero de actualización. Estos campos se distinguen de los
adicionales, además, en que se conoce el campo que se va a actualizar, pero lo que
no se conoce es el valor.
● $tabla_campos_undef: al igual que "$tabla_campos_adicionales", este array se
utiliza para almacenar los nombres de las tablas en las que se utilizará este
parámetro. Por ejemplo, "separador_campos" se utiliza en todas las tablas, por lo que
se inserta "all" en este array en la posición correspondiente.
● $var_campos_undef: array que contiene los nombres de las variables que
almacenan los valores de los campos no definidos. Por ejemplo, el separador de
campos se almacena en la variable de nombre "separador_campo".
● $valores_campos_undef: array con los valores de cada campo seleccionable en la
lista desplegable del campo no definido.
● $desc_campos_undef: array con la descripción de cada campo seleccionable en la
lista desplegable del campo no definido. La razón de ser de este array y el anterior
es que normalmente los separadores son caracteres especiales, como nueva línea
('\n') o tabulador ('\t'), que debido a una característica de PHP se envían de forma
incorrecta al siguiente formulario (duplica las barras invertidas). Por ello, se envía un
entero que se utilizará en un array en el siguiente formulario para obtener el valor
correcto. Como mostrar el entero en la lista desplegable no ofrecería ninguna
información al usuario se introduce este array, que contiene una descripción correcta
de cada uno de los campos no definidos.
4.1.1 PASO 1 – VALIDACIÓN .El primer paso es el más sencillo de todos. Consta de una pantalla en la que se
muestran dos campos de texto, uno para el login del usuario y otro para la contraseña de
éste.
49
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
La razón de ser de este paso es bien sencilla y fundamental: si no existiera este paso,
cualquier usuario podría acceder al sistema y causar destrozos o malfuncionamientos en la
base de datos. Es por ello que se antoja un requisito del sistema validar a los usuarios
permitidos al comienzo del proceso, de forma que se asegure el acceso a usuarios con los
permisos necesarios.
El fichero que implementa este paso es “update.html”.
4.1.2 PASO 2 – S ELECCIÓN DE FICHEROS E INSERCIÓN DE RUTAS .El segundo paso responde a la necesidad del sistema de conocer el origen de la
información que se usará para la actualización. Por ello, se muestra en pantalla un
formulario con tres partes bien diferenciadas:
● Formulario de selección de ficheros y tablas: el usuario ha de seleccionar los
ficheros de texto que contienen los datos a partir de los cuales se actualizarán las
tablas de la base de datos y las tablas que éstos actualizan.
50
Ilustración 2: Captura del paso 1 (Validación de usuario)
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Formulario de inserción de rutas urls: el usuario insertará en este campo de texto
las distintas direcciones web que complementarán a los ficheros indicados en el paso
anterior.
● Formulario de inserción de rutas locales: el usuario insertará aquí las rutas que se
encuentren en el ordenador desde el que se realiza la actualización que contengan
información complementaria para los casos del primer formulario (tablas a
actualizar).
El objetivo es complementar la actualización de todas las formas disponibles, para que el
resultado sea el más completo y satisfactorio posible.
Las únicas formas de complementación que no se han considerado son:
● Actualización a través del contenido de páginas web.
● Actualización a través de otra base de datos.
La razón de no tener en cuenta la actualización a partir de otra base de datos es bien
simple. Normalmente, los usuarios mantienen las bases de datos introduciendo datos en
éstas a través de formularios de páginas web, y por tanto, solamente tienen que validarse en
el sistema como usuarios para poder realizar estas modificaciones. Sin embargo, para poder
acceder a una base de datos de forma directa y obtener listados de datos de tablas de la
misma es necesaria la contraseña del usuario root o maestro, que normalmente es el mismo
usuario que creó la página web. Esta contraseña normalmente se encuentra bien protegida
y el acceso a la misma es muy limitado, de modo que sólo lo conoce un grupo reducido de
usuarios, que no suele ser el mismo grupo que intenta actualizar otra base de datos distinta
en otra página distinta.
Respecto de no tener en cuenta el contenido de una página web para complementar los
datos, la razón radica en que, a pesar de haber muchos sistemas automatizados hoy en día
para mostrar información de bases de datos en pantalla (listados de los contenidos de bases
de datos en páginas webs), todavía existen páginas que se programan manualmente, y
muchas veces ni siquiera acceden a bases de datos para la obtención de la información que
muestran, sino que ésta se encuentra embebida (incrustada) en el mismo código de la
página. El problema que conlleva esto es que el error humano actúa en casos como el
incorrecto cierre de etiquetas html, o errores tipográficos, de modo que si, por ejemplo, se
buscara el volumen de una publicación, habría páginas en las que éste se mostraría
precedido de "Vol.", mientras que en otras podría ser "Volumen", "Volume" o simplemente
"V.". Esto conlleva una casuística demasiado extensa como para tenerla en cuenta. Por otro
51
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
lado, si cada campo se encontrara embebido en una etiqueta de elemento "<li>" dentro de
una lista "<ul>", utilizando como separador de cada elemento, por ejemplo, ";", y al usuario
casualmente en algún caso se le olvidara insertar dicho separador, entonces resultaría en
una actualización errónea, y lo mismo pasaría si se le olvidara cerrar la etiqueta de elemento
con "</li>" si se utiliza ésta para discriminar entre entradas distintas.
Por todas estas razones no se han tenido en cuenta estos métodos de actualización.
52
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4.1.3 PASO 3 – S ELECCIÓN DE CAMPOS DE LA ACTUALIZACIÓN .La finalidad de este tercer paso es clara: el sistema necesita saber qué campos del
fichero de actualización facilitado se corresponden de forma directa con alguno de los
53
Ilustración 3: Captura del paso 2 (Selección de ficheros)
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
campos de las tablas de la base de datos y cuáles son campos a partir de los cuales se
construirán otros.
En este paso también se analizan las rutas facilitadas en el paso anterior, de forma que
se muestran en pantalla solamente aquellas a las que se ha podido acceder (comprobación
previa antes de proceder a ciegas a su uso). Se analizan tanto las rutas correspondientes a
direcciones de internet para actualización mediante web como las correspondientes a rutas
locales para actualización mediante ficheros sitos en el mismo ordenador de la actualización
(o de la misma red).
El diagrama de flujo que recoge la secuencia de ejecución de este paso se muestra a
continuación:
54Ilustración 4: Flujo del proceso de selección de campos (Paso 3)
Recoger información de base de datos
Subir ficheros de actualización al servidor
Para cada tabla
Mostrar campos de la tabla
Mostrar campos adicionales
Mostrar campos interactivos
Analizar urls del paso 2Mostrar las correctas y accesibles
Mostrar directorios del paso 2
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4.1.4 PASO 4 – COMPLECIÓN DE ENTRADAS PARA ACTUALIZACIÓN .El paso 4 se repite cíclicamente, mostrando en pantalla las entradas que restan por
actualizar en la base de datos. Inicialmente se muestran todas las entradas procesadas a
partir de los ficheros de actualizaciones, divididas en los campos finales que actualizarán la
tabla correspondiente. En la primera iteración de este paso, el sistema procede al análisis de
todos los ficheros facilitados, y durante este largo proceso, se va mostrando en pantalla un
mensaje indicando la entrada del documento que se está analizando, ya que el usuario
podría pensar que el sistema queda colgado en un estado inconsistente (véase ilustración
6).
Por cada entrada de los ficheros se muestra un cajón de campos editables, entre los que
se encuentran los siguientes elementos:
55
Ilustración 5: Captura del paso 3 (Selección de campos)
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Tabla que actualizará.
● Campos que se usarán para la actualización, mostrados mediante campos de
texto para una posible modificación si fuera necesaria antes de proceder a la
actualización. La razón de hacer esto radica en que muchas veces existen errores
tipográficos en las fuentes de la información, y con esto se quiere dar la opción al
usuario de que corrija dichos fallos. Esto se puede ver fácilmente en el campo de
fichero pdf que se explica a continuación, pues si se encuentra un documento que
tenga un porcentaje de coincidencia entre 95-100%, esto querrá decir que varía en
alguna/s letra/s, de forma que estos errores son fácilmente identificables.
● Fichero pdf que se subirá al servidor: aquí se mostrarán el fichero pdf que mayor
coincidencia tenga con la publicación buscada (siempre que tenga un porcentaje de
coincidencia superior al 95%), si se encuentra en alguna de los directorios o urls
facilitados en el paso 2, junto con el porcentaje de coincidencia entre paréntesis. Si
no se ha encontrado ninguno, se puede indicar un fichero pdf manualmente,
insertando la ruta en el campo de texto o bien buscándolo en un directorio local
pulsando en el botón "examinar". En el caso de que la búsqueda devuelva varios
documentos con porcentajes de coincidencia superiores al 95%, entonces se
mostrarán en pantalla todos los resultados y se dará al usuario la posibilidad de
escoger el resultado correcto (esto suele ocurrir cuando un artículo y una ponencia
de congreso de un mismo autor sobre una misma temática se encuentran a la vez en
la fuente de la información: normalmente coincidirán en el nombre del artículo, y al
sistema le será imposible detectar cuál es el correcto).
● Casilla de verificación de "no especificación de pdf".
● Casilla de verificación de "entrada completa".
● Casilla de verificación de "entrada no deseada" (cuando no se desea añadir la
entrada a la base de datos).
El proceso de actualización tiene lugar en este paso de la siguiente forma: se mostrarán
todas las entradas contenidas en los ficheros de actualización; una vez una entrada esté
completa, se marcará la casilla de verificación de "entrada completa" y el sistema pasará a
actualizarla, de modo que al volver sobre este paso se mostrarán todas las entradas que
hubiere antes a excepción de las ya actualizadas. Todo esto puede observarse en la
ilustración 8.
En el proceso de actualización también se controla si existe una entrada igual en la base
56
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
de datos antes de actualizarla, con la finalidad de evitar duplicidades.
El fichero “functions.step3.php” es un fichero de funciones complementario para el paso
4, debido a que es bastante laborioso, y por claridad del código principal se han extraído la
mayoría de funciones independientes y se han incluido en este fichero.
Además, hay un fichero “proc_files.php” que realiza todo lo correspondiente a la copia
de ficheros en el servidor. Puesto que la copia de ficheros es un proceso largo, el usuario
puede creer que en algún momento del proceso el sistema se ha quedado colgado, ha
quedado en un estado inconsistente. Para soslayar este incoveniente está este fichero.
Durante la copia de ficheros muestra en pantalla una barra de progreso (como se muestra
en la Ilustración 7) que indica al usuario qué fichero se está copiando, el porcentaje copiado
y el porcentaje del total de ficheros a copiar. A su vez, en el fichero “paso3.php” está
programado que se muestre por pantalla cada una de las entradas que se van procesando.
Esto significa que en primer lugar se actualiza la base de datos y posteriormente se procede
a la copia de los ficheros.
Una vez actualizada por completo la base de datos, el sistema mostrará por pantalla un
mensaje de éxito en la actualización, como se muestra en la figura 8.
57Ilustración 6: Captura del paso 4 - Analizando las entradas de los ficheros
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
58
Ilustración 7: Captura del paso 4 - Copiando ficheros
Ilustración 8: Captura del paso 4 - Base de datos actualizada
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
59
Ilustración 9: Captura del paso 4 - Listado de los artículos encontrados
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4.1.5 FICHERO DE INCLUSIÓN GENERAL .El fichero de inclusión general es un fichero que se incluye al comienzo de todos los
ficheros que componen el proceso de actualización. En primer lugar desempeña una función
muy importante porque genera unos arrays a partir de la información de la base de datos
especificada que facilitan la migración hacia otro sistema. Esto es, crea arrays con
información sobre los campos de las tablas de las bases de datos y otra información que se
emplea en los pasos iniciales de configuración y que, al ser de carácter general, permiten a
un usuario avanzado que desee adaptar el sistema a otra base de datos modificar
solamente el procesado que se hace de los datos de la misma, sin tener que programar
nuevo código para obtener esta información. Estos arrays son:
● $lista_campos_adicionales: almacena los campos que no aparecen como tales
en las tablas de la base de datos pero que son necesarios porque a partir de ellos se
generarán otros que sí se encuentran en éstas.
● $tabla_campos_adicionales: almacena los nombres de las tablas que modificarán
los campos adicionales recogidos en “$lista_campos_adicionales”.
● $var_campos_adicionales: indica los nombres de los arrays que almacenarán los
valores de los campos adicionales tras leerlos de las fuentes de información
indicadas.
● $lista_campos_undef: estos campos son campos no existentes en tablas y que no
son necesarios para obtener campos existentes en la tabla, pero que sí son
necesarios para procesar éstos. A modo de ejemplo, un campo de este array es
“separador_campos”, el cual indica qué separador se utilizará en los ficheros de texto
para separar los campos contenidos.
● $tabla_campos_undef: similar a “$tabla_campos_adicionales” pero referido a
“$lista_campos_undef”.
● $var_campos_undef: similar a “$var_campos_adicionales” pero referido a
“$lista_campos_undef”.
● $valores_campos_undef: los campos definidos en “$lista_campos_undef” no
pueden ser ingresados por el usuario, y necesitan de unos valores definidos
previamente, permitiendo al usuario elegir uno u otro valor. Estos valores
predefinidos se almacenan en este array. Por ejemplo, para el caso del separador de
campos “separador_campos”, los valores pueden ser un retorno de carro, un carácter
nueva línea, un tabulador, un punto y coma, ...
60
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● $desc_campos_undef: son las descripciones que se mostrarán en la lista
desplegable del script de actualización, de modo que estas etiquetas almacenadas
en el array representarán lo que el usuario verá. Por ejemplo, en el caso de un
retorno de carro, aparecería en la lista desplegable “\r”.
Lo que resta de contenido de este fichero es un conjunto de funciones de carácter
general que son usadas en prácticamente todos los pasos del proceso de actualización.
El fichero que implementa estas funciones de carácter general es “functions.inc.php”.
4.2 CONTROL REMOTO DE PROCESOS EN TIEMPO REAL MEDIANTE MATLAB /TCP/IP.La finalidad de esta parte del proyecto es controlar un sistema a través de Simulink, en
tiempo real haciendo uso del toolbox "Real Time Workshop" y de forma remota haciendo
uso del protocolo Tcp/Ip para transportar datos a través de red e implementar un sistema
cliente/servidor.
Este sistema se pensaba emplear en la red de excelencia Hycon, y estaba destinado
para su uso en los experimentos sobre la planta solar de los laboratorios de la Universidad
de Sevilla, pero al final no se implementó. Estos experimentos se realizaban desde
universidades situadas en otros países, por lo que el control debía hacerse a través de un
operario situado en el ordenador de control de la planta solar, llevando a cabo todas las
acciones deseadas por los usuarios remotos. El problema que tiene este planteamiento es
que hay que tener una persona dedicada íntegramente a insertar las órdenes de los
usuarios, puesto que éstos no pueden acceder directamente al controlador.
Por ello, se pensó en una forma alternativa de control, basándose en el protocolo Tcp/Ip.
Matlab dispone de un modo de ejecución en Simulink denominado "modo externo".
Activando este modo, antes de la ejecución Matlab compila el modelo de Simulink,
generando código ejecutable. Este código ejecutable no es más que un servidor que
escucha peticiones en un puerto determinado. Para conectarse, un cliente simplemente
debe ejecutar el mismo fichero de modelo de Simulink con el que se compiló el servidor en
Matlab, e indicar la dirección ip y el puerto en los que se encuentra corriendo el servidor.
Con este modo parece en principio que se puede solucionar el problema del control remoto,
pero no es así: con este modo, cualquier usuario puede conectarse a la planta y modificar
parámetros sin ningún tipo de supervisión, lo que podría redundar en malfuncionamientos de
los equipos, inhabilitación de los mismos o incluso catástrofes. Por otra parte, solamente
61
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
puede conectarse un usuario al servidor.
Por tanto, el modo externo del Real Time Workshop ofrece ventajas e inconvenientes,
pero no sirve para solventar el problema en cuestión.
Tampoco se pudo utilizar el programa Matlab Server que implementa el propio Matlab,
debido a que, si bien permite la ejecución remota de ficheros de Matlab sobre el ordenador
que implementa el servidor, ésta se ejecuta en una instancia distinta por petición, esto es, si
el usuario ejecutase el controlador en Matlab Server, se crearía una nueva instancia de
ejecución para el nuevo usuario, de forma que se crearían varias para distintos usuarios,
perdiendo el requisito del control en tiempo real, puesto que no se pueden aplicar varios
controladores a una misma planta simultáneamente. Este modo de trabajo es útil para
realizar simulaciones de forma externa, pero se necesita un método que incluya la
exclusividad de la planta: solamente un usuario puede tener acceso a ella e implementar el
control que desee.
La solución fue utilizar funciones S, que pueden ser programadas en C. La función S
diseñada consta de un bloque con 1 entrada (que en realidad es irrelevante, pues no realiza
ninguna función, pero que podría tener su utilidad en una posterior facilidad del usuario, esto
es, siempre es más cómodo facilitar las referencias iniciales a través de bloques y
establecer su valor gráficamente, de modo que una futura mejora podría ser establecer
tantas entradas como salidas y facilitar los valores iniciales de los parámetros a través de
estas entradas en lugar de mediante la ventana de configuración del bloque) y 10 salidas. El
objetivo es que el usuario pueda establecer los valores que desee a las salidas del bloque,
pudiéndolos usar como referencias de otros bloques o incluso para cambiar valores de
parámetros, como ganancias estáticas. La función S lee periódicamente un fichero de
intercambio que almacena los valores a cambiar. Si el usuario desea modificar alguna de las
salidas del bloque, entonces una interfaz web actúa de cliente con un servidor que se
encuentra en el mismo ordenador que el ejecutable servidor de Matlab. Este servidor recibe
la información con los parámetros a cambiar y modifica el fichero de intercambio para que al
leerlo el ejecutable servidor de Matlab obtenga los nuevos valores de las salidas.
Las ventajas que ofrece este sistema sobre el modo externo son varias:
● Posibilidad de controlar el sistema desde cualquier ordenador vía la interfaz web.
● Posibilidad de implementar restricciones al control remoto mediante programación
en la función S encargada de la lectura promiscua del fichero de intercambio.
● Posibilidad de restringir qué parámetros se pueden modificar.
62
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Posibilidad de control simultáneo mediante varios usuarios.
Las desventajas también son importantes:
● El protocolo Tcp/Ip, a pesar de ser robusto, no es invulnerable a fallos en la red y
podrían perderse las modificaciones de algunos usuarios.
● Necesidad de implementar los bloques de Simulink como funciones S si se desea
cambiar parámetros de un bloque, como por ejemplo, la ganancia estática de un
sistema de segundo orden (este problema se verá más adelante).
En el siguiente apartado se describirán cada una de las partes que componen el sistema
completo.
4.2.1 ESTRUCTURA GENERAL DEL S ISTEMA DE CONTROL REMOTO.La estructura de conexión del sistema se muestra a continuación:
Los elementos involucrados son:
● Ordenador remoto: se trata de un PC con conexión a internet que accederá a la
interfaz web de control remoto del sistema mediante un navegador cualquiera.
● Servigar: es el servidor que aloja la interfaz web de control remoto. Implementa un
63
Ilustración 10: Estructura general del sistema de control remoto
SERVIGAR
NEOXITE
WebPage
Server
Server
Client
WWW
REMOTE PC
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
servidor IIS con sistema operativo Windows XP Professional. La interfaz web se
encuentra programada en Visual C# (la parte del servidor) y ASP (la parte de la
interfaz web). Esta interfaz web es la encargada de mostrar al usuario los valores
existentes en el modelo de Simulink que se encuentra corriendo actualmente en el
servidor Neoxite, así como de recibir los nuevos valores que los usuarios remotos
deseen modificar y enviar dichos datos a una aplicación servidor que escucha en un
determinado puerto en Neoxite. Además, tiene implementado una aplicación servidor
que recibe de Neoxite una representación del modelo de Simulink implementado,
para que se muestre al usuario en la interfaz web, el modelo de Simulink (fichero
“.mdl”) y el fichero con los valores de los parámetros.
● Neoxite: es el ordenador que se encarga del control del sistema. Será el que
implemente la ejecución del modelo en Simulink para el control del sistema, por lo
que consta de una aplicación en Matlab para generar una representación del modelo
y enviar ésta junto con el modelo a la aplicación servidor en Servigar. Esta aplicación
en Matlab invoca una aplicación cliente que envía ambos ficheros a la aplicación
servidor en Servigar. También implementa una aplicación servidor que recoge los
datos enviados por Servigar cuando se modifiquen los valores de los parámetros.
Esta aplicación servidora modifica el fichero de intercambio en consecuencia,
permitiendo que en la siguiente lectura del bloque de función S Simulink modifique
los valores de sus salidas.
4.2.2 S ERVIGAR .
4.2.2.1 INTERFAZ WEB.La interfaz web se encuentra programada en ASP y Visual C#, debido a que se tenía
pensado implementarla en un principio en el Benchmark 2 de la red de excelencia Hycon,
que se encarga del control remoto de un sistema híbrido (una plataforma solar con 4 placas
solares, un sistema de refrigeración y una caldera), y se necesitaba implementar ActiveX
para poder realizar el control vía OPC.
Como se puede observar en la siguiente imagen, la interfaz web es simple: muestra dos
cuadros de texto por cada parámetro modificable (uno con el valor actual y otro para insertar
el nuevo valor), y debajo de estos cuadros se sitúa una representación gráfica del
controlador implementado, para que los usuarios sepan si el controlador implementado es el
64
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
suyo o no. Además, de esta forma es más fácil ver qué salida se corresponde con el
parámetro deseado, consiguiendo una modificación de los parámetros más fácil e intuitiva.
La parte de ASP es bien simple. No ocurre así con la parte de Visual C#. Lo primero que
se hace es comprobar que el usuario posee los permisos necesarios para proceder con la
modificación de parámetros (para ello tiene que estar dado de alta en el sistema, es decir,
en la web, y tener reservado un periodo de prueba sobre la planta o bien ser el
administrador). Posteriormente, se comprueba la existencia del fichero de modelo de
Simulink así como de su representación gráfica.
El siguiente paso es la lectura del fichero "nombre.mdl" (donde "nombre" indica el
65
Ilustración 11: Captura de la interfaz web del sistema de control remoto
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
nombre del fichero que se encuentre en el direcorio de la página), que contiene los valores
actuales de los parámetros. Esto se utilizará para mostrar los valores en los campos
sombreados en gris, que indican los valores actuales. Si el usuario desea un nuevo valor,
deberá indicarlo en el cuadro blanco adjunto.
Asociado al botón "Change Parameters" se encuentra el método
"ButtonChangeParams_Click", que implementa toda la parte cliente de la interfaz web, la
cual será la que envíe los datos cambiados a la aplicación servidor sito en Neoxite. El primer
paso es establecer una conexión con el equipo destino, en este caso Neoxite.
Posteriormente, se crea el mensaje a enviar. Para ello se miran todos los campos de texto
de los parámetros. Si el campo no está vacío, entonces se introduce en el mensaje una
línea con el texto "varX=valor\n", donde X es el número de la variable y valor es la cantidad
introducida en el campo de texto. Las líneas se separan unas de otras introduciendo un
carácter de nueva línea "\n".
La construcción del mensaje inicial obedece a un protocolo bastante simple creado para
esta aplicación. El formato de dicho mensaje es:
REQUEST*MODE*IP_ADDRESS*MSG_LENGTH*FILE_NAME
"REQUEST" indica el tipo de petición. En este caso, siempre será del tipo
"MOD_REQUEST", que indican que se trata de una petición de modificación del fichero de
intercambio.
"MODE" indica el modo de la petición. En este caso, siempre será "OVERWRITE", que
indica que en el lado servidor se crea un nuevo fichero, sobreescribiendo el anterior en caso
de que existiera.
"IP_ADDRESS" es la dirección a la que se envía el mensaje, es decir, la dirección de
NEOXITE.
"MSG_LENGTH" es el tamaño del fichero que se va a enviar posteriormente. Este
mensaje será el que incluya todos los datos necesarios para la modificación del fichero de
intercambio.
"FILE_NAME" es el nombre del fichero que se va a modificar.
Una vez enviado este mensaje inicial de solicitud de modificación del fichero de
intercambio se espera el ACK o mensaje de asentimiento. Este mensaje se caracteriza
porque simplemente se trata de una cadena de texto con el mensaje "PROCEED" en caso
de que se permita proceder con la modificación. En caso de recibir cualquier otra cosa, se
66
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
aborta la operación.
Una vez enviado los datos que se han de modificar, se modifica también el fichero
"nombre.log" (donde "nombre" indica el nombre del fichero que se encuentre en el directorio
de la página), que reside en Servigar y que se utiliza para leer los valores actuales de los
parámetros. Puesto que se modifican, se ha de actualizar. Para éste no es necesario
realizar una petición, puesto que se encuentra en el mismo ordenador.
Por último, se han de refrescar los campos de texto con los valores actuales, y vaciar el
contenido de los campos de texto que modifican los valores de los parámetros.
En todo momento existe una etiqueta para mostrar mensajes de error en caso de que los
hubiere. Los casos contemplados son los errores de conexión con la aplicación servidor en
Neoxite.
El código para la interfaz web se encuentra en el fichero “tunning.aspx.cs”.
4.2.2.2 APLICACIÓN S ERVIDOR EN S ERVIGAR .Esta aplicación se encuentra programada en Visual C#. Su función principal es la
recepción de tres ficheros, necesarios para el correcto funcionamiento de la interfaz web.
Estos tres ficheros son enviados por la aplicación cliente en Neoxite, y son los siguientes
(donde "nombre" indica el nombre del fichero que se encuentre en el direcorio de la página):
● nombre.log: fichero de texto plano que contiene los valores iniciales de los
parámetros.
● nombre.mdl: fichero de modelo de Simulink que contiene el modelo implementado
en el control del sistema.
● nombre.png: fichero de imagen que contiene una captura del modelo con la
finalidad de mostrarlo posteriormente en la interfaz web.
La aplicación servidor es una aplicación multihilo, pues implementa en un hilo un servidor
síncrono que se bloquea a la escucha de nuevas peticiones por un determinado puerto, y
por otro lado, un hilo que implementa el control de la aplicación y permite en cualquier
momento salir de la misma.
La primera operación que se realiza es la ejecución del hilo de control de la aplicación,
denominado "hilo_lector", por leer de forma promiscua la entrada de datos a través del
teclado.
67
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
En segundo lugar se inicia el servidor en sí, enlazándolo con el punto local
correspondiente a Servigar (193.147.161.89), y poniéndolo a escuchar de forma promiscua
en un puerto (39854) dentro de un bucle de control. En este bucle, lo primero que se hace
es, como ya se ha dicho, poner el servidor a escuchar en un puerto específico, y
posteriormente, cuando se recibe una conexión entrante, comienza el procesamiento de la
petición.
En primer lugar se realiza un filtrado de las IPs, pues no se permite la conexión de
cualquier equipo. Si se trata de una dirección IP válida y admitida, entonces se recibe el
mensaje y se procesa la solicitud. Existen distintos casos:
● "COPY_REQUEST": solicitud de copia de ficheros remota.
● "MOD_REQUEST": solicitud de modificación remota de ficheros.
● "ABORT": solicitud de abortar programa.
Todo esto se resume en el flujo de programa de la ilustración 12.
Hay que mencionar que en una petición de copia remota de ficheros (COPY_REQUEST)
se compara la extensión del fichero recibido. Si dicha extensión coincide con la extensión
propia de los ficheros de modelo de Simulink (.mdl), entonces se genera también el fichero
.log aquí. Este fichero se crea a partir de la lectura y el análisis del fichero de modelado de
Simulink. Se busca la línea de definición de los parámetros del bloque que contiene la
función S que implementa el control remoto, se almacenan los valores de dichos parámetros
en un array y posteriormente se insertan en un fichero, de nombre el mismo que el fichero
de modelado, y extensión “.log”. Este fichero será el que utilizarán más adelante la interfaz
web y la aplicación servidor de Servigar para la actualización de los valores modificados por
el usuario remotamente.
El hilo lector de teclado es más simple en su concepción y funcionamiento. Simplemente
lee la entrada del teclado a la espera de recibir la cadena "exit", momento en el cual
procede a enviarse a sí mismo un mensaje "ABORT" para salir del bucle de escucha
promiscua de mensajes entrantes.
Todo el código se encuentra embebido en estructuras try-catch para capturar todas las
excepciones posibles, con la finalidad de hacer seguro el código.
68
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
4.2.3 NEOXITE.
4.2.3.1 B LOQUE TUNNING (S-FUNCTION).El fichero “tunning.c” contiene el código fuente del bloque que implementa la lectura del
fichero de intercambio.
Lo primero que debe hacerse es compilar este fichero para que Matlab genere una dll
que pueda usarse en los bloques de funciones S de Simulink. Para ello, desde la línea de
comandos y siendo el directorio de trabajo el que contiene el fichero “tunning.c”, el usuario
ha de escribir en la línea de comandos de Matlab:
mex tunning.c
Tras haber finalizado la compilación, en el mismo directorio se encontrará el fichero
“tunning.dll”, que contendrá la versión compilada del código fuente de la función S.
Para utilizar esta dll, en el modelo de Simulink que implemente el controlador que se
desea testear remotamente el usuario debe insertar un bloque “S-Function” (en Simulink
Library Browser se encuentra en “Simulink”→”User–Defined Functions”→”S-Function”), y
69
Ilustración 12: Flujo del programa multihilo servidor de Servigar
Port Listening
IP Filter
Process Received Message
COPY REQ. MOD REQ. ABORT
Read Keyboard Input
Exit
EXIT
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
especificar en las propiedades del mismo lo siguiente:
S-function name: tunning
S-function parameters: 1,2,3,4,5,6,7,8,9,10
Entonces aparecerá un bloque de Simulink de nombre “tunning”, con una entrada y diez
salidas. Nótese que el nombre de la función S que se especifica debe ser el de la dll. Si la dll
no se encuentra en el mismo directorio que el modelo de Simulink que la invoca, al intentar
ejecutar el modelo producirá un error.
Los parámetros que se definen en las propiedades corresponden a los valores iniciales
de las salidas del bloque. Estos valores son los que posteriormente se modificarán a través
de la interfaz web (se ha puesto del 1 al 10 por poner algún valor, pero el usuario deberá
poner aquí las referencias iniciales que desea a la salida del bloque).
Por otro lado, también hay que tener en cuenta las distintas modificaciones de las
propiedades del modelo que hay que realizar previamente. Para que se genere el ejecutable
del modelo es necesario establecer la siguiente configuración:
● En “Tools”→”Real-Time Workshop”→”Options”:
○ En la pestaña “Real-Time Workshop”:
■ Category: Target configuracion.
● System target file: grt.tlc.
● Template makefile: grt_default_tmf.
● Make command: make_rtw.
● Desmarcar “Generate code only”.
■ Category: General code generation options:
● Marcar “Verbose builds”.
● Marcar “Local block outputs”.
■ Category: GRT code generation options:
● Marcar “External mode”.
○ En la pestaña “Solver”:
■ Solver options:
● Type: Fixed-step, discrete (no continuous states).
70
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Fixed step size: auto.
● Mode: Single Tasking.
● En “Tools”→”External mode control panel”:
○ En “Target interface”:
■ MEX-file for external interface: ext_comm.
En la pestaña de la ventana de Simulink que muestra una lista desplegable hacia abajo y
que tiene seleccionada la opción “Normal”, hay que seleccionar la opción “External”.
Una vez creado el modelo de Simulink deseado para implementar el controlador, se ha
de compilar el modelo completo, y para ello se presiona en el botón “Build All”, que se
encuentra junto a la lista desplegable anterior.
4.2.3.2 APLICACIÓN MATLAB .La finalidad de la aplicación programada para Matlab es la establecer todos los requisitos
previos para un control remoto. Básicamente se encarga de la generación de la imagen del
controlador y el posterior envío de la misma junto con el fichero del controlador al servidor
web.
El flujo del programa se describe en el siguiente esquema:
71
Ilustración 13: Flujo del script de Matlab para el sistema de control remoto
Obtener nombre controlador
Almacenar imagen controlador
Enviar .mdl y .png
Eliminar ficheros intermedios
Fin
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Inicialmente el programa solicita al usuario el nombre del fichero que contiene el
controlador (con extensión .mdl o sin ella). A continuación abre dicho controlador en una
nueva ventana de Simulink donde realiza una captura para generar el fichero de imagen.
Dicho fichero de imagen se crea haciendo uso del ejecutable "convert.exe" que se
distribuye con el paquete de software libre ImageMagick.
Matlab proporciona un fichero de imagen “.bmp”, pero para enviar imágenes a través de
la red es conveniente convertir el formato a uno que ofrezca compresión y además
proporcione ventajas adicionales, como la transparencia de fondo, para una mejor
integración con la interfaz web. Por todo ello, el formato destino de la conversión es .png
(Portable Network Graphics), y es debido a esto la utilización de ImageMagick, ya que
proporciona un ejecutable en línea de comandos que facilita en gran medida la conversión
de “.bmp” a “.png”.
Por último, el programa invoca a la aplicación cliente de Neoxite
(cp_client_neoxite.exe), que es la que se encarga del envío de ambos ficheros, el de
imagen y el de Simulink, a la aplicación servidor sito en Servigar, que ubica ambos ficheros
en un directorio específico para que la interfaz web sea capaz de generar correctamente los
datos en pantalla.
El fichero que contiene la aplicación Matlab es "sendtoservigar.m".
NOTA: el fichero de parámetros se ha de crear manualmente antes de proceder a la
ejecución del modelo de Simulink. Se ha de crear un fichero de texto. Su contenido puede
ser nulo, o si el usuario lo prefiere, puede insertar una línea por variable, con la sintaxis
“varX=val”, donde “X” indica el índice de la variable (var1, var2, etc) y val el valor de la
misma, aunque esto lo realiza el bloque de modificación de parámetros automáticamente
una vez se inicia su ejecución, pero se ha de recalcar que dicho bloque NO crea el fichero.
El nombre del fichero deberá ser “tunning.txt”.
4.2.3.3 APLICACIÓN C LIENTE.La aplicación cliente de Neoxite es la que se encarga de la copia/modificación de
ficheros remota en Servigar. Es invocada por el script programado para Matlab y, al igual
que los servidores programados tanto en Neoxite como en Servigar, dispone de un protocolo
de transferencia diseñado para un mejor control y una mayor fiabilidad de las operaciones
72
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
remotas.
El protocolo posee un esquema de funcionamiento simple. En primer lugar el cliente
genera un mensaje de intercambio de información en el que indica al servidor el tipo de
petición que desea realizar y además le proporciona información diversa que es necesaria
para éste. El formato de este mensaje inicial es:
REQUEST*MODE*IP_ADDRESS*MSG_LENGTH*FILE_NAME
"REQUEST" indica el tipo de petición. Puede ser del tipo "COPY_REQUEST" o
"MOD_REQUEST", que indican que se trata de una petición de copia de fichero o de
modificación de fichero respectivamente.
"MODE" indica el modo de la petición. Puede tener los valores "CREATE" u
"OVERWRITE", que indica que en el lado servidor se crea un nuevo fichero, sin
sobreescritura en el primer caso, o sobreescribiendo el anterior en caso de que existiera en
el segundo caso.
"IP_ADDRESS" es la dirección a la que se envía el mensaje, es decir, la dirección de
NEOXITE.
"MSG_LENGTH" es el tamaño del fichero que se va a enviar posteriormente. Este
mensaje será el que incluya todos los datos necesarios para la modificación del fichero de
intercambio.
"FILE_NAME" es el nombre del fichero que se va a modificar.
Una vez enviado este mensaje inicial de solicitud de modificación del fichero de
intercambio se espera el ACK o mensaje de asentimiento. Este mensaje se caracteriza
porque simplemente se trata de una cadena de texto con el mensaje "PROCEED" en caso
de que se permita proceder con la modificación. En caso de recibir cualquier otra cosa, se
aborta la operación.
Una vez recibido el asentimiento positivo se procede al envío del fichero, que el servidor
recogerá en el lado destino, creando un fichero similar en el sitio adecuado.
Existen distintos casos:
● "COPY_REQUEST": solicitud de copia de ficheros remota.
● "MOD_REQUEST": solicitud de modificación remota de ficheros.
● "ABORT": solicitud de abortar programa.
Los envíos se realizan al puerto 39854 de Servigar, que es donde se encuentra
73
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
escuchando la aplicación servidor.
4.2.3.4 APLICACIÓN S ERVIDOR .Esta aplicación se encuentra programada en Visual C#. Su función principal es la
recepción del fichero que contiene la actualización de los parámetros del bloque de control
remoto, modificados por el usuario remoto a través de la interfaz web. Este fichero es
enviado por la interfaz web en Servigar, y tiene extensión “.log” (fichero de texto plano que
contiene los valores actualizados de los parámetros).
La aplicación servidor es una aplicación multihilo, pues implementa en un hilo un servidor
síncrono que se bloquea a la escucha de nuevas peticiones por un determinado puerto, y
por otro lado, un hilo que implementa el control de la aplicación y permite en cualquier
momento salir de la misma.
La primera operación que se realiza es la ejecución del hilo de control de la aplicación,
denominado "hilo_lector", por leer de forma promiscua la entrada de datos a través del
teclado.
En segundo lugar se inicia el servidor en sí, enlazándolo con el punto local
correspondiente a Neoxite (172.16.1.231), y poniéndolo a escuchar de forma promiscua en
un puerto (32000) dentro de un bucle de control. En este bucle, lo primero que se hace es,
como ya se ha dicho, poner el servidor a escuchar en el puerto específico, y posteriormente,
cuando se recibe una conexión entrante, comienza el procesamiento de la petición.
En primer lugar se realiza un filtrado de las IPs, pues no se permite la conexión de
cualquier equipo. Si se trata de una dirección IP válida y admitida, entonces se recibe el
mensaje y se procesa la solicitud. Existen distintos casos:
● "COPY_REQUEST": solicitud de copia de ficheros remota.
● "MOD_REQUEST": solicitud de modificación remota de ficheros.
● "ABORT": solicitud de abortar programa.
Todo esto se resume en el flujo de programa de la ilustración 14:
74
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
El hilo lector de teclado es más simple en su concepción y funcionamiento. Simplemente
lee la entrada del teclado a la espera de recibir la cadena "exit", momento en el cual
procede a enviarse a sí mismo un mensaje "ABORT" para salir del bucle de escucha
promiscua de mensajes entrantes.
Todo el código se encuentra embebido en estructuras try-catch para capturar todas las
excepciones posibles, con la finalidad de hacer seguro el código.
4.2.4 UBICACIÓN Y PUESTA A PUNTO DE LOS PROGRAMAS .La ubicación de cada uno de los programas es importante. Si no se tiene cuidado al
colocar los ejecutables se obtendrán errores adicionales. A continuación se especifica la
puesta a punto de cada uno de ellos:
● Aplicación de conversión de formato gráfico "convert.exe": debe encontrarse en el
mismo directorio que la aplicación de Matlab "sendtoservigar.m".
● Aplicación de Matlab: esta aplicación es un fichero con nombre
"sendtoservigar.m". Debe situarse en el directorio de trabajo donde se encuentre el
fichero de modelo de Simulink que contiene el controlador a implementar el control
75
Ilustración 14: Flujo del programa multihilo servidor de Neoxite
Port Listening
IP Filter
Process Received Message
COPY REQ. MOD REQ. ABORT
Read Keyboard Input
Exit
EXIT
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
remoto. La ejecución es muy simple. Basta con escribir "sendtoservigar" en la línea
de comandos de Matlab (con cuidado de estar situados en el mismo directorio en
que se encuentra "sendtoservigar.m"), y la secuencia a seguir una vez invocado el
script es la siguiente:
○ Inserción del nombre del fichero de modelo de Simulink (con o sin extensión
".mdl").
○ Esperar a la finalización del programa.
Durante el transcurso de la ejecución, la aplicación irá mostrando por pantalla los
distintos avances que irán sucediendo, como son la detección del fichero de
modelado, la obtención de su representación, la conversión del formato gráfico o el
envío sucesivo de los ficheros al servidor sito en Servigar.
● Interfaz web en Servigar: es la página web que contiene la interfaz de
modificación remota de los parámetros. El resultado de la compilación de esta página
ha de ubicarse en el directorio web en el que se proporcione el servicio de hosting
de páginas (depende del servidor web instalado, por ejemplo, Apache Server o
Internet Information Server, y de su configuración). En este punto hay que tener en
cuenta que la interfaz web se diseñó para su interfuncionamiento con el sitio web de
la Planta Solar encuadrada en el proyecto europeo Hycon. Este hecho indica que el
sistema de validación es el que usaba dicho sitio web. Si se desea utilizar en otro
ámbito, será necesario modificar la programación de dicha interfaz para adecuarla a
las nuevas condiciones de trabajo.
● Aplicación servidor en Servigar "cp_server_servigar.exe": debe ubicarse en la
misma carpeta que la página "tunning.aspx", que es la que implementa la interfaz
web para cambiar remotamente los parámetros. El funcionamiento de este servidor
es sencillo: una vez ejecutado, mostrará por pantalla un mensaje indicando que si se
escribe la palabra "exit" se detendrá la ejecución del mismo, dando a entender que
se ejecutará de forma indefinida si el usuario no escribe la orden correspondiente. El
servidor se quedará a la escucha de peticiones en el puerto designado y cuando
reciba alguna lo mostrará por pantalla.
● Aplicación cliente en Neoxite "cp_client_neoxite.exe": esta aplicación debe
ubicarse en la misma carpeta que el script de Matlab "sendtoservigar.exe", ya que
éste lo utiliza para el envío de ficheros al servidor ubicado en Servigar. En teoría el
usuario no necesita saber de la ejecución de este cliente, puesto que lo invoca la
76
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
misma aplicación "sendtoservigar.m".
● Aplicación servidor en Neoxite "cp_server_neoxite.exe": debe ubicarse en el
mismo directorio en que se esté ejecutando el fichero del modelo de Simulink, puesto
que en dicho directorio se creará el fichero “.log” que se utilizará para alterar los
valores de los parámetros. El funcionamiento de este servidor es, al igual que el
situado en Servigar, bastante sencillo: una vez ejecutado, mostrará por pantalla un
mensaje indicando que si se escribe la palabra "exit" se detendrá la ejecución del
mismo, dando a entender que se ejecutará de forma indefinida si el usuario no
escribe la orden correspondiente. El servidor se quedará a la escucha de peticiones
en el puerto designado y cuando reciba alguna lo mostrará por pantalla.
4.2.5 EJEMPLO COMPLETO DE CONTROL REMOTO.A continuación se mostrará un ejemplo completo que ilustrará el funcionamiento de la
utilidad de control remoto.
1º) Se situarán los siguientes ficheros en el directorio “%MATLAB_PATH%/work/” en el
ordenador Neoxite:
● convert.exe● cp_client_neoxite.exe● cp_server_neoxite.exe● tunning.c● tunning.txt● params.mdl● sendtoservigar.mEl fichero tunning.txt es un fichero de texto que contiene una lista de asignación de
valores a las variables cuyos valores se podrá cambiar, con las asignaciones separadas por
retornos de carro. Un ejemplo del contenido podría ser:
var1=1var2=2var3=3
Se situarán los siguientes ficheros en el directorio “/Files/Simulink/” del sitio web de la
planta solar en Servigar:
● cp_server_servigar.exe2º) Lo siguiente a realizar es la compilación del bloque de modificación remota de
parámetros. Desde la línea de comandos de Matlab se escribirá:
77
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
mex tunning.c
A continuación se configurará el fichero de modelo de Simulink tal y como se describe en
el punto 3.2.3.1. Una vez hecho esto, ya nos encontramos en condiciones de generar el
ejecutable. Para hacer esto, presionamos sobre el botón “Build All” de la ventana de
Simulink. Una vez terminada la compilación se habrá generado una carpeta
“params_grt_rtw” que contendrá todo el código fuente del ejecutable generado, mientras que
el ejecutable se encontrará en la misma carpeta que el modelo de Simulink.
78
Ilustración 15: Compilado de la función S "tunning.c" en Matlab
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
3º) Antes de proceder a la ejecución del modelo, se han de “arrancar” los distintos
servidores que deben quedarse a la espera de peticiones en los puertos. Por tanto, en este
paso se ejecutan los ejecutables “cp_server_neoxite.exe” y “cp_server_servigar.exe” en
79
Ilustración 16: Modelo de ejemplo de Simulink
Ilustración 17: Compilación del model de ejemplo de Simulink para su uso con RTW y el modo externo
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Neoxite y Servigar respectivamente.
4º) El operario encargado de ejecutar el controlador pondrá en marcha el sistema,
invocando "sendtoservigar.m" desde la línea de comandos de Matlab. Esta aplicación se
comunicará con el servidor sito en Servigar y llevará a cabo la puesta a punto del sistema.
Una vez configurado el sistema, el operario ejecutará el controlador del usuario, no sin antes
haber arrancado el ejecutable servidor del modo externo generado en el paso 2. Para ello, el
operario abrirá una ventana de comandos de Windows (una consola), se desplazará al
directorio donde se encuentra dicho ejecutable para el modo externo y una vez ubicado en
dicha carpeta ejecutará el siguiente comando:
params -tf inf -wLa opción “-tf” establece el tiempo final de la ejecución en tiempo real. Con “inf” se
indica que se desea que el tiempo de ejecución sea infinito. La opción “-w” se utiliza para
esperar el mensaje de bienvenida del host, esto es, que no se empieza a ejecutar hasta que
un cliente se conecta con el fichero del modo externo.
80
Ilustración 18: Servidor corriendo en Servigar
Ilustración 19: Servidor corriendo en Neoxite
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Lo siguiente será, como ya se dijo anteriormente, ejecutar el controlador del usuario.
Para ello, se abre el modelo del controlador en Simulink, se escoge el modo externo en la
lista desplegable superior y se presiona sobre el botón que hay justamente a la izquierda de
la lista, que muestra como ayuda emergente al posar el ratón sobre él “Connect to target”.
Esto conectará el modelo con el ejecutable que se ha arrancado antes. Una vez conectado,
ya solamente resta pulsar en el botón “Start real-time code”, situado a la izquierda del
anterior.
81
Ilustración 20: Ejecución del modelo compilado de Simulink
Ilustración 21: Ejecución del modelo de Simulink en modo externo haciendo uso de RTW
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
82
Ilustración 22: Esquema del envío de ficheros de Neoxite a Servigar mediante el script de Matlab
SERVIGAR
NEOXITE
Server
Client
WWW
Ilustración 23: Ejecución del script de Matlab
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
El usuario cuyo controlador se encuentra en funcionamiento, debido a que en la
supervisión de los resultados observa que éstos no son los deseados, desea modificar
determinados aspectos de su controlador, y para ello accede a la interfaz web desde un
punto remoto a través de internet:
83
Ilustración 24: Recepción de los ficheros enviados por Matlab en el servidor de Servigar
Ilustración 25: Acceso del usuario remoto a la interfaz web de Servigar
SERVIGARWebPage
WWW
REMOTE PC
Ilustración 26: Captura de la interfaz web
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Después de validarse convenientemente, el usuario tendrá acceso a la interfaz web y
verá los valores actuales de los parámetros de su controlador y modificará aquellos que no
le plazcan. En este momento, tras pulsar el botón de actualizar dichos valores, la interfaz
web se comunicará con el servidor sito en Neoxite para modificar el fichero de intercambio
de datos, de forma que el bloque de modificación de parámetros pueda actualizar los
nuevos valores.
84
Ilustración 27: Esquema del envío de datos de la interfaz web al servidor de Neoxite
SERVIGAR
NEOXITE
WebPage
Server
WWW
REMOTE PC
Ilustración 28: Recepción de los parámetros modificados en el servidor de Neoxite
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
85
Ilustración 29: Captura del valor del parámetro después del cambio
Ilustración 30: Captura del valor del parámetro antes del cambio
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
5 RESULTADOS EXPERIMENTALES .
5.1 S ISTEMA DE ACTUALIZACIÓN DE B ASES DE DATOS
Como batería de pruebas del sistema se utilizaron ficheros de texto con publicaciones
contenidas en la base de datos del SICA.
En estos ficheros, los campos se encontraban separados mediante tabuladores, mientras
que las entradas a añadir en la base de datos se encontraban separadas mediante retornos
de carro.
Cada uno de los ficheros se encargaba de actualizar una tabla distinta de la base de
datos, que para las pruebas fue la base de datos “groupweb”, emplazada en el servidor
Nyquist de los laboratorios de la Universidad de Sevilla, y que albergaba el sitio web del
grupo de control predictivo.
Inicialmente se realizaron pruebas de inserción manual de los datos contenidos en los
ficheros, y posteriormente se procedió a la actualización de la base de datos mediante el
sistema diseñado en el presente proyecto.
Los tiempos de actualización se muestran en la siguiente tabla comparativa:
Nombre del fichero
Número de entradas
Tiempo empleado en inserción
manual de datos
Tiempo empleado en inserción
automática de datos
Tiempo empleado por el sistema en el
análsis de datosjournals.txt 75 3h15m 0h31m 0h15m
congress.txt 211 7h32m 1h20m 0h42m
phds.txt 10 0h23m 0h05m 0h02m
books.txt 9 0h18m 0h03m 0h01m
actas.txt 26 1h03m 0h07m 0h04m
TOTAL: 331 12h31m 2h06m 1h04m
Todos los experimentos se llevaron a cabo en condiciones óptimas, esto es, tomando
como conocida la existencia y localización de los documentos pdf complementarios a las
entradas existentes en los ficheros de texto, así como usando un operario con amplia
86
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
destreza en el uso de ordenadores con una velocidad de mecanografiado de 400 ppm.
En la siguiente tabla se muestran las estadísticas resultantes de la comparación de
ambos métodos:
Nombre de fichero
Reducción de tiempo
Tiempo efectivo de trabajo
Tiempo medio por entrada manual
Tiempo medio por entrada automática
journals.txt 84.1 % 51.6 % 2.60m 0.41m
congress.txt 82.3 % 47.5 % 2.14m 0.38m
phds.txt 78.3 % 60.0 % 2.30m 0.50m
books.txt 83.3 % 66.6 % 2.00m 0.33m
actas.txt 88.9 % 42.9 % 2.42m 0.27m
TOTAL: 83.2 % 49.2 % 2.27m 0.38m
Como demuestran los resultados, el trabajo se reduce en casi la mitad, y el tiempo que
se tarda en actualizar el sistema disminuye alrededor de un 80 %, por lo que se deduce que
el sistema funciona produciendo los resultados esperados.
5.2 CONTROL REMOTO DE UNA PLANTA A TRAVÉS DE UNA INTERFAZ WEB USANDO MATLAB .
Las pruebas llevadas a cabo con la función S programada dieron los resultados
esperados. No obstante, si el tiempo de muestreo del sistema es muy bajo, esto implicará
que se realizarán muchos accesos al disco duro para la lectura del fichero de texto que
almacena los valores de las variables. Por tanto, se recomienda programar una pequeña
porción de código para que la lectura del fichero sólo se lleve a cabo cada ciertos múltiplos
del tiempo de muestreo o mediante cualquier otro criterio del usuario.
Si no se tiene acceso al tiempo de muestreo, siempre es posible definir una variable
global de valor incremental conforme avanza la ejecución del modelo. Cuando ésta adquiera
un determinado valor, se reiniciaría y éste sería el evento mediante el cual se llevaría a cabo
la lectura del fichero de texto con los valores.
En lo que respecta a las pruebas, como cabía esperar, se modificaron los valores de las
salidas del bloque, aunque el sistema en determinadas ocasiones se ralentizaba, sobretodo
cuando el tiempo de muestreo era bajo.
87
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
6 CONCORDANCIA ENTRE RESULTADOS Y OBJETIVOS .
6.1 S ISTEMA DE ACTUALIZACIÓN DE B ASES DE DATOS .Como se desprende del apartado anterior, los resultados obtenidos con el sistema son
bastante buenos. Se consigue reducir drásticamente el tiempo de actualización de un
sistema en torno al 80 %.
Por otra parte, también se alivia el trabajo realizado por el usuario encargado de la
actualización, pues éste realiza hasta un 50 % menos de trabajo empleando el sistema
diseñado que si lo actualizase directamente.
En consecuencia, los objetivos son satisfechos completamente, puesto que permiten que
con un mínimo esfuerzo y una mínima dedicación de tiempo se lleve a cabo la actualización
exitosa de la base de datos.
6.2 CONTROL REMOTO DE PLANTA MEDIANTE MATLAB /TCP/IP.Los resultados cumplen con los objetivos en tanto que permiten la manipulación de datos
en Matlab a través de una interfaz web. El mayor problema reside en la correcta
“configuración” de las lecturas promiscuas del fichero de datos que almacena los valores
que se han de cambiar, pues puede llegar colapsar el sistema o actualizar con demasiada
lentitud el mismo.
No obstante, los objetivos fijados se cumplen.
88
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
7 CONCLUSIONES .
7.1 ACTUALIZACIÓN AUTOMÁTICA DE B ASE DE DATOS .El sistema cumple de forma esperada todos los objetivos establecidos al comienzo del
mismo. No obstante, aquí se podrían remarcar las ventajas e inconvenientes del sistema,
derivadas de la experimentación con el mismo.
Ventajas:
● La actualización se realiza de forma satisfactoria.
● No se producen duplicidades de entradas en la base de datos debido a una
comprobación anterior.
● Aunque la copia de ficheros en el servidor no es inmediata, para no dar al usuario
la impresión de cuelgue del sistema se ha creado una barra de progreso que
muestra al usuario la progresión de la copia del fichero actual y la progresión total de
la copia de ficheros. Aunque esto no resuelve el problema de la lentitud de la subida
sí sirve para evitar que el usuario tenga una falsa impresión de incompleción de la
actualización y éste intente actualizar la página de actualización, lo que sí podría
resultar en resultados incoherentes o duplicidades.
● Igualmente, el análisis de los ficheros de las publicaciones no es inmediato, y se
muestra una línea de información que indica la línea que se está analizando en el
momento con la finalidad de que el usuario vea que el sistema está funcionando y no
está colgado.
● Se ofrece al usuario la posibilidad de corregir los posibles errores existentes antes
de proceder con la actualización, e incluso la posibilidad de complementar los
campos no disponibles en los ficheros de actualización.
Desventajas:
● El análisis de coincidencia de los nombres de las publicaciones y los nombres de
los documentos a subir al servidor disponibles en los hiperenlaces es demasiado
lento, y esta lentitud crece conforme más aumente la diferencia de longitudes de las
cadenas a comparar. Es por esto que se ha limitado esta diferencia a un máximo de
5 caracteres, para no ralentizar en exceso el sistema.
89
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● La copia de ficheros en el servidor no es inmediata, y depende de la calidad de la
conexión de que se disponga para realizar la actualización.
● La lentitud del sistema aumenta con el volumen de datos a actualizar, pero esto
es una consecuencia inevitable.
7.2 CONTROL REMOTO DE S ISTEMAS MEDIANTE MATLAB /SIMULINK.El sistema de control remoto funciona correctamente y de la forma esperada. Al igual que
en el apartado anterior, se sopesarán aquí sus ventajas e inconvenientes:
Ventajas:
● Posibilidad de cambiar parámetros en un modelo de Simulink vía internet en
cualquier momento y desde cualquier lugar.
● Interfaz web simple y fácil de usar.
Desventajas:
● Sistema complejo de servidores y clientes. Sería más eficaz poder implementar
mecanismos tcp/ip dentro del bloque de la función S de Simulink, pues ahorraría un
servidor en Neoxite.
● Para modificar parámetros hay que programar los bloques manualmente
mediantes funciones en C e implementarlos a través de bloques de funciones S.
● El sistema parece quedarse colgado en la simulación a veces, pero no se cuelga
realmente.
● El transporte de la información depende de un protocolo de internet, con todas las
desventajas que esto conlleva: posibilidad de ataques, pérdida de los mensajes de
información.
90
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
8 FUTURAS MEJORAS (LÍNEAS DE INVESTIGACIÓN ).
En la parte de la actualización automática de bases de datos:
● Implementar un sistema inteligente de análisis de datos en páginas web para
complementar la información con texto disponible en la misma, basando el análisis
en etiquetas html o palabras claves.
● Eliminar la interacción del usuario con el sistema de actualización en la corrección
de errores tipográficos implementando un diccionario propio y un sistema de
corrección.
● En el caso de la subida de ficheros, analizar el contenido de los ficheros a subir
para asegurar al 100% la efectividad de la elección del fichero correcto.
● Hacer que el sistema cumpla con las exigencias de la W3C.
● Implementar un sistema de validación de usuario que utilice SSH (Secure SHell),
con la finalidad de mejorar la seguridad del sistema mediante técnicas de cifrado.
En la parte de control remoto:
● Situar los campos de texto justo en las salidas del bloque de la función S, para
que sea todavía más directa la asociación entre los campos de texto y las salidas del
bloque.
● Automatizar todavía más la aplicación de Matlab que genera los ficheros de
imagen y envía los ficheros a Servigar, para que compile directamente el modelo de
Simulink (en caso de que se vaya a usar el modo externo), lo ponga a ejecutar y se
quede a la espera de órdenes.
● Intentar implementar el envío/recepción de mensajes por tcp/ip en el mismo
Simulink (es bastante difícil, porque al intentar implementarlo Simulink se cuelga,
pero es posible definir un protocolo de envío para el modo externo compilando
librerías propias para las capas 1 y 2 del modelo OSI).
91
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Intentar la modificación de parámetros en el Workspace en tiempo real (difícil
porque las funciones creadas por MathWorks con esta finalidad implementan el
fichero de cabecera "mex.h", mientras que si la aplicación se ha de controlar en
tiempo real requiere de Real Time Workshop, y las librerías de este toolbox son
incompatibles con "mex.h".
● Implementar un sistema de validación de usuario que utilice SSH (Secure SHell),
con la finalidad de mejorar la seguridad del sistema mediante técnicas de cifrado.
● Robustecer el protocolo diseñado con códigos CRC de 16 ó 31 bits para
verificación de las transmisiones, a fin de desechar mensajes erróneos que puedan
llegar al servidor o al cliente.
● Implementar un sistema final de comprobación de que realmente se han
modificado los datos.
92
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
9 B IBLIOGRAFÍA .En la parte de control remoto se han utilizado los documentos publicados por The
MathWorks, empresa responsable de la creación del programa Matlab y la ingente ayuda del
paquete de programación Microsoft Visual .NET.
En la parte relativa al sistema de actualización de bases de datos, la documentación
utilizada fue:
CONVERSE, TIM; PARK, JOYCE; MORGAN, CLARK. PHP5 and MySQL Bible. Wiley
Publishing Inc., 2004. ISBN: 0-7645-5746-7.
DUBOIS, PAUL. MySQL The definitive guide to using, programming, and administering MySQL 4.1 and 5.0 3rd Edition. Sams, March 08, 2005. ISBN: 0-672-32673-
6.
GOURLEY, DAVID; TOTTY, BRIAN; SAYER, MARJORIE; REDDY, SAILU; AGGARWAL,
ANSHU. HTTP: The Definitive Guide. O'Reilly, September 2002. ISBN: 1-56592-509-2.
GREENSPAN, JAY; BULGER, BRAD. MySQL/PHP Database Applications. M&T
Books, 2001. ISBN: 0-7645-3537-4.
HUNGER, STEVE. Debian GNU/Linux Bible. Hungry Minds Inc., 2001. ISBN: 0-7645-
4710-0.
LAURI, BEN; LAURI, PETER. Apache The Definitive Guide, 3rd Edition. O'Reilly,
December 2002. ISBN: 0-596-00203-3.
NEGUS, CHRISTOPHER. Linux Bible 2005 Edition. Wiley Publishing Inc., 2005. ISBN:
0-7645-7949-5.
WONG, CLINTON. HTTP Pocket Reference, 1st Edition. O'Reilly, May 2000. ISBN: 1-
56592-862-8.
También se empleó el sitio web de la World Wide Web Consortium Schools, que legisla
todo lo referente a la web (HTML, XHTML, etc) para documentación:
http:// www.w3schools.com/
93
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
10 ANEXOS
10.1 CONTENIDOS DEL CD-ROM.El contenido del cd-rom adjunto se desglosa a continuación:
● Final: contiene los ejecutables principales (versiones finales compiladas) que se
han de emplear para poner en funcionamiento el sistema.
○ Control.Remoto: contiene los ejecutables correspondientes a la parte de
control remoto del proyecto.
○ SQL.Update: contiene los ficheros finales del sistema de actualización de
bases de datos.
■ Artículos.Nyquist: contiene una copia de la web empleada para tomar los
ficheros pdf del grupo de control predictivo.
■ Final.Site: contiene una copia del directorio completo de la página.
■ New.Files: nuevos ficheros creados para la actualización.
■ Old.Modified.Files: antiguos ficheros del sitio web que han sido
actualizados.
● Sources: contiene el código fuente de los programas desarrollados.
○ Control.Remoto: contiene el código fuente de los programas desarrollados
para la aplicación de control remoto.
■ Aplicacion.Matlab: código del programa “sendtoservigar.m”.
■ Cliente.Neoxite: código fuente del cliente ubicado en Neoxite empleado por
“sendtoservigar.m” para el envío remoto de ficheros.
■ Image.Magick: programa de software libre que contiene diversas utilidades
para el tratamiento de imágenes.
■ Interfaz.Web: código fuente de la interfaz web utilizada para el cambio de
los valores de los parámetros. También se incluye en un fichero comprimido
el proyecto del sitio web desarrollado para la red de excelencia Hycon con
motivo de los experimentos sobre la planta solar de los laboratorios de la
Universidad de Sevilla.
94
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
■ Servidor.Neoxite: código fuente del servidor ubicado en Neoxite, empleado
para la recepción de los nuevos valores de los parámetros modificados.
■ Servidor.Servigar: código fuente del servidor ubicado en Servigar,
empleado para la recepción de los ficheros de imagen y de modelo de
Simulink enviados por el cliente de Neoxite invocado por “sendtoservigar.m”.
■ Bloque.S-Function: código fuente del bloque de modificación remota de
parámetros.
■ Ejemplo.Controlador: controlador empleado en el ejemplo incluido en esta
memoria para el sistema de control remoto mediante Matlab y la interfaz web.
○ SQL.Update: código fuente del sistema de actualización de bases de datos.
■ Original.Site: copia de la página web del grupo de control predictivo.
■ Articulos.Nyquist: ficheros originales del sitio web utilizado para obtener los
documentos “.pdf” para actualizar la base de datos.
● Programas: contiene algunos los programas necesarios para el proyecto (que no
necesiten de licencia o sean software libre). En la mayoría de las carpetas se
incluyen ficheros de ayuda para aprender a manejarlos:
○ Control Remoto: programas utilizados en el sistema de control remoto.
■ Image-Magick: paquete de software libre con herramientas y utilidades
relacionadas con los formatos gráficos. Se utiliza para la conversión de
formatos.
○ SQL.Update: programas utilizados para la actualización de las bases de datos.
■ Apache.Server: servidor de páginas web Apache.
■ Compresores: algunos compresores para Linux.
■ Lectores.Ext2: permiten leer particiones de Linux desde sistemas
Windows.
■ MySQL: servidor de bases de datos SQL.
■ MySQL Administrator: gestor para mantenimiento de bases de datos
MySQL.
■ MySQL Control Center. Gestor para mantenimiento de bases de datos
MySQL.
95
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
■ PHP: lenguaje de programación de páginas web.
● PDF.Collection: colección de documentos “.pdf” necesarios para la actualización
de la base de datos del sitio web del grupo de control predictivo.
● Docs: ficheros de documentación empleados para el proyecto.
○ Control.Remoto: ficheros de documentación de la parte relativa al control
remoto vía web de procesos.
○ SQL.Update: ficheros de documentación de la parte relativa a la actualización
de bases de datos.
10.2 MANUAL DE USO : S ISTEMA DE ACTUALIZACIÓN DE B ASES DE DATOS .
10.2.1 INSTALACIÓN .Los archivos situados en el directorio “Final/SQL.Update/Final.Site” constituyen la
nueva versión del sitio web del grupo de control predictivo. Basta con sobreescribir la
carpeta que contiene el antiguo sitio mediante una transferencia ftp/telnet o similar.
Si se desea copiar únicamente los ficheros correspondientes al sistema, entonces
simplemente se han de copiar en el directorio del sitio web del grupo de control predictivo los
ficheros de la carpeta “Final/SQL.Update/New.Files”.
El directorio en que se encuentra el antiguo sitio web del grupo de control predictivo es
“/var/www/groupweb/”, en el servidor Nyquist.
10.2.2 USANDO EL S ISTEMA DE ACTUALIZACIÓN DE B ASES DE DATOS .La interfaz del sistema de actualización es bastante intuitiva. Para acceder al sistema
simplemente se ha de escribir la ruta en el navegador, empleando como fichero
“update.html”. Por ejemplo, si el root del servidor web es “/var/www/”, y el sitio web está en
la carpeta “/var/www/groupweb/”, y se ha realizado la instalación indicada en el punto 10.2.1,
entonces se debería escribir la ruta “http://nyquist.us.es/groupweb/update.html”.
En pantalla se mostrarán cuatro opciones:
● Actualizar base de datos.
96
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● Editar fichero de definición de publicaciones.
● Crear copia de seguridad de la base de datos.
● Restaurar copia de seguridad de la base de datos.
En todos y cada uno de los cuatro pasos el usuario ha de ingresar el nombre y la
contraseña para poder validarse. En caso de no hacerlo, no podrá acceder a ninguna de las
opciones presentadas.
10.2.2.1 ACTUALIZAR B ASE DE DATOS .En el primer paso de la actualización el usuario ha de seleccionar los ficheros de texto
que contengan las entradas a añadir a la base de datos, así como elegir la tabla de la base
de datos que actualizará dicho fichero. Los nombres de las tablas guardan relación directa
con el contenido de las mismas. Así, una tabla que almacena publicaciones en revistas se
llama “journals”, una que almacena ponencias en congresos se llama “congress”, etc.
Asimismo, se permite añadir direcciones web para buscar documentos en formato “.pdf”
con la finalidad de complementar las entradas de los ficheros de texto. Con esta misma
finalidad también se permite añadir rutas de directorios.
En el segundo paso el usuario debe indicar al sistema los campos de que constan las
entradas de los ficheros que indicó en el paso anterior, así como los separadores que se
utilizan para distinguir campos y entradas (tabuladores, retornos de carro, etc). Mención
especial tiene el campo “authors” o “supervisors”, que representan a los autores o
supervisores de una publicación. Para ellos también es necesario indicar al sistema el tipo
de separadores usados. Los más comunes para este caso son “;” o “,”.
Al final del documento se indica además si las direcciones y directorios facilitados en el
paso anterior son leíbles correctamente y se tiene acceso a ellos.
Hay que remarcar que los campos se han de indicar en el mismo orden con que
aparecen en los ficheros de texto, y de forma consecutiva. Caso aparte son los separadores,
que se muestran únicamente al final, ya que, al no existir como tales campos, entonces no
tienen necesidad de ir a continuación de los campos de los ficheros.
En el tercer paso se procede al análisis de los datos facilitados. El sistema mostrará un
breve mensaje por pantalla conforme vaya analizando entradas. Una vez finalice el análisis,
97
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
mostrará sendos campos de edición por cada entrada. Estos campos de edición se
corresopnden con la totalidad de campos disponibles para una publicación del tipo indicado,
mostrando el campo en blanco si no se incluía en los ficheros de texto iniciales.
En caso de que el sistema haya encontrado ficheros que se estimen coincidentes para la
publicación, los mostrará en pantalla. Si se trata de varios ficheros, entonces los desglosará
en una lista con botones tipo “radio” para que el usuario seleccione el correcto. Si el usuario
no desea especificar fichero pdf alguno, entonces basta con que marque la casilla “No
deseo especificar ningún fichero .pdf”.
También se muestran otras dos casillas de verificación que son excluyentes: una la
marcará el usuario cuando desee actualizar la base de datos con esa publicación (“Active
esta casilla si la entrada ya está completa”) y la otra la marcará cuando no desea incluirla en
la base de datos (“En caso de no querer añadir esta entrada, active esta casilla”).
Por supuesto, se permite al usuario cambiar el documento pdf en caso de que ninguno
de los encontrados sea correcto o en el caso de que no se haya encontrado ninguno.
Una vez el usuario haya realizado todas las modificaciones que desee, basta con que
pulse el botón “Volver al paso 3” para que el sistema proceda con las actualizaciones. Este
paso se volverá a mostrar tantas veces como sea necesario hasta que no queden entradas
que actualizar.
NOTA IMPORTANTE: se recomienda emplear ficheros de texto con no más de 25
entradas. Aunque se ha modificado el tiempo de carga de las páginas a 30 minutos, los
datos generados por los formularios son excesivos y pueden generar un colapso del hilo
servidor que sirve las páginas.
10.2.2.2 EDITAR FICHERO DE DEFINICIÓN DE PUBLICACIONES .Esta opción del sistema permite al usuario acceder al fichero de definición de
publicaciones. Este fichero es usado por el sistema para la generación de referencias y para
la búsqueda de los documentos pdf.
Con esta opción se presenta al usuario una caja de edición de texto con el contenido de
dicho fichero, para que lo modifique a su conveniencia.
El fichero guarda un formato muy estricto. Existen dos zonas bien diferenciadas: la zona
98
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
de publicaciones de revistas y la zona de ponencias en congresos. El comienzo de cada una
de las zonas se encuentra indicado con “::JOURNALS” y “::CONGRESS” respectivamente.
En cada zona, el usuario puede definir tantas publicaciones como desee.
Cada publicación requiere de dos líneas. La primera se utiliza para almacenar el nombre
completo de la publicación. Esta línea debe ir precedida de los caracteres de comentario “//”.
en la segunda línea el usuario debe introducir las siglas o el acrónimo de la publicación,
seguido de “;” y un tabulador, y a continuación debe escribir las palabras claves de la
publicación separadas por tabuladores (las palabras claves son aquellas que se utilizarán en
la búsqueda de documentos posteriormente y en la generación de referencias).
Una vez que se hayan realizado las modificaciones deseadas, basta con pulsar el botón
“Actualizar fichero de definiciones” y las modificaciones serán guardadas automáticamente.
10.2.2.3 CREAR COPIA DE S EGURIDAD DE LA B ASE DE DATOS .Esta opción crea automáticamente una copia de seguridad de la base de datos. Se
mostrará por pantalla un mensaje indicando la hora y la fecha en que se realizó la copia de
seguridad, así como el nombre del fichero que contiene la copia.
10.2.2.4 RESTAURAR COPIA DE S EGURIDAD DE LA B ASE DE DATOS .Aquí se presenta una tabla por pantalla que permite al usuario restaurar una copia de
seguridad creada previamente, así como borrarla. Para cada una de las copias de seguridad
se muestran la hora y la fecha de creación, a fin de que el usuario proceda con la que más
convenga.
La opción “Actualizar directorio de pdfs” hace que el sistema, al actualizar la base de
datos, borre todos los documentos pdf que no se correspondan con entradas existentes en
la base de datos. Esto se incluye para prevenir futuros errores en que se actualicen entradas
que no tengan ficheros pdf y al no haber borrado los de una copia anterior se muestre un
fichero erróneo.
En consecuencia, se recomienda restaurar una copia, y comprobar en el sitio web que se
ha restaurado la deseada. Si esto es así, entonces ya se puede proceder a restaurar esa
misma marcando la opción de actualización del directorio de pdfs. Además, también es
recomendable borrar las copias de seguridad con fecha y hora posterior a la restaurada, con
99
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
el fin de prevenir futuras complicaciones.
10.3 MANUAL DE USO : S ISTEMA DE CONTROL REMOTO.
10.3.1 INSTALACIÓN .La ubicación de cada uno de los programas es importante. Si no se tiene cuidado al
colocar los ejecutables se obtendrán errores adicionales. A continuación se especifica la
correcta ubicación de cada uno de ellos (NOTA: todos los ficheros aquí especificados se
encuentran en el directorio “Final” del CD-Rom que acompaña esta memoria):
● Aplicación de conversión de formato gráfico "convert.exe": debe encontrarse en el
mismo directorio que la aplicación de Matlab "sendtoservigar.m".
● Aplicación de Matlab: esta aplicación es un fichero con nombre
"sendtoservigar.m". Debe situarse en el directorio de trabajo donde se encuentre el
fichero de modelo de Simulink que contiene el controlador a implementar el control
remoto. La ejecución es muy simple. Basta con escribir "sendtoservigar" en la línea
de comandos de Matlab (con cuidado de estar situados en el mismo directorio en
que se encuentra "sendtoservigar.m"), y la secuencia a seguir una vez invocado el
script es la siguiente:
○ Inserción del nombre del fichero de modelo de Simulink (con o sin extensión
".mdl").
○ Esperar a la finalización del programa.
Durante el transcurso de la ejecución, la aplicación irá mostrando por pantalla los
distintos avances que irán sucediendo, como son la detección del fichero de
modelado, la obtención de su representación, la conversión del formato gráfico o el
envío sucesivo de los ficheros al servidor sito en Servigar.
● Interfaz web en Servigar: es la página web que contiene la interfaz de
modificación remota de los parámetros. El resultado de la compilación de esta página
ha de ubicarse en el directorio web en el que se proporcione el servicio de hosting
de páginas (depende del servidor web instalado, por ejemplo, Apache Server o
Internet Information Server, y de su configuración). En este punto hay que tener en
cuenta que la interfaz web se diseñó para su interfuncionamiento con el sitio web de
100
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
la Planta Solar encuadrada en el proyecto europeo Hycon. Este hecho indica que el
sistema de validación es el que usaba dicho sitio web. Si se desea utilizar en otro
ámbito, será necesario modificar la programación de dicha interfaz para adecuarla a
las nuevas condiciones de trabajo.
● Aplicación servidor en Servigar "cp_server_servigar.exe": debe ubicarse en la
misma carpeta que la página "tunning.aspx", que es la que implementa la interfaz
web para cambiar remotamente los parámetros. El funcionamiento de este servidor
es sencillo: una vez ejecutado, mostrará por pantalla un mensaje indicando que si se
escribe la palabra "exit" se detendrá la ejecución del mismo, dando a entender que
se ejecutará de forma indefinida si el usuario no escribe la orden correspondiente. El
servidor se quedará a la escucha de peticiones en el puerto designado y cuando
reciba alguna lo mostrará por pantalla.
● Aplicación cliente en Neoxite "cp_client_neoxite.exe": esta aplicación debe
ubicarse en la misma carpeta que el script de Matlab "sendtoservigar.exe", ya que
éste lo utiliza para el envío de ficheros al servidor ubicado en Servigar. En teoría el
usuario no necesita saber de la ejecución de este cliente, puesto que lo invoca la
misma aplicación "sendtoservigar.m".
● Aplicación servidor en Neoxite "cp_server_neoxite.exe": debe ubicarse en el
mismo directorio en que se esté ejecutando el fichero del modelo de Simulink, puesto
que en dicho directorio se creará el fichero “.log” que se utilizará para alterar los
valores de los parámetros. El funcionamiento de este servidor es, al igual que el
situado en Servigar, bastante sencillo: una vez ejecutado, mostrará por pantalla un
mensaje indicando que si se escribe la palabra "exit" se detendrá la ejecución del
mismo, dando a entender que se ejecutará de forma indefinida si el usuario no
escribe la orden correspondiente. El servidor se quedará a la escucha de peticiones
en el puerto designado y cuando reciba alguna lo mostrará por pantalla.
10.3.2 USANDO EL CONTROL REMOTO.1º) Se situarán los siguientes ficheros en el directorio “%MATLAB_PATH%/work/” en el
ordenador que implementará el controlador:
101
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
● convert.exe● cp_client_neoxite.exe● cp_server_neoxite.exe● tunning.c● tunning.txt● params.mdl● sendtoservigar.mEl fichero tunning.txt es un fichero de texto que contiene una lista de asignación de
valores a las variables cuyos valores se podrá cambiar, con las asignaciones separadas por
retornos de carro.
Se situarán los siguientes ficheros en el directorio “./Files/Simulink/” de la interfaz web
diseñada (en la ruta relativa al directorio en el que se encuentra el fichero de la interfaz) en
el ordenador que implementará la interfaz web:
● cp_server_servigar.exe
2º) Lo siguiente a realizar es la compilación del bloque de modificación remota de
parámetros. Desde la línea de comandos de Matlab se escribirá:
mex tunning.cA continuación se configurará el fichero de modelo de Simulink tal y como se describe en
el punto 3.2.3.1. Una vez hecho esto, ya nos encontramos en condiciones de generar el
ejecutable. Para hacer esto, presionamos sobre el botón “Build All” de la ventana de
Simulink. Una vez terminada la compilación se habrá generado una carpeta
“params_grt_rtw” que contendrá todo el código fuente del ejecutable generado, mientras que
el ejecutable se encontrará en la misma carpeta que el modelo de Simulink.
3º) Antes de proceder a la ejecución del modelo, se han de “arrancar” los distintos
servidores que deben quedarse a la espera de peticiones en los puertos. Por tanto, en este
paso se ejecutan los ejecutables “cp_server_neoxite.exe” y “cp_server_servigar.exe” en los
ordenadores que implementan el control con Matlab (en adelante, “servidor matlab”) y la
interfaz web (en adelante, “servidor web”) respectivamente.
4º) El operario encargado de ejecutar el controlador pondrá en marcha el sistema,
invocando "sendtoservigar.m" desde la línea de comandos de Matlab. Esta aplicación se
comunicará con el servidor web y llevará a cabo la puesta a punto del sistema. Una vez
configurado el sistema, el operario ejecutará el controlador del usuario, no sin antes haber
arrancado el ejecutable servidor del modo externo generado en el paso 2. Para ello, el
operario abrirá una ventana de comandos de Windows (una consola) en el servidor Matlab,
se desplazará al directorio donde se encuentra dicho ejecutable para el modo externo y una
vez ubicado en dicha carpeta ejecutará el siguiente comando:
102
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
params -tf inf -wLa opción “-tf” establece el tiempo final de la ejecución en tiempo real. Con “inf” se
indica que se desea que el tiempo de ejecución sea infinito. La opción “-w” se utiliza para
esperar el mensaje de bienvenida del host, esto es, que no se empieza a ejecutar hasta que
un cliente se conecta con el fichero del modo externo.
Lo siguiente será, como ya se dijo anteriormente, ejecutar el controlador del usuario.
Para ello, se abre el modelo del controlador en Simulink, se escoge el modo externo en la
lista desplegable superior y se presiona sobre el botón que hay justamente a la izquierda de
la lista, que muestra como ayuda emergente al posar el ratón sobre él “Connect to target”.
Esto conectará el modelo con el ejecutable que se ha arrancado antes. Una vez conectado,
ya solamente resta pulsar en el botón “Start real-time code”, situado a la izquierda del
anterior.
En caso de que el usuario desee modificar algún valor en el bloque de modificación de
parámetros, debe validarse en la interfaz web, tras lo cual tendrá acceso a la interfaz y verá
los valores actuales de los parámetros de su controlador, modifcando aquellos que no le
plazcan. En este momento, tras pulsar el botón de actualizar dichos valores, la interfaz web
se comunicará con el servidor Matlab para modificar el fichero de intercambio de datos, de
forma que el bloque de modificación de parámetros pueda actualizar los nuevos valores.
10.4 CÓDIGO FUENTE.
10.4.1 S ISTEMA DE ACTUALIZACIÓN DE B ASES DE DATOS .
10.4.1.1 UPDATE.HTML
<html><head>
<script type="text/javascript">function assign(){
document.getElementById("login").value = document.getElementById("user").value;
document.getElementById("pass").value =document.getElementById("password").value;
}function assign_pubs(){
document.getElementById("login_pubs").value =
103
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
document.getElementById("user").value;document.getElementById("pass_pubs").value =
document.getElementById("password").value;}
</script></head><body>
<table align=center><form name="validacion" action="paso1.php" method="post"><tr>
<td colspan=2 align="center"> <img src="images/backup.jpg"> </td></tr><tr>
<td colspan=2> <br> </br> </td></tr><tr>
<td width="50%" align=right>Login:     </td><td width="50%"><input type="text" id="user" name="user"></td>
</tr><tr>
<td width="50%" align=right>Contraseña:     </td><td width="50%">
<input type="password" id="password" name="password"></td>
</tr><tr>
<td colspan="2" align="center"><input type="submit" id="update" name="update"
value="Actualizar base de datos"></td>
</tr></form><form name="edit_pubs" action="pubs_editor.php" method="post"><tr>
<td colspan=2 align="center"><input type="submit" id="edit_pub_file" name="edit_pub_file"
value="Editar fichero de definición de publicaciones"onclick="assign_pubs();" />
<input type="hidden" id="login_pubs" name="login" value="" /><input type="hidden" id="pass_pubs" name="pass" value="" />
</td></tr></form><form name="validacion" action="backup.php" method="post"><tr>
<td colspan=2 align="center"><input type="submit" id="create_backup" name="create_backup"
value="Crear copia de seguridad de la base de datos"onclick="assign();" />
</td></tr><tr>
<td colspan=2 align="center"><input type="submit" id="restore_backup" name="restore_backup"
value="Restaurar copia de seguridad de la base de datos"onclick="assign();" />
<input type="hidden" id="login" name="login" value="" /><input type="hidden" id="pass" name="pass" value="" />
</td></tr></form><tr>
<td colspan=2> <br> </br> </td></tr>
104
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
<tr><td colspan=2 align="center">
<img src="images/php_icon.png"> </img><img src="images/mysql_icon.gif"> </img><img src="images/apache_icon.gif" height="52"> </img>
</td></tr>
</table>
</body></html>
10.4.1.2 PASO 1.PHP
<?phpinclude "functions.inc.php";$conexion_mysql =& conecta_db(); // Conexión con la base de datos
if (valida_usuario($_POST["user"], $_POST["password"])) {// Inicio de sesión y envío de los datos del usuario para validar en los// subsiguientes pasossession_start();$_SESSION["user"] = $_POST["user"];$_SESSION["password"] = $_POST["password"];
// Mensaje de bienvenidaprint "\t<h2>Actualización automática de la Base de Datos</h2><br />" .
"Hola, usuario \"" . $_POST["user"] . "\".<br />" ."Bienvenido al script de actualización automática de la base de datos " ."del sitio web del Grupo de Control Predictivo.<br /><br />\n\t<h3>" ."Paso 1: Introducción de los ficheros de actualización y selección " ."de las bases de datos a actualizar:</h3><br />";
$tablas_db = lista_tablas();info_campos($tablas_db, $tipo_campos_tablas, $nombre_campos_tablas);
// Impresión del formulario de alta de ficheros y selección de tablas en el// navegadorecho "\t<form name='upload' id='upload' action='paso2.php' " .
"ENCTYPE='multipart/form-data' method='POST'>\n";echo "\t\t<table border='0'>\n";$max_campos = 0;for ($i=0;$i<count($tablas_db);$i++)
if ($max_campos < count($nombre_campos_tablas[$i]))$max_campos = count($nombre_campos_tablas[$i]);
// Se imprime una fila de la tabla por cada tabla existente en la base de// datos.echo "\t\t\t<tr>\n";echo "\t\t\t\t<td width='620px' align=center>Seleccione aquí los ficheros " .
"que contengan las actualizaciones:</td>\n";echo "\t\t\t\t<td width='100px'>Tabla a actualizar:</td>\n";echo "\t\t\t</tr>\n";for ($i=0;$i<count($tablas_db);$i++) {
// Nueva filaecho "\t\t\t<tr>\n";// 1ª columna => Campo de texto para escribir el nombre del fichero con las// actualizaciones.echo "\t\t\t\t<td width='620px'>\n";echo "\t\t\t\t\t<input type='file' id='fichero" . $i .
"' name='fichero" . $i . "' size=80 />\n";echo "\t\t\t\t</td>\n";// 2ª columna => Lista desplegable para seleccionar la base de datos que se// actualizará.
105
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t\t<td>\n";echo "\t\t\t\t\t<select name='tabla" . $i . "'>\n";echo "\t\t\t\t\t\t<option value=''></option>\n";for ($k=0;$k<count($tablas_db);$k++)
echo "\t\t\t\t\t\t<option value='" . $tablas_db[$k] . "'>". $tablas_db[$k] . "</option>\n";
echo "\t\t\t\t\t</select>\n";echo "\t\t\t\t</td>\n";// 3ª columna => Lista desplegable para seleccionar el tipo de libro en caso// de tener que modificarse la tabla "books".echo "\t\t\t</tr>\n";
}// Campo de texto para las urlsecho "\t\t\t<tr><td align=center colspan='" . $max_campos . "'><br>" .
"Inserte aquí las direcciones webs desde las que se pueden actualizar " ."los campos:<br>(NOTA: Separe las rutas mediante retornos de carro)" ."<textarea name=webs id=webs rows=10 cols=86></textarea></td></tr>\n";
// Campo de texto para los directoriosecho "\t\t\t<tr><td align=center colspan='" . $max_campos . "'><br>" .
"Inserte aquí los directorios que contengan ficheros .pdf para insertar " ."en la base de datos:<br>(NOTA: Separe las rutas mediante retornos " ."de carro)<textarea name=dirs id=dirs rows=10 cols=86></textarea>" ."</td></tr>\n";
echo "\t\t\t<tr><td colspan='" . $max_campos . "'>(NOTA: Se buscarán " ."ficheros que contengan en su nombre las tres partes clave de la " ."referencia de la base de datos, esto es, el apellido del autor " ."principal, las siglas de la publicación y el título del " ."artículo/congreso).</td></tr>\n";
echo "\t\t</table>\n";echo "\t\t<input type=submit value='Ir al paso 2' />\n";echo "\t</form>\n";desconecta_db($conexion_mysql);
}else {
echo "Error en el nombre de usuario o en la contraseña.<br />Por favor, " ."vuelva a la pantalla de validación.<br />";
echo "<a href=\"./update.html\">Página de validación</a>";}
?>
10.4.1.3 PASO 2.PHP
<?phpinclude "functions.inc.php";session_start();error_reporting(0); // No se reporta ningún tipo de error$conexion_mysql =& conecta_db(); // Conexión con la base de datos
// Validación del usuarioif (valida_usuario($_SESSION["user"], $_SESSION["password"])) {
// Tamaño, tipo y extensión permitidos para los ficheros a subir//*******************************************************$MAX_SIZE = 2000000;$FILE_MIMES = array('text/plain');$FILE_EXTS = array('.txt');
// Variables de configuración//*******************************************************$site_name = $_SERVER['HTTP_HOST'];$url_dir = "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);$url_this = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];$upload_dir = "temp/";
106
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$upload_url = $url_dir."/temp/";$message = "";
// Obtención de las variables necesarias de la base de datos$tablas_db = lista_tablas();info_campos($tablas_db, $tipo_campos_tablas, $nombre_campos_tablas);$max_campos = 0;$max_adds = 0;
for ($i=0;$i<count($tablas_db);$i++){
$num_campos_tabla = 0;$encontrada = false;for ($j=0; $j<count($tablas_db); $j++){
if ($tablas_db[$j] == $_POST["tabla".$i]){
$encontrada = true;$cont = $j;
}}if ($encontrada == true){
$num_campos_tabla = count($nombre_campos_tablas[$cont]);$num_campos_adds = 0;for ($j=0; $j<count($tabla_campos_adicionales); $j++)
if (($tabla_campos_adicionales[$j] == $tablas_db[$cont]) ||($tabla_campos_adicionales[$j] == "all"))
$num_campos_adds++;if ($max_campos < $num_campos_tabla + $num_campos_adds)
$max_campos = $num_campos_tabla + $num_campos_adds;}
}
// Directorio temporal de subida para la copia localif (!is_dir("temp")) {
if (!mkdir($upload_dir))die ("Directorio de subida no existe y su creación falló");
if (!chmod($upload_dir,0755))die ("Cambio de permisos a 755 fallido.");
}
// Vaciado del directorio temporalborra_dir_temp($upload_dir);// Copia local de los ficheros de actualización en el directorio TEMPfor ($i=0;$i<count($tablas_db);$i++) {
if ($_FILES["fichero" . $i]) {$file_type = $_FILES["fichero" . $i]["type"];$file_name = $_FILES["fichero" . $i]["name"];$file_ext = strtolower(substr($file_name,strrpos($file_name,".")));//Comprobación del tamaño del ficheroif ( $_FILES["fichero" . $i]["size"] > $MAX_SIZE)
$message = "Los ficheros deben tener un tamaño máximo de 2MB.";//Comprobación del tipo y extensión del ficheroelse if (!in_array($file_type, $FILE_MIMES) &&
!in_array($file_ext, $FILE_EXTS) )$message = "Lo sentimos mucho, no se permite subir " .
$file_name . "(" . $file_type . ").";else
$message = do_upload("fichero".$i, $upload_dir, $upload_url);}else if (!$_FILES["fichero" . $i])
$message = "Fichero especificado no válido.";}
107
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Mensaje de bienvenidaprint "<html>\n";print "\t<head>\n";print "\t</head>\n";print "\t<body>\n";print "\t\t<h2>Actualización automática de la Base de Datos</h2><br />" .
"\n\t\t<h3>Paso 2: Selección de los campos que aparecen en los ficheros " ."de actualización.</h3><br />\n\t\tA continuación se muestran, separados " ."mediante barras horizontales, los ficheros indicados en el paso 1, así " ."como las tablas asociadas seleccionadas. En este paso el usuario deberá " ."seleccionar los campos que se detallan en el fichero de actualización, y" ." en el mismo orden en que éstos aparecen.<br />\n\t\tPor último, se " ."seleccionará el tipo de documento (en caso de que la tabla a modificar " ."sea \"books\"), indicando si se trata de un libro normal o un libro de " ."actas, así como los separadores de campos y de filas empleados en el " ."fichero.<br /><br />\n";
// Impresión del formulario de selección de campos del fichero de// actualización//********************************************************************echo "\t\t<form name='upload' id='upload' action='paso3.php' " .
"ENCTYPE='multipart/form-data' method='POST'>\n";// Ahora se muestran los conjuntos de listas desplegables para seleccionar los// campos que contienen los ficheros subidos al servidorecho "\t\t\t<table width=100%>\n";for ($i=0;$i<count($tablas_db);$i++) {
$num_campos_adicionales = 0;$num_campos_undef = 0;// Una nueva fila por cada fichero introducido y tabla seleccionadaif (($_FILES["fichero".$i]["name"] != "") && ($_POST["tabla".$i] != "")) {
echo "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $max_campos .">Fichero \"" . $_FILES["fichero" . $i]["name"] ."\" => Tabla \"" . $_POST["tabla" . $i] . "\"</td>\n";
// Se imprimen los campos adicionales que correspondanfor ($j=0; $j<count($lista_campos_adicionales); $j++)
if (($tabla_campos_adicionales[$j] == "all") ||($tabla_campos_adicionales[$j] == $_POST["tabla".$i]))
$num_campos_adicionales++;// Se imprimen los separadores que correspondanfor ($j=0; $j<count($lista_campos_undef); $j++){
if (($tabla_campos_undef[$j] == "all") ||($tabla_campos_undef[$j] == $_POST["tabla".$i]))
{echo "\t\t\t\t\t<td>" . ucwords($lista_campos_undef[$j]) .
"</td>\n";$num_campos_undef++;
}}echo "\t\t\t\t</tr>\n";echo "\t\t\t\t<tr>\n";$indice_tabla = 0;for ($j=0;$j<count($tablas_db);$j++)
if ($tablas_db[$j] == $_POST["tabla" . $i])$indice_tabla = $j;
// Numero de campos de esta tabla (no se cuenta el id)$n_campos = count($nombre_campos_tablas[$indice_tabla]) – 1;// Numero de campos adicionales de esta tabla$n_adds = 0;for ($j=0; $j<count($tabla_campos_adicionales); $j++)
if (($tabla_campos_adicionales[$j] == $tablas_db[$indice_tabla]) ||($tabla_campos_adicionales[$j] == "all"))
$n_adds++;for ($j=0; $j<$max_campos; $j++) {
// Se añaden los elementos de la tabla en cuestión (inclusive los
108
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// adicionales)if ($j < $n_campos + $n_adds){
echo "\t\t\t\t\t<td>\n";echo "\t\t\t\t\t\t<select name='campo" . $i . "-" . $j . "'>\n";echo "\t\t\t\t\t\t\t<option value=''></option>\n";for ($k=1;$k<=(count($nombre_campos_tablas[$indice_tabla]));$k++) {
if ($k < count($nombre_campos_tablas[$indice_tabla]))echo "\t\t\t\t\t\t\t<option value='"
. $nombre_campos_tablas[$indice_tabla][$k] . "'>"
. $nombre_campos_tablas[$indice_tabla][$k] . "</option>\n";else
for ($m=0; $m<count($lista_campos_adicionales); $m++)if (($tabla_campos_adicionales[$m] == "all") ||
($tabla_campos_adicionales[$m] == $_POST["tabla".$i])){
echo "\t\t\t\t\t\t\t<option value='". $var_campos_adicionales[$m]. "'>" . $var_campos_adicionales[$m]. "</option>\n";
}}echo "\t\t\t\t\t\t</select>\n";echo "\t\t\t\t\t</td>\n";
}// Se añaden las celdas vacías que resten hasta el número máximo de// camposelse
echo "\t\t\t\t\t<td>\n\t\t\t\t\t</td>\n";}// Se muestran los campos interactivos que correspondanfor ($j=0; $j<count($lista_campos_undef); $j++){
if (($tabla_campos_undef[$j] == "all") ||($tabla_campos_undef[$j] == $_POST["tabla".$i]))
{echo "\t\t\t\t\t<td>\n";echo "\t\t\t\t\t\t<select name='" . $var_campos_undef[$j]
. $i . "'>\n";echo "\t\t\t\t\t\t\t<option value=''></option>\n";for ($k=0; $k<count($desc_campos_undef[$lista_campos_undef[$j]]);
$k++)echo "\t\t\t\t\t\t\t<option value='" .
$valores_campos_undef[$lista_campos_undef[$j]][$k]. "'>" . $desc_campos_undef[$lista_campos_undef[$j]][$k]. "</option>\n";
echo "\t\t\t\t\t\t</select>\n";echo "\t\t\t\t\t</td>\n";
}}
// Línea horizontal para separar los distintos ficheros de actualizaciónecho "\t\t\t\t</tr>\n";$longitud = $max_campos+4;for ($k=0;$k<count($tablas_db);$k++)
if ($_POST["tabla".$k] == "books")$longitud++;
echo "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $longitud ."><hr /></td>\n";
echo "\t\t\t\t</tr>\n";}
}// Se muestran las direcciones que se insertaron en el paso previo (se// comprueba que son direcciones válidas, esto es, que direccionen a un// documento html, php, ..., pero no un nombre de dominio, y que éstas existan// y se puedan leer)
109
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $longitud . ">\n";echo "\t\t\t\t\t\tDirecciones que se utilizarán para actualizar la base de " .
"datos:\n";$tok = strtok($_POST["webs"], "\n");$i = 0;echo "\t\t\t\t\t\t<ul>\n";$exts = array(".html", ".htm", ".php", ".asp", ".aspx");while ($tok !== false) {
// Comprobaciones previas$error = "";$address = trim($tok);$pos_site = strlen($address);$pos_barra = strrpos(substr($address, 0, $pos_site), "/");// Caso en que la dirección termina en barra invertida => ERRORif ($pos_barra == $pos_site)
$error = "La dirección debe apuntar a un documento, no un directorio " ."o nombre de dominio.";
else {$last_part = substr($address, $pos_barra + 1);$found = false;// Se busca una de las terminaciones permitidasfor ($j=0; $j<count($exts); $j++)
if (strpos($last_part, $exts[$j]) !== false)$found = true;
// Si la dirección no apunta a un documento con extensión permitidaif ($found == false)
$error = "La dirección debe apuntar a un documento, no un " ."directorio o nombre de dominio.";
else {$desc_read = fopen($address, "rb");if ($desc_read == FALSE)
$error = "La dirección indicada no existe o no se puede acceder " ."a ella.";
}}// En caso de error se muestra un mensaje en pantalla pero no se envía como// campo oculto la dirección facilitadaif ($error != "")
// En caso de éxito, se muestra la dirección por pantalla y se envía como// campo ocultoecho "\t\t\t\t\t\t\t<li>" . $address . "\n\t\t\t\t\t\t\t\t"
"<ul>\n\t\t\t\t\t\t\t\t\t<li>Error: ".$error."\n\t\t\t\t\t\t\t\t\t" ."</li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</li>\n";
else {echo "\t\t\t\t\t\t\t<li>" . $address . "</li>\n";echo "\t\t\t\t\t\t\t<input type=hidden name='url" . $i . "' value='" .
$address . "' />\n";$i++;
}$tok = strtok("\n");
}echo "\t\t\t\t\t\t</ul>\n";echo "\t\t\t\t\t\tNOTA: Las páginas que hayan generado errores no se " .
"tendrán en cuenta para la actualización. Si desea que se tengan en " ."cuenta, vuelva al paso anterior y solucione los problemas que " ."puedan existir.\n";
echo "\t\t\t\t\t</td>\n";echo "\t\t\t\t</tr>\n";echo "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $longitud . "><hr /></td>\n";// Se muestran los directorios insertados en el paso previoecho "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $longitud . ">\n";echo "\t\t\t\t\t\tDirectorios que se utilizarán para actualizar la base de" .
"datos:\n";$tok = strtok($_POST["dirs"], "\n");$i = 0;
110
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t\t\t\t<ul>\n";while ($tok !== false) {
$directory = trim($tok);if (is_dir($directory) == false)
echo "\t\t\t\t\t\t\t<li>" . stripslashes($directory) ."\n\t\t\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t\t\t<li>Error: El " ."directorio no existe o no se puede acceder a él.\n\t\t\t\t\t\t\t\t\t" . "</li>\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t</li>\n";
else {echo "\t\t\t\t\t\t\t<input type=hidden name='dir" . $i . "' value='" .
stripslashes($directory) . "' />\n";echo "\t\t\t\t\t\t\t<li>" . stripslashes($directory) . "</li>\n";$i++;
}$tok = strtok("\n");
}echo "\t\t\t\t\t\t</ul>\n";echo "\t\t\t\t\t\tNOTA: Los directorios que hayan generado errores no se
" tendrán cuenta para la actualización. Si desea que se tengan en cuenta," ." vuelva al paso anterior y solucione los problemas que puedan existir.\n";
echo "\t\t\t\t\t</td>\n";echo "\t\t\t\t</tr>\n";echo "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=" . $longitud . "><hr /></td>\n";echo "\t\t\t\t</tr>\n";echo "\t\t\t</table>\n";echo "\t\t\t<br />\n";// Insertamos el conjunto de parámetros ocultos, a saber, los nombres de las// tablas a actualizar y ficheros a utilizarfor ($i=0;$i<count($tablas_db);$i++) {
if (($_FILES["fichero".$i]["name"] != "") && ($_POST["tabla".$i] != "")) {echo "\t\t\t<input type=hidden name='tabla" . $i . "' value='" .
$_POST["tabla".$i] . "' />\n";echo "\t\t\t<input type=hidden name='fichero" . $i . "' value='" .
$_FILES["fichero".$i]["name"] . "' />\n";}
}echo "\t\t\t<input type=submit value='Ir al paso 3' />\n";echo "\t\t\t \n";echo "\t\t\t<a href=\"/groupweb/help.html\" target=\"popup\" " .
"onClick=\"window.open('/groupweb/help.html', 'window', " ."'width=600,height=400,resizable=1,scrollbars=1'); return " ."false;\">Ayuda</a>\n";
echo "\t\t</form>\n";echo "\t</body>\n";echo "</html>\n";desconecta_db($conexion_mysql);
}else {
echo "Error en el nombre de usuario o en la contraseña.<br />Por favor, " ."vuelva a la pantalla de validación.<br />";
echo "<a href=\"./update.html\">Página de validación</a>";}
?>
10.4.1.4 PASO 3.PHP
<?phpinclude "functions.inc.php";include "functions.step3.php";session_start();$conexion_mysql =& conecta_db(); // Conexión con la base de datosunset($sentencias_SQL);
111
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
unset($sentencia_SQL);unset($congresos);unset($revistas);unset($table_type);unset($titulo);unset($ind_sql);unset($referencia);// Cambiamos el tiempo máximo de respuesta, porque esto tarda bastanteini_set("max_execution_time", "1800");// No se reporta ningún tipo de errorerror_reporting(0);
// Validación del usuarioif (valida_usuario($_SESSION["user"], $_SESSION["password"])) {
// Declaración y definición de variables$pubs_file = "pubs.txt";$log_file = "pdf_log.txt";$campo_def_add = array(
"tabla" => 0, // Tabla que actualizará esta entrada"error" => 1,"pdf" => 2, // Dirección web del fichero pdf
// [0] => direccion// [1] => porcentaje
"finished" => 3, // Bandera para saber si se ha terminado esta entrada"authors" => 4,"sep_authors" => 5, // Separador para los autores"supervisors" => 6, // Supervisores"sep_supervisors" => 7); // Separador de los supervisores
$def_offset = count($campo_def_add);// Array con los mensajes de error que se contemplan$mensajes_error = array(
"congreso" => "No se ha podido completar el campo \"reference\" debido a " ."que se desconoce el congreso.",
"revista" => "No se ha podido completar el campo \"reference\" debido a " ."que se desconoce la revista.",
"fecha" => "Es obligatorio especificar al menos los campos \"authors\", " ."\"title\", el nombre de publicación/congreso y la fecha de " ."publicación. No se ha especificado la fecha de publicación, por lo " ."que no se puede generar el campo \"reference\".",
"autores" => "Es obligatorio especificar al menos los campos \"authors\"" .", \"title\", el nombre de publicación/congreso y la fecha de "."publicación. No se han especificado los autores, por lo que no se " ."puede generar el campo \"reference\".",
"titulo" => "Es obligatorio especificar al menos los campos \"authors\", " ."\"title\", el nombre de publicación/congreso y la fecha de " ."publicación. No se ha especificado el título de la publicación.");
// Array de números romanos para los títulos de artículos y ponencias, para// ponerlos todos en mayúsculas$numbers = array("I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X",
"XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX","XXI", "XXII", "XXIII", "XXIV", "XXV", "XXVI", "XXVII", "XXVIII", "XXIX","XXX", "XXXI", "XXXII", "XXXIII", "XXXIV", "XXXV", "XXXVI", "XXXVII","XXXVIII", "XXXIX", "XL", "XLI", "XLII", "XLIII", "XLIV", "XLV", "XLVI","XLVII", "XLVIII", "XLIX", "L");
$letra = array("b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m","n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");
// Array de acrónimos y siglas que deben ir en mayúsculas$mayusc = array("IEEE", "CD", "HTTP", "OPC", "ROM");// Array asociativo del tipo de publicación con el entero que le corresponde$tipo_publicacion = array(
"congress" => 1,"journals" => 2,"pfcs" => 3,"phds" => 4,"books" => 5);
112
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$ind_sql = 0;$temp_dir = "temp/";$catalogo_sep = array("\n","\r","\r\n","\t",";",":",",",".");
//Comprobación de la variable "FORMULARIO". Si ésta se encuentra definida,//quiere decir que se está redireccionando a esta página desde ella misma para//actualizar el fichero de las publicaciones conocidas. Esta modificación ha//de hacerse antes que cualquier consulta al mismo.$formulario = 0;if (isset($_POST["formulario"]))
$formulario = $_POST["formulario"];else
$formulario = 0;
// Recuperación de información de la base de datos.$conexion_mysql = conecta_db();$tablas_db = lista_tablas();info_campos($tablas_db, $tipo_campos_tablas, $nombre_campos_tablas);info_campos_asoc($tablas_db, $tipo_campos, $campos_tablas);
// Inserción de los campos especificados en $lista_campos_undef en arrays con// nombres especificados en $var_campos_undef //**************************************************************************$max_campos = 0; // Número máximo de camposfor ($i=0;$i<count($tablas_db);$i++)
if ($max_campos < count($nombre_campos_tablas[$i]))$max_campos = count($nombre_campos_tablas[$i]);
for ($i=0;$i<count($tablas_db);$i++){
for ($k=0; $k<count($var_campos_undef); $k++){
$var_name = $var_campos_undef[$k];$$var_name = array();
}}
// Extracción de los campos que se han de actualizar,// los separadores e información diversa$indice_tablas = 0; // Índice para recorrer todas las tablas de
// la base de datos$campos_update[0][0] = "";for ($i=0; $i<count($tablas_db); $i++) {
if (isset($_POST["tabla" . $i]) && isset($_POST["fichero" . $i]) &&($_POST["tabla" . $i] != "") && ($_POST["fichero" . $i] != ""))
{$nombre_tablas[$indice_tablas] = $_POST["tabla" . $i];$nombre_ficheros[$indice_tablas] = $_POST["fichero" . $i];if (($_POST["tabla" . $i] != "sent") &&
($_POST["tabla" . $i] != "authors") &&($_POST["tabla" . $i] != "people"))
{$dependencias[$indice_tablas] = "authors";
}// Los separadores necesitan un procesado especial, y en realidad se pasa// el índice de una tabla en la que buscar el separadorfor ($k=0; $k<count($var_campos_undef); $k++)
array_push($$var_campos_undef[$k],$catalogo_sep[$_POST[$var_campos_undef[$k] . $i]]);
for ($j=0; $j<$max_campos; $j++) {if ($_POST["campo" . $i . "-" . $j] != "") {
$campos_update[$indice_tablas][$j] =$_POST["campo" . $i . "-" . $j];
}}
113
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$indice_tablas++;}
}// ACTUALIZACIÓN DEL FICHERO DE PUBLICACIONES EN CASO DE REDIRECCIONAMIENTO DE // LA PÁGINA//****************************************************************************if (isset($_POST["errores"]))
// Obtención del número de publicaciones desconocidas$n_unknown = $_POST["errores"];
else$n_unknown = 0;
$added_entries = 0;$mod_entries = 0;$processed = 0;$new_pubs[$added_entries]["tabla_modif"] = "";$pubs_mod[0] = "";if ($formulario == 1) {
// Editamos el fichero "pubs.txt" para añadir las revistas ingresadas$j = 0;unset($parte_nueva);while ($processed < $n_unknown) {
$tabla_actual = $_POST["tabla_modif" . $j];// Si los parámetros son correctos.... (esto es,// que no hayan dejado ninguno de los campos vacíos)if (isset($_POST["comment" . $j])){
if (($_POST["comment" . $j] != "") &&($_POST["abbrev" . $j] != "") &&($_POST["keywords" . $j] != ""))
{// Se almacenan los datos necesarios para actualizar// otra publicación cualquiera con el mismo error$new_pubs[$added_entries]["tabla_modif"] =
$_POST["tabla_modif" . $j];$indice = 0;if ($tabla_actual == "journals")
for ($l=0; $l<count($campos_tablas[$tabla_actual]); $l++)if ($campos_tablas[$tabla_actual][$l] == "journal")
$indice = $l;else if ($tabla_actual == "congress") {
for ($l=0; $l<count($campos_tablas[$tabla_actual]); $l++)if ($campos_tablas[$tabla_actual][$l] == "booktitle")
$indice = $l;}$new_pubs[$added_entries]["nombre"] =
$_POST["campos_def" . $j . "-" . ($indice + $def_offset)];$new_pubs[$added_entries]["abbrev"] = $_POST["abbrev" . $j];// Obtenemos los parámetros de la nueva publicación$comentario = $_POST["comment" . $j];$siglas = $_POST["abbrev" . $j];$claves = $_POST["keywords" . $j];// ....se procede a realizar una copia del// contenido del fichero de publicaciones$archivo = fopen("pubs.txt", "r+t");$contenido = fread($archivo, filesize("pubs.txt"));fclose($archivo);// Entrada a buscar en el contenido$cadena = "::".strtoupper($_POST["tabla_modif".$j]);// En caso de que se encuentre la entrada de// inserción, se procede a crear la cadena a insertarif (stripos(" ".$contenido, $cadena)) {
// Separamos las palabras claves mediante tabuladores$palabra = quita_tildes(trim(strtolower(strtok($claves, " "))));$k = -1;unset($claves_separadas);
114
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
while ($palabra != FALSE) {$k++;$claves_separadas = $claves_separadas . "\t" . $palabra;$palabra = strtok(" ");
}// PARTE_NUEVA es la cadena referente a la nueva publicación$parte_nueva = "\n// " . $comentario . "\n" . strtoupper($siglas)
. ";" . $claves_separadas . "\n";// Actualizamos el contenido total del fichero$contenido = substr($contenido, 0, stripos(" " .
$contenido, $cadena) -1 + strlen($cadena)) . $parte_nueva .substr($contenido, stripos(" " .$contenido, $cadena) + strlen($cadena));
//Insertamos el nuevo contenido en el fichero de las//publicaciones$archivo = fopen("pubs.txt", "w+t");fwrite($archivo, $contenido);fclose($archivo);// Actualizamos la referencia de la publicación$added_entries++;$_POST["campos_def" . $j . "-" . $campo_def_add["error"]] = "";$k = 0;while ($campos_tablas[$tabla_actual][$k] != "reference")
$k++;$l = 0;while(!ctype_digit($_POST["campos_def" . $j .
"-" . ($k+$def_offset)][$l])){
$l++;}$cad = "campos_def" . $j . "-" . ($k+$def_offset);$_POST[$cad] = substr($_POST[$cad], 0, $l) .
strtoupper($siglas) . substr($_POST[$cad], $l);$_POST["field" . $j . "-" . ($k+$def_offset)] =
$_POST[$cad];$pubs_mod[$mod_entries++] = $j;
}}else {
// Se busca el índice para extraer// el nombre de la publicación$indice = 0;if ($tabla_actual == "journals") {
for ($l=0;$l<count($campos_tablas[$tabla_actual]);$l++)if ($campos_tablas[$tabla_actual][$l] == "journal")
$indice = $l;}else if ($tabla_actual == "congress") {
for ($l=0;$l<count($campos_tablas[$tabla_actual]);$l++)if ($campos_tablas[$tabla_actual][$l] == "congress")
$indice = $l;}$nombre = $_POST["campos_def" . $j . "-" .
($indice + $def_offset)];$changed = false;// Se busca una publicación que tenga el mismo// nombre y que modifique la misma tabla siempre// y cuando no se haya modificado antes la referenciafor ($n=0; $n<count($new_pubs); $n++) {
if (($tabla_actual == $new_pubs[$n]["tabla_modif"]) &&($nombre == $new_pubs[$n]["nombre"]) &&($changed == false))
{$_POST["campos_def" . $j . "-" .
$campo_def_add["error"]] = "";
115
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$k = 0;while ($campos_tablas[$tabla_actual][$k] != "reference")
$k++;$l = 0;while(!ctype_digit($_POST["campos_def" . $j .
"-" . ($k+$def_offset)][$l])){
$l++;}$cad = "campos_def" . $j . "-" . ($k+$def_offset);$_POST[$cad] = substr($_POST[$cad], 0, $l) .
strtoupper($new_pubs[$n]["abbrev"]) .substr($_POST[$cad], $l);
$_POST["field" . $j . "-" . ($k+$def_offset)] =$_POST[$cad];
$changed = true;$pubs_mod[$mod_entries++] = $j;
}}
}$processed++;
}$j++;
}}// APELLIDOS: contiene los apellidos de todos los autores// pertenecientes al grupo.$peticion_sql = "SELECT bibtexname FROM people";$resultado = mysql_query($peticion_sql) or die("La consulta falló: " .
mysql_error());$i = 0;while ($linea = mysql_fetch_array($resultado, MYSQL_ASSOC)) {
$nombres_usuarios[$i] = $linea["bibtexname"];$i++;
}$apellidos = busca_apellido_reg($nombres_usuarios);// AUTORES_GRUPO: array con los nombres de los autores del grupo$resultado = mysql_query("SELECT name, surname FROM people");$j = 0;while ($row = mysql_fetch_assoc($resultado)) {
$autores_grupo[$j] = quita_tildes(strtolower(trim($row['name'] ." " . $row['surname'])));
$j++;}
// Mensaje de bienvenidaimprime_mensaje_bienvenida($formulario, $log_file);// Mensaje de progresoecho "\t\t<div id='progress' style='margin:20px 0px 0px " .
"0px;position:relative;padding:0px;width:700px;" ."height:30px;left:25px;'></div>\n";
flush();ob_flush();
// Apertura del fichero con los datos a actualizar//*****************************************// Primero se mira qué tablas se van a modificar, pues si se trata de// "congress" o "journals", ha de crearse un array a partir de las// publicaciones contenidas en el fichero auxiliar "pubs.txt".genera_arrays($pubs_file, $tablas_db, $congresos, $siglas_congreso, $revistas,
$siglas_revista);// Bucle principal -> una iteración por cada tabla principal a modificar$n_tablas = count($nombre_tablas);// Nº de tablas a modificarunset($errores);
116
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
for ($i=0;$i<$n_tablas;$i++)$errores[$i] = FALSE; // Variable que indica si hay
// publicaciones desconocidas// Índice para saber el número de errores en las entradas de la actualización$n_errores = $n_unknown - $added_entries;$entrado = FALSE;$def_count = 0;$mark[0] = 0;
// Obtención de las direcciones$i = 0;while (isset($_POST["url" . $i])) {
$urls[$i] = $_POST["url" . $i];$i++;
}$html_contents = get_html_content($urls);// Obtención de los directorios$i = 0;while (isset($_POST["dir" . $i])) {
$dirs[$i] = $_POST["dir" . $i];$i++;
}
if ($formulario == 0) {// Bucle principal, se recorren todos los ficheros y se crea una entrada en// $campos_def por cada publicación. Esta entrada contendrá toda la// información necesaria para poder actualizar la BD posteriormente, sin
// necesidad de procesar// otra vez toda la información.$ini_msg = "<b>PROCESANDO FICHERO \"";for ($i=0; $i<$n_tablas; $i++) {
// Apertura del fichero de actualización$archivo = fopen($temp_dir.$nombre_ficheros[$i], "r");$msg = $ini_msg . $nombre_ficheros[$i] . "\"</b>: ";if ($archivo) {
unset($contenido);unset($lineas);unset($num_lineas);$contenido = fread($archivo, filesize($temp_dir .
$nombre_ficheros[$i]));$lineas = explode($separador_linea[$i], $contenido);$num_lineas = count($lineas);$l_count = 0;
$vacio = false;$campos_erroneos = false;for ($j=0; $j<count($campos_update[$i]); $j++) {
if ($campos_update[$i][$j] == "")$vacio = true;
else if ($vacio == true)$campos_erroneos = true;
}if ($campos_erroneos == false) {
while ($l_count < $num_lineas) {// Paso 1: Obtener una fila de la tabla$linea = trim($lineas[$l_count]);if ($linea != "") {
// Se muestra el mensaje de progreso$ind_title = 0;for ($j=0; $j<=count($campos_def[$def_count])-$def_offset; $j++)
if ($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j] == "title")
$ind_title = $j;$progress_msg = $msg . "Procesando entrada " .
117
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
($def_count+1) . "...";echo "\t\t<script type=\"text/javascript\"> " .
"document.getElementById(\"progress\").innerHTML " ."= '" . $progress_msg . "' </script>\n";
flush();ob_flush();
for ($j=0;$j<(count($campos_tablas[$nombre_tablas[$i]])+$def_offset); $j++)
{// Contendrá los campos finales de cada línea,// para generar la orden SQL$campos_def[$def_count][$j] = "";
}$campos_def[$def_count][$campo_def_add["tabla"]] =
$nombre_tablas[$i];// Paso 2: Extraer cada uno de los campos (se insertan en
// "campos_temp")$campo = strtok($linea, $separador_campo[$i]);$j = -1;while ($campo != FALSE) {
$j++;$campos_temp[$j] = $campo;$campo = strtok($separador_campo[$i]);
}//Paso 3: Identificar campos e insertarlos en una tabla que se //usará posteriormente para generar las órdenes SQL// Bucle que se recorre una vez por cada campo de la tabla para// rellenar los campos no especificados y los directamente // asignablesfor ($j=0; $j<count($campos_tablas[$nombre_tablas[$i]]); $j++){
$encontrado = FALSE;$inserta = false;// NOTA: Los campos de autores, fecha, título y publicación// son obligatorios en todos los casosswitch ($campos_tablas[$nombre_tablas[$i]][$j]) {
// Si el campo en cuestión es la fecha de un PFC o un // PHD, se usa la nomenclatura AÑO-MES-DÍA, con 4 dígitos// de precisión el año y dos dígitos el resto, separados// por guionescase "datephd":case "datepfc":
for ($k=0; $k<count($campos_update[$i]); $k++) {if ($campos_update[$i][$k] ==
$campos_tablas[$nombre_tablas[$i]][$j]){
if (strpos($campos_temp[$k], "/") !== false)$parts = explode("/", $campos_temp[$k]);
else if (strpos($campos_temp[$k], "-") !== false)$parts = explode("-", $campos_temp[$k]);
else if (strpos($campos_temp[$k], ".") !== false)$parts = explode(".", $campos_temp[$k]);
else if (strpos($campos_temp[$k], " ") !== false)$parts = explode(" ", $campos_temp[$k]);
$field = $parts[2] . "-" . $parts[1] ."-" . $parts[0];
$inserta = true;}
}break;
// Código de libro: libro o actascase "code":
$field = $_POST["tipo_libro".$i];
118
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$inserta = true;break;
default:for ($k=0; $k<count($campos_update[$i]); $k++){
if ($campos_update[$i][$k] ==$campos_tablas[$nombre_tablas[$i]][$j])
{$field = $campos_temp[$k];$inserta = true;
}}break;
}if ($inserta == true){
trata_texto($field, $siglas_congreso,$siglas_revista, $mayusc, $numbers);
$campos_def[$def_count][$j + $def_offset] = $field;$inserta = false;
}}// Bucle que procesa los casos particulares y los inserta en la// tabla de campos para las órdenes SQL:// * Campos ficticios a partir de los cuales se deben obtener// otros campos// * Campos para actualizar otras tablas interrelacionadas// (authors, supervisors)// * Campos que se obtienen de forma indirecta a partir de// otros campos (reference)// AUTHORS:for ($k=0; $k<count($campos_update[$i]); $k++) {
if ($campos_update[$i][$k] == "authors") {$cad = $campos_temp[$k];$cad = str_replace(". ", ".", $cad);$cad = str_replace(".", ". ", $cad);$cad = ucwords(strtolower($cad));$campos_def[$def_count][$campo_def_add["authors"]] =
$cad;}
}// SEP_AUTHORS:$campos_def[$def_count][$campo_def_add["sep_authors"]] =
$separador_autor[$i];// SUPERVISORS:for ($k=0; $k<count($campos_update[$i]); $k++)
if ($campos_update[$i][$k] == "supervisors")$campos_def[$def_count][$campo_def_add["supervisors"]] =
$campos_temp[$k];// SEP_AUTHORS:$campos_def[$def_count][$campo_def_add["sep_supervisors"]] =
$separador_super[$i];// REFERENCE:$indice = 0;for ($l=0;$l<count($campos_update[$i]);$l++)
if ($campos_update[$i][$l] == "authors")$indice = $l;
// El primer campo de la referencia es el primer apellido del// autor. Para insertarlo, se busca el primer apellido de todos// los autores posibles del grupo en el grupo de autores. Se// escoge el autor que aparezca en primer lugar.$main_author = strtok($campos_temp[$indice],
$separador_autor[$i]);$reference = busca_apellido_autor($main_author,
$apellidos);
119
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
unset($nombre);// El segundo campo de la referencia es el tipo de publicación.switch ($nombre_tablas[$i]) {
case "books":$reference = $reference . "BOOK";$insertado = TRUE;break;
case "phds":$reference = $reference . "PHD";$insertado = TRUE;break;
case "pfcs":$reference = $reference . "PFC";$insertado = TRUE;break;
case "journals":$revista = busca_revista($campos_update[$i],
$campos_temp, $revistas, $siglas_revista, $insertado);$reference = $reference . $revista;if ($insertado == false) {
$campos_def[$def_count][$campo_def_add["error"]] .="revista*";
$n_errores++;set_form($formulario);
}break;
case "congress":$congreso = busca_congreso($campos_update[$i],
$campos_temp, $congresos, $siglas_congreso,$insertado);
$reference = $reference . $congreso;if ($insertado == false) {
$campos_def[$def_count][$campo_def_add["error"]] .="congreso*";
$n_errores++;set_form($formulario);
}break;
}// El tercer campo de la referencia es el añofor ($k=0; $k<count($campos_update[$i]); $k++) {
switch ($campos_update[$i][$k]) {case "year":case "datepfc":case "datephd":
$year = "";if (strpos($campos_temp[$k], "-") !== false)
$parts = explode("-", $campos_temp[$k]);else if (strpos($campos_temp[$k], "/") !== false)
$parts = explode("/", $campos_temp[$k]);else if (strpos($campos_temp[$k], ".") !== false)
$parts = explode(".", $campos_temp[$k]);else if (strpos($campos_temp[$k], " ") !== false)
$parts = explode(".", $campos_temp[$k]);else
$year = $campos_temp[$k];if ($year == "")
for ($n=0; $n<count($parts); $n++)if (strlen($parts[$n]) == 4)
$year = $parts[$n];$reference = $reference . $year;break;
}}for ($j=0; $j<count($campos_tablas[$nombre_tablas[$i]]); $j++)
120
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if ($campos_tablas[$nombre_tablas[$i]][$j] == "reference")$campos_def[$def_count][$j + $def_offset] = $reference;
// Es necesario especificar el año o la fecha de// publicación para poder generar la referencia$especificado = false;for ($j=0;
$j<count($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]]);$j++)
{switch
($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j]){
case "datepfc":case "datephd":case "year":
if ($campos_def[$def_count][$j+$def_offset] != "")$especificado = true;
break;}
}if ($especificado == false) {
$campos_def[$def_count][$campo_def_add["error"]] .="fecha*";
set_form($formulario);}
// Es necesario especificar el título de la publicación$especificado = false;for ($j=0;
$j<count($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]]);$j++)
{switch
($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j]){
case "title":if ($campos_def[$def_count][$j+$def_offset] != "")
$especificado = true;break;
}}if ($especificado == false) {
$campos_def[$def_count][$campo_def_add["error"]] .="titulo*";
set_form($formulario);}
// Es necesario especificar los autores para poder generar la// referencia$especificado = false;if ($campos_def[$def_count][$campo_def_add["authors"]] != "")
$especificado = true;if ($especificado == false) {
$campos_def[$def_count][$campo_def_add["error"]] .="autores*";
set_form($formulario);}
// Se mira en las páginas facilitadas si existe un hyperlink// de un fichero pdf para la publicación en cuestión$ind_title = 0;for ($j=0; $j<=count($campos_def[$def_count])-$def_offset;
$j++){
121
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j] == "title")
$ind_title = $j;busca_publicacion_web($html_contents, $urls,
$campos_def[$def_count][$ind_title+$def_offset],$siglas_congreso, $siglas_revista, $mayusc, $numbers,$campos_def[$def_count][$campo_def_add["pdf"]]);
// Se busca en los directorios siempre// que se tenga la referencia completaif ((strpos($campos_def[$def_count][$campo_def_add["error"]],
"revista") === false) &&(strpos($campos_def[$def_count][$campo_def_add["error"]],
"congreso") === false) &&(strpos($campos_def[$def_count][$campo_def_add["error"]],
"autores") === false) &&(strpos($campos_def[$def_count][$campo_def_add["error"]],
"fecha") === false)){
// Solamente se mira en los directorios si el usuario ha // incluido algunoif (is_array($dirs)) {
$path = 0;$percent = 1;busca_publicacion_dir($dirs, $reference, $pubs_file,
$campos_def[$def_count][$campo_def_add["pdf"]]);}
}// Si no se ha encontrado nada, entonces se pone en blanco un // campo de los pdfs para al menos dar la oportunidad de// añadirloif (($campos_def[$def_count][$campo_def_add["pdf"]][0][0]== "") ||!isset($campos_def[$def_count][$campo_def_add["pdf"]][0][0])){
$campos_def[$def_count][$campo_def_add["pdf"]][0][0] = "";$campos_def[$def_count][$campo_def_add["pdf"]][0][1] = "";set_form($formulario);
}
// La primera vez todas las entradas se toman como incompletas$campos_def[$def_count][$campo_def_add["finished"]] = 0;$def_count++;
}$l_count++;unset($linea);
}}else
echo "Ha especificado incorrectamente los campos en el paso " ."anterior. Por favor, reintente la operación tras subsanar " ."el error.";
fclose ($archivo);} else die("Error al abrir el fichero (compruebe que el fichero " .
"existe y que se tienen los permisos necesarios para acceder al " . "mismo.");
}}// Si no es la primera vez que se carga la página (esto es, se// redirecciona a sí misma)...else{
// Se obtiene la tabla $campos_def$i = 0; // 1ª dimensión de $campos_def$j = 0; // 2ª dimensión de $campos_def// Una iteración por cada entradawhile (isset($_POST["campos_def" . $i . "-" . $j]) ||
122
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
isset($_POST["campos_def" . $i . "-" . $j . "-0-0"])){
// Una iteración por cada campo de cada entradawhile (isset($_POST["campos_def" . $i . "-" . $j]) ||
isset($_POST["campos_def" . $i . "-" . $j . "-0-0"])){
if ($j < $def_offset) {if (($j != $campo_def_add["pdf"]) &&
($j != $campo_def_add["finished"]) &&($j != $campo_def_add["authors"]))
{$campos_def[$i][$j] = $_POST["campos_def" . $i . "-" . $j];
}else if ($j == $campo_def_add["authors"])
$campos_def[$i][$j] = $_POST["field" . $i . "-" . $j];else if ($j == $campo_def_add["pdf"]) {
unset($url); unset($mark);$salir = false; // Bandera para salir del bucle$k = 0; // Contador para la totalidad de direcciones$bad = 0; // Contador para las direcciones erróneas// En caso de lista de ficheros, se obtiene cuál// de los fichero es el actualmente seleccionadoif (isset($_POST["pdf_check" . $i])) {
// Se obtiene el fichero pdf seleccionado$m = $_POST["pdf_check" . $i];// Se comprueba si éste se puede leer$desc_read = fopen($_POST["url" . $i . "-" . $m], "rb");if ($desc_read == false)
$checked = -1;else {
$checked = $m;fclose($desc_read);
}}// Bandera para saber si ya hay un fichero// con el botón radio seleccionado$marked = false;while ($salir == false) {
$url = "";// Caso en que el campo del fichero es de// tipo texto y se encuentra en una webif (isset($_POST["url" . $i . "-" . $k]) &&
($_POST["url" . $i . "-" . $k] != "")){
// En caso de que se haya cambiado el contenido del// campo, se realizan las comprobaciones pertinentesif (stripslashes($_POST["url" . $i . "-" . $k]) !=
stripslashes($_POST["campos_def" .$i . "-" . $j . "-" . $k . "-0"]))
{// Comprobación de que se puede leer dicha dirección$desc_read = fopen(stripslashes($_POST["url" .
$i . "-" . $k]), "rb");if ($desc_read == true) {
// Se actualiza la dirección del fichero$campos_def[$i][$j][$k-$bad][0] =
stripslashes($_POST["url" . $i ."-" . $k]);
// Se actualiza el porcentaje$campos_def[$i][$j][$k-$bad][1] = 0;if (isset($_POST["pdf_check".$i])) {
if (($checked == $k) ||(($marked == false) &&($checked == -1)))
{
123
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$mark[$i][$j][$k-$bad] = 1;$marked = true;
}else
$mark[$i][$j][$k-$bad] = 0;}fclose($desc_read);
}// Si no se puede leer, se incrementa el// contador de direcciones erróneaselse {echo "mierda";
$bad++;}
}// En caso de que no se haya cambiado nada, se// procede a la copia directa de la informaciónelse {
// Se actualiza la dirección del fichero$campos_def[$i][$j][$k-$bad][0] =
stripslashes($_POST["campos_def".$i . "-" . $j . "-" . $k . "-0"]);
if (isset($_POST["pdf_check" . $i])) {if (($checked == $k) ||
(($marked == false) && ($checked == -1))){
$mark[$i][$j][$k-$bad] = 1;$marked = true;
}else
$mark[$i][$j][$k-$bad] = 0;}// Se actualiza el porcentaje$campos_def[$i][$j][$k-$bad][1] =
$_POST["campos_def". $i . "-" .$j . "-" . $k . "-1"];}
}// Caso en que el campo del fichero es// de tipo texto y éste está en blancoelse if (isset($_POST["url" . $i . "-" . $k]) &&
($_POST["url" . $i . "-" . $k] == "")){
$bad++;}// Caso en que el campo del fichero es de// tipo fichero y se encuentra en blancoelse if (isset($_FILES["url" . $i . "-" . $k]))
$bad++;// Caso en que no hay más ficheroselse
$salir = true;$k++;
}if (!isset($campos_def[$i][$campo_def_add['pdf']])) {
$campos_def[$i][$campo_def_add['pdf']][0][0] = "";$campos_def[$i][$campo_def_add['pdf']][0][1] = "";
}}// El campo de entrada terminada (finished) se ha// de obtener de otro campo ocultoelse if ($j == $campo_def_add["finished"])
if (isset($_POST["finished" . $i]))$campos_def[$i][$j] = 1;
else$campos_def[$i][$j] = 0;
124
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}else {
$campos_def[$i][$j] = $_POST["field" . $i . "-" . $j];}$j++;
}$i++;$j = 0;
}// Solamente se procesan los datos de las entradas// que el usuario desea añadir, las demás se eliminanfor ($i=0; $i<count($campos_def); $i++)
if (isset($_POST["nondesired" . $i]))$campos_def = elimina_entrada($campos_def, $i);
// Se procede a buscar en los directorios aquellas entradas// que anteriormente dieron errores debido a la referenciaif (is_array($dirs)) {
if (isset($pubs_mod) && ($pubs_mod[0] != "")) {for ($i=0; $i<count($pubs_mod); $i++) {
// Obtención de la posición de la referencia$ref_ind = 0;$tab_ind = $campos_def[$pubs_mod[$i]][$campo_def_add["tabla"]];while ($campos_tablas[$tab_ind][$ref_ind] != "reference")
$ref_ind++;$ref_ind += $def_offset;$path = 0;$percent = 1;busca_publicacion_dir($dirs,
$campos_def[$pubs_mod[$i]][$ref_ind], $pubs_file,$campos_def[$pubs_mod[$i]][$campo_def_add["pdf"]]);
}}
}
// Se procede a procesar las entradas completas$mostrado = false;for ($i=0; $i<count($campos_def); $i++) {
flush();ob_flush();if ($campos_def[$i][$campo_def_add["finished"]] == 1) {
$mostrado = true;if (procesa_entrada($campos_def[$i], $campo_def_add, $campos_tablas,
$tipo_publicacion, $autores_grupo, $id, $letra)){
if (!isset($_POST["req_pdf".$i])){
if (isset($campos_def[$i][$campo_def_add["pdf"]])){
if (isset($_POST["pdf_check" . $i]))$ind = $_POST["pdf_check" . $i];
else$ind = 0;
if ($campos_def[$i][$campo_def_add["pdf"]][$ind][0] != ""){
inserta_pdf($campos_def[$i][$campo_def_add["pdf"]][$ind][0],$log_file,
$tipo_publicacion[$campos_def[$i][$campo_def_add["tabla"]]],$id);
}}
}}if (isset($delete))
$delete[count($delete)] = $i;else
125
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$delete[0] = $i;}
}// Se borran las entradas ya procesadasfor ($i=(count($delete)-1); $i>=0; $i--)
$campos_def = elimina_entrada($campos_def, $delete[$i]);// Se procede a la copia de los ficheros$desc_read = fopen($log_file, "r");if ($desc_read != false) {
// Obtención del contenido del ficherowhile (!feof($desc_read))
$content .= fread($desc_read, 8192);fclose($desc_read);if (trim($content) != "")
print "\n\t\t<script type=\"text/javascript\"> " ."Abrir_Ventana('http://localhost/groupweb/proc_files.php', " ."'600', '200') </script>\n";
}if ($mostrado == true)
echo "\t\t<br /><br />\n";}
echo "\t\t<script type=\"text/javascript\"> " ."document.getElementById(\"progress\").style.display = 'none'</script>\n";
// Se procede a examinar las entradas disponibles para// eliminar las ya existentes en la base de datosfor ($i=(count($campos_def)-1); $i>-1; $i--) {
$sentencia_SQL = crea_orden_sql($campos_def[$i], $campo_def_add, $campos_tablas);
$query_sql = "SELECT title, reference FROM " .$campos_def[$i][$campo_def_add["tabla"]];
$resultado = mysql_query($query_sql);$num_refs = 0;// Si la entrada ya existe en la base de datos// se procede a su borrado de la tabla $campos_defif (busca_entrada_similar($resultado, $campos_def[$i], $campo_def_add,
$campos_tablas, $num_refs)){
$campos_def = elimina_entrada($campos_def, $i);}
}// Si existen entradas en la tabla $campos_def ha de// presentarse nuevamente el formularioif (count($campos_def) > 0) {
set_form($formulario);abre_formulario();// Si todavía existen entradas incompletas en $campos_def,// se muestran de nuevo los resultados por pantallaimprime_resultados($campos_def, $campo_def_add, $campos_tablas,
$mensajes_error, $mark);// Se envían los campos ocultos que se enviaban inicialmentefor ($i=0; $i<count($nombre_tablas); $i++) {
echo "\t\t\t<input type='hidden' name='tabla" . $i . "' value=\"" .$nombre_tablas[$i] . "\" />\n";
echo "\t\t\t<input type='hidden' name='fichero" . $i . "' value=\"" .$nombre_ficheros[$i] . "\" />\n";
}for ($i=0; $i<count($campos_update); $i++)
for ($j=0;$j<count($campos_update[$i]);$j++)echo "\t\t\t<input type='hidden' name='campo" . $i . "-" .
$j . "' value=\"" . $campos_update[$i][$j] . "\" />\n";for ($i=0; $i<count($separador_campo); $i++)
echo "\t\t\t<input type='hidden' name='separador_campo" . $i ."' value=\"" . $_POST["separador_campo" . $i] . "\" />\n";
for ($i=0; $i<count($separador_campo); $i++)
126
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t<input type='hidden' name='separador_linea" . $i ."' value=\"" . $_POST["separador_linea" . $i] . "\" />\n";
// Se ha de pasar la lista de urls ...for ($i=0; $i<count($urls); $i++)
echo "\t\t\t<input type='hidden' name='url" . $i . "' value=\"" .$urls[$i] . "\" />\n";
// ... así como la lista de urlsfor ($i=0; $i<count($dirs); $i++)
echo "\t\t\t<input type='hidden' name='dir" . $i . "' value=\"" .stripslashes($dirs[$i]) . "\" />\n";
// FORMULARIO nos permitirá discernir si se trata de un redireccionamiento// a la propia página o es la primera vez que se llega a ellaecho "\t\t\t<input type='hidden' name='formulario' value=\"" .
$formulario . "\" />\n";// ERRORES nos indica la cantidad de variables que hay que comprobar, esto // es, el nº de mini-formularios creados para cada publicación no reconocidaecho "\t\t\t<input type='hidden' name='errores' value=\"" .
$n_errores . "\" />\n";// Envío del array $campos_deffor ($i=0; $i<count($campos_def); $i++) {
for ($j=0; $j<count($campos_def[$i]); $j++) {if (!is_array($campos_def[$i][$j]))
echo "\t\t\t<input type='hidden' name='campos_def" . $i . "-" .$j . "' value=\"" . $campos_def[$i][$j] . "\" />\n";
else {for ($k=0; $k<count($campos_def[$i][$j]); $k++) {
if (!is_array($campos_def[$i][$j][$k]))echo "\t\t\t<input type='hidden' name='campos_def" . $i .
"-" . $j . "-" . $k . "' value=\"" .$campos_def[$i][$j][$k] . "\" />\n";
else {for ($m=0; $m<count($campos_def[$i][$j][$k]); $m++) {
echo "\t\t\t<input type='hidden' name='campos_def" .$i . "-" . $j . "-" . $k . "-" . $m . "' value=\"" .$campos_def[$i][$j][$k][$m] . "\" />\n";
}}
}}
}}echo "\t\t\t<input type='submit' value='Volver al paso 3' />\n";cierra_formulario();
}// Si ya no quedan entradas incompletas en $campos_def,// se muestra el mensaje de actualización con éxitoelse {
echo "\t\tActualización de la base de datos completada.<br></br>";echo "Muchas gracias por su colaboración.<br></br>\n";
}cierra_pagina();desconecta_db($conexion_mysql);
}else {
echo "Error en el nombre de usuario o en la contraseña.<br />Por favor, " ."vuelva a la pantalla de validación.<br />";
echo "<a href=\"./update.html\">Página de validación</a>";}
?>
10.4.1.5 PROC_FILES .PHP
<?php
127
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
include "functions.step3.php";set_time_limit (36000);
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html>
<head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><meta http-equiv="imagetoolbar" content="no" /><meta name="robots" content="noindex, nofollow" /><meta http-equiv="Cache-Control" content="no-cache" /><meta http-equiv="Pragma" content="no-cache" /><title>Barra progreso PHP/ PHP Progress bar</title>
</head><body>
<?php// Nombre del fichero con la información de los pdfs a copiar$log_file = "pdf_log.txt";// Ruta de destino de los ficheros pdfs$ruta = "./files/";// Recuperacion de las rutas de los ficheros a partir del fichero pdf_log.txt$desc_read = fopen($log_file, "r");if ($desc_read == FALSE)
$read = false;else {
// Obtención del contenido del fichero de logwhile (!feof($desc_read)) {
// Obtención del contenido de la dirección$log_content = fread($desc_read, 8192);
}fclose($desc_read);
}// Separación de la información de cada fichero en líneas => $linea$tok = strtok($log_content, "\n");$i = 0;while ($tok !== false) {
$linea[$i] = $tok;$tok = strtok("\n");$i++;
}// Se realiza una iteración por cada fichero que se ha de copiar$i=0;while ($i < count($linea)) {
// Extracción de la información de cada línea$n_tok = 0;$tok = strtok($linea[$i], "\t");while ($tok !== false) {
// 1er campo: Ruta del fichero pdfif ($n_tok == 0){
// URL del fichero$urls[$i] = $tok;// Tamaño del fichero$size[$i] = sprintf("%.2f", (trim(remote_file_size($urls[$i])))/1024);if ($size[$i] == "0.00") {
$size[$i] = sprintf("%.2f", (trim(filesize($urls[$i])))/1024);}// Eliminación de las barras invertidasif (strpos($urls[$i], "\\") !== false)
$nombres[$i] = substr($urls[$i], strrpos($urls[$i], "\\"));else if (strpos($urls[$i], "/") !== false)
$nombres[$i] = str_replace("%20", " ", substr($urls[$i],strrpos($urls[$i], "/") + 1));
$n_tok++;}
128
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// 2º y 3er campos: Tipo de publicación e id del ficheroelse if ($n_tok != 0){
$pub_type = $tok;$tok = strtok("\t");$id = $tok;// Si existen el tipo de publicación y la id de la entrada de// la base de datos, se calcula la ruta del ficheroif (($pub_type !== false) && ($id !== false))
$ruta_fichero[$i] = $ruta . "t" . trim($pub_type) ."i" . trim($id) . ".pdf";
// Si no, entonces se borra la entrada de la tabla de $urlselse
for ($j=$i; $j<(count($linea[$i])-1); $j++)$linea[$j] = $linea[$j+1];
}}$i++;
}// Impresión de los divs que mostrarán los progresosecho "<div id='info_file' style='margin:20px 0px 0px 0px;position:relative;" .
"padding:0px;width:550px;height:30px;left:25px;'></div>\n";echo "<div id='file_progress' style='position:relative;padding:0px;width:" .
"512px;height:27px;left:25px;" ."background-image:url(images/pbar_background.gif)'></div>\n";
echo "<div id='info_total' style='margin:20px 0px 0px 0px;position:relative;" ."padding:0px;width:550px;height:30px;left:25px;'></div>\n";
echo "<div id='total_progress' style='position:relative;padding:0px;width:" ."512px;height:27px;left:25px;" ."background-image:url(images/pbar_background.gif)'></div>\n";
$max_bars = 250; // Máximo nº de barras que se mostrarán$total_transferred = 0; // Tamaño total transferido$count_bars = 0;$read_size = 8192; // Tamaño del bloque de lectura$read_sizeKB = $read_size/1024; // Tamaño del bloque de lectura en KB$error = false;$totalbar_size = array_sum($size)/$max_bars;// Se muestra el total de KB a transferirecho "<script type=\"text/javascript\"> document.getElementById" .
"(\"info_total\").innerHTML = \"Total a transferir: " . array_sum($size) . "KB\" </script>\n";
// Para cada fichero se realiza una iteración// y se muestra el porcentaje de avancefor ($i=0; $i<count($nombres); $i++) {
$bar_size = $size[$i]/$max_bars;$filesize_transferred = 0;// Apertura del flujo de lectura$desc_read = fopen($urls[$i], "rb");if ($desc_read == false)
$error = true;else {
// Apertura del flujo de escritura$desc_write = fopen($ruta_fichero[$i], "wb");if ($desc_write == false)
$error = true;else {
// Se muestra el texto de progresoecho "<script type=\"text/javascript\"> document.getElementById" .
"(\"info_file\").innerHTML = \"Copiando el fichero "" .$nombres[$i] . "" [" . $size[$i] . " KB]\" </script>\n";
while (!feof($desc_read)) {$pdf_content = fread($desc_read, $read_size);fwrite($desc_write, $pdf_content);// Actualización de la barra de progreso del fichero que se está // copiando
129
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$filesize_transferred += strlen($pdf_content)/1024;$num_bars = sprintf("%.0d", $filesize_transferred/$bar_size);$bars = "<div style='float:left;margin:6px 0px 0px 6px;width:" .
($num_bars*2) . "px;height:12px;background:red;color:red;'> </div>";echo "<script type=\"text/javascript\"> " .
"document.getElementById(\"file_progress\").innerHTML = \"" .$bars . "\" </script>\n";
// Actualización de la barra de progreso del tamaño total que se ha de // transferir$total_transferred += strlen($pdf_content)/1024;$num_bars = sprintf("%.0d", $total_transferred/$totalbar_size);$bars = "<div style='float:left;margin:6px 0px 0px 6px;width:" .
($num_bars*2) . "px;height:12px;background:red;color:red;'> </div>";echo "<script type=\"text/javascript\"> " .
"document.getElementById(\"total_progress\").innerHTML = \"" .$bars . "\" </script>\n";
flush();ob_flush();
}fclose($desc_read);fclose($desc_write);
}}
}
// Una vez copiados todos los ficheros, se procede a// borrar el contenido del fichero de logeado de pdfs$desc_write = fopen($log_file, "w");if ($desc_write != false)
fclose($desc_write);
// Se retrasa 2 segundos el cierre de la ventanasleep(2);echo "<script type='text/javascript'> window.close() </script>\n";
?>
10.4.1.6 B ACKUP .PHP
<?phpinclude "functions.inc.php";// Cambiamos el tiempo máximo de respuesta,// porque hay que buscar el fichero "mysqldump"ini_set("max_execution_time", "600");// No se reporta ningún tipo de error//error_reporting(0);session_start();
?><html>
<head><script type="text/javascript">
function resize(){
var width = window.screen.width;var height = window.screen.availHeight;var left = (parseInt(width) - 650)/2;document.getElementById("table_div").style.left = left;document.getElementById("table_div").style.top = 100;
}</script>
</head><body>
<div id="table_div" name="table_div" style="position:absolute;width:610px;"><?php
130
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$conexion_mysql =& conecta_db(); // Conexión con la base de datosif (isset($_POST['login']) && isset($_POST['pass'])) {
$login = $_POST['login'];$pass = $_POST['pass'];$_SESSION['login'] = $login;$_SESSION['pass'] = $pass;
}else if (isset($_SESSION['login']) && isset($_SESSION['pass'])) {
$login = $_SESSION['login'];$pass = $_SESSION['pass'];
}if (($login != "") && ($pass != "")) {
if (valida_usuario($login, $pass)) {// Obtener el root (C:/ en el caso de Windows o// ./ en el caso de Linux)$php_dir = str_replace("\\", "/", getcwd());$dir = getcwd();chdir('../');$new_dir = getcwd();while ($dir != $new_dir) {
$dir = $new_dir;chdir('../');$new_dir = getcwd();
}$root = str_replace("\\", "/", $new_dir);// Buscamos el fichero "mysqldump" en la// ruta almacenada en el fichero de logeochdir($php_dir);$dump_file = "dump_path.log";$dump_path = "";$dont_exists = false;if (file_exists($dump_file)) {
if (($handler = fopen($dump_file, "r")) != false) {$content = fread($handler, filesize($dump_file));if ($content != "") {
if (file_exists($content)) {$dump_path = $content;
}else {
$dont_exists = true;}
}else {
$dont_exists = true;}
}else {
$dont_exists = true;}
}else {
$dont_exists = true;}// Si el fichero de logeo no existe, o no contiene// una ruta válida, se busca el ficheroif ($dont_exists == true) {
$found = false;$path = $root;$filename = array("Linux" => "mysqldump",
"WINNT" => "mysqldump.exe");seek_file($path, $filename, $found);$dump_path = $path;if ($found == true) {
$dump_path = $path . "/" . $filename[PHP_OS];chdir($php_dir);
131
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if (($handler = fopen($dump_file, "w")) != false)fwrite($handler, $dump_path);
$dont_exists = false;}
}// Si se ha encontrado el fichero se procede a mostrar// el contenido de la página en función del botón pulsadoif ($dont_exists == false) {
// Caso de crear nueva copia de seguridad.// Simplemente se informa de la creación.if (isset($_POST['create_backup'])) {
// Obtención de la hora y la fecha$hora = date("H.i.s");$fecha = date("d-m-Y");// Comprobación de la existencia del directorio de backupchdir($php_dir);if (!file_exists("./db_backup/"))
mkdir("./db_backup");chdir($php_dir . "/db_backup/");// Creación del registro del contenido del directorio de pdfsif ($dir_handler = opendir($php_dir . "/files/")) {
if ($log_handler = fopen("pdf_" . $hora ."_" . $fecha . ".log", "w"))
{while (($res = readdir($dir_handler)) !== false){
if (is_file($php_dir . "/files/" . $res)) {fwrite($log_handler, $res . "\n");
}}fclose($log_handler);
}closedir($dir_handler);
}chdir($dump_dir);// Sustituir aquí el nombre de usuario, la clave y el nombre de la// base de datosexec("mysqldump --user=nombre_usuario --password=clave " .
"--add-drop-table base_datos > " . $php_dir . "/db_backup/" ."backup_" . $fecha . "_" . $hora . ".sql");
if (file_exists($php_dir . "/db_backup/" ."backup_" . $fecha . "_" . $hora . ".sql"))
{echo "\t\t\tCreada copia de seguridad con hora " .
str_replace(".", ":", $hora) . " el día " .str_replace("-", "/", $fecha) . " en el fichero " ."backup_" . $fecha . "_" . $hora . ".sql<br />\n";
echo "\t\t\tVolver a la <a href=\"./update.html\">" ."página principal</a>.\n";
}}// Caso de restauración de copia de seguridad.// Se muestra una tabla con todas las copias existentes.else if (isset($_POST['restore_backup']) || isset($_POST['restore'])
|| isset($_POST['delete'])){
// Caso de haber seleccionado una copia de seguridad// para restauración en el caso anterior.if (isset($_POST['restore'])) {
chdir(dirname($dump_path));// Sustituir aquí el nombre de usuario, la clave y el nombre de la// base de datospassthru("mysql --user=nombre_usuario --password=clave " .
"base_datos < " . str_replace("/", "\\", $php_dir) ."\db_backup\\" . $_POST['filename']);
132
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Caso de haber marcado la casilla de actualización// de directorio contenedor de los ficheros pdfif (isset($_POST['update_pdf'])) {
// Lectura del contenido del fichero de registro de pdfs$content = "";$pdf_log_name = str_replace("backup", "pdf",
$_POST['filename']);$pdf_log_name = str_replace(".sql", ".log",
$pdf_log_name);if ($log_handler = fopen($php_dir . "/db_backup/" .
$pdf_log_name, "r")){
while (!feof($log_handler))$content .= fread($log_handler, 8192);
fclose($log_handler);}// Apertura del directorio de pdfs para lecturaif ($dir_handler = opendir($php_dir . "/files/")) {
while (($res = readdir($dir_handler)) !== false)if (is_file($php_dir . "/files/" . $res))
// Si el fichero que está siendo leído no se encuentra// en el fichero de registro, entonces debe borrarseif (stripos($content, $res) === false)
unlink($php_dir . "/files/" . $res);closedir($dir_handler);
}}
}// Caso de haber seleccionado una// copia de seguridad para ser borrada.if (isset($_POST['delete'])) {
if (file_exists($php_dir . "/db_backup/" . $_POST['filename']))unlink($php_dir . "/db_backup/" . $_POST['filename']);
$pdf_log_name = str_replace("backup", "pdf", $_POST['filename']);$pdf_log_name = str_replace(".sql", ".log", $pdf_log_name);if (file_exists($php_dir . "/db_backup/" . $pdf_log_name))
unlink($php_dir . "/db_backup/" . $pdf_log_name);}chdir($php_dir . "/db_backup/");if ($handler = opendir('.')) {
$found = false;echo "\t\t\t<form action=\"backup.php\" method=\"post\">\n";echo "\t\t\t\t<input type=\"hidden\" id=\"filename\" " .
"name=\"filename\" value=\"\" />\n";echo "\t\t\t\t<table border=1>\n";echo "\t\t\t\t\t<thead style=\"background-color:silver;\">\n";echo "\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t<th>Fecha</th>\n";echo "\t\t\t\t\t\t\t<th>Hora</th>\n";echo "\t\t\t\t\t\t\t<th colspan=\"3\"></th>\n";echo "\t\t\t\t\t\t</tr>\n";echo "\t\t\t\t\t</thead>\n";echo "\t\t\t\t\t<tbody>\n";while (($res = readdir($handler)) !== false) {
$found = true;$parts = pathinfo($res);if (is_file($res) && ($parts["extension"] == "sql")) {
$tok = explode("_", $res);$fecha = str_replace("-", "/", $tok[1]);$hora= str_replace(".", ":", str_replace(".sql", "", $tok[2]));echo "\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t<td width=\"90\" valign=\"center\" " .
"align=\"center\">\n";echo "\t\t\t\t\t\t\t\t" . $fecha . "\n";echo "\t\t\t\t\t\t\t</td>\n";
133
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t\t\t\t\t<td width=\"70\" valign=\"center\" " ."align=\"center\">\n";
echo "\t\t\t\t\t\t\t\t" . $hora . "\n";echo "\t\t\t\t\t\t\t</td>\n";echo "\t\t\t\t\t\t\t<td width=\"110\" valign=\"center\" " .
"align=\"center\">\n";echo "\t\t\t\t\t\t\t\t<input type=\"submit\" id=\"restore\" " .
"name=\"restore\" value=\"Restaurar copia\" " ."onclick=\"document.getElementById('filename').value = " ."'" . $res . "';\" />\n";
echo "\t\t\t\t\t\t\t</td>\n";echo "\t\t\t\t\t\t\t<td width=\"90\" valign=\"center\" " .
"align=\"center\">\n";echo "\t\t\t\t\t\t\t\t<input type=\"submit\" id=\"delete\" " .
"name=\"delete\" value=\"Borrar copia\" " ."onclick=\"document.getElementById('filename').value = " ."'" . $res . "';\" />\n";
echo "\t\t\t\t\t\t\t</td>\n";echo "\t\t\t\t\t\t\t<td width=\"200\">\n";echo "\t\t\t\t\t\t\t\t<input type=\"checkbox\" " .
"name=\"update_pdf\" value=\"1\" />\n";echo "\t\t\t\t\t\t\t\t<label for=\"update_pdf\">" .
"Actualizar directorio de pdfs</label>\n";echo "\t\t\t\t\t\t\t</td>\n";echo "\t\t\t\t\t\t</tr>\n";
}}if ($found) {
echo "\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t<td colspan=\"5\">\n";echo "\t\t\t\t\t\t\t\tNOTAS IMPORTANTES:\n";echo "\t\t\t\t\t\t\t\t<ul>\n";echo "\t\t\t\t\t\t\t\t\t<li>\n";echo "\t\t\t\t\t\t\t\t\t\tUna vez que se proceda con la " .
"restauración de una copia de seguridad y el resultado" ."sea el deseado, procédase al borrado de las copias de" ."seguridad posteriores a fin de evitar conflictos en " ."futuro.\n";
echo "\t\t\t\t\t\t\t\t\t</li>\n";echo "\t\t\t\t\t\t\t\t\t<li>\n";echo "\t\t\t\t\t\t\t\t\t\tLa casilla \"Actualizar " .
"directorios\" utiliza un registro de seguridad para " ."eliminar los ficheros pdfs añadidos con posterioridad " ."a la copia de seguridad a restaurar. Se recomienda " ."restaurar la copia primero con la casilla " ."deseleccionada, y en caso de resultar exitosa la " ."restauración, proceder entonces restaurarla " ."nuevamente con la casilla marcada, y por último, " ."eliminar las copias de seguridad posteriores.\n";
echo "\t\t\t\t\t\t\t\t\t</li>\n";echo "\t\t\t\t\t\t\t\t</ul>\n";echo "\t\t\t\t\t\t\t</td>\n";echo "\t\t\t\t\t\t</tr>\n";
}echo "\t\t\t\t\t</tbody>\n";echo "\t\t\t\t</table>\n";echo "\t\t\t</form>\n";
}// Se muestra el mensaje de la restauración de// copia de seguridad cuando corresponda.if (isset($_POST['restore'])) {
echo "\t\t\tRestaurada copia de seguridad <b>" .$_POST['filename'] . "</b>.<br />\n";
if (isset($_POST['update_pdf']))echo "\t\t\tActualizado sistema de archivos pdfs.<br />\n";
134
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\tVolver a la <a href=\"./update.html\">página " ."principal</a>.<br />\n";
}// Se muestra el mensaje del borrado de// copia de seguridad cuando corresponda.if (isset($_POST['delete'])) {
echo "\t\t\tBorrada copia de seguridad <b>" .$_POST['filename'] . "</b>.<br />\n";
echo "\t\t\tVolver a la <a href=\"./update.html\">" ."página principal</a>.<br />\n";
}}
}}// Caso de que el usuario no esté validado correctamente se notifica por // pantallaelse {
echo "El nombre de usuario y/o la contraseña introducido/s no son " ."válidos.\n<br />";
echo "<a href=\"./update.html\">Volver a la página de validación</a>";}
}else {
echo "El nombre de usuario y/o la contraseña introducido/s no son " ."válidos.\n<br />";
echo "<a href=\"./update.html\">Volver a la página de validación</a>";}
?></div><script type="text/javascript"> resize(); </script>
</body></html>
10.4.1.7 PUBS _EDITOR.PHP
<?phpinclude "functions.inc.php";// Cambiamos el tiempo máximo de respuesta,// porque hay que buscar el fichero "mysqldump"ini_set("max_execution_time", "600");// No se reporta ningún tipo de error//error_reporting(0);session_start();
?><html>
<head></head><body>
<div id="table_div" name="table_div"><?php
// Validación de usuario$conexion_mysql =& conecta_db(); // Conexión con la base de datosif (isset($_POST['login_pubs']) && isset($_POST['pass_pubs'])) {
$login = $_POST['login_pubs'];$pass = $_POST['pass_pubs'];$_SESSION['login'] = $login;$_SESSION['pass'] = $pass;
}else if (isset($_SESSION['login']) && isset($_SESSION['pass'])) {
$login = $_SESSION['login'];$pass = $_SESSION['pass'];
}if (($login != "") && ($pass != "")) {
135
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if (valida_usuario($login, $pass)) {// Si el usuario entra por primera vez, entonces se muestra// el editor con el contenido del fichero de definicionesif (!isset($_POST["update_pubs"])) {
// Obtención del contenido del fichero$h_file = fopen("pubs.txt", "r");$content = "";while (!feof($h_file)) {
$content .= fread($h_file, 8192);}fclose($h_file);// Mensaje de bienvenidaecho "\t\t\t<h2>Fichero de definición de publicaciones:</h2><br />\n";// Explicación de las partes de una definiciónecho "\t\t\tEste fichero contiene las definiciones de las " .
"publicaciones, que incluyen los siguientes componentes por " ."publicación:<br />\n";
echo "\t\t\t<ul>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\t1ª línea: Comentario precedido por \"//\" que " .
"especifica el nombre completo de la publicación.\n";echo "\t\t\t\t</li>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\t2ª línea: Acrónimo o abreviatura de la publicación, " .
"seguido de \";\" y un tabulador, tras lo cual siguen las palabras " ."claves que se utilizarán para determinar la publicación separadas " ."por tabuladores.\n";
echo "\t\t\t\t</li>\n";echo "\t\t\t</ul>\n";// Explicación de los grupos de definicionesecho "\t\t\tExisten dos grupos definidos para cada tipo de publicación:"
. "<br />\n";echo "\t\t\t<ul>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\tLas publicaciones del tipo \"revista\" o \"journal\" " .
"se incluirán tras el identificador \"::JOURNALS\".\n";echo "\t\t\t\t</li>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\tLas publicaciones del tipo \"ponencia en congreso\" " .
"se incluirán tras el identificador \"::CONGRESS\".\n";echo "\t\t\t\t</li>\n";echo "\t\t\t</ul>\n";// Consejos de ediciónecho "\t\t\tConsejos:"
. "<br />\n";echo "\t\t\t<ul>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\tAntes de incluir una publicación asegúrese de que ".
"realmente no se encuentra incluida en la lista existente.\n";echo "\t\t\t\t</li>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\tTenga cuidado con las modificaciones que realice, " .
"pues el fichero de definiciones de publicaciones se actualizará " ."con el contenido final que usted indique.\n";
echo "\t\t\t\t</li>\n";echo "\t\t\t\t<li>\n";echo "\t\t\t\t\tAbsténgase de incluir preposiciones, artículos, " .
"conjunciones, etc. en las palabras claves. Incluya solamente las " ."palabras que mejor definan la publicación (sin tildes y en " ."minúsculas).\n";
echo "\t\t\t\t</li>\n";echo "\t\t\t</ul>\n";// Formulario con el editorecho "\t\t\t<form id=\"editor_form\" name=\"editor_form\" " .
"method=\"post\" action=\"pubs_editor.php\"\n";
136
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "\t\t\t\t<textarea id=\"pubs_content\" name=\"pubs_content\" " ."cols=\"120\" rows=\"30\">" . $content . "</textarea>\n";
echo "\t\t\t\t<input type=\"submit\" id=\"update_pubs\" " ."name=\"update_pubs\" " ."value=\"Actualizar fichero de definiciones\" />\n";
echo "\t\t\t</form>";}// Si no es la primera vez que se visita la página,// entonces se ha de actualizar el fichero de definicioneselse {
$h_file = fopen("pubs.txt", "w");if (fwrite($h_file, $_POST["pubs_content"]) === FALSE) {
echo "\t\t\tNo se puede escribir en el archivo de definiciones.";}else
echo "\t\t\tFichero de definiciones actualizado con éxito.\n";}
}// Caso de que el usuario no esté validado correctamente// se notifica por pantallaelse {
echo "El nombre de usuario y/o la contraseña introducido/s no son " ."válidos.\n<br />";
echo "<a href=\"./update.html\">Volver a la página de validación</a>";}
}else {
echo "El nombre de usuario y/o la contraseña introducido/s no son " ."válidos.\n<br />";
echo "<a href=\"./update.html\">Volver a la página de validación</a>";}
?></div>
</body></html>
10.4.1.8 FUNCTIONS .INC.PHP
<?php// Estas variables se utilizan para indicar campos que se facilitan en el fichero// de actualización y que no existen como tales en la tabla, es decir, que// requieren de un procesado posterior$lista_campos_adicionales = array('autores', 'supervisores');$tabla_campos_adicionales = array('all', 'phds');$var_campos_adicionales = array('authors', 'supervisors');// Estas variables se utilizan para que el usuario seleccione un valor, pues no// se facilitan en el fichero de actualización$lista_campos_undef = array('separador campos', 'separador filas',
'separador autores', 'separador supervisores', 'tipo de libro');$tabla_campos_undef= array('all', 'all', 'all', 'phds', 'books');$var_campos_undef = array('separador_campo', 'separador_linea',
'separador_autor', 'separador_super', 'tipo_libro');$valores_campos_undef = array(
$lista_campos_undef[0] => array (0,1,2,3,4,5,6,7),$lista_campos_undef[1] => array (0,1,2,3,4,5,6,7),$lista_campos_undef[2] => array (0,1,2,3,4,5,6,7),$lista_campos_undef[3] => array (0,1,2,3,4,5,6,7),$lista_campos_undef[4] => array ("1","2"));
$desc_campos_undef = array($lista_campos_undef[0] => array ("\\n","\\r","\\r\\n","\\t",";",":",",","."),$lista_campos_undef[1] => array ("\\n","\\r","\\r\\n","\\t",";",":",",","."),$lista_campos_undef[2] => array ("\\n","\\r","\\r\\n","\\t",";",":",",","."),$lista_campos_undef[3] => array ("\\n","\\r","\\r\\n","\\t",";",":",",","."),
137
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$lista_campos_undef[4] => array ("Libro","Actas"));
//************************************************************************// CONECTA_DB: realiza la conexión con la base de datos.// Entrada: - Ninguna// Salida: - Identificador de la conexión con la base de datos => $conexion//************************************************************************function &conecta_db() {
// Conexión con el servidor MySQL// El usuario deberá modificar estos datos para acceder correctamente$host = "nombre_host";$user = "nombre_de_usuario";$pass = "clave_de_usuario";$db = "base_datos";$conexion = mysql_connect($host, $user, $pass);if (!$conexion) {
die("No se pudo conectar con la base de datos: " . mysql_error());}// Conexión con la base de datosmysql_select_db("groupweb") or die("Error: " . mysql_error());
return $conexion;}
//************************************************************************// DESCONECTA_DB: realiza la desconexión con la base de datos// Entrada: - Identificador de la conexión con la base de datos => $conexion// Salida: - Ninguna//************************************************************************function desconecta_db(&$conexion) {
mysql_close($conexion);}
//*******************************************************************// LIBERA_RECURSO: realiza la liberación de los recursos// Entrada: - Identificador del recurso de la base de datos => $recurso// Salida: - Ninguna//*******************************************************************function libera_recurso($recurso) {
mysql_free_result($recurso);}
//******************************************************************// VALIDA_USUARIO: realiza la validación del usuario introducido// Entrada: - Login del usuario a validar => $login// - Contraseña del mismo => $password// Salida: - Bandera con valor TRUE si el usuario se validó con éxito// o FALSE en caso contrario => $validado//******************************************************************function valida_usuario($login, $password) {
$validado = FALSE;$peticion_sql = "SELECT password FROM people WHERE login='" . $login . "'";$resultado = mysql_query($peticion_sql) or die("Error, la consulta falló: "
. mysql_error());while ($linea = mysql_fetch_array($resultado, MYSQL_ASSOC)) {
if ($linea["password"] == $password)$validado = TRUE;
}libera_recurso($resultado);return $validado;
}
//**************************************************************************// LISTA_TABLAS: almacena en un array todas las tablas existentes en la base// de datos
138
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Entrada: - Ninguna// Salida: - Array con las tablas de la base de datos => $tablas_db//**************************************************************************function lista_tablas() {
$resultado = mysql_list_tables("groupweb");$i = 0;while ($i < mysql_num_rows ($resultado)) {
$tablas_db[$i] = mysql_tablename ($resultado, $i);$i++;
}libera_recurso($resultado);return $tablas_db;
}
//*******************************************************************************// INFO_CAMPOS: devuelve el tipo y el nombre de cada campo de cada una de las// tablas de una base de// datos contenidas en el array pasado// Entrada: - Array con los nombres de las tablas de la base de datos => $tablas// - Array para almacenar los tipos de los campos de cada tabla =>// $tipo_campos// - Array para almacenar los nombres de los campos de cada tabla =>// $nombre_campos// Salida: - Ninguna//*******************************************************************************function info_campos($tablas, &$tipo_campos, &$nombre_campos) {
$i = 0;while ($i < count($tablas)) {
$resultado = mysql_query("SELECT * FROM " . $tablas[$i]);$fields = mysql_num_fields($resultado);$j = 0;while ($j < $fields) {
$type = mysql_field_type ($resultado, $j);$name = mysql_field_name ($resultado, $j);$nombre_campos[$i][$j] = $name;$tipo_campos[$i][$j] = $type;$j++;
}$i++;
}libera_recurso($resultado);
}
//*******************************************************************************// INFO_CAMPOS_ASOC: devuelve el tipo y el nombre de cada campo de cada una de// las tablas de una base de datos contenidas en el array pasado, pero// utilizando como índices de la primera dimensión del array los nombres de// las tablas// Entrada: - Array con los nombres de las tablas de la base de datos => $tablas// - Array para almacenar los tipos de los campos de cada tabla =>// $tipo_campos// - Array para almacenar los nombres de los campos de cada tabla =>// $nombre_campos// Salida: - Ninguna//*******************************************************************************function info_campos_asoc($tablas, &$tipo_campos, &$nombre_campos) {
$i = 0;while ($i < count($tablas)) {
$resultado = mysql_query("SELECT * FROM " . $tablas[$i]);$fields = mysql_num_fields($resultado);$j = 0;while ($j < $fields) {
$type = mysql_field_type ($resultado, $j);$name = mysql_field_name ($resultado, $j);$nombre_campos[$tablas[$i]][$j] = $name;
139
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$tipo_campos[$tablas[$i]][$j] = $type;$j++;
}$i++;
}libera_recurso($resultado);
}
//***************************************************************************// BORRA_DIR_TEMP: borra el contenido del directorio facilitado// Entrada: - Ruta del directorio cuyo contenido se desea borrar => $directorio// Salida: - Ninguna.//***************************************************************************function borra_dir_temp($directorio) {
$manejador = opendir($directorio);$lista = "";while ($fichero = readdir($manejador))
if(!is_dir($fichero) && !is_link($fichero))unlink($directorio."\/".$fichero);
}
//*******************************************************************************// BUSCA_APELLIDO_REG: busca el apellido de la referencia bibliográfica de las// personas registradas como usuarios del sitio web GROUPWEB// Entrada: - Array con los nombres de los autores registrados en el sistema =>// $nombres// Salida: - Array con los primeros apellidos de los autores => $apellidos//*******************************************************************************function busca_apellido_reg ($nombres) {
for ($i=0;$i<count($nombres);$i++) {$nombres[$i] = trim($nombres[$i]);if ($apellido = strtok($nombres[$i], ",")) {
if (stripos($apellido, " ")) {$salir = FALSE;$apellido = strtok($nombres[$i], " ");while (($apellido != FALSE) && ($salir != TRUE)) {
if (($apellido != "el") && ($apellido != "la") &&($apellido != "los") && ($apellido != "las") &&($apellido != "de") && ($apellido != "da") &&($apellido != "del") &&(stripos($apellido, ".") == FALSE)) {
$apellidos[$i] = strtolower(quita_tildes($apellido));$salir = TRUE;
}}
}else
$apellidos[$i] = strtolower(quita_tildes($apellido));} else {
$apellido = strtok($nombres[$i], " ");$apellidos[$i] = strtolower(quita_tildes($apellido));
}}return $apellidos;
}
//******************************************************************************// QUITA_TILDES: elimina las tildes y el carácter "ñ" de la cadena pasada como// argumento// Entrada: - Cadena de caracteres a la que se desea quitar las tildes =>// $cadena// Salida: - Cadena sin tildes => $cadena//******************************************************************************function quita_tildes($cadena){
140
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$cadena = str_replace("á", "a", $cadena);$cadena = str_replace("é", "e", $cadena);$cadena = str_replace("í", "i", $cadena);$cadena = str_replace("ó", "o", $cadena);$cadena = str_replace("ú", "u", $cadena);$cadena = str_replace("ñ", "n", $cadena);return $cadena;
}
//*******************************************************************************// BUSCA_APELLIDO_AUTOR: busca el primer apellido del autor pasado en la cadena// $autor. Primero comprueba los autores registrados, que se encuentran en la// tabla $apellidos_reg.// Entrada: - Nombre del autor => $autor// - Array con los apellidos de los autores registrados =>// $apellidos_reg// Salida: - Primer apellido del autor pasado => $reference//*******************************************************************************function busca_apellido_autor ($autor, $apellidos_reg) {
// La primera búsqueda es para los autores del grupo, que tienen// su nombre bibliográfico en la base de datos$pos = -1;$nombre_completo = quita_tildes(strtolower($autor));for ($k=0;$k<count($apellidos_reg);$k++) {
$back = stripos(" " . $nombre_completo ,$apellidos_reg[$k]);if ($back != FALSE)
$pos = $k;}
if ($pos != - 1)$reference = strtolower($apellidos_reg[$pos]);
// Si la búsqueda no ha tenido éxito, es que el autor no// pertenece al grupo. Se obtiene entonces el apellido.else {
$palabra = strtok($nombre_completo, " ");$k = -1;// Insertamos en un array los nombres y apellidos$nombre_completo = $nombre_completo . " ";while ($palabra != FALSE) {
$k++;$nombre[$k] = $palabra;$palabra = strtok(" ");
}// Buscamos una coma. Si ésta existe en alguno de// los campos, quiere decir que lo primero son los apellidos.$coma = FALSE;for ($k=0;$k<count($nombre);$k++) {
if (stripos($nombre[$k], ","))$coma = TRUE;
}if ($coma == TRUE) {
// Si existe coma, buscamos el primer// apelllido que no se encuentre abreviado$k = 0;$encontrado = FALSE;while (!$encontrado) {
if (stripos(" ".$nombre[$k], ".")) {$k++;
} elseif (strlen($nombre[$k]) < 4) {// Aquí se tienen en cuenta los artículos// y preposiciones de los apellidosswitch (strtolower($nombre[$k])) {
case "de":$k++;break;
141
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
case "del":$k++;break;
case "la":$k++;break;
case "el":$k++;break;
case "las":$k++;break;
case "los":$k++;break;
case "da":$k++;break;
default:$encontrado = $k;break;
}} else {
$encontrado = $k;}
}$reference = strtolower(rtrim(ltrim($nombre[$encontrado])));
}// Si no existen comas, entonces se escoge la segunda palabra empezando// por el final que tenga más de 3 letras. También hay que tener cuidado// en esto, pues mucha gente suele poner el segundo apellido abreviado.// Hay que buscar puntos, en consecuencia.else {
$primer_apellido = FALSE;$segundo_apellido = FALSE;for ($k=(count($nombre) - 1);$k>-1;$k--) {
if (stripos(" ".$nombre[$k], ".") != FALSE) {if ($segundo_apellido == FALSE)
$segundo_apellido = $nombre[$k];else if ($primer_apellido == FALSE)
$primer_apellido = $nombre[$k];} else if (strlen($nombre[$k]) < 4){
// Aquí se tienen en cuenta los artículos y// preposiciones de los apellidosswitch (strtolower($nombre[$k])) {
case "de":break;
case "del":break;
case "la":break;
case "el":break;
case "las":break;
case "los":break;
case "da":break;
default:if ($segundo_apellido == FALSE)
$segundo_apellido = $nombre[$k];else if ($primer_apellido == FALSE)
$primer_apellido = $nombre[$k];break;
142
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}} else if ($segundo_apellido == FALSE) {
$segundo_apellido = $nombre[$k];} else if ($primer_apellido == FALSE) {
$primer_apellido = $nombre[$k];}
}if ((stripos($primer_apellido, ".") == FALSE) && (count($nombre) > 2))
$reference = $primer_apellido;else
$reference = $segundo_apellido;$reference = quita_tildes(strtolower(rtrim(ltrim($reference))));
}}return $reference;
}
//******************************************************************************// GENERA_ARRAYS: genera ararys que contienen las siglas de las publicaciones y// las palabras claves de éstas para la ulterior búsqueda de la publicación en// la entrada correspondiente del fichero de actualización.// Entrada: - Nombre del archivo que contiene la información de las revistas y// congresos => $pubs_file// - Array con los nombres de las tablas de la base de datos => $tablas_db// - Array para almacenar las palabras claves de los nombres de los// congresos => $congresos// - Array para almacenar las siglas de los nombres de los congresos =>// $siglas// - Array para almacenar las palabras claves de los nombres de las revistas// => $revistas// - Array para almacenar las siglas de los nombres de las revistas =>// $siglas_rev// Salida: - Ninguna//******************************************************************************function genera_arrays ($pubs_file, $tablas_db, &$congresos, &$siglas,
&$revistas, &$siglas_rev){
for ($i=0;$i<count($tablas_db);$i++) {if ($tablas_db[$i] == "congress") {
$j = 0; // Índice que se incrementa con cada congreso// Se modifica la tabla "congress" => cargamos en arrays// las abreviaturas y palabras claves de cada congreso.$archivo = fopen($pubs_file, "r"); // Apertura del fichero$inicio = FALSE;$salir = FALSE;if ($archivo) {
while (!feof($archivo)) {// Paso 1: Obtener una fila de la tabla (NOTA 1: fgets lee// hasta fin de fichero, fin de línea o cuando haya leído los// bytes indicados; NOTA 2: Cuidado con la longitud de las líneas,// porque pueden dar lugar a capturas erróneas de datos.unset($linea_nueva);$linea_nueva = fgets($archivo, 1024);// Buscamos el comienzo de los congresos => "::CONGRESS"if (stripos(" ".$linea_nueva, "::CONGRESS")) {
$inicio = TRUE;$salir = FALSE;
}// Si se encuentra otra línea que comience por "::" es que// se trata de otro tipo de publicación y dejamos de buscar datoselse if (stripos(" ".$linea_nueva, "::"))
$salir = TRUE;// Aquí se realiza el relleno de la tablaelse if (($inicio == TRUE) && ($salir == FALSE)) {
// Proseguimos si no se trata de un comentario
143
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if (stripos(" ".$linea_nueva, "//") == FALSE) {// Obtención de las siglas$siglas[$j] = strtok($linea_nueva, ";");// Obtención de las palabras clave del congreso para la// búsqueda del congreso$offset = strpos($linea_nueva, ";");$keywords = substr($linea_nueva, $offset+1);$word = strtok($keywords, "\t");$k = 0;while ($word != FALSE) {
//print $word." ";$congresos[$j][$k] = $word;$word = strtok("\t");$k++;
}//print "<br>";$j++;
}}
}}
}elseif ($tablas_db[$i] == "journals") {
$j = 0; // Índice que se incrementa con cada congreso// Se modifica la tabla "congress" => cargamos en arrays// las abreviaturas y palabras claves de cada revista.$archivo = fopen("pubs.txt", "r"); // Apertura del fichero$inicio = FALSE;$salir = FALSE;if ($archivo) {
while (!feof($archivo)) {// Paso 1: Obtener una fila de la tabla (NOTA1 : fgets lee// hasta fin de fichero, fin de línea o cuando haya leído los// bytes indicados; NOTA 2: Cuidado con la longitud de las líneas,// porque pueden dar lugar a capturas erróneas de datos.$linea = fgets($archivo, 1024);// Buscamos el comienzo de los congresos => "::JOURNALS"if (stripos(" ".$linea, "::JOURNALS")) {
$inicio = TRUE;$salir = FALSE;
}// Si se encuentra otra línea que comience por "::" es que// se trata de otro tipo de publicación y dejamos de buscar datoselseif (stripos(" ".$linea, "::"))
$salir = TRUE;// Aquí se realiza el relleno de la tablaelseif (($inicio == TRUE) && ($salir == FALSE)) {
// Proseguimos si no se trata de un comentarioif (stripos(" ".$linea, "//") == FALSE) {
// Obtención de las siglas$siglas_rev[$j] = strtok($linea, ";");// Obtención de las palabras clave del congreso// para la búsqueda de la revista$offset = strpos($linea, ";");$keywords = substr($linea, $offset+1);$word = strtok($keywords, "\t");$k = 0;while ($word != FALSE) {
$revistas[$j][$k] = $word;$word = strtok("\t");$k++;
}$j++;
}}
144
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}}
}}
}
//*****************************************************************// DO_UPLOAD: realiza la copia en el servidor del fichero de actualización.// Entrada: - Nombre del fichero => $fichero// - Directorio de subida => $upload_dir// - Dirección del fichero a subir => $upload_url//*****************************************************************function do_upload($fichero, $upload_dir, $upload_url) {
$temp_name = $_FILES[$fichero]['tmp_name'];$file_name = $_FILES[$fichero]['name'];$file_name = str_replace("\\","",$file_name);$file_name = str_replace("'","",$file_name);$file_path = $upload_dir.$file_name;
//Comprobación del nombre del ficheroif ( $file_name == "") {
$message = "Nombre de fichero especificado no válido.";return $message;
}
$result = move_uploaded_file($temp_name, $file_path);if (!chmod($file_path,0777))
$message = "cambio de permisos a 777 fallido.";else
$message = ($result)?"$file_name uploaded successfully." :"Something is wrong with uploading a file.";
return $message;}
//*****************************************************************// SEEK_FILE: busca un fichero en una ruta determinada.// Entrada: - Ruta de búsqueda (en caso de encontrar el fichero,// se inserta en esta variable la ruta del mismo => $path// - Fichero a buscar => $file// - Bandera que indica si se ha encontrado => $found//*****************************************************************function seek_file(&$path, $file, &$found){
// Cambia al directorio de búsquedaif (chdir($path)) {
// Si se consigue abrir....if ($gestor = opendir('.')) {
// Mientras que no se haya encontrado el fichero// y se pueda leer el siguiente ítem del directorio....while (($found == false) &&
(($res = readdir($gestor)) !== false)){
if (is_dir($res) && ($res != ".") && ($res != "..")) {$path = str_replace("\\", "/", getcwd()) . "/" . $res;seek_file($path, $file, $found);if ($found == false) {
chdir("../");$path = str_replace("\\", "/", getcwd());
}}else if (is_executable($res)) {
if (strpos($res, $file[PHP_OS]) !== false) {$found = true;
}}
145
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}}
}}
?>
10.4.1.9 FUNCTIONS .STEP3.PHP
<?php//************************************************************************// CIERRA_PAGINA: cierra las etiquetas "body" y "html" del documento.// Entrada: - Ninguna// Salida: - Ninguna//************************************************************************function cierra_pagina(){
echo "\t</body>\n";echo "</html>\n";
}
//************************************************************************// TRATA_TEXTO: procesa una cadena de texto, pasando las siglas de congresos y// abreviaturas de cadenas a mayúsculas, al igual que los números romanos y// otras palabras especiales// Entrada: - Cadena de texto que hay que tratar => $texto// - Array con las siglas de los congresos => $siglas_congreso// - Array con las siglas de las revistas => $siglas_revista// - Array con palabras especiales que deben ir en mayúsculas => $mayusc// - Array con números romanos => $numbers// Salida: - Cadena de texto tratada (por referencia) => $texto//************************************************************************function trata_texto(&$texto, $siglas_congreso, $siglas_revista, $mayusc,
$numbers){
// Se pone la primera letra de cada palabra en mayúsculas$texto = trim(ucwords(strtolower(str_replace("\"", "'", $texto))));// Se ponen en mayúsculas las siglas de los congresosfor ($p=0;$p<count($siglas_congreso);$p++) {
$pos = stripos(" ".$texto, $siglas_congreso[$p]);if (($pos > 0) && !ctype_alpha($texto[$pos-2]) &&
!ctype_alpha($texto[$pos+strlen($siglas_congreso[$p])-1])){
$texto = substr($texto,0,$pos-1) . $siglas_congreso[$p] .substr($texto,$pos+strlen($siglas_congreso[$p])-1,strlen($texto));
}}// Se ponen en mayúsculas las siglas de las revistasfor ($p=0;$p<count($siglas_revista);$p++) {
$pos = stripos(" ".$texto, $siglas_revista[$p]);if (($pos > 0) && !ctype_alpha($texto[$pos-2]) &&
!ctype_alpha($texto[$pos+strlen($siglas_revista[$p])-1]) &&(strlen($siglas_revista[$p]) > 1))
{$texto = substr($texto,0,$pos-1) . $siglas_revista[$p] .
substr($texto,$pos+strlen($siglas_revista[$p])-1,strlen($texto));}
}// Se ponen en mayúsculas las palabras especiales que deben asífor ($p=0;$p<count($mayusc);$p++) {
$pos = stripos(" ".$texto, $mayusc[$p]);if (($pos > 0) && !ctype_alpha($texto[$pos-2]) &&
!ctype_alpha($texto[$pos+strlen($mayusc[$p])-1])){
146
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$texto = substr($texto,0,$pos-1) . $mayusc[$p] .substr($texto,$pos+strlen($mayusc[$p])-1,strlen($texto));
}}// Se ponen en mayúsculas los números romanosfor ($p=0;$p<count($numbers);$p++) {
$pos = stripos(" ".$texto, $numbers[$p]);if (($pos > 0) && !ctype_alpha($texto[$pos-2]) &&
!ctype_alpha($texto[$pos+strlen($numbers[$p])-1])){
$texto = substr($texto,0,$pos-1) . $numbers[$p] .substr($texto,$pos+strlen($numbers[$p])-1,strlen($texto));
}}$texto = trim($texto);
}
//************************************************************************// BUSCA_REVISTA: busca una publicación en la colección de revistas disponible.// Entrada: - Nombres de los campos de la publicación (tabla, nombre, etc) =>// $fields// - Valores de los campos contenidos en $fields => $fields_values// - Array con las palabras claves de los nombres de revistas => $journals// - Array con los acrónimos de las revistas => $journals_acr// - Bandera que se pone a 1 si se encuentra al menos una revista =>// $insertado// Salida: - Cadena final para insertar en la referencia => $ref_journal// - Bandera que indica si se ha encontrado algún congreso// coincidente (por referencia) => $insertado//************************************************************************function busca_revista($fields, $fields_values, $journals,
$journals_acr, &$insertado){
unset($revista);$insertado = false;// Obtenemos el nombre de la revistafor ($k=0;$k < count($fields);$k++) {
if ($fields[$k] == "journal")$revista = $fields_values[$k];
}// Pasamos a minúsculas y quitamos las tildes$revista = quita_tildes(strtolower($revista));// Se busca la revista en la lista de revistas de que se dispone.$salir = FALSE;$k = 0;$ref_journal = "";while ($salir == FALSE) {
unset($encontrado);$encontrado = TRUE;// Primero se buscan las palabras clavesfor ($l=0;$l<count($journals[$k]);$l++){
if (!($encontrado &&(stripos(" ".$revista." ", trim($journals[$k][$l])) != FALSE)))
{$encontrado = FALSE;
}}if ($encontrado == TRUE) {
// Si ya se ha añadido alguna revista, se añade un guión separadorif ($insertado)
$ref_journal = $ref_journal . "-";$insertado = TRUE;$ref_journal = $ref_journal . strtoupper($journals_acr[$k]);
}
147
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
if ($k < (count($journals) - 1))$k++;
else$salir = TRUE;
}return $ref_journal;
}
//************************************************************************// BUSCA_CONGRESO: busca una publicación en la colección de congresos disponible.// Entrada: - Nombres de los campos de la publicación (tabla, nombre, etc) =>// $fields// - Valores de los campos contenidos en $fields => $fields_values// - Array con las palabras claves de los nombres de revistas => $congress// - Array con los acrónimos de las revistas => $congress_acr// - Bandera que se pone a 1 si se encuentra al menos una revista => $flag// Salida: - Cadena final para insertar en la referencia => $ref_congress// - Bandera que se pone a 1 si se encuentra al menos una revista// (por referencia) => $flag//************************************************************************function busca_congreso($fields, $fields_values, $congress,
$congress_acr, &$flag){
unset($congreso);// Obtenemos el nombre del congresofor ($k=0;$k < count($fields);$k++) {
if ($fields[$k] == "booktitle")$congreso = $fields_values[$k];
}// Pasamos a minúsculas y quitamos las tildes. Añadimos un espacio al comienzo// porque si coincide la búsqueda justamente al comienzo de la cadena,// "stripos" devuelve la posición 0, que se interpreta como FALSE.$congreso = quita_tildes(strtolower($congreso));// Aquí se busca el congreso en la lista de congresos de que se dispone. Si no// se encuentra el congreso de la entrada seleccionada, se muestra en pantalla// un mensaje de error y un formulario de relleno del nuevo congreso$salir = FALSE;$flag = FALSE;$k = 0;$ref_congress = "";while ($salir == FALSE) {
unset($encontrado);$encontrado = TRUE;// Primero se buscan las palabras clavesfor ($l=0;$l<count($congress[$k]);$l++)
if (stripos(" ".$congreso, trim($congress[$k][$l])) == FALSE)$encontrado = FALSE;
if ($encontrado == TRUE) {// Si ya se ha añadido algún congreso, se añade un guión separadorif ($flag)
$ref_congress = $ref_congress . "-";$flag = TRUE;$ref_congress = $ref_congress . strtoupper($congress_acr[$k]);
}if ($k < (count($congress) - 1))
$k++;else
$salir = TRUE;}// Se realiza un filtrado por si hay siglas duplicadasfor ($l=0;$l<count($congress_acr);$l++) {
if ($congress_acr[$l] != "") {// Si se encuentran dos o más coincidencias...if (substr_count($ref_congress, $congress_acr[$l]) > 1) {
$salir = FALSE;
148
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$subcadena = $ref_congress."-";while ($salir == FALSE) {
// Hay que tener cuidado y eliminar solamente una de ellas$pos = strripos($subcadena, $congress_acr[$l]);$seccion = substr($ref_congress."-", $pos);
$sustituta = str_replace($congress_acr[$l]."-", "", $seccion);if ($sustituta != $seccion) {
$salir = TRUE;$sustituta = substr($subcadena, 0, $pos) . $sustituta;
} else {$subcadena = substr($subcadena, 0, $pos);
}}if ($sustituta[strlen($sustituta)-1] == "-")
$ref_congress = substr($sustituta, 0, strlen($sustituta)-1);}
}}return $ref_congress;
}
//************************************************************************// GET_HTML_CONTENT: obtiene el contenido de una página web para un análisis// posterior.// Entrada: - Array con las direcciones webs que se han de analizar => $urls// Salida: - Array con el contenido de texto que contienen las direcciones de// entrada => $contenido//************************************************************************function get_html_content($urls){
for ($p=0; $p<count($urls); $p++){
// Apertura del fichero con los hiperenlaces$descriptor = fopen($urls[$p], "r");$html_content = "";while (!feof($descriptor)) {
// Obtención del contenido de la dirección$html_content .= fread($descriptor, 8192);
}fclose($descriptor);$contenido[$p] = $html_content;
}return $contenido;
}
//************************************************************************// GET_PDF: busca una publicación en la colección de revistas disponible.// Entrada: - Url del pdf capturada del hiperenlace => $url_pdf// - Url del sitio web que contiene el hiperenlace => $url_site// Salida: - Ruta del fichero pdf => $final_pdf_url//************************************************************************function get_pdf($url_pdf, $url_site){
// Hay que preparar la dirección del fichero$num_levels = substr_count($url_pdf, "../");$pos_site = strlen($url_site);$pos_site = strrpos(substr($url_site, 0, $pos_site), "/");for ($k=0; $k<$num_levels; $k++)
$pos_site = strrpos(substr($url_site, 0, $pos_site), "/");if ($num_levels > 0)
$pos_pdf = strrpos($url_pdf, "../") + 3;else
$pos_pdf = 0;$final_pdf_url = substr($url_site, 0, $pos_site+1) .
149
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
substr($url_pdf, $pos_pdf);
// Si se ha encontrado una dirección adecuada....if ($final_pdf_url != ""){
// El fichero pdf se debe poder leer; en caso contrario,// se eliminará la ruta$desc_read = fopen($final_pdf_url, "rb");if ($desc_read == FALSE)
$final_pdf_url = "";}return $final_pdf_url;
}
//************************************************************************// BUSCA_PUBLICACION_WEB: busca una publicación en la colección de revistas// disponible// Entrada: - Contenido de las direcciones web facilitadas => $html_contents// - Array con las direcciones webs facilitadas por el usuario => $urls// - Nombre de la publicación => $titulo// - Siglas de los congresos => $siglas_congreso// - Acrónimos de las revistas => $siglas_revista// - Array con palabras especiales que deben ir en mayúsculas => $mayusc// - Array con números romanos que deben ir en mayúsculas => $numbers// - Array en el que se insertarán las rutas y porcentajes de los// ficheros pdfs que se encuentren => $pdf// Salida: - Array con las rutas de los ficheros pdf => $pdf//************************************************************************function busca_publicacion_web($html_contents, $urls, $titulo,
$siglas_congreso, $siglas_revista, $mayusc, $numbers, &$pdf){
$found = false;$n_pdf = 0;$html_tags = array("<b>", "</b>", "<i>", "</i>", "<ul>", "</ul>", "<ol>",
"</ol>", "<li>", "</font>", "<br />", "<br />");$html_chars = array(9, 10, 13);$p = 0;while ($p < count($html_contents)){
$pos_ini = 0;// Bucle de búsqueda del hiperlink del pdfdo {
// Primera ocurrencia del inicio de la etiqueta hyperlink$pos_ini = stripos($html_contents[$p], "<a href=\"", $pos_ini);if ($pos_ini !== false) {
// Primera ocurrencia del final de la etiqueta hyperlink$pos_fin = stripos($html_contents[$p], "</a>", $pos_ini);if ($pos_fin !== false) {
// Se extrae la etiqueta de hyperlink$hyperlink = substr($html_contents[$p], $pos_ini,
$pos_fin-$pos_ini);// Se decodifican los caracteres html especiales (p.e., ")$hyperlink = htmlspecialchars_decode($hyperlink);// Se quitan los retornos de carro y otros caracteres especialesfor ($i=0; $i<count($html_chars); $i++)
$hyperlink = str_replace(chr($html_chars[$i]), "", $hyperlink);// Se quitan las etiquetas de formato de texto htmlfor ($i=0; $i<count($html_tags); $i++) {
if ($html_tags[$i] == "</font") {if (($posicion1 = stripos($hyperlink, "<font")) !== false) {
$posicion2 = strpos($hyperlink, ">", $posicion+1);$hyperlink = substr($hyperlink, 0, $posicion1) .
substr($hyperlink, $posicion2+1,strlen($hyperlink)-$posicion2);
}
150
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}$hyperlink = str_replace($html_tags[$i], "", $hyperlink);
}// Se quitan los espacios repetidos$espacio = false;for ($i=0; $i<strlen($hyperlink); $i++) {
if (($hyperlink[$i] == " ") && ($espacio == true))$hyperlink = substr($hyperlink, 0, $i-1) .
substr($hyperlink, $i+1);else if ($hyperlink[$i] == " ")
$espacio = true;else
$espacio = false;}// Se busca el comienzo del nombre de la publicación$pos_i_tit = strpos($hyperlink, ">");while(($pos_i_tit < strlen($hyperlink)) &&
!ctype_alnum($hyperlink[$pos_i_tit]) &&($hyperlink[$pos_i_tit] != "<"))
{$pos_i_tit++;
}// Se busca el fin del nombre de la publicación$pos_f_tit = strlen($hyperlink);while(($pos_i_tit < strlen($hyperlink)) &&
!ctype_alnum($hyperlink[$pos_f_tit]) &&($hyperlink[$pos_f_tit] != ">"))
{$pos_f_tit--;
}$hyperlink_titulo = trim(substr($hyperlink, $pos_i_tit,
$pos_f_tit-$pos_i_tit+1));// Se permite un error máximo de 5 letrasif (abs(strlen($hyperlink_titulo)-strlen($titulo)) < 5) {
$porcentaje = 0;trata_texto($hyperlink_titulo, $siglas_congreso,
$siglas_revista, $mayusc, $numbers);similar_text($titulo, $hyperlink_titulo, $porcentaje);//Si se encuentra el título en esta etiqueta...if ((stripos($hyperlink, $titulo) > 0) || ($porcentaje > 90)) {
//... obtenemos la ruta completa del pdf...$pos_ini += 9;$pos_fin = stripos($html_contents[$p], "\"", $pos_ini);$pdf_url = substr($html_contents[$p], $pos_ini,
$pos_fin - $pos_ini);$pdf_url = get_pdf($pdf_url, $urls[$p]);// ... y en caso de que éste sea accesibleif ($pdf_url != "") {
// ... asignamos la nueva ruta$pdf[$n_pdf][0] = $pdf_url;// ... y obtenemos el porcentaje de similitud$pdf[$n_pdf][1] = $porcentaje;$found = true;$n_pdf++;
}}
}$pos_ini = $pos_fin;
}else
$pos_ini++;}
} while ($pos_ini > 0);
$p++;
151
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}if ($found == false) {
$pdf[$n_pdf][0] = "";$pdf[$n_pdf][1] = "";
}}
//************************************************************************// REMOTE_FILE_SIZE: obtiene el tamaño de un fichero// Entrada: - Url del fichero cuyo tamaño se desea obtener => $url// Salida: - Cadena con el tamaño del fichero => $return//************************************************************************function remote_file_size ($url) {
$head = "";$url_p = parse_url($url);$host = $url_p["host"];$path = $url_p["path"];
$fp = fsockopen($host, 80, $errno, $errstr, 20);if(!$fp) { return false; } else {
fputs($fp, "HEAD ".$url." HTTP/1.1\r\n");fputs($fp, "HOST: dummy\r\n");fputs($fp, "Connection: close\r\n\r\n");$headers = "";while (!feof($fp)) {
$headers .= fgets ($fp, 128);}
}fclose ($fp);$return = false;$arr_headers = explode("\n", $headers);foreach($arr_headers as $header) {
$s = "Content-Length: ";if(substr(strtolower ($header), 0, strlen($s)) == strtolower($s)) {
$return = substr($header, strlen($s));break;
}} return $return;
}
//************************************************************************// ABRE_FORMULARIO: inserta la etiqueta HTML de apertura de un formulario// Entrada: - Ninguna// Salida: - Ninguna//************************************************************************function abre_formulario(){
echo "\t\t<form name='upload' id='upload' action='paso3.php' ". "ENCTYPE='multipart/form-data' method='POST'>\n";
}
//************************************************************************// CIERRA_FORMULARIO: inserta la etiqueta HTML de cierre de un formulario// Entrada: - Ninguna// Salida: - Ninguna//************************************************************************function cierra_formulario(){
echo "\t\t</form>\n";}
152
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
//************************************************************************// IMPRIME_RESULTADOS: imprime en el documento actual del navegador los// resultados de la búsqueda del sistema, esto es, cada una de las entradas// analizadas junto con los datos extraídos.// Entrada: - Array con los valores de los campos devueltos del análisis de// todos los datos facilitados por el usuario => $campos_def// - Array con los valores de los campos adicionales resultado del// análisis de todos los datos facilitados por el usuario =>// $campo_def_add// - Array con los nombres de los campos de las tablas de la base de datos// => $campos_tablas// - Array con los mensajes de error que se pueden mostrar =>// $mensajes_error// - Array que indica cuál de las urls de pdfs es la que se encuentra// seleccionada actualmente => $mark// Salida: - Ninguna//************************************************************************function imprime_resultados($campos_def, $campo_def_add,
$campos_tablas, $mensajes_error, $mark){
$def_offset = count($campo_def_add);for ($def_count=0; $def_count<count($campos_def); $def_count++){
echo "\t\t\t<table border='0' width='100%' >\n";// Impresión del nombre de la tablaecho "\t\t\t\t<tr>\n\t\t\t\t\t<td>Tabla:</td>\n\t\t\t\t\t<td>" .
$campos_def[$def_count][$campo_def_add["tabla"]] ."</td>\n\t\t\t\t</tr>\n";
// Impresión de los campos que pertenecen lícitamente a la tablafor ($j=0; $j<count($campos_def[$def_count])-$def_offset; $j++){
if ($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j] != "id")
{echo "\t\t\t\t<tr>\n";echo "\t\t\t\t\t<td valign=\"top\">" .
ucwords($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j]). ":</td>\n";
echo "\t\t\t\t\t<td>";if
($campos_tablas[$campos_def[$def_count][$campo_def_add["tabla"]]][$j] =="abstract")
{echo "<textarea name='field" . $def_count . "-" .
($j+$def_offset) . "' cols=\"90\" rows=\"5\">" .$campos_def[$def_count][$j+$def_offset] . "</textarea>";
}else
echo "<input type='text' name='field" . $def_count . "-" .($j+$def_offset) . "' size='120' value=\"" .$campos_def[$def_count][$j+$def_offset] . "\" />";
echo "</td>\n";echo "\t\t\t\t</tr>\n";
}}// Impresión del campo "autores"echo "\t\t\t\t<tr>\n";echo "\t\t\t\t\t<td>Autores:</td>\n";echo "\t\t\t\t\t<td>";echo "<input type='text' name='field" . $def_count . "-" .
$campo_def_add["authors"] . "' size='120' value=\"" .ucwords(strtolower($campos_def[$def_count][$campo_def_add["authors"]])) ."\" />";
153
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
echo "</td>\n";echo "\t\t\t\t</tr>\n";// Impresión del campo correspondiente al fichero pdfecho "\t\t\t\t<tr>\n";echo "\t\t\t\t\t<td valign=top>PDF File:</td>\n";$n_pdfs = count($campos_def[$def_count][$campo_def_add["pdf"]]);echo "\t\t\t\t\t<td>\n";$porcentaje = 0;$pos = -1;if ($n_pdfs > 1) {
if (!isset($mark[$def_count][$campo_def_add["pdf"]][0])) {for ($k=0; $k<$n_pdfs; $k++){
if ($campos_def[$def_count][$campo_def_add["pdf"]][$k][1] > $porcentaje)
{$porcentaje =
$campos_def[$def_count][$campo_def_add["pdf"]][$k][1];$pos = $k;
}}
}else {
for ($k=0; $k<$n_pdfs; $k++){
if ($mark[$def_count][$campo_def_add["pdf"]][$k] == 1) {$pos = $k;
}}
}}for ($k=0; $k<$n_pdfs; $k++) {
$mensaje = "";// Si hay varios enlaces de ficheros, entonces// se muestran botones tipo radioif ($n_pdfs > 1) {
$mensaje = "\t\t\t\t\t\t<input type='radio' id='pdf_check" .$def_count . "-" . $k . "' name='pdf_check" . $def_count ."' value='" . $k . "'";
if ($k == $pos)$mensaje .= " checked";
$mensaje .= " />\n";}// Se añade el campo de texto con la dirección del pdf$mensaje .= "\t\t\t\t\t\t<input type='text' id='url" . $def_count .
"-" . $k . "' name='url" . $def_count . "-" . $k . "' value=\"" .str_replace("\\\\", "\\",
$campos_def[$def_count][$campo_def_add["pdf"]][$k][0]). "\" size='95' onclick=\"change('" . $def_count . "', '" .$k . "', 'url');\" />\n";
// En caso de tratarse de un fichero que facilita el usuario// manualmente no se muestra porcentaje de coincidencia algunoif ($campos_def[$def_count][$campo_def_add["pdf"]][$k][1] == "0") {
$mensaje .= "\t\t\t\t\t\t<span id='percent_" . $def_count ."_" . $k . "'>( Custom )</span>\n";
$mensaje .= "\t\t\t\t\t\t<input type='button' id='change_pdf_bt_" .$def_count . "_" . $k . "' " . "value='Cambiar' " ."onclick=\"change_pdf_file('" . $def_count . "', '" .$k . "', 'url');\" />" . "<br />\n";
}// En cualquier otro caso, se muestra el porcentaje de coincidenciaelse {
$mensaje .= "\t\t\t\t\t\t<span id='percent_" .$def_count . "_" . $k . "'>(" .sprintf("%.2f",
154
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$campos_def[$def_count][$campo_def_add["pdf"]][$k][1]) ." %)</span>\n";
$mensaje .= "\t\t\t\t\t\t<input type='button' id='change_pdf_bt_" .$def_count . "_" . $k . "' " . "value='Cambiar' " ."onclick=\"change_pdf_file('" . $def_count . "', '" .$k . "', 'url');\" />" . "<br />\n";
}echo $mensaje;
}echo "\t\t\t\t\t\t<input type='checkbox' id='req_pdf" . $def_count .
"' name='req_pdf" . $def_count. "' value='1' ";
if (isset($_POST["req_pdf" . $def_count]))echo "checked ";
echo "/>No deseo especificar ningún fichero .pdf<br />\n";echo "\t\t\t\t\t</td>\n";echo "\t\t\t\t</tr>\n";set_form($formulario);
// Si ha habido errores, entonces se muestran los// campos de texto correspondientes más los fallos$contador = 0;$tok = strtok($campos_def[$def_count][$campo_def_add["error"]], "*");while ($tok !== false) {
$tokens[$contador] = $tok;$contador++;$tok = strtok("*");
}if ($campos_def[$def_count][$campo_def_add["error"]] != "") {
for ($n=0; $n<count($tokens); $n++) {switch ($tokens[$n]) {
case "revista":case "congreso":
echo "\t\t\t\t<tr>\n";echo "\t\t\t\t\t<td valign=top>Error:</td>\n";echo "\t\t\t\t\t<td bgcolor=red>" .
$mensajes_error[$tokens[$n]] . "</td>\n";echo "\t\t\t\t</tr>\n";echo "\t\t\t\t\t<td></td>\n";echo "\t\t\t\t\t<td>\n\t\t\t\t\t<table>\n";echo "\t\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t\t<td>Descripción:</td>\n";echo "\t\t\t\t\t\t\t\t<td><input type='text' name='comment" .
$def_count . "' size='80' /><br /></td>\n";echo "\t\t\t\t\t\t\t</tr>\n";echo "\t\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t\t<td>Palabras clave:</td>\n";echo "\t\t\t\t\t\t\t\t<td><input type='text' name='keywords" .
$def_count . "' size='80' /><br /></td>\n";echo "\t\t\t\t\t\t\t</tr>\n";echo "\t\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t\t<td>Siglas:</td>\n";echo "\t\t\t\t\t\t\t\t<td><input type='text' name='abbrev" .
$def_count . "' size='80' /><br /></td>\n";echo "\t\t\t\t\t\t\t</tr>\n";echo "\t\t\t\t\t\t\t<tr>\n";echo "\t\t\t\t\t\t\t\t<td colspan=2><input type=hidden " .
"name='tabla_modif" . $def_count."' value='" .$campos_def[$def_count][$campo_def_add["tabla"]]."' /><br /></td>\n";
echo "\t\t\t\t\t\t\t</tr>\n";echo "\t\t\t\t\t\t</table>\n\t\t\t\t\t</td>\n";break;
case "fecha":case "autores":
155
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
case "titulo":echo "\t\t\t\t<tr>\n";echo "\t\t\t\t\t<td valign=top>Error:</td>\n";echo "<td bgcolor=red>" . $mensajes_error[$tokens[$n]] .
"</td>\n";echo "\t\t\t\t</tr>\n";break;
default:break;
}}
}unset($tokens);if ($campos_def[$def_count][$campo_def_add["error"]] == "") {
// Solamente se muestra la posibilidad de "entrada completa"// si no hay erroresecho "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=2><input " .
"type='checkbox' id='finished" . $def_count . "' name='finished" .$def_count . "' /><label for=\"finished" . $def_count ."\">Active esta casilla si esta entrada ya está completa" ."</label></td>\n";
echo "\t\t\t\t</tr>\n";// También se muestra una casilla para el caso en que no se// quiera añadir una entradaecho "\t\t\t\t<tr>\n\t\t\t\t\t<td colspan=2><input " .
"type='checkbox' id='nondesired" . $def_count . "' name='nondesired" .$def_count . "' /><label for=\"nondesired" . $def_count ."\">En caso de no querer añadir esta entrada, active esta casilla" ."</label></td>\n";
echo "\t\t\t\t</tr>\n";}echo "\t\t\t</table>\n\t\t\t<br />\n";echo "\t\t\t<hr noshade size='8' />\n";
}}
//************************************************************************// SET_FORM: activa una bandera que indica si hay que mostrar el formulario de// actualización de la base de datos o no.// Entrada: - Bandera => $formulario// Salida: - Ninguna//************************************************************************function set_form(&$formulario){
if ($formulario == 0)$formulario = 1;
}
//************************************************************************// CODIGO_JAVASCRIPT: inserta funciones javascript (una abre la nueva ventana// de copia de ficheros, y las restantes se utilizan para cambiar la// naturaleza del campo de entrada de selección de fichero).// Entrada: - Bandera que indica si el formulario de actualización de la base de// datos se ha de mostrar => $formulario// - Ruta del fichero que almacena los nombres de los ficheros pdf a// subir al servidor => $log_file// Salida: - Ninguna//************************************************************************function codigo_javascript($formulario, $log_file){
print "\t\t<script type=\"text/javascript\">";print "\n\t\t\tvar winName=\"Progreso de la copia de ficheros\"";print "\n\t\t\tvar sec_window;";print "\n\t\t\tfunction Abrir_Ventana(theURL, w, h) {" .
"\n\t\t\t\tvar winl = (screen.width-w)/2;" .
156
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
"\n\t\t\t\tvar wint = (screen.height-h)/2;" ."\n\t\t\t\tif (winl < 0) winl = 0;" ."\n\t\t\t\tif (wint < 0) wint = 0;" ."\n\t\t\t\tvar windowprops =\"top=\"+wint+\",left=\"+winl+\"," ."toolbar=no,location=no,status=no, " ."menubar=no,scrollbars=no, resizable=no,width=\" + w + \",height=\" + h;" ."\n\t\t\t\tsec_window = window.open(theURL,winName,windowprops);" ."\n\t\t\t}\n";
print "\t\t\tfunction change_pdf_file(id1, id2, str)\n" ."\t\t\t{\n" ."\t\t\t\tvar name = str + id1 + \"-\" + id2;\n" ."\t\t\t\tvar object = document.getElementById(name);\n" ."\t\t\t\tobject.type = \"file\";\n" ."\t\t\t\tobject.size = \"107\";\n" ."\t\t\t\tdocument.getElementById(\"change_pdf_bt_\" + id1 + \"_\" + id2)." ."style.visibility = \"hidden\";\n" ."\t\t\t\tdocument.getElementById(\"percent_\" + id1 + \"_\" + id2)." ."innerHTML = \"\";\n" ."\t\t\t}\n";
print "\t\t\tfunction change(id1, id2, str)\n" ."\t\t\t{\n" ."\t\t\t\tvar name = str + id1 + \"-\" + id2;\n" ."\t\t\t\tvar object = document.getElementById(name);\n" ."\t\t\t\tdocument.getElementById(name).onChange = change;\n" ."\t\t\t\tif (object.type == \"file\")\n" ."\t\t\t\t{\n" ."\t\t\t\t\tvar url = object.value;\n" ."\t\t\t\t\tobject.type = \"text\";\n" ."\t\t\t\t\tobject.value = url;\n" ."\t\t\t\t\tdocument.getElementById(\"change_pdf_bt_\" + id1 + \"_\" + " ."id2).style.visibility = \"visible\";\n" ."\t\t\t\t}\n" ."\t\t\t}\n";
print "\t\t</script>\n";// En caso de que sea la primera vez que se ejecuta la aplicación, se procede// al borrado del contenido del fichero que contiene la información de los// nombres de los pdfsif ($formulario == 0) {
$desc_write = fopen($log_file, "w");if ($desc_write != false)
fclose($desc_write);}
}
//************************************************************************// IMPRIME_MENSAJE_BIENVENIDA: muestra información concerniente al paso// 3 de la actualización de la base de datos.// Entrada: - Bandera que indica si el formulario de actualización de la base de// datos se ha de mostrar => $formulario// - Ruta del fichero que almacena los nombres de los ficheros pdf a// subir al servidor => $log_file// Salida: - Ninguna//************************************************************************function imprime_mensaje_bienvenida($formulario, $log_file){
print "<html>\n";print "\t<head>\n";codigo_javascript($formulario, $log_file);print "\t</head>\n";print "\t<body>\n";print "\t\t<h2>Actualización automática de la Base de Datos</h2><br />" .
"\n\t\t<h3>Paso 3: Introducción de los datos de las publicaciones en caso" ." de no tener constancia de las mismas.</h3><br />A continuación se " ."muestran, separados mediante barras horizontales, las entradas de los " ."ficheros indicados en el paso 1 que no concuerdan con ninguna de las " .
157
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
"publicaciones de que se disponen en este momento.<br />Asimismo, se le " ."facilita un formulario justo debajo de la entrada no registrada para " ."que añada el nombre de la publicación, sus siglas y el conjunto de " ."palabras claves que se emplearán en la búsqueda posteriormente.<br />" ."<br />";
print "NOTA 1: si la publicación aparece repetida varias veces, solamente " ."debe introducir una vez los datos en los formularios.<br />";
print "NOTA 2: inserte las palabras clave separadas por espacios simples " ."(ni tabuladores ni retornos de carro).<br />";
print "NOTA 3: para registrar una nueva publicación se requieren los tres " ."campos citados anteriormente OBLIGATORIAMENTE.<br />";
print "NOTA 4: si modifica el nombre de los autores, el año o el título de " ."la publicación, asegúrese de modificar también la referencia, así como " ."de verificar la exactitud de los ficheros pdfs encontrados, pues se " ."realizaron con la referencia errónea.<br />";
print "NOTA 5: no añada letras al final de las referencias. En caso de que " ."ya exista una entrada similar, el sistema añadirá la letra pertinente " ."al final de la referencia en cuestión.<br /><br /><br />\n";
}
//************************************************************************// ELIMINA_ENTRADA: borra una fila del array que contiene los valores de los// campos correspondientes a las entradas que se han de insertar en la base// de datos.// Entrada: - Array con los valores de los campos para la actualización =>// $campos_def// - Índice de la entrada que se ha de eliminar => $entrada// Salida: - Array con la entrada eliminada//************************************************************************function elimina_entrada($campos_def, $entrada){
$new_ind = 0;for ($i=0; $i<count($campos_def); $i++) {
if ($i != $entrada) {$nueva_tabla[$new_ind] = $campos_def[$i];$new_ind++;
}}return $nueva_tabla;
}
//************************************************************************// CREA_ORDEN_SQL: crea una cadena con una sentencia SQL para actualizar una// nueva entrada de la base de datos.// Entrada: - Array con los valores de los campos de la entrada a actualizar =>// $entrada// - Campos adicionales necesarios para la actualización => $campo_def_add// - Nombres de los campos de la tabla a actualizar => $campos_tablas// Salida: - Cadena con la orden SQL => $sentencia_SQL//************************************************************************function crea_orden_sql($entrada, $campo_def_add, $campos_tablas){
// Creación de la orden SQL$sentencia_SQL = "INSERT INTO " . $entrada[$campo_def_add["tabla"]] . " (";$valores = "";for ($k=0; $k<count($campos_tablas[$entrada[$campo_def_add["tabla"]]]); $k++){
if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$k] != "id"){
$sentencia_SQL .= $campos_tablas[$entrada[$campo_def_add["tabla"]]][$k];$valores .= "\"" . $entrada[$k+count($campo_def_add)] . "\"";if ($k != (count($campos_tablas[$entrada[$campo_def_add["tabla"]]]) - 1)){
$sentencia_SQL .= ",";$valores .= ",";
158
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}}
}$sentencia_SQL .= ") VALUES (" . $valores . ");";return $sentencia_SQL;
}
//************************************************************************// BUSCA_ENTRADA_SIMILAR: busca una entrada dada en la tabla que se va a// actualizar para comprobar si ya existe otra entrada idéntica.// Entrada: - Objeto con los resultados de una consulta SQL solicitando todos// los títulos y referencias de las publicaciones de la tabla => $resultado// - Array con los valores de los campos de la entrada a actualizar =>// $entrada// - Campos adicionales necesarios para la actualización => $campo_def_add// - Nombres de los campos de la tabla a actualizar => $campos_tablas// - Número de referencias similares a la buscada => $num_refs// Salida: - Bandera que indica si se han encontrado entradas similares en// la base de datos => $salir// - Número de referencias encontradas similares a la buscada// (por referencia) => $num_refs//************************************************************************function busca_entrada_similar($resultado, $entrada,
$campo_def_add, $campos_tablas, &$num_refs){
$ind_title = -1;$ind_ref = -1;$salir = false;// Se buscan las posiciones del título y la referenciafor ($k=0; $k<count($campos_tablas[$entrada[$campo_def_add["tabla"]]]); $k++){
if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$k] == "title")$ind_title = $k + count($campo_def_add);
if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$k] == "reference")$ind_ref = $k + count($campo_def_add);
}while ($row = mysql_fetch_assoc($resultado)) {
if (strcasecmp(trim($row["title"]), $entrada[$ind_title]) == 0){
// Se toma la referencia de la BD y se quitan las posibles// letras al final debidas a referencias repetidas$terminar = FALSE;$m = strlen($row["reference"]);while (($terminar != TRUE) && ($m > 0)) {
if (ctype_digit($row["reference"][$m]))$terminar = TRUE;
else$m--;
}$ref_db = substr($row["reference"], 0, $m + 1);// En caso de que coincidan el título y la referencia// se toma como entrada idénticaif (strcasecmp(trim($ref_db),
trim($entrada[$ind_ref])) == 0){
$salir = TRUE;}
}if (stripos(trim($row["reference"]),
trim($entrada[$ind_ref])) !== false){
$num_refs++;}
}// Devuelve TRUE en caso de que exista una entrada
159
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// similar en la base de datos; FALSE en caso contrarioreturn $salir;
}
//************************************************************************// OBTAIN_AUTHORS: separa los nombres de los autores en palabras sueltas y las// inserta en un array.// Entrada: - Cadena con los nombres de los autores => $autores// - Separador de los nombres de autores => $separador// Salida: - Array con los nombres de los autores separados y a su vez cada// nombre separado en palabras => $authors//************************************************************************function obtain_authors($autores, $separador){
$tok = strtok ($autores, $separador);$num_tok = 0;while ($tok !== false) {
$token[$num_tok] = $tok;$num_tok++;$tok = strtok($separador);
}// Se obtiene el número de autores ===> $num_tok// Para cada autor, se separan todas las palabras del// nombre en tokens ===> $autores$num_autores = $num_tok;for ($j=0;$j<$num_autores;$j++) {
$tok = strtok ($token[$j]," ");$num_tok = 0;while ($tok !== false) {
$authors[$j][$num_tok] = quita_tildes(strtolower(trim($tok)));$num_tok++;$tok = strtok(" ");
}}return $authors;
}
//************************************************************************// BUSCA_AUTOR: busca un autor determinado en el conjunto de autores// pertenecientes al grupo de control predictivo.// Entrada: - Autor de la publicación => $autor// - Autores del grupo de control predictivo => $autores_grupo// Salida: - Índice para buscar el autor en el array de autores del grupo// (vale -1 si no se encuentra) => $people//************************************************************************function busca_autor($autor, $autores_grupo){
$fin_busqueda = false;$encontrado = true;$people = -1;$k = 0;while (($fin_busqueda == FALSE) && ($k < count($autores_grupo))) {
$encontrado = TRUE;// Bucle para cada palabra del nombre del autor de la publicación// "autor" -> autor de la publicación;// "autores_grupo" -> autores del grupo de control predictivofor ($l=0;$l<count($autor);$l++) {
// Buscamos la palabraif (($encontrado == TRUE) &&
(stripos(" ".$autores_grupo[$k], $autor[$l]) == FALSE)){
// Si no se ha encontrado, se comprueba si hay alguna abreviaturaif (stripos($autor[$l], ".")) {
// Abreviatura en el autor de la publicación// Obtención de la inicial de la abreviatura
160
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
$inicial = strtok($autor[$l], ".");$word = strtok ($autores_grupo[$k]," ");$salir = FALSE;while (($word !== false) && ($salir != TRUE)) {
if (trim($word) == ($inicial."."))$salir = TRUE;
$word = strtok(" ");}if ($salir !== TRUE)
$encontrado = FALSE;} elseif (stripos($autores_grupo[$k], ".")) {
// Abreviatura en el autor del grupo$word = strtok ($autores_grupo[$k]," ");$salir = FALSE;while (($word !== false) && ($salir != TRUE)) {
if (stripos($word, "."))$salir = TRUE;
$word = strtok(" ");}// Obtención de la inicial de la abreviatura$inicial = trim($word);if ($autor[$l] != ($inicial."."))
$encontrado = FALSE;} else {
// Si no hay abreviaturas y no se ha encontrado// la palabra, es que no se trata de este autor$encontrado = FALSE;
}}
}if ($encontrado == TRUE) {
$people = $k + 1;$fin_busqueda = TRUE;
}$k++;
}return $people;
}
//************************************************************************// CREA_ORDEN_SQL_AUTOR: crea la orden SQL para actualizar la tabla de autores// tras haber actualizado la tabla de la publicación.// Entrada: - Orden SQL correspondiente a la actualización de la publicación// de este autor => $orden_SQL// - Tipo de la publicación => $tipo// - Id del autor en la tabla "people" de autores del grupo => $people// - Id devuelto al insertar la publicación en la tabla => $id// - Orden del autor => $i// - Nombre del autor en caso que no pertenezca al grupo => $autor// - Jobcode (solamente cuando sea PHD ó PFC) => $jobcode// Salida: - Orden SQL para actualizar la tabla de autores => $autor_SQL//************************************************************************function crea_orden_sql_autor($orden_SQL, $tipo, $people,
$id, $i, $autor, $jobcode){
// Autor pertenece al grupoif ($people != -1) {
// Caso PFC ó PHD => Hay que insertar el JOBCODEif ((stripos(" ".$orden_SQL, "INSERT INTO pfcs") != 0) ||
(stripos(" ".$orden_SQL, "INSERT INTO phds") != 0) ||(stripos(" ".$orden_SQL, "INSERT INTO books") != 0))
{$autor_SQL = "INSERT INTO authors (people,publication,type," .
"numorder,jobcode) VALUES (\"".$people."\",\"" . $id ."\",\"" . $tipo . "\",\"" . ($i+1) . "\",\"". $jobcode .
161
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
"\");";}// Cualquier otro casoelse
$autor_SQL = "INSERT INTO authors (people,publication," ."type,numorder) VALUES (\"" . $people . "\",\"" .$id . "\",\"" . $tipo . "\",\"" . ($i+1) . "\");";
}// Autor NO pertenece al grupoelse {
$name = "";// Obtención del nombre del autor no perteneciente al grupofor ($p=0; $p<count($autor); $p++)
$name .= $autor[$p] . " ";$name = ucwords(strtolower(trim($name)));// Caso PFC ó PHD => Hay que insertar el JOBCODEif ((stripos(" ".$orden_SQL, "INSERT INTO pfcs") != 0) ||
(stripos(" ".$orden_SQL, "INSERT INTO phds") != 0) ||(stripos(" ".$orden_SQL, "INSERT INTO books") != 0))
{$autor_SQL = "INSERT INTO authors (name,publication,type," .
"numorder,jobcode) VALUES (\"" . $name . "\",\"" . $id ."\",\"" . $tipo . "\",\"" . ($i+1) . "\",\"" . $jobcode ."\");";
}// Cualquier otro casoelse
$autor_SQL = "INSERT INTO authors (name,publication," ."type,numorder) VALUES (\"" . $name . "\",\"" .$id . "\",\"" . $tipo . "\",\"" . ($i+1) . "\");";
}return $autor_SQL;
}
//************************************************************************// BARRA_PROGRESO: inserta el div para mostrar la información de progreso en// el análisis de información que se hace la primera vez que se llega al// paso 3.// Entrada: - Ninguna// Salida: - Ninguna//************************************************************************function barra_progreso(){
echo "\t<div id='progress' style='position:relative;padding:" ."0px;width:450px;height:60px;left:25px;'>";
for ($i=1; $i<=10; $i++) {echo "\t<div style='float:left;margin:5px 0px 0px 1px;width:2px;" .
"height:12px;background:red;color:red;'> </div>";flush();ob_flush();
}echo "</div>";echo "<script>document.getElementById('progress').style.display = " .
"'none'</script>";}
//************************************************************************// PROCESA_ENTRADA: procesa una nueva entrada para añadir en la base de datos,// generando todas las órdenes SQL necesarias para llevar a cabo con éxito// la actualización.// Entrada: - Valores de los campos de la entrada a actualizar => $entrada// - Campos adicionales de la entrada a actualizar => $campo_def_add// - Nombres de los campos de las tablas de la base de datos =>// $campos_tablas// - Tipo de la publicación => $tipo
162
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// - Array con los autores del grupo => $autores_grupo// - Id devuelto en la actualización de la publicación en la tabla// => $id// Salida: - Bandera que indica si se ha actualizado con éxito la entrada o// no => $salir// - Id devuelto en la actualización de la publicación en la tabla// (por referencia) => $id//************************************************************************function procesa_entrada($entrada, $campo_def_add, $campos_tablas,
$tipo, $autores_grupo, &$id, $letra){
// 1ª PARTE: ACTUALIZACIÓN DE LA ENTRADA CORRESPONDIENTE EN LA TABLA INDICADA//****************************************************************************$sentencia_SQL = crea_orden_sql($entrada, $campo_def_add,
$campos_tablas);$query_sql = "SELECT title, reference FROM " .
$entrada[$campo_def_add["tabla"]];$resultado = mysql_query($query_sql);$num_refs = 0;$duplicada = false;$salir = busca_entrada_similar($resultado, $entrada,
$campo_def_add, $campos_tablas, $num_refs);// Si hay varias referencias iguales, entonces se añade// la letra correspondiente (WARNING: máx. nº de letras => abecedario)if ($num_refs != 0) {
// Se buscan las posiciones del título y la referenciafor ($k=0;$k<count($campos_tablas[$entrada[$campo_def_add["tabla"]]]);$k++){
if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$k] == "reference")$ind_ref = $k + count($campo_def_add);
}$entrada[$ind_ref] .= $letra[$num_refs-1];$sentencia_SQL = crea_orden_sql($entrada, $campo_def_add,
$campos_tablas);}if ($salir == FALSE) {
// Ejecutar la actualización de la entrada$resultado = mysql_query($sentencia_SQL);if ($resultado == FALSE)
echo "<h1>ERROR</h1><br />" . mysql_error() . "<br />";$id = mysql_insert_id(); // Índice de la última inserción de la tabla
}else {
for ($k=0;$k<count($campos_tablas[$entrada[$campo_def_add["tabla"]]]);$k++)if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$k] == "title")
$ind_title = $k;echo "\t<ul><li>No se ha añadido la entrada correspondiente a " .
"la publicación con título \"" .$entrada[$ind_title + count($campo_def_add)] ."\" porque ya existe una entrada similar en la base de datos." ."<br /></li></ul>\n";
$duplicada = true;}// 2ª PARTE: ACTUALIZACIONES COLATERALES EN OTRAS TABLAS (DEPENDENCIAS)//***************************************************************************if ($salir == FALSE) {
// Paso 4: Añadir/actualizar los autores$delete_SQL = "DELETE FROM authors WHERE publication=\"" . $id .
"\" AND type=\"" . $tipo[$entrada[$campo_def_add["tabla"]]] . "\";";$resultado = mysql_query($delete_SQL);if ($resultado == FALSE)
echo "<h1>ERROR</h1><br />" . mysql_error() . "<br />";$autores = obtain_authors($entrada[$campo_def_add["authors"]],
$entrada[$campo_def_add["sep_authors"]]);// Bucle para cada autor
163
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
for ($i=0;$i<count($autores);$i++) {$people = busca_autor($autores[$i], $autores_grupo);$autores_SQL[$i] = crea_orden_sql_autor($sentencia_SQL,
$tipo[$entrada[$campo_def_add["tabla"]]], $people, $id, $i,$autores[$i], "a");
$resultado = mysql_query($autores_SQL[$i]);if ($resultado == FALSE)
echo "<h1>ERROR</h1><br />" . mysql_error() . "<br />";}// En caso de PFC ó PHD, hay que procesar también los supervisoresif ((stripos($sentencia_SQL, "INSERT INTO pfcs") !== false) ||
(stripos($sentencia_SQL, "INSERT INTO phds") !== false)){
$supervisores = obtain_authors($entrada[$campo_def_add["supervisors"]],$entrada[$campo_def_add["sep_supervisors"]]);
// Bucle para cada supervisorfor ($i=0;$i<count($supervisores);$i++) {
$people = busca_autor($supervisores[$i], $autores_grupo);$supervisores_SQL[$i] = crea_orden_sql_autor($sentencia_SQL,
$tipo[$entrada[$campo_def_add["tabla"]]], $people, $id, $i,$autores[$i], "s");
$resultado = mysql_query($supervisores_SQL[$i]);if ($resultado == FALSE)
echo "<h1>ERROR</h1><br />" . mysql_error() . "<br />";}
}}$ind_title = 0;for ($j=0; $j<=count($entrada)-count($campo_def_add); $j++)
if ($campos_tablas[$entrada[$campo_def_add["tabla"]]][$j] == "title")$ind_title = $j;
if ($duplicada == false)echo "\t\tActualizada entrada '" .
$entrada[$ind_title + count($campo_def_add)] . "'.<br />";// Devuelve TRUE en caso de error, FALSE en caso de// que se haya podido actualizar la base de datosreturn !$salir;
}
//************************************************************************// INSERTA_PDF: añade los datos necesarios para copiar posteriormente un fichero// pdf y renombrarlo con las reglas del sitio web del grupo de control// predictivo al final de un fichero de texto del sistema de actualización.// Entrada: - Url del fichero pdf a copiar => $url// - Url del fichero de texto a modificar => $log_file// - Tipo de la publicación contenida en el pdf => $tipo_publicacion// - Id devuelto al actualizar la tabla con la información de la// publicación => $id// Salida: - Ninguna//************************************************************************function inserta_pdf($url, $log_file, $tipo_publicacion, $id){
$descriptor = fopen($log_file, "a");$final = $url."\t".$tipo_publicacion."\t".$id."\n";fwrite($descriptor, $final, strlen($final));fclose($descriptor);
}
//************************************************************************// BUSCA_PUBLICACION_DIR: busca una publicación en un directorio facilitado por// el usuario. Si encuentra en la ruta del fichero todas las partes que// componen la referencia, entonces se toma como fichero válido de la// publicación (pdf).// Entrada: - Array con los directorios facilitados por el usuario => $dirs// - Referencia de la publicación buscada => $referencia
164
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// - Url del fichero que contiene las siglas y acrónimos de las revistas y// congresos => $pubs_file// - Array para insertar las rutas y porcentajes de los ficheros// encontrados => $pdfs// Salida - Array con las rutas y porcentajes de los ficheros encontrados// (por referencia) => $pdfs//************************************************************************function busca_publicacion_dir($dirs, $referencia, $pubs_file, &$pdfs){
$path = 0;$percent = 1;// Obtención del año, primer apellido y publicación a// partir de la referencia => array $token$i = 0;$pos2 = 0;$pos1 = $pos2;while (!ctype_upper($referencia[$pos2]))
$pos2++;$token[$i] = substr($referencia, $pos1, $pos2);$i++;$pos2;$pos1 = $pos2;while (!ctype_digit($referencia[$pos2]))
$pos2++;$token[$i] = substr($referencia, $pos1, $pos2-$pos1);$i++;$pos2 +=2;$token[$i] = substr($referencia, $pos2);$keywords = get_keywords($pubs_file, $token[1]);for ($i=0; $i<count($dirs); $i++) {
if (is_dir($dirs[$i])) {// Se obtiene un listado de todos los directorios// y ficheros bajo este directorio$content = scandir($dirs[$i]);// Para cada entrada del array se comprueba si es fichero,// enlace simbólico o directoriofor ($j=0; $j<count($content); $j++) {
$ruta = $dirs[$i] . "\\\\" . $content[$j];// Caso de ser directorio se almacena en otro array// para llamar recursivamente esta funciónif ((is_dir($ruta)) && ($content[$j] != ".") &&
($content[$j] != "..")){
$coincidencias = busca_publicacion_dir(array($ruta),$referencia, $pubs_file, $pdfs);
}// Caso de ser fichero, se mira si se trata del buscado o no// REQUISITO: se debe encontrar SIEMPRE el apellido, el año// Y las siglas de la publicación o un % > 0.6 en las palabras claveselse if (is_file($ruta)) {
$filename = quita_tildes($content[$j]);$nueva_ruta = $dirs[$i] . "\\\\" . $filename;$valido = true;// Búsqueda del primer apellido del autor principalif (stripos($nueva_ruta, $token[0]) === false)
$valido = false;// Búsqueda de la publicación$num_cases = 0;if (stripos($nueva_ruta, $token[1]) === false) {
// Si la búsqueda de las siglas falla, entonces// se buscan las palabras clavesfor ($k=0; $k<count($keywords); $k++) {
if (stripos($nueva_ruta, $keywords[$k]) !== false)$num_cases++;
}
165
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}else
$num_cases = count($keywords);// Aquí se tiene en cuenta un porcentaje de similitud,// esto es, que se encuentren como mínimo un determinado// número de palabras clavesif (($num_cases/count($keywords)) < 0.6)
$valido = false;// Búsqueda del añoif (stripos($nueva_ruta, $token[2]) === false)
$valido = false;if ($valido) {
$n_pdfs = count($pdfs);if (!isset($pdfs[$n_pdfs-1][0]))
$n_pdfs = 0;else if ($pdfs[$n_pdfs-1][0] == "")
$n_pdfs--;$pdfs[$n_pdfs][0] = stripslashes($ruta);$pdfs[$n_pdfs][1] = ($num_cases/count($keywords))*100;
}}
}}
}}
//************************************************************************// GET_KEYWORDS: obtiene las palabras clave de una publicación a partir de sus// siglas. Esto es útil para la búsqueda de ficheros pdf en los directorios, ya// que algunas veces usan las siglas y otras los nombres completos.// Entrada: - Url del fichero que contiene las siglas y acrónimos de las// revistas y congresos => $pubs_file// - Siglas de la publicación => $siglas// Salida: - Palabras clave de la publicación => $keywords//************************************************************************function get_keywords($pubs_file, $siglas){
// Se buscan las palabras clave de la publicación basándose en las siglas$pubs = "";$archivo = fopen($pubs_file, "r");// Apertura del ficheroif ($archivo) {
while (!feof($archivo))$pubs .= fread($archivo, 8192);
$pos_siglas = stripos($pubs, $siglas.";") + strlen($siglas) + 1;$cadena = trim(substr($pubs, $pos_siglas,
strpos(substr($pubs, $pos_siglas), "\n")));$parte = strtok($cadena, "\t");$i = 0;$empezado = false;for ($j=0; $j<strlen($cadena); $j++) {
if ((ctype_alnum($cadena[$j])) && (!$empezado)) {$empezado = true;$pos_ini = $j;
}else if (!ctype_alnum($cadena[$j]) && $empezado) {
$empezado = false;$pos_fin = $j;$keywords[$i] = trim(substr($cadena, $pos_ini, $pos_fin-$pos_ini));$i++;
}else if (ctype_alnum($cadena[$j]) &&
$empezado && ($j == (strlen($cadena)-1))){
$keywords[$i] = trim(substr($cadena, $pos_ini));}
166
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}}return $keywords;
}?>
10.4.1.10 HELP.HTML
<html><body>
A continuación se muestran las distintas tablas y sus correspondientes campos,junto con una descripción de cada uno:<br></br><table cellspacing=10>
<caption><h3>Tabla CONGRESS</h3></caption><thead>
<tr><th>Nombre del campo</th><th>Descripción</th>
</tr></thead></tbody>
<tr><td width="30%" align=right> TITLE<td> Título de la ponencia del congreso
</tr><tr>
<td width="30%" align=right> ABSTRACT<td> Resumen de la ponencia
</tr><tr>
<td width="30%" align=right> REFERENCE<td> Referencia de la publicación
</tr><tr>
<td width="30%" align=right> BOOKTITLE<td> Nombre del congreso
</tr><tr>
<td width="30%" align=right> YEAR<td> Año de publicación de la ponencia
</tr><tr>
<td width="30%" align=right> MONTH<td> Mes de publicación de la ponencia
</tr><tr>
<td width="30%" align=right> ADDRESS<td> Dirección
</tr><tr>
<td width="30%" align=right> PAGES<td> Páginas del documento de publicación de la ponencia
</tr></tbody>
</table>
<table cellspacing=10><caption><h3>Tabla JOURNALS</h3></caption><thead>
<tr><th>Nombre del campo</th><th>Descripción</th>
167
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
</tr></thead></tbody>
<tr><td width="30%" align=right> TITLE<td> Título del artículo
</tr><tr>
<td width="30%" align=right> ABSTRACT<td> Resumen del artículo
</tr><tr>
<td width="30%" align=right> REFERENCE<td> Referencia de la publicación
</tr><tr>
<td width="30%" align=right> JOURNAL<td> Nombre de la revista o publicación
</tr><tr>
<td width="30%" align=right> YEAR<td> Año de publicación del artículo
</tr><tr>
<td width="30%" align=right> VOLUME<td> Volumen de publicación
</tr><tr>
<td width="30%" align=right> PAGES<td> Páginas del artículo en la publicación
</tr></tbody>
</table>
<table cellspacing=10><caption><h3>Tabla BOOKS</h3></caption><thead>
<tr><th>Nombre del campo</th><th>Descripción</th>
</tr></thead></tbody>
<tr><td width="30%" align=right> TITLE<td> Título del libro
</tr><tr>
<td width="30%" align=right> ABSTRACT<td> Resumen del libro
</tr><tr>
<td width="30%" align=right> REFERENCE<td> Referencia de la publicación
</tr><tr>
<td width="30%" align=right> PUBLISHER<td> Editorial
</tr><tr>
<td width="30%" align=right> YEAR<td> Año de publicación del libro
</tr>
168
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
<tr><td width="30%" align=right> ISBN<td> ISBN del libro
</tr><tr>
<td width="30%" align=right> CODE<td> Código del documento: 1) Libro de texto 2) Libro de actas
</tr></tbody>
</table>
<table cellspacing=10><caption><h3>Tabla PFCS</h3></caption><thead>
<tr><th>Nombre del campo</th><th>Descripción</th>
</tr></thead></tbody>
<tr><td width="30%" align=right> TITLE<td> Título del libro
</tr><tr>
<td width="30%" align=right> AUTHOR<td> Autor del proyecto fin de carrera
</tr><tr>
<td width="30%" align=right> ABSTRACT<td> Resumen del libro
</tr><tr>
<td width="30%" align=right> REFERENCE<td> Referencia de la publicación
</tr></tbody>
</table>
<table cellspacing=10><caption><h3>Tabla PHDS</h3></caption><thead>
<tr><th>Nombre del campo</th><th>Descripción</th>
</tr></thead></tbody>
<tr><td width="30%" align=right> TITLE<td> Título del libro
</tr><tr>
<td width="30%" align=right> ABSTRACT<td> Resumen del libro
</tr><tr>
<td width="30%" align=right> DATEPHD<td> Fecha de finalizacion del doctorado
</tr><tr>
169
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
<td width="30%" align=right> REFERENCE<td> Referencia de la publicación
</tr></tbody>
</table>
NOTAS:<ul>
<li>No se facilita el campo de inserción de documentos. Se ha de hacer mediantemodificación manual desde el sitio web del grupo de control predictivo.
</li><li>
Existe en la página de actualización un campo no existente en ninguna de lastablas, "authors", ya que se suele almacenar el conjunto de autores alcompleto, y no de forma separada. El script de actualización se encarga desepararlos posteriormente.
</li><li>
En condiciones normales no es necesario modificar la tabla "authors", ya que los cambios los realiza automáticamente el programa de actualización.
</li></ul>
</body></html>
10.4.2 CONTROL REMOTO DE PROCESOS MEDIANTE MATLAB /TCP/IP.
10.4.2.1 TUNNING .ASPX .CS
using System;using System.Collections;using System.ComponentModel;using System.Data;using System.Data.Odbc;using System.Drawing;using System.Globalization;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;using System.Web;using System.Web.SessionState;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.HtmlControls;using Solar.Classes;
namespace Solar.RemoteTunning{
/// <summary>/// Esta clase define los métodos necesarios para proporcionar el control remoto/// de la planta a un usuario logeado en el sistema/// </summary>public class RemoteTunning : System.Web.UI.Page{
170
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
protected System.Web.UI.WebControls.Label Parameter_1_name;protected System.Web.UI.WebControls.Label Parameter_2_name;protected System.Web.UI.WebControls.Label Parameter_3_name;protected System.Web.UI.WebControls.Label Parameter_4_name;protected System.Web.UI.WebControls.Label Parameter_5_name;protected System.Web.UI.WebControls.Label Parameter_6_name;protected System.Web.UI.WebControls.Label Parameter_7_name;protected System.Web.UI.WebControls.Label Parameter_8_name;protected System.Web.UI.WebControls.Label Parameter_9_name;protected System.Web.UI.WebControls.Label Parameter_10_name;protected System.Web.UI.WebControls.TextBox Parameter_1_value;protected System.Web.UI.WebControls.TextBox Parameter_2_value;protected System.Web.UI.WebControls.TextBox Parameter_3_value;protected System.Web.UI.WebControls.TextBox Parameter_4_value;protected System.Web.UI.WebControls.TextBox Parameter_5_value;protected System.Web.UI.WebControls.TextBox Parameter_6_value;protected System.Web.UI.WebControls.TextBox Parameter_7_value;protected System.Web.UI.WebControls.TextBox Parameter_8_value;protected System.Web.UI.WebControls.TextBox Parameter_9_value;protected System.Web.UI.WebControls.TextBox Parameter_10_value;protected System.Web.UI.WebControls.Button ButtonChangeParams;protected System.Web.UI.WebControls.Label LabelError;protected System.Web.UI.WebControls.TextBox Old_value1;protected System.Web.UI.WebControls.TextBox Old_value5;protected System.Web.UI.WebControls.TextBox Old_value2;protected System.Web.UI.WebControls.TextBox Old_value3;protected System.Web.UI.WebControls.TextBox Old_value4;protected System.Web.UI.WebControls.TextBox Old_value6;protected System.Web.UI.WebControls.TextBox Old_value7;protected System.Web.UI.WebControls.TextBox Old_value8;protected System.Web.UI.WebControls.TextBox Old_value9;protected System.Web.UI.WebControls.TextBox Old_value10;protected System.Web.UI.WebControls.Label LabelOld1;protected System.Web.UI.WebControls.Label LabelNew1;protected System.Web.UI.WebControls.Label LabelNew2;protected System.Web.UI.WebControls.Label LabelOld2;protected System.Web.UI.WebControls.Image ModeloSimulink;private UserInfo ui = new UserInfo();
//private System.Windows.Forms.Button();private void Page_Load(object sender, System.EventArgs e){
try{
//solamente se permite el acceso a usuarios logados//con privilegio de administradorif (ui.UserLogged()){
if ((ui.GetHasTest()=="True") || (ui.GetTypeOfUser()=="root")){
int NUM_PARAMS = 10;bool fallo = false;
string dir_path = @"C:\Inetpub\ProyectoFC\Solar\Tests\Files\Simulink";
string[] files = null;// Obtain name and path of the model filefiles = Directory.GetFiles(dir_path, "*.mdl");string mdl_name = null;string mdl_path = null;if (files.Length != 0){
mdl_name = files[0].Substring(files[0].LastIndexOf("\\") + 1);mdl_path = files[0];
171
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}else
fallo = true;// Obtain name and path of the image filefiles = Directory.GetFiles(dir_path, "*.png");string png_name = null;string png_path = null;if (files.Length != 0){
png_name = files[0].Substring(files[0].LastIndexOf("\\") + 1);png_path = files[0];
}else
fallo = true;// Obtain name and path of the log filefiles = Directory.GetFiles(dir_path, "*.log");string log_name = null;string log_path = null;if (files.Length != 0){
log_name = files[0].Substring(files[0].LastIndexOf("\\") + 1);log_path = files[0];
}else
fallo = true;
// Check if the file existsif (!fallo && (File.Exists(@mdl_path))){
Bitmap imagen = new Bitmap(png_path);int height = imagen.Height;int width = imagen.Width;ModeloSimulink.Height = height;ModeloSimulink.Width = width;using (StreamReader sr = new StreamReader(log_path)) {
string line = null;int i = 0;while ((line = sr.ReadLine()) != null){
string[] parts = line.Split(new Char [] {'='});switch (parts[0]){
case "var0":Old_value1.ReadOnly = false;Old_value1.Text = parts[1];Old_value1.ReadOnly = true;i++;break;
case "var1":Old_value2.Text = parts[1];i++;break;
case "var2":Old_value3.Text = parts[1];i++;break;
case "var3":Old_value4.Text = parts[1];i++;break;
case "var4":Old_value5.Text = parts[1];i++;
172
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
break;case "var5":
Old_value6.Text = parts[1];i++;break;
case "var6":Old_value7.Text = parts[1];i++;break;
case "var7":Old_value8.Text = parts[1];i++;break;
case "var8":Old_value9.Text = parts[1];i++;break;
case "var9":Old_value10.Text = parts[1];i++;break;
}}
if (i != NUM_PARAMS){
LabelError.Text += "You must specify " + NUM_PARAMS +" parameters" + " in your .mdl file.";
LabelError.Visible = true;}
}// Create an instance of StreamReader to read from a file.// The using statement also closes the StreamReader.
string url = "http://servigar2.us.es/Solar/Tests/Files/Simulink/"+ png_name;
ModeloSimulink.ImageUrl = url;}else if (fallo == true){
LabelError.Text="There is no controller availabe at this "+"moment. If you have booked a period and it is running now,"+" please, contact the web administrator "+"(soladmin@cartuja.us.es) or the solar plant supervisor "+"(solarplant@hotmail.com).";
LabelError.Visible = true;ModeloSimulink.Visible = false;
}}else
Response.Redirect("../LogInOut/ForbiddenAccess.aspx");}else
Response.Redirect("../LogInOut/LogExpired.aspx");}catch (Exception exc){
LabelError.Text = "Exception caught: " + e.ToString();LabelError.Visible = true;ModeloSimulink.Visible = false;
}}
#region Código generado por el Diseñador de Web Formsoverride protected void OnInit(EventArgs e)
173
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
{//// CODEGEN: llamada requerida por el Diseñador de Web Forms ASP.NET.//InitializeComponent();base.OnInit(e);
}
/// <summary>/// Método necesario para admitir el Diseñador. No se puede modificar/// el contenido del método con el editor de código./// </summary>private void InitializeComponent(){
this.ButtonChangeParams.Click += new System.EventHandler(this.ButtonChangeParams_Click);
this.Load += new System.EventHandler(this.Page_Load);
}#endregion
private void ButtonChangeParams_Click(object sender, System.EventArgs e){
Socket s = null; // Socket descriptorint SERVICE_PORT = 32000; // Port to send the data to the serverIPHostEntry iphe = Dns.Resolve("193.147.161.89");// Obtain name and path of the log filestring dir_path = @"C:\Inetpub\ProyectoFC\Solar\Tests\Files\Simulink";string[] files = Directory.GetFiles(dir_path, "*.log");string log_name = files[0].Substring(files[0].LastIndexOf("\\") + 1);string log_path = files[0];
try{
foreach(IPAddress ipad in iphe.AddressList){
IPEndPoint ipe = new IPEndPoint(ipad, SERVICE_PORT);
// Open the socketSocket tmpS = new Socket(ipe.AddressFamily, SocketType.Stream,
ProtocolType.Tcp);
// Connect the sockettmpS.Connect(ipe);
if(tmpS.Connected){
s = tmpS;break;
}else
continue;}if (s == null){
Console.WriteLine("Cannot connect the socket to the specified " +"address.\n");
}else{
string Texto1 = Parameter_1_value.Text;string Texto2 = Parameter_2_value.Text;string Texto3 = Parameter_3_value.Text;string Texto4 = Parameter_4_value.Text;string Texto5 = Parameter_5_value.Text;
174
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
string Texto6 = Parameter_6_value.Text;string Texto7 = Parameter_7_value.Text;string Texto8 = Parameter_8_value.Text;string Texto9 = Parameter_9_value.Text;string Texto10 = Parameter_10_value.Text;string muestra = Texto1 + Texto2 + Texto3 + Texto4 + Texto5 + Texto6 +
Texto7 + Texto8 + Texto9 + Texto10;
// Creacion del mensaje con el contenido del fichero a modificarstring content = "";if (Texto1 != "")
content += "var0=" + Texto1 + "\n";else
content += "var0=" + Old_value1.Text + "\n";if (Texto2 != "")
content += "var1=" + Texto2 + "\n";else
content += "var1=" + Old_value2.Text + "\n";if (Texto3 != "")
content += "var2=" + Texto3 + "\n";else
content += "var2=" + Old_value3.Text + "\n";if (Texto4 != "")
content += "var3=" + Texto4 + "\n";else
content += "var3=" + Old_value4.Text + "\n";if (Texto5 != "")
content += "var4=" + Texto5 + "\n";else
content += "var4=" + Old_value5.Text + "\n";if (Texto6 != "")
content += "var5=" + Texto6 + "\n";else
content += "var5=" + Old_value6.Text + "\n";if (Texto7 != "")
content += "var6=" + Texto7 + "\n";else
content += "var6=" + Old_value7.Text + "\n";if (Texto8 != "")
content += "var7=" + Texto8 + "\n";else
content += "var7=" + Old_value8.Text + "\n";if (Texto9 != "")
content += "var8=" + Texto9 + "\n";else
content += "var8=" + Old_value9.Text + "\n";if (Texto10 != "")
content += "var9=" + Texto10 + "\n";else
content += "var9=" + Old_value10.Text + "\n";
// Send the remote modify request// Cambiar aqui la direccion del neoxitestring msg = "MOD_REQUEST*OVERWRITE*193.147.161.89*" +
content.Length + "*tunning.txt";s.Send(ASCIIEncoding.ASCII.GetBytes(msg));
// Receiving the ack messagestring data = null;byte[] bytes = new byte[1024];int bytesRec = s.Receive(bytes);data += Encoding.ASCII.GetString(bytes,0,bytesRec);if (data.CompareTo("PROCEED") == 0)
s.Send(ASCIIEncoding.ASCII.GetBytes(content));
175
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Once we receive the MODIFY_ACK, we update the log file with new // valuesusing (StreamWriter sw = new StreamWriter(log_path, false)) {
sw.Write(content);}
// Refresh info boxes with new valuesif (Texto1 != "")
Old_value1.Text = Texto1;if (Texto2 != "")
Old_value2.Text = Texto2;if (Texto3 != "")
Old_value3.Text = Texto3;if (Texto4 != "")
Old_value4.Text = Texto4;if (Texto5 != "")
Old_value5.Text = Texto5;if (Texto6 != "")
Old_value6.Text = Texto6;if (Texto7 != "")
Old_value7.Text = Texto7;if (Texto8 != "")
Old_value8.Text = Texto8;if (Texto9 != "")
Old_value9.Text = Texto9;if (Texto10 != "")
Old_value10.Text = Texto10;
// Delete content of the other text boxesParameter_1_value.Text = null;Parameter_2_value.Text = null;Parameter_3_value.Text = null;Parameter_4_value.Text = null;Parameter_5_value.Text = null;Parameter_6_value.Text = null;Parameter_7_value.Text = null;Parameter_8_value.Text = null;Parameter_9_value.Text = null;Parameter_10_value.Text = null;
}}catch (SocketException ex){
LabelError.Text += "No se pudo establecer la conexión con el servidor." +"Lamentamos las molestias.";
LabelError.Visible = true;}
}}
}
10.4.2.2 CP_SERVER _SERVIGAR
using System;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;
namespace cp_server_servigar{
176
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
/// <summary>/// Class Servidor_Servigar: This class implements a server which can copy /// remote files and modify files with remote parameters/// </summary>class Servidor_Servigar{
/// <summary>/// The main entry point for the application./// The server receive first a message containing the operation it has to do:/// *) COPY_REQUEST: remote copy of a file, transfer over IP and create /// new/// *) MOD_REQUEST: remote modification of a file on the server, do not/// create a new file/// *) ABORT: self message for exiting the program and stop listening/// The server has two threads: the main thread listen at a specific port for/// incoming requests, and the secondary thread is only for terminating
/// purposes (it reads the command line and when user enters "exit" it/// finishes the program./// </summary>[STAThread]static void Main(string[] args){
string server_address = "servigar2.us.es";int server_port = 39854;
try{
// Welcome messageConsole.WriteLine("Server running at " +
SERVIGAR:\n===========================");
// Just after that message, we start the secondary thread for abortingReader lector = new Reader();Thread hilo_lector = new Thread(new ThreadStart(lector.KeyboardRead));hilo_lector.Start();
// Allowed IPs for requestingstring[] allowed_ips = {"193.147.161.89", "193.147.160.155",
"172.16.1.4", "127.0.0.1"};bool salir = false; // Flag for exiting the main loopstring data = null; // Incoming data from the client.byte[] bytes = new Byte[1024]; // Data buffer for incoming data.
// Create the local endpointIPHostEntry ipHostInfo = Dns.Resolve("servigar2.us.es");IPAddress ipAddress = ipHostInfo.AddressList[0];IPEndPoint localEndPoint = new IPEndPoint(ipAddress, server_port);
// Create a TCP/IP socket.Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming // connections.listener.Bind(localEndPoint);listener.Listen(10);
// Start listening for connections.while (salir == false) {
Console.WriteLine("\n\nWaiting for a connection...");// Program is suspended while waiting for an incoming connection.Socket handler = listener.Accept();data = null;
177
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Filtering remote IPstring remoteIP =
((IPEndPoint)handler.RemoteEndPoint).Address.ToString();Console.WriteLine("Incoming request from " + remoteIP);
bool allowed = false;foreach (string ip in allowed_ips){
if (ip.CompareTo(remoteIP) == 0){
Console.WriteLine("Allowed IP => Processing request");allowed = true;break;
}}
// If it is an allowed ip address (white list), go on...if (allowed){
// Receiving the request messagebytes = new byte[1024];int bytesRec = handler.Receive(bytes);data += Encoding.ASCII.GetString(bytes,0,bytesRec);
// What does the user want to do?String[] tokens = data.Split(new Char [] {'*'});data = null;FileStream fs_write = null;BinaryWriter w = null;long size = 0;
switch (tokens[0]){
case "COPY_REQUEST":#region COPY REQUEST: remote copy of a file
// Check the existence of the file to create.// If it does not exist, create the new, empty data file.string ack_msg = null;int flag = 0;if (File.Exists(tokens[4])){
if (tokens[1].CompareTo("CREATE") == 0){
flag = 1;ack_msg = "DENIED*Destiny file already exists. " +
"Remote copy denied.\n";Console.WriteLine("Destiny file already exists. " +
"Remote copy denied.\n");}else if (tokens[1].CompareTo("OVERWRITE") == 0){
flag = 2;ack_msg = "PROCEED";
}}else{
flag = 3;ack_msg = "PROCEED";
}
// Sending the ack messagehandler.Send(ASCIIEncoding.ASCII.GetBytes(ack_msg));
178
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// If the ack_msg is PROCEED, go on with the writingif (flag > 1){
Console.WriteLine("Received COPY request. " +"Waiting for the data...");
// First, see if there exist files with the same// extension. In affirmative case, delete them allString[] partes = tokens[4].Split(new Char [] {'.'});string dir_path =
@"C:\Inetpub\ProyectoFC\Solar\Tests\Files\Simulink";string[] dirs =
Directory.GetFiles(dir_path, "*." + partes[1]);if (dirs.Length != 0)
foreach (string dir in dirs) File.Delete(dir);
// Create the writer for data.if (flag == 2)
// File will be overwritedfs_write = new FileStream(tokens[4],
FileMode.Create);else if (flag == 3)
// File does not existfs_write = new FileStream(tokens[4],
FileMode.CreateNew);else
Console.WriteLine("Internal error.\n");w = new BinaryWriter(fs_write);
// Receiving the data (file)size = 0;string data_mod = "";Console.WriteLine("Starting receiving data...");while (true){
bytes = new byte[1024];bytesRec = handler.Receive(bytes);size += bytesRec;w.Write(bytes, 0, bytesRec);data_mod += Encoding.ASCII.GetString(bytes,
0, bytesRec);if (size == Convert.ToInt64(tokens[3]))
break;}Console.WriteLine("File \"" + tokens[4] +
"\" has been created");fs_write.Close();w.Close();
// If this is a model file, we create a log file for// variables storage purposesif (partes[1].CompareTo("mdl") == 0){
int pos = data_mod.IndexOf("Block {");pos = data_mod.IndexOf("BlockType", pos + 1);pos = data_mod.IndexOf("\"S-Function\"", pos + 1);pos = data_mod.IndexOf("Parameters", pos + 1);int pos2 = data_mod.IndexOf("}", pos + 1);pos = data_mod.IndexOf("\"", pos + 1);if (pos < pos2){
pos2 = data_mod.IndexOf("\"", pos + 1);string[] parameters = (data_mod.Substring(pos+1,
pos2-pos-1)).Split(new Char [] {','});
179
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Before creating log file, we delete all// log filesdirs = Directory.GetFiles(dir_path, "*.log");if (dirs.Length != 0)
foreach (string dir in dirs) File.Delete(dir);
// Creating the log fileStreamWriter sr = File.CreateText(partes[0] +
".log");for (int i=0; i<10; i++)
sr.WriteLine("var" + i + "=" +parameters[i] + "\n");
sr.Close();}
}}break;#endregion
case "MOD_REQUEST":#region MODIFY REQUEST: remote modification of a file
// Sending the ack messageack_msg = "PROCEED";handler.Send(ASCIIEncoding.ASCII.GetBytes(ack_msg));
// Create the writer for data.fs_write = new FileStream(tokens[4], FileMode.Append,
FileAccess.Write);w = new BinaryWriter(fs_write);
// Receiving the data to be added to the filesize = 0;while (true){
bytes = new byte[1024];bytesRec = handler.Receive(bytes);size += bytesRec;w.Write(bytes, 0, bytesRec);
if (size == Convert.ToInt64(tokens[3]))break;
}fs_write.Close();w.Close();break;#endregion
case "ABORT":salir = true;break;
default:Console.WriteLine("Request of the user is not allowed.\n");break;
}}
}}# region Specific CATCHS// Thrown by: Thread (Constructor), Dns.Resolve, Socket.Bind,
// Socket.Receive, ASCIIEncoding.GetString, Socket.Send,// Directory.GetFiles, File.Delete, FileStream (Constructor),
180
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// BinaryWriter (Constructor), BinaryWriter.Write,// String.IndexOf, File.CreateTextcatch (System.ArgumentNullException e){
Console.WriteLine("ArgumentNullException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.Threading.ThreadStateException e){
Console.WriteLine("ThreadStateException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Start, Dns.Resolve, Socket.Bind, Socket.Receive,// FileStream (Constructor)catch (System.Security.SecurityException e){
Console.WriteLine("SecurityException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.OutOfMemoryException e){
Console.WriteLine("OutOfMemoryException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.NullReferenceException e){
Console.WriteLine("NullReferenceException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket (Constructor), Socket.Bind, Socket.Listen,// Socket.Accept, Socket.RemoteEndPoint, Socket.Receive, Socket.Sendcatch (System.Net.Sockets.SocketException e){
Console.WriteLine("SocketException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPEndPoint (Constructor), ASCIIEncoding.GetString,// FileStream (Constructor), BinaryWriter.Write, String.IndexOf,// String.Substringcatch (System.ArgumentOutOfRangeException e){
Console.WriteLine("ArgumentOutOfRangeException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Bind, Socket.Listen, Socket.Accept,// Socket.RemoteEndPoint, Socket.Receive, Socket.Send,// BinaryWriter.Write, StreamWriter.WriteLinecatch (System.ObjectDisposedException e){
Console.WriteLine("ObjectDisposedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Acceptcatch (System.InvalidOperationException e)
181
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
{Console.WriteLine("InvalidOperationException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, File.CreateTextcatch (System.UnauthorizedAccessException e){
Console.WriteLine("UnauthorizedAccessException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// BinaryWriter (Constructor), BinaryWriter.Write, Convert.ToInt64,// File.CreateTextcatch (System.ArgumentException e){
Console.WriteLine("ArgumentException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// File.CreateTextcatch (System.IO.PathTooLongException e){
Console.WriteLine("PathTooLongException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// File.CreateTextcatch (System.IO.DirectoryNotFoundException e){
Console.WriteLine("DirectoryNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: File.Delete, File.CreateTextcatch (System.NotSupportedException e){
Console.WriteLine("NotSupportedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileStream (Constructor)catch (System.IO.FileNotFoundException e){
Console.WriteLine("FileNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Console.WriteLine, File.Delete, FileStream (Constructor),// BinaryWriter.Write, StreamWriter.WriteLinecatch (System.IO.IOException e){
Console.WriteLine("IOException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Convert.ToInt64catch (System.FormatException e){
Console.WriteLine("FormatException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
182
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}// Thrown by: Convert.ToInt64catch (System.OverflowException e){
Console.WriteLine("OverflowException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}#endregion
// Thrown by: anycatch (Exception e){
Console.WriteLine("Exception caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}Console.WriteLine("\nPress ENTER to continue...");Console.Read();
}}
/// <summary>/// Class Reader: this class implements a keyboard reader for exiting the
/// executable program. When user writes a line, it reads the command line/// and if the sentence is "exit", the class sends a message to the listening /// port on this machine to exit the socket loop of the class/// Servidor_Servigar/// </summary>internal class Reader{
public void KeyboardRead(){
int server_port = 39854; // Server port for sending the datastring server_address = "193.147.161.89"; // Servigar2.us.es IP addressstring opt = null; // Line enteredSocket s = null; // Socket descriptorbool salir = false; // Flag for exiting the loopIPHostEntry iphe = null;
while (salir == false){
try{
Console.Write("(You can type \"exit\" at any moment to exit " +"the program)\n");
opt = Console.ReadLine();// If the user writes "exit", proceed with the termination processif (opt.ToLower() == "exit"){
// Format check of the IP addressIPAddress address = IPAddress.Parse(server_address);if(address.AddressFamily == AddressFamily.InterNetwork){
// Check if the IP address is validiphe = Dns.Resolve(server_address);
foreach(IPAddress ipad in iphe.AddressList){
IPEndPoint ipe = new IPEndPoint(ipad, server_port);
// Open the socketSocket tmpS =
new Socket(ipe.AddressFamily, SocketType.Stream,ProtocolType.Tcp);
183
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Connect the sockettmpS.Connect(ipe);
if(tmpS.Connected){
s = tmpS;break;
}else
continue;}
if (s == null){
Console.WriteLine("Cannot connect the socket to the " +"specified address.\n");
}else{
string msg = "ABORT";s.Send(ASCIIEncoding.ASCII.GetBytes(msg));salir = true;
}}
}}#region Specific CATCHs// Thrown by: Console.ReadLine, Console.WriteLinecatch(System.IO.IOException e){
Console.WriteLine("IOException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Console.ReadLinecatch(System.OutOfMemoryException e){
Console.WriteLine("OutOfMemoryException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parse, Dns.Resolve, Socket.Connect,// ASCIIEncoding.GetBytes, Socket.Sendcatch(System.ArgumentNullException e){
Console.WriteLine("ArgumentNullException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parsecatch(System.FormatException e){
Console.WriteLine("FormatException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket (Constructor), Socket.Connect,// Socket.Sendcatch(System.Net.Sockets.SocketException e){
Console.WriteLine("SocketException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket.Connect
184
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
catch(System.Security.SecurityException e){
Console.WriteLine("SecurityException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPEndPoint (Constructor)catch(System.ArgumentOutOfRangeException e){
Console.WriteLine("ArgumentOutOfRangeException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Connect, Socket.Sendcatch(System.ObjectDisposedException e){
Console.WriteLine("ObjectDisposedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}#endregion// Thrown by: anycatch(Exception e){
Console.WriteLine("Exception caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}}
}}
}
10.4.2.3 TUNNING .C
/* * sfuntmpl_basic.c: Basic 'C' template for a level 2 S-function. * * ------------------------------------------------------------------------- * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | * ------------------------------------------------------------------------- * * Copyright 1990-2002 The MathWorks, Inc. * $Revision: 1.27 $ */#include <stdio.h>#include <string.h>#include <stdlib.h>
#define NUM_VARS 10FILE *pfile; //Exchange file descriptorchar s[255]; //Global variable to store the read lines from the exchange filechar var_name[255]; //Global variable to store the name of a variablechar var_value[255]; //Global variable to store the value of a variableint changed_var; //Temporal index for selecting the changed variableint allowed; //Flag indicating if a variable value is an allowed valueint valid; //Flag indicating if a variable name is a valid nameint i; //Loops counterint count_orig; //Counter for the originating stringint count_dest; //Counter for the destiny stringint prueba = 0;
185
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
//Allowed variable names for tunning parametersconst char* valid_vars[NUM_VARS] ={"var0","var1","var2","var3","var4","var5","var6","var7","var8","var9"};//Array for the new valuesdouble change_value[10];int changed_value[10] = {0,0,0,0,0,0,0,0,0,0};
/* * You must specify the S_FUNCTION_NAME as the name of your S-function * (i.e. replace sfuntmpl_basic with the name of your S-function). */
#define S_FUNCTION_NAME tunning#define S_FUNCTION_LEVEL 2
/* * Need to include simstruc.h for the definition of the SimStruct and * its associated macro definitions. */#include "simstruc.h"
/* Error handling * -------------- * * You should use the following technique to report errors encountered within * an S-function: * * ssSetErrorStatus(S,"Error encountered due to ..."); * return; * * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. * It cannot be a local variable. For example the following will cause * unpredictable errors: * * mdlOutputs() * { * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} * sprintf(msg,"Error due to %s", string); * ssSetErrorStatus(S,msg); * return; * } * * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. */
/*====================* * S-function methods * *====================*/
/* Function: mdlInitializeSizes =============================================== * Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). */static void mdlInitializeSizes(SimStruct *S){ /* See sfuntmpl_doc.c for more details on the macros below */
ssSetNumSFcnParams(S, 10); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* Return if number of expected != number of actual parameters */ return; }
186
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0);
if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ /* * Set direct feedthrough flag (1=yes, 0=no). * A port has direct feedthrough if the input is used in either * the mdlOutputs or mdlGetTimeOfNextVarHit functions. * See matlabroot/simulink/src/sfuntmpl_directfeed.txt. */ ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S, NUM_VARS)) return; ssSetOutputPortWidth(S, 0, 1); ssSetOutputPortWidth(S, 1, 1); ssSetOutputPortWidth(S, 2, 1); ssSetOutputPortWidth(S, 3, 1); ssSetOutputPortWidth(S, 4, 1); ssSetOutputPortWidth(S, 5, 1); ssSetOutputPortWidth(S, 6, 1); ssSetOutputPortWidth(S, 7, 1); ssSetOutputPortWidth(S, 8, 1); ssSetOutputPortWidth(S, 9, 1);
ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0);
ssSetOptions(S, 0);}
/* Function: mdlInitializeSampleTimes ========================================= * Abstract: * This function is used to specify the sample time(s) for your * S-function. You must register the same number of sample times as * specified in ssSetNumSampleTimes. */static void mdlInitializeSampleTimes(SimStruct *S){ ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0);
}
#define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */#if defined(MDL_INITIALIZE_CONDITIONS) /* Function: mdlInitializeConditions ======================================== * Abstract: * In this function, you should initialize the continuous and discrete * states for your S-function block. The initial states are placed * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). * You can also perform any other initialization activities that your * S-function may require. Note, this routine will be called at the * start of simulation and if it is present in an enabled subsystem * configured to reset states, it will be call when the enabled subsystem
187
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
* restarts execution to reset the states. */ static void mdlInitializeConditions(SimStruct *S) { }#endif /* MDL_INITIALIZE_CONDITIONS */
#define MDL_START /* Change to #undef to remove function */#if defined(MDL_START) /* Function: mdlStart ======================================================= * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is the place * to do it. */ static void mdlStart(SimStruct *S) { }#endif /* MDL_START */
/* Function: mdlOutputs ======================================================= * Abstract: * In this function, you compute the outputs of your S-function * block. Generally outputs are placed in the output vector, ssGetY(S). */static void mdlOutputs(SimStruct *S, int_T tid){
int nOutputPorts = ssGetNumOutputPorts(S);int i,j;prueba = prueba + 1;for (i = 0; i < nOutputPorts; i++) {
real_T *y = (real_T *) ssGetOutputPortSignal(S,i);real_T *pr;int_T ny = ssGetOutputPortWidth(S,i);for (j = 0; j < ny; j++) {
//SomeFunctionToFillInOutput(y[j]);if (changed_value[i] == 1)
y[j] = change_value[i];else{
if (mxIsEmpty( ssGetSFcnParam(S,i)) ||mxIsSparse( ssGetSFcnParam(S,i)) ||mxIsComplex( ssGetSFcnParam(S,i)) ||!mxIsNumeric( ssGetSFcnParam(S,i)) )
{ssSetErrorStatus(S,"Parameters must be real finite vectors");return;
}else{
pr = mxGetPr(ssGetSFcnParam(S,i));y[j] = *pr;
}}
}}
pfile = fopen("tunning.txt","r");if (pfile != NULL){
// The file exist. We must check if there are new values.
188
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
Do{
fgets (s, 255, pfile); //Read a new linecount_orig = 0;if (s[0] != '\0'){
//New line character terminating a line or a variable assignmentwhile ((s[count_orig] != '\n') && (s[count_orig] != '\0')){
count_dest = 0;//Extracting the variable namewhile (s[count_orig] != '='){
var_name[count_dest] = s[count_orig];count_dest++;count_orig++;
}var_name[count_dest] = '\0';count_orig++;count_dest = 0;//Extracting the value of the variable//New line can finish with '\0' if only one variable is wanted to//change or with '\n' or ';' if more than one variable are neededwhile ((s[count_orig] != ';') && (s[count_orig] != '\n')
&& (s[count_orig] ! '\0')){
var_value[count_dest] = s[count_orig];count_dest++;count_orig++;
}var_value[count_dest] = '\0';/************************************//*Processing the variable assignment*//************************************///First, we check if the variable name is a valid namevalid = 0;for (i=0;i<NUM_VARS;i++){
if (strcmp(var_name, valid_vars[i]) == 0){
valid = 1;changed_var = i;
}}//If the name is valid, then check the value restrictions//(Limitations about the changing range)allowed = 1;//If the restrictions are accomplished, then proceed with the//new value assignmentif (allowed && valid){
change_value[changed_var] = atof(var_value);changed_value[changed_var] = 1;
}}
}s[0] = '\0';
} while (!feof(pfile) && !ferror(pfile));}// Once we have read the file, we delete the contentsfclose(pfile);pfile = fopen("tunning.txt","w");if (pfile != NULL){
fclose(pfile);
189
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}// The file does not exist, so we create an empty file here/*fclose(pfile);pfile = fopen("prueba.txt","w");if (pfile != NULL){
fprintf(pfile, "%d", prueba);fclose(pfile);
}*/}
#define MDL_UPDATE /* Change to #undef to remove function */#if defined(MDL_UPDATE) /* Function: mdlUpdate ====================================================== * Abstract: * This function is called once for every major integration time step. * Discrete states are typically updated here, but this function is useful * for performing any tasks that should only take place once per * integration step. */ static void mdlUpdate(SimStruct *S, int_T tid) { }#endif /* MDL_UPDATE */
#define MDL_DERIVATIVES /* Change to #undef to remove function */#if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives ================================================= * Abstract: * In this function, you compute the S-function block's derivatives. * The derivatives are placed in the derivative vector, ssGetdX(S). */ static void mdlDerivatives(SimStruct *S) { }#endif /* MDL_DERIVATIVES */
/* Function: mdlTerminate ===================================================== * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was * allocated in mdlStart, this is the place to free it. */static void mdlTerminate(SimStruct *S){}
/*======================================================* * See sfuntmpl_doc.c for the optional S-function methods * *======================================================*/
/*=============================* * Required S-function trailer * *=============================*/
#define RT#ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */#include "simulink.c" /* MEX-file interface mechanism */
190
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
#else#include "cg_sfun.h" /* Code generation registration function */#endif
10.4.2.4 S ENDTOSERVIGAR .Mip_address = '193.147.161.89'; %193.147.161.89 == servigar2.us.es
%172.16.1.231 == neoxiteclear nombre ok str_name pos filename file_contents descriptor caracter coords;clear tokens new_contents x1 x2 y1 y2 nombre_mod orden s w comando fichero ans;
nombre = input('Introduzca el nombre del fichero que contiene el modelo de Simulink:\n>>>>> ','s');
% Se comprueba el formato del nombre y si existe el ficherook = 0;% Si existe un fichero mdl con ese nombre (es irrelevante si incluye extension o% no)if (exist(nombre) == 4)
str_name = java.lang.String(nombre);pos = str_name.lastIndexOf('.');if (pos > 0)% Caso en que se especifica '.mdl'if ((nombre(pos+2) == 'm') && (nombre(pos+3) == 'd') && (nombre(pos+4) == 'l'))
disp('Fichero de modelo de Simulink encontrado...')str_name = str_name.substring(0, pos);nombre = char(str_name.toString);pos = str_name.indexOf('.');if (pos > 0)
disp('Error: El nombre del modelo de simulink no debe contener el carácter"."')
ok = 1;end% Caso en que el nombre contiene '.' pero no se trata de la extension '.mdl'
elsedisp('Error: El nombre del modelo de simulink no debe contener el carácter
"."')ok = 1;
endelse
disp('Fichero de modelo de Simulink encontrado...')endelse
disp('Error: No se encuentra el fichero especificado')ok = 1;
end
if (ok == 0)% Posicionado de la ventana de modelo en la esquina superior izquierda% ¿Por que? Porque si se tapa parte del controlador, no se ve en la imagenfilename = java.lang.StringBuffer(nombre);filename = filename.append('.mdl');descriptor = java.io.FileReader(filename.toString);file_contents = java.lang.StringBuffer('');caracter = descriptor.read;while (caracter ~= -1)
file_contents.append(char(caracter));caracter = descriptor.read;
enddescriptor.close;pos = file_contents.toString.indexOf('System {');pos = file_contents.toString.indexOf('Location', pos + 1);pos = file_contents.toString.indexOf('[', pos + 1);coords = file_contents.substring(pos +
191
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
1,file_contents.toString.indexOf(']',pos+1));tokens = java.util.StringTokenizer(coords, ',');x1 = str2num(tokens.nextToken.toString.trim);y1 = str2num(tokens.nextToken.toString.trim);x2 = str2num(tokens.nextToken.toString.trim);y2 = str2num(tokens.nextToken.toString.trim);new_contents = java.lang.StringBuffer(file_contents.substring(0, pos + 1));new_contents.append('0, 0, ');new_contents.append(num2str(x2-x1));new_contents.append(', ');new_contents.append(num2str(y2-y1));new_contents.append(file_contents.substring(file_contents.toString.indexOf(']',
pos + 1)));
descriptor = java.io.FileWriter(strcat(nombre,'modified.mdl'));descriptor.write(new_contents.toString);descriptor.close;nombre_mod = strcat(nombre, 'modified');
% Apertura del modelo se Simulink facilitadoif (exist(nombre_mod) ~= 0)
evalin('base', nombre_mod);else
disp('Error')end
% Almacenado de la imagen en formato BMPdisp('Generando fichero de imagen del modelo...')orden = java.lang.StringBuffer('print -s');orden.append(nombre_mod);orden.append(' -dbitmap ');orden.append(nombre_mod);orden = char(orden.toString);evalin('base', orden);bdclose(nombre_mod);
% Almacenado de la imagen en formato PNGdisp('Convirtiendo formato de imagen...')orden = java.lang.StringBuffer('convert ');orden = orden.append(nombre_mod);orden.append('.bmp -transparent "#FFFFFF" ');orden.append(nombre_mod);orden.append('.png');orden = char(orden.toString);[s, w] = dos(orden);if (s == 0)
% Caso en que no se ha producido error algunodisp('Modelo de Simulink almacenado en fichero .png para visionado en web.')
% Copia del fichero de imagen al servidorcomando = java.lang.StringBuffer('cp_client_neoxite OVERWRITE ');comando.append(nombre_mod);comando.append('.png ');comando.append(ip_address);comando.append(' ');comando.append(nombre);comando.append('.png');comando = char(comando.toString);[s, w] = dos(comando);if (s ~= 0)
% Caso en que se ha producido algun errorok = 1;disp(w)
else% Se procede a la copia del modelo de Simulink
192
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
comando = java.lang.StringBuffer('cp_client_neoxite OVERWRITE ');comando.append(nombre);comando.append('.mdl ');comando.append(ip_address);
comando.append(' ');comando.append(nombre);comando.append('.mdl');comando = char(comando.toString);[s, w] = dos(comando);if (s ~= 0)
% Caso en que se ha producido algun errorok = 1;disp(w)
endend
elseok = 1;disp(w)disp('Asegurese de que el fichero "convert.exe" se encuentra en el directorio
de trabajo')end
end
if (ok == 1)disp('***********************************************************************')disp('Se produjo un error en el proceso. Corrija los errores con ayuda de los')disp('mensajes anteriores y vuelva a ejecutar el proceso.')
end
% Borrado de todos los ficheros intermedios creados en el procesodisp('Borrando los ficheros intermedios generados...')fichero = strcat(nombre_mod, '.mdl');if (exist(fichero) ~= 0)
delete(fichero);endfichero = strcat(nombre_mod, '.bmp');if (exist(fichero) ~= 0)
delete(fichero);endfichero = strcat(nombre_mod, '.png');if (exist(fichero) ~= 0)
delete(fichero);end
% Borrado de todas las variables intermedias creadas en el procesodisp('Eliminando las variables intermedias generadas...')clear nombre ok str_name pos filename file_contents descriptor caracter coords ans;clear tokens new_contents x1 x2 y1 y2 nombre_mod orden s w comando fichero ip_address;
disp('Listo')disp(sprintf('\n\n'))
10.4.2.5 CP_CLIENT_NEOXITE
using System;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;
namespace cp_client_neoxite{
193
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
/// <summary>/// Class Cliente_Neoxite: implements a tcp/ip client for remote
/// copy/modification of files from NEOXITE computer to any other./// </summary>
class Cliente_Neoxite{
/* Method Main: main method of the class Cliente_Neoxite. * ====================================================== * Exit codes: * 0: No error * 1: Insufficient parameters at the command line * 2: Socket error * 3: File does not exist * 4: The IP address does not have the correct format */
[STAThread]static int Main(string[] args){
int exit_code = 0; // Returned valueint SERVICE_PORT = 39854; // Server port for sending the data
// User calls the program with the correct number of parametersif (args.Length == 4){
Socket s = null; // Socket descriptorIPHostEntry iphe = null;
try{
// Format check of the IP addressIPAddress address = IPAddress.Parse(args[2]);if(address.AddressFamily == AddressFamily.InterNetwork){
// Check if the IP address is validiphe = Dns.Resolve(args[2]);
foreach(IPAddress ipad in iphe.AddressList){
IPEndPoint ipe = new IPEndPoint(ipad, SERVICE_PORT);
// Open the socketSocket tmpS =
new Socket(ipe.AddressFamily, SocketType.Stream,ProtocolType.Tcp);
// Connect the sockettmpS.Connect(ipe);
if(tmpS.Connected){
s = tmpS;break;
}else
continue;}
if (s == null){
Console.WriteLine("Cannot connect the socket to the specified" +" address.\n");
exit_code = 2;}
194
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
else{
// First of all, check the existence of the fileFileInfo userfile = new FileInfo(args[1]);if (userfile.Exists){
long filelength = userfile.Length;
// Send the remote copy requestString[] tokens = args[1].Split(new Char [] {'\\'});string filename = tokens[tokens.Length-1];string msg = "COPY_REQUEST*" + args[0] + "*" + filename +
"*" + filelength + "*" + args[3];s.Send(ASCIIEncoding.ASCII.GetBytes(msg));
// Receive the ack messagestring data = null;byte[] bytes = new byte[1024];int bytesRec = s.Receive(bytes);data += Encoding.ASCII.GetString(bytes,0,bytesRec);Console.WriteLine(data);
// Create the reader for data.FileStream fs_read = new FileStream(args[1], FileMode.Open,
FileAccess.Read);BinaryReader r = new BinaryReader(fs_read);
// Read data from the specified file.byte[] buffer = new byte[255];do{
buffer = r.ReadBytes(255);s.Send(buffer);
}while (buffer.Length != 0);
// Close the streamsr.Close();fs_read.Close();
}else{
Console.WriteLine("The specified file does not exist.\n");exit_code = 3;
}s.Close();
}}else{
Console.WriteLine("Incorrect format of the remote machine IP " +"address.\n");
exit_code = 4;}
}#region Specific CATCHs// Thrown by: FileStream (Constructor)catch (System.IO.DirectoryNotFoundException e){
Console.WriteLine("DirectoryNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileInfo (Constructor), FileStream (Constructor)catch (System.IO.FileNotFoundException e)
195
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
{Console.WriteLine("FileNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileInfo (Constructor), FileStream (Constructor)catch (System.UnauthorizedAccessException e){
Console.WriteLine("UnauthorizedAccessException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileInfo (Constructor), FileStream (Constructor)catch (System.IO.PathTooLongException e){
Console.WriteLine("PathTooLongException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileInfo (Constructor)catch (System.NotSupportedException e){
Console.WriteLine("NotSupportedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Console.WriteLine, FileInfo.Length, FileStream// (Constructor), BinaryReader.ReadBytes, FileStream.Closecatch (System.IO.IOException e){
Console.WriteLine("IOException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Connect, Socket.Send, Socket.Receive,// BinaryReader.ReadBytescatch(System.ObjectDisposedException e){
Console.WriteLine("ObjectDisposedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPEndPoint (Constructor), Encoding.GetString,// FileStream (Constructor), BinaryReader.ReadBytescatch(System.ArgumentOutOfRangeException e){
Console.WriteLine("ArgumentOufOfRangeException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parsecatch(System.FormatException e){
Console.WriteLine("FormatException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parse, DNS.Resolve, Socket.Connect,// FileInfo (Constructor), Socket.Send, Encoding.GetBytes,// Socket.Receive, Encoding.GetString, FileStream (Constructor)catch(System.ArgumentNullException e){
Console.WriteLine("ArgumentNullException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
196
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}// Thrown by: DNS.Resolve, Socket (Constructor), Socket.Connect,// Socket.Send, Socket.Receivecatch(System.Net.Sockets.SocketException e){
Console.WriteLine("SocketException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);exit_code = 2;
}// Thrown by: DNS.Resolve, Socket.Connect, FileInfo (Constructor),// Socket.Receive, FileStream (Constructor)catch(System.Security.SecurityException e){
Console.WriteLine("SecurityException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);exit_code = 2;
}// Thrown by: FileInfo (Constructor), FileStream (Constructor),// BinaryReader (Constructor)catch (System.ArgumentException e){
Console.WriteLine("ArgumentException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}#endregion// Thrown by: anycatch(Exception e){
Console.WriteLine("Exception caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}}// Show how call the programelse{
Console.WriteLine("Syntax:\n" +"\tcp_client_neoxite COPY_MODE local_filename remote_ip_address " +"remote_filename\n\nCOPY_MODE:\n" +"\tCREATE: Create the file only if it does not exist.\n" +"\tOVERWRITE: Create the file in any case.\n" +"local_filename: name of the file at the local side (client side). " +"Ex:\n\tc:\\mydir\\myfile.ext (full path)\n" +"\tmyfile.ext (only the filename, local path)\n" +"remote_ip_address: IP address of the remote machine. Ex:\n" +"\t127.0.0.1 (local copy)\n" +"\t165.35.2.98 (remote copy)\n" +"remote_filename: name of the file at the remote side (server " +"side). Ex:\n\t\\..\\..\\myfile2.ext (copy the file two levels " +"up from the server dir\n" +"\tmyfile2.ext (copy the file in the dir in which the server is\n");
exit_code = 1;}
return exit_code;}
}}
197
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
10.4.2.6 CP_SERVER _NEOXITE
using System;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;
namespace cp_server_neoxite{
/// <summary>/// Class Servidor_Neoxite: This class implements a server which can copy remote/// files and modify files with remote parameters/// </summary>class Servidor_Neoxite{
/// <summary>/// The main entry point for the application./// The server receive first a message containing the operation it has to do:/// *) COPY_REQUEST: remote copy of a file, transfer over IP and create/// new/// *) MOD_REQUEST: remote modification of a file on the server, do not/// create a new file/// *) ABORT: self message for exiting the program and stop listening/// The server has two threads: the main thread listen at a specific port for/// incoming requests, and the secondary thread is only for terminating/// purposes (it reads the command line and when user enters "exit" it/// finishes the program./// </summary>[STAThread]static void Main(string[] args){
string server_address = "servigar2.us.es"; // NEOXITE: 172.16.1.231int server_port = 32000;
try{
// Welcome messageConsole.WriteLine("Server running at
NEOXITE:\n===========================");
// Just after that message, we start the secondary thread for abortingReader lector = new Reader();Thread hilo_lector = new Thread(new ThreadStart(lector.KeyboardRead));hilo_lector.Start();
// Allowed IPs for requestingstring[] allowed_ips = {"193.147.161.89", "193.147.160.155",
"172.16.1.4", "127.0.0.1", "172.16.1.231"};bool salir = false; // Flag for exiting the main loopstring data = null; // Incoming data from the client.byte[] bytes = new Byte[1024]; // Data buffer for incoming data.
// Create the local endpointIPHostEntry ipHostInfo = Dns.Resolve(server_address);IPAddress ipAddress = ipHostInfo.AddressList[0];IPEndPoint localEndPoint = new IPEndPoint(ipAddress, server_port);
// Create a TCP/IP socket.Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming// connections.
198
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
listener.Bind(localEndPoint);listener.Listen(10);
// Start listening for connections.while (salir == false) {
Console.WriteLine("\n\nWaiting for a connection...");// Program is suspended while waiting for an incoming connection.Socket handler = listener.Accept();data = null;
// Filtering remote IPstring remoteIP =
((IPEndPoint)handler.RemoteEndPoint).Address.ToString();Console.WriteLine("Incoming request from " + remoteIP);
bool allowed = false;foreach (string ip in allowed_ips){
if (ip.CompareTo(remoteIP) == 0){
Console.WriteLine("Allowed IP => Processing request");allowed = true;break;
}}
// If it is an allowed ip address (white list), go on...if (allowed){
// Receiving the request messagebytes = new byte[1024];int bytesRec = handler.Receive(bytes);data += Encoding.ASCII.GetString(bytes,0,bytesRec);
// What does the user want to do?String[] tokens = data.Split(new Char [] {'*'});data = null;FileStream fs_write = null;BinaryWriter w = null;long size = 0;
switch (tokens[0]){
case "COPY_REQUEST":#region COPY REQUEST: remote copy of a file
// Check the existence of the file to create.// If it does not exist, create the new, empty data file.string ack_msg = null;int flag = 0;if (File.Exists(tokens[4])){
if (tokens[1].CompareTo("CREATE") == 0){
flag = 1;ack_msg = "DENIED*Destiny file already exists. " +
"Remote copy denied.\n";Console.WriteLine("Destiny file already exists. " +
"Remote copy denied.\n");}else if (tokens[1].CompareTo("OVERWRITE") == 0){
flag = 2;ack_msg = "PROCEED";
199
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}}else{
flag = 3;ack_msg = "PROCEED";
}
// Sending the ack messagehandler.Send(ASCIIEncoding.ASCII.GetBytes(ack_msg));
// If the ack_msg is PROCEED, go on with the writingif (flag > 1){
Console.WriteLine("Received COPY request. " +"Waiting for the data...");
// Create the writer for data.// File will be overwritedif (flag == 2)
fs_write = new FileStream(tokens[4], FileMode.Create);// File does not exist
else if (flag == 3)fs_write = new FileStream(tokens[4], FileMode.CreateNew);
elseConsole.WriteLine("Internal error.\n");
w = new BinaryWriter(fs_write);
// Receiving the data (file)size = 0;Console.WriteLine("Starting receiving data...");while (true){
bytes = new byte[1024];bytesRec = handler.Receive(bytes);size += bytesRec;w.Write(bytes, 0, bytesRec);if (size == Convert.ToInt64(tokens[3]))
break;}Console.WriteLine("File \"" + tokens[4] + "\" has " +
"been overwrited");fs_write.Close();w.Close();
}break;#endregion
case "MOD_REQUEST":#region MODIFY REQUEST: remote modification of a file
Console.WriteLine("Received MODIFY request. " +"Waiting for the data...");
// Sending the ack messageack_msg = "PROCEED";handler.Send(ASCIIEncoding.ASCII.GetBytes(ack_msg));
// Receiving the data to be added to the filesize = 0;string text_modif = "";Console.WriteLine("Starting receiving data...");while (text_modif.Length != Convert.ToInt64(tokens[3])){
bytes = new byte[1024];
200
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
bytesRec = handler.Receive(bytes);text_modif += Encoding.ASCII.GetString(bytes,0,bytesRec);
}using (StreamWriter sw = new StreamWriter(tokens[4])) {
sw.Write(text_modif);}break;Console.WriteLine("File \"" + tokens[4] + "\" has " +
"been modified");#endregion
case "ABORT":salir = true;break;
default:Console.WriteLine("Request of the user is not allowed.\n");break;
}}
}} # region Specific CATCHS// Thrown by: Thread (Constructor), Dns.Resolve, Socket.Bind,
// Socket.Receive, ASCIIEncoding.GetString, Socket.Send,// Directory.GetFiles, File.Delete, FileStream (Constructor),// BinaryWriter (Constructor), BinaryWriter.Write,// String.IndexOf, File.CreateText, StreamWriter (Constructor)catch (System.ArgumentNullException e){
Console.WriteLine("ArgumentNullException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.Threading.ThreadStateException e){
Console.WriteLine("ThreadStateException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Start, Dns.Resolve, Socket.Bind, Socket.Receive,// FileStream (Constructor), StreamWriter (Constructor)catch (System.Security.SecurityException e){
Console.WriteLine("SecurityException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.OutOfMemoryException e){
Console.WriteLine("OutOfMemoryException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Thread.Startcatch (System.NullReferenceException e){
Console.WriteLine("NullReferenceException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket (Constructor), Socket.Bind, Socket.Listen,
201
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Socket.Accept, Socket.RemoteEndPoint, Socket.Receive, Socket.Sendcatch (System.Net.Sockets.SocketException e){
Console.WriteLine("SocketException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPEndPoint (Constructor), ASCIIEncoding.GetString,// FileStream (Constructor), BinaryWriter.Write, String.IndexOf,// String.Substringcatch (System.ArgumentOutOfRangeException e){
Console.WriteLine("ArgumentOutOfRangeException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Bind, Socket.Listen, Socket.Accept,// Socket.RemoteEndPoint, Socket.Receive, Socket.Send,// BinaryWriter.Write, StreamWriter.WriteLine,// StreamWriter.Writecatch (System.ObjectDisposedException e){
Console.WriteLine("ObjectDisposedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Acceptcatch (System.InvalidOperationException e){
Console.WriteLine("InvalidOperationException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, File.CreateText,// StreamWriter (Constructor)catch (System.UnauthorizedAccessException e){
Console.WriteLine("UnauthorizedAccessException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// BinaryWriter (Constructor), BinaryWriter.Write, Convert.ToInt64,// File.CreateText, StreamWriter (Constructor)catch (System.ArgumentException e){
Console.WriteLine("ArgumentException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// File.CreateText, StreamWriter (Constructor)catch (System.IO.PathTooLongException e){
Console.WriteLine("PathTooLongException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Directory.GetFiles, File.Delete, FileStream (Constructor),// File.CreateText, StreamWriter (Constructor)catch (System.IO.DirectoryNotFoundException e){
Console.WriteLine("DirectoryNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
202
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
}// Thrown by: File.Delete, File.CreateText, StreamWriter.Writecatch (System.NotSupportedException e){
Console.WriteLine("NotSupportedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: FileStream (Constructor)catch (System.IO.FileNotFoundException e){
Console.WriteLine("FileNotFoundException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Console.WriteLine, File.Delete, FileStream (Constructor),// BinaryWriter.Write, StreamWriter.WriteLine, StreamWriter// (Constructor), StreamWriter.Writecatch (System.IO.IOException e){
Console.WriteLine("IOException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Convert.ToInt64catch (System.FormatException e){
Console.WriteLine("FormatException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Convert.ToInt64catch (System.OverflowException e){
Console.WriteLine("OverflowException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}#endregion// Thrown by: anycatch (Exception e){
Console.WriteLine("Exception caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}Console.WriteLine("\nPress ENTER to continue...");Console.Read();
}}
/// <summary>/// Class Reader: this class implements a keyboard reader for exiting the/// executable program. When user writes a line, it reads the command/// line and if the sentence is "exit", the class sends a message to the/// listening port on this machine to exit the socket loop of the class/// Servidor_Servigar/// </summary>internal class Reader{
public void KeyboardRead(){
int server_port = 32000; // Server port for sending the datastring server_address = "193.147.161.89"; // Servigar2.us.es IP address
203
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
string opt = null; // Line enteredSocket s = null; // Socket descriptorbool salir = false; // Flag for exiting the loopIPHostEntry iphe = null;
while (salir == false){
try{
Console.Write("(You can type \"exit\" at any moment to exit " +"the program)\n");
opt = Console.ReadLine();// If the user writes "exit", proceed with the termination processif (opt.ToLower() == "exit"){
// Format check of the IP addressIPAddress address = IPAddress.Parse(server_address);if(address.AddressFamily == AddressFamily.InterNetwork){
// Check if the IP address is validiphe = Dns.Resolve(server_address);
foreach(IPAddress ipad in iphe.AddressList){
IPEndPoint ipe = new IPEndPoint(ipad, server_port);
// Open the socketSocket tmpS =
new Socket(ipe.AddressFamily, SocketType.Stream,ProtocolType.Tcp);
// Connect the sockettmpS.Connect(ipe);
if(tmpS.Connected){
s = tmpS;break;
}else
continue;}
if (s == null){
Console.WriteLine("Cannot connect the socket to the " +"specified address.\n");
}else{
string msg = "ABORT";s.Send(ASCIIEncoding.ASCII.GetBytes(msg));salir = true;
}}
}}#region Specific CATCHs// Thrown by: Console.ReadLine, Console.WriteLinecatch(System.IO.IOException e){
Console.WriteLine("IOException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}
204
SISTEMA DE GESTIÓN DOCUMENTAL A TRAVÉS DE INTERNET
// Thrown by: Console.ReadLinecatch(System.OutOfMemoryException e){
Console.WriteLine("OutOfMemoryException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parse, Dns.Resolve, Socket.Connect,// ASCIIEncoding.GetBytes, Socket.Sendcatch(System.ArgumentNullException e){
Console.WriteLine("ArgumentNullException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPAddress.Parsecatch(System.FormatException e){
Console.WriteLine("FormatException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket (Constructor), Socket.Connect,// Socket.Sendcatch(System.Net.Sockets.SocketException e){
Console.WriteLine("SocketException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Dns.Resolve, Socket.Connectcatch(System.Security.SecurityException e){
Console.WriteLine("SecurityException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: IPEndPoint (Constructor)catch(System.ArgumentOutOfRangeException e){
Console.WriteLine("ArgumentOutOfRangeException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}// Thrown by: Socket.Connect, Socket.Sendcatch(System.ObjectDisposedException e){
Console.WriteLine("ObjectDisposedException caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}#endregion// Thrown by: anycatch(Exception e){
Console.WriteLine("Exception caught!!!");Console.WriteLine("Source : " + e.Source);Console.WriteLine("Message : " + e.Message);
}}
}}
}
205