php-mysql

296
Experto en Desarrollo de Soluciones Corporativas en Software Libre 2010 / ??? Desarrollo de Aplicaciones Web avanzadas con PHP y MySQL Copyright (c) 2010 (Daniel González Zaballos y David Vaquero Santiago) Financiado por: Impartido por: Espacio para el logotipo del centro de formación

Upload: hugo-leon

Post on 30-Oct-2014

568 views

Category:

Documents


4 download

DESCRIPTION

Php-Mysql

TRANSCRIPT

Page 1: Php-Mysql

Experto en Desarrollo de Soluciones Corporativas en

Software Libre

2010 / ???

Desarrollo de Aplicaciones Web avanzadas

con PHP y MySQL Copyright (c) 2010 (Daniel González Zaballos y David Vaquero Santiago)

Financiado por: Impartido por: Espacio para el logotipo del centro de formación

Page 2: Php-Mysql

LICENCIA CREATIVE COMMONS

Reconocimiento-Compartir bajo la misma licencia 3.0 España

Usted es libre de:

• copiar, distribuir y comunicar públicamente la obra

• hacer obras derivadas

Bajo las condiciones siguientes:

• Reconocimiento — Debe reconocer los créditos de la obra de la manera especificada por el

autor o el licenciador (pero no de una manera que sugiera que tiene su apoyo o apoyan el uso

que hace de su obra).

• Compartir bajo la misma licencia — Si transforma o modifica esta obra para crear una obra

derivada, sólo puede distribuir la obra resultante bajo la misma licencia, una de similar o una de

compatible.

Entendiendo que:

• Renuncia — Alguna de estas condiciones puede no aplicarse si se obtiene el permiso del titular

de los derechos de autor

• Dominio Público — Where the work or any of its elements is in the public domaine under

applicable law, that status is in no way affected by the license.

• Otros derechos — Los derechos siguientes no quedan afectados por la licencia de ninguna

manera:

• Los derechos derivados de usos legítimos u otras limitaciones reconocidas por ley no se

ven afectados por lo anterior.

• Los derecho morales del auto;

• Rights other persons may have either in the work itself or in how the work is used, such

as publicity or privacy rights.

• Aviso — Al reutilizar o distribuir la obra, tiene que dejar bien claro los términos de la licencia de

esta obra.

Page 3: Php-Mysql

INDICE

IND-I

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN

SOFTWARE LIBRE

Contenido Pág.

1. CUESTIONES PREVIAS .......................................................................1 

2. DESCRIPCIÓN DE LA ARQUITECTURA APACHE, PHP Y MYSQL...3 

2.1.  Introducción a la plataforma LAMP..................................................................3 

2.1.1.  Principios de la arquitectura cliente servidor................................................3 

2.1.2.  Tipos de Arquitectura Cliente Servidor.........................................................4 

2.2.  La Arquitectura LAMP........................................................................................4 

2.2.1.  Introducción a LAMP ....................................................................................4 

2.2.2.  Glosario de Términos ...................................................................................4 

2.2.3.  Elementos de la Arquitectura LAMP ............................................................5 

2.2.4.  Proceso de una Petición LAMP....................................................................6 

2.3.  Pasos de la Instalación de un Entorno LAMP.................................................7 

2.3.1.  Instalación y configuración o acceso a un Servidor DNS ............................7 

2.3.2.  Instalación y configuración de un SGBD: Mysql ..........................................8 

2.3.3.  Instalación y configuración de una aplicación LAMP ...................................8 

3. INTRODUCCIÓN A LA INSTALACIÓN DE LAMP................................9 

3.1.  Introducción........................................................................................................9 

3.2.  Configuración de Servicios LAMP ...................................................................9 

3.2.1.  Configuración de un Servidor DNS ..............................................................9 

3.2.2.  Configuración de un dominio DNS ...............................................................9 

3.3.  Instalación de LAMP ........................................................................................10 

3.3.1.  Instalación de *AMP en Windows con XAMPP..........................................10 

3.3.2.  El panel de Control de XAMPP ..................................................................10 

3.3.3.  Instalación de una LAMP en OpenSuse 10.2 ............................................11 

4. HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP 15 

4.1.  Eclipse y extensiones......................................................................................15 

Page 4: Php-Mysql

INDICE

IND-II

4.1.1.  Eclipse el IDE .............................................................................................15 

4.1.2.  Instalación de Eclipse para PHP................................................................15 

4.1.3.  Gestión de versiones: SVN ........................................................................16 

4.2.  Firefox y sus extensiones ...............................................................................19 

4.2.1.  Referencias ................................................................................................19 

4.2.2.  Contenido ...................................................................................................19 

4.2.3.  Mysql WorkBench.......................................................................................21 

4.2.4.  Publicación de Código................................................................................22 

5. PHP BÁSICO .......................................................................................25 

5.1.  Estructura básica de un fichero PHP.............................................................26 

5.1.1.  Inclusión de ficheros externos....................................................................27 

5.2.  Elementos del Lenguaje:.................................................................................28 

5.2.1.  Variables.....................................................................................................28 

5.2.2.  Constantes .................................................................................................29 

5.2.3.  Operadores.................................................................................................30 

5.3.  Tipo de datos abstractos: ...............................................................................32 

5.3.1.  Manejo de Cadenas de caracteres ............................................................32 

5.3.2.  Manejo de arrays de datos:........................................................................36 

5.3.3.  Variables predefinidas................................................................................37 

5.4.  Estructuras de control:....................................................................................38 

5.4.1.  Sentencias condicionales...........................................................................38 

5.4.2.  Switch .........................................................................................................39 

5.4.3.  Bucles.........................................................................................................40 

5.4.4.  Break y Continue........................................................................................42 

5.5.  Funciones .........................................................................................................42 

5.5.1.  Ámbitos de Variables .................................................................................43 

5.5.2.  Paso de variables.......................................................................................45 

5.5.3.  Recursividad...............................................................................................46 

5.6.  Salidas por pantalla .........................................................................................46 

5.7.  Actividades .......................................................................................................48 

Page 5: Php-Mysql

INDICE

IND-III

5.7.1.  Tipos de datos, cadenas y arrays. .............................................................48 

5.7.2.  Estructuras de control.................................................................................49 

5.7.3.  Funciones ...................................................................................................51 

6. FORMULARIOS Y SUS MÉTODOS....................................................53 

6.1.  GET y POST ......................................................................................................56 

6.2.  Otros..................................................................................................................58 

6.3.  Actividad ...........................................................................................................58 

7.BASES DE DATOS RELACIONALES .................................................61 

7.1.  SQL: lenguaje de definición y manejo de datos ...........................................61 

7.1.1.  Lenguaje de definición de datos (LDD) ......................................................62 

7.1.2.  Lenguaje de manipulación de datos (LMD)................................................63 

7.1.3.  Recuperación de clave ...............................................................................65 

7.1.4.  Disparadores (Triggers)..............................................................................65 

7.2.  Integridad referencial.......................................................................................66 

7.2.1.  Ejemplo: Cómo funciona ............................................................................66 

8. ADMINISTRACIÓN..............................................................................69 

8.1.  Manejo de usuarios..........................................................................................69 

8.1.1.  Usuarios por defecto ..................................................................................69 

8.1.2.  Conectarse al servidor MySQL...................................................................70 

8.1.3.  Privilegios de usuarios................................................................................71 

8.2.  Manejo de datos ...............................................................................................72 

8.2.1.  Copias de seguridad...................................................................................72 

9.ACCESO A DATOS..............................................................................75 

9.1.  Introducción......................................................................................................75 

9.1.1.  Tipos de datos ............................................................................................75 

9.2.  Acceso a datos.................................................................................................77 

9.2.1.  Creación de una tabla ................................................................................77 

9.2.2.  Eliminar una tabla.......................................................................................78 

9.2.3.  Modificar la estructura de una tabla ...........................................................78 

Page 6: Php-Mysql

INDICE

IND-IV

9.2.4.  Índices de una tabla ...................................................................................78 

9.2.5.  Manipulación de datos ...............................................................................78 

9.2.6.  Vistas..........................................................................................................80 

9.2.7.  Sentencias preparadas ..............................................................................82 

9.2.8.  Exportación e importación de datos...........................................................83 

9.2.9.  Rutinas almacenadas y disparadores ........................................................85 

10. EJEMPLO Y EJERCICIOS ................................................................91 

10.1.  Introducción .....................................................................................................91 

10.2.  Ejercicios ..........................................................................................................91 

10.2.1.  Ejercicio 1 - Modelado de la base de datos ...............................................91 

10.2.2.  Ejercicio 2 - Creación de la base de datos en MySQL...............................92 

10.2.3.  Ejercicio 3 - Poblar la base de datos en MySQL........................................97 

10.2.4.  Ejercicio 4 - Integridad referencial en MySQL............................................99 

10.2.5.  Ejercicio 5 - Acceso a Datos ......................................................................99 

10.2.6.  Ejercicio 6 - Manejo de vistas...................................................................101 

10.2.7.  Ejercicio 7 - Disparadores ........................................................................102 

11. GESTIÓN DE FICHEROS................................................................105 

11.1.  Recepción y manejo de ficheros ..................................................................105 

11.1.2.  Actividad ...................................................................................................109 

11.2.  POO en PHP....................................................................................................109 

11.2.1.  Definición de Clases, objetos, atributos y métodos .................................109 

11.2.2.  Manejo de objetos ....................................................................................111 

11.2.3.  Actividades ...............................................................................................112 

11.2.4.  Uso de la Herencia...................................................................................112 

11.2.5.  Actividades ...............................................................................................113 

11.2.6.  Manejo de excepciones............................................................................113 

11.2.7.  Actividades ...............................................................................................114 

11.2.8.  Diferencias entre clases abstractas e interfaces......................................116 

12. DESARROLLO MVC CON PHP ......................................................119 

12.1.  ¿Qué es MVC?................................................................................................119 

Page 7: Php-Mysql

INDICE

IND-V

12.2.  ¿Porqué utilizar el paradigma MVC?............................................................119 

12.3.  Empezando a separar nuestro código.........................................................120 

12.4.  Abstrayéndonos del gestor de base de datos ............................................121 

12.5.  Actividades .....................................................................................................122 

13. GESTOR DE PLANTILLAS: SMARTY............................................125 

13.1.1.  Instalación.................................................................................................125 

13.1.2.  Bases de smarty.......................................................................................126 

13.1.3.  Modificadores, funciones, filtros, plugins, estructuras de control.............126 

13.1.4.  Como usar smarty ....................................................................................127 

13.2.  Generación de CSS........................................................................................129 

13.3.  Creando layouts .............................................................................................130 

13.4.  Creando formularios......................................................................................131 

13.4.1.  Actividades ...............................................................................................131 

13.5.  Accesibilidad en Web ....................................................................................132 

14. CAPA DE ACCESO A DATOS CON ADODB.................................135 

14.1.  Conexiones a Bases de Datos ......................................................................135 

14.2.  Generación de Consultas..............................................................................136 

14.2.1.  Actividad ...................................................................................................136 

14.3.  Acceso a los Metadatos ................................................................................137 

14.3.1.  MetaDatabases() ......................................................................................137 

14.3.2.  MetaTables($ttype = false, $showSchema = false, $mask=false)...........137 

14.3.3.  MetaColumns($table,$toupper=true)........................................................137 

14.3.4.  MetaColumnNames($table)......................................................................137 

14.3.5.  MetaPrimaryKeys($table, $owner=false) .................................................138 

14.3.6.  ServerInfo($table).....................................................................................138 

14.3.7.  MetaForeignKeys($table, $owner=false, $upper=false) ..........................138 

14.3.8.  FetchField($column_number)...................................................................139 

14.4.  Ejecución de Consultas.................................................................................139 

14.4.1.  Actividad ...................................................................................................140 

15. USO DE SERVICIOS DE INTERNET CON PHP .............................141 

Page 8: Php-Mysql

INDICE

IND-VI

15.1.  Distintos modelos de Servicios Web...........................................................142 

15.2.  Algunos API's WEB accesibles a través de Internet ..................................142 

15.3.  Recursos.........................................................................................................143 

15.4.  Actividades .....................................................................................................143 

15.4.1.  Actividad 1 ................................................................................................143 

15.4.2.  Actividad 2 ................................................................................................143 

15.4.3.  Actividad 3 ................................................................................................143 

15.4.4.  Actividad 4 ................................................................................................144 

16. MANEJO DE USUARIOS/SEGURIDAD..........................................145 

16.1.  Autenticación y Autorización .......................................................................145 

16.1.1.  Actividades ...............................................................................................147 

16.2.  Manejo de Sesiones.......................................................................................148 

16.2.1.  Actividades ...............................................................................................149 

16.3.  Manejo de Cookies.........................................................................................149 

16.3.2.  Actividades ...............................................................................................151 

17. CONSTRUIR APLICACIONES PHP SEGURAS .............................153 

17.1.  Tratamiento de imágenes de manera dinámica..........................................153 

17.1.1.  Generación de captcha para formularios .................................................153 

17.1.2.  Retoque de imágenes ..............................................................................155 

17.1.3.  Actividades ...............................................................................................155 

17.2.  Bibliotecas de seguridad: IDS ......................................................................156 

18. OPTIMIZACIÓN EN PHP .................................................................159 

18.1.  Procesos a Optimizar ....................................................................................159 

18.2.  Buenas prácticas de codificación ................................................................161 

18.3.  Actividades .....................................................................................................162 

18.3.1.  Actividad 1 ................................................................................................162 

18.3.2.  Actividad 2 ................................................................................................162 

18.3.3.  Actividad 3 ................................................................................................162 

18.3.4.  Actividad 4 ................................................................................................162 

Page 9: Php-Mysql

INDICE

IND-VII

19. FRAMEWORKS DE DESARROLLO EN PHP.................................163 

19.1.  Actividades .....................................................................................................164 

19.1.1.  Actividad 1 ................................................................................................164 

19.1.2.  Actividad 2 ................................................................................................164 

19.1.3.  Actividad 3 ................................................................................................164 

19.1.4.  Actividad 4 ................................................................................................164 

20. JAVASCRIPT...................................................................................165 

20.1.  Conceptos básicos ........................................................................................165 

20.2.  Sintaxis y clases básicas ..............................................................................165 

20.2.1.  Incluir scripts en el código HTML .............................................................165 

20.3.  Elementos del Lenguaje:...............................................................................166 

20.3.1.  Tipos de datos ..........................................................................................166 

20.3.2.  Las variables.............................................................................................166 

20.3.3.  Objetos, Arrays y Funciones ....................................................................167 

20.4.  Operadores .....................................................................................................167 

20.4.1.  Operadores Aritméticos............................................................................167 

20.4.2.  Operadores Binarios.................................................................................168 

20.4.3.  Operadores Lógicos .................................................................................169 

20.4.4.  Operadores Varios ...................................................................................171 

20.4.5.  Funciones Globales..................................................................................171 

20.5.  Estructuras de control...................................................................................173 

20.5.1.  Condiciones..............................................................................................173 

20.5.2.  Switch .......................................................................................................174 

20.5.3.  Bucles .......................................................................................................174 

20.6.  Ruptura de Bucles..........................................................................................175 

20.7.  Los Objetos de Javascript ............................................................................176 

20.7.1.  Objeto Object............................................................................................176 

20.7.2.  Objeto Function ........................................................................................177 

20.7.3.  Objeto Array..............................................................................................178 

20.7.4.  Objeto window ..........................................................................................180 

Page 10: Php-Mysql

INDICE

IND-VIII

20.7.5.  Objeto document ......................................................................................182 

20.7.6.  Objeto form...............................................................................................184 

20.7.7.  Objeto Boolean.........................................................................................185 

20.7.8.  Objeto Number .........................................................................................186 

20.7.9.  Objeto String.............................................................................................186 

20.7.10.  Objeto Date .......................................................................................190 

20.7.11.  Objeto Math.......................................................................................197 

20.7.12.  Objeto Regular Expession ................................................................199 

20.8.  Eventos ...........................................................................................................203 

20.8.1.  Eventos en JavaScript..............................................................................203 

20.8.2.  Métodos de evento disponibles en JavaScript.........................................205 

20.9.  Actividades .....................................................................................................206 

20.9.1.  Actividad 1 ................................................................................................206 

20.9.2.  Actividad 2 ................................................................................................206 

20.9.3.  Actividad 3 ................................................................................................206 

20.9.4.  Actividad 4 ................................................................................................207 

20.9.5.  Actividad 5 ................................................................................................207 

20.9.6.  Actividad 6 ................................................................................................207 

20.9.7.  Actividad 7 ................................................................................................207 

20.9.8.  Actividad 8 ................................................................................................207 

20.9.9.  Actividad 9 ................................................................................................207 

20.9.10.  Actividad 10.......................................................................................207 

20.9.11.  Actividad 11.......................................................................................207 

20.9.12.  Actividad 12.......................................................................................208 

20.9.13.  Actividad 13.......................................................................................208 

20.9.14.  Actividad 14.......................................................................................208 

20.9.15.  Actividad 15.......................................................................................208 

20.9.16.  Actividad 16.......................................................................................208 

20.9.17.  Actividad 17.......................................................................................208 

20.9.18.  Actividad 18.......................................................................................208 

Page 11: Php-Mysql

INDICE

IND-IX

20.9.19.  Actividad 19.......................................................................................208 

20.10. Introducción a XML........................................................................................209 

20.10.1.  Historia ..............................................................................................209 

20.10.2.  Ventajas del XML ..............................................................................209 

20.10.3.  XHTML ..............................................................................................210 

20.10.4.  Estructura de un documento XML.....................................................210 

20.10.5.  Partes de un documento XML...........................................................212 

20.10.6.  Document Type Definition (DTD) ......................................................213 

20.10.7.  XML Schemas ...................................................................................215 

20.10.8.  Extended Style Language (XSL).......................................................217 

20.10.9.  Xlink, Xpath y Xpointer......................................................................220 

20.10.10.  SAX y DOM.......................................................................................222 

20.10.11.  Actividades ........................................................................................226 

20.10.12.  Referencias .......................................................................................227 

21. JAVASCRIPT EN LOS DISTINTOS NAVEGADORES ...................229 

21.1.  La propiedad “float” de CSS.........................................................................229 

21.2.  Estilos computados de un elemento............................................................230 

21.3.  Accediendo al “class” de un elemento........................................................230 

21.4.  Accediendo al atributo “for” de las etiquetas <label /> .............................230 

21.5.  Obtener la posición del puntero del ratón...................................................230 

21.6.  Obtener el tamaño del navegador o del área visible ..................................231 

21.7.  Transparencias...............................................................................................231 

22. MANEJO DEL DOM.........................................................................233 

22.1.  Creando elementos y textos .........................................................................234 

22.2.  Usando innerHTML ........................................................................................236 

22.3.  Eliminando un elemento o nodo de texto....................................................236 

22.4.  Manipulando los estilos de los elementos ..................................................237 

22.5.  Actividades .....................................................................................................237 

22.5.1.  Actividad 1 ................................................................................................238 

22.5.2.  Actividad 2 ................................................................................................238 

Page 12: Php-Mysql

INDICE

IND-X

23.BIBLIOTECAS JAVASCRIPT BÁSICAS: JQUERY Y MOOTOOLS239 

23.2.  Validaciones de formularios con JavaScript. .............................................240 

23.2.1.  Validación con JQuery .............................................................................241 

23.2.2.  Validación con MooTools .........................................................................242 

23.3.  Manejo dinámico de elementos HTML.........................................................243 

23.4.  Actividades .....................................................................................................246 

24.INTRODUCCIÓN A AJAX.................................................................247 

24.1.  Tecnologías incluidas en Ajax......................................................................247 

24.2.  Problemas e Inconvenientes ........................................................................248 

24.3.  Métodos HTTP ................................................................................................248 

24.4.  Objeto XMLHTTPRequest..............................................................................249 

24.5.  Formatos de intercambio de Información ...................................................252 

25. CONSTRUCCIÓN DE SERVICIOS WEB EN PHP. .........................257 

25.1.  Introducción a los servicios web .................................................................257 

25.1.1.  Soap .........................................................................................................257 

25.1.2.  REST ........................................................................................................258 

25.1.3.  En otras palabras .....................................................................................258 

25.2.  Actividad .........................................................................................................259 

25.3.  Desarrollo de servicios web .........................................................................259 

25.4.  Ejemplo de uso de un servicio REST: CRUDL............................................263 

25.4.1.  Listado ......................................................................................................273 

25.4.2.  Mostrado...................................................................................................273 

25.4.3.  Inserción ...................................................................................................274 

25.4.4.  Modificación..............................................................................................274 

25.4.5.  Borrado.....................................................................................................274 

25.4.6.  Búsqueda .................................................................................................275 

25.5.  Actividades .....................................................................................................275 

25.5.1.  Actividad 1 ................................................................................................275 

25.5.2.  Actividad 2 ................................................................................................275 

Page 13: Php-Mysql

INDICE

IND-XI

26.CONSULTA DE SERVICIOS WEB EN JAVASCRIPT: JQUERY ....277 

26.1.  Manejo de consultas: uso del objeto XMLHTTPRequest...........................277 

26.1.1.  Método Open............................................................................................278 

26.2.  Importación y exportación de datos ............................................................280 

26.3.  Manejo de los datos y su uso en el DOM ....................................................281 

26.4.  Actividad .........................................................................................................281 

Page 14: Php-Mysql
Page 15: Php-Mysql

Cuestiones Previas

1

Cuestiones Previas

En este punto se verá desde la teoría hasta la práctica de la puesta en marcha de la Arquitectura *AMP.

¿Porqué llamarla *AMP?

La A significa Apache, la M Mysql y la P PHP.

Se puede encontrar definido también el sistema operativo substituyendo el * por una L (Linux), por una W (Windows) o por una M (Mac OS).

Con las siglas completas *AMP, incluiría LAMP, WAMP y MAMP.

Este curso trata de explicar las cosas comunes y específicas de varias de estas arquitecturas.

Page 16: Php-Mysql
Page 17: Php-Mysql

Descripción de la arquitectura Apache, PHP y MYSQL

3

Descripción de la Arquitectura Apache, PHP y MYSQL

2.1. Introducción a la plataforma LAMP

Bienvenidos a esta documentación sobre La Teoría de funcionamiento de la plataforma LAMP. Espero que os sea grata y que os ayude a entender mejor el desarrollo de aplicaciones mediante los ordenadores con GNU/Linux.

2.1.1. Principios de la arquitectura cliente servidor

A fin de poder entender correctamente el comportamiento de la arquitectura LAMP es importante describir el funcionamiento de la arquitectura de aplicaciones Cliente-Servidor. En Dicha arquitectura disponemos de dos tipos de agentes:

Cliente: Ordenador o programa informático que solicita información.

Page 18: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

4

Servidor: Ordenador o programa informático que dispone de información.

Dentro de este tipo de arquitectura podemos definir distintos tipos de Agentes dependiendo del tratamiento que se realice con la información:

Activo: El Agente realiza un procesado activo de la información. Calculo intensivo, cálculo de la presentación gráfica de la información, acceso a datos son algunas de las tareas típicas de un Agente Activo.

Pasivo: El agente se limita a manejar información en bruto o preprocesada.

2.1.2. Tipos de Arquitectura Cliente Servidor

A continuación se detallan los distintos tipos de Arquitecturas de Cliente - Servidor:

Cliente Activo, Servidor Pasivo: El cliente realiza la practica totalidad del trabajo de procesado de la información. Ejemplo: Google Earth.

Cliente Pasivo, Servidor Pasivo: Tanto el cliente como el Servidor simplemente pasan información. Ejemplo: Gateways de comunicaciones VoIP.

Cliente Pasivo, Servidor Activo: El Servidor realiza todo el trabajo de procesado y el cliente simplemente presenta los datos. Ejemplo: Servidores de terminales.

Cliente Activo, Servidor Activo: Tanto el Servidor como el Cliente procesan la información. Ejemplo: Servicios de Correo Electrónico.

2.2. La Arquitectura LAMP

2.2.1. Introducción a LAMP

Dependiendo de la aplicación LAMP que el tipo de arquitectura puede variar, pero por simplicidad en el presente manual sólo va a tratarse del Tipo Cliente Activo - Servidor Activo.

2.2.2. Glosario de Términos

A continuación se detallan un glosario de términos que permiten entender mejor la arquitectura LAMP:

HTML: Hyper Text Markup Language. Lenguaje que permite definir el contenido y su presentación para que el cliente web permita visualizar la información que contiene. Dicho lenguaje permite la inclusión de medios (gráficos, sonidos, vídeos, etc.).

Etiqueta o TAG: Unidad mínima de representación en el Lenguaje HTML. Permite definir: párrafos, tablas, enlaces, imágenes, etc...

CSS: (Cascading Style Sheets) Hojas de Estilo en Cascada . Permiten generar clases de estilo que se pueden aplicar a etiquetas HTML. Dichas hojas de estilo se pueden definir dentro de los ficheros HTML o incluso referenciarlos. Los TAG permiten agrupar cambios en las propiedades de un determinando TAG.

Java Script (JS): Lenguaje de programación que permite en la parte cliente procesar y realizar cambios en la presentación. Dichos Scripts suelen estar referenciados desde el fichero HTML.

Page 19: Php-Mysql

Descripción de la arquitectura Apache, PHP y MYSQL

5

Página Web: Unidad de contenido de un servidor web. Normalmente está compuesta de un fichero formateado en HTML y sus referencias.

Sitio Web: Conjunto de reglas del Servidor Web y las páginas Web que lo componen.

Servicio DNS: Servidor que entre otras funciones permite traducir nombres de máquinas en Internet a direcciones IP.

Navegador Web: Cliente que permite consultar a Servidores Web y presentar la información HTML. Ejemplos: Firefox, Konqueror, Opera, Internet Explorer, etc.

Plugin Web: Extensión de un navegador web que permite añadir una funcionalidad a un navegador web, por ejemplo la visualización de elementos no estándar. Ejemplos: Flash Player, JVM, etc.

Apache: Servidor Web Libre. Dicho servidor es altamente flexible y actualmente el 60 % de los sitios web funcionan con Apache.

Módulo de Apache: Conjunto de funcionalidades agrupadas que permiten extender el tratamiento de la información por parte del servidor Web Apache.

URL: Uniform Resource Locator. Definición del acceso a un recurso. El concepto de URL ha sido incorporado dentro del más general de URI (Uniform Resource Identifier - Identificador Uniforme de Recurso), pero el término URL aún se utiliza ampliamente. La URL está dividida en tres partes: Nombre del Servidor Web, Recurso a acceder y Parámetros GET.

Método GET: Forma de paso de parámetros mediante URL.

Método POST: Forma de paso de parámetros mediante formulario (normalmente).

PHP: PHP Hypertext Pre-processor. es un lenguaje de programación usado generalmente para la creación de contenido para sitios web. PHP está preparado para funcionar como un módulo de Apache (y otros servidores Web).

Dirección IP: Identificativo único de un interfaz de red basado en el Protocolo IP.

SGBD: Sistema de Gestión de Bases de Datos. Son un tipo de software muy específico, dedicado a servir de interfaz entre la base de datos, el usuario y las aplicaciones que la utilizan. Se compone de un lenguaje de definición de datos, de un lenguaje de manipulación de datos y de un lenguaje de consulta. En los textos que tratan este tema, o temas relacionados, se mencionan los términos SGBD y DBMS, siendo ambos equivalentes, y acrónimos, respectivamente, de Sistema Gestor de Bases de Datos y DataBase Management System -su expresión inglesa.SQL: Lenguaje de Consulta Estructurado (Structured Query Language). Es un lenguaje declarativo de acceso a bases de datos relacionales que permite especificar diversos tipos de operaciones sobre las mismas. Auna características del álgebra y el cálculo relacional permitiendo lanzar consultas con el fin de recuperar información de interés de una base de datos, de una forma sencilla.

2.2.3. Elementos de la Arquitectura LAMP

A continuación se detallarán los elementos de una arquitectura LAMP:

Cliente Web/DNS: Navegador Web. Por ejemplo: Firefox.

Servidor DNS: Conversor de nombres a IP’s. Por ejemplo: BIND.

Servidor Web: Almacén y procesador de la Información Web. Apache en nuestro caso.

Módulo de PHP: Módulo para apache que permite procesar ficheros escritos en el Lenguaje PHP. Por ejemplo: PHP5

Aplicación LAMP: Conjunto de ficheros PHP que componen una Aplicación Web. Por ejemplo: PhpMyAdmin

Page 20: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

6

SGBD: Sistema de gestión de bases de datos que permitirá almacenar la información dinámicamente. En nuestro caso Mysql.

2.2.4. Proceso de una Petición LAMP

A continuación se detallarán los pasos que realizan el cliente y el servidor de una arquitectura LAMP

1. Cliente Web: Solicitud de conversión del nombre de una máquina al Servidor DNS. Por ejemplo: www.google.es

2. Servidor DNS: Recepción y tratamiento de la solicitud. Una vez recibida la petición realiza las consultas necesarias para resolver y obtener la dirección IP.

3. Servidor DNS: Devuelve la dirección IP que corresponde al Servidor Web al navegador Web.

4. Cliente Web: Realiza la solicitud de información mediante una URL(Método GET) o un formulario (Método POST). Dicha solicitud incluye: la dirección IP del servidor web, el puerto del servidor web, URL y parámetros POST(esta sólo en el caso de formularios normalmente).

5. Servidor Web: Control de Acceso, Análisis de la petición y localización del recurso.

6. Servidor Web: Selección del módulo de PHP para interpretar el fichero PHP elegido.

7. Módulo de PHP: Ejecución del programa PHP elegido.

8. Aplicación PHP: Procesado de los parámetros GET o POST.

9. Aplicación PHP: Realización de las llamadas SQL al Servidor de SGBD.

10. SGBD: Recogida y procesado de la petición SQL.

11. SGBD: Retorno de los datos solicitados.

12. Aplicación PHP: Procesado de los datos devueltos por el SGBD y Generación del HTML resultante.

13. Modulo PHP: Paso del HTML resultante a Apache.

14. Apache: Devuelve el HTML al cliente Web.

15. Cliente Web: Presentación del HTML resultante, CSS y elementos relacionados y ejecución del Javascript.

A continuación se puede visualizar un gráfico que resume dichos pasos:

Page 21: Php-Mysql

Descripción de la arquitectura Apache, PHP y MYSQL

7

2.3. Pasos de la Instalación de un Entorno LAMP

2.3.1. Instalación y configuración o acceso a un Servidor DNS

Debido a que la instalación y configuración específicas dependen del sistema operativo y la versión escogida, se van a enumerar los pasos necesarios para su configuración, que son los siguientes:

1. Alta de un dominio. Ejemplo: midominio.com

2. Alta de las máquinas que pertenecen al dominio. Ejemplo: servidor.midominio.com. en este paso se relaciona la dirección IP de la máquina con el nombre dentro del dominio.

3. Alta de los Alias necesarios: www, ftp, correo, etc. Se relacionan los nombre reales de las máquinas con un alias o apodo de la máquina.

4. Esperar de 24 a 48h a que se replique la información entre los Servidores DNS de todo el mundo.

5. Realizar una consulta de DNS para ver si ha funcionado correctamente la operación para cada una de las máquinas y alias creados.

6. Instalación y configuración de Apache.

Page 22: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

8

Debido a que la instalación y configuración específicas dependen del sistema operativo y la versión escogida, se van a enumerar los pasos necesarios para su configuración, que son los siguientes:

1. Configuración de los parámetros básicos: Directorio principal de directorio, reglas de acceso por defecto, numero de hijos, memoria ram, número máximo de peticiones, etc...

2. Alta y Configuración de los módulos básicos necesarios: redirección, proxy, configuración, etc...

3. Prueba de funcionamiento del servidor web con un fichero HTML de ejemplo.

4. Instalación y Configuración del módulo de PHP: inclusión del módulo, asociación del tipo de fichero al módulo, configuración de tamaño máximo de upload, memoria por hilo php, acceso a datos, etc...

5. Alta de un sitio web virtual que permita manejar el sitio principal del dominio. Ejemplo: www.midominio.com relacionado con el directorio /var/www/midominio.com/

6. Configuración de las reglas especiales para el sitio principal del dominio: control de acceso, etc.

7. Prueba de funcionamiento de PHP con un fichero de ejemplo.

2.3.2. Instalación y configuración de un SGBD: Mysql

Debido a que la instalación y configuración específicas dependen del sistema operativo y la versión escogida, se van a enumerar los pasos necesarios para su configuración, que son los siguientes:

1. Configuración básica del servidor Mysql: memoria principal disponible, tipos de tabla disponibles, memoria destinada a cache, etc...

2. Inserción de usuarios básicos.

3. Creación de una base de datos de ejemplo.

4. Creación de una tabla de ejemplo.

5. Modificación de un usuario para tener acceso a la base de datos creada.

6. Prueba de funcionamiento con un cliente de Mysql.

2.3.3. Instalación y configuración de una aplicación LAMP

Debido a que la instalación y configuración específicas dependen del sistema operativo y la versión escogida, se van a enumerar los pasos necesarios para su configuración, que son los siguientes:

1. Creación de una base de datos en el servidor para la aplicación.

2. Colocación de las tablas principales necesarias para el funcionamiento de la aplicación LAMP.

3. Instalación de la aplicación web en el sitio web principal.

4. Configuración de la aplicación web.

5. Prueba de la aplicación web

Page 23: Php-Mysql

INTRODUCCION A LA INSTALACIÓN DE LAMP

9

Introducción a la Instalación de LAMP

3.1. Introducción

En el presente manual se van a definir a fondo aquellas tareas necesarias para poner en funcionamiento una plataforma LAMP. Por simplicidad el manual está dedicado a su instalación y configuración en una OpenSuse 10.2.

3.2. Configuración de Servicios LAMP

3.2.1. Configuración de un Servidor DNS

Debido que las distintas posibilidades a la hora de gestionar un dominio son tan variadas, en el presente manual se va a suponer que se dispone de un dominio contratado y que se sabe la dirección ip de cada una de las máquinas que van a ir dentro del dominio.

3.2.2. Configuración de un dominio DNS

Page 24: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

10

Una vez que hayamos accedido a la herramienta de configuración dispondremos de un interfaz a través del cual podremos modificar las entradas del dominio. Disponemos básicamente de tres tipo de entradas: A o entradas de maquinas (relacionan una ip con un nombre dentro del dominio), CNAME relacionan mediante un alias un nombre de máquina con otro nombre y MX que relaciona el servidor por correo por defecto con un nombre de máquina.

A continuación de puede ver una figura en el que se ve cómo configurar dichas entradas:

Una vez guardados los cambios espere entre 24 y 48h a que dichos cambios surtan efecto. Después de que haya pasado dicho plazo, pruebe a entrar mediante el navegador web para ver si funciona correctamente.

3.3. Instalación de LAMP

A continuación se detallarán los distintos tipos de instalaciones de un Entorno *AMP.

3.3.1. Instalación de *AMP en Windows con XAMPP

En este punto detallaremos la instalación de XAMPP para Windows.

• La versión de XAMPP para Windows está disponible en: http://www.apachefriends.org/en/xampp-windows.html

• Elija la versión en Formato EXE para su descarga, actualmente está disponible en: http://www.apachefriends.org/download.php?xampp-win32-1.7.3.exe

• Descargue el fichero en su ordenador y ejecute el instalador como administrador del sistema.

• Una vez en el instalador, seleccione el directorio de instalación y pulse en instalar.

• Este proceso puede tardar unos minutos y depende de la potencia de su ordenador.

• Durante el proceso, tal vez le pregunte si desea activar los servicios relacionados con Apache, Mysql, etc...

• Inicialmente le diremos que no es necesario, ya que siempre podremos colocar los servidores como servicios en cualquier momento.

• Después nos preguntará si deseamos arrancar el “XAMPP Control Panel”. No es necesario arrancarlo, pero aprovecharemos para hacerlo, para así explicar su funcionamiento.

3.3.2. El panel de Control de XAMPP

Hay varias maneras de arrancar y parar los servidores:

• Mediante los script de arranque y parada • Mediante el panel de control de XAMPP

Lance el Panel de Control de XAMPP (si no lo ha hecho todavía) mediante el icono en su escritorio. Cuando haya arrancado, pulse en el botón “Start” de Apache y Mysql.

Si, por lo que sea, el arranque de apache falla, el texto “Running” al lado de la fila de Apache desaparecerá. Esto puede ser debido a que algún programa esté haciendo uso del puerto 80 de su máquina.

Page 25: Php-Mysql

INTRODUCCION A LA INSTALACIÓN DE LAMP

11

3.3.2.1. Cree Una base de datos de prueba en Mysql

Para crear dicha base de datos puede utilizar el phpmyadmin instalado con XAMPP.

Para ello siga lo siguientes pasos:

• Vaya desde su navegador web a la siguiente dirección: http://localhost • Podrá ver La pantalla principal de XAMPP, donde puede seleccionar su

idioma. • En el menú de la derecha seleccione PhpMyAdmin • Una vez que PhpMyAdmin se haya abierto en su navegador, seleccione su

idioma. • Introduzca los datos de acceso. Si no se han configurado usuarios, sólo

existirá el usuario “root”. • Así que ponga en Nombre de usuario “root” y la contraseña déjela vacía. • Pulse en continuar. • Una vez esté dentro (logueado) en PhpMyAdmin, encontrará un formulario

para crear una nueva base de datos. • Introduzca el nombre de la base de datos. • En el campo “Collation” seleccione “utf8_unicode_ci”. • Haga clic en el botón “Crear” • Debería ver la base de datos a su izquierda. • Seleccione la nueva base de datos. • Trabaje con ella :)

3.3.3. Instalación de una LAMP en OpenSuse 10.2

En OpenSuse 10.2 esta tarea es muy sencilla, describimos ahora todos los pasos:

1. Entre en el Menú de Acciones (KickOff) en el apartado de PC y pulse en el Configurador de administración YAST.

2. Valídese como Superusuario. En cuanto intente entrar en YAST deberá introducir la contraseña del SuperAdministrador (root) y pulsar en el botón Aceptar.

3. En la pestaña de Software pulse en el icono de Instalar/desinstalar Software.

4. En la pestaña de Software pulse en el icono de Instalar/desinstalar Software.

5. Una vez haya entrado en la herramienta se actualizarán los listado de Software disponibles para su manejo.

6. Cuando haya terminado de gestionar los listados, aparecerá una nueva pantalla. En la parte superior derecha de la pantalla aparece una etiqueta llamada filtro y una lista desplegable. pulse en ella y seleccione Patrones. Aparecerá un listado en la parte de la izquierda.

7. En dicho listado aparecen grupos de paquetes con funcionalidades acompañados de una caja de selección al lado izquierdo de cada uno de ellos. Para seleccionar alguno de ellos pulse con el botón izquierdo en cualquiera de las cajas de selección, esta caja aparecerá marcada con un símbolo de visto bueno, también verá que en la parte de la derecha de la pantalla principal, los paquetes individuales aparecerán todos seleccionados. Para de-seleccionar un patrón repita la misma operación, verá que el símbolo de visto bueno desaparecerá de la caja de selección.

8. Seleccione el patrón denominado Servidor Web y LAMP.

9. Pulse en el botón Aceptar. Aparecerá la pantalla de descarga de paquetes desde los medios.

Page 26: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

12

10. Introduzca el CD o DVD de instalación de OpenSuse 10.2. y pulse en el botón Ok. Se iniciará la descarga de paquetes individuales.

11. A continuación se configurarán los paquetes y servicios con YAST.

12. A continuación pulse en el botón No en el cuadro de diálogo.

13. Se cerrará la venta de instalar y Desinstalar paquetes.

14. A continuación pulse en el botón No en el cuadro de diálogo.

15. Se cerrará la venta de instalar y Desinstalar paquetes.

16. A continuación necesita activar el servidor Apache y el PHP. Para lo cual debe entrar en YAST en la pestaña Servicios de red en el icono Servidor HTTP.

17. Después aparecerá la primera pantalla de configuración de Apache. En ella deberán aparecer: el puerto por el que escuchará las peticiones web (por defecto 80) y las direcciones ip por las que se permite que escuche el servidor web (127.0.0.1 por defecto).

18. Pulse en el botón Siguiente.

19. A continuación deberá marcar (si no lo está hecho ya) el cuadro de selección al lado de Habilitar lenguaje de guiones PHP5.

20. Pulse en Siguiente.

21. A continuación puede ser los parámetros básicos del servidor, tales como directorio principal, dirección de correo del administrador, etc. Pulse en Siguiente.

22. Después podrá ver los Sitios Web Virtuales que maneja el servidor, si no desea manejar ninguno más pulse en Siguiente. Si desea configurar un nuevo Sitio Web Virtual pulse en añadir y siga los siguientes pasos.

23. A continuación introduzca los parámetros de configuración del nuevo servidor virtual: nombre del servidor, directorio principal del Sitio Web Virtual y el correo del administrador del sitio web virtual. Pulse en el botón Siguiente.

24. A continuación introduzca otros parámetros de configuración del nuevo servidor virtual: acceso a CGI, HTML público, etc..

25. Pulse el botón Siguiente.

26. Después de añadir el nuevo sitio Web Virtual. Pulse en Siguiente.

27. Después de configurar los Sitios Web Virtuales, marque la opción Iniciar el servidor web en el arranque. Pulse en Siguiente.

28. A continuación se configurará el servidor web y se rearrancará si es necesario. Pulse en Finalizar.

29. A continuación introduzca la url en el navegador web y compruebe que se visualiza correctamente.

30. Ahora es necesario comprobar si el módulo de php funciona correctamente, para lo cual es necesario crear un fichero index.php en el directorio principal del dominio del Sitio Web Virtual. Para ello necesita abrir una terminal con permisos de súper-administrador, esto se puede conseguir si va al Menú de Acciones, pestaña Aplicaciones, submenú Sistema, submenú Terminal, icono Programa de terminal - modo de superusuario. Le solicitará la contraseña del administratorio (root), introduzcala y pulse en el botón OK.

31. Una vez abierta la terminal ejecute los siguientes comandos: echo "" >/srv/www/htdocs/index.php chmod 777 /srv/www/htdocs/index.php

32. Evidentemente la ruta debe coincidir con la localización del directorio raíz del Sitio Web Virtual

Page 27: Php-Mysql

INTRODUCCION A LA INSTALACIÓN DE LAMP

13

33. Después abra su navegador e introduzca la url seguido de /index.php En nuestro ejemplo www.midominio.com/index.php Si se abre correctamente podrá ver la información del módulo php instalado en su Apache.

3.3.3.1. Configuración de Mysql

A fin de poder arrancar automáticamente en el arranque el servidor Mysql es necesario modificar los niveles de arranque. Para lo cual entre en YAST y vaya a la pestaña Sistema y entre en el editor de niveles de ejecución. Los pasos a seguir son los siguientes:

1. A continuación selecciones el servicio Mysql con el botón derecho del ratón y pulse el botón Activar situado abajo a la izquierda de la pantalla.

2. Una vez activado el servicio saldrá una pantalla con el resultado (debería marcar un éxito en el proceso de activación). Pulse en el botón Ok. Después pulse en el botón finalizar.

3. Después pulse el botón Finalizar para que se apliquen los cambios. Cuando salga la pantalla de validación pulse en Si.

Sería conveniente recordar que el usuario por defecto de Mysql tras la instalación es root y no dispone de una contraseña asignada.

A fin de poder gestionar correctamente Mysql pasaremos al siguiente paso, Instalar la aplicación Web PhpMyAdmin

3.3.3.2. Instalación y configuración de PhpMyAdmin

Para poder gestionar de una manera sencilla Mysql, instalaremos PhpMyAdmin, una herramienta de gestión de Mysql vía web. Así mataremos dos pájaros de un tiro. Los pasos a seguir son los siguientes:

1. Descargarse la última versión de PhpMyAdmin, cuando nos pregunte el navegador qué hacer con el le diremos que queremos guardarlo en el disco duro, en el escritorio por ejemplo.

2. Una vez descargado el fichero deberemos descomprimirlo, para lo cual pulsamos sobre él para abrirlo y descomprimirlo también en el escritorio

3. Después debe copiar el contenido de la carpeta que incluya el index.php al directorio /srv/www/phpmyadmin

4. Debe recordar que para hacer esto es necesario realizar esta operación como SuperAdministrador del sistema.

5. Después debe modificar los permisos de la carpeta para que el usuario root tenga permisos de acceso a los ficheros.

6. Después debe comprobar mediante el navegador que tiene acceso a la url http://localhost/phpmyadmin.index.php. En nuestro ejemplo: http://www.midominio.com/phpmyadmin/index.php

Page 28: Php-Mysql
Page 29: Php-Mysql

HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP

15

Herramientas de Desarrollo de proyectos para PHP

4.1. Eclipse y extensiones

4.1.1. Eclipse el IDE

Eclipse es una de las mejores y más extensibles herramientas se desarrollo disponibles actualmente. Debido a a facilidad para poder generar extensiones de funcionalidad y visualizadores, dispone de distintas distribuciones adaptadas a las distintas necesidades del proceso de generación de un proyecto.

En el caso que nos ocupa, hablaremos principalmente de la distribución específica de J2EE.

4.1.2. Instalación de Eclipse para PHP

Descargar e instalar el JRE para nuestro sistema operativo: http://www.java.com/es/download/manual.jsp

Page 30: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

16

Descargar e instalar la versión de Eclipse para desarrolladores PHP desde: http://www.eclipse.org/downloads/

4.1.3. Gestión de versiones: SVN

En la comunidad de software libre colaboran en la construcción de código y documentos muchas personas. El trabajo de construcción de código de manera colaborativa se puede realizar gracias a un eficiente uso de sistemas de control de versiones. Un sistema de control de versiones es fundamentalmente un software con una metodología que permite

almacenar los elementos que se vayan a gestionar (texto, imágenes) en un depósito común y poder hacer cambios sobre los mismos.

saber qué cambios se han realizado en los elementos y quién los ha realizado. Si además son ficheros de texto podemos saber que se ha cambiado con exactitud.

volver en algún punto hacia atrás el código, retornar a un estado anterior.

Además se pueden gestionar ramificaciones en el código para trabajar en funcionalidades nuevas sin romper la aplicación que funciona, importar código de depósitos independientes, hacer marcas de versiones que sean hitos importantes. Con todo ello podemos llegar a tener una línea temporal (más que una línea es un árbol) donde podemos visualizar cual ha sido la evolución de nuestro código en cada momento.

Existen muchos gestores de versiones de código: Git, Mercurial, Bazaar, pero quizás uno de los más utilizados sea Subversion http://subversion.tigris.org/. Subversion surge de replantear desde cero otro sistema más antiguo llamado CVS de manera que el nuevo sistema no tuviera lo mismos fallos que el anterior pero si todo lo bueno que había aportado. Tanto Subversion como CVS son sistema de control de versiones centralizados, donde hay un sólo deposito que almacena el código. En contra punto tenemos que Git y Mercurial son distribuidos y el depósito completo es la suma de todos los depósitos parciales de los participantes.

Crear un depósito o repositorio es simplemente indicar al programa que determinado directorio va a ser el almacén de código. El gestor de versiones almacenará meta-datos de cambios, fechas y autores en ficheros y carpetas no visibles dentro de este directorio. Si queremos que el repositorio sea público además deberemos configurar Apache para que lo sirva mediante Webdav+svn. El depósito creado puede estar vacío, pero a partir de aquí nosotros trabajaremos en una copia desde la que nos bajaremos (update) y subiremos (commit) los cambios.

Habitualmente se comienza un proyecto creando 3 directorios dentro del depósito: trunk/tronco, tags/etiquetas y branches/ramas. En trunk se almacenaría el desarrollo principal del proyecto. En determinado momento puede que tengamos nuestra aplicación funcionando como queremos (a falta de más cosas quizás) pero nos interesa marcar que esta versión en concreto está funcionando. Estas marcas se guardan en tags/etiquetas. La mayoría de los contribuidores a tu proyecto tendrán su propia carpeta en branches/ramas para hacer sus desarrollos. Cuando estén seguros de que todo va a ir bien es cuando se hace un merge/fusión con el trunk/tronco. Los branches también son muy utilizados para hacer experimentos o pruebas que pueden romperlo todo.

En la mayoría de los casos los commits, updates y merges mezclan correctamente el código nuevo con el que existía, integrando solo los cambios (también se dice diff o delta). Pero se puede dar el caso de el sistema no pueda hacer la integración y entonces es cuando se produce un conflicto que debe ser resuelto por el desarrollador a mano.

Page 31: Php-Mysql

HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP

17

4.1.3.1. Primeros pasos con Subversion

La manera de más rápida de ponerse a funcionar con Subversión es mediante la línea de comandos. En todo caso existen muchos programas libres para la gestión mediante interfaz visual del repositorio y continuamente se están lanzando plugins para programas tanto editores de código como de otro ámbito que permiten hacer commits, updates y diffs de esta tercera aplicación.

Puedes descargar Subversion para Ms Windows de aquí: http://www.collab.net/downloads/subversion/, pulsando en el primer botón de DOWNLOAD. Cuando termine la descarga instala la aplicación. Si te pide reiniciar el sistema haz lo. Los usuarios de GNU/Linux, BSDs y MacOSX podrán instalar el software según el método habitual de su distribución. Para verificar que la instalación ha tenido éxito abre la línea de comandos y escribe “svn” luego pulsa intro. Si te aparece algo similar a lo siguiente es que todo ha ido bien. Type ‘svn help’ for usage.

4.1.3.2. Crear un repositorio

Vamos a crear nuestro primer repositorio. Para no complicar mucho las cosas en Ms Windows lo crearemos en la carpeta raíz y en los UNIX en nuestro home:

En Windows: cd c:\ svnadmin create reposvn

En UNIX cd svnadmin create reposvn

Ahora vamos a hacernos una copia del depósito vacío para continuar trabajando desde nuestra copia local. Lo primero es el lugar de origen y lo segundo es el destino. svn co file:///c:/reposvn/ copiasvn svn co file:///home/usuario/reposvn copiasvn

A partir de este momento trabajamos exclusivamente desde la copia. Crearemos la estructura inicial de carpetas recomendada:

Creamos las carpetas trunk, branches y tags en la carpeta copiasvn con nuestro gestor de ficheros habitual. Estas carpetas todavía no están controladas por el sistema de gestión de versiones hasta que no hagamos el siguiente comando: cd copiasvn svn add trunk tags branches svn ci -m "subiendo estructura inicial"

Con el comando svn add estamos añadiendo estos tres directorios (podrían ser ficheros de texto o imágenes o cualquier otro tipo de fichero) al control de versiones, pero todavía se encuentran únicamente en nuestra copia local. Con svn ci subimos nuestros cambios de la copia local al depósito principal y mediante el parámetro -m “mensaje” estamos incluyendo un breve comentario entre las comillas para explicar porque hemos hecho esos cambios. Eso ayudaría a otros desarrolladores, en un entorno colaborativo, a identificar tu contribución.

Para tener más juego ahora nos haremos otra copia local:

En Windows: svn co file:///c:/reposvn/ segundacopiasvn

En Unix:

Page 32: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

18

svn co file:///home/usuario/reposvn segundacopiasvn

Como veremos ahora se nos bajan los directorios estructurales.

Dentro de trunk creamos un fichero de texto que llamaremos LEEME. Si le pedimos a Subversión que nos diga el estado nos dirá lo siguiente:

Comando: svn status -u segundacopiasvn

Respuesta: ? trunk/LEEME

La interrogación ? indica los ficheros que no están bajo el sistema de control. En lugar de la interrogación también nos podría aparecer: M: el fichero o directorio ha sido modificado en local *: el fichero o directorio ha sido modificado en el depósito principal pero todavía no nos hemos bajado los cambios. C: el fichero o directorio tiene un conflicto no resuelto. A: el fichero o directorio ha sido añadido pero todavía no lo hemos subido al depósito principal D: el fichero o directorio va a ser borrado. I: el fichero o directorio es ignorado. !: un fichero o directorio que estaba siendo gestionado por el control de versiones a desaparecido. Si hacemos svn update se restablecerá con la versión del depósito principal.

Vamos a añadir el fichero LEEME y subirlo al repositorio: svn add LEEME svn ci -m "necesitaba un fichero para escribir la ayuda" LEEME

Ahora vamos a la primera copia local que hicimos: svn status -u copiasvn

Veremos que está pendiente de ser actualizada. svn update copiasvn

y ahora en copiasvn/trunk aparecerá el fichero LEEME que creamos como si fuéramos otro usuario en otra copia.

En un entorno remoto con un depósito compartido es donde todo esto cobra sentido. Subversión permite operar de la misma manera accediendo mediante URLs http://example.com/reposvn/trunk en lugar de rutas a directorios y ficheros locales.

Esto es lo básico para comprender y empezar a trabajar con Subversion, según la metodología elegida o nuestra forma personal de trabajo se pueden hacer muchas cosas más y es muy recomendable leer el manual oficial del equipo de desarrollo de Subversión ya que, como decíamos, no solo se ofrece una herramienta con unas funcionalidades sino también una metodología de trabajo. http://svnbook.red-bean.com/

Page 33: Php-Mysql

HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP

19

4.1.3.3. Instalación de la extensión de SVN para Eclipse

• Comience la instalación desde el menú ayuda de eclipse, Ayuda/instalar actualizaciones/encontrar e instalar.

• Seleccione que quiere buscar nuevas funcionalidades para instalar.

• Seleccione nuevo sitio de actualizaciones e introduzca la siguiente URL: http://subclipse.tigris.org/update_1.6.x

• Seleccione el nuevo sitio introducido.

• Seleccione el meta-paquete subeclipse.

• Acepte la licencia.

• Instale.

• Espere a que termine de descargar e instalar la extensión.

• Seguramente le pida reiniciar eclipse.

4.2. Firefox y sus extensiones

4.2.1. Referencias

• Web developer: tutorial

• Yslow

• Firebug

4.2.2. Contenido

De cara a poder presentar Firefox como una herramienta útil para desarrolladores web. Indicaremos la principales extensiones disponibles que permiten mejorar incluso depurar aplicaciones web, tanto a nivel de funcionalidad como a nivel de estándares de calidad y accesibilidad.

En esta parte del tema presentaremos 3 extensiones: Web Developer, Yslow y Firebug.

4.2.2.1. Web Developer

Link de Descarga: https://addons.mozilla.org/es-ES/firefox/addon/60 Una de las herramientas mas potente que puede ofrecer Firefox es Web Developer. Este agregado pone a disposición una serie de herramientas fundamentales para cualquier diseñador/desarrollador web. En este tutorial vamos a desglosar generalmente todas las funciones que nos ofrece web developer, quien puede convertirse en un gran compañero de trabajo.

Page 34: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

20

La primer herramienta que nos ofrece es “Disable”, esta permite activar y desactivar funciones dinámicas de los sitios webs como puede ser Java, Javascript en su totalidad o solo alarmas estrictas y la cache. también te permite desactivar el color de una pagina, pop-ups, fuentes mínimas entre otras cosas, esto vendría a ser como un depurador para comprobar funcionalidades dinámicas.

Continuando con este apartado nos encontramos con “Cookies”, donde su palabra lo dice todo. Podemos gestionar todo tipo de pruebas, como desactivarlas, borrarlas, ver su información y mas.

Una vez que comprobamos esto entramos en el apartado de diseño con la opción “CSS”. Aquí tenéis la posibilidad de desactivar las hojas de estilos por partes, ver su información, editar, ver por tipo de medio.

“Forms” comprueba tus formularios mostrándote sus elementos ocultos, sus etiquetas Con “Images” podes deshabilitar las mismas, mostrar sus atributos ALT, ver sus dimensiones, rutas, esconderlas y mas

“Information” te permite ver información especifica sobre las diferentes etiquetas en si es lo que hace.

“Miscellaneus” te permite ver y mover lineas guías, medir zonas o imágenes con una regla, mostrar elementos ocultos, editar HTML, marcar los links como visitados y mas…

“Outline” es una de las herramientas esenciales, con este menú podes ver el tamaño de los diferentes elementos en tu pagina a través de una linea. Podes ver lo que ocupa tus cabeceras, frames, elementos de bloques y mas.

“Resize” su nombre lo dice todo, con esta opción podes ver tus paginas en diferentes resoluciones y realizar Zoom.

En “Tools” se encuentran Validadores, a través de este menú podes validar tus paginas en la W3C, WAI, buscar errores java y también validar css y html de forma local entre mas opciones.

“View Source” te permite ver el código puro y duro de la pagina en visualización, ver código generado, de frames y mas.

Por ultimo tenemos el botón “Options”, el cual te permite modificar muchos parámetros de este fabuloso agregado que es una herramienta fundamental para cualquier webmaster. debug

Al lado derecho de “Options” está disponible este debugger que te avisa sobre los errores de Javascript y CSS, así como también el modo actual del navegador.

Simplemente funcional y perfecta en su desempeño, Web Developer recorre cada rincón de tu pagina web haciendo que el análisis y la búsqueda de errores no sea para nada estresante.

4.2.2.2. Yslow

Link de Descarga: https://addons.mozilla.org/es-ES/firefox/addon/5369

Las opciones de Yslow son variadas pero cabe destacar las siguientes:

Valoración del grado de accesibilidad

Descripción de los elementos mostrados

Page 35: Php-Mysql

HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP

21

JS

CSS

Imágenes

DOM

Tiempos de carga

4.2.2.3.

4.2.2.4. Firebug

Link de Descarga: https://addons.mozilla.org/es-ES/firefox/addon/1843

Nos Permite:

Inspeccionar y editar el HTML, JS y CSS

Visualización del DOM

Ver los recursos cargados

Depuración de AJAX.

4.2.3. Mysql WorkBench

4.2.3.1. Uso de Mysql WorkBench

La compra de MySQL AB por parte de Sun Microsystems y posteriormente por parte de Oracle, es sin lugar a dudas un reconocimiento al buen trabajo hecho por la comunidad de MySQL, para llevar a esta base de datos a ser una de las mejores bases de datos open source que se encuentre en el mercado, y que hoy por hoy es la base de datos predilecta por los desarrolladores, e incluso grandes empresas como Suzuki, Sagem, o la misma Adobe o sitios como Yahoo! Finance, para bases de datos transaccionales o bodegas de datos (Data Warehousing).MySQL provee entre sus herramientas, una denominada MySQL WorkBench la cual nos permite desde una ambiente gráfico, diseñar un modelo E-R de una base de datos y luego crear la base de datos, como tal en una base de datos MySQL. Para este tutorial es necesario tener instalado:

MySQL 5.x o superior

MySQL WorkBench 5.x.x

NOTA: En esta demo, solo se mostrará el funcionamiento de MySQL Workbench, pero no la instalación de éste ni la de MySQL Server. El servidor Mysql puede estar instalado en cualquier equipo y/o sistema operativo soportado (Windows, Linux, Aix, etc). MySQL Workbench solo se encuentra disponible para Windows. En el ejemplo crearemos una base de datos muy sencilla, la cual no representa un ejemplo real. Simplemente es para probar las características. Primero creemos el esquema “test”, haciendo clic en el símbolo “+”. Abajo se abre una pestaña en que nos pregunta el nombre del esquema (test) y el idioma del esquema, el cual se recomienda dejar por default como se muestra

Page 36: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

22

en la figura. Si la aplicación pregunta si desean renombrar todos los objetos, seleccionen “Si”.

Ya creado el esquema, procedemos a crear las tablas. Existen dos formas, aunque muy similares de crearlas. La primera es desde la pantalla en la que estamos, la otra es mediante la ventana visual, en la cual podremos además, realizar las relaciones entre las tablas. Pero primero lo primero; las tablas. Verifica que estés en el esquema “test” y luego haz doble clic en el icono de “Add Table”. Al hacer clic en esta opción, se despliega al lado un icono representando la nueva tabla, mientras que debajo se abre una nueva pestaña, en la cual podemos editar todo al respecto de las tablas haciendo (Columnas, llaves, triggers, etc) clic en cada una de las pestañas ubicadas en la parte inferior de esta nueva pestaña. Nota: los triggers solo están disponibles a partir de MySQL 5. Cualquier tabla con triggers generada en Workbench arrojará un error cuando se corra en una versión inferior a MySQL 5.0 Agregaremos un par de columnas a la tabla:

Al hacer clic en la pestaña “Columns”, podemos editar todas las columnas de la tabla indicada. Podemos alterar el nombre, el tipo de dato, si es nulo o no (NN) y si es Auto incremental (AI), obviamente este último es sólo para datos de tipo numérico, De igual forma podemos especificar un valor por default para la columna. En la parte derecha, inmediatamente podemos indicar si la columna seleccionada hace parte de la llave primaria (PRIMARY KEY), si es UNSIGNED o ZEROFILL para las variables numéricas y si la variable es de tipo carácter, podemos especificar si es BINARY. Ahora pasemos a crear una tabla por medio de un diagrama E-R. En la parte superior observamos la opción “Add Diagram”. Hacemos doble clic sobre ella.

Luego se abre una nueva pestaña en la cual encontramos un grid. A la izquierda, encontramos una barra de herramientas, desde la cual podremos crear tablas y vistas, además de relaciones (1:1,1:n,n:m…) y a la derecha un árbol con los objetos de nuestro esquema (tablas, vistas, etc). De esa ventana, seleccionamos la tabla que creamos y la arrastramos hasta el grid. Luego hacemos clic derecho y seleccionamos “Edit table”, abajo nos muestra la pestaña para editar la tabla y crear columnas, llaves, etc. Buscamos a la izquierda el icono que nos permite crear una nueva tabla. Hacemos un clic en el icono y luego un clic en el grid.

Editamos las segunda tabla y ahora haremos una relación muchos a uno. Seleccionamos el icono, y luego cada una de las tablas (primero la de muchos y luego la de uno). En mi caso, la tabla de “muchos” es table1. Quedaría algo así: Como ven el Workbench se apega a la teoría relacional, donde en este caso la llave de a relación “uno” pasa a la tabla de “muchos”. Igualmente si creamos una relación M.N (muchos a muchos) generará una relación entre las dos tablas. A continuación viene la mejor parte de esta herramienta: la generación del script SQL. Como ven, podemos exportar el diseño, incluso como una imagen en pdf, o en png, entre otros. La primera pantalla, nos muestra las opciones con las que queremos que se genere el script DDL. Luego seleccionamos la ubicación destino del archivo que se creará.

Luego nos muestra un resumen de lo que creará; usuarios, tablas, vistas, rutinas y triggers. Incluso si seleccionamos el botón “Detailed Selection” de cada sección, podemos especificar aún más, por ejemplo, qué tablas deseo realmente exportar.

Luego finalizar, y en la ruta que le hallamos indicado estará un archivo .sql, con nuestro script. Como se podrán dar cuenta Workbench, resuelve algunas limitantes en la comunidad open source de un buen software front-end para MySQL, y sobre todo de una herramienta que provea Forward Engineering, de una manera tan sencilla y bien ilustrada. Digamos que la única limitante de WorkBench es su ausencia en otras plataformas.

4.2.4. Publicación de Código

Page 37: Php-Mysql

HERRAMIENTAS DE DESARROLLO DE PROYECTOS PARA PHP

23

Una vez realizada toda la instalación del Entorno *AMP, si necesitamos colocar código accesible desde el servidor web, será necesario colocar los ficheros y carpetas en un directorio que depende de la instalación. En Linux normalmente será /var/www , en Windows será C:\XAMPP\htdocs

Page 38: Php-Mysql
Page 39: Php-Mysql

PHP BASICO

25

PHP Básico

Lo primero de todo, ¿que significa PHP?. En un principio, significaba “Personal Home Page Tools” pero más tarde - en la versión 3 de PHP - se decidió usar un acrónimo recursivo (donde una de las letras hace referencia al propio acrónimo) cambiando el nombre a PHP Hypertext Preprocessor.

Es un lenguaje orientado a crear páginas web dinámicas en las que podemos acceder a una base de datos. Es multiplataforma, esto es, puede funcionar en varios sistemas operativos, como Linux, Windows, o Mac OS. Además es libre, por lo que se presenta como una alternativa de fácil acceso para todos (si estás interesado en conocer algo acerca del Software Libre puedes visitar este enlace de la wikipedia http://es.wikipedia.org/wiki/Software_libre).

A diferencia de otros lenguajes de programación como C, PHP es un lenguaje interpretado. Es decir, a la hora de ejecutar nuestro programa, no hace falta traducir nuestro código a un lenguaje que entienda el ordenador (a este proceso de “traducción” se le llama “compilar”), si no que hay un intérprete que es el que le dice al ordenador que es lo que queremos que haga. Esto hace que el desarrollo de aplicaciones sea más rápido ya que no hace falta compilar cada vez que hagamos el más mínimo cambio en nuestro código. En nuestro caso, al código al ser interpretado, también se le llama “script”.

¿Como funciona el proceso de ejecución de una web en php?

1. Pepito accede desde su navegador a nuestro documento con código PHP.

2. El servidor recibe la petición y localiza el documento.

Page 40: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

26

3. El servidor arranca el interprete que traduce nuestro código y lo ejecuta.

4. El interprete, tras ejecutarlo, se lo devuelve al servidor, ya traducido en html.

5. El servidor manda el código html al navegador web de Pepito para que vea nuestra web.

A modo de curiosidad: aunque PHP se concibió originalmente para la creación de páginas web, existe la posibilidad de usarlo como cualquier otro lenguaje de programación interpretado como Python o Perl, si se ejecuta con su interprete desde línea de comandos con phpCLI (php Command Line Interpreter o Interprete en Linea de Comandos de php), esto es, sin que tenga que haber una interacción entre el servidor y un navegador web.

5.1. Estructura básica de un fichero PHP

Nuestro script PHP puede estar sólo en un fichero, pero también puede estar incrustado en código HTML. Para que nuestro interprete pueda diferenciar qué es código PHP y código HTML, usamos las etiquetas <?php y ?>. Estas etiquetas indican donde empieza y donde acaba nuestro código PHP. También se puede usar exclusivamente <? y ?> siempre y cuando, en nuestro servidor la directiva short_open_tag esté activada. Es mas podríamos prescindir de la etiqueta ?> si en nuestro fichero sólo vamos a usar código php.

Veamos un ejemplo. Tranquilo/a si no entiendes nada de lo que hay a continuación, ya lo veremos más tarde. <?php //aquí empieza nuestro código php $a = "Hola mundo."; echo $a; //aquí termina nuestro código php ?>

Como ves, se han colocado las etiquetas <?php y ?> y dentro nuestro script. En este caso si ejecutamos este script, el resultado al acceder por nuestro navegador seria el siguiente: Hola mundo.

“Mágicamente” el texto en el que se explica donde empieza y donde termina el código php no aparece. A esto se le llama comentarios (y los vas a ver mucho en este curso :D).

En los lenguajes de programación se puede (y se debe) colocar comentarios para explicar parte del código, así cuando tengamos que retomar nuestro script o cuando otra persona tenga que retocar nuestro código, podremos saber de forma más rápida que es lo que estamos haciendo. Podemos poner comentarios en una sola linea o en bloque. <?php //Este es un comentario en una linea /* Este es un comentario en bloque Este es un comentario en bloque Este es un comentario en bloque Este es un comentario en bloque*/ ?>

Casi siempre que escribamos una instrucción hay que terminar dicha instrucción con el carácter ; (hay algunas excepciones, como los comentarios, que ya las iremos viendo más adelante)

Page 41: Php-Mysql

PHP BASICO

27

¡Ah! Y un pequeño consejo, cuando programes, intenta indentar tu código para una mayor legibilidad. En PHP se podría escribir todo un programa en una sola linea kilométrica, pero es altamente aconsejable que separes cada cosa que hagas en lineas diferentes y con una identación adecuada. El resto de programadores (y tú mismo/a) te lo agradecerán cuando tengan que revisar tu código.

5.1.1. Inclusión de ficheros externos

Como dijo Julio César, Divide y vencerás. En la cultura popular, divide y vencerás hace referencia a un refrán que implica resolver un problema difícil, dividiéndolo en partes más simples tantas veces como sea necesario, hasta que la resolución de las partes se torna obvia. La solución del problema principal se construye con las soluciones encontradas.

Dicha técnica que veremos un poco más adelante cuando entremos a hablar de “funciones” también nos sirve como excusa para explicar la inclusión de ficheros externos.

Como se ha comentado anteriormente, se en php se podría escribir todo un programa en una sola línea, pero no debemos hacerlo por tener una mejor lectura de nuestro código. Asimismo podríamos dividir nuestro código en diferentes ficheros para que en cada fichero tengamos algo específico y nos sea más fácil encontrar un código en concreto si estamos buscando algún error.

Pongamos un sencillo ejemplo. Imaginemos que en nuestra aplicación web queremos acceder a una base de datos (o bbdd) y hacer complicadas operaciones matemáticas.

Para ello podríamos crear un fichero llamado index.php donde estuviese toda la lógica principal de nuestro programa, crear otro llamado basededatos.php y otro llamado matematicas.php donde tengamos los complicados cálculos. Así si tenemos un problema al acceder a la bbdd, solo tendríamos que revisar el archivo basededatos.php y lo mismo con los cálculos matemáticos.

PHP nos deja incluir ficheros externos mediante los métodos include, require, include_once y require_once.

Así en nuestro programa principal en el fichero index.php tendríamos: <?php include "basededatos.php"; include "matematicas.php"; //aquí empieza nuestro código del programa principal ... //aquí termina nuestro código del programa principal ?>

Esto nos sirve no sólo para tener funcionalidades específicas que creemos nosotros en ficheros a parte, si no que además nos permite incluir librerías y funcionalidades creadas por otras personas, que nos pueden facilitar mucho la vida.

¿Cuales son las diferencias entre require, require_once, include e include_once?

Bien, entre require e include:

require buscará el fichero, si este no existe, mostrara un “Fatal Error”, y parará la ejecución de nuestra aplicación.

include buscará el fichero, si este no existe mostrará un “Warning” y dejará que nuestra aplicación siga su curso.

Page 42: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

28

require_once e include_once siguen la misma norma que require e include acerca de los Fatal Error y de los Warning. La diferencia radica en que require_once e include_once, sólo se ejecutarán una vez. Si por alguna razón el trozo de código en el que están require_once o include_once vuelve a ejecutarse, php lo ignorará.

5.2. Elementos del Lenguaje:

A continuación veremos algunos elementos que tendremos que usar a la hora de crear nuestros programas.

5.2.1. Variables

Una variable se puede definir como porción de memoria que ha sido creada para el almacenamiento de algún valor. Valor que puede variar a lo largo de la ejecución de nuestro script.

Por ejemplo, en una ecuación normal del tipo “2 + x = 4”, x sería nuestra variable, y en este caso almacenaría el número 2.

A la hora de programar esto es más o menos lo mismo, solo que las variables pueden almacenar algo más que simples números. En el caso de PHP se pueden almacenar los siguientes tipos de datos:

Números enteros, también llamado int (de integer)

Números de coma flotante, es decir números decimales, también llamados float (de Floating Point number)

Cadenas de texto, esto es, palabras, sílabas, frases. También conocidos como str (de String)

Arrays también conocidos como matrices. contienen más de un valor y de diferentes tipos. Puede contener por ejemplo, 2 enteros, 5 decimales, 10 cadenas de texto, 3 objetos e incluso más arrays.

Booleanos, sus únicos valores pueden ser true o false (Verdadero o falso)

Objetos Un Objeto, es un contenedor de uno o más datos (variables o propiedades miembro) junto a las operaciones de manipulación de dichos datos (funciones/métodos). Ya los veremos más adelante.

En php para identificar una variable, se le antepone el símbolo $.

Así pues en el primer ejemplo que pusimos en este temario $a = “Hola mundo”; vemos como $a es realmente una variable que está almacenando una cadena de texto con el valor “Hola mundo”.

Veamos algunos ejemplos de como operar con variables. <?php $a = 1; //El valor de $a es 1 $a = 2; //El valor de $a es 2 $a + 1; //En este caso si usásemos el método "echo" para escribir por pantalla, aparecería el valor 3, pero $a seguiría siendo 2 $b = $a + 1; //$b valdria $a + 1 en este caso 2 + 1, es decir $b es

Page 43: Php-Mysql

PHP BASICO

29

3 $c = $b - $a //$c valdría $b menos el valor de $a, en este caso 3 - 2, es decir $c es igual a 1 ?>

En php el tipado de las variables es dinámico. En otros lenguajes de programación antes de usar una variable hay que crearla y decir de que tipo es. Por ejemplo en C habría que hacer int a; a = 1;

Es más, ni siquiera se podría asignar valores que no fuesen de ese mismo tipo. Es decir, a una variable de tipo int no se le puede asignar un valor decimal (ya que sería un tipo de dato float)

En nuestro caso, en PHP, no hace falta crearla (o inicializarla), ya que se pueden hacer estas operaciones al vuelo. Además se le puede cambiar el tipo de dato sin problemas asignándole un valor distinto.

Veamos como se comportarían las variables en ficheros externos mediante el uso de require, include, require_once, e include_once.

Imaginemos que tenemos 2 ficheros, fichero1.php y fichero 2.php

fichero1.php: <?php $variable = 10; ?>

fichero2.php: <?php include “fichero1.php”; echo $variable; //esto mostraria por la pantalla 10 $variable = 20; include “fichero1.php”; echo $variable; //esto volveria a mostrar por pantalla 10 y no 20 ya que se ha //vuelto a ejecutar nuestro fichero1.php ?>

Ahora modifiquemos fichero2.php: <?php include_once “fichero1.php”; echo $variable; //esto mostraria por la pantalla 10 $variable = 20; include_once “fichero1.php”; echo $variable; //esto ahora mostraria 20 por que php al ser un include_once ha //ignorado la ejecución de nuestro script fichero1.php ?>

5.2.2. Constantes

A diferencia de las variables, las constantes no varían su valor a lo largo de la ejecución de nuestra aplicación. Además estas no llevan el símbolo $ precediéndoles Se declaran de la siguiente forma <?php define("NOMBREVARIABLE", "valor"); define("NOMBREVARIABLE2", 27); echo NOMBREVARIABLE;

Page 44: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

30

echo "<br />"; echo NOMBREVARIABLE2; ?>

Al usar el comando “echo” nos saldría por pantalla lo siguiente (nótese que se ha puesto un salto de carro html en el segundo “echo”): valor 27

Es aconsejable utilizar mayúsculas para declarar el nombre de las constantes.

5.2.3. Operadores

Operadores Aritméticos Sintaxis Nombre Descripción $a + $b Suma Suma de $a y $b. $a - $b Resta Diferencia entre $a y $b $a * $b Multiplicación Producto de $a y $b $a / $b División Cociente de $a entre $b

$a % $b Módulo Resto de la división de $a entre $b

Operador de Asignación Este operador ya lo hemos visto en la sección de las variables el símbolo ”=”. Básicamente la variable de la izquierda toma el valor de la expresión que se encuentre después del símbolo =.

Se puede enrevesar un poco las asignaciones como veremos a continuación. <?php $a = ($b = 5) + 3; /* En este caso habríamos inicializado 2 variables. $a y $b * $b tendría el valor 5, pero $a tendría el valor $b + 3, * es decir, 8. */ ?>

Es posible combinar el operador de asignación con operadores aritméticos. <?php $a = 2; //Inicializamos la variable $a $a += 1; // Esto equivaldría a $a = $a + 1 Es decir, a $a le asignamos su valor mas 1, en este caso, 3 ?>

Operadores de Comparación Los operadores de comparación, como su nombre indica, permiten comparar dos valores. Veremos su uso un poco más adelante, en las estructuras de control.

Sintaxis Nombre Descripción $a == $b Igualdad Cierto si $a es igual a $b.

$a === $b Identidad Cierto si $a es igual a $b y si son del mismo tipo (sólo PHP4)

$a != $b Desigualdad Cierto si $a no es igual a $b. $a < $b Menor que Cierto si $a es estrictamente

Page 45: Php-Mysql

PHP BASICO

31

menor que $b. $a > $b Mayor que Cierto si $a es estrictamente

mayor que $b. $a <= $b Menor o igual que Cierto si $a es menor o igual

que $b. $a >= $b Mayor o igual que Cierto si $a es mayor o igual

que $b.

¡Ojo!, un error muy habitual es confundir = con ==. El primero es asignación y el segundo comparación.

Operadores de Incremento/Decremento Sintaxis Nombre Descripción

++$a Preincremento Incrementa $a en uno y después devuelve $a.

$a++ Postincremento Devuelve $a y después incrementa $a en uno.

–$a Predecremento Decrementa $a en uno y después devuelve $a.

$a– Postdecremento Devuelve $a y después decrementa $a en uno.

Esto puede ser un poco lío, veamos un ejemplo <?php echo "Postincremento<br />"; $a = 1; echo "Al usar el operador el valor es 1: " . $a++ . ". Después de usarlo es 2: ". $a."<br />"; echo "Preincremento<br />"; $a = 1; echo "Al usar el operador el valor es 2: " . ++$a . ". Después de usarlo es 2: ". $a."<br />"; echo "Postdecremento<br />"; $a = 2; echo "Al usar el operador el valor es 2: " . $a-- . ". Después de usarlo es 1: ". $a."<br />"; echo "Predecremento<br />"; $a = 2; echo "Al usar el operador el valor es 1: " . --$a . ". Después de usarlo es 1: ". $a."<br />"; ?>

Esto nos devolvería lo siguiente: Postincremento Al usar el operador el valor es 1: 1. Después de usarlo es 2: 2 Preincremento Al usar el operador el valor es 2: 2. Después de usarlo es 2: 2 Postdecremento Al usar el operador el valor es 2: 2. Después de usarlo es 1: 1 Predecremento Al usar el operador el valor es 1: 1. Después de usarlo es 1: 1

Operadores Lógicos Su uso más habitual suele ser con tipos de datos booleanos. Los veremos también en más adelante en las estructuras de control.

Page 46: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

32

Sintaxis Nombre Descripción $a and $b ó $a && $b Y Cierto si tanto $a como $b son

ciertos. $a or $b ó $a || $b O Cierto si $a o $b son ciertos.

$a xor $b O exclusiva Cierto si $a es cierto o $b es cierto, pero no ambos a la vez.

! $a Negación Cierto si $a no es cierto.

5.3. Tipo de datos abstractos:

5.3.1. Manejo de Cadenas de caracteres

Es hora de profundizar un poco en las cadenas de caracteres o strings.

Hay 4 formas de delimitar una cadena de caracteres en PHP.

• Comillas simples

• Comillas dobles

• Documento incrustado “heredoc” (Desde PHP 4)

• Documento incrustado “nowdoc” (Desde PHP 5.3.0)

Comillas simples La forma más sencilla de especificar una cadena es acotarla mediante comillas simples (el signo ').

Si se quiere poner dentro del texto una comilla simple hay que escaparla con el símbolo “backslash” (la barra inclinada a la izquierda \), de esta forma \'. Si se quiere poner esta barra de forma literal, hay que duplicar la barra: \\.

Veamos unos ejemplos: <?php echo 'esta es una cadena normal'; echo 'Se pueden poner varias lineas de esta forma sin ningún problema'; echo 'Para escribir el símbolo "\'" hay que usar la barra "\\"'; // Esto mostraría: Para escribir el símbolo "'" hay que usar la barra "\" ?>

Comillas dobles Si la cadena de texto esta acotada entre comillas dobles (”), PHP podrá interpretar mas secuencias de escape para caracteres especiales.

Secuencia de caracteres escapados Significado \n salto de linea (LF or 0x0A (10) in ASCII) \r retorno de carro (CR or 0x0D (13) in ASCII)

Page 47: Php-Mysql

PHP BASICO

33

\t tabulación horizontal (HT or 0x09 (9) in ASCII) \v tabulación vertical (VT or 0x0B (11) in ASCII)

(desde PHP 5.2.5) \f form feed (FF or 0x0C (12) in ASCII) (desde

PHP 5.2.5) \\ barra \$ signo dolar \" comilla doble

\[0-7]{1,3} Carácter ASCII que coincide con el numero octal

\x[0-9A-Fa-f]{1,2} Carácter ASCII que coincide con el numero hexadecimal

Si intentamos escapar cualquier otro carácter con la la barra “backslash”, dicha barra aparecerá también (cosa que también ocurre en las comillas simples)

Lo más importante de las cadenas acotadas con comillas dobles, es el hecho de que las variables pueden ser expandidas (mostradas). <?php $variable = "pepe"; echo "mi nombre es $variable"; //Esto mostraría: mi nombre es pepe ?>

Heredoc Este tipo de documento incrustado incluido en PHP 4, nos permite volcar en la pantalla grandes cantidades de texto, evitando la necesidad de escapar caracteres en su interior.

Su sintaxis es la siguiente. Se coloca el operador: <<< y seguido un identificativo. Acto seguido una nueva linea en la que habrá el texto que queramos, y para finalizar en una nueva linea y SIEMPRE en la primera columna de la linea, de nuevo el identificativo y un punto y coma.

El identificativo puede ser cualquier combinación de letras (habitualmente se usa EOF o EOT, pero se puede usar cualquier otro que no esté en el texto a introducir). Además deberá seguir las mismas reglas que cualquier etiqueta en PHP, es decir, sólo caracteres alfanuméricos o guiones bajos, y debe empezar con un carácter no-numérico o con un guión bajo.

Este tipo de cadena nos permite usar comillas dobles sin necesidad de escape, además como en las comillas dobles también interpreta (expande) las variables, lo cual es muy útil a la hora de insertar gran cantidad de código HTML. <?php $variables = "variables"; $texto = <<<EOT Este es nuestro texto, con "comillas", e incluso usando $variables. EOT; echo $texto; //la salida por pantalla sería: Este es nuestro texto, con "comillas", e

Page 48: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

34

incluso usando variables. ?>

En php 5.3.0 permite declarar el heredoc con el primer identificador entre comillas dobles. <?php $texto = <<<"EOT" Nuestro texto. EOT; ?>

Nowdoc (a partir de PHP 5.3.0) Los documentos incrustados tipo nowdocs son a las strings de comillas simples, lo que los “heredocs” a las strings de comillas dobles. Un Nowdoc es prácticamente lo mismo que un heredoc, pero en el cual no se parsearán las variables. Es útil cuando necesitamos escribir grandes cantidades de texto que no necesiten mostrar variables etc…

Su sintaxis es similar al de un heredoc, solo que el primer identificador tiene que ir entre comillas simples: <?php $texto = <<<'EOT' Nuestro texto. EOT; ?>

5.3.1.1. Operaciones con cadenas de caracteres

Concatenación En php, para concatenar (unir) 2 cadenas de caracteres usaremos el símbolo punto ”.”. Al igual que el operador de suma, permite su combinación con el operador de asignación. <?php $cadena1 = "¡hola "; $cadena2 = "mundo!"; //Para unirlas podríamos hacer lo siguiente $resultado = $cadena1.$cadena2; //También se puede unir de forma literal: $resultado = "¡hola "."mundo!"; //o usando la mezcla del punto con el operador de asignación $cadena1 .= "mundo!"; //en este caso el valor de $cadena1 se modificaría por ¡hola mundo! ?>

Búsqueda A continuación veremos algunas funciones para buscar contenidos dentro de nuestras cadenas.

función descripción strlen(cadena); Nos devuelve el tamaño de la cadena (en nº de

caracteres) substr_count(cadena,subcadena); Devuelve cuantas veces aparece una subcadena

en nuestra cadena

Page 49: Php-Mysql

PHP BASICO

35

strstr(cadena,subcadena); Localiza subcadena dentro de la cadena original stristr(cadena,subcadena); Igual que la función anterior pero sin distinción

entre mayúsculas y minúsculas strpos(cadena,subcadena); Primera ocurrencia de una cadena en otra strrpos(cadena,subcadena); Ultima ocurrencia de una cadena en otra

Extracción función descripción

strchr(cadena,carácter); Devuelve la subcadena que comienza en la primera aparición del carácter indicado

substr(cadena,comienzo,longitud); Devuelve una subcadena que empiece en la posición y tenga la longitud que nosotros

queramos

Comparación función descripción

strcmp(cadena1,cadena2); Compara dos cadenas siendo sensible a mayúsculas y minúsculas

strcasecmp(cadena1,cadena2); Compara dos cadenas sin ser sensible a mayúsculas y minúsculas

strncmp(cadena1,cadena2,tamaño); Compara los N primeros caracteres de una cadena

Alteración función descripción

chop(cadena); Devuelve la cadena de caracteres sin espacios en blanco ni saltos de linea

ltrim(cadena); Elimina los espacios en blanco que estén a la izquierda de una cadena

rtrim(cadena) ; Igual que ltrim pero con el lado derecho trim(cadena); Elimina espacios en blanco a ambos lados de

una cadena str_pad(cadena,longitud,relleno,lugar); Comprueba si la longitud de la cadena es menor

que el valor indicado, si es así añade los caracteres necesarios. El lugar de añadir puede ser: STR_PAD_RIGHT para añadirlos por la

derecha(opción por defecto), STR_PAD_LEFT para la izquierda y STR_PAD_BOTH para

ambos lados str_repeat(carácter,numero_veces); Repite un carácter el numero de veces indicado

strtolower(cadena); Convierte toda la cadena a minúsculas strtoupper(cadena); Convierte toda la cadena a mayúsculas

ucfirst(cadena); Convierte en mayúscula el primer carácter de una cadena

ucwords(cadena); Convierte en mayúsculas el primer carácter de cada palabra de la cadena

str_replace(subcadena1,subcadena2,cadena); Sustituye una palabra por otra dentro de una cadena

strtr(cadena,originales,traducidos); Traduce los caracteres que deseemos substr_replace(cadena,nueva,comienzo,longitud); Sustituye una porción del contenido de una

Page 50: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

36

cadena

Veamos algunos ejemplos de uso. $cadena = "hola mundo!!!"; $valor = strlen($cadena); //$valor valdria 13 $valor = substr_count($cadena, "!");// $valor valdria 3 $valor = strchr($cadena,"!"); //$valor valdria "!!!" $valor = chop($cadena); //$valor valdria "holamundo!!!" $valor = strtoupper($cadena); //$valor valdría "HOLA MUNDO!!!" $valor = strtr($cadena,"aou","áóú"); //$valor valdría "hólá múndó!!!"

5.3.2. Manejo de arrays de datos:

Un array (o matriz, como también son llamados) es un tipo de variable, con la singularidad de que no contiene un único valor, sino un conjunto de valores referenciados con un índice.

Un array se puede crear a través de la función array(). Ésta toma un cierto número de parejas clave � valor separadas con coma. Y para acceder a su valor en la variable, hay que escribir el nombre de la variable y el índice ( también llamado clave o key) entre corchetes. <?php $mi_array = array( key => value , ... ); // key puede ser un entero o una cadena de texto // value puede ser cualquier valor ?>

Veamos un ejemplo: <?php $ciudades = array( 0=>"salamanca", 1=>"valladolid", 2=>"sevilla"); echo $ciudades[0]; //mostraría: salamanca ?>

PHP tiene la ventaja de que se pueden crear arrays dinámicamente. Es decir sin usar la función array(), e incluso podemos añadir más entradas a nuestro array. <?php $ciudades[3] = "barcelona"; $nuevo_array[0] = "pepe"; $nuevo_array[1] = "jose"; ?>

5.3.2.1. Uso asociativo de arrays

Como hemos comentado en un ejemplo, en PHP los índices pueden ser números o cadenas de texto. A los arrays cuyos índices son cadenas de texto se les llama arrays asociativos.

Estos arrays tienen la ventaja de que es más fácil identificar cual es el contenido por el nombre de su clave. Por ejemplo: <?php $direccion = array("calle" => "Gran vía",

Page 51: Php-Mysql

PHP BASICO

37

"portal" => 23, "piso" => 5, "letra" => "B", "telefono" => 91234567); ?>

5.3.2.2. Arrays multidimensionales.

Dentro de un array se pueden almacenar todos los tipos de datos soportados por php, por lo que es posible incluir otros arrays. Imaginemos el caso anterior de la dirección, en la que podríamos tener más de un numero de telefono, el móvil y el de casa: <?php $telefonos = array("casa" => 91234567, "móvil" => 61234567); $direccion = array("calle" => "Gran vía", "portal" => 23, "piso" => 5, "letra" => "B", "telefono" => $telefonos); ?>

Hemos incluido el array $telefonos dentro de la clave “telefono” de nuestro array dirección. La forma de acceder sería muy sencilla: <?php echo $dirección["telefono"]["casa"]; //Mostraría: 91234567 ?>

Para ver una forma de recorrer un array, mira el bucle “foreach” dentro de la sección Bucles, en Estructuras de control.

5.3.2.3. Funciones de manejo de arrays

Aquí veremos algunas funciones que se suelen usar bastante. Para el listado completo visitar: http://www.php.net/manual/es/ref.array.php

Función Descripción array_key_exists Comprueba si el índice o clave dada existe en la

matriz array_keys Devuelve todas las claves de una matriz

array_merge Combina dos o más matrices array_pop Extrae el último elemento de la matriz array_push Inserta uno o más elementos al final de la matriz

array_values Devuelve todos los valores de una matriz count Cuenta los elementos de una matriz o

propiedades de un objeto ia_array Nos dice si una variable es un array o no

5.3.3. Variables predefinidas

PHP tiene un buen número de variables predefinidas de ámbito global que pueden ser accedidas en cualquier punto de nuestro script. Más adelante veremos un punto más centrado en explicar el ámbito de las variables.

Las siguientes variables también son conocidas como superglobales. Su contenido suelen ser arrays de datos.

Page 52: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

38

Variable Definición $GLOBALS Hace referencia a todas las variables disponibles

en ámbito global $_SERVER Información del servidor y del entorno de

ejecución $_GET variables HTTP GET

$_POST variables HTTP POST $_FILES Variables de Carga de Archivos HTTP

$_REQUEST Variables HTTP Request (contiene por defecto las variables $_GET, $_POST y $_COOKIE)

$_SESSION Variables de sesión $_ENV Variables de entorno. Muchas son entregadas

por el intérprete de comandos bajo el que PHP está corriendo y diferentes sistemas suelen tener diferentes tipos de intérpretes de comandos, el listado de variables se puede encontrar en la

documentación del intérprete de comandos que use su sistema.

$_COOKIE Cookies HTTP

5.4. Estructuras de control:

Con las estructuras de control, podremos añadir mucha más lógica a nuestros scripts.

5.4.1. Sentencias condicionales

La sentencia if La sentencia if, sirve para ejecutar un código si se cumple cierta condición.

Su estructura es la siguiente: Si (condición){ ejecuta este código } en caso contrario { ejecuta este otro }

Veámoslo con código php: <?php $edad = 18; if($edad >= 18){ //Si $edad es mayor o igual a 18 echo "Puedes sacarte el carne de conducir"; } else { //si no echo "No puedes sacarte el carne de conducir"; } ?>

En este caso, la sentencia else significa “en caso contrario”. Se puede colocar una sentencia elseif que permite añadir una condición al “caso contrario”. Veamos un ejemplo juntando operadores lógicos y operadores de comparación. <?php $edad = 18; $carnet = true; if($edad >= 18 && $carnet == true){ //si edad es mayor o igual a 18 y

Page 53: Php-Mysql

PHP BASICO

39

carnet es igual a verdadero. echo "Puedes conducir"; } elseif ($edad >=18 && $carnet != true) { //si edad es mayor o igual a 18 y carnet no es igual a verdadero echo "No puedes conducir pero puedes sacarte el carnet"; } else{ echo "No puedes conducir ni sacarte el carnet"; }

Nótese que en valores booleanos hay varias expresiones que funcionan igual. Por ejemplo. <?php $valor = true; //Si queremos que un if se ejecute si el valor es verdadero podemos hacer por ejemplo: if ($valor == true)... //si valor es igual a verdadero if ($valor) //Si valor es verdadero //aunque hay mas formas de complicarlo :) //si queremos que una sentencia if se ejecute cuando valor sea falso podemos hacer lo siguiente if ($valor == false)... //si valor es igual a falso if ($valor != true)... //si valor no es igual a verdadero if (!$valor)... //si "no valor" es verdadero (es decir si valor es falso) Recordar que una sentencia if se ejecuta si el resultado de la condición es verdadero, por lo que para ejecutarse cuando el contenido de una variable es falso, entonces hay que "negar" esa variable. ?>

Nota: El contenido de un if deberá ir siempre entre llaves. Aunque se pueden omitir si el contenido es sólo y exclusivamente una acción. Por ej: <?php //correcto if($i == 1) echo "i es igual a 1"; //incorrecto if($i == 1) echo "i es igual a 1"; $i++; //correcto if($i == 1){ echo "i es igual a 1"; $i++; } ?>

5.4.2. Switch

Con la estructura switch podremos hacer que se ejecute cierto código en concreto, en función del valor de una variable. Es como anidar varios “if”. <?php switch($variable){ case 1: echo '$variable es igual a 1'; break; case 2: echo '$variable es igual a 2'; break; case 3:

Page 54: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

40

echo '$variable es igual a 3'; break; default: echo '$variable no es igual ni a 1 ni a 2 ni a 3'; break; } //esto es igual a: if($variable == 1)} '$variable es igual a 1'; }elseif($variable == 2)} '$variable es igual a 2'; }elseif($variable == 3)} '$variable es igual a 3'; }else{ '$variable no es igual ni a 1 ni a 2 ni a 3'; }else ?>

con la sentencia “default” podemos decir que se ejecute código que no corresponda con ningún caso que propongamos.

5.4.3. Bucles

Hay 3 tipos, “para valor haz”, “mientras valor haz” y “haz mientras valor”, o como comentaba Coti, profesor de la Universidad de Salamanca: “metralleta”, “John Wayne” y “Clint Eastwood”. En php son llamados “for”, “while” y “do… while”.

bucle for Es el tipo “para valor haz” o bucle “metralleta” (es decir se disparara tantas veces como balas haya en el cargador).

El bucle for consta de 3 partes:

• Inicialización: a una variable se le da un valor

• Condición: Cada vez que se inicie el bucle se valorará esta condición, como cualquier sentencia if, se ejecutara si el resultado de la condición es verdadero.

• Actualización: es la parte en la que se puede cambiar el valor de la variable inicializada (esta parte puede quitarse si actualizamos el valor dentro del bucle)

Veamos un ejemplo: <?php for($i = 1; $i <10; $i++){ ... } //es lo mismo que for($i = 1; $i <10; ){ ... $i++; ... } ?>

En este caso este bucle se disparará hasta que el valor de $i sea 10.

Bucle foreach

Page 55: Php-Mysql

PHP BASICO

41

PHP y algunos lenguajes de programación tiene una especie de bucle “for” que se usa para recorrer arrays, el bucle foreach.

Su declaración es la siguiente:

foreach($nombre_variable_con_array as $nombre_inventado_indice

$nombre_inventado_valor) <? $mi_array = array( "uno" => 1, "dos" => 2, "tres" => 3, "cuatro" => cuatro ); foreach($mi_array as $indice => $valor) { print "$mi_array[$indice] => $valor. "; } //esto mostraría: 1 => 1. 2 => 2. 3 => 3. 4 => 4. //si quisiéramos que la salida fuese parecida a uno => 1. dos = 2... el foreach tendría que ser así foreach($mi_array as $indice => $valor) { print "$indice => $valor. "; } ?>

Bucle While El bucle while o bucle “John Wayne” (es decir primero preguntará si la el resultado de la comparación es verdadero antes de disparar el contenido del bucle). <?php $i = false; while($i == true){ ... if (condicionquequeramos) $i = false; ... } ?>

Bucle Do...While El bucle do…while o bucle “Clint Eastwood” (es decir primero se ejecutará una vez y después preguntará si la el resultado de la comparación es verdadero ). Su diferencia, como es obvio con el bucle while, es que este bucle se ejecutará SIEMPRE como mínimo una vez. <?php $i = 1; do{ echo "este bucle se ejecutara solo una vez"; }while($i < 1); ?>

Ojo con las condiciones, ya que si las colocamos mal, podremos provocar un “bucle infinito” en el que no se saldría nunca. Por ejemplo:

Page 56: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

42

<?php $i = 1; do{ echo "este bucle se ejecutara solo una vez"; }while($i == 1); //Al no variar el valor de $i este bucle do-while siempre se ejecutaría ?>

5.4.4. Break y Continue

Break Con Break podemos parar la ejecución de un bucle o de una sentencia switch y hacer que se salga de dicha estructura de control. por ejemplo en un switch, si al final del código que se ejecuta dentro de un “case”, se ejecutaría el siguiente “case” si lo hubiera. Es decir: <?php switch ($valor){ case 1: echo "hola"; case 2: echo "adios"; break; case 3: echo "hola y adios"; break; } ?>

En este código si $valor fuese igual a 1, se ejecutaría el case 1 y case 2 ya que dentro de case 1 no se ha colocado el break.

Continue Con continue podemos volver al principio del bucle desde cualquier parte del mismo.

5.5. Funciones

Durante todo el manual se ha hecho referencia a la palabra función. Pero ¿que es una función exactamente?. Podríamos definirla como un conjunto de instrucciones que nos permiten resolver una tarea específica. Estas tareas pueden ser muy simples como sumar una serie de números, o más complejas como sacar cierta información de una base de datos.

Antes de crear una función para tratar datos, es conveniente mirar la amplia referencia de funciones que tiene php http://www.php.net/manual/es/funcref.php

Una función normal en php se escribe de la siguiente forma: <?php function nombre_función($parametro_1, $parametro_2 ... $parametro_n){ instruccion_1; instruccion_2; .... instruccion_n; return $variable; //con esto podríamos devolver un valor para almacenar en otra variable o para usarla en otra función

Page 57: Php-Mysql

PHP BASICO

43

} ?>

Recuerda “divide y vencerás”, intenta simplificar y dividir las instrucciones en funciones especificas. No es aconsejable tener diferentes funcionalidades dentro de una función. A la hora de revisar y mantener tu código será más fácil.

Veamos una función simple en la que sumamos 3 números pasados como parámetros: <?php //Declaramos la función function suma($valor_1, $valor_2, $valor_3){ $suma = $valor_1 + $valor_2 + $valor_3; return $suma; //con esto podríamos devolver un valor para almacenar en otra variable o para usarla en otra función } //llamamos a la función echo suma(1,2,3); //el resultado por pantalla sería: 6 ?>

5.5.1. Ámbitos de Variables

Existen 2 tipos de ámbitos, globales y locales. Las variables globales, como su nombre indica, pueden ser accedidas desde todo nuestro script, y las locales, solamente se pueden acceder desde la función donde estén declaradas. Las variables locales desaparecen en cuanto se termina de ejecutar la función.

Por ejemplo: <?php //ejemplo de variable global: $mi_variable_global = "pepe"; function mi_función(){ //ejemplo de variable global: $mi_variable_local = "jose"; } ?>

Para poder usar las variables globales dentro de una función, hay que usarla a través de la variable superglobal $GLOBALS, o declarando la variable con el comando global. Si no, la variable que utilizaríamos dentro de la función seria realmente una variable local. Ojo, las variables superglobales vistas en el apartado de variables predefinidas, no necesitan ser declaradas mediante el comando global Veámoslo mejor con un ejemplo: <?php //variable global $mi_variable_global = "pepe"; function modificar_variable_global(){ //uso erróneo de variable global: $mi_variable_global = "jose"; } echo $mi_variable_global; //mostramos el valor de la variable global echo "<br />"; //introducimos un salto de linea modificar_variable_global();

Page 58: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

44

echo $mi_variable_global; //mostramos otra vez el valor de la variable global ?> El resultado en este caso sería: pepe pepe Ya que no hemos instanciado correctamente nuestra variable global. En cambio si hacemos esto: <?php //variable global $mi_variable_global = "pepe"; function modificar_variable_global(){ //uso de variable global a trabes de la variable superglobal $GLOBALS: $GLOBALS['mi_variable_global'] = "jose"; //también se puede hacer de esta forma: global $mi_variable_global; $mi_variable_global = "jose"; } echo $mi_variable_global; //mostramos el valor de la variable global echo "<br />"; //introducimos un salto de linea modificar_variable_global(); echo $mi_variable_global; //mostramos otra vez el valor de la variable global, ahora sí modificada correctamente ?> El resultado seria: pepe jose

5.5.1.1. Variables estáticas

Como hemos comentado el las variables de ámbito local se destruyen al terminar la ejecución de nuestra función, pero existe una forma de hacer preservar su valor, gracias al comando static. Con él, nuestras variables locales mantendrán su valor cada vez que nuestra función sea ejecutada. Por ejemplo: <?php function test(){ static $i = 0; $i++; echo $i." "; } test(); test(); test(); ?>

Page 59: Php-Mysql

PHP BASICO

45

Si ejecutamos este código, la salida por pantalla sería la siguiente: 1 2 3 Si nuestra variable $i no estuviese declarada como static, la salida sería 1 1 1

5.5.2. Paso de variables

Cuando se pasa una variable a una función (un parámetro), esto se puede hacer de 2 formas, por valor, o por referencia).

5.5.2.1. Paso por valor

El paso por valor (por defecto en PHP), hace una copia de la variable que es la que se usa dentro de la función, por lo que si la variable cambia dentro de la función, la variable original estará intacta. <?php function mi_función($parametro){ $parametro++; } $mi_variable = 1; echo "mi_variable vale: ".$mi_variable." antes de llamar a la función"; mi_función($mi_variable); echo "mi_variable vale: ".$mi_variable." después de llamar a la función"; ?> Esto haría que la salida por pantalla fuese la siguiente: mi_variable vale: 1 antes de llamar a la función mi_variable vale: 1 después de llamar a la función

5.5.2.2. Paso por referencia

Con el paso por referencia, a diferencia del paso por valor, se modifica el valor de la original. Hay que anteponer el símbolo & al nombre del parametro en la función: <?php function mi_función(&$parametro){ //atención al símbolo & $parametro++; } $mi_variable = 1; echo "mi_variable vale: ".$mi_variable." antes de llamar a la función"; mi_función($mi_variable); echo "mi_variable vale: ".$mi_variable." después de llamar a la función"; ?> Esto haría que la salida por pantalla fuese la siguiente: mi_variable vale: 1 antes de llamar a la función mi_variable vale: 2 después de llamar a la función

Page 60: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

46

5.5.2.3. Parámetros por defecto

Podemos definir valores por defecto para los parámetros. Sirven para que los parámetros contengan un valor predefinido, que será el que tomen si no se les pasa ningún valor al llamar al la función. Se definen asignando un valor al parámetro al declararlo en la función. <?php function mi_función($parametro_1 = "pepe", $parametro_2 = "jose"){ .... } mi_función(); //al llamar a la función así, dentro de nuestra función $parametro_1 valdria "pepe" y parametro_2 valdria "jose" mi_función("Antonio"); //$parametro_1 valdria "Antonio" y parametro_2 valdria "jose" mi_función("Antonio","rosa"); //$parametro_1 valdria "Antonio" y parametro_2 valdria "rosa" ?>

5.5.3. Recursividad

PHP nos permite crear funciones recursivas. Esto es, funciones que se puedan llamar a sí mismas. En otras palabras, es como hacer un bucle con la propia función. Mucho cuidado con hacer una función recursiva ya que puede ocurrirnos lo mismo que con bucles infinitos, y además una función recursiva es peligrosa si tratamos datos grandes, ya que si utilizamos pasos por valor, el consumo de memoria puede ser muy grande.

Ejemplo de función recursiva <?php $i = 0; function suma_hasta_5(){ global $i; if ($i<5){ $i++; suma_hasta_5(); } else { echo "Ya hemos llegado a 5"; } } suma_hasta_5(); ?>

5.6. Salidas por pantalla

Como hemos visto a lo largo de este temario, se ha usado la función echo para mostrar texto por pantalla. Es hora de conocer otras formas como print, printf, print_r o var_dump.

5.6.1.1. print y echo

Son prácticamente iguales pero tienen alguna diferencia, por ejemplo echo() puede tomar expresiones múltiples, como:

Page 61: Php-Mysql

PHP BASICO

47

<?php echo "uno", "dos", "tres"; print "uno", "dos", "tres"; //esto daría error ?>

mientras el print() no. Sin embargo, se utiliza el print() como parte de una expresión más compleja, donde el echo() no se podría aplicar, debido a que print() puede retornar un valor true o false y el echo() no. Otra diferencia es la velocidad donde echo es aproximadamente un 50% más rápida.

5.6.1.2. printf

Sirve par dar formato a un texto y mostrarlo por pantalla (hay una función que se llama sprintf que hace exactamente lo mismo pero sin mostrarlo por pantalla, es decir, para poder almacenar el resultado en una variable). la sintaxis seria:

printf(“cadena”,parametro1,parametro2…)

En la cadena habrá patrones (señalizados con un símbolo %) y el resto del texto que queramos. Los parámetros serán las variables o valores que queramos insertar en la cadena, habrá tantos (y en orden) como patrones haya.

Veamos un ejemplo: <?php $nombre = "pepe"; $numero = 1; printf("este es un ejemplo de un nombre %s y este otro de un numero %d",$nombre,$numero); ?>

El significado del patrón variaría según el carácter que tenga al final:

especificador definición b el argumento es interpretado como un número

entero, y presentado como un número binario. c el argumento es interpretado como un entero, y

presentado como el carácter ASCII con dicho valor.

d el argumento es tratado como un entero y presentado con notación decimal

e el argumento es tratado como un entero y presentado con notación exponencial.

f el argumento es tratado como un double y presentado como un número de coma flotante.

o el argumento es tratado como un entero, y presentado como un número octal.

x el argumento es tratado como un entero y presentado como un número hexadecimal (con

minúsculas). X el argumento es tratado como un entero y

presentado como un número hexadecimal (con mayúsculas).

s el argumento es tratado como una cadena y es presentado como tal.

Page 62: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

48

5.6.1.3. print_r

print_r nos muestra el contenido de una variable de forma que sea legible por humanos. <?php $mi_variable = array("uno" => 1, "dos" => 2, "tres" => 3); print_r ($mi_variable); ?>

Esto nos mostraría:

Array ( [uno] � 1 [dos] � 2 [tres] � 3 )

5.6.1.4. var_dump

Es similar a print_r solo que además nos da mas información acerca del contenido de la variable, como cantidad (en caso de arrays) y tipos de dato. En el mismo ejemplo que antes: <?php $mi_variable = array("uno" => 1, "dos" => 2, "tres" => 3); var_dump ($mi_variable); ?>

Esto nos mostraría:

array(3) { [“uno”]� int(1) [“dos”]� int(2) [“tres”]� int(3) }

5.7. Actividades

5.7.1. Tipos de datos, cadenas y arrays.

5.7.1.1. Actividad 1

Definir una variable de cada tipo: integer, double, string y boolean. Luego imprimirlas en la página, una por línea.

5.7.1.2. Actividad 2

Escribe tu nombre y tu edad por pantalla. Tu edad deberá ir dentro de una variable. Haz una versión con comillas simples y otra con comillas dobles, expandiendo la variable dentro de la cadena en la versión que sea posible.

5.7.1.3. Actividad 3

Define un array con valores del 1 al 10, con los valores desordenados e imprimelo por pantalla con print_r, después con las funciones de arrays que proporciona php ordena el array de mayor a menor y muestralo por pantalla. http://www.php.net/manual/es/book.array.php

Page 63: Php-Mysql

PHP BASICO

49

5.7.1.4. Actividad 4

Crea 2 arrays asociativos con 5 elementos cada uno, con el contenido que tu quieras, combínalos y saca el contenido por pantalla usando print_r. Después usa array_push y array_pop (revisa la documentación en http://www.php.net/manual/es/book.array.php), y vuelve a sacar el contenido por pantalla.

5.7.2. Estructuras de control

5.7.2.1. Actividad 1

Genera un valor aleatorio entre 1 y 5, y escribir el número en castellano: (ej, si sale el numero 1, escribir “uno”). Para generar un numero aleatorio, usar la función rand http://php.net/manual/es/function.rand.php

5.7.2.2. Actividad 2

Di si se ejecutaría el if o el else en cada caso. <?php $valor1 = 1; $valor2 = 3; if ($valor1 >= $valor2){ //script if } else { //script else } ?> <?php $valor1 = 1; $valor2 = 1.0; if ($valor1 == $valor2){ //script if } else { //script else } ?> <?php $valor1 = 1; $valor2 = "1"; if ($valor1 == $valor2){ //script if } else { //script else } ?> <?php

Page 64: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

50

$valor1 = true; if ($valor1){ //script if } else { //script else } ?> <?php $valor1 = false; if (!$valor1){ //script if } else { //script else } ?> <?php $valor1 = true; $valor2 = false; $valor3 = 4; $valor4 = 10; if (($valor1 && ($valor3 <= $valor4) && $valor1 != $valor2) || ($valor4 - 3 == $valor3){ //script if } else { //script else } ?>

5.7.2.3. Actividad 3

Crea 3 bucles, uno con for, otro con while, y otro con do-while, que den 10 vueltas. Comprueba las vueltas poniendo salidas por pantalla.

5.7.2.4. Actividad 4

Crea un bucle for, que de 5 vueltas, pero el indice deberá empezar en el número 27 e ir en decremento.

5.7.2.5. Actividad 5

Crea un bucle for que de 5 vueltas. Pero el índice que uses, en vez de ir sumando de uno en uno, deberá ir de 2 en 2. Además incluye dentro del for, un switch que:

En el primer caso, muestre por pantalla a suma del indice consigo mismo.

En el segundo caso, muestre la resta del indice consigo mismo.

En el tercer caso, muestre la multiplicación del indice por 4 y dividido por 3 (el calculo habrá que hacerlo en una sola expresión y el resultado deberá aparecer en decimales).

Page 65: Php-Mysql

PHP BASICO

51

En el cuarto caso, habrá que crear un bucle do_while en el que se rellene un array con valores desde el 0 hasta el valor que tenga el índice. Y mostrar dicho array con un var_dump por pantalla.

En el quinto caso, comprueba si el número es múltiplo de 5. En caso de serlo deberá aparecer en pantalla, el mensaje “Es múltiplo de 5”, y en caso contrario, “No es múltiplo de 5”.

5.7.3. Funciones

5.7.3.1. Actividad 1

Crea una función en la que definas un array bidimensional (2 dimensiones) en el que estén el nombre y la edad de 5 personas. La edad será un número aleatorio entre 16 y 22.

En otra función al que se le pase por referencia el array creado, recorre dicho array con un bucle while y por cada persona escribe “Hola nombre, tu edad es edad.” Después de escribirlo, deberás borrar el contenido de ese valor del array (http://php.net/manual/es/function.unset.php) sólo en caso de que la persona sea menor de edad (edad menor o igual que 18), y se deberá mostrar por pantalla que se ha procedido al borrado de dicho valor.

5.7.3.2. Actividad 2

Implementa una función en la que se calcule el sumatorio de un numero dado. El resultado será una cadena de texto con el formato “El sumatorio del numero número es resultado” (ej: El sumatorio del numero 4 es 10) que deberá irse agregando a un array declarado de forma global. Para dar formato a esa cadena de texto, usa la función sprintf. Después crea un bucle do_while que dará un numero aleatorio de vueltas entre 15 y 20, y donde se llamará dicha función con el valor que tenga el índice en ese momento. Al salir llamara a otra función que recorrerá el array global en sentido inverso y mostrará el contenido, con una linea por cada valor que contenga el array.

El sumatorio de un numero es la suma de los n-1 enteros anteriores a n. Por ejemplo el sumatorio de 4 es 10 (4 + 3 + 2 + 1)

5.7.3.3. Actividad 3

Escribe una función recursiva en la que se escribirá una serie de fibonacci, que se repetirá tantas veces como valga el valor pasado. Utiliza una variable estática para ir almacenando el índice.

La serie de fibonacci es aquella en la que el siguiente termino en la sucesión, equivale a la suma de los 2 anteriores.

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55

Por ejemplo, si pasáramos el valor 5, en pantalla nos debería aparecer:

0, 1, 1, 2, 3.

Utiliza el tratamiento de cadenas adecuado para que después del último valor aparezca un punto en vez de una coma.

Page 66: Php-Mysql
Page 67: Php-Mysql

FORMULARIOS Y SUS METODOS

53

Formularios y sus Métodos

Antes de meternos con la forma de funcionar php con los formularios, vamos a pegarle un repaso a las etiquetas html que pueden componer un formulario.

form La etiqueta FORM es la etiqueta contenedora de un formulario en HTML. Su sintaxis básica es la siguiente: <FORM ACTION="nuestro_script.php" METHOD="post/get"> ... formulario ... </FORM>

Con el atributo “action”, indicamos cual es el nombre del script que procesará el formulario, y con el atributo “method”, indicamos como su nombre indica, el método por el cual van a ser procesados, post, o get que los veremos un poco más adelante.

Cuadro de texto Algunos de los componentes de un formulario (por ejemplo: campos ocultos, cuadros de texto, cuadros de texto de contraseña, botones…) usan la etiqueta input y varían definiendo un valor diferente en el atributo type. vamos a centrarnos ahora en los cuadros de texto.

Page 68: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

54

Los cuadros de texto son los campos donde podremos introducir los datos de nuestro formulario. Se suelen usar para colocar nombres, direcciones, fechas, etc… es decir, la mayoría de los datos a introducir en un formulario.

Su sintaxis es la siguiente: <input type="text" namemane="nombre" value="valor por defecto">

Con el atributo type=“text” es con el que le decimos que es un campo de texto, el atributo name=”” hace que podamos identificar este cuadro cuando mandemos los datos a php, y con value podemos poner un valor por defecto si queremos (como volver a colocar los datos del formulario si al hacer una validación desde php, se han encontrado errores)

Cuadro de texto contraseña Los atributos son exactamente los mismos que un cuadro de texto, solo que cambia el valor type. En este caso es “password”. Con este tipo de campo de texto, cada vez que introduzcamos un carácter, éste se verá como un asterisco, por seguridad. <input type="password" name="contrasenia">

Aunque tiene la posibilidad de poner un atributo value con un valor por defecto, no se suele usar, ya que por seguridad es aconsejable que el usuario siempre meta la contraseña.

Ficheros Igual que en un cuadro de texto o en un campo de contraseña, los atributos son iguales. Pero su representación será muy distinta. Aparecerá un cuadro de texto con un botón al lado, que al pulsarlo nos permitirá elegir un fichero de nuestro equipo para mandarlo al formulario. El tamaño máximo del fichero que se podrá cargar, dependerá de la configuración de nuestro servidor. <input type="file" name="archivo">

Checkbox Los checkbox se suelen usar cuando se quiere ofrecer al usuario la posibilidad de elegir varios items. <input type="checkbox" name="nombre" value="valor_al_estar_seleccionado" checked>

Aquí, el value, no es un valor por defecto que verá el usuario, si no que es el valor que tendrá cuando se seleccione el checkbox (a la hora de enviar el formulario a php).

Con el atributo checked podemos decir si estará seleccionado cuando se cargue nuestro formulario.

Radiobutton Es similar a un checkbox solo que entre un grupo de radiobuttons, solo podrá haber 1 seleccionado. <input type="radio" value="azul" checked name="color">

Page 69: Php-Mysql

FORMULARIOS Y SUS METODOS

55

A diferencia de los checkbox y del resto de los input, cuando queramos dar varias opciones con un radiobutton referidos a una misma temática, como por ejemplo: “colores de carrocería: Rojo azul o negro.” todos los radiobutton tendrán el mimo nombre en el atributo name. Así cuando ejecutemos nuestro formulario, se mandará exclusivamente el valor del radiobutton seleccionado.

Botones Tenemos 2 tipos principales, type=“submit” y type=“reset”

Con submit ejecutaremos el formulario y haremos que se invoque a nuestro script php definido en el action de la etiqueta form.

Con Reset pondremos los valores del formulario a como estuviesen originalmente. <input type="submit" value="enviar" name="enviar">

Para botones que no tengan una lógica predefinida, se usará type=“button”. Estos se suelen usar si tenemos pensado dar algún tipo de lógica mediante javascript.

Campo oculto HTML nos brinda la oportunidad de colocar campos ocultos, útiles para guardar identificativos. Ojo que no sean visibles en el navegador, no implica que sean del todo invisibles, ya que si se abre el código fuente, se verán. Así que no guardes información comprometida aquí :). <input type="hidden" name="edad" value="55">

textareas A diferencia de los cuadros de texto, los text areas tienen etiqueta de inicio y de cierre, y se pueden escribir varias lineas de texto (recordemos que en los cuadros de texto solo se puede escribir una) <textarea rows="5" name="descripcion" cols="20">Es de color rojo</textarea>

Select box <select name="dia"> <option selected value="lunes">lunes</option> <option value="martes">martes</option> <option value="miercoles">miércoles</option> </select>

Los select box son por defecto listas desplegables en las que podemos elegir un valor.

Como en en el caso de los radiobutton o los checkbox el valor que se mandará es el del atributo “value”. Tenemos el atributo selected que hará que cuando se cargue nuestra página, ese valor, sea el valor por defecto.

Adicionalmente, este tipo de elemento html tiene la opción de convertirse en una lista de selección múltiple en vez de una lista desplegable, añadiéndole el parametro “MULTIPLE” en la etiqueta select, además hay que añadir unos corchetes al nombre para que funcione correctamente en php:

Page 70: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

56

<select name="dia[]" MULTIPLE> <option selected value="lunes">lunes</option> <option value="martes">martes</option> <option value="miercoles">miércoles</option> </select>

6.1. GET y POST

Los métodos Get y Post son 2 de los métodos que tiene HTML para mandar información y son los que habitualmente se usan en PHP para gestionar formularios.

Ambos mandan información pero la forma de hacerlo es radicalmente distinta. GET lo manda por URL (la dirección web a la vista) mientras POST de forma transparente.

PHP nos permite acceder a nuestros valores mediante las variables superglobales predefinidas $_POST y $_GET. Ambas son arrays asociativos de datos en los que estarán nuestros valores.

Por ejemplo si tenemos una caja de texto llamada edad podremos recoger la información de la siguiente forma: <?php //si el método elegido en nuestro formulario es GET $edad = $_GET['edad']; //si el método elegido en nuestro formulario es POST $edad = $_POST['edad']; ?>

Ojo, si estamos intentando coger un fichero (<input type="file">), no lo encontraremos ni en $_GET ni en $_POST, si no en $_FILES. Y dispondrá de más información. <?php //el array asociativo con el nombre de nuestro input tipo fichero: $_FILES['archivo']['name']; //contiene el nombre del fichero. $_FILES['archivo']['size']; //contiene el tamaño del fichero en bytes ?>

$_FILES['archivo']['size'] devolverá 0 si el proceso ha fallado (por ejemplo se ha sobrepasado el tamaño máximo de carga)

Veamos un ejemplo de un formulario completo con método post (Nota: en nuestro ejemplo, nuestro script está en un fichero en la carpeta raíz de nuestro dominio, y se llama index.php): <?php //La forma habitual de saber si se ha ejecutado un formulario es viendo si esta definida la variable del botón de envío if (isset($_POST['enviar'])) { //si se ha mandado el formulario al pulsar el botón submit echo 'Tu nombre es '.$_POST['nombre']; echo '<br />'; echo 'Tu apellido es '.$_POST['apellido']; echo '<br />'; echo 'El color que has elegido es '.$_POST['color']; echo '<br />';

Page 71: Php-Mysql

FORMULARIOS Y SUS METODOS

57

if (count($_POST['dia']) > 0){ echo 'Los dias que has escogido son:'; foreach ($_POST['dia'] as $valor){ echo $valor." "; } } else{ echo "No has escogido ningún valor en el select box multiple"; } echo '<br />'; if ($_POST['check']=="si"){ echo 'Has marcado el checkbox <br />'; }else{ echo 'No has marcado el checkbox <br />'; } echo 'El valor que has escogido en el primer grupo de radiobuttons es '.$_POST['radio1'].'<br />'; echo 'El valor que has escogido en el segundo grupo de radiobuttons es '.$_POST['radio2'].'<br />'; echo '<a href="index.php"> Volver al formulario</a>'; } else{//en caso de que no se haya enviado el formulario, nos muestra esto otro. ?> <html> <head><title>Formulario de ejemplo</title></head> <body> <form action="index.php" method="post"> Escribe tu nombre <input type="text" name="nombre"> <br /> Escribe tu apellido (es un campo contrase&ntilde;a, así que lo verás oculto) <input type="password" name="apellido"><br /> Elige un color. <select name ="color"> <option value="negro">negro</option> <option value="blanco">blanco</option> <option value="azul">azul</option> <option value="rojo">rojo</option> <option value="amarillo">amarillo</option> </select><br /> Elige uno o varios dias de la semana. Puedes elegir más de uno dejando pulsada la tecla Ctrl <select name ="dia[]" multiple> <option value="lunes">lunes</option> <option value="martes">martes</option> <option value="miercoles">miercoles</option> <option value="jueves">jueves</option> <option value="viernes">viernes</option> <option value="sabado">sabado</option> <option value="domingo">domingo</option> </select> <br /> Si quieres, marca este checkbox <input type="checkbox" name="check" value="si"><br /> <hr /> Aquí un grupo de radio buttons <input type="radio" value="1" name="radio1"> 1 <br /> <input type="radio" value="2" name="radio1"> 2 <br /> <input type="radio" value="3" name="radio1"> 3 <br /> <input type="radio" value="4" name="radio1"> 4 <br /> <hr /> Aquí otro grupo de radio buttons diferente

Page 72: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

58

<input type="radio" value="a" name="radio2"> a <br /> <input type="radio" value="b" name="radio2"> b <br /> <input type="radio" value="c" name="radio2"> c <br /> <input type="radio" value="d" name="radio2"> d <br /> <input type="submit" name="enviar" value="Enviar"> </form> </body> </html> <?php } ?>

Cuando se mandan los datos por GET, como hemos dicho, los parámetros aparecerán en la dirección web. La forma es:

http://www.nuestrodominio.com/script.php?variable1=valor1&variable2=valor2&variablen=valorn

Es decir. Tendremos la dirección a nuestro script, después una interrogante ”?” que indicara que a partir de ese punto vendrán los pares de nuestras variables y sus valores, separadas por el símbolo ampersand ”&”.

En este ejemplo que hemos puesto, en php la forma de coger los datos seria: <?php $variable1 = $_GET["variable1"]; $variable2 = $_GET["variable2"]; $variablen = $_GET["variablen"]; ?>

6.2. Otros

Aunque los veremos en un punto más avanzado del curso, nombraremos ahora otros métodos que tiene html.

• DELETE Borra el recurso especificado.

• PUT Sube o carga un archivo, de una forma más eficiente que POST, pero la desventaja es que habitualmente los servidores compartidos no suelen tener activado PUT.

• HEAD: Pide que la respuesta idéntica a la que correspondería a una petición GET, pero sin el cuerpo de la respuesta. Esto es útil para la recuperación de meta-información escrita en los encabezados de respuesta, sin tener que transportar todo el contenido.

6.3. Actividad

Crea un formulario (post) típico de registro de una pagina web, pero que valide que todos los campos y en caso de no introducir correctamente alguno (o no introducirlo), vuelva al formulario respetando los valores escritos (menos la contraseña). En caso correcto, haz una salida por pantalla con los valores. Y coloca un enlace para volver al formulario (no hace falta respetar los valores escritos por el usuario):

• Nombre (sólo texto)

• Apellidos (sólo texto)

Page 73: Php-Mysql

FORMULARIOS Y SUS METODOS

59

• Usuario (texto y números pero sin caracteres extraños ni espacios en blanco)

• Contraseña (texto y números pero sin caracteres extraños ni espacios en blanco)

• Repetir contraseña (validar que ha introducido la contraseña 2 veces de forma correcta)

• E-mail (que por lo menos tenga una @ y un dominio con un punto después de esta, p.ej: [email protected])

• Genero (radio button masculino femenino)

• Comunidad autónoma en la que vive (select box normal)

• Elementos de ocio digital que posee: PC, móvil, PlayStation 3, Xbox 360, Wii, PSP, Nintendo DS. (Select box múltiple)

• Checkbox indicando si se quiere que se le mande información al correo.

Para tratamiento de cadenas se aconseja revisar las funciones de php dedicadas al tratamiento de cadenas. http://www.php.net/manual/es/ref.strings.php

Page 74: Php-Mysql
Page 75: Php-Mysql

Bases de datos Relacionales

61

Bases de Datos Relacionales

7.1. SQL: lenguaje de definición y manejo de datos

Existen muchos tipos de bases de datos en función del modo en que almacenan y acceden a la información que guardan: relacional, jerárquica, en red, orientada a objetos,… Ejemplos de gestores de bases de datos relacionales no hay muchos: MySQL, Oracle, PostGres, Informix, Microsoft SQL Server, mSQL,…

Un gestor de base de datos relacional almacena los datos en tablas, cada una de las cuales está formada por filas o “registros”, y que a su vez están formadas por columnas o “campos”.

El acceso a estas bases de datos se realiza mediante el lenguaje SQL (Structured Query Language). SQL es un lenguaje formal declarativo, estandarizado ISO, para manipular información en una base de datos. Es el lenguaje unificado para realizar consultas y dar instrucciones al gestor de base de datos.

El lenguaje SQL (o ANSI SQL) sufrió varias revisiones a lo largo del tiempo:

Año Nombre Alias Comentarios 1986 SQL-86 SQL-87 Primera publicación

hecha por ANSI. Confirmada por ISO en

1987.

Page 76: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

62

1989 SQL-89 Revisión menor.

1992 SQL-92 SQL2 Revisión mayor. 1999 SQL:1999 SQL2000 Se agregaron

expresiones regulares, consultas recursivas

(para relaciones jerárquicas), triggers y algunas características orientadas a objetos.

2003 SQL:2003 Introduce algunas características de

XML, cambios en las funciones,

estandarización del objeto sequence y de

las columnas autonuméricas.

2006 SQL:2006 ISO/IEC 9075-14:2006 Define las maneras en las cuales el SQL se

puede utilizar conjuntamente con

XML. 2008 SQL:2008 Permite el uso de la

cláusula ORDER BY fuera de las

definiciones de los cursores. Incluye los disparadores del tipo

INSTEAD OF. Añade la sentencia

TRUNCATE.

En la actualidad el SQL es el estándar de facto de la inmensa mayoría de los SGBD comerciales. Y, aunque la diversidad de añadidos particulares que incluyen las distintas implementaciones comerciales del lenguaje es amplia, el soporte al estándar SQL-92 es general y muy amplio.

7.1.1. Lenguaje de definición de datos (LDD)

El lenguaje de definición de datos (Data Definition Language, o DDL), es el que se encarga de la modificación de la estructura de los objetos de la base de datos. Existen cuatro operaciones básicas: CREATE, ALTER, DROP y TRUNCATE.

7.1.1.1. CREATE

Crea un objeto dentro de la base de datos. Puede ser una tabla, vista, índice, trigger, función, procedimiento o cualquier otro objeto que el motor de la base de datos soporte.

Ejemplo (crear una tabla) CREATE TABLE 'TABLA_NOMBRE' ( 'CAMPO_1' INT, 'CAMPO_2' STRING )

Page 77: Php-Mysql

Bases de datos Relacionales

63

7.1.1.2. ALTER

Permite modificar la estructura de un objeto. Se pueden agregar/quitar campos a una tabla, modificar el tipo de un campo, agregar/quitar índices a una tabla, modificar un trigger, etc.

Ejemplo (agregar columna a una tabla) ALTER TABLE 'TABLA_NOMBRE' ( ADD NUEVO_CAMPO INT UNSIGNED meel )

7.1.1.3. DROP

Elimina un objeto de la base de datos. Puede ser una tabla, vista, índice, trigger, función, procedimiento o cualquier otro objeto que el motor de la base de datos soporte.

Se suele combinar con la sentencia ALTER.

Ejemplo ALTER TABLE ''TABLA_NOMBRE'' ( DROP COLUMN ''CAMPO_NOMBRE1'' )

7.1.1.4. TRUNCATE

Trunca (borra) todo el contenido de una tabla.

Ejemplo TRUNCATE TABLE ''TABLA_NOMBRE1''

7.1.2. Lenguaje de manipulación de datos (LMD)

7.1.2.1. Definición

Un lenguaje de manipulación de datos (Data Manipulation Language, o DML) es un lenguaje proporcionado por el sistema de gestión de base de datos que permite a los usuarios llevar a cabo las tareas de consulta o manipulación de los datos, organizados por el modelo de datos adecuado.

7.1.2.2. INSERT

Una sentencia INSERT de SQL agrega uno o más registros a una (y sólo una) tabla en una base de datos relacional.

Forma básica INSERT INTO ''tabla'' (''columna1'', [''columna2,... '']) VALUES (''valor1'', [''valor2,...''])

Las cantidades de columnas y valores deben ser iguales. Si una columna no se especifica, le será asignado el valor por omisión. Los valores especificados (o implícitos) por la sentencia INSERT deberán satisfacer todas las restricciones aplicables. Si ocurre

Page 78: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

64

un error de sintaxis o si alguna de las restricciones no se cumple, no se agrega la fila y se devuelve un error.

Ejemplo: INSERT INTO mi_agenda (nombre, teléfono) VALUES ('Juan Nadie', 987654321);

Cuando se especifican todos los valores de una tabla, se puede utilizar la sentencia acortada: INSERT INTO ''tabla'' VALUES (''valor1'', [''valor2,...''])

Ejemplo (asumiendo que 'nombre' y 'número' son las únicas columnas de la tabla 'agenda_telefonica'): INSERT INTO mi_agenda VALUES ('Juan Nadie', 987654321);

Formas avanzadas Inserciones en múltiples filas

Una característica de SQL (desde SQL-92) es el uso de constructores de filas para insertar múltiples filas a la vez, con una sola sentencia SQL: INSERT INTO ''tabla'' (''columna1'', [''columna2,... '']) VALUES (''valor1a'', [''valor1b,...'']), (''valor2a'', [''valor2b,...'']),...

Ejemplo (asumiendo que 'nombre' y 'número' son las únicas columnas en la tabla 'agenda_telefonica'):

INSERT INTO mi_agenda VALUES ('Juan Nadie', '987654321'), ('Luisa Amigo', '321654987');

Que podía haber sido realizado por las sentencias INSERT INTO mi_agenda VALUES ('Juan Nadie', '987654321'); INSERT INTO mi_agenda VALUES ('Luisa Amigo', '321654987');

Copia de filas de otras tablas

Un INSERT también puede utilizarse para recuperar datos de otros, modificarla si es necesario e insertarla directamente en la tabla. Todo esto se hace en una sola sentencia SQL que no implica ningún procesamiento intermedio en la aplicación cliente.

Un SUBSELECT se utiliza en lugar de la cláusula VALUES. El SUBSELECT puede contener JOIN, llamadas a funciones, y puede incluso consultar en la misma TABLA los datos que se inserta.

Lógicamente, el SELECT se evalúa antes que la operación INSERT esté iniciada.

Un ejemplo: INSERT INTO mi_agenda2 SELECT * FROM mi_agenda WHERE nombre IN ('Juan Nadie', 'Luisa Amigo')

Page 79: Php-Mysql

Bases de datos Relacionales

65

7.1.2.3. UPDATE

Una sentencia UPDATE de SQL es utilizada para modificar los valores de un conjunto de registros existentes en una tabla. UPDATE ''tabla'' SET ''columna1'' = ''valor1'' ,''columna2'' = ''valor2'',... WHERE ''columnaN = ''valorN''

Ejemplo: UPDATE mi_agenda SET telefono = '951786324' WHERE nombre = 'Juan Nadie';

7.1.2.4. DELETE

Una sentencia DELETE de SQL borra uno o más registros existentes en una tabla. DELETE FROM ''tabla'' WHERE ''columna1'' = ''valor1''

Ejemplo: DELETE FROM mi_agenda WHERE nombre = 'Juan Nadie';

7.1.3. Recuperación de clave

Los diseñadores de base de datos que usan una clave suplente como la clave principal para cada tabla, se encuentran normalmente con el problema de que es necesario recuperar automáticamente la clave primaria de una sentencia SQL INSERT para su uso en otras sentencias SQL.

La mayoría de los sistemas no permiten sentencias SQL INSERT para retornar fila de datos. Por lo tanto, se hace necesario aplicar una solución en tales escenarios.

Las implementaciones más frecuentes:

• Utilizando un procedimiento almacenado especifico para genera la clave suplente, realizar la operación INSERT, y finalmente devolver la clave generada.

• Utilizando una sentencia SELECT específica sobre una tabla temporal que contiene la última fila insertada.

• Utilizando una sentencia SELECT después de la sentencia INSERT con función específica que devuelve la clave primaria generada por el registro insertado más recientemente.

• Utilizando una combinación única de elementos del original SQL INSERT en una sentencia SELECT posterior.

• Utilizando un GUID en la sentencia SQL INSERT y la recupera en una sentencia SELECT.

7.1.4. Disparadores (Triggers)

Page 80: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

66

Los disparadores (triggers) son definidos sobre la tabla en la que opera la sentencia INSERT, y son evaluados en el contexto de la operación.

Los disparadores BEFORE INSERT permiten la modificación de los valores que se insertará en la tabla.

Los disparadores AFTER INSERT no puede modificar los datos de ahora en adelante, pero se puede utilizar para iniciar acciones en otras tablas, por ejemplo para aplicar mecanismos de auditoría.

7.2. Integridad referencial

La integridad referencial es una propiedad deseable en las bases de datos. Gracias a la integridad referencial se garantiza que una entidad (fila o registro) siempre se relaciona con otras entidades válidas, es decir, que existen en la base de datos. Implica que en todo momento dichos datos sean correctos, sin repeticiones innecesarias, datos perdidos y relaciones mal resueltas.

Todas las bases de datos relacionales gozan de esta propiedad gracias a que el software gestor de base de datos vela por su cumplimiento. En cambio, las bases de datos jerárquicas requieren que los programadores se aseguren de mantener tal propiedad en sus programas.

7.2.1. Ejemplo: Cómo funciona

Supongamos una base de datos con las entidades Persona y Factura. Toda factura corresponde a una persona y solamente una. Implica que en todo momento dichos datos sean correctos, sin repeticiones innecesarias, datos perdidos y relaciones mal resueltas.

Supongamos que una persona se identifica por su atributo DNI (Documento nacional de identidad). También tendrá otros atributos como el nombre y la dirección. La entidad Factura debe tener un atributo DNI_cliente que identifique a quién pertenece la factura.

Por sentido común es evidente que todo valor de DNI_cliente debe corresponder con algún valor existente del atributo DNI de la entidad Persona. Esta es la idea intuitiva de la integridad referencial.

¿Cuándo se pueden producir errores en los datos?

Cuando insertamos una nueva fila en la tabla secundaria y el valor de la clave foránea no existe en la tabla principal. Insertamos una nueva factura y en la columna DNI_cliente escribimos un dni que no está en la tabla de Personas (persona que no existe).

Cuando modificamos el valor de la clave principal de un registro que tiene 'hijos', modificamos el DNI de una persona, sustituimos el valor que tenía por un nuevo valor , si esa persona tenía facturas asignadas, qué pasa con esas facturas, no pueden seguir teniendo DNI antiguo porque ese DNI ya no existe, en este caso hay dos alternativas, no dejar cambiar el DNI de la persona o bien cambiar el DNI_cliente de todas las facturas relacionadas.

Cuando modificamos el valor de la clave foránea, el nuevo valor debe existir en la tabla principal. Por ejemplo cambiamos el DNI_cliente de una Factura, tenía asignado el de una persona y ahora se le asigna a otra persona. El otro DNI debe existir en la tabla de personas.

Page 81: Php-Mysql

Bases de datos Relacionales

67

Cuando queremos borrar una fila de la tabla principal y ese registro tiene 'hijos', por ejemplo queremos borrar Una persona si existen Facturas asignadas a esa persona, estos no se pueden quedar con el valor DNI de ese cliente, porque tendrían asignado un DNI de una persona que no existe. En este caso tenemos dos alternativas, no dejar borrar la persona, o bien borrarla y poner a valor nulo el campo DNI_cliente de todos sus 'hijos'.

Asociada a la integridad referencial están los conceptos de actualizar los registros en cascada y eliminar registros en cascada.

Actualización y borrado en cascada

El actualizar y/o eliminar registros en cascada, son opciones que se definen cuando definimos la clave foránea y que le indican al sistema gestor qué hacer en los casos comentados en el punto anterior.

Actualizar registros en cascada:

Esta opción le indica al sistema gestor de la base de datos que cuando se cambie un valor del campo clave de la tabla principal, automáticamente cambiará el valor de la clave foránea de los registros relacionados en la tabla secundaria.

Por ejemplo, si cambiamos en la tabla de personas (la tabla principal) el valor 1 por el valor 10 en el campo DNI (la clave principal), automáticamente se actualizan todos las facturas (en la tabla secundaria) que tienen el valor 1 en el campo DNI_cliente (en la clave ajena) dejando 10 en vez de 1.

Si no se tiene definida esta opción, no se puede cambiar los valores de la clave principal de la tabla principal. En este caso, si intentamos cambiar el valor 1 del DNI de la tabla de personas , no se produce el cambio y el sistema nos devuelve un error o un mensaje que los registros no se han podido modificar por infracciones de clave.

Eliminar registros en cascada:

Esta opción le indica al sistema gestor de la base de datos que cuando se elimina un registro de la tabla principal automáticamente se borran también los registros relacionados en la tabla secundaria.

Por ejemplo: Si borramos una persona, automáticamente todas las facturas de esa persona se borrarán de la tabla de Facturas.

Si no se tiene definida esta opción, no se pueden borrar registros de la tabla principal si estos tienen registros relacionados en la tabla secundaria. En este caso, si intentamos borrar una persona, no se produce el borrado y el sistema nos devuelve un error o un mensaje que los registros no se han podido eliminar por infracciones de clave.

Por otra parte existen tres tipos de integridad referencial:

Al elegir una integridad referencial completa, todas las columnas de una clave foránea deben ser nulas, o todas no nulas. Por ejemplo, en la definición de una clave foránea de las tablas Persona (DNI) y Facturas (DNI_cliente) con este tipo de integridad referencial, le dice a nuestro sistema de gestión de bases de datos, que la clave (NULL, NULL) es aceptada, pero valores como (100, NULL) o (NULL, 100) violan la integridad referencial por que parte es nula y la otra es no nula.

En el caso de parcial, permitimos parcialmente claves foráneas con valores nulos, siempre y cuando el valor no nulo, corresponda con el valor de la columna correspondiente de la clave primaria. Con el mismo ejemplo, este tipo de integridad

Page 82: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

68

referencial también admitiría por ejemplo una clave (NULL, NULL) en el caso de nuestro ejemplo de 2 columnas, además de los valores (NULL, 100) y (100, NULL) siempre y cuando una de las columnas de la clave primaria tenga (en este ejemplo) el valor 100 en alguna de los registros de la tabla.

Y por último con integridad referencial simple le diríamos a nuestros sistema de gestión de bases de datos (siguiendo con nuestro ejemplo) que acepte claves foráneas con los valores (NULL, NULL), (NULL, 100) y (100, NULL) tenga o no la clave primaria el valor 100 en la columna correspondiente de los registros de la tabla.

Page 83: Php-Mysql

ACCESO A DATOS

69

Administración

8.1. Manejo de usuarios

8.1.1. Usuarios por defecto

Siempre que queramos utilizar MySQL deberemos hacer login con un usuario autorizado y con los privilegios adecuados. MySQL permite asignar a cada usuario privilegios distintos, que determinan las tareas que podrá realizar cada uno: acceder, modificar, consultar datos y realizar tareas administrativas y de control en la base de datos.

El sistema de usuarios MySQL es independiente del sistema de usuarios de la plataforma Linux o Microsoft Windows en que esté ejecutándose.

Al instalar MySQL, por defecto se crea el usuario root, sin ninguna contraseña. Este el usuario más importante, ya que posee total control sobre las bases de datos, por lo que lo primero que debemos hacer es proporcionarle una contraseña. De lo contrario, cualquier persona que tenga acceso local o remoto a nuestro ordenador podría acceder y realizar cualquier acción con los datos, las tablas o las bases de datos.

Es aconsejable crear un nuevo usuario para acceder a las bases de datos, al que daremos solo los permisos necesarios para las tareas que debemos hacer con él, dejando a root solo para la tareas administrativas y de control. (También es aconsejable borrar los usuarios que se crean por defecto).

Page 84: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

70

Los usuarios que MySQL crea por defecto al instalarse tienen distintos permisos según se haya instalado sobre linux o Microsoft Windows.

8.1.1.1. En Linux

Tras su instalación, los privilegios de acceso por defecto se establecen ejecutando el script scripts/mysql_install_db. Este script lanza el servidor mysqld y crea los siguientes usuarios y permisos:

• root: es un superusuario con todos los permisos. Debe conectarse desde localhost. Carece de contraseña.

• usuario anónimo que tiene todos los privilegios respecto de las bases de datos cuyos nombres sean test o empiecen por test_. Accede exclusivo desde localhost.

8.1.1.2. En Microsoft Windows

En la instalación por defecto, todos los usuarios locales (que accedan desde localhost) tienen todos los privilegios respecto de todas las bases de datos, sin necesidad de contraseña. Para asegurar la instalación es conveniente eliminar estos usuarios anónimos, y establecer unos nuevos con contraseña, así como fijar la contraseña del root o superusuario: C:\> C:\mysql\bin\mysql mysql mysql> DELETE FROM user WHERE Host='localhost' AND User=''; mysql> QUIT C:\> C:\mysql\bin\mysqladmin reload C:\> C:\mysql\bin\mysqladmin -u root password tu_nueva_contraseña

Lo anterior solo establece contraseña para el usuario root que se conecta desde localhost. Si nuestra base de datos va a estar conectada a internet, necesitamos también asignar una contraseña a root cuando se conecte a través de host (nombre de tu máquina, root@host): C:\mysql\bin>mysqladmin u root -h tu_host password tu_password

8.1.2. Conectarse al servidor MySQL

Los programas cliente de MySQL espera por lo general que usted especifique los parámetros de conexión cuando quiere acceder a un servidor MySQL:

• El nombre de la máquina donde se está ejecutando el servidor MySQL.

• Su nombre de usuario.

• Su password.

Por ejemplo, el cliente mysql puede ejecutarse desde un prompt de línea de comandos (indicado aquí por shell>) de la siguiente manera: shell> mysql -h nombre_host -u nombre_usuario –p su_clave

Las sintaxis alternativas de las opciones -h, -u, y -p son –host=nombre_host, –user=nombre_usuario, y –password=su_clave.

Page 85: Php-Mysql

ACCESO A DATOS

71

Nótese que no hay espacios entre -p o –password= y la clave que le sigue.

Los programas clientes de MySQL utilizan valores por defecto para cualquier parámetro que no se especifique:

• El nombre de servidor por defecto es localhost.

• El nombre de usuario por defecto es ODBC en Windows y su nombre de usuario Unix en Unix.

• No se aplica ninguna clave si -p no está especificado.

De esta manera, para un usuario de Unix con un nombre de usuario de jnadie, todos los siguientes comandos son equivalentes: shell> mysql -h localhost -u jnadie shell> mysql -h localhost shell> mysql -u jnadie shell> mysql

Puede especificar valores diferentes para que se utilicen cuando se realiza una conexión de manera que no tenga que introducirlos en la línea de comandos cada vez que invoca un programa cliente. Esto puede llevarse a cabo de diversas maneras:

• Puede especificar los parámetros de conexión en la sección [client] de un archivo de opciones. La sección relevante del archivo debería tener el siguiente aspecto:

[client] host=nombre_servidor user=nombre_usuario password=su_clave

• Puede especificar algunos parámetros de conexión utilizando variables de entorno. El nombre del servidor para mysql puede ser especificado utilizando MYSQL_HOST. El nombre de usuario MySQL puede especificarse mediante USER (esto es para Windows y Netware únicamente). La clave se puede especificar utilizando MYSQL_PWD, aunque esto es inseguro.

8.1.3. Privilegios de usuarios

Se pueden asignar permisos actuando directamente sobre las tablas de la base de datos mysql, pero la forma mas cómoda y segura es, una vez hecho login como root, asignar permisos con el comando GRANT, por ejemplo: mysql> grant select, insert on *.* to probador@'%' identified by 'mi_clave'; Query OK, 0 rows affected (0.17 sec)

Con este comando creamos un usuario llamado probador que tiene el derecho de seleccionar e insertar datos en todas las bases de datos y tablas (*.*), con la contraseña mi_clave.

El signo % después del nombre de usuario significa que el usuario puede hacer login desde cualquier máquina. Si en su lugar hubiéramos escrito localhost solo podría conectarse desde local; y si queremos dar permiso al usuario desde una máquina remota, debemos escribir el nombre de dicha máquina maquina.dominio.org o su IP 198.162.1.100.

El comando GRANT concede permisos, y en caso de no existir el usuario lo crea.

Page 86: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

72

Para retirar permisos de un usuario se usa el comando REVOKE: mysql> REVOKE ALL ON *.* FROM probador@'%';

8.1.3.1. Ejemplos

• Permisos a probador para acceder por localhost y seleccionar, insertar datos, actualizar, crear, modificar y borrar tablas en todas las tablas de la base de datos mi_base_de_datos :

mysql> GRANT select, insert, update, create, alter, delete, drop ON mi_base_de_datos.* TO probador@localhost IDENTIFIED BY 'mi_clave';

• Todos los permisos disponibles para la tabla primera dentro de la base de datos mi_base_de_datos a probador:

mysql> GRANT All ON mi_base_de_datos.primera TO probador@localhost IDENTIFIED BY 'mi_clave';

• permiso exclusivo de conexión a probador a cualquier base de datos y tablas: mysql> GRANT USAGE ON *.* TO probador@localhost IDENTIFIED BY 'mi_clave';

8.2. Manejo de datos

8.2.1. Copias de seguridad

MySQL incluye varias herramientas para la realización de copias de seguridad de la base de datos, mediante las que podremos poner a salvo nuestros datos y, en el eventual caso de que se pierdan, poder recuperarlos.

Podemos realizar las copias de seguridad de varias formas:

• a través de la sentencia SQL BACKUP TABLE.

• herramientas como puede ser mysqldump o mysqlhotcopy.

8.2.1.1. Mediante BACKUP TABLE

Realiza una copia de una tabla llamada “mitabla” a la carpeta backups:

Page 87: Php-Mysql

ACCESO A DATOS

73

BACKUP TABLE mitabla TO `/backups/´

Para recuperar los datos: RESTORE TABLE mitabla FROM '/backups/´

8.2.1.2. Comando mysqldump

Para realizar la copia de seguridad de la base de datos “mibase” al fichero “copia_seguridad.sql”: mysqldump -opt -password=sucontraseña -user=nombreusuario mibase > archivo.sql

usuario y password para acceder a la base de datos que se esta haciendo el backup

Para recuperar la información de un fichero y restaurar una copia de seguridad de la base de datos se utiliza el comando mysql.

Otra forma mas extendida mysql -password=sucontraseña -user=nombreusuario mibase < archivo.sql

Page 88: Php-Mysql
Page 89: Php-Mysql

ACCESO A DATOS

75

Acceso a datos

9.1. Introducción

MySQL , como sistema gestor de bases de datos relacionales, está organizado a partir de tablas. Dichas tablas contienen campos. Y cada campo es capaz de contener un tipo de dato.

9.1.1. Tipos de datos

Al diseñar nuestras tablas tenemos que especificar el tipo de datos y tamaño que podrá almacenar cada campo. Una correcta elección debe procurar que la tabla no se quede corta en su capacidad, que destine un tamaño apropiado a la longitud de los datos, y la máxima velocidad de ejecución

MySQL admite dos tipos generales de datos: números y cadenas de caracteres. Y junto a estos se admiten otros tipos de datos especiales: formatos de fecha, enumerados.

9.1.1.1. Datos numéricos

En este tipo de campos solo pueden almacenarse números, positivos o negativos, enteros o decimales, en notación hexadecimal, científica o decimal.

Page 90: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

76

Tipo Descripción BIT o BOOL número entero que puede ser 0 ó 1

TINYINT número entero con rango de valores válidos desde -128 a 127. Si se configura como

unsigned (sin signo), el rango de valores es de 0 a 255

SMALLINT números enteros, con rango desde -32768 a 32767. Si se configura como unsigned, 0 a

65535. MEDIUMINT números enteros; el rango de valores va desde -

8.388608 a 8388607. Si se configura como unsigned, 0 a 16777215

INT números enteros, en un rango de -2147463846 a 2147483647. Si configuramos este dato como

unsigned, el rango es 0 a 4294967295 BIGINT número entero con rango de valores desde -

9223372036854775808 a 9223372036854775807. Unsigned, desde 0 a

18446744073709551615 FLOAT (m,d) números decimales. Podemos especificar

cuantos dígitos (m) pueden utilizarse (término también conocido como ancho de pantalla), y

cuantos en la parte decimal (d). Mysql redondeará el decimal para ajustarse a la

capacidad DOUBLE número de coma flotante de precisión doble. Es

un tipo de datos igual al anterior cuya única diferencia es el rango numérico que abarca

DECIMAL números como cadenas

9.1.1.2. Caracteres o cadenas

Tipo Descripción CHAR cadenas de longitud fija. Su longitud abarca

desde 1 a 255 caracteres VARCHAR cadenas, en el mismo rango de 1 a 255

caracteres, pero en este caso, de longitud variable

TINYTEXT, TINYBLOB cadenas con un máximo de 255 caracteres. La diferencia entre la familia de datatypes text y

blob es que la primera es para cadenas de texto plano (sin formato) y case-insensitive (sin

distinguir mayúsculas o minúsculas) mientras que blob se usa para objetos binarios: cualquier tipo de datos o información, desde un archivo de texto con todo su formato (se diferencia en esto

de el tipo Text) hasta imágenes, archivos de sonido o vídeo

TEXT y BLOB cadenas con un rango de 255 - 65535 caracteres. La diferencia entre ambos es que TEXT permite comparar dentro de su contenido sin distinguir mayúsculas y minúsculas, y BLOB si distingue

Page 91: Php-Mysql

ACCESO A DATOS

77

MEDIUMTEXT, MEDIUMBLOB textos de hasta 16777215 caracteres LONGTEXT, LONGBLOB, texto hasta máximo de 4.294.967.295 caracteres

Nota: Un campo CHAR ocupará siempre el máximo de longitud que le hallamos asignado, aunque el tamaño del dato sea menor (añadiendo espacios adicionales que sean precisos). Mientras que VARCHAR solo almacena la longitud del dato, permitiendo que el tamaño de la base de datos sea menor. Eso si, el acceso a los datos CHAR es mas rápido que VARCHAR.

No pueden alternarse columnas CHAR y VARCHAR en la misma tabla. MySQL cambiará las columnas CHAR a VARCHAR. También cambia automáticamente a CHAR si usamos VARCHAR con valor de 4 o menos

9.1.1.3. Varios

Tipo Descripción DATE Fecha. El formato por defecto es YYYY MM

DD desde 0000 00 00 a 9999 12 31 DATETIME Combinación de fecha y hora. El rango de

valores va desde el 1 de enero del 1001 a las 0 horas, 0 minutos y 0 segundos al 31 de

diciembre del 9999 a las 23 horas, 59 minutos y 59 segundos. El formato de almacenamiento es

de año-mes-dia horas:minutos:segundos TIMESTAMP Combinación de fecha y hora. El rango va desde

el 1 de enero de 1970 al año 2037. El formato de almacenamiento depende del tamaño del campo

TIME almacena una hora. El rango de horas va desde -838 horas, 59 minutos y 59 segundos a 838, 59

minutos y 59 segundos. El formato de almacenamiento es de 'HH:MM:SS'

YEAR almacena un año. El rango de valores permitidos va desde el año 1901 al año 2155. El campo

puede tener tamaño dos o tamaño 4 dependiendo de si queremos almacenar el año con dos o

cuatro dígitos SET almacena un campo que puede contener

ninguno, uno ó varios valores de una lista. La lista puede tener un máximo de 64 valores

ENUM es igual que SET, pero solo se puede almacenar uno de los valores de la lista

9.2. Acceso a datos

9.2.1. Creación de una tabla

Se usa la siguiente sintaxis: CREATE TABLE nombre_tabla (campo1 tipo_dato NOT NULL AUTOINCREMENT, campo2 tipo_dato, PRIMARY KEY (campo1));

Page 92: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

78

MySQL creará una tabla con 2 campos de los cuales campo1 es un valor único (clave primaria que no puede ser sobreescrito.

9.2.2. Eliminar una tabla

Se usa la siguiente sintaxis: DROP TABLE nombre_tabla;

9.2.3. Modificar la estructura de una tabla

Se usa la siguiente sintaxis: ALTER TABLE nombre_tabla [ADD nombre_atributo definición] // Para añadir un nuevo campo [CHANGE antiguo_atributo nuevo_atributo definición] // Para cambiar un campo [DROP nombre_atributo]; // Para borrar un campo

9.2.4. Índices de una tabla

Los índices son una estructura que permiten el acceso organizado a los datos contenidos de una tabla.

Para crear un índice se usa la siguiente sintaxis: CREATE [UNIQUE] INDEX nombre_indice ON nombre_tabla (campos);

9.2.5. Manipulación de datos

9.2.5.1. Inserción de datos

La inserción de datos en la tabla se realiza mediante el comando INSERT cuyo sintaxis es: INSERT INTO nombre_tabla [campo_1, campo_2, ... , campo_n] VALUES (valor_1, valor_2, ..., valor_n)

9.2.5.2. Consultas de datos

La consulta de datos se realiza con el comando SELECT y la sintaxis es la siguiente: SELECT ([*]/[atributos]) FROM nombre_tabla/s [WHERE lista_condiciones] [GROUP BY campo/s] [HAVING listaCondiciones] [ORDER BY Campo]

Existen un conjunto de funciones dentro de las consultas de datos que nos permiten obtener información o realizar operaciones con respecto a los registros:

Page 93: Php-Mysql

ACCESO A DATOS

79

función Descripción COUNT(*/DISTINCT campo) Cuenta el número de filas

SUM(campo) Suma los valores del campo indicado AVG(campo) Obtiene la media aritmética del campo MAX(campo) Obtiene el valor máximo del campo MIN(campo) Obtiene el valor mínimo del campo

Veamos un ejemplo básico donde utilizamos WHERE y ORDER BY, aquí veremos como seleccionar de la tabla `sucursales` los campos `razon_social`, `id` y `direccion` en todos aquellos registros que el campo `razon_social` sea la cadena de texto 'mi razon social' y además, lo ordenaremos por campo `id` SELECT `razon_social`, `id`, `direccion` FROM `sucursales` WHERE `razon_social` = 'mi razon social' ORDER BY `id`;

9.2.5.3. Modificación de datos

Para modificar datos se usa la sentencia UPDATE cuya sentencia es: UPDATE nombre_tabla SET campo_w=valor_1 [, campo_2=valor_2 ...] [WHERE condición] [ORDER BY campo/s]

9.2.5.4. Borrado de datos

Para borrar datos se usa la sentencia DELETE cuya sintaxis es: DELETE FROM nombre_tabla [WHERE condición]

9.2.5.5. Consulta de datos usando JOIN

MySQL soporta las siguientes posibles sintaxis de JOIN (unión de dos tablas) en comandos SELECT y DELETE y UPDATE: table_reference, table_reference table_reference [INNER | CROSS] JOIN table_reference [join_condition] table_reference STRAIGHT_JOIN table_reference table_reference LEFT [OUTER] JOIN table_reference join_condition table_reference NATURAL [LEFT [OUTER]] JOIN table_reference { ON table_reference LEFT OUTER JOIN table_reference ON conditional_expr } table_reference RIGHT [OUTER] JOIN table_reference join_condition table_reference NATURAL [RIGHT [OUTER]] JOIN table_reference

donde table_reference se define como: tbl_name [[AS] alias] [[USE INDEX (key_list)] | [IGNORE INDEX (key_list)] | [FORCE INDEX (key_list)]]

donde join_condition se define como: ON conditional_expr | USING (column_list)

De entre todos los tipos posibles, los más usados son los siguientes:

Page 94: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

80

• JOIN: Se obtienen todos los registros que verifican la condición en las dos tablas, sin mostrarse los que no la cumplen.

• LEFT JOIN: Se obtienen todos los registros que verifican la condición en las dos tablas, mostrando los registros que no lo cumplen correspondientes a la tabla de la izquierda (con los datos de la tabla de la derecha no informados).

• RIGHT JOIN: Se obtienen todos los registros que verifican la condición en las dos tablas, mostrando los registros que no lo cumplen correspondientes a la tabla de la derecha (con los datos de la tabla de la izquierda no informados).

Veamos que el caso de JOIN se puede sustituir por una coma:

Esta consulta: mysql> SELECT * FROM personas2, telefonos2 -> WHERE personas2.id=telefonos2.id;

Sería equivalente a estas: mysql> SELECT * FROM personas2 JOIN telefonos2 -> ON (personas2.id = telefonos2.id); mysql> SELECT * FROM personas2 JOIN telefonos2 -> WHERE (personas2.id = telefonos2.id); mysql> SELECT * FROM personas2 INNER JOIN telefonos2 -> ON (personas2.id = telefonos2.id); mysql> SELECT * FROM personas2 CROSS JOIN telefonos2 -> ON (personas2.id = telefonos2.id); mysql> SELECT * FROM personas2 JOIN telefonos2 USING(id);

9.2.6. Vistas

Una vista es un objeto de la base de datos que que agrupa una selección o un conjunto de datos.

9.2.6.1. Crear Vistas

Podemos crear o modificar vistas con CREATE VIEW. CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW nombre_vista [(columnas)] AS sentencia_select [WITH [CASCADED | LOCAL] CHECK OPTION]

Esta sentencia crea una vista nueva o reemplaza una existente si se incluye la cláusula OR REPLACE.

Para ver su uso consideremos que disponemos de la siguiente tabla: mysql> desc mail_aliases; +-------------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+----------+------+-----+---------+-------+ | alias | char(32) | NO | MUL | NULL | | | domain | char(64) | NO | | NULL | | | comments | text | NO | | NULL | | +-------------+----------+------+-----+---------+-------+ 3 rows in set (0.01 sec)

En esta tabla podemos consultar los alias de correo para todos los dominios de un servidor.

Page 95: Php-Mysql

ACCESO A DATOS

81

Para acceder a datos específicos de forma repetida, podemos definir vistas. Por ejemplo, podemos crear una vista para un determinado dominio: mysql> create view mail_alias_myhost as select alias, comments from mail_aliases where domain="myhost"; Query OK, 0 rows affected (0.04 sec)

A continuación mediante la vista podremos acceder a los datos que se han seleccionado: mysql> select * from mail_alias_myhost; +---------------+-----------------------------+ | alias | comments | +---------------+-----------------------------+ | helpdesk | Soporte y ayuda | | .... | .... | +---------------+-----------------------------+

Mediante la palabra clave ALGORITHM podemos indicar como deseamos que funcione:

• UNDEFINED: Dejamos el control a MySQL (caso por defecto).

• MERGE: el texto de una sentencia que haga referencia a la vista y la definición de la vista son mezclados de forma que parte de la definición de la vista reemplaza las partes correspondientes de la consulta.

• TEMPTABLE: En el momento de hacer una consulta sobre la vista se crea una tabla temporal. Este método tiene una gran ventaja y una gran desventaja:

o Desventaja: La vista no puede modificarse, por lo que cualquier cambio se deberá hacer en la tabla original.

o Ventaja: Los bloqueos se liberan antes, ya que la consulta de la vista se hace a partir de la tabla temporal. Esto permite que otros threads accedan antes a la tabla que ejecutando una consulta mucho mas pesada usando el algoritmo MERGE.

9.2.6.2. Borrar Vistas

Podemos eliminar o borrar vistas con DROP VIEW. DROP VIEW [IF EXISTS] nombre_vista [, nombre_vista] ...

9.2.6.3. (Meta)Información de Vistas

Para obtener información de definición de una vista (metadatos) se utiliza SHOW CREATE VIEW.

SHOW CREATE VIEW nombre_vista

Muestra la sentencia CREATE VIEW que se utilizó para crear la vista. Por ejemplo: mysql> SHOW CREATE VIEW mail_alias_myhost; +-------+----------------------------------------------------+ | Table | Create Table | +-------+----------------------------------------------------+ | v | create view mail_alias_myhost as | | | select alias, comments from mail_aliases | | | where domain="myhost"; | +-------+----------------------------------------------------+

Page 96: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

82

9.2.6.4. Restricciones en vistas

Presentamos las restricciones más importantes, o qué más a menudo se presentan. Para más información, recomendamos la lectura de l punto H.4. Restricciones en vistas del manual de MySQL.

El procesamiento de vistas no está optimizado:

• No es posible crear un índice en una vista.

• Los índices pueden utilizarse para procesar vistas usando un algoritmo de combinación (MERGE). Sin embargo, una vista que se procesa con el algoritmo de tablas temporales (temptable) no es capaz de tomar ventaja de los índices que hacen referencia a las tablas que contiene.

Las subconsultas no pueden utilizarse en la cláusula FROM de una vista.

No se puede modificar una tabla y seleccionar de la misma en una subconsulta.

Se puede usar DROP TABLE o ALTER TABLE para eliminar o modificar una tabla utilizada en la definición de una vista (lo cual invalida la vista) y no se obtendrá ninguna alerta de las operaciones de eliminar o modificar. Sin embargo, se obtiene un error más tarde, cuando se utiliza la vista.

9.2.7. Sentencias preparadas

Una sentencia o procedimiento preparado es una sentencia SQL definida y parametrizada en el servidor de modo que solo necesita para su ejecución los valores correspondientes a los campos parametrizados.

La sintaxis SQL se basa en los siguientes tres comandos SQL: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @var_name] ...]; {DEALLOCATE | DROP} PREPARE stmt_name;

El comando PREPARE prepara un comando y le asigna un nombre, stmt_name, con el que referirse al comando posteriormente. Los nombres de comando no son sensibles a mayúsculas. preparable_stmt es una cadena literal o una variable de usuario que contenga el texto del comando. El texto debe representar un comando SQL único, no varios. Dentro del comando, pueden usarse caracteres '?' como marcadores de parámetros para indicar dónde estarán los valores en la consulta posterior cuando la ejecute. Los caracteres '?' no deben delimitarse con comillas, incluso si pretende ligarlos con valores de cadenas.

Tras preparar un comando, lo ejecuta con un comando EXECUTE que se refiere al nombre de comando preparado. Si el comando preparado contiene cualquier marcador de parámetro, debe añadir una cláusula USING que liste las variables de usuario conteniendo los valores a ligar con los parámetros. Los valores de parámetros pueden proporcionarse sólo por variables de usuario, y la cláusula USING debe nombrar exactamente tantas variables como el número de marcadores de parámetros en el comando.

Page 97: Php-Mysql

ACCESO A DATOS

83

Para eliminar un comando preparado, use el comando DEALLOCATE PREPARE . Tratar de ejecutar un comando preparado tras borrarlo provoca un error.

Los siguientes comandos SQL pueden usarse en comandos preparados: CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, y la mayoría de comandos SHOW .

El siguiente ejemplo muestra una sentencia preparada que calcula la hipotenusa de un triángulo dadas las longitudes de los dos catetos. mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'; mysql> SET @a = 3; mysql> SET @b = 4; mysql> EXECUTE stmt1 USING @a, @b; +------------+ | hypotenuse | +------------+ | 5 | +------------+ mysql> DEALLOCATE PREPARE stmt1;

9.2.8. Exportación e importación de datos

MySQL permite copiar tablas en diferentes formatos de texto, así como importar datos a partir de fichero de texto en diferentes formatos.

Esto se puede usar para exportar los datos de nuestras bases de datos a otras aplicaciones, o bien para importar datos desde otras fuentes a nuestras tablas. También se puede usar para hacer copias de seguridad y restaurarlas posteriormente.

9.2.8.1. Exportar a otros ficheros

Para extraer datos desde una base de datos a un fichero se usa la sentencia SELECT. Para ello, se añaden los elementos que permiten identificar el fichero de salida y el formato de los campos en dicho fichero. El resto de las cláusulas de siguen siendo aplicables.

El fichero de salida se identifica mediante: [INTO OUTFILE 'file_name' export_options]

dónde file_name es el nombre del fichero de salida. Ese fichero no debe existir.

Para definir el formato de salida se usa: [FIELDS [TERMINATED BY '\t'] [[OPTIONALLY] ENCLOSED BY ''] [ESCAPED BY '\\' ] ] [LINES [STARTING BY ''] [TERMINATED BY '\n'] ]

La cláusula FIELDS se refiere a las opciones de cada columna:

• TERMINATED BY 'carácter': nos permite elegir el carácter delimitador que se usará para señalar cada columna. El valor por defecto es el tabulador.

Page 98: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

84

• [OPTIONALLY] ENCLOSED BY 'carácter': sirve para elegir el carácter usado para entrecomillar cada columna. Por defecto no se entrecomilla ninguna columna. Si se añade la palabra OPTIONALLY sólo se entrecomillarán las columnas de texto y fecha.

• ESCAPED BY 'carácter': sirve para indicar el carácter que se usará para escapar aquellos caracteres que pueden dificultar la lectura posterior del fichero. Por defecto se usa el carácter '\'.

La cláusula LINES se refiere a las opciones para cada fila:

• STARTING BY 'carácter': permite seleccionar el carácter para comenzar cada línea. Por defecto no se usa ningún carácter para ello.

• TERMINATED BY 'carácter': permite elegir el carácter para terminar cada línea. Por defecto es el retorno de línea.

Veamos un ejemplo. Vamos a obtener obtener un fichero de texto a partir de la tabla 'gente', con las columnas delimitadas por ';', entrecomillando las columnas de texto con '”' y separando cada fila por la secuencia '\r\n': mysql> SELECT * FROM gente -> INTO OUTFILE "gente.txt" -> FIELDS TERMINATED BY ';' -> OPTIONALLY ENCLOSED BY '\"' -> LINES TERMINATED BY '\n\r'; Query OK, 5 rows affected (0.00 sec)

El fichero de salida tendrá este aspecto: "Fulano";"1974-04-12" "Mengano";"1978-06-15" "Tulano";"2000-12-02" "Pegano";"1993-02-10" "Mengano";\N

La fecha para “Mengano” era NULL, para indicarlo se muestra el valor \N.

9.2.8.2. Importar a partir de ficheros externos

Se puede recuperar el contenido de un fichero e incluirlo en una tabla.

Para hacerlo disponemos de la sentencia “LOAD DATA”, cuya sintaxis más simple es: LOAD DATA [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY '\t'] [[OPTIONALLY] ENCLOSED BY ''] [ESCAPED BY '\\' ] ] [LINES [STARTING BY ''] [TERMINATED BY '\n'] ] [IGNORE number LINES] [(col_name,...)]

• La cláusula LOCAL indica, si aparece, que el fichero está en el ordenador del cliente. Si no se especifica el fichero de texto se buscará en el servidor, concretamente en el mismo directorio donde esté la base de datos.

Page 99: Php-Mysql

ACCESO A DATOS

85

• Las cláusulas REPLACE e IGNORE afectan al modo en que se tratan las filas leídas que contengan el mismo valor para una clave principal o única para una fila existente en la tabla. Si se especifica REPLACE se sustituirá la fila actual por la leída. Si se especifica IGNORE el valor leído será ignorado.

• La parte INTO TABLA tbl_name indica en qué tabla se insertarán los valores leídos.

• Las cláusulas FIELDS y LINES tienen el mismo significado que vimos el exportar datos.

• La cláusula IGNORE número LINES permite que las primeras número líneas no se interpreten como datos a importar.

• La última parte nos permite indicar la columna a la que será asignada cada una de las columnas leídas, esto será útil si el orden de las columnas en la tabla no es el mismo que en el fichero de texto, o si el número de columnas es diferente en ambos.

• Por ejemplo, supongamos que queremos añadir el contenido de este fichero a la tabla “gente”:

Fichero de datos de "gente" fecha,nombre 2004-03-15,Xulana 2000-09-09,Con Clase 1998-04-15,Pingrana

Como vemos, hay dos filas al principio que no contienen datos válidos, las columnas están separadas con comas y, como hemos editado el fichero en MSWindows, las líneas terminan con “\n\r”.

La sentencia adecuada para leer los datos es: mysql> LOAD DATA INFILE "gente.txt" -> INTO TABLE gente -> FIELDS TERMINATED BY ',' -> LINES TERMINATED BY '\r\n' -> IGNORE 2 LINES -> (fecha,nombre); Query OK, 3 rows affected (0.00 sec) Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

El contenido de la tabla queda entonces: mysql> SELECT * FROM gente; +-----------+------------+ | nombre | fecha | +-----------+------------+ | Fulano | 1974-04-12 | | Mengano | 1978-06-15 | | Tulano | 2000-12-02 | | Pegano | 1993-02-10 | | Mengano | NULL | | Xulana | 2004-03-15 | | Con Clase | 2000-09-09 | | Pingrana | 1998-04-15 | +-----------+------------+ 8 rows in set (0.00 sec)

9.2.9. Rutinas almacenadas y disparadores

Page 100: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

86

9.2.9.1. Disparadores (triggers)

Un disparador es un objeto con nombre dentro de una base de datos el cual se asocia con una tabla y se activa cuando ocurre en ésta un evento en particular.

El soporte actual es básico, por lo tanto hay ciertas limitaciones en lo que puede hacerse con ellos.

Para crear un disparador se utiliza la sentencia CREATE TRIGGER: CREATE TRIGGER nombre_disp momento_disp evento_disp ON nombre_tabla FOR EACH ROW sentencia_disp

Mientras que para eliminar un disparador se utiliza la sentenciaDROP TRIGGER: DROP TRIGGER [nombre_esquema.]nombre_disp

Para entenderlo mejor planteamos un ejemplo de uso.

Definimos en nuestra base de datos 2 tablas:

• usuarios: con los datos de nuestros usuarios.

• acciones: donde guardaremos las acciones realizadas sobre nuestras tablas.

Las tablas serán las siguientes: /* Creamos la tabla de acciones*/ CREATE TABLE acciones( fecha DATE, hora TIME, accion VARCHAR(50), id_usuario integer ); /*Creamos la tabla de usuarios*/ CREATE TABLE usuarios( id_usuario integer PRIMARY KEY, nombre VARCHAR(50), apellido VARCHAR(50) );

Creamos 3 disparadores sobre la tabla de usuarios, sobre las acciones que se realicen sobre ella (inserción, modificación o borrado).

Los disparadores son: /*Disparador para el registro de inserciones*/ DELIMITER | CREATE TRIGGER inser_usuarios BEFORE INSERT ON usuarios FOR EACH ROW BEGIN INSERT INTO acciones VALUES(CURDATE(),CURTIME(),'Registro insertado', new.id_usuario); END; | DELIMITER ; /*Disparador para el registro modificado*/ DELIMITER | CREATE TRIGGER update_usuarios BEFORE UPDATE ON usuarios FOR EACH ROW BEGIN INSERT INTO acciones VALUES(CURDATE(),CURTIME(),'Registro Modificado', old.id_usuario); END; | DELIMITER ;

Page 101: Php-Mysql

ACCESO A DATOS

87

/*Disparador para el registro eliminado*/ DELIMITER | CREATE TRIGGER delete_usuarios BEFORE DELETE ON usuarios FOR EACH ROW BEGIN INSERT INTO acciones VALUES(CURDATE(),CURTIME(),'Registro eliminado', old.id_usuario); END; | DELIMITER ;

Explicamos brevemente cómo lo hemos usado en la última definición:

• DELIMITER: los disparadores están formados por varias instrucciones, por lo tanto, antes de comenzar su definición, debes especificar qué carácter delimita (o separa).

• CREATE TRIGGER: Es la sentencia de creación del disparador.

• BEFORE: Indica el momento de acción del disparador

• DELETE: Indica el evento que activará al disparador

• FOR EACH ROW: Define lo que se ejecutará cada vez que el disparador se active, lo cual ocurre una vez por cada fila afectada por la sentencia activadora.

• Las palabras clave OLD y NEW permiten acceder a columnas en los registros afectados por un disparador. (OLD y NEW no son sensibles a mayúsculas).

o En un disparador para INSERT, solamente puede utilizarse NEW.nom_col; ya que no hay una versión anterior del registro.

o En un disparador para DELETE sólo puede emplearse OLD.nom_col, porque no hay un nuevo registro.

o En un disparador para UPDATE se puede emplear OLD.nom_col para referirse a las columnas de un registro antes de que sea actualizado, y NEW.nom_col para referirse a las columnas del registro luego de actualizarlo.

Podemos ver su funcionamiento realizando las siguientes acciones: INSERT INTO usuarios VALUES (1,'Pepe','Gómez'); INSERT INTO usuarios VALUES (2,'Luis','López'); INSERT INTO usuarios VALUES (3,'Juan','Nadie'); /*Verificamos las inserciones*/ select * from usuarios; /*Revisamos la tabla de acciones */ select * from acciones; /*Modificamos 1 registroo*/ update usuarios set apellido = 'Hernández' where id_usuario=1; /*Revisamos la tabla de acciones */ select * from acciones; /*Eliminamos 1registroo*/ delete from usuarios where id_usuario=3; /*Revisamos la tabla de acciones */ select * from acciones;

Page 102: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

88

9.2.9.2. Rutinas o Procedimientos almacenados

Un procedimiento almacenado es un conjunto de comandos SQL que pueden almacenarse en el servidor. Una vez que se hace, los clientes no necesitan relanzar los comandos individuales pero pueden en su lugar referirse al procedimiento almacenado.

Algunas situaciones en que los procedimientos almacenados pueden ser particularmente útiles:

• Cuando múltiples aplicaciones cliente se escriben en distintos lenguajes o funcionan en distintas plataformas, pero necesitan realizar la misma operación en la base de datos.

• Cuando la seguridad es muy importante.

Los procedimientos almacenados pueden mejorar el rendimiento ya que se necesita enviar menos información entre el servidor y el cliente. Pero a cambio se aumenta la carga del servidor de la base de datos ya que la mayoría del trabajo se realiza en la parte del servidor y no en el cliente.

Para crear un procedimiento almacenado se utiliza la sentencia CREATE PROCEDURE: CREATE PROCEDURE sp_name ([parameter[,...]]) [characteristic ...] routine_body parameter: [ IN | OUT | INOUT ] param_name type type: Any valid MySQL data type characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } | COMMENT 'string' routine_body: procedimientos almacenados o comandos SQL válidos

Mientras que para eliminar un procedimiento almacenado se utiliza la sentenciaDROP PROCEDURE: DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

Para facilitar la explicación, planteemos un ejemplo de uso.

Nuestro sistema tendrá dos tablas, una con ventas y la otra con comisiones. En la primera se almacenarán cada venta que se realiza en un comercio, y en la segunda las comisiones que le corresponden a cada vendedor en el momento. CREATE TABLE `ventas` ( `vendedor` int(11), `producto` int(11), `importe` float ) CREATE TABLE `comisiones` ( `vendedor` int(11), `comision` float )

Page 103: Php-Mysql

ACCESO A DATOS

89

Las comisiones se calcula de una forma especial, le corresponde un porcentaje de las ventas según el tipo de producto, y es importante para los vendedores el que se sepa en cada momento qué comisiones lleva ganadas.

Para calcular qué comisión le corresponde a un vendedor, calcularemos los porcentajes para cada tipo de producto vendido y luego lo añadiremos/actualizaremos en la tabla de comisiones. Todo se realizará en un procedimiento almacenado. DELIMITER | DROP PROCEDURE IF EXISTS `test`.`sp_comisiones`| CREATE PROCEDURE `test`.`sp_comisiones` (IN mivendedor INT) BEGIN DECLARE micomision INT DEFAULT 0; DECLARE suma INT; DECLARE existe BOOL; select IFNULL(sum(importe),0) into suma from ventas where producto = 1 and vendedor = mivendedor; SET micomision = micomision + (suma * 0.15); select IFNULL(sum(importe),0) into suma from ventas where producto = 2 and vendedor = mivendedor; SET micomision = micomision + (suma * 0.1); select IFNULL(sum(importe),0) into suma from ventas where producto = 3 and vendedor = mivendedor; SET micomision = micomision + (suma * 0.2); select count(1)>0 into existe from comisiones where vendedor = mivendedor; if existe then UPDATE comisiones set comision = comision+micomision where vendedor = mivendedor; else insert into comisiones (vendedor, comision) values (mivendedor, micomision); end if; END | DELIMITER ;

Ahora, para actualizar los datos de las comisiones usaremos un trigger, así cuando se haga una venta (insert en la tabla ventas), se llamará al procedimiento almacenado (sp_comisiones), que recalculará la comisión para ese vendedor. DELIMITER $$ DROP TRIGGER `test`.`tr_ventas_insert`$$ CREATE TRIGGER `test`.`tr_ventas_insert` AFTER INSERT on `test`.`ventas` FOR EACH ROW BEGIN call sp_comisiones(new.vendedor); END$$ DELIMITER ;

9.2.9.3. Restricciones

Presentamos las restricciones más importantes. Para un estudio más profundo remitimos a H.1. Restricciones en procedimientos almacenados y disparadores del manual de MySQL.

Todas las restricciones para las funciones almacenadas se refieren también a los disparadores.

Las rutinas almacenadas no pueden contener sentencias SQL arbitrarias. Las siguientes sentencias no están permitidas dentro de una rutina almacenada:

• CHECK TABLES

• LOCK TABLES, UNLOCK TABLES

Page 104: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

90

• FLUSH

• LOAD DATA, LOAD TABLE

• Sentencias SQL preparadas(PREPARE, EXECUTE, DEALLOCATE).

Además, en funciones almacenadas (pero no para procedimientos almacenados), no están permitidas las siguientes sentencias:

• Sentencias que hacen commits o rollbacks explícitos o implícitos.

• Sentencias que devuelvan un resultado. Esto incluye sentencias SELECT que no tienen una cláusula INTO y la sentencia SHOW.

Page 105: Php-Mysql

EJEMPLOS Y EJERCICIOS

91

Ejemplo y ejercicios

10.1. Introducción

El objetivo es definir una base de datos para la gestión, simple, de una o varias entidades bancarias.

Consideramos que una entidad bancaria puede tener varias sucursales, que es dónde se realizan las transacciones con clientes. Los clientes abren cuentas en las sucursales para gestionar sus fondos monetarios, pudiendo disponer de una única cuenta en diferentes sucursales de diferentes entidades bancarias.

Además, las entidades bancarias ofrecen préstamos a sus clientes, que asocian a cuentas que tienen en sus sucursales.

10.2. Ejercicios

10.2.1. Ejercicio 1 - Modelado de la base de datos

El modelo de la bb.dd. final (usando MySQL Workbench) es:

Page 106: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

92

10.2.2. Ejercicio 2 - Creación de la base de datos en MySQL

Crear la base de datos curso_ejemplo con las tablas desde MySQLWorkbench

Crear la base de datos curso_ejemplo CREATE DATABASE `curso_ejemplo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Crear las tablas:

1. Crear la tabla entidad_bancaria:

CREATE TABLE IF NOT EXISTS ‘entidad bancaria’ ( ‘id’ INT NOT NULL AUTO_INCREMENT, ‘razon_social’ VARCHAR(45) NOT NULL, PRIMARY KEY (‘id’)) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

2. Probar a crear la tabla cuenta sin haber creado antes la tabla sucursal: NO se puede por integridad referencial.

3. Crear la tabla sucursal:

Page 107: Php-Mysql

EJEMPLOS Y EJERCICIOS

93

CREATE TABLE IF NOT EXISTS `sucursal` ( `id` INT(4) NOT NULL , `direccion` VARCHAR(45) NOT NULL , `entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`, `entidad_bancaria_id`) , INDEX `fk_sucursal_entidad_bancaria` (`entidad_bancaria_id` ASC) , CONSTRAINT `fk_sucursal_entidad_bancaria` FOREIGN KEY (`entidad_bancaria_id` ) REFERENCES `entidad_bancaria` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

4. Crear la tabla cuenta: CREATE TABLE IF NOT EXISTS `cuenta` ( `id` INT NOT NULL AUTO_INCREMENT , `tipo` INT(1) NOT NULL DEFAULT 0 , `saldo` DOUBLE NOT NULL DEFAULT 0 , `fecha_alta` DATE NOT NULL , `sucursal_id` INT(4) NOT NULL , `sucursal_entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`) , INDEX `fk_cuenta_sucursal1` (`sucursal_id` ASC, `sucursal_entidad_bancaria_id` ASC) , CONSTRAINT `fk_cuenta_sucursal1` FOREIGN KEY (`sucursal_id` , `sucursal_entidad_bancaria_id` ) REFERENCES `sucursal` (`id` , `entidad_bancaria_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

5. Crear la tabla cliente: CREATE TABLE IF NOT EXISTS `cliente` ( `id` INT NOT NULL AUTO_INCREMENT , `dni` VARCHAR(10) NOT NULL , `nombre` VARCHAR(100) NOT NULL , `telefono` VARCHAR(12) NULL , PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

6. Crear la tabla prestamo: CREATE TABLE IF NOT EXISTS `prestamo` ( `id` INT NOT NULL AUTO_INCREMENT , `valor` INT NOT NULL , `fecha` DATE NOT NULL , `sucursal_id` INT(4) NOT NULL , `sucursal_entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`) , INDEX `fk_prestamo_sucursal1` (`sucursal_id` ASC, `sucursal_entidad_bancaria_id` ASC) , CONSTRAINT `fk_prestamo_sucursal1` FOREIGN KEY (`sucursal_id` , `sucursal_entidad_bancaria_id` ) REFERENCES `sucursal` (`id` , `entidad_bancaria_id` ) ON DELETE NO ACTION

Page 108: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

94

ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci

7. Crear la tabla cliente_has_prestamo: CREATE TABLE IF NOT EXISTS `cliente_has_prestamo` ( `cliente_id` INT NOT NULL , `prestamo_id` INT NOT NULL , PRIMARY KEY (`cliente_id`, `prestamo_id`) , INDEX `fk_cliente_has_prestamo_cliente1` (`cliente_id` ASC) , INDEX `fk_cliente_has_prestamo_prestamo1` (`prestamo_id` ASC) , CONSTRAINT `fk_cliente_has_prestamo_cliente1` FOREIGN KEY (`cliente_id` ) REFERENCES `cliente` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_cliente_has_prestamo_prestamo1` FOREIGN KEY (`prestamo_id` ) REFERENCES `prestamo` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci

8. Crear la tabla cliente_has_cuenta: CREATE TABLE IF NOT EXISTS `cliente_has_cuenta` ( `cliente_id` INT NOT NULL , `cuenta_id` INT NOT NULL , PRIMARY KEY (`cliente_id`, `cuenta_id`) , INDEX `fk_cliente_has_cuenta_cliente1` (`cliente_id` ASC) , INDEX `fk_cliente_has_cuenta_cuenta1` (`cuenta_id` ASC) , CONSTRAINT `fk_cliente_has_cuenta_cliente1` FOREIGN KEY (`cliente_id` ) REFERENCES `cliente` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_cliente_has_cuenta_cuenta1` FOREIGN KEY (`cuenta_id` ) REFERENCES `cuenta` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

• Usando un script SQL -- ----------------------------------------------------- -- Table `entidad_bancaria` -- ----------------------------------------------------- DROP TABLE IF EXISTS `entidad_bancaria` ; CREATE TABLE IF NOT EXISTS `entidad_bancaria` ( `id` INT NOT NULL AUTO_INCREMENT , `razon_social` VARCHAR(45) NOT NULL , PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Datos de entidad bancaria';

Page 109: Php-Mysql

EJEMPLOS Y EJERCICIOS

95

-- ----------------------------------------------------- -- Table `sucursal` -- ----------------------------------------------------- DROP TABLE IF EXISTS `sucursal` ; CREATE TABLE IF NOT EXISTS `sucursal` ( `id` INT(4) NOT NULL , `direccion` VARCHAR(45) NOT NULL , `entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`, `entidad_bancaria_id`) , INDEX `fk_sucursal_entidad_bancaria` (`entidad_bancaria_id` ASC) , CONSTRAINT `fk_sucursal_entidad_bancaria` FOREIGN KEY (`entidad_bancaria_id` ) REFERENCES `entidad_bancaria` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Sucursal de la entidad bancaria'; -- ----------------------------------------------------- -- Table `cuenta` -- ----------------------------------------------------- DROP TABLE IF EXISTS `cuenta` ; CREATE TABLE IF NOT EXISTS `cuenta` ( `id` INT NOT NULL AUTO_INCREMENT , `tipo` INT(1) NOT NULL DEFAULT 0 , `saldo` DOUBLE NOT NULL DEFAULT 0 , `fecha_alta` DATE NOT NULL , `sucursal_id` INT(4) NOT NULL , `sucursal_entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`) , INDEX `fk_cuenta_sucursal1` (`sucursal_id` ASC, `sucursal_entidad_bancaria_id` ASC) , CONSTRAINT `fk_cuenta_sucursal1` FOREIGN KEY (`sucursal_id` , `sucursal_entidad_bancaria_id` ) REFERENCES `sucursal` (`id` , `entidad_bancaria_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Datos de cuentas bancarias'; -- ----------------------------------------------------- -- Table `cliente` -- ----------------------------------------------------- DROP TABLE IF EXISTS `cliente` ; CREATE TABLE IF NOT EXISTS `cliente` ( `id` INT NOT NULL AUTO_INCREMENT , `dni` VARCHAR(10) NOT NULL , `nombre` VARCHAR(100) NOT NULL , `telefono` VARCHAR(12) NULL , PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Información de cliente';

Page 110: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

96

-- ----------------------------------------------------- -- Table `prestamo` -- ----------------------------------------------------- DROP TABLE IF EXISTS `prestamo` ; CREATE TABLE IF NOT EXISTS `prestamo` ( `id` INT NOT NULL AUTO_INCREMENT , `valor` INT NOT NULL , `fecha` DATE NOT NULL , `sucursal_id` INT(4) NOT NULL , `sucursal_entidad_bancaria_id` INT NOT NULL , PRIMARY KEY (`id`) , INDEX `fk_prestamo_sucursal1` (`sucursal_id` ASC, `sucursal_entidad_bancaria_id` ASC) , CONSTRAINT `fk_prestamo_sucursal1` FOREIGN KEY (`sucursal_id` , `sucursal_entidad_bancaria_id` ) REFERENCES `sucursal` (`id` , `entidad_bancaria_id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Datos de los préstamos'; -- ----------------------------------------------------- -- Table `cliente_has_prestamo` -- ----------------------------------------------------- DROP TABLE IF EXISTS `cliente_has_prestamo` ; CREATE TABLE IF NOT EXISTS `cliente_has_prestamo` ( `cliente_id` INT NOT NULL , `prestamo_id` INT NOT NULL , PRIMARY KEY (`cliente_id`, `prestamo_id`) , INDEX `fk_cliente_has_prestamo_cliente1` (`cliente_id` ASC) , INDEX `fk_cliente_has_prestamo_prestamo1` (`prestamo_id` ASC) , CONSTRAINT `fk_cliente_has_prestamo_cliente1` FOREIGN KEY (`cliente_id` ) REFERENCES `cliente` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_cliente_has_prestamo_prestamo1` FOREIGN KEY (`prestamo_id` ) REFERENCES `prestamo` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Prestamos de clientes: tabla para resolver la relación n a m.'; -- ----------------------------------------------------- -- Table `cliente_has_cuenta` -- ----------------------------------------------------- DROP TABLE IF EXISTS `cliente_has_cuenta` ; CREATE TABLE IF NOT EXISTS `cliente_has_cuenta` ( `cliente_id` INT NOT NULL , `cuenta_id` INT NOT NULL , PRIMARY KEY (`cliente_id`, `cuenta_id`) , INDEX `fk_cliente_has_cuenta_cliente1` (`cliente_id` ASC) , INDEX `fk_cliente_has_cuenta_cuenta1` (`cuenta_id` ASC) , CONSTRAINT `fk_cliente_has_cuenta_cliente1`

Page 111: Php-Mysql

EJEMPLOS Y EJERCICIOS

97

FOREIGN KEY (`cliente_id` ) REFERENCES `cliente` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_cliente_has_cuenta_cuenta1` FOREIGN KEY (`cuenta_id` ) REFERENCES `cuenta` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

10.2.3. Ejercicio 3 - Poblar la base de datos en MySQL

1. Poblar datos de la tabla entidad_bancaria: INSERT INTO `entidad_bancaria` (`id`, `razon_social`) VALUES (1, 'Caja de Ahorros'), (2, 'Banco Primero');

2. Poblar datos de la tabla cuenta SIN poblar los datos de la tabla sucursal: No se puede por integridad referencial.

3. Poblar datos de la tabla sucursal: INSERT INTO `sucursal` (`id`, `direccion`, `entidad_bancaria_id`) VALUES (1, 'C/ HierbaBuena', 1), (1, 'C/ Naranja', 2), (2, 'C/ Tomillo', 1), (2, 'C/ Limón', 2), (3, 'C/ Menta', 1);

4. Poblar datos de la tabla cuenta: INSERT INTO `cuenta` (`id`, `tipo`, `saldo`, `fecha_alta`, `sucursal_id`, `sucursal_entidad_bancaria_id`) VALUES (1, 0, 1345.00, '2010-04-29', 1, 1), (2, 1, 56789.00, '2010-04-07', 2, 1), (3, 1, 856.45, '2010-04-11', 2, 1), (4, 0, 1654.00, '2010-04-30', 2, 2);

5. Poblar datos de la tabla cliente: INSERT INTO `cliente` (`id`, `dni`, `nombre`, `telefono`) VALUES (1, '123456789', 'Juan Nadie', '+34321654987'), (2, '987654321', 'José López', '+34789456123'), (3, '678912345', 'Luisa Fernández', '+34102938475');

6. Poblar datos de la tabla prestamo: INSERT INTO `prestamo` (`id`, `valor`, `fecha`, `sucursal_id`, `sucursal_entidad_bancaria_id`) VALUES (1, 150000, '2010-05-18', 1, 1), (2, 8000, '2010-06-15', 2, 2);

7. Poblar datos de la tabla cliente_has_cuenta: INSERT INTO `cliente_has_cuenta` (`cliente_id`, `cuenta_id`) VALUES (1, 1), (2, 2), (2, 3), (3, 4);

8. Poblar datos de la tabla cliente_has_prestamo:

Page 112: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

98

INSERT INTO `cliente_has_prestamo` (`cliente_id`, `prestamo_id`) VALUES (1, 1), (2, 2);

• SQL con los datos de todos los ejercicios: -- -- Datos para la tabla `entidad_bancaria` -- INSERT INTO `entidad_bancaria` (`id`, `razon_social`) VALUES (1, 'Caja de Ahorros'), (2, 'Banco Primero'); -- -- Datos para la tabla `sucursal` -- INSERT INTO `sucursal` (`id`, `direccion`, `entidad_bancaria_id`) VALUES (1, 'C/ HierbaBuena', 1), (1, 'C/ Naranja', 2), (2, 'C/ Tomillo', 1), (2, 'C/ Limón', 2), (3, 'C/ Menta', 1); -- -- Datos para la tabla `cuenta` -- INSERT INTO `cuenta` (`id`, `tipo`, `saldo`, `fecha_alta`, `sucursal_id`, `sucursal_entidad_bancaria_id`) VALUES (1, 0, 1345.00, '2010-04-29', 1, 1), (2, 1, 56789.00, '2010-04-07', 2, 1), (3, 1, 856.45, '2010-04-11', 2, 1), (4, 0, 1654.00, '2010-04-30', 2, 2); -- -- Datos para la tabla `cliente` -- INSERT INTO `cliente` (`id`, `dni`, `nombre`, `telefono`) VALUES (1, '123456789', 'Juan Nadie', '+34321654987'), (2, '987654321', 'José López', '+34789456123'), (3, '678912345', 'Luisa Fernández', '+34102938475'); -- -- Datos para la tabla `prestamo` -- INSERT INTO `prestamo` (`id`, `valor`, `fecha`, `sucursal_id`, `sucursal_entidad_bancaria_id`) VALUES (1, 150000, '2010-05-18', 1, 1), (2, 8000, '2010-06-15', 2, 2); -- -- Datos para la tabla `cliente_has_cuenta` -- INSERT INTO `cliente_has_cuenta` (`cliente_id`, `cuenta_id`) VALUES (1, 1), (2, 2), (2, 3), (3, 4); -- -- Datos para la tabla `cliente_has_prestamo`

Page 113: Php-Mysql

EJEMPLOS Y EJERCICIOS

99

-- INSERT INTO `cliente_has_prestamo` (`cliente_id`, `prestamo_id`) VALUES (1, 1), (2, 2);

10.2.4. Ejercicio 4 - Integridad referencial en MySQL

1. Borrar la tabla 'entidad_bancaria': DROP TABLE IF EXISTS `entidad_bancaria` ;

NO se puede.

2. Insertar un registro en la tabla sucursal para una entidad Bancaria inexistente: INSERT INTO `sucursal` (`id`, `direccion`, `entidad_bancaria_id`) VALUES (1, 'C/ Arbusto', 3);

NO se puede.

3. Borrar un registro en la tabla cliente que tiene cuentas dadas de alta: DELETE FROM `curso_ejemplo`.`cliente` WHERE `cliente`.`id` =3;

NO se puede.

10.2.5. Ejercicio 5 - Acceso a Datos

1. Conectarse a la base de datos de ejemplo desde la consola: mysql -u root -p curso_ejemplo

2. Comprobar las tablas de la base de datos: mysql> show tables; +-------------------------+ | Tables_in_curso_ejemplo | +-------------------------+ | cliente | | cliente_has_cuenta | | cliente_has_prestamo | | cuenta | | entidad_bancaria | | prestamo | | sucursal | +-------------------------+

3. Obtener los datos de la tabla 'sucursal': mysql> SELECT * from sucursal; +----+----------------+---------------------+ | id | direccion | entidad_bancaria_id | +----+----------------+---------------------+ | 1 | C/ HierbaBuena | 1 | | 1 | C/ Naranja | 2 | | 2 | C/ Tomillo | 1 | | 2 | C/ Lim�n | 2 | | 3 | C/ Menta | 1 | +----+----------------+---------------------+

4. Modificar un registro en la tabla sucursal y ver el resultado:

Page 114: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

100

mysql> UPDATE `curso_ejemplo`.`sucursal` SET `direccion` = 'C/ Limonero' WHERE `sucursal`.`id` =2 AND `sucursal`.`entidad_bancaria_id` =2; Query OK, 1 row affected (0,00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * from sucursal; +----+----------------+---------------------+ | id | direccion | entidad_bancaria_id | +----+----------------+---------------------+ | 1 | C/ HierbaBuena | 1 | | 1 | C/ Naranja | 2 | | 2 | C/ Tomillo | 1 | | 2 | C/ Limonero | 2 | | 3 | C/ Menta | 1 | +----+----------------+---------------------+

5. Borrar un registro en la tabla sucursal y ver el resultado: mysql> DELETE FROM `curso_ejemplo`.`sucursal` WHERE `sucursal`.`id` = 3 AND `sucursal`.`entidad_bancaria_id` = 1; Query OK, 1 row affected (0,00 sec) mysql> SELECT * from sucursal; +----+----------------+---------------------+ | id | direccion | entidad_bancaria_id | +----+----------------+---------------------+ | 1 | C/ HierbaBuena | 1 | | 1 | C/ Naranja | 2 | | 2 | C/ Tomillo | 1 | | 2 | C/ Limonero | 2 | +----+----------------+---------------------+

6. Exportar la tabla cliente a fichero: mysql> SELECT * FROM `cliente` INTO OUTFILE "cliente.txt" FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n\r' ; Query OK, 3 rows affected (0,00 sec)

7. Seleccionar las sucursales, mostrando la razón social de la entidad bancaria propietaria, ordenado por entidad bancaria: mysql> SELECT b.razon_social AS name, a.id AS code, a.direccion AS address -> FROM sucursal AS a, entidad_bancaria AS b -> WHERE a.entidad_bancaria_id=b.id -> ORDER BY b.id; +-----------------+------+----------------+ | name | code | address | +-----------------+------+----------------+ | Caja de Ahorros | 1 | C/ HierbaBuena | | Caja de Ahorros | 2 | C/ Tomillo | | Banco Primero | 1 | C/ Naranja | | Banco Primero | 2 | C/ Limonero | +-----------------+------+----------------+

8. Seleccionar todos los préstamos existentes, informando el nombre y dni del prestatario: mysql> select b.nombre, b.dni, a.valor, a.fecha from prestamo as a, cliente as b, cliente_has_prestamo as c where c.prestamo_id = a.id and c.cliente_id = b.id; +------------+-----------+--------+------------+ | nombre | dni | valor | fecha | +------------+-----------+--------+------------+ | Juan Nadie | 123456789 | 150000 | 2010-05-18 | | Jos� L�pez | 987654321 | 8000 | 2010-06-15 | +------------+-----------+--------+------------+

Page 115: Php-Mysql

EJEMPLOS Y EJERCICIOS

101

9. Seleccionar las cuentas existentes, mostrando la calle de la sucursal donde está asociada, mediante el uso de JOIN: mysql> select cuenta.id, saldo, fecha_alta, direccion from cuenta left join sucursal on cuenta.sucursal_id = sucursal.id and cuenta.sucursal_entidad_bancaria_id = sucursal.entidad_bancaria_id; +----+--------+------------+----------------+ | id | saldo | fecha_alta | direccion | +----+--------+------------+----------------+ | 1 | 1345 | 2010-04-29 | C/ HierbaBuena | | 2 | 56789 | 2010-04-07 | C/ Tomillo | | 3 | 856.45 | 2010-04-11 | C/ Tomillo | | 4 | 1654 | 2010-04-30 | C/ Limonero | +----+--------+------------+----------------+

10. Mostrar, para todas las sucursales, las cuentas existentes: mysql> select cuenta.id, saldo, fecha_alta, direccion from cuenta right join sucursal on cuenta.sucursal_id = sucursal.id and cuenta.sucursal_entidad_bancaria_id = sucursal.entidad_bancaria_id; +------+--------+------------+----------------+ | id | saldo | fecha_alta | direccion | +------+--------+------------+----------------+ | 1 | 1345 | 2010-04-29 | C/ HierbaBuena | | NULL | NULL | NULL | C/ Naranja | | 2 | 56789 | 2010-04-07 | C/ Tomillo | | 3 | 856.45 | 2010-04-11 | C/ Tomillo | | 4 | 1654 | 2010-04-30 | C/ Limonero | +------+--------+------------+----------------+

10.2.6. Ejercicio 6 - Manejo de vistas

1. Creamos una nueva tabla en la base de datos, direccion, que contendrá las direcciones de los clientes: CREATE TABLE IF NOT EXISTS `direccion` ( `id` INT NOT NULL AUTO_INCREMENT , `calle` VARCHAR(45) NOT NULL , `poblacion` VARCHAR(45) NOT NULL , `c_postal` VARCHAR(45) NOT NULL , `cliente_id` INT NOT NULL , PRIMARY KEY (`id`) , INDEX `fk_direccion_cliente1` (`cliente_id` ASC) , CONSTRAINT `fk_direccion_cliente1` FOREIGN KEY (`cliente_id` ) REFERENCES `cliente` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

2. Poblamos la tabla: INSERT INTO `direccion` (`id`, `calle`, `poblacion`, `c_postal`, `cliente_id`) VALUES (1, 'C/ Puenteduero 23', 'Miciudad', '01010', 1), (2, 'C/ Tudela 45', 'Miciudad', '01010', 1), (3, 'C/ Zamora 3, 7º A', 'Miciudad', '01010', 2);

3. Definimos la vista: mysql> CREATE VIEW `datos_cliente` AS SELECT `cliente`.`nombre` AS `nombre`,`cliente`.`dni` AS `dni`,`cliente`.`telefono` AS `telefono`,`direccion`.`calle` AS `calle`,`direccion`.`poblacion`

Page 116: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

102

AS `poblacion`,`direccion`.`c_postal` AS `c_postal` FROM (`cliente` JOIN `direccion` on((`cliente`.`id` = `direccion`.`cliente_id`)));

4. Comprobamos su estructura: mysql> desc datos_cliente; +-----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+-------+ | nombre | varchar(100) | NO | | NULL | | | dni | varchar(10) | NO | | NULL | | | telefono | varchar(12) | YES | | NULL | | | calle | varchar(45) | NO | | NULL | | | poblacion | varchar(45) | NO | | NULL | | | c_postal | varchar(45) | NO | | NULL | | +-----------+--------------+------+-----+---------+-------+

5. Comprobamos el contenido: mysql> select * from datos_cliente; +------------+-----------+--------------+-------------------+----- | nombre | dni | telefono | calle | +------------+-----------+--------------+-------------------+----- | Juan Nadie | 123456789 | +34321654987 | C/ Puenteduero 23 | | Juan Nadie | 123456789 | +34321654987 | C/ Tudela 45 | | Jos� L�pez | 987654321 | +34789456123 | C/ Zamora 3, 7� A | +------------+-----------+--------------+------------------- ---------------+----------+ poblacion | c_postal | ----------+----------+ Miciudad | 01010 | Miciudad | 01010 | Miciudad | 01010 | -----------+----------+

10.2.7. Ejercicio 7 - Disparadores

1. Creamos una nueva tabla en la base de datos, direccion, que contendrá las direcciones de los clientes: CREATE TABLE IF NOT EXISTS `auditoria_cliente` ( `id` INT NOT NULL AUTO_INCREMENT , `dni` VARCHAR(10) NOT NULL , `nombre` VARCHAR(100) NOT NULL , `telefono` VARCHAR(12) NOT NULL , `timestamp` DATETIME NOT NULL , PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;

2. Asociamos un disparador, de manera que cada vez que se modifique un dato en la tabla cliente quede registrado el cambio: mysql> CREATE TRIGGER trigger_auditoria_cliente AFTER UPDATE ON cliente -> FOR EACH ROW -> INSERT INTO auditoria_cliente(dni, nombre, telefono, timestamp ) -> VALUES (OLD.dni, OLD.nombre, OLD.telefono, CURRENT_USER(), NOW() );

3. Comprobamos que el disparador funciona, para lo que modificamos un registro de la tabla y comprobamos que la tabla auditoria_cliente ha sido modificada: mysql> UPDATE cliente SET dni = '123456786', nombre = 'Juan Nadie Nada', telefono = '+34321654988' WHERE id = 1; Query OK, 1 row

Page 117: Php-Mysql

EJEMPLOS Y EJERCICIOS

103

affected (0,00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from auditoria_cliente; +----+------------+------------+--------------+----------+--------| id | dni | nombre | telefono | usuario | +----+------------+------------+--------------+----------+------------+------------+------------+---------------+---------+--------- | 1 | 123456789A | Juan Nadie | +34321654987 | apache@% | ----+------------+------------+---------------+---------+--------- --------------------+ timestamp | --------------------+ 2010-04-28 16:24:49 | --------------------+ 1 row in set (0,00 sec)

Page 118: Php-Mysql
Page 119: Php-Mysql

GESTION DE FICHEROS

105

Gestión de ficheros

Gracias a los ficheros, podremos almacenar información útil. Como configuraciones para nuestras aplicaciones, datos de nuestras aplicaciones (aunque a veces es mejor utilizar una base de datos para ello), logs de errores, etc…

11.1. Recepción y manejo de ficheros

PHP nos ofrece la posibilidad de gestionar ficheros de una forma sencilla. Disponemos de una amplia variedad de funciones para su manejo (disponibles en http://www.php.net/manual/es/ref.filesystem.php), pero nos centraremos en las más básicas.

La primera función que utilizaremos para usar un fichero, será fopen() que se usa para abrir dicho fichero. Dispone de varios tipos de modos de acceso al fichero (nota: llamaremos cursor a una posición desde donde se puede interactuar con el fichero, como si de un cursor de un fichero de Word cualquiera se tratase):

Modo de apertura Descripción r Modo de solo lectura. Se abre el fichero y el

cursor se coloca al principio del mismo, permitiendo leerlo hasta el final.

r+ Modo de lectura/escritura. Se abre el fichero y el cursor se coloca al principio del mismo, permitiendo leer o escribir en el fichero.

w Modo de sólo escritura. Se crea el fichero si no

Page 120: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

106

existiese, y, si existe, se borra todo su contenido, se sitúa el cursor al principio del fichero

permitiéndonos escribir. w+ Modo de escritura/lectura. Si el fichero no

existe, se crea, y, si existiese, se borra todo su contenido, se sitúa el cursor al principio del

fichero permitiéndonos escribir y leer. a Modo de añadido. Abre el fichero, sitúa el

cursor al final del mismo y permite escribir. Si el fichero no existe, lo crea, pero, en caso de

existir, no borra su contenido. a+ Modo de añadido/lectura. Sitúa el cursor al final

del fichero y permite escribir y leer. Si el fichero no existe, lo crea, ero, si existe, no borra su

contenido. x Creación y apertura para sólo escritura; coloca el

cursor al principio del archivo. Si el archivo ya existe, la llamada a fopen() fallará devolviendo FALSE y aparecerá un Warning en pantalla. Si

el archivo no existe se intenta crear. x+ Creación y apertura para lectura y escritura;

coloca el cursor al principio del archivo. Si el archivo ya existe, la llamada a fopen() fallará

devolviendo FALSE y aparecerá un Warning en pantalla. Si el archivo no existe se intenta crear.

Su sintaxis es la siguiente: <?php fopen("ruta_a_fichero.txt","modo"); ?>

Veamos un ejemplo abriendo un fichero que está en nuestra carpeta, y otro ejemplo en el que estamos accediendo a un fichero que se encuentra en una carpeta. <?php //En nuestra misma carpeta $fichero = fopen("mi_fichero.txt","r");//Así lo abriríamos en modo de solo lectura. //En otra carpeta $fichero = fopen("carpeta/mi_fichero.txt", "w"); //Así lo abriríamos en modo de sólo escritura ?>

Una cosa a tener en cuenta es el sistema operativo que estemos usando. Ya que si usamos un sistema bajo UNIX, las rutas se harán con una barra inclinada a la derecha /, en cambio para especificar los diferentes niveles entre carpetas en windows, necesitamos 2 barras inclinadas a la izquierda: \\ <?php //Accediendo a un fichero en una carpeta en un sistema UNIX $fichero = fopen("carpeta/mi_fichero.txt", "w"); //Así lo abriríamos en modo de sólo escritura //Accediendo a un fichero en una carpeta en un sistema Windows $fichero = fopen("carpeta\\mi_fichero.txt", "w"); //Así lo abriríamos en modo de sólo escritura ?>

Page 121: Php-Mysql

GESTION DE FICHEROS

107

Nota: fopen, a parte de servirnos para abrir ficheros locales, nos permite abrir URLs, tipo fopen("http://www.google.com"). Para que se sepa que es una url, habrá que poner el protocolo delante, es decir el http:// ya que no seria lo mismo fopen("http://www.google.com") que fopen("www.google.com"). En ese segundo caso, php intentaría abrir un fichero local llamado www.google.com

Al igual que “abrimos” un fichero, php nos da una función para cerrarlo. ¿Por que hay que cerrar los ficheros?, primero, para no tener variables en memoria con posibilidad de tener gran cantidad de datos. Y otra cosa importante, es que si queremos leer el fichero después de haber introducido datos mediante fputs por ejemplo (la función la veremos más adelante), primero hay que cerrar el archivo con fclose.

Este es su uso: <?php $fichero = fopen('archivo.txt', 'r'); fclose($fichero); ?>

11.1.1.1. Lectura de ficheros

Para leer una linea entera (siempre que el modo de apertura nos permita la lectura), podemos usar la función fgets().

Su sintaxis es: <?php fgets($manejador [, int $longitud ]) ?>

donde $manejador es el fichero que hayamos abierto con fopen, y donde $longitud es un numero entero en bytes que nos indica el tamaño máximo de la linea a leer. $longitud es un parámetro opcional. Hasta PHP 4.3.0, al omitirlo se asumía una longitud de línea de 1024. Si la mayoría de las lineas en el archivo son todas mayores de 8KB, es más eficiente para el script especificar la longitud máxima de línea.

Después de leer la línea, el cursor pasaría a la linea siguiente.

Veamos un ejemplo de fgets, donde además veremos una buena forma de recorrer un fichero hasta el final del mismo: <?php if($fh = fopen("fichero.txt","r")){ //Al colocarlo dentro de la condición if, sabremos si no ha habido ningún problema al abrir el fichero while (!feof($fh)){ //Atención a la función feof(), se usa para saber si se ha llegado al final de un fichero $F1[] = fgets($fh); } fclose($fh); } ?>

En este trozo de código, vamos almacenando el contenido de nuestro fichero en un array. Gracias a la función feof(), sabremos si el cursor está situado en el final del fichero.

Page 122: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

108

11.1.1.2. Escritura de ficheros

Para escribir dentro de un fichero, usaremos fputs o fwrite (son idénticas, aunque fputs es un poco más rápida que fwrite).

Su sintaxis es: <?php fwrite ( $manejador , $cadena_texto [, $longitud ] ); fputs ( $manejador , $cadena_texto [, $longitud ] ); ?>

Donde: $manejador es la variable con el contenido del fichero, abierto con fopen habitualmente, $cadena es el texto que va a ser escrito, y $longitud es un parámetro opcional, de tipo entero que determina la longitud en bytes de lo que se va a escribir. Si se da el argumento longitud, la escritura se detendrá después de hayan sido escritos tantos bytes como se indiquen o se alcance el final de $cadena, lo que suceda primero.

Veamos un ejemplo: <?php $fp = fopen('texto.txt', 'w'); fputs($fp, "1"); fputs($fp, "23"); fclose($fp); // el contenido de 'texto.txt' es 123 todo junto. $fp = fopen('texto2.txt', 'w'); fputs($fp, "1\n"); fputs($fp, "23"); fclose($fp); //en este caso el contenido de texto2.txt seria un 1 en una linea y un 23 en otra. ?>

11.1.1.3. Manejo de ficheros subidos desde un formulario con php

Lo primero es crear un formulario con un input tipo file. Ojo al tipo de codificación que tiene que tener el formulario para subir archivos, enctype=“multipart/form-data”. <form action="upload.php" method="post" enctype="multipart/form-data"> <input name="archivo" type="file" /> <input name="enviar" type="submit" value="Enviar" /> <input name="action" type="hidden" value="upload" /> </form>

Cuando se sube un fichero, se copia a una carpeta temporal, que si no es utilizado mientras funciona nuestro script, el contenido de dicha carpeta se borrará.

Para saber la ruta y otras propiedades del archivo, tenemos que recurrir a la variable superglobal $_FILES. Ten en cuenta que es un array asociativo donde el índice es el nombre del campo del formulario usado para el fichero:

• $_FILES['archivo']['size']: tamaño en bytes

• $_FILES['archivo']['type']: tipo mime del archivo, por ejemplo image/jpeg

Page 123: Php-Mysql

GESTION DE FICHEROS

109

• $_FILES['archivo']['name']: nombre original

• $_FILES['archivo']['tmp_name']: nombre del archivo temporal que se utiliza para almacenar en el servidor el archivo recibido

Imaginemos que tenemos una carpeta llamada “archivos_subidos” donde tenemos permisos de escritura. <?php if ($_POST["action"] == "upload") { // obtenemos los datos del archivo $tamano = $_FILES["archivo"]['size']; $tipo = $_FILES["archivo"]['type']; $archivo = $_FILES["archivo"]['name']; if ($archivo != "") { // guardamos el archivo en la carpeta archivos_subidos $destino = "archivos_subidos/".$archivo; if (copy($_FILES['archivo']['tmp_name'],$destino)) { echo = "Archivo subido: <b>".$archivo."</b>"; } else { echo "Error al subir el archivo"; } } else { echo = "Error al subir archivo"; } } ?>

Tenemos más funciones de manejo del sistema de ficheros en http://es2.php.net/manual/en/ref.filesystem.php

11.1.2. Actividad

11.1.2.1. Actividad 1

Crea un formulario que te permita subir una foto, y copiarla a un directorio de tu elección. Al mismo tiempo cuando se copie el fichero, crea un fichero de texto que se llame igual que la foto pero con extensión txt (pj: mifoto.jpg → mifoto.txt) En el que se almacene el nombre del fichero, y la fecha en la que se ha subido. Al terminar el proceso, deberá mostrar el contenido del fichero en la plantilla html

11.2. POO en PHP

La programación orientada a objetos es un paradigma de programación avanzado. PHP5 incorpora una nueva forma de POO respecto a versiones anteriores (PHP4 incorporaba objetos, pero lo hacía de una forma algo extraña a bajo nivel), la cuál contribuye a mejorar su rendimiento y aumentar sus posibilidades.

11.2.1. Definición de Clases, objetos, atributos y métodos

Page 124: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

110

• Una clase es la definición de un objeto, por decirlo de alguna forma, sería nuestro código. Se compone de atributos y métodos.

• Un atributo no es más que una variable perteneciente a la clase, y que se puede acceder desde cualquier método mediante una sintaxis específica como si de una variable global se tratara.

• Un método es una función perteneciente a una clase

• Un objeto es la instancia en tiempo de ejecución de dicha clase.

Veámoslo con un ejemplo más del día a día Imaginémos una persona. Con todas sus características físicas, su género, altura, peso, color de pelo, extremidades etc.

Persona, seria nuestra clase, donde su peso, su altura, pierna izquierda, pierna derecha etc… serían sus atributos, y acciones cotidianas como andar, correr, comer, serían los métodos de dicha clase donde se pueden usar los atributos. Por ejemplo para nuestro método correr, necesitaríamos usar los atributos pierna izquierda y pierna derecha.

Ahora imaginemos “Persona” (nuestra clase), si llevamos la definición Persona, a personas de verdad, por ejemplo Juan y María, estos serian los objetos. Es decir, nosotros tenemos una definición de persona, de la cual puede haber n instancias de la misma, con los mismos atributos (aunque con valores diferentes). En este caso, nuestro objeto “Juan” por ejemplo tendría su atributo “genero” con el valor “masculino”, y nuestro objeto “Maria” tendría su atributo “genero” como “femenino”.

Veamos un ejemplo en PHP de nuestra clase Persona: <?php class Persona{ public $genero; // | public $altura; // | --- >estos serían nuestros atributos como si de variables normales se trataran. public $peso; // | public function andar(){ // | } // | // | ---> así se declararían los métodos, como simples funciones. public function correr(){ // | } // | } ?>

Como has podido ver, se ha colocado la palabra “public” delante de nuestros atributos y nuestras funciones. Esto mostrará la visibilidad de nuestro atributo o de nuestro método. Hay 3 tipos:

• public el método o el atributo se puede acceder desde cualquier lado.

• private sólo se puede acceder al método o al atributo desde la misma clase pero no lo podrán ver las clases hijas (veremos que es una clase hija en el siguiente punto, la herencia).

• protected solo se puede acceder al método o al atributo desde la misma clase o desde clases hijas.

Las clases disponen de un método “constructor” que se ejecutará siempre que se cree el objeto. Este método se llama en php5 __construct() <?php class MiClase{

Page 125: Php-Mysql

GESTION DE FICHEROS

111

public __construct(){ //código que queremos que se ejecute al crearse nuestro objeto } } ?>

11.2.2. Manejo de objetos

Para crear un objeto a partir de una clase definida, usaremos la palabra reservada “new” seguido del nombre de nuestra clase: <?php $a = new MiClase(); //Esto creará una instancia de mi clase "MiClase", dentro de $a //Si quisiéramos usar los métodos o atributos de la clase se usará una flecha $a->mi_atributo; $a->mi_método(); ?>

Cuando estamos definiendo una clase si necesitamos hacer referencia al propio objeto, se usa la palabra $this. $this es una referencia al objeto que se está usando (usualmente el objeto al que el método pertenece, pero puede ser otro objeto, si un método es llamado estáticamente desde el contexto de un objeto secundario). Veamos un ejemplo: <?php class A { function foo() { if (isset($this)) { echo '$this esta definido ('; echo get_class($this); echo ")\n"; } else { echo "\$this no esta definido.\n"; } } } class B { function bar() { A::foo(); } } $a = new A(); $a->foo(); A::foo(); $b = new B(); $b->bar(); B::bar(); ?>

El resultado del ejemplo seria: $this esta definido (a) $this no esta definido.

Page 126: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

112

$this esta definido (b) $this no esta definido.

11.2.3. Actividades

11.2.3.1. Actividad 1

Crea un objeto que contenga 2 atributos numéricos, e implementa 5 funciones. suma, resta, multiplicación, división (decimal) y división entera, que muestren el resultado de la operación por pantalla.

11.2.3.2. Actividad 2

Modifica la clase anterior para que los atributos sean privados y solo se pueda acceder a ellos mediante los métodos setParam1() y setParam2().

Ahora las funciones suma, resta, multiplicación, división_decimal y división_entera, serán métodos privados. Sólo se podrá acceder a ellos a través de una función publica “operación()” que recibirá como único parámetro una cadena de texto que será el nombre de cada operación.

11.2.4. Uso de la Herencia

La herencia es uno de los mecanismos fundamentales de la programación orientada a objetos. Gracias a la herencia, podemos definir clases, a partir de la definición de otras clases. Las clases que hereden de otras, poseerán los mismos atributos y métodos que la clase “padre”, pero además podrá extender su funcionalidad añadiendo más atributos y métodos.

Por ejemplo, imaginemos la clase “mamíferos”. Todos los mamíferos tienen cosas en común, pero otras muy diferentes. Por ello se crearían clases que heredasen de “mamíferos” como podrían ser “perros”, “gatos”, o nuestra clase “persona”.

Ejemplo <?php class MiClasePadre{ public $var1; //Esta variable podrá ser usada desde cualquier sitio private $var2; //esta variable solo puede ser usada en esta clase protected $var3; //esta variable solo la podrán usar esta clase y sus clases hijas. public function funcion1(){ //Esta función podrá ser usada desde cualquier sitio } private function funcion2(){ //esta función solo puede ser usada en esta clase } protected function funcion3(){ //esta función solo la podrán usar esta clase y sus clases hijas. } } class MiClaseHija extends MiClasePadre{ public $otra_variable; public function otrafuncion(){

Page 127: Php-Mysql

GESTION DE FICHEROS

113

} } ?>

Al igual que vimos en el punto anterior que se puede decir la visibilidad de un método o un atributo, opcionalmente podremos usar las siguientes palabras clave delante de la palabra class y que tienen mucho que ver con la herencia:

• abstract: clase que no puede ser crear una instancia como objeto

• final: no podrá tener clases hijas

Las clases abstractas sirven para declarar una entidad, a la cual no se le puede implementar su código en parte o al completo todavía, ya que puede que su funcionalidad varíe dependiendo de quien herede.

Ejemplo de clase abstracta: <?php abstract class nombre_clase{ public $x; private $y; public function __construct(){ … } public abstract function nombre_método(); //no se define nada de código solo la declaración del método }

Como vemos, también se puede asignar la palabra abstract a un método, el cual no implementa código, es mas, ni siquiera lleva llaves para definirlo. Ese método habrá que implementarlo después en las clases hijas.

11.2.5. Actividades

11.2.5.1. Actividad 1

Crea una clase que herede la clase del ejercicio 2 del punto anterior. Haz las modificaciones necesarias en los atributos y métodos para que sean accesibles desde esta clase nueva, pero no desde fuera de ellas.

11.2.5.2. Actividad 2

En esta nueva clase añade el método concatenación. Que haga una concatenación de cadenas de texto con los 2 métodos de la clase padre. Redefine en la clase hija la función getParam1 y la función getParam2 y haz los cambios necesarios en la clase hija para que dependiendo del método devuelva un entero, un float, o una cadena. Pista: necesitaras redefinir el método operación y añadir un atributo nuevo. Para hacer una conversión de tipos utiliza las los operadores (int)(string)(float): ejemplo: $a = (int)$b;

11.2.6. Manejo de excepciones

Page 128: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

114

A partir de PHP5 se ha incluido el uso de excepciones como en otros lenguajes de programación. El manejo de excepciones es una estructura de control de los lenguajes de programación diseñada para manejar condiciones anormales que pueden ser tratadas por el mismo programa que se desarrolla.

Por ejemplo, un programa puede admitir cierto número de errores en el formato de los datos y continuar su proceso para producir el mejor resultado posible en lugar de producir una salida aparatosa llena de mensajes de error probablemente incomprensibles para el usuario. Muchas veces, la acción asociada a una excepción es simplemente producir un mensaje informativo y terminar; otras veces, es sólo indicación de la necesidad de un cambio en la estrategia de resolución del problema.

Una excepción puede ser lanzada thrown, y capturada (“catched”) dentro de PHP. El código debe estar delimitado dentro de un bloque try, para facilitar el capturar las excepciones potenciales. Cada bloque try debe tener al menos un bloque catch. Múltiples bloques catch pueden ser usados para capturar diferentes clases de excepciones. En la ejecución normal (cuando no hay excepciones dentro de un bloque try, o cuando el bloque catch correspondiente a la clase de la excepción lanzada no esta presente) continuará hasta el último bloque catch definido en la secuencia. Las excepciones pueden ser iniciadas o reiniciadas dentro de un bloque catch.

Cuando es lanzada una excepción, la siguiente línea de código no será ejecutada y PHP intentará encontrar el primer bloque de captura de excepciones catch. Si una excepción no es capturada se despliega un error fatal de PHP con un mensaje de que la excepción no fue capturada.

El objeto lanzado como excepción, deberá ser una instancia de la clase “Exception” o una clase heredada de la misma. Intentar lanzar (throw) un objeto que no lo sea, provocará que PHP lance un error fatal.

Veamos un ejemplo de uso: <?php function inverso($x) { if (!$x) { throw new Exception('Se ha intentado dividir por cero.'); echo "hola"; //esta linea nunca aparecerá ya que se ha lanzado la excepción. } else return 1/$x; } try { echo inverso(5) . "\n"; echo inverso(0) . "\n"; } catch (Exception $e) { echo 'Excepción capturada: ', $e->getMessage(), "\n"; } // Se continua con la ejecución. echo 'Hola mundo'; ?>

Al ejecutar este script este sería nuestro resultado: 0.2 Excepción capturada: Se ha intentado dividir por cero. Hola mundo

11.2.7. Actividades

Page 129: Php-Mysql

GESTION DE FICHEROS

115

11.2.7.1. Actividad 1

Modifica la clase hija del ejercicio anterior para que admita la posibilidad de concatenar arrays de datos. Añade un control de excepciones comprobando que los datos van a ser arrays.

11.2.7.2. Interfaces

Las interfaces son como una declaración de las funciones que deberán tener las clases que implementen una interfaz.

Es decir, si nosotros declaramos una interfaz, cuando una clase la implemente, nos aseguraremos de que esas clases tendrán dichas funciones.

Cuando se defina una interfaz, se declararán exclusivamente los métodos a implementar pero sin crear ningún tipo de código dentro, de eso se tienen que encargar las clases que la implementen.

Por ejemplo, imaginemos un globo típico que llevan los niños por la calle con helio, y un avión En principio no tienen nada en común, por lo que si hubiese que establecer una herencia sería prácticamente imposible, pero dichos objetos tienen la cualidad de que de una forma pueden ascender y descender en el aire.

Ahora por ejemplo creamos un interfaz volador: <?php interface volador{ public function ascender(); public function descender(); } ?>

Recuerda, en la interfaz no se codifican los métodos.

Ahora veamos como implementar en nuestra clase dichos métodos. <?php class globo implements volador{ public function ascender(){ echo "Parece que el bebé se ha quedado sin su juguete"; } public function descender(){ echo "Debe estar picado..."; } } ?>

Se podrían implementar varias interfaces en la misma clase, en cuyo caso se indicarían todos los nombres de las interfaces separadas por comas.

En el código de la clase estamos obligados a declarar y codificar todos los métodos de la interfaz.

Nota: en concreto, PHP 5 entiende que si una clase implementa una interfaz, los métodos de esa interfaz estarán siempre en la clase, aunque no se declaren. De modo que si no los declaramos explícitamente, PHP 5 lo hará por nosotros. Esos métodos de la interfaz serán abstractos, así que la clase tendrá que definirse como abstracta.

Ahora veamos el código de nuestro avión:

Page 130: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

116

<?php class avión implements volador{ private $piloto; private $gasolina; function __construct(){ $this->gasolina = 0; $this->piloto = false; } public function ascender(){ if (!$this->piloto){ echo "¿donde vas sin piloto? anda, busca uno"; } else if ($this->gasolina = 0) { echo "Deberías revisar la gasolina"; } else { echo "A volar!!..."; } } public function descender(){ if (!$this->piloto){ echo "¿Pero se puede saber como has arrancado esto sin piloto? ¡Estas loco! ¿Has visto Perdidos?... ya sabes lo que te espera"; } else { echo "Bajando..."; } } } ?>

Como se puede ver, ambas clases no tienen nada en común salvo los métodos, que además por dentro son completamente diferentes.

Gracias a las interfaces, podremos hacer llamadas polimórficas pasando como parámetros, los objetos que implementan una interfaz. <?php function sube (volador $objeto){ $objeto->ascender(); } $unglobo = new globo(); $unavion = new avión(); sube($unglobo); sube($unavion); //con esto haríamos que nuestro globo y nuestro avión ascendieran con la misma función. class ladrillo{ public $peso; } $ladrillo = new ladrillo(); sube($ladrillo); // Esto daría un Fatal Error en el que se nos indicaría que hay que implementar la interfaz volador ya que nuestra clase ladrillo no lo hace ?>

11.2.8. Diferencias entre clases abstractas e interfaces

Page 131: Php-Mysql

GESTION DE FICHEROS

117

Cuando hemos definido los interfaces, seguramente te hayan venido a la cabeza las clases abstractas, ya que parecen hacer lo mismo. Sí, y no :)

Veamos unas diferencias:

Característica Interfaz Clase abstracta Herencia Múltiple Una clase puede implementar

tantas interfaces requiera. Por lo general, una clase sólo

puede heredar una clase abstracta.

Implementación por defecto Una interfaz no puede proporcionar ningún código de

implementación, solo la cabecera de la función.

Una clase abstracta puede proporcionar la implementación de algunos métodos y dejar sin implementar exclusivamente

aquellos que varíen dependiendo de la clase hija

atributos Los interfaces carecen de atributos

Una clase abstracta puede tener atributos

11.2.8.1. Actividades

Crea una clase abstracta y una interfaz con métodos idénticos, y haz una implementacíon de cada una en dos objetos (uno en cada).

Page 132: Php-Mysql
Page 133: Php-Mysql

DESARROLLO MVC CON PHP

119

Desarrollo MVC con PHP

12.1. ¿Qué es MVC?

MVC corresponde al acrónimo de Model View Controller,o en castellano, modelo vista controlador. Es un paradigma de programación ampliamente utilizado en el desarrollo de aplicaciones web. Se encarga de separar las funcionalidades en 3 capas diferentes,como su nombre indica: modelo vista y controlador.

• El Modelo es la capa encargada de interactuar con la base de datos

• La vista es la capa que se encarga de tratar (unir la información recibida desde el controlador y el código HTML) lo que el usuario verá.

• El Controlador es la capa que se encarga de la lógica general de la aplicación,recoge las peticiones de la vista, llamará al modelo para recoger la información solicitada, y estos datos los devolverá de nuevo a la vista para que los muestre al usuario.

12.2. ¿Porqué utilizar el paradigma MVC?

Básicamente por el mantenimiento y reusabilidad de nuestro código. Si nuestro código fallara, sería mas fácil localizar errores al tener menos lineas de código. O si por ejemplo un cliente nos pide cambiar nuestro tipo de base de datos (por ejemplo de mysql a

Page 134: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

120

sqlserver) sólo tendríamos que cambiar el modelo y no tendríamos que re-escribir toda nuestra aplicación.

Veamos un ejemplo, de cómo seria una aplicación sencilla para mostrar edad y nombre de un grupo de personas sin el paradigma MVC: <? // abrimos conexión $cn = mysql_connect('localhost', 'usuario', 'clave'); mysql_select_db('nombre_bd', $cn); // cogemos el nombre y edad mediante una SQL $resultado=mysql_query('SELECT nombre, edad FROM personas', $cn); ?> <h1>Personas</h1> <table> <tr> <th>Nombre</th> <th>Edad</th> </tr> <?php // recorremos el array y mostramos los datos while ($fila = mysql_fetch_array($resultado, MYSQL_ASSOC)) { echo "<tr>"; echo "<td> ".$fila['nombre']." </td>"; echo "<td> ".$fila['edad']." </td>"; echo "</tr>"; } ?> </table> <?php //cerramos la conexión mysql_close($cn); ?>

Al estar todo en un solo fichero, si tuviésemos que cambiar el tipo de base de datos, habría que re-escribir prácticamente todo. Además si se trabaja con un diseñador web, mientras nosotros trabajamos en nuestro listado, él no podría trabajar en el diseño.

12.3. Empezando a separar nuestro código

El ejemplo anterior los separaremos en 3 archivos, controlador.php modelo.php y vista.php.

controlador.php require('modelo.php'); $personas = cogePersonas(); require('vista.php');

modelo.php <?php function cogePersonas() { $cn = mysql_connect('localhost', 'usuario', 'clave'); mysql_select_db('nombre_bd', $cn); $resultado = mysql_query('SELECT nombre, edad FROM personas', $cn); $personas = array();

Page 135: Php-Mysql

DESARROLLO MVC CON PHP

121

while($persona = mysql_fetch_assoc($resultado)) { $personas[] = $persona; } mysql_close(); } ?>

vista.php <h1>Personas</h1> <table> <tr> <th>Nombre</th> <th>Edad</th> </tr> <?php foreach($personas as $persona){ ?> <tr> <td><?php echo $persona['nombre'];?></td> <td><?php echo $persona['edad'];?></td> </tr> <?php } //fin del foreach ?> </table>

Con esta separación como vemos nuestro controlador seria solo un mero programa para pasar datos de modelo a vista. Aquí es donde si queremos podemos implementar lógica adicional para hacer más seguras nuestras aplicaciones (validaciones, control de usuarios… etc).

12.4. Abstrayéndonos del gestor de base de datos

En este ejemplo, hemos usado MySQL como nuestro gestor de base de datos. Si tuviésemos una aplicación muy compleja, y tuviésemos que cambiar nuestro gestor de base de datos, nos tocaría cambiar todas las funciones de acceso a mysql por las de acceso al gestor de base de datos nuevo… y eso es malo. Por ello podemos dividir aun más nuestro modelo (recuerda,¡divide y vencerás! :D).

acceso_mysql.php function conectar($servidor, $usuario, $clave) { return mysql_connect($servidor, $usuario, $clave); } function cerrarConexion($cn) { mysql_close($cn); } function consulta($consulta, $base_datos, $cn) { mysql_select_db($base_datos, $cn); return mysql_query($consulta, $cn); } function cogerResultado($resultado, $tipo = MYSQL_ASSOC) {

Page 136: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

122

return mysql_fetch_array($resultado, $tipo); }

modelo.php switch(GESTOR_BBDD){ //GESTOR_BBDD Es una constante que podríamos haber definido en un fichero de configuración de nuestra aplicación case "MYSQL": require_once("acceso_mysql.php"); break; case "SQLSERVER": require_once("acceso_sqlserver.php"); //un fichero similar al de mysql pero con las funciones de sqlserver break; case "ORACLE": require_once("acceso_oracle.php");//lo mismo aquí pero con oracle :) break; default: require_once("acceso_mysql.php"); break; } function cogePersonas() { $cn = conectar('localhost', 'usuario', 'clave'); $resultado=consulta('SELECT nombre, edad FROM personas', 'db', $cn); $personas = array(); while ($persona = cogerResultado($resultado)) { $personas[] = $persona; } cerrarConexion($cn); return $personas; }

Ahora por cada gestor de base de datos que queramos añadir, solo tenemos que añadir un fichero más con las funciones típicas de ese gestor, sin cambiar nuestro modelo.

12.5. Actividades

Vamos a usar el paradigma modelo vista y controlador, pero usando objetos.

Crea un fichero index.php y 3 objetos, control, modelo, y vista.

• En el fichero index php, se inicializara el objeto control.

• El objeto modelo, proveerá de funciones para acceder a un fichero de texto que tendrá un formato CSV (cada fila hace de registro, y los campos están separados por el símbolo ”;”) Los campos corresponderán a este orden: nombre, edad, dirección, teléfono

Jose;39;Gran via 39;91234567 Pedro;16;Calle Mayor 1;91234567 Maria;25;Calle Antonio Machin 23;91234567

• El objeto vista, tendrá una función para recibir los datos, y los formateara con sintaxis HTML.

• El objeto control tendrá como mínimo 2 atributos, que serán $modelo y $vista (en ellos hay que instanciar un modelo y una vista)

Page 137: Php-Mysql

DESARROLLO MVC CON PHP

123

o Se llamará al objeto modelo para obtener los datos del fichero CSV y se los pasara a la vista para que los muestre.

Page 138: Php-Mysql
Page 139: Php-Mysql

GESTOR DE PLANTILLAS: SMARTY

125

Gestor de plantillas: Smarty

Bueno, lo primero de todo, ¿que son las plantillas?. Son ficheros que contienen la estructura completa de un documento, a la cual se le pasarán valores de determinadas variables. Por poner un ejemplo de la vida real, podrían compararse a las quinielas. El papel es igual para todo el mundo, pero cada persona la rellena de forma diferente. Es decir, cada persona le pasara unos valores diferentes a la plantilla

En las plantillas de Smarty podemos crear la estructura completa de un documento HTML, y en el lugar donde debe desplegarse el valor de la variable, insertamos la expresión {$variable}.

Esto es lo mismo que escribir <?echo $variable;?>, pero como vemos, es más sencillo de entender y “ensucia” menos nuestra plantilla, que recordemos que muchas veces es un diseñador el que tiene que retocarla, y a menudo no saben de programación. Veamos como instalar Smarty.

13.1.1. Instalación

Para ejecutar Smarty es suficiente descargar el archivo correspondiente y descomprimirlo, o hacer un “sudo apt-get install smarty” si estamos en un sistema basado en debian, como ubuntu.

Si nos descargamos el fichero, tendremos que tener en cuenta que el código que necesitamos, la biblioteca en sí,se encuentra en el directorio /libs.

Page 140: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

126

Necesitaremos incluir en nuestra aplicacion el fichero Smarty.class.php con ayuda de la función require() (si lo hemos instalado a través de ubuntu, es posible que la ruta donde esté Smarty.class.php sea /usr/share/php/smarty/).

Veamos ahora qué necesitamos para usar Smarty en nuestra aplicación. Smarty requiere la creación de cuatro carpetas. Sus nombres por defecto son /templates, /templates_c, /configs y /cache (Si queremos cambiarlos, habria que cambiar las 4 variables que les corresponden dentro del fichero Smaty.class.php: $template_dir, $compile_dir, $config_dir y $cache_dir). Muy importante, al menos /templates_c y /cache necesitarán tener permiso de escritura para el servidor web.

Ya estamos listos para empezar a jugar con Smarty, pero antes, ya que smarty tiene mucho que ver con el diseño de nuestra aplicación, no nos vendrá mal dar un repaso rápido a la creación de un fichero CSS.

13.1.2. Bases de smarty

13.1.3. Modificadores, funciones, filtros, plugins, estructuras de control

13.1.3.1. Modificadores

Los modificadores funcionan como algunas funciones de tratamiento de cadenas de PHP. ¿Por que usar modificadores de Smarty en vez de las funciones de PHP?. Si usamos los modificadores, nosotros como programadores no tendremos que preocuparnos si le tenemos que pasar el texto en mayúsculas al diseñador, o en minúsculas, por que vaya a quedar más bonito. Es el diseñador el que automáticamente por medio de dichos modificadores, transformará el contenido como quiera. Además que la sintaxis de Smarty siempre será mucho más fácil de usar para el diseñador que la que se puede encontrar en PHP.

http://www.smarty.net/manual/es/language.modifiers.php

13.1.3.2. Funciones

Smarty nos ofrece un abanico de funciones que nos automatizan la creación de elementos HTML a través de arrays de datos. Pongamos un ejemplo para verlo más claro: Si escribimos en nuestra plantilla:

{html_radios name=“color” options=$colores separator=”<br />”}

donde $colores es un array con los siguientes datos:

$colores = array ("1" => "azul", "2" => "amarillo", "3" => "rojo", "4" => "negro");

cuanto smarty lo procese, nos dará el siguiente resultado en nuestro código HTML:

<input type=“radio” name=“magazine” value=“1” />azul<br /> <input type=“radio” name=“magazine” value=“2” />amarillo<br /> <input type=“radio” name=“magazine” value=“3” />rojo<br /> <input type=“radio” name=“magazine” value=“4” />negro<br />

Page 141: Php-Mysql

GESTOR DE PLANTILLAS: SMARTY

127

Y el diseñador sólo ha escrito una línea :D

13.1.3.3. Filtros

Los filtros funcionan de manera similar a los modificadores, ya que son capaces de alterar contenido. Pero en este caso, los filtros están mas orientados a limpiar nuestras plantillas determinados elementos, como por ejemplo comentarios en documentos HTML que no queremos que se lea, o incluso agregar contenido, como firmas, por ejemplo: “Esto lo he hecho con Smarty”.

http://www.smarty.net/manual/es/plugins.prefilters.postfilters.php

13.1.3.4. Plugins

Si las funciones, filtros, o modificadores que tenemos a nuestra disposición no nos sirven para la funcionalidad que necesitemos, Smarty nos permite crear nuestras propias funciones, filtros y modificadores.

13.1.3.5. Estructuras de control

También es posible la creación de instrucciones if o foreach, por ejemplo; con el objetivo de verificar si la variable que se da a la plantilla no está vacía, esto es:

{if $name != ””} ¡Bienvenido! {else} ¿Cómo te llamas? {/if} En el ejemplo citado se despliega el rótulo “¡Bienvenido!”, si la variable $name no está vacía, o “¿Cómo te llamas?” en el caso contrario.

También es posible utilizar bucles, en este caso el foreach, que nos permite recorrer arrays de datos: {foreach key=key item=item from=$mi_array} {$key}: {$item}<br /> {/foreach}

13.1.4. Como usar smarty

Para ver como usar Smarty, pongamos un ejemplo de una web de un grupo de música, Metallica por ejemplo. Imaginemos la discografía, en la que cada disco debería tener su página propia. Para no escribir una página por cada disco, utilizaremos el sistema de plantillas. Imagina que el fichero se llama album.tpl dentro del directorio /templates. <html> <head> <title>{$name}</title> </head> <body> <h1>{$name}</h1> <table> <tr> <td><img src="{$cover}" alt="" /></td> <td><h4>Canciones:</h4><br />{$songs}</td> </tr> </table>

Page 142: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

128

<h4>Descripción del álbum:</h4> <p>{$info}</p> <p><a href="">Página principal</a></p> </body> </html>

Y ahora creemos el fichero php que hará uso de esta plantilla. (Para hacer más comprensible este ejemplo, se escriben los datos tal cual, pero lo suyo es utilizar una base de datos, y usando por ejemplo, el paradigma MVC). <?php require ("Smarty.class.php"); $smarty = new Smarty; $smarty->assign("name", "Master of Puppets"); $smarty->assign("cover", "img/masterofpuppetscover.jpg"); $smarty->assign("songs", "«Battery»; «Master of Puppets»; «The Thing That Should Not Be»; «Welcome Home (Sanitarium)»; «Disposable Heroes»; «Leper Messiah»; «Orion»; «Damage, Inc.»"); $smarty->assign("info", "Master of Puppets es el tercer álbum del grupo de thrash metal Metallica. Fue lanzado al mercado el 3 de marzo de 1986, y fue el último álbum grabado junto al bajista Cliff Burton que moriría trágicamente en septiembre de ese mismo año en un accidente de autobús. Muchos consideran que es donde se refleja claramente la habilidad de su bajista Cliff Burton. Este disco alcanzó la posición número 29 de la lista del Billboard y fue uno de los primeros del thrash metal en serlo. La banda de metal progresivo Dream Theater lanzó un álbum de versiones de Master of Puppets en el año 2004 bajo el nombre "Dream Theater Oficial Bootleg: Master of Puppets" en el cual se encuentra la totalidad de las canciones del disco original producido por Metallica."); $smarty->display("album.tpl"); ?>

Como podemos observar, smarty hace uso de la función →assign() para mandar las variables a la vista y poder ser usadas más tarde como {$variable} y en el momento que se usa →display(“nombre_plantilla.tpl”) nos muestra el contenido de la plantilla.

A partir de aquí, Smarty “compila” la plantilla y empieza a sustituir las etiquetas smarty por código php. Por ejemplo {$var} será cambiado por: <?php echo $this->_tpl_vars['var']; ?>

Cuando se haya traducido todo el documento, automáticamente se copiara al directorio /templates_c, y cada vez que se llame a nuestro fichero php, el servidor cogerá el fichero ya traducido, por lo que no tendrá que hacer la “compilación” de nuevo. Si en algún momento nuestro la plantilla es modificada, smarty lo detectará automáticamente, y volverá a “compilarla”

Si se quiere usar comentarios dentro de la plantilla usaremos {* y *}: <p> código de mi plantilla </p> {* esto es un comentario que no se vera ni siquiera en el código html en nuestro navegador *} <p> código de mi plantilla </p> ...

Ahora imaginemos que necesitamos hacer uso de los caracteres ”{}” en nuestro documento HTML,por ejemplo si usamos javascript o css. Debemos utilizar {ldelim} para la llave izquierda y {rdelim} para la llave derecha. Lo mismo se refiere a colocar en el documento estilos o scripts, por ejemplo:

Page 143: Php-Mysql

GESTOR DE PLANTILLAS: SMARTY

129

<style> p {ldelim}color: #000000; font-size: 12px{rdelim} </style>

Es obvio que si hay que usar una gran cantidad de llaves… este sistema no es cómodo. Por ello Smarty nos deja las etiquetas {literal}{/literal} Y todo lo que haya entre medias, no lo interpretará.

{literal} <style> p {color: #000000; font-size: 12px} </style> {/literal}

De paso mencionaré que Smarty tiene su propio mecanismo de comentarios, que son eliminados durante la compilación. Los comentarios en la plantilla se inician con {* y terminan con *}.

Ya que estamos viendo la etiqueta style, peguemos un repaso rápido a los CSS

13.2. Generación de CSS

Las Hojas de Estilo (CSS: Cascading StyleSheets) son un sistema que permiten aplicar un diseño y un formato a los documentos HTML y todo esto separando el estilo visual del contenido del mismo ya que todos los estilos están en el fichero css.

Para incluir un fichero CSS en nuestro documento css hay que usar la etiqueta link dentro de nuestra etiqueta head: <html> <head> <title>titulo</title> <link rel="stylesheet" type="text/css" href="estilos.css" /> </head> <body> </body> </html>

También se puede utilizar la etiqueta style dentro del propio documento: <style> p {color: #000000; font-size: 12px} </style>

Pero es más recomendable utilizar la otra forma, incluyéndolo con link, ya que así separamos por completo estilo y contenido.

El formato básico de una clase CSS es: selector { atributo1: valor; atributo2: valor; ... atributo_n: valor; }

Los algunos selectores son los siguientes:

SELECTOR UNIVERSAL El asterisco “*” hace referencia a todos los elementos HTML del documento * { background-color: black; }

SELECTOR POR TIPO Los selectores por tipo hacen referencia a las etiquetas html en sí, por ejemplo para un párrafo, etiqueta <p> sería lo siguiente:

Page 144: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

130

p { background-color: white; }

SELECTOR POR CLASE El selector por clase, hace referencia a todos los elementos que tengan el atributo class=“mi_clase”. En el documento css la clase se hace referencia con un punto. Puede ir solo o acompañando a la etiqueta html. .mi_clase { background-color: yellow; }

Esto hará referencia a todos los elementos html que tengan el atributo class=“mi_clase”. p.mi_clase { background-color: yellow; }

Y esto hará referencia a todos los párrafos <p> que tengan el atributo class=“mi_clase”.

SELECTOR POR ID El atributo id, único dentro del documento HTML. Por lo tanto este estilo sólo se aplicará a un elemento. Se hace referencia con una almohadilla #. #mi_clase { background-color: yellow; }

SELECTORES DESCENDENTES Para hacer referencia a elementos que estén dentro de otros, se utiliza este tipo de selectores. Básicamente hay que definir el elemento padre y separado con un espacio el elemento al que queremos aplicarle el estilo. Por ejemplo, si nos encontramos esto: p strong { background-color: yellow; }

Esto significa que el estilo se aplicara al contenido de todas las etiquetas strong, que estén dentro de párrafos <p> <p> A este código no se le aplicaría el estilo <strong> a este si</strong> a este no </p> <strong> a este tampoco por que esta fuera de un párrafo </strong>

En cuanto a los atributos, hay una gran cantidad de ellos, podemos encontrar algunos interesantes aquí: http://www.desarrolloweb.com/articulos/186.php

Por último, señalar, que si añadimos más de una hoja de estilo, y algunos selectores hagan referencia al mismo elemento, sus atributos se sumarán, y si hay algún atributo repetido en las diferentes hojas de estilo, se aplicará la última que haya sido leída.

13.3. Creando layouts

Lo bueno de usar un sistema de plantillas es que podemos fragmentar nuestro layout en varios ficheros e irlos referenciando dentro del layout principal.

Imaginemos un index.tpl con la estructura principal. <html> <head>titulo</head> <link rel="stylesheet" type="text/css" href="estilos.css" /> <body> {include_template file="cabecera.tpl"} {include_template file="menu.tpl"} {include_template file="contenido.tpl"} {include_template file="pie.tpl"} </body> </html>

Después en vamos definiendo el resto de plantillas:

por ejemplo cabecera.tpl: <div class="slogan"> Eslogan de mi pagina web</div> <div class="logo"></div>

Page 145: Php-Mysql

GESTOR DE PLANTILLAS: SMARTY

131

Y así sucesivamente. Podemos añadir lógica a nuestros layouts. Por ejemplo dentro de la plantilla contenido.tpl, no se mostrará lo mismo si estamos en la página principal, que si estamos por ejemplo (retomando el ejemplo anterior de metallica) mostrando el álbum de nuestro grupo favorito.

contenido.tpl {if $tipo == "album"} {include_template file="album.tpl"} {else} {include_template file="otro_layout.tpl"} {/if}

13.4. Creando formularios

Cuando creamos formularios, un trabajo algo tedioso es crear el código html donde se pondrá de nuevo los datos si ha habido algún fallo al intentar insertar, o editar un elemento, o poner listados en elementos select. Smarty nos simplifica esto al no tener que poner código php en nuestra plantilla.

<form method=“post” action=“inscripcion.php”> Usuario <input type="text" name="Usuario" value="{$usuario}"><br> Nombre <input type="text" name="Nombre" value="{$nombre}"><br> Pais <select name="pais"> {html_options options=$paises} {* Esta función html_options equivaldría al siguiente foreach: {foreach key=key item=item from=$paises} <option value="{$key}">{$item}</option> {/foreach} *} </select> <input type="submit" value="Enviar">

</form>

Aquí (http://www.smarty.net/manual/es/language.custom.functions.php) podemos ver más funciones que nos pueden resultar muy útiles a la hora de generar formularios, ya que se pueden usar funciones para crear checkboxes, radiobuttons, etc…

13.4.1. Actividades

Vamos a seguir ampliando las funcionalidades de los 3 objetos que hemos creado anteriormente en el ejercicio del paradigma MVC

13.4.1.1. Actividad 1

Crea un layout para una web que contenga:

• Cabecera

o Menu

o logotipo

• Espacio para contenido

• Formulario para introducir Nombre, edad, dirección y teléfono.

Page 146: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

132

• Pie de pagina

Cuando se acceda a nuestra web, mostrará:

• Una cabecera que contendrá un menú (el menú de momento solo pondrá un enlace a nuestra página de inicio) y espacio para un logotipo o un slogan con el nombre de la aplicacion “gestión de contactos”

• En el contenido aparecerá el listado de personas con sus datos personales en una tabla html y un enlace que lleve a una página para introducir una nueva persona.

• En el pie de pagina estará tu nombre y la informaron básica sobre la web (lenguajes usados, año… etc)

13.4.1.2. Actividad 2

Modifica el objeto vista de nuestro ejercicio del paradigma MVC para implementar toda la lógica de smarty necesaria para que funcione nuestra web. Recuerda modificar el modelo para que permita añadir más personas al final del fichero.

13.5. Accesibilidad en Web

Según la Wikipedia “la accesibilidad web se refiere a la capacidad de acceso a la Web y a sus contenidos por todas las personas independientemente de la discapacidad (física, intelectual o técnica) que presenten o de las que se deriven del contexto de uso (tecnológicas o ambientales). Esta cualidad está íntimamente relacionada con la usabilidad”.

Cuando los sitios web están diseñados pensando en la accesibilidad, todos los usuarios pueden acceder en condiciones de igualdad a los contenidos. Por ejemplo, cuando un sitio tiene un código XHTML semánticamente correcto, se proporciona un texto equivalente alternativo a las imágenes y a los enlaces se les da un nombre significativo, esto permite a los usuarios ciegos utilizar lectores de pantalla o líneas Braille para acceder a los contenidos. Cuando los vídeos disponen de subtítulos, los usuarios con dificultades auditivas podrán entenderlos plenamente. Si los contenidos están escritos en un lenguaje sencillo e ilustrados con diagramas y animaciones, los usuarios con dislexia o problemas de aprendizaje están en mejores condiciones de entenderlos.

Si el tamaño del texto es lo suficientemente grande, los usuarios con problemas visuales puedan leerlo sin dificultad. De igual modo, el tamaño de los botones o las áreas activas adecuado puede facilitar su uso a los usuarios que no pueden controlar el ratón con precisión. Si se evitan las acciones que dependan de un dispositivo concreto (pulsar una tecla, hacer clic con el ratón) el usuario podrá escoger el dispositivo que más le convenga.

Las limitaciones en la accesibilidad de los sitios Web pueden ser:

• Visuales: En sus distintos grados, desde la baja visión a la ceguera total, además de problemas para distinguir colores (Daltonismo).

• Motrices: Dificultad o la imposibilidad de usar las manos, incluidos temblores, lentitud muscular, etc, debido a enfermedades como el Parkinson, distrofia muscular, parálisis cerebral, amputaciones…

• Auditivas: Sordera o deficiencias auditivas.

Page 147: Php-Mysql

GESTOR DE PLANTILLAS: SMARTY

133

• Cognitivas: Dificultades de aprendizaje (dislexia, discalculia, etc) o discapacidades cognitivas que afecten a la memoria, la atención, las habilidades lógicas, etc.

Estas pautas se pueden agrupar en 3 tipos.

• Pautas de Accesibilidad al Contenido en la Web (WCAG): Están dirigidas a los webmasters e indican cómo hacer que los contenidos del sitio Web sean accesibles.

• Pautas de Accesibilidad para Herramientas de Autor (ATAG) Están dirigidas a los desarrolladores del software que usan los webmasters, para que estos programas faciliten la creación de sitios accesibles.

• Pautas de Accesibilidad para Agentes de Usuario (UAAG) Están dirigidas a los desarrolladores de Agentes de usuario (navegadores y similares), para que estos programas faciliten a todos los usuarios el acceso a los sitios Web.

Normativa sobre accesibilidad en la ley española:

• Ley 51/2003 de 2 de diciembre de Igualdad de Oportunidades, No Discriminación y Accesibilidad Universal con discapacidad.

• Real Decreto 366/2003 de 16 de marzo, de accesibilidad y no discriminación de las personas con discapacidad en sus relaciones con la Administración General del Estado.

• Ley 27/2007, de 23 de octubre, por la que se reconocen las lenguas de signos españolas y se regulan los medios de apoyo a la comunicación oral de las personas sordas, con discapacidad auditiva y sordociegas.

• Real Decreto 1494/2007, de 12 de noviembre, por el que se aprueba el Reglamento sobre las condiciones básicas para el acceso de las personas con discapacidad a la sociedad de la información.

• Ley 49/2007, de 26 de diciembre, por la que se establece el régimen de infracciones y sanciones en materia de igualdad de oportunidades, no discriminación y accesibilidad universal de las personas con discapacidad.

Normativa UNE 139803:2004

Llamada “Aplicaciones informáticas para personas con discapacidad. Requisitos de accesibilidad para contenidos en la Web”, proporciona soluciones accesibles para los desarrolladores Web, creando un listado de recursos que permiten definir las características que han de cumplirse en materia de los contenidos Web en Internet, Intranets y en cualquier otro tipo de redes informáticas, para que éstos puedan ser utilizados por el mayor número de personas, incluyendo las personas con discapacidad y las personas de edad avanzada.

Hay una traducción muy interesante acerca de las pautas de accesibilidad de contenido en la web (WCAG) en esta URL: http://qweos.net/blog/2009/01/28/guias-practicas-para-profesionales-web-puntos-de-verificacion-de-las-pautas-de-accesibilidad-al-contenido-web-wcag-20/

Page 148: Php-Mysql
Page 149: Php-Mysql

CAPA DE ACCESO A DATOS CON ADODB

135

Capa de acceso a datos con AdoDB

Si recuerdas, dentro del punto de MVC, se hablaba de la abstracción de acceso a datos. Aparecía una estructura switch donde hacíamos un require de un fichero con el acceso a mysql, oracle, sqlserver dependiendo de la variable que se analizaba en el switch. AdoDB hace más o menos lo mismo. Nos ofrece un api con el cual podemos acceder a diferentes tipos de bases de datos utilizando las mismas funciones.

14.1. Conexiones a Bases de Datos

Recordemos como acceder a una base de datos MySQL con el api de PHP y como recorrer los datos que nos mande php . <?php $db = mysql_connect("localhost", "root", "password"); mysql_select_db("mydb",$db); $result = mysql_query("SELECT * FROM usuarios",$db); if ($result === false) die("failed"); while ($fields = mysql_fetch_row($result)) { for ($i=0, $max=sizeof($fields); $i < $max; $i++) { print $fields[$i].' '; } print "<br>n";

Page 150: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

136

} ?>

Y esta es la forma de hacerlo con AdoDB. <?php include("adodb.inc.php"); //incluimos nuestra libreria de adodb $db = NewADOConnection('mysql'); //creamos una conexión a base de datos almacenada en $db $db->Connect("localhost", "root", "password", "mydb"); //conectamos con nuestra base de datos llamada mydb $result = $db->Execute("SELECT * FROM usuarios"); //ejecutamos la SQL if ($result === false) die("failed"); //si el resultado,también llamado recordset, de la ejecución es false, cortamos la ejecución del script while (!$result->EOF) { //mientras que no se llegue al final de los registros for ($i=0, $max=$result->FieldCount(); $i < $max; $i++) //se recorre cada campo del registro print $result->fields[$i].' '; $result->MoveNext(); //OJO, siempre es necesario usar esta función para pasar al siguiente registro print "<br>n"; } $db->Close();//Cerramos la conexión. ?>

Veamos algunas funciones que se pueden usar con un recordset (el resultado de ejecutar una consulta):

$recordset→Move($pos) mueve el recordset a una fila en particular. ADODB soporta avance de filas en todas las bases de datos. Algunas bases de datos no soportan retroceso en el recordset. Puede de todas maneras simular este comportamiento usando un caché.

$recordset→RecordCount() retorna el total de filas obtenidas en el recordset. Algunas bases de datos no soportan esto y se devuelven un -1.

$recordset→GetArray() coloca el resultado del recordset en un array.

14.2. Generación de Consultas

Algo muy recomendable a la hora de hacer consultas a una BBDD, es tener una clase que genere consultas SQL de forma automatizada.

Por ejemplo una clase, que tenga como atributos la tabla que se esta usando, un prefijo de la tabla (por si queremos tener varias instalaciones de nuestra aplicación en una sola base de datos).

14.2.1. Actividad

Crea una clase que genere de forma automática consultas SQL. Ten en cuenta:

Page 151: Php-Mysql

CAPA DE ACCESO A DATOS CON ADODB

137

• Que se pueda usar un prefijo para la tabla

• Que contemple los casos de SELECT, INSERT, UPDATE y DELETE

• Dichos casos deberán tener funciones con los mismos nombres: →select →insert, →update, →delete

14.3. Acceso a los Metadatos

Veamos funciones que nos permiten acceder a los metadatos de una base de datos, de una tabla, o de campos. En principio estos son accesibles a través de $db, es decir, la conexión creada a la base de datos.

14.3.1. MetaDatabases()

Devuelve un array con la lista de bases de datos disponibles en el servidor. Solo disponible para ODBC, MySQL y ADO.

14.3.2. MetaTables($ttype = false, $showSchema = false, $mask=false)

Devuelve un array de las tablas y vistas de la base de datos actual. El array omitirá en lo posible las tablas del sistema. Para únicamente mostrar tablas use db→MetaTables('TABLES'). Para únicamente mostrar vistas use $db→MetaTables('VIEWS'). Actualmente el parámetro $showSchema solo funciona para DB2, y cuando es verdadero, agrega el nombre del esquema a la tabla, ej. “SCHEMA.TABLE”.

Se puede definir una mascara de coincidencia. Por ejemplo, con $mask = 'TMP%' solo encontrara las tablas que empiecen con 'TMP'. Por lo pronto solo mssql, oci8, odbc_mssql y postgres* manejan el parámetro $mask.

14.3.3. MetaColumns($table,$toupper=true)

Devuelve un array de objetos de la clase ADOFieldObject, un objeto por cada columna de la tabla $table. Cada instancia tiene definidos las propiedades (name, type, max_length). Actualmente Sybase no reconoce los tipos de fecha y ADO no puede identificar el tipo adecuado de datos (por lo que se identifican como 'varchar').

El parámetro $toupper determina si hay que convertir a mayúsculas el nombre de la tabla (requerido por algunas bases de datos).

Para el manejo de esquemas, en el parámetro $table mande el valor “$schema.$tablename”. Estos solo funciona en algunas bases de datos.

14.3.4. MetaColumnNames($table)

Devuelve un array con los nombres de las columnas de la tabla $table. Desde ADOdb 4.22, es un array asociativo con las claves en mayúsculas

Page 152: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

138

Es decir, array('FIELD1' 'Field1', 'FIELD2' 'Field2')

14.3.5. MetaPrimaryKeys($table, $owner=false)

Devuelve un array con el nombre de las columnas que forman la clave primaria de la tabla $table. Actualmente manejado por mysql, odbc (incluyendo db2, odbc_mssql, etc), mssql, postgre, interbase/firebird, oci8.

Las vistas (y algunas tablas) tienen clave primaria, pero algunas veces esta información no esta disponible para la base de datos. Tu puedes definir una función ADODB_View_PrimaryKeys($databaseType, $database, $view, $owner) que devuelva el array conteniendo los campos que forman la clave primaria. Si esta función existe sera invocada cuando MetaPrimaryKeys() no pueda encontrar la llave primaria para tabla o vista. <?php // En este ejemplo: dbtype = 'oci8', $db = 'mydb', $view = 'dataView', $owner = false function ADODB_View_PrimaryKeys($dbtype,$db,$view,$owner) { switch(strtoupper($view)) { case 'DATAVIEW': return array('DATAID'); default: return false; } } $db = NewADOConnection('oci8'); $db->Connect('localhost','root','','mydb'); $db->MetaPrimaryKeys('dataView'); ?>

14.3.6. ServerInfo($table)

Devuelve un array asociativo con dos elementos 'description' y 'version'. El elemento 'description' contiene una cadena con la descripción de la base de datos. El elemento 'version' contiene una cadena con el numero de version.

14.3.7. MetaForeignKeys($table, $owner=false, $upper=false)

Devuelve un array asociativo con las claves foráneas (foreign keys) de la tabla, o falso si no esta soportado. Por ejemplo, si la tabla 'empleados' tiene una clave foránea 'empleados.empl_dept' apunta a 'departamentos.dept_clav', y empleados.empl_puesto=organigrama.orga_puesto y empleados.empl_cat=organigrama.orga_cat, entonces $db→MetaForeignKeys('empleados') obtendrá como resultado: array( 'departamentos' => array('empl_dept=dept_clav'), 'organigrama' => array('empl_puesto=orga_puesto','empl_cat=orga_cat') )

Page 153: Php-Mysql

CAPA DE ACCESO A DATOS CON ADODB

139

Opcionalmente el dueño de la tabla o vista se puede definir en $owner. Si $upper es verdadero entonces el nombre de las tablas (que serán las claves del array asociativo) se convierten a mayúsculas

14.3.8. FetchField($column_number)

Ojo, a esta función se accede a través del recordset, no de la conexión.

Devuelve un objeto conteniendo name, type and max_length de el campo solicitado. Si max_length no se puede determinar con seguridad, tendrá el valor de -1. El numero de columna esta en base a cero (la primer columna es 0). Ver el ejemplo 2.

14.4. Ejecución de Consultas

Ya hemos visto cómo ejecutar una sentencia SELECT en ADODB.

Como ejecutar sentencias como INSERT, UPDATE con ADODB:

Desde la version 4.56 de ADOdb, se puede usar manejamos AutoExecute(), que simplifica las cosas proporcionando una función de nivel superior que encapsula las llamadas a GetInsertSQL() y GetUpdateSQL(). Por ejemplo, un INSERT puede hacerse así: <?php $record["firstname"] = "Bob"; $record["lastname"] = "Smith"; $record["created"] = time(); $insertSQL = $db->AutoExecute($rs, $record, 'INSERT'); //donde $rs es un recordset ?>

y un UPDATE así: <?php $record["firstname"] = "Caroline"; $record["lastname"] = "Smith"; # Actualiza el apellido de Caroline de Miranda a Smith $insertSQL = $db->AutoExecute($rs, $record, 'UPDATE', 'id = 1'); ?>

En versiones anteriores habría que generar la SQL mediante las funciones GetInsertSQL y GetUpdateSQL(). <?php include('adodb/adodb.inc.php'); $sql = "SELECT * FROM mi_tabla WHERE id = -1"; //Creamos una SQL para que seleccione una consulta en blanco de la tabla que queremos modificar $db = NewADOConnection("mysql"); //creamos la conexión $db->Connect("localhost", "root", "contraseña", "base_de_datos"); //Se conecta a la BD $rs = $db->Execute($sql); //Ejecutamos la SQL para obtener el recordset $record = array(); //iniciamos el array que mandaremos con los valores a hacer el insert //añadimos los valores $record["campo1"] = "valor1"; $record["campo2"] = "valor2";

Page 154: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

140

$record["campo3"] = "valor3"; $insertSQL = $db->GetInsertSQL($rs, $record);//Generamos la SQL mandando el recordset vacío, y los campos para hacer el insert. $db->Execute($insertSQL); //Insertamos /************************** * Ahora veremos el update **************************/ $sql = "SELECT * FROM mi_tabla WHERE id = 1"; //Hacemos una consulta en la que seleccionemos el registro a actualizar. $rs = $db->Execute($sql); //Y la obtenemos $record = array(); //iniciamos el array //colocamos los valores que queremos modificar $record["campo1"] = "otro valor1"; $record["campo2"] = "otro valor2"; $updateSQL = $db->GetUpdateSQL($rs, $record); //Generamos la SQL $db->Execute($updateSQL); //Ejecutamos $db->Close(); //Cerramos la conexión ?>

Para hacer un DELETE, solo tendremos que usar la SQL “DELETE FROM mi_tabla WHERE condición” y usar un $db→Execute();

14.4.1. Actividad

Vamos a seguir ampliando funcionalidades a nuestro gestor de contactos que llevamos haciendo desde nuestro ejercicio MVC. Coge el objeto de modelo, y modifícalo para que a partir de ahora, en vez de acceder a un fichero para coger los datos de las personas, se acceda a base de datos. Implementa también los métodos de edición y borrado.

Esto implicará también modificar el formulario para que admita la edición, el listado para incluir los enlaces de edición y borrado, y el controlador para que gestione todo.

Page 155: Php-Mysql

USO DE SERVICIOS DE INTERNET CON PHP

141

Uso de servicios de internet con PHP

Muchas veces nos pueden surgir situaciones en el desarrollo de una aplicación en las que no podamos acceder directamente a las bases de datos para poder intercambiar y gestionar información. Diferentes políticas de compartición de datos, así como distintos sistemas de gestión de bases de datos pueden poner trabas a la hora de manejar dichas informaciones.

Para ello se han desarrollado una serie de protocolos y estándares que sirven para intercambiar datos entre aplicaciones. Distintas aplicaciones de software desarrolladas en lenguajes de programación diferentes, y ejecutadas sobre cualquier plataforma, utilizados para intercambiar datos en redes de ordenadores como Internet.

Este tipo de protocolos y estándares de intercambio de información son los denominados: Web Services.

La interoperabilidad se consigue mediante la adopción de estándares abiertos. Las organizaciones OASIS y W3C son los comités responsables de la arquitectura y reglamentación de los servicios Web.

Ventajas de los servicios web:

• Aportan interoperabilidad entre aplicaciones de software independientemente de sus propiedades o de las plataformas sobre las que se instalen.

Page 156: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

142

• Los servicios Web fomentan los estándares y protocolos basados en texto, que hacen más fácil acceder a su contenido y entender su funcionamiento.

• Al apoyarse en HTTP, los servicios Web pueden aprovecharse de los sistemas de seguridad firewall sin necesidad de cambiar las reglas de filtrado.

• Permiten que servicios y software de diferentes compañías ubicadas en diferentes lugares geográficos puedan ser combinados fácilmente para proveer servicios integrados.

• Permiten la interoperabilidad entre plataformas de distintos fabricantes por medio de protocolos estándar y abiertos. Las especificaciones son gestionadas por una organización abierta, la W3C, por tanto no hay secretismos por intereses particulares de fabricantes concretos y se garantiza la plena interoperabilidad entre aplicaciones.

15.1. Distintos modelos de Servicios Web

Dentro de los protocolos y estándares abiertos y libres de la industria de los servicios web podemos destacar los siguientes:

• SOAP: http://es.wikipedia.org/wiki/Simple_Object_Access_Protocol

• REST: http://es.wikipedia.org/wiki/Representational_State_Transfer

• XML-RPC: http://es.wikipedia.org/wiki/XML-RPC

Estos tres sistemas de intercambio de información, son distintos entre sí, aunque cumplen con las condiciones enumeradas anteriormente. Las diferencias principales suelen ser a nivel de protocolo y a nivel de formatos de intercambio de información.

Así como el XML-RPC fue un precursor sencillo de intercambio de información, SOAP su sucesor está totalmente protocolizado y estructurado, y ha dado lugar a una serie de estándares complementarios a la hora de realizar esas transacciones de información. Ambos sistemas están basados en el intercambio de ficheros XML.

El caso de REST o RESTful el formato de intercambio de fichero puede llegar a variar y no está tan estructurado con en el caso de SOAP. Por lo que que es más abierto y flexible a la hora de realizar ese tipo de intercambios de información.

El conjunto de funcionalidades ofrecidas por un determinado servicio web, suele ser denominado API WEB.

15.2. Algunos API's WEB accesibles a través de Internet

Dichas API's son publicadas por los constructores de software para permitir acceso a características de bajo nivel o propietarias, detallando solamente la forma en que cada rutina debe ser llevada a cabo y la funcionalidad que brinda, sin otorgar información a cerca de como se lleva a cabo la tarea. Son utilizadas por los programadores para

Page 157: Php-Mysql

USO DE SERVICIOS DE INTERNET CON PHP

143

construir sus aplicaciones sin necesidad de volver a programar funciones ya hechas por otros, reutilizando código que se sabe que está probado y que funciona correctamente.

En la web, las API's son publicadas por sitios para brindar la posibilidad de realizar alguna acción o acceder a alguna característica o contenido que el sitio provee. Algunas de las más conocidas son las API's de:

• Google API's: http://www.google.com/apis/

• Flickr: http://www.flickr.com/services/api/

• Amazon: https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html

• Facebook: http://developers.facebook.com/docs/

• Twitter: http://apiwiki.twitter.com/

Por otra parte podemos, llegar a encontrar determinados estándares web que permiten funcionalidades de otro ámbito distinto.

Por ejemplo para temas de autenticación podemos usar:

• OpenID: http://es.wikipedia.org/wiki/OpenID

• Oauth: http://es.wikipedia.org/wiki/OAuth

15.3. Recursos

Algunos de estos API's suelen ser accesibles a través de bibliotecas de acceso a dichos protocolos y estándares de intercambio de información. Una de las tareas principales a la hora de permitir la integración de este tipo de servicios web en nuestras aplicaciones suele ser la localización de la información correspondiente a dicho API, así como la búsqueda de bibliotecas que faciliten la conexión o el intercambio de información. Cada protocolo y cada estándar suele tener una serie de bibliotecas de funciones asociadas.

15.4. Actividades

15.4.1. Actividad 1

Localiza una biblioteca que permita consultar servicios SOAP en PHP.

15.4.2. Actividad 2

Localiza una biblioteca que permita manejar una autenticación con Oauth en PHP.

15.4.3. Actividad 3

Localiza las bibliotecas de acceso a los API's de facebook para PHP.

Page 158: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

144

15.4.4. Actividad 4

Localiza la información correspondiente al API Open Social.Describe para qué funciona y que recursos tienes disponibles.

Page 159: Php-Mysql

FRAMEWORKS DE DESARROLLO EN PHP

145

Manejo de usuarios/seguridad

16.1. Autenticación y Autorización

Aunque sean 2 palabras parecidas, cuando se habla de autenticación y autorización, no hablamos de lo mismo. Por que dirían los componentes de la agrupación cómica Les Luthiers… parecido no es lo mismo caballero.

La autenticación (también llamada autentificación), es el proceso de intento de verificar la identidad digital del remitente de una comunicación como una petición para conectarse. Es decir, el típico proceso de introducir un usuario y una contraseña.

Podríamos dividir los métodos de autenticación en 3 categorías:

• Sistemas basados en algo conocido. Ejemplo, una contraseña (o password) o una frase de paso (passphrase).

• Sistemas basados en algo poseído. Ejemplo, una tarjeta de identidad, una tarjeta inteligente, dispositivo usb. (En esta categoría entrarían los DNI-electronicos)

• Sistemas basados en una característica física del usuario o un acto involuntario del mismo: Ejemplo, verificación de voz, de escritura, de huellas, de patrones oculares.

Habitualmente en nuestros sistemas web utilizaremos una contraseña. Para hacer más seguras nuestras aplicaciones, deberemos guardar de forma segura las contraseñas de

Page 160: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

146

nuestros usuarios para tratar de evitar que si otras personas las roban, no puedan hacer nada con ellas. Aquí es donde entran los métodos de encriptación. PHP nos ofrece algunas funciones para encriptar contraseñas con diferentes algoritmos, por ejemplo crypt, md5 o sha1.

La función md5

Esta función se encarga de aplicar el algoritmo hash md5, el primer parámetro es la cadena a encriptar, y el segundo recibe un valor booleano, si este es FALSE (por defecto) devolverá el valor hexadecimal, y si el parámetro es TRUE retornara el valor binario. <?php $md5_encripted = md5("contraseña"); //es lo mismo que $md5_encripted = md5("contraseña",false); ?>

La función crypt()

crypt a diferencia de md5 utiliza el segundo parámetro otra cadena adicional, que se usa como semilla para generar la cadena encriptada. Si no se le pasa una, php le dará una aleatoria. <?php $crypt_encripted = crypt("contraseña", "semilla"); ?>

La función sha1()

Esta función esta desplazando al la función md5, utiliza encriptacion de un solo sentido usando el algoritmo de hash seguro. (http://www.faqs.org/rfcs/rfc3174.html)

<?php $sha1_encripted = sha1("contraseña"); ?>

Evidentemente podemos usar varios métodos de encriptación a la vez. para hacerlo más seguro

<?php $sha1_md5_encripted = sha1(md5("contraseña")); ?>

O juntar diferentes cadenas que solo nosotros sepamos, o combinaciones con el usuario y la contraseña:

<?php $sha1_md5_encripted = sha1(crypt("contraseña"."usuario", "semilla))."holahola"); ?>

Cuando guardemos la contraseña de un usuario, lo que haremos será guardar la cadena encriptada, y la comparación será entre cadenas encriptadas:

<?php $password = md5($_POST['password']); $bd_user_pass = getUserPassword($user_id); //imaginemos que getUserPassword accede a nuestra bbdd con el id del usuario y recoge la cadena encriptada con md5 if ($password == $bd_user_pass) echo "acceso concedido"; ?>

Page 161: Php-Mysql

FRAMEWORKS DE DESARROLLO EN PHP

147

Evidentemente si hemos hecho alguna combinación de cadenas extrañas, cuando hagamos la comparación deberemos hacer exactamente el mismo proceso para poder comparar ambas cadenas.

La autorización por su parte, es el proceso de decirnos (tras estar autentificados) si se tiene acceso a un recurso. La autorización podríamos dividirla también en 3 niveles:

• Aplicación: el usuario tras identificarse tiene acceso la aplicación, por ejemplo: entrar en un foro.

• Funcionalidad: el usuario tras identificarse tiene acceso a una funcionalidad: por ejemplo entrar a la galería de fotos del foro.

• Objeto: el usuario tras identificarse y poder entrar en la funcionalidad de nuestra aplicación, puede acceder a determinado elemento: Por ejemplo, acceder a una foto en concreto de la galería de fotos, o a un post concreto en el foro.

Evidentemente, no siempre es necesario llegar a incluir una autorización de estos 3 niveles en nuestras aplicaciones. Si no que tendremos que evaluar nuestra aplicación y si vemos necesario implementarlo o no.

Una buena forma de establecer una autorización de forma genérica y no por usuario (lo que sería prácticamente imposible) es utilizando grupos, (o perfiles, o roles, aquí la terminología nos daría igual ya que cada uno podría llamarlo de la diferentes formas para referirse a lo mismo). La idea es agrupar una serie de funcionalidades o recursos disponibles en nuestra aplicación a un grupo. Por ejemplo, no es lo mismo la cantidad de recursos a los que puede acceder un administrador, que un usuario normal, o un usuario anónimo que no está autenticado en nuestro sistema.

A modo de información, hay un par de APIs que han surgido hace relativamente poco, y que están intentando unificar un sistema de Autenticación y de Autorización. Sus nombres son OpenID y OAuth.

OpenID es un standard de identificación digital descentralizado, con el que un usuario puede identificarse en una página web a través de una URL (o un XRI en la versión actual) y puede ser verificado por cualquier servidor que soporte el protocolo.

En los sitios que soporten OpenID, los usuarios no tienen que crearse una nueva cuenta de usuario para obtener acceso. En su lugar, solo necesitan disponer de un identificador creado en un servidor que verifique OpenID, llamado proveedor de identidad o IdP.

OAuth por su parte es un protocolo abierto, que permite autorización segura de un API de modo estándar y simple para aplicaciones de escritorio, móviles, y web.

Para desarrolladores de consumidores, OAuth es un método de interactuar con y publicar datos protegidos. Para desarrolladores de proveedores de servicio, OAuth proporciona a los usuarios un acceso a sus datos al mismo tiempo que protege las credenciales de su cuenta. En otras palabras, OAuth permite a un usuario del sitio A compartir su información en el sitio A (proveedor de servicio) con el sitio B (llamado consumidor) sin compartir toda su identidad.

16.1.1. Actividades

16.1.1.1. Actividad 1

Crea en php un sistema autenticación, usando las funciones de encriptación que tu desees.

Page 162: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

148

16.1.1.2. Actividad 2

Diseña un sistema de autorización que contemple los 3 tipos de niveles. De acceso a la aplicación, a la funcionalidad, y a nivel de objeto.

16.2. Manejo de Sesiones

A la hora de almacenar ciertos valores durante un tiempo y que podamos acceder a ellos de forma rápida sin la necesidad de tener que guardarlos en una base de datos, podemos usar las sesiones y las cookies. Centremonos primero en las sesiones.

Las sesiones, en aplicaciones web realizadas con PHP y en el desarrollo de páginas web en general, nos sirven para almacenar información que se memorizará durante toda la visita de un usuario a una página web. Dicho de otra forma, un usuario puede ver varias páginas durante su paso por un sitio web y con sesiones podemos almacenar variables que podremos acceder en cualquiera de esas páginas.

Con las sesiones guardaremos información única para cada usuario durante su visita. Es decir la sesión que abra un usuario en una aplicación será independiente de las que abran otros usuarios.

Estas sesiones, tendrán un identificador único, para identificar que sesión pertenece a cada usuario. Identificativo que para ser conservado habrá que guardarlo en una cookie o propagarla a través de la URL. Esto es configurable a través del fichero php.ini.

Veamos como usar sesiones.

session_start () Función necesaria siempre que usemos una sesión. Inicia una sesión o continúa una que pudiera estar abierta en otras páginas (de nuestra aplicación se entiende). Al usar session_start() PHP creará el identificador único, o si ya está creado, lo recibirá por URL o de una cookie.

Se puede configurar php.ini para que se inicialice la sesión sin hacer session_start() (directiva session.auto_start = 1)

Muy importante, si se quiere usar sesiones, hay que usar session_start antes de escribir cualquier texto en nuestra página, ya que si no lo hacemos seguramente nos salte un error ya que al iniciar sesión se deben leer las cookies del usuario, algo imposible de hacer cuando las cabeceras HTTP estan enviadas.

A partir de ahora podremos usar la variable global $_SESSION, que es un array asociativo. Recuerda que este curso es sobre PHP5, si usases una version anterior a PHP 4.1.0 habría que usar $HTTP_SESSION_VARS que no es de ámbito global, o registrar variables por separado con session_register(). Pero centrémonos en PHP5.

Cómo definir una variable de sesión: <?php session_start(); $_SESSION["variable"] = "Valor"; ?>

Si queremos leer la variable sería de la siguiente forma (recuerda que hay que usar session_start siempre al inicio): <?php session_start(); print $_SESSION["variable"]; ?>

Page 163: Php-Mysql

FRAMEWORKS DE DESARROLLO EN PHP

149

Para obtener el id de una sesión podremos usar la función session_id().

Mas funciones sobre sesiones en el manual de php: http://www.php.net/manual/en/ref.session.php

16.2.1. Actividades

16.2.1.1. Actividad 1

Partiendo del ejercicio de crear un sistema de autenticación en php, implementa sesiones para que el usuario permanezca logueado en tu sistema. Implementa también una función “logout” en la que se salga de la sesión.

16.2.1.2. Actividad 2

Extiende el ejercicio anterior creando un contador de visitas del usuario a la web. Ten en cuenta:

16.2.1.3. Actividad 3

Para recordar smarty, crea un formulario que esté dividido en 3 pantallas diferentes. Introducción de nombre y apellidos, introducción de dirección, e introducción de gustos musicales.

Se deberá pasar de una pantalla a otra manteniendo los datos en sesión. Cuando se haya introducido los datos en las 3 pantallas diferentes, se irá a una cuarta, donde se mostrarán los valores.

16.3. Manejo de Cookies

Cuando queremos guardar variables que perduren más allá de lo que pueda durar una sesión y no son datos críticos como contraseñas, podemos usar las cookies. Estas variables se conservan durante el tiempo que nosotros necesitemos.

Algunos usos de las cookies podrían ser llevar un contador de visitas que haya hecho el usuario a nuestra página, opciones de personalización como el tema visual que quiere usar nuestro usuario, o el identificativo de sesión.

Como crear cookies con php:

16.3.1.1. setcookie()

Es la función principal para el uso de cookies. Es una función que admite varios parámetros de los cuales sólo el primer parámetro es obligatorio.

Estos son los parámetros en orden:

Nombre:

Cadena de caracteres con el nombre que queremos darle a la cookie.

Page 164: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

150

Valor:

Cadena de caracteres con el valor.

Caducidad

Es un timestamp con el valor de la fecha en la que caducará la cookie. Lo habitual es usar es usar la función time(), que genera el timestamp, y después sumarle en segundos el tiempo que queramos que dure la cookie. Por ejemplo para que la cookie dure un año: time() + (60 * 60 * 24 * 365).

Ruta

La ruta donde la cookie se podrá utilizar dentro del dominio. Por defecto, la cookie se podrá utilizar en el directorio donde se ha creado y sus subdirectorios. Si indicamos ”/” la cookie tendrá validez dentro de todo el dominio.

Dominio

Es el subdominio donde se podrá acceder a la cookie. Las cookies sólo se pueden generar y utilizar para el dominio de la página donde está colocado el script, pero podemos hacerlo visible para todos los subdominios del dominio de la web por medio de ”.midominio.com”.

Seguro

Es un booleano que, si es true, indica que la cookie sólo puede ser transmitida por https (http seguro).

Sólo http

Esto es otro booleano que sirve para indicar que la cookie sólo puede ser accedida por medio de las cabeceras del http, lo que la haría inalcanzable para lenguajes de script en el cliente como Javascript. Este parámetro fue añadido en PHP 5.2.0

La function setcookie() de PHP genera y envía la cookie al navegador y devuelve un booleano, si es true indica que se pudo incluir en el navegador del usuario y si es false indica que no ha podido colocarla en el sistema. Ojo, que esto no indica que el usuario haya aceptado la cookie, ya que puede tener configurado el navegador para que no la acepte, y esto no lo puede detectar setcookie().

Veamos diferentes llamadas a setcookie(): <?php setcookie("cookie1", "valor"); setcookie("cookie2", "valor2", time() + 3600); setcookie("cookie3", "valor3", time() + 3600, "/", ".midominio.com"); ?>

Recordemos algo que comentábamos en la parte de sesiones. Para enviar una cookie, hay que hacerlo antes de escribir texto en la página, es decir, antes de mandar las cabeceras HTTP.

Para recuperar las cookies, podemos usar la variable super global $_COOKIE. $_COOKIE, es un array asociativo que tendrá las cookies que estén disponibles en la página PHP en el dominio y directorio donde esté. <?php $_COOKIE["migalleta"]; $_COOKIE["cookie2"]; ?>

Page 165: Php-Mysql

FRAMEWORKS DE DESARROLLO EN PHP

151

16.3.2. Actividades

16.3.2.1. Actividad 1

Extiende el ejercicio del sistema de login con sesiones y contador de visitas, incluyendo un sistema con cookies para que se mantenga la sesión incluso después de cerrar el navegador.

16.3.2.2. Actividad 2

Haz otra version del ejercicio 3 de sesiones del formulario con 4 vistas, sustituyendo las sesiones por cookies.

16.3.2.3. Actividad 3

Y de paso, vamos a seguir ampliando nuestro gestor de contactos :) Añade el sistema de login a la web que estamos haciendo, con un cuadro de login. No hace falta introducir el usuario y contraseña en una base de datos, puede hacerse la comprobación directamente en el objeto controlador.

Si no estamos logueados en el sistema, en vez de mostrarnos el listado de contactos, nos mostrará un formulario de login, y no nos dejará acceder a crear ni editar contactos.

Page 166: Php-Mysql
Page 167: Php-Mysql

CONSTRUIR APLICACIONES PHP SEGURAS

153

Construir aplicaciones PHP seguras

Tras haber visto los puntos de Autorización y Autenticación, seguiremos aportando más seguridad a nuestras aplicaciones mediante la generación de un Captcha y mirando una libreria de IDS (Intrusion Detection System).

17.1. Tratamiento de imágenes de manera dinámica

17.1.1. Generación de captcha para formularios

Un captcha es una imagen que crearemos en la que se incluye código alfanumérico que el usuario deberá introducir para validar que es quien nos está mandando la información en el formulario, es una persona real, y no un bot.

Para generar esta imagen utilizaremos la biblioteca GD.

La primero es crear una imagen con un texto aleatorio, para ello creamos un archivo llamado captcha.php el cual creará dinámicamente el texto y la imagen. <?php session_start(); function randomText($length) { $pattern = "1234567890abcdefghijklmnopqrstuvwxyz";

Page 168: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

154

for($i=0;$i<$length;$i++) { $key .= $pattern{rand(0,35)}; } return $key; } $_SESSION['captcha'] = randomText(8); // Creamos una imagen y despues añadimos el texto $im = imagecreatetruecolor(120, 20); $text_color = imagecolorallocate($im, 255, 255, 255); imagestring($im, 5, 20, 1, $_SESSION['captcha'], $text_color); // Mandamos la cabecera con el tipo de contenido, en este caso image/jpeg header('Content-type: image/jpeg'); // Mostramos la imagen imagejpeg($im); // Liberamos memoria imagedestroy($im); ?>

Crear el formulario y el código php para verificar el Captcha, por ejemplo en nuestro fichero index.php. Recuerda poner el fichero captcha.php en el mismo directorio que el index. <?php session_start(); if ($_POST['action'] == "checkdata") { if ($_SESSION['captcha'] == $_POST['captcha']) { echo "Bienvenido"; } else { echo "Inténtalo de nuevo"; } exit; } ?> Ingresar el texto mostrado en la imagen <br> <form action="index.php" method="post"> <img src="captcha.php" width="100" height="20"><br> <input name="captcha" type="text"><br> <input name="btsubmit" type="submit" value="Verificar Codigo"> <input name="action" type="hidden" value="checkdata"> </form>

Ahora que ya sabemos como podemos hacer un captcha a mano, es hora de conocer otra forma. Con la el servicio reCAPTCHA. Un servicio gratuito, que ofrece un api con el que poder generar captchas para nuestras aplicaciones. Nos pide que nos demos de alta, para que nos den unas claves con las que nos identificarán a la hora de pedir el captcha. Códigos como los de cualquier servicio online, tipo googlemaps, facebook, etc… 1. Descarga la libreria reCAPTCHA Library (http://recaptcha.net), descomprímela y copia recaptchalib.php al directorio donde este tu formulario. 2. Date de alta para conseguir una clave. 3. Ahora estamos listos para empezar a modificar nuestro código. Lo primero añadimos el código para mostrar el CAPTCHA: <?php require_once('recaptchalib.php'); $publickey = "..."; // Esta es una de las claves que se consigue al darte de alta. echo recaptcha_get_html($publickey); ?>

Page 169: Php-Mysql

CONSTRUIR APLICACIONES PHP SEGURAS

155

4. En el código que procesa el formulario para validar, habría que añadir el siguiente código: <?php require_once('recaptchalib.php'); $privatekey = "..."; //esta es otra clave que se consigue al darse de alta $resp = recaptcha_check_answer ($privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); if (!$resp->is_valid) { die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." . "(reCAPTCHA said: " . $resp->error . ")"); }

17.1.2. Retoque de imágenes

Ya que estamos viendo una pequeña pasada por encima de la biblioteca GD, vamos a ver como hacer un thubmnail (una imagen reducida), para por ejemplo crear las miniaturas de una galeria. <?php function createThumbnail($imageDirectory, $imageName, $thumbDirectory, $thumbWidth) { $srcImg = imagecreatefromjpeg("$imageDirectory/$imageName"); //esta función crea una imagen en memoria a partir de un fichero $origWidth = imagesx($srcImg); //nos da la anchura de la foto $origHeight = imagesy($srcImg); //nos da la altura de la foto $ratio = $origWidth / $thumbWidth; //calculamos el ratio a partir de la anchura para poder crear la imagen al tamaño adecuado. $thumbHeight = $origHeight * $ratio; //aplicamos la reduccion $tumbilla = imagecreate($thumbWidth, $thumbHeight); //creamos una imagen en memoria imagecopyresized($thumbImg, $srcImg, 0, 0, 0, 0, $thumbWidth, $thumbHeight, imagesx($thumbImg), imagesy($thumbImg)); //y finalmente hacemos una reducción de nuestra imagen original, a nuestra thumbnail, ojo seguimos trabajando en memoria. imagejpeg($thumbImg, "$thumbDirectory/$imageName"); //y escribimos en disco. } createThumbnail("directorioconimagenes", "fichero.jpg", "directorioparaminiaturas", 100); ?>

Para ver más funciones sobre el api de imágenes de GD, revisa este enlace: http://php.net/manual/en/ref.image.php

17.1.3. Actividades

Page 170: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

156

17.1.3.1. Actividad 1

Crea un formulario en el que te permita subir una fotografía (puedes reutilizar el usado en el temario de ficheros), y que además te permita introducir un pequeño texto. Se hará un thumbnail de la fotografía, y además se le añadirá como marca de agua (tanto a la fotografía como al thumbnail) el texto del formulario. La fotografía se tendrá que copiar al directorio /photo, y la thumbnail al directorio /thumbs. Cuando se haya completado todo el proceso, muestra una pequeña vista con las 2 fotografías.

17.1.3.2. Actividad 2

Crea un captcha, y añádelo a nuestra aplicación de gestor de contactos, para que pida un captcha en el login, y en el añadido y edición de contactos.

17.2. Bibliotecas de seguridad: IDS

Para hacer aún mas seguras nuestras aplicaciones, en las comprobaciones básicas que solemos hacer en formularios (numero de caracteres introducidos, que sean numéricos… etc), a veces no está de más hacer algunas comprobaciones para evitar que nos inyecten código malicioso que podría hacer ejecutar consultas SQL entre otras cosas.

Algunos tipos de ataques pueden ser:

• Register_Globals

• Reporte de error

• Cross-Site Scripting (XSS)

• Inclusión de archivo remoto (RFI)

• SQL Injection

Por ello, han aparecido algunas bibliotecas de seguridad como PHP-IDS http://php-ids.org (PHP- Intrussion Detection System), que lo que hacen es hacer una comprobación del contenido que se está pasando y nos devuelve una valoración en forma de número, que nos dice el riesgo que podemos correr al tratar dicho contenido.

Veamos como probar IDS:

• Lo primero descarga la ultima versión desde http://php-ids.org

• Descomprime el fichero. Sólo necesitaremos el contenido de libs. Por ejemplo si vamos a usar el directorio /var/www/ descomprime el contenido del directorio libs ahí Debería quedar una ruta como /var/www/IDS/

• Ve al fichero /var/www/IDS/Config/Config.ini.php y haz una copia en ese mismo directorio que se llame Config.ini

• Edítalo y configura la ruta correcta hasta IDS del parámetro base_path (si estas usando la ruta /var/www/, el valor debería ser /var/www/IDS/)

Ahora crearemos un fichero index.php (o como quieras llamarlo)

Page 171: Php-Mysql

CONSTRUIR APLICACIONES PHP SEGURAS

157

<?php require_once ('IDS/Init.php'); $request = array( 'REQUEST' => $_REQUEST, 'GET' => $_GET, 'POST' => $_POST, 'COOKIE' => $_COOKIE ); $init = IDS_Init::init('IDS/Config/Config.ini'); $ids = new IDS_Monitor($request, $init); $result = $ids->run(); if (!$result->isEmpty()) { // Si hay riesgo, echaremos un vistazo al objeto de resultado echo $result; } ?> <html> <head></head> <body> <form action="index.php" method="post"> <textarea name="texto"></textarea> <input type="submit" value="enviar"> </form> </body> </html>

Y ahora es hora de probar que funciona. Escribe cualquier texto que se te ocurra y dale a enviar. Si no has escrito nada que ids considere peligroso, parecerá que no ocurre nada. Pero ahora escribe lo siguiente (con comillas incluidas)

"192.168.0.200",2008-06-04T17:36:08+02:00,54

Si lo ejecutamos veremos que de repente ha salido un pequeño informe, indicando que el código que hemos metido tiene un riesgo catalogado con un 12. Date cuenta que está cogiendo la el valor del textarea “texto” desde $_POST y desde $_REQUEST. Por tanto sumaría 6 y 6 desde cada uno. Además nos indica que tipo de riesgo estamos sufriendo, en este caso sería un posible caso de SQL injection.

Al utilizar PHP-IDS a parte de comprobar lo que vaya por POST, como ves también revisará lo que vaya por GET (en la url) o incluso via COOKIE, ya que el cracker podría intentar escribir dichos valores en las cookies de nuestro sistema.

Page 172: Php-Mysql
Page 173: Php-Mysql

OPTIMIAZACION EN PHP

159

Optimización en PHP

Uno de los procesos principales a la hora de gestionar un proyecto hecho en PHP es la mejora del rendimiento de la aplicación web. Bien porque tenemos una misma aplicación que debe de servir muchas peticiones en poco tiempo, o bien porque tenemos varias aplicaciones instaladas en el mismo servidor y todas ellas deben poder ejecutarse a la vez. El último caso es el más típico, porque la mayor parte de los hosting suelen ser compartidos entre clientes, si nuestra aplicación es lo suficientemente ligera, nos permitirá que nuestra “parte” del servidor vaya mucho más ágil y así poder dar un mejor servicio.

La siguientes mejoras propuestas deben considerarse complementarias a todos aquellos principios que rigen la Ingeniería del Software (modularidad, abstracción, etc…) y de la Algoritmia (optimización del algoritmos de programación).

18.1. Procesos a Optimizar

Los procesos que se ven afectados en la resolución de una consulta a una aplicación PHP son aquellos de los que nos vamos a preocupar en resolver en esta parte del temario.

Principalmente podemos destacar los siguientes:

• Parámetros por defecto de PHP: dependiendo de las configuraciones que se vayan dejando en el php.ini, pueden ser más o menos óptimas para poder servir páginas php más rápidas

Page 174: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

160

o Solución: Cambiar las configuraciones sobre PHP:

Las variables de PHP que se deben usar:

variables_order = ‘GPC’

register_argc_argv = ‘Off’

register_globals = ‘Off’ (también útil para temas de seguridad)

always_populate_raw_post_data = ‘Off’

magic_quotes_gpc = ‘Off’

A parte de desactivar los logs de errores, consumen tiempo y recursos y a parte si tienes un error no muestras información que quizás no quieras.

• Compilación de Objetos: cada vez que llamas a una página se llama al compilador y se vuelve a procesar, aunque no haya cambiado.

o Solución: Si se cachean los objetos de PHP (parecido a lo que ocurre con JSP), la primera vez se compilaría y la siguiente se usaría la compilada. Existen varias herramientas que nos permiten realizar este cacheado de objetos:

Alternative PHP Cache (APC): Se trata de una extensión PECL que cachea el byte-code en memoria compartida. En la versión PHP6 sera incluido en el core por defecto. http://pecl.php.net/package/APC

eAccelerator: Es un proyecto derivado de del ya discontinuado Turck MMCache. Permite almacenar el byte-code tanto en memoria compartida como en disco. http://eaccelerator.net/

XCache: Al igual que APC, almacena el byte-code en memoria compartida. Este tiene muy buena fama ya que ha sido creado por uno de los desarrolladores de LigHTTPd. http://xcache.lighttpd.net/

Turck MMCache for PHP: uno de los primeros aceleradores, ya descontinuado, pero se ha dejado en el listado, para saber cual fue uno de los precursores. http://turck-mmcache.sourceforge.net/index_old.html

• Consultas a la BBDD: Uno de los mayores problemas a la hora de escalar correctamente una aplicación PHP, son las consultas a la BBDD. Ya que suelen consumir tiempo (es posible que demasiado), sobre todo cuanto más crecen los datos que debemos manejar.

o Solución 1: Implantar sistemas distribuidos de caché de objetos: se trata de tener la mayoría de la BD en memoria, usando para ello memcached (http://memcached.org/). Claro, que esto realmente puede ser poco útil en sitios que no tengan un elevado número de visitas.

o Solución 2: Realizar un estudio personalizado de las consultas que más nos consumen recursos dentro de la aplicación. Optimizarlas para mejorar su rendimiento a nivel de Servidor de BBDD.

Page 175: Php-Mysql

OPTIMIAZACION EN PHP

161

o Solución 3: Colocar el servidor de BBDD en otra máquina para así, no cargar la misma máquina con ambos procesos (PHP y BBDD).

• Generación de HTML, CSS, JS: En toda aplicación existe una parte correspondiente a la “vista” que normalmente suele ser estática. Además, dentro del código PHP se produce el proceso de generación del código HTML, CSS y JS de nuestra aplicación. A veces, simplemente para incluirlo, a veces para “calcularlo”.

o Solución: Si se separa convenientemente el código dinámico del estático se puede mejorar bastante el rendimiento de nuestra aplicación. Porque suelen existir datos estáticos que se muestran más de una vez y no se quiere que se recargue. Los sistemas de caché también proveen una separación entre código y HTML, que no solo mejorará el rendimiento, sino que además hará más sencilla una futura actualización. La mayoría de los sistemas de plantillas suelen incluir dichos cacheados de plantillas que permiten que esta generación sea muy ágil por parte del servidor.Los principales sistemas de plantillas son:

Smarty Templates: http://www.smarty.net/

DWOO: http://dwoo.org/

Pear Templates: http://pear.php.net/package/HTML_Template_IT/redirected

y PHP savant: http://phpsavant.com/

• Código generado: una vez generado todo el código hay que mandarlo al cliente, este código puede ser muy pesado a nivel de datos.

o Solución: Comprimir la salida: mediante PHP, comprimimos la salida usando el formato zip.

18.2. Buenas prácticas de codificación

Una de las cuestiones principales a la hora de ponerse a codificar es principalmente la manera de programar. Establecer unas determinadas maneras ayuda a crear una serie de criterios de calidad en el uso del lenguaje. Para ello será necesario adaptarse o crear dichas “reglas del juego” una vez se llegue a un nuevo equipo de trabajo en la empresa.

Dichas buenas prácticas deberían incluir algunos de las siguientes cuestiones:

• Estructuras básicas de carpetas: mediante este sistema una persona puede fácilmente ubicar un fichero en base a su función específica.

• Nomenclaturas: será necesario establecer una serie de normas a la hora de nombrar cada uno de los ficheros y cada tipo de contenido dentro de un fichero, a destacar:

o de ficheros

o de comentarios

o de variables

o de estructuras de control

Page 176: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

162

o de funciones

o de clases

• Uso de Sistemas de Control de Versiones: se debe establecer una política de cómo usar el repositorio de versiones con los proyectos.

• Lenguaje de modelado de datos: una vez tomados los requisitos del proyecto esta bien definir un documento estándar de modelado de datos.

• Informes Varios: debido a la gran cantidad de informes que se deben recoger en un determinado proyecto, está bien poder establecer una plantilla mínima por cada tipo de informe.

18.3. Actividades

18.3.1. Actividad 1

Busca comparativas de Aceleradores de PHP y haz un informe de los mismos.

18.3.2. Actividad 2

Dwoo es un sistema de plantillas similar a Smarty. Busca parecidos y diferencias en el uso de estas dos bibliotecas de plantillas.

18.3.3. Actividad 3

Dinámica de grupo: Discutir en un foro el listado de elementos a estandarizar en el código php. Llegar a una serie de conclusiones y ponerlas por escrito.

18.3.4. Actividad 4

Dinámica de grupo: Elegir un sistema de control de versiones, valorando los pros y los contra del mismo.

Page 177: Php-Mysql

FRAMEWORKS DE DESARROLLO EN PHP

163

Frameworks de desarrollo en PHP

La palabra Framework viene a definirse, como un conjunto de herramientas y bibliotecas que facilitan el desarrollo de aplicaciones sobre una determinada tecnología.

En el caso de PHP existen varios Frameworks de desarrollo que permiten agilizar el desarrollo de aplicaciones web. Entre ellos podemos destacar los siguientes:

• Zend Framework: http://framework.zend.com/

• Symfony: http://www.symfony-project.org/

• CakePHP: http://cakephp.org/

• CodeIgniter: http://codeigniter.com/

Todos ellos tienen sus pros y sus contras, a través de la red, se pueden conseguir comparativas entre ellos (por ejemplo http://www.dinamiclearning.es/desarrollo-web/frameworks-php) que permiten comparar aquellas funcionalidades principales, tales como:

• Arquitectura MVC (Modelo, Vista, Controlador)

• Orientado a Objetos en PHP5

• ActiveRecord (ORM Mapeo Objeto Relacional)

Page 178: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

164

• TemplateView (Vistas y algo de Plantillas)

• Generadores de Formularios (Ahorran trabajo y permiten el uso sencillo de grillas)

• Utilización de Scriptaculous (Prototype) para AJAX y Efectos Visuales

• Generación de Reportes PDF

• Ficheros de configuración

• Soporte de sistemas de autenticación y autorización (oauth, openid, auth y authz)

• Soporte para la generación de servicios web

19.1. Actividades

19.1.1. Actividad 1

Escoge uno de los frameworks listados en este tema y localiza manuales y tutoriales para él.

19.1.2. Actividad 2

Identifica de las características indicadas en el tema, cuales de ellas soporta

19.1.3. Actividad 3

Intenta realizar un “Hola Mundo” usando ese framework

19.1.4. Actividad 4

Intenta realizar una funcionalidad (módulo o componente) con ese Framework.

Page 179: Php-Mysql

JAVASCRIPT

165

Javascript

20.1. Conceptos básicos

Javascript, al igual que PHP es un lenguaje interpretado. No hay una compilación de por medio. También es de tipado dinámico por lo que no hay que definir el tipo de dato. Pero una de las diferencias principales con PHP por ejemplo, es que PHP se ejecuta en nuestro servidor, y javascript se ejecuta en nuestro navegador.

Está pensado para darle dinamismo a las webs. Desde simples efectos visuales, hasta conectar con un servidor y descargar contenido para sustituir parte de nuestra web (esto último lo veremos en la parte de AJAX).

20.2. Sintaxis y clases básicas

20.2.1. Incluir scripts en el código HTML

Para incluir el código javascript en nuestra página HTML tenemos 2 formas de hacerlo (exactamente igual que con los CSS).

Page 180: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

166

La primera es escribirlo directamente en nuestro código mediante la etiqueta script: <script type="text/javascript"> //mi código javascript </script>

La otra forma es enlazar desde un fichero externo también mediante la etiqueta script: <script type="text/javascript" src="ruta/hasta/mi/script.js"></script>

Algo que hay que tener en cuenta es que el código javascript se ejecutará de forma lineal (también llamado secuencial), es decir mientras se va cargando la página. Para que esto no suceda, el código que no queramos que se ejecute mientras se está cargando, lo meteremos en funciones, que podremos llamar nosotros cuando queramos, o que se disparen al suceder algún evento.

Los eventos tienen la naturaleza de objetos, o sea, poseen métodos y propiedades. Así cuando se produce un evento podemos saber quien lo dispara, en que posición de la pantalla se ha disparado y otras propiedades dependientes de cada evento en concreto. Y aquí viene uno de las causas para tus futuros dolores de cabeza: cada navegador maneja los eventos de manera algo diferente. Pero bueno, no nos preocupemos de esto… todavía :)

20.3. Elementos del Lenguaje:

20.3.1. Tipos de datos

Los tipos de datos que nos podremos encontrar en javascript son: numéricos, cadenas, booleanos y punteros.

Este último tipo de datos que también se emplea a menudo en los scripts para la captura de eventos, son direcciones de memoria, usadas para asignar funciones. Si en una variable se guarda el nombre de una función esa variable se convierte en otro nombre para esa función. ¿Raro? Esto tiene su verdadera utilidad al asignar funciones a los eventos disparados por el ratón.

20.3.2. Las variables

Veamos un ejemplo de como declarar variables en javascript:

<script language="Javascript"> var navegador_version = 0; function verNavegador() { var version; version = document.appVersion; return version; } </script>

En este ejemplo navegador_version es una variable global mientras que version es local a la función verNavegador(). Observa que las variables están creadas con la palabra clave var, el uso de esta palabra es opcional, sólo es obligatorio si una variable local tienen el mismo nombre que una global. Otro detalle a tener en cuenta es que al mismo tiempo que creamos la variable podemos darle un valor, si no lo hacemos la variable contendrá el valor null.

Page 181: Php-Mysql

JAVASCRIPT

167

20.3.3. Objetos, Arrays y Funciones

Estos puntos los veremos más adelante, ya que Javascript trata a Objetos, Arrays y Funciones como si fuesen objetos.

20.4. Operadores

20.4.1. Operadores Aritméticos

En los primeros ejemplos de este tutor tan sólo se han usado sentencias muy simples como asignar un valor a una variable, mediante el operador de asignación, =, o realizar operaciones aritméticas, pero evidentemente JavaScript puede realizar mas operaciones. En esta sección y las siguientes se presentan los operadores de que dispone este lenguaje clasificados en varios grupos, según el contexto en el que se usen. Comenzamos con los mas conocidos, los operadores aritméticos.

20.4.1.1. Suma +

Se trata de un operador usado para sumar dos valores numéricos o para concatenar cadenas entre sí o números y cadenas. var var1 = 10, var2= "Buenos", var3 = " días", var4 = 31; document.write(var1+var4) /* resultado 41 */ document.write(var2+var3) /* resultado: Buenos días */ document.write(var1+var3) /* resultando: 10 días */

20.4.1.2. Resta -

Operador usado para restar valores numéricos. Puede actuar sobre un único operando numérico cambiándole de signo. var num1 = 10, num2 = 8, res = 0; res = num1 - num2; /*res contiene 2 */ res = -res /* ahora res contiene -2*/

20.4.1.3. Producto ( * ) y cociente ( / )

Realizan las operaciones aritméticas de multiplicar y dividir dos valores

var op1 = 50, op2= 4, div, mul; div = op1/op2 /*div contiene 12.5 */ mul = op1 * op2 /*mul contendrá 200 */ Resto %

20.4.1.4. módulo % (resto de la división)

var op1 = 50, op2= 4, resto; resto = op1 % op2; /*resto contiene 2 */

20.4.1.5. Incremento ( ++) y decremento (--)

Estos operadores se usan para incrementar o decrementar en 1 el valor de una variable. Si el operador se antepone a la variable la operación de incremento o decremento es prioritaria sobre cualquier otra.

Page 182: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

168

var op1=5, op2 = 5, res; res = ++op1; /*res adquiere el valor 6 y luego op1 el 6*/ res = op1++; /*res adquiere el valor 5 y luego op2 el 6*/

20.4.1.6. Operadores compuestos

Los operadores +, -, *, / pueden asociarse con el operador de asignación ( para cambiar el valor de una variable numérica por incrementándolo, decrementándolo, multiplicándolo o dividiéndolo por un valor. El operador += puede usarse igualmente con variables de cadena. var num = 20, cad = "buena"; num += 5; /*num adquiere el valor 25 (20 + 5) */ cad += 's' ; /*cad adquiere el valor 'buenas' */ num *= 10; /*num adquiere el valor 250 (25*10) */

20.4.2. Operadores Binarios

El ordenador, internamente, trata cualquier tipo de datos como una cadena binaria (ceros y unos). Así los números se representan en sistema binario de numeración mientras que los caracteres se convierten a código ASCII, que son números que se almacenan por tanto codificados en binario. JavaScript ofrece los operadores típicos para trabajar con estas cadenas a nivel de bit (cada uno de los ceros o unos de las cadenas binarias. Para trabajar con estos operadores es conveniente tener una idea previa sobre la codificación binaria.

20.4.2.1. Complementación ~

Complementa una cadena binaria convirtiendo los 1 en 0 y los 0 en 1. Por ejemplo el número 38 escrito en sistema binario es 00100110 si le aplicamos este operador se convierte en 11011001, o sea el -39 (JavaScript usa codificación en complemento a 2 para los números negativos).

20.4.2.2. Desplazamiento izquierda <<

Desplaza los bits a la izquierda los lugares que se le indique rellenando con ceros por la derecha y desechando los bits de mayor peso, esto equivale a multiplicar por potencias de 2. Por ejemplo si al 00011010 (26) lo desplazamos 2 a la izquierda tendremos el 01101000 (104). var num = 26, res; res = num << 2; /* num contendrá 104 */

20.4.2.3. Desplazamiento derecha >>

Desplaza los bits a la derecha los lugares que se le indique rellenando con ceros por la izquierda y desechando los bits de menor peso, esto equivale a una división entera por potencias de 2. Por ejemplo si al 00011010 (26) lo desplazamos 2 a la derecha tendremos el 00000110 (6). var num = 26, res; res = num << 2; /* num contendrá 104 */ </Code> === AND lógico binario & ===

Page 183: Php-Mysql

JAVASCRIPT

169

Realiza un AND lógico bit a bit entre dos valores. El AND lógico da como resultado 1 sólo si ambos bits son 1. Por ejemplo <code javascript> 0 1 1 0 1 1 0 1 (109) AND 0 0 1 0 0 1 1 0 (38) resultado: 0 0 1 0 0 1 0 0 (36) var op1 = 109, op2 = 38, res; res = op1 & op2; /*res contiene 36 */

20.4.2.4. OR lógico binario |

Realiza un OR lógico bit a bit entre dos valores. El OR lógico da como resultado 0 sólo si ambos bits son 0. Por ejemplo

0 0 1 1 1 0 1 0 (58) OR 0 1 0 1 0 0 1 0 (82) resultado: 0 1 1 1 1 0 1 0 (122)

En el ejemplo podemos ver la sintaxis del operador var op1 = 58, op2 = 82, res; res = op1 | op2; /*res contiene 122 */

20.4.2.5. XOR lógico binario ^

Realiza un XOR lógico bit a bit entre dos valores. El XOR lógico da como resultado 1 si uno sólo de los bits es 1. Por ejemplo

0 0 1 1 1 0 1 0 (58) OR 0 1 0 1 0 0 1 0 (82) resultado: 0 0 1 0 1 0 0 0 (40)

En el ejemplo podemos ver la sintaxis del operador var op1 = 109, op2 = 38, res; res = op1 ^ op2; /*res contiene 40*/

20.4.3. Operadores Lógicos

Los operadores lógicos se utilizan para realizar comparaciones entre valores, numéricos o no, dando como resultado un valor booleanos (true, false). La operación lógica negación invierte el operando, si es true lo hace false y viceversa. Si se comparan números con cadenas, JavaScript intenta convertir internamente los datos. En los

operadores relacionales (>, <, >=, ) intenta convertir los datos en tipo número. Para los

operadores de igualdad (== ! intenta convertir los tipos de datos a cadena, número y booleano. Los operadores de identidad (===, != no realizan conversión de tipo.

20.4.3.1. Mayor que >

Compara dos valores y devuelve true si el primero es mayor que el segundo. Compara tanto números como cadenas. var hoy = 4; ayer = 10, comp; comp = hoy > ayer /* comp adquiere el valor false*/

Page 184: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

170

20.4.3.2. Menor que <

Compara dos valores y devuelve true si el primero es mayor que el segundo. Compara tanto números como cadenas. var hoy = 4; ayer = 10, comp; comp = hoy < ayer /* comp adquiere el valor false*/

20.4.3.3. Mayor o igual >=

Compara dos valores y devuelve true si el primero es mayor o es igual que el segundo. Compara tanto números como cadenas. var hoy = 4; ayer = 4, comp; comp = hoy >= ayer /* comp adquiere el valor true*/

20.4.3.4. Menor o igual <=

Compara dos valores y devuelve true si el primero es menor o es igual que el segundo. Compara tanto números como cadenas. var hoy = 4; ayer = 4, comp; comp = hoy <= ayer /* comp adquiere el valor true*/

20.4.3.5. Iguales ==

Compara dos valores y devuelve true si ambos son iguales. Compara tanto números como cadenas. var hoy = 4; ayer = 4, comp; comp = hoy == ayer /* comp adquiere el valor true*/

20.4.3.6. Idénticos ===

Similar a == pero también compara el tipo de datos de los operandos

Compara dos valores y devuelve true si el primero es mayor o es igual que el segundo.

Compara tanto números como cadenas. var hoy = 4; ayer = '4', comp; comp = hoy == ayer; /* comp adquiere el valor true*/ comp = hoy === ayer /* comp adquiere el valor false*/

20.4.3.7. No iguales != y No idénticos !==

Invierten el sentido de las comparaciones iguales == e idénticos === respectivamente.

20.4.3.8. AND lógico &&

Este operador se utiliza para concatenar comparaciones, es decir, para comprobar varias condiciones. El resultado sólo será true si todas las comparaciones lo son. var op1 = 2, op2 = 50, op3 = 25, comp; comp = (op1 > op2) && (op1 < op3); /*comp adquiere el valor false */

comp es false por que op1 no es mayor que op2 aunque sea mayor que op3

Page 185: Php-Mysql

JAVASCRIPT

171

20.4.3.9. OR lógico ||

Como el anterior, sirve para realizar comparaciones compuestas y sólo devolverá false cuando todas las comparaciones los sean. Es decir basta que una comparación sea true para que devuelva el valor true. var op1 = 2, op2 = 50, op3 = 25, comp; comp = (op1 > op2) && (op1 < op3); /*comp adquiere el valor true */

comp es true por que op1 es menor que op3, (op1 < op3 es por tanto true)

20.4.4. Operadores Varios

20.4.4.1. delete

Se usa para borrar propiedades de un objeto o elementos de un array. Devuelve true si la operación se realizó con éxito. var lista = new Array(1,4,7,9,10); delete(lista,0);

El elemento lista[1] contiene ahora undefined.

20.4.4.2. new

Se utiliza para crear instancias de un objeto var hoy = new Date("10 /30/2000")

20.4.4.3. typeof

Devuelve el tipo de dato al que pertenece una variable o expresión. Los tipos devueltos son number, string, boolean, object, function y undefined. hoy = 1.2345; tipo = typeof(hoy);

La variable tipo contendrá number.

20.4.5. Funciones Globales

A sí como JavaScript proporciona objetos predefinidos, también posee una serie de funciones predefinidas. Se trata de las funciones: eval, isNan, Number, String, parseInt, parseFloat, escape, unescape.

20.4.5.1. eval

Se usa para evaluar una cadena con código JavaScript sin referirse a un objeto concreto.

La sintaxis de eval es: eval(expr)

donde expr es la cadena a evaluar.

Page 186: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

172

20.4.5.2. isNaN(arg)

Determina si el argumento es un valor NaN (not a number)

20.4.5.3. parseInt(str, [base])

Convierte una cadena de caracteres en un valor numérico. La función lleva como argumento la cadena a convertir y opcionalmente puede llevar un segundo argumento para indicar la base de numeración en que está escrita la cadena. Si se omite se supone que la cadena representa un número en base 10. La cadena sólo podrá contener caracteres válidos para el sistema de numeración indicado: dígitos (0..9 para la base 10, 0 1 para números binarios, 0..7 para sistema octal, 0..9, A..F para sistema hexadecimal) y signo (+, -). Si encuentra algún carácter no válido sólo interpreta desde el principio de la cadena hasta el carácter no válido. Si comienza por un carácter ilegal devuelve NaN.

Ejemplo: var minum1 = "14"; document.write(parseInt(minum1));

Escribirá 14. En el siguiente ejemplo transforma un número binario a decimal: var minum1 = "11001"; document.write(parseInt(minum1,2));

Ahora escribirá 25, el equivalente decimal al binario 11001.

20.4.5.4. parseFloat(str)

Convierten una la cadena que se le pasa como argumento a un valor numérico de tipo flotante. Los caracteres válidos de la cadena son los mismos que en parseInt mas el punto decimal y el exponente (E). No admite un segundo argumento. Por lo demás funciona exactamente igual que parseInt. var minum1 = "14.5E2"; document.write(parseInt(minum1))

Escribirá el número 1450, 14.5 por 10 elevado a 2.

20.4.5.5. Number(objArg) y String(objArg)

Permiten convertir el objeto pasado como argumento a un número o a una cadena. Por ejemplo: var hoy = new Date(); hoy.getDate(); document.write(string(hoy));

Escribirá en pantalla la cadena “Sun Sep 3 20:40:05 UTC+0200 2000” si la fecha del día es domingo 3 de Septiembre y la hora es las 20:40:05.

20.4.5.6. escape(cadarg)

Codifica la cadena del argumento substituyendo todos los caracteres no ASCII por su código en el formato %xx. Por ejemplo: var cadena = "Buenos días"; document.write(escape(cadena));

Page 187: Php-Mysql

JAVASCRIPT

173

Produce la frase "Buenos d%EDas", pues la í (i acentuada) es el código hexadecimal ED de ese carácter.

20.4.5.7. unescape(cadarg)

Es inversa a la anterior, de manera que si la cadena contiene códigos del tipo %xx son convertidos al correspondiente carácter ASCII extendido. var cadena = "Buenos d%EDas"; document.write(escape(cadena));

Ahora se escribirá “Buenos días”, se ha substituido %ED por su equivalente í (i acentuada).

20.5. Estructuras de control

20.5.1. Condiciones

El orden en que se ejecutan las instrucciones de un programa es, por defecto, secuencial: ejecución instrucción tras instrucción. Así un programa se escribirá como una sucesión de instrucciones o sentencias, utilizando un punto y coma para indicar el final de la instrucción. Pueden agruparse una serie de sentencias en un bloque encerrándolas entre llaves. A veces es necesario alterar este orden para ello se utilizan las instrucciones de control: condicionales, selección y bucles. Serán las sentencias condicionales las primeras que veremos.

Una sentencia condicional es una instrucción en la que se hace una comparación y según el resultado verdadero o falso (true o false) de la misma el programa seguirá ejecutando una u otra instrucciones. La condicional mas simple que podemos escribir es aquella que ejecuta u omite una serie de sentencias dependiendo de si la comprobación da verdadero o falso. La sintaxis de esta sentencia es. if (condición) {bloque a ejecutar si la condición es cierta} else {bloque a ejecutar si la condición es false}

Si omitimos la parte del else tendremos una condicional simple. Esta sintaxis en algunos casos puede simplificarse utilizando la siguiente forma: (condición) ?{bloque si cierta} : {bloque si falsa}

En el siguiente ejemplo evitamos realizar una división por cero if (div == 0) alert('No se puede dividir por 0'); else coc = num / div;

Otro ejemplo usando la segunda forma: cad = (num >= 0) ? ' + ' : ' - ';

En este ejemplo cad tomará el valor + si num es positivo o cero y el - si es negativo. Las sentencias if pueden anidarse, es decir, dentro de una sentencia if pueden meterse mas sentencias if.

Las condiciones pueden ser sencillas como en estos ejemplos o pueden enlazarse usando los operadores && y || (AND y OR lógicos). Veamos un ejemplo en el que comprobamos si un número está comprendido entre 1 y 5:

Page 188: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

174

if ((num>=1) y (num < 5) { lista[indice] = 'Muy bajo'; bajos++; } indice++;

En este ejemplo si num está entre 1 y 5 (excluido) se anota en una lista la palabra 'Muy bajo' y se incrementa la variable bajos. Como vemos no se ha usado la parte de else y como se deben ejecutar mas de una sentencia las hemos encerrado entre llaves. Si num no cumple la condición el programa se salta este bloque. En cualquier caso la siguiente instrucción que se ejecute tras el condicional será la que incrementa el valor de indice.

20.5.2. Switch

switch (idioma) { case 'castellano' : pagCast(); break; case 'ingles' : pagIng(); break; case 'frances' : pagFran(); break; case 'alemán' : pagAlem(); break; default : error ('Idioma no presente'); }

Durante la ejecución se compara la variable idioma con cada uno de los posibles valores y cuando coincidan ejecuta el código correspondiente. La instrucción break pone fin al bloque y hace que el programa salte a la instrucción siguiente a la sentencia switch(), si se omite el programa continuaría con la siguiente comparación. La sección del default es opcional, su finalidad es ejecutar algún código cuando ninguna de las condiciones se cumpla.

20.5.3. Bucles

20.5.3.1. Sentencia while

En esta estructura el programa primero comprueba la condición: si es cierta pasa a ejecutar el cuerpo del bucle, y si es falsa pasa a la instrucción siguiente a la sentencia while. Como siempre un ejemplo lo aclarará todo: var lista = new Array(10); var ind=0; while (ind < 10) { lista[ind] = '0'; ind++; }

En este ejemplo mientras que el valor almacenado en ind sea menor que 10 (la longitud del array ) irá almacenando en cada elemento del array lista un 0 e incrementando el valor de ind. Cuando este valor sea 10 el programa no entrará en el cuerpo del bucle. Si no se incrementara el valor de ind el bucle no acabaría nunca, el programa quedaría ejecutando indefinidamente el cuerpo del bucle.

Page 189: Php-Mysql

JAVASCRIPT

175

20.5.3.2. Sentencia do...while

Se trata de un bucle en el que la condición se comprueba tras la primera iteración, es decir que el cuerpo del bucle se ejecuta al menos una vez. El ejemplo anterior quedaría como sigue: var lista = new Array(10); var ind=0; do lista[ind] = '0'; ind++; while (ind < 10)

Como vemos aquí no son imprescindibles las llaves para encerar el cuerpo del bucle. No está contemplada en el standard ECMA 1.5.

20.5.3.3. Sentencia for

Esta sentencia utiliza una variable de control a modo de contador para controlar la repetición del cuerpo del bucle. La sentencia da un valor inicial a este contador y en cada iteración lo modifica según le indiquemos y comprueba la condición, si se cumple ejecuta el cuerpo del bucle, si no lo salta y continúa por la siguiente sentencia. Vemos el ejemplo anterior usando esta sentencia: var lista = new Array(10); var ind; for (ind=0; ind < 10; ind++) { lista[ind] = '0'; }

Como vemos el cuerpo del bucle no incrementa la variable ind, esto se indica en la cabecera de la sentencia. Este código hace exactamente lo mismo que el anterior.

20.5.3.4. Sentencia for ... in

Se trata de una variante de la sentencia for utilizada para iterar o recorrer todos los elementos de un objeto o de un array. Usa una variable de control que en cada iteración toma el valor del elemento del objeto recorrido. Por ejemplo si pruebas este código podrás ver todos los elementos del objeto document var item; for (item in document) document.write(item+'<br>');

Con una matriz la variable de control toma el valor de los índices de la matriz, no su contenido.

20.6. Ruptura de Bucles

Aunque procuremos usara una programación estructura alguna vez puede ser necesario interrumpir la repetición de un bucle o forzar una iteración del mismo, esto puede lograrse mediante las sentencias break y continue. Son sentencias aplicables a cualquiera de las estructuras de bucle en JavaScript.

Page 190: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

176

20.6.1.1. break

La sentencia break interrumpe la iteración actual y envía al programa a la instrucción que sigue al bucle. var lista = new Array ('a','b','c','z','x','f'); var item ; for (item in lista) { if (lista[item] == "z") break; document.write(lista[item]+'<br>'); }

Este ejemplo escribiría el contenido del array lista hasta encontrar una letra z.

20.6.1.2. continue

La sentencia continue interrumpe la iteración actual y envía al programa a la comprobación de la condición, si esta es cierta continúa con la siguiente iteración. var lista = new Array ('a','b','c','z','x','f'); var item ; for (item in lista) { if (lista[item] == "z") continue; document.write(lista[item]+'<br>'); }

Este ejemplo escribiría el contenido del array saltándose la letra z.

20.7. Los Objetos de Javascript

20.7.1. Objeto Object

Pues sí: existe un objeto llamado Object del que derivan todos los objetos de JavaScript, los predefinidos y los definidos por el usuario. Esto significa que los objetos usados en JavaScript heredan las propiedades y métodos de Object.

20.7.1.1. Métodos

toString

Devuelve una cadena dependiendo del objeto en que se use

Objeto Cadena devuelta por el método Array Los elementos del array separados por coma

Boolean Si el valor es false devuelve “false” si no devuelve “true”

Function La cadena “function nombre_de_función(argumentos){ [código]}”

Number Representación textual del número String El valor de la cadena

Page 191: Php-Mysql

JAVASCRIPT

177

Default ”[object nombre_del_objeto]”

valueOf

Devuelve el valor del objeto dependiendo del objeto en que se use

Objeto Valor que devuelve el método Array Una cadena formada por los elementos

separados por coma Boolean El valor booleano (true o false)

Date La fecha como el número de milisegundos desde el 1/1/1970, 00:00

Function La propia función Number El valor numérico String La cadena

Default El propio objeto

20.7.1.2. Propiedades

constructor

Esta propiedad contiene una referencia a la función que crea las instancias del objeto en particular. Por ejemplo: x = new String("Hola"); //En este caso s.constructor contendrá // function String() { [native code] }

prototype

Es una propiedad utilizada para asignar nuevos métodos o propiedades a un objeto, elementos estos que serán heredados por las diferentes instancias de ese objeto.

Ejemplo: Array.prototype.nombTipo = "matriz"; lista = new Array(9); document.write(lista.nombTipo); //Escribirá la palabra matriz que es el nombTipo //que hemos dado para el objeto Array

20.7.1.3. ¿Como crear nuestros propios objetos?

Lo vemos en el siguiente punto :) el objeto Function.

20.7.2. Objeto Function

Permite la creación de funciones, ya sean con nombre o anónimas. La creación de una función puede realizarse por el método tradicional y común a la mayoría de lenguajes de programación: function sumar(a, b) { return a+b; }

O bien mediante el conocido operador new:

Page 192: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

178

sumar = new Function ("a", "b", "return a+b");

En cualquier caso la función se usará de igual forma: document.write( sumar(90, 100) );

20.7.2.1. Métodos

Los heredados del objeto Object

20.7.2.2. Propiedades

arguments

Se trata de un array que contiene los argumentos pasados a la función. Esta propiedad permite el uso de funciones con un número variable de argumentos.

caller

Contiene una referencia a la función que llamó a la actual.

constructor

Heredada de la clase Object

20.7.2.3. Creando funciones "objeto"

Si queremos crear un “objeto javascript”, lo que haremos realmente será crear una función: function pagina (titulo, color, fondo) { this.titulo = titulo; this.color = color; this.imgfondo = fondo; this.length = 3; } var miPagina = new pagina("Mi página", "Blue", "cruces.gif"); var nuevapag = new pagina("2a Página", "White", "");

Si queremos añadir métodos a nuestro objeto, podemos hacerlo como al crear cualquier función: function mi_objeto(param1, param2) { this.propiedad1 = param1; this.propiedad2 = param2; this.mi_metodo_sumar = new Function ("a", "b", "return a+b"); }

20.7.3. Objeto Array

A diferencia de otros lenguajes, en javascript, los arrays son objetos, que tienen sus propias propiedades y métodos (ampliables por el usuario) veámos algunas comúnes a los navegadores:

Page 193: Php-Mysql

JAVASCRIPT

179

20.7.3.1. Propiedades

length

Como su nombre indica esta propiedad nos devuelve la longitud del array, es decir, el número de elementos que puede almacenar. Su uso es muy simple: var lista = new Array(50); tamagno = lista.length; /*tamagno almacenaría el valor 50 */

prototype

Esta es una propiedad muy potente en el sentido que nos permite agregar al objeto Array las propiedades y métodos que queramos. Array.protoype.descriptor = null; dias = new Array ('lunes', 'Martes', 'Miercoles', 'Jueves', 'Viernes'); dias.descriptor = "Dias laborables de la semana";

En este ejemplo hemos creado una nueva propiedad para el objeto array, la propiedad descriptor que podría utilizarse para darle un título a la matriz.

20.7.3.2. Métodos

concat(objArray)

Une el objeto Array con el array que se le pasa como argumento y devuelve el resultado

en un nuevo array, sin modificar los arrays que se concatenan.

join()

Convierte los elementos de un array en una cadena separados por el carácter que se le indique. El separador por defecto es la coma. a= new Array("Hola","Buenos","días"); document.write(a.join() +" <br>"); document.write(a.join(", ") +" <br>"); document.write(a.join(" + ") +" <br>") ;

La salida de este programa sería Hola,Buenos,Días Hola, Buenos, Días Hola+Buenos+Días

reverse()

Invierte el orden de los elementos de un Array en el propio array, sin crear uno nuevo.

slice(ini, fin)

Extrae parte de un Array devolviéndolo en un nuevo objeto Array. lista = new Array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'); sublista = lista.slice(2,6); alert(sublista.join());

En el ejemplo sublista contendrá los elementos desde el índice 2 al 5 ambos inclusive, o sea, 'c', 'd', 'e', 'f'. Si se omite el segundo argumento se extrae hasta el último elemento del array y si es negativo se entiende como contando desde el final.

Page 194: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

180

sort(rutord)

Ordena alfabéticamente los elementos de un objeto Array. Opcionalmente podemos pasar como argumento una función para determinar el orden, esta función posee dos argumentos y devolverá un valor negativo si el primer argumento es menor que el segundo, cero si son iguales y un valor positivo si el primer argumento es mayor que el segundo. En castellano esto es necesario si queremos que la ñ y vocales acentuadas figuren en su lugar.

20.7.4. Objeto window

Es el objeto principal en la jerarquía y contiene las propiedades y métodos para controlar la ventana del navegador. De él dependen todos los demás objetos de la jerarquía. Vamos a ver la lista de sus propiedades y métodos.

20.7.4.1. Propiedades

Propiedad Descripción closed Indica la posibilidad de que se haya cerrado la

ventana. (Javascript 1.1) defaultStatus Texto que se escribe por defecto en la barra de

estado del navegador. document Objeto que contiene el la página web que se está

mostrando. Frame Un objeto frame de una página web. Se accede

por su nombre. frames array El vector que contiene todos los frames de la

página. Se accede por su índice a partir de 0. history Objeto historial de páginas visitadas.

innerHeight Tamaño en pixels del espacio donde se visualiza la página, en vertical. (Javascript 1.2)

innerWidth Tamaño en pixels del espacio donde se visualiza la página, en horizontal. (Javascript 1.2)

length Numero de frames de la ventana. location La URL del documento que se está

visualizando. Podemos cambiar el valor de esta propiedad para movernos a otra página. Ver

también la propiedad location del objeto document.

locationbar Objeto barra de direcciones de la ventana. (Javascript 1.2)

menubar Objeto barra de menús de la ventana. (Javascript 1.2)

name Nombre de la ventana. Lo asignamos cuando abrimos una nueva ventana.

opener Hace referencia a la ventana de navegador que abrió la ventana donde estamos trabajando.

outherHeight Tamaño en pixels del espacio de toda la ventana, en vertical. Esto incluye las barras de desplazamiento, botones, etc. (Javascript 1.2)

outherWidth Tamaño en pixels del espacio de toda la ventana, en horizontal. Esto incluye las barras

de desplazamiento. (Javascript 1.2)

Page 195: Php-Mysql

JAVASCRIPT

181

parent Hace referencia a la ventana donde está situada el frame donde estamos trabajando.

personalbar Objeto barra personal del navegador. (Javascript 1.2)

self Ventana o frame actual. scrollbars Objeto de las barras de desplazamiento de la

ventana. status Texto de la barra de estado.

statusbar Objeto barra de estado del navegador. (Javascript 1.2)

toolbar Objeto barra de herramientas. (Javascript 1.2) top Hace referencia a la ventana donde está situada

el frame donde estamos trabajando. Como la propiedad parent.

window Hace referencia a la ventana actual, igual que la propiedad self.

20.7.4.2. Métodos

Metodo Descripción alert(texto) Presenta una ventana de alerta donde se puede

leer el texto que recibe por parámetro back() Ir una página atrás en el historial de páginas

visitadas. Funciona como el botón de volver de la barra de herramientas. (Javascript 1.2)

blur() Quitar el foco de la ventana actual. (Javascript 1.1)

captureEvents(eventos) Captura los eventos que se indiquen por parámetro (Javascript 1.2).

clearInterval() Elimina la ejecución de sentencias asociadas a un intervalo indicadas con el método

setInterval().(Javascript 1.2) clearTimeout() Elimina la ejecución de sentencias asociadas a

un tiempo de espera indicadas con el método setTimeout().

close() Cierra la ventana. (Javascript 1.1) confirm(texto) Muestra una ventana de confirmación y permite

aceptar o rechazar. find() Muestra una ventanita de búsqueda. (Javascript

1.2 para Netscape) focus() Coloca el foco de la aplicación en la ventana.

(Javascript 1.1) forward() Ir una página adelante en el historial de páginas

visitadas. Como si pulsásemos el botón de adelante del navegador. (Javascript 1.2)

home() Ir a la página de inicio que haya configurada en el explorador. (Javascript 1.2)

moveBy(pixelsX, pixelsY) Mueve la ventana del navegador los pixels que se indican por parámetro hacia la derecha y

abajo. (Javascript 1.2) moveTo(pixelsX, pixelsY) Mueve la ventana del navegador a la posición

indicada en las coordenadas que recibe por parámetro. (Javascript 1.2)

Page 196: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

182

open() Abre una ventana secundaria del navegador. Se puede aprender a utilizarla en el reportaje de

cómo abrir ventanas secundarias. print() Como si pulsásemos el botón de imprimir del

navegador. (Javascript 1.2) prompt(pregunta,inicializacion_de_la_respuesta) Muestra una caja de diálogo para pedir un dato.

Devuelve el dato que se ha escrito. releaseEvents(eventos) Deja de capturar eventos del tipo que se indique

por parámetro. (Javascript 1.2) resizeBy(pixelsAncho,pixelsAlto) Redimensiona el tamaño de la ventana,

añadiendo a su tamaño actual los valores indicados en los parámetros. El primero para la

altura y el segundo para la anchura. Admite valores negativos si se desea reducir la ventana.

(Javascript 1.2) resizeTo(pixelsAncho,pixelsAlto) Redimensiona la ventana del navegador para

que ocupe el espacio en pixels que se indica por parámetro (Javascript 1.2)

routeEvent() Enruta un evento por la jerarquía de eventos. (Javascript 1.2)

scroll(pixelsX,pixelsY) Hace un scroll de la ventana hacia la coordenada indicada por parámetro. Este método está

desaconsejado, pues ahora se debería utilizar scrollTo()(Javascript 1.1)

scrollBy(pixelsX,pixelsY) Hace un scroll del contenido de la ventana relativo a la posición actual. (Javascript 1.2)

scrollTo(pixelsX,pixelsY) Hace un scroll de la ventana a la posición indicada por el parámetro. Este método se tiene que utilizar en lugar de scroll. (Javascript 1.2)

setInterval() Define un script para que sea ejecutado indefinidamente en cada intervalo de tiempo.

(Javascript 1.2) setTimeout(sentencia,milisegundos) Define un script para que sea ejecutado una vez

después de un tiempo de espera determinado. stop() Como pulsar el botón de stop de la ventana del

navegador. (Javascript 1.2)

20.7.5. Objeto document

Con el objeto document se controla la página web y todos los elementos que contiene. El objeto document es la página actual que se está visualizando en ese momento. Depende del objeto window, pero también puede depender del objeto frame en caso de que la página se esté mostrando en un frame.

20.7.5.1. Propiedades

Veamos una lista de las propiedades del objeto document y luego veremos algún ejemplo.

Propiedad Descripción alinkColor Color de los enlaces activos

Anchor Un ancla de la página. Se consigue con la etiqueta <A name=“nombre_del_ancla”>. Se

accede por su nombre.

Page 197: Php-Mysql

JAVASCRIPT

183

anchors (array) Un array de las anclas del documento (enlaces <a>).

Applet Un applet de la página. Se accede por su nombre. (Javascript 1.1)

applets (array) Un array con todos los applets de la página. (Javascript 1.1)

Area Una etiqueta <AREA>, de las que están vinculadas a los mapas de imágenes (Etiqueta ).

Se accede por su nombre. (Javascript 1.1) bgColor El color de fondo del documento. classes Las clases definidas en la declaración de estilos

CSS. (Javascript 1.2) cookie Una cookie domain Nombre del dominio del servidor de la página. Embed Un elemento de la pagina incrustado con la

etiqueta <EMBED>. Se accede por su nombre. (Javascript 1.1)

embeds (array) Todos los elementos de la página incrustados con <EMBED>. (Javascript 1.1)

fgColor El color del texto. Para ver los cambios hay que reescribir la página.

Form Un formulario de la página. Se accede por su nombre.

forms (array) Un array con todos los formularios de la página. ids Para acceder a estilos CSS. (Javascript 1.2)

Image Una imagen de la página web. Se accede por su nombre. (Javascript 1.1)

images (array) Cada una de las imágenes de la página introducidas en un array. (Javascript 1.1)

lastModified La fecha de última modificación del documento. linkColor El color de los enlaces.

Link Un enlace de los de la página. Se accede por su nombre.

links (array) Un array con cada uno de los enlaces de la página.

location La URL del documento que se está visualizando. Es de solo lectura.

referrer La página de la que viene el usuario. tags Estilos definidos a las etiquetas de HTML en la

página web. (Javascript 1.2) title El titulo de la página. URL Lo mismo que location, pero es aconsejable

utilizar location ya que URL no existe en todos los navegadores.

vlinkColor El color de los enlaces visitados.

20.7.5.2. Métodos

Método Descripción captureEvents() Para capturar los eventos que ocurran en la

página web. Recibe como parámetro el evento

Page 198: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

184

que se desea capturar. close() Cierra el flujo del documento. (Se verá más

adelante en este manual un artículo sobre el flujo del documento)

contextual() Ofrece una línea de control de los estilos de la página. En el caso que deseemos especificarlos

con Javascript. getSelection() Devuelve un string que contiene el texto que se

ha seleccionado. En un principio sólo funcionaba en Netscape.

handleEvent() Invocas el manejador de eventos del elemento especificado.

open() Abre el flujo del documento. releaseEvents() Liberar los eventos capturados del tipo que se

especifique, enviándolos a los objetos siguientes en la jerarquía.

routeEvent() Pasa un evento capturado a través de la jerarquía de eventos habitual.

write() Escribe dentro de la página web. Podemos escribir etiquetas HTML y texto normal.

writeln() Escribe igual que el método write(), aunque coloca un salto de línea al final.

20.7.6. Objeto form

El objeto form es un sub-objeto del objeto document y este a su vez, lo es del objeto window.

Así como para crear una página en HTML se utilizan las etiquetas <HTML> Y </HTML>, lo mismo sucede con un formulario: el formulario debe estar contenido entre las etiquetas <form> y </form>

En principio la sintaxis básica para referirnos a un formulario sería: window.document.forms.nombre_del_formulario

En la que tranquilamente pueden prescindirse de window y forms ya que el navegador toma al formulario como un objeto en sí mismo. De la misma forma, tambien puede prescindirse de document. Pero esta omisión solo se hará si queremos referirnos a un formulario en particular (por ejemplo a un formulario llamado “datos”). Pero al momento de referirnos a “todos los formularios de una página”, solo se podrá prescindir del objeto window.

20.7.6.1. Propiedades principales del objeto form

El objeto form posee las siguientes propiedades:

^ propiedad ^ descripción ^

name es el nombre único del formulario.

action es el lugar al cual se envía el formulario para ser procesado. El action define la URL a la cual se

envía dicho formulario. method método de envío de los datos insertados en un

Page 199: Php-Mysql

JAVASCRIPT

185

formulario. El method puede ser: GET = envía los datos en una cadena “visible”. Conveniente

para enviar pocos datos. POST = envía los datos en forma “invisible”. Conveniente para enviar

una gran cantidad de datos. target define la ventana o marco (frame) en la que se

mostrarán o procesarán los resultados del formulario. El valor es el mismo que el utilizado

en HTML (blank, self, top, nombre_marco, etc..)

20.7.6.2. Métodos del objeto form

El objeto form posee dos métodos:

método descripción submit envía el formulario. reset restablece el formulario a los valores por

defecto.

20.7.7. Objeto Boolean

Las variables booleanas o lógicas son las que sólo pueden tomar dos valores: true, verdadero, y false, falso. Este tipo de variables está implementado en JavaScript como un objeto.

20.7.7.1. Métodos

toString

Si el valor es false devuelve la cadena “false” y si es true devuelve la cadena “true”

valueOf

Devuelve el valor booleano (true o false)

20.7.7.2. Propiedades

constructor

heredada del objeto genérico Object, devuelve la referencia al constructor: function Boolean() { [native code] }

prototype

Es una propiedad utilizada para asignar nuevos métodos o propiedades, heredado del objeto genérico Object. Por ejemplo podemos traducir los valores true o false. function valor () { return this.valueOf()?'cierto':'falso' } Boolean.prototype.valor = valor; var item = new Boolean(false); document.write(item.valor());

Con este ejemplo logramos que true se devuelva como la cadena “cierto” y false como la cadena “falso”.

Page 200: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

186

20.7.8. Objeto Number

Es el objeto destinado al manejo de datos y constantes numéricas. Realmente no es habitual crear objetos de este tipo ya que JavaScript los crea automáticamente cuando es necesario. No obstante la sintaxis para su creación es la habitual para cualquier objeto: minumero = new Number(valorinicial)

El valor inicial es optativo, si no se usa el objeto se crea con valor null

20.7.8.1. Métodos

Los heredados del objeto Object

20.7.8.2. Propiedades

Además de las heredadas del objeto Object Number posee las siguientes propiedades:

MAX_VALUE

Indica el valor máximo utilizable por JavaScript, actualmente 1.79E+308.

MIN_VALUE

Indica el valor mínimo utilizable por JavaScript, actualmente 2.22E-308.

NaN

Una constante usada para indicar que una expresión ha devuelto un valor no numérico. NaN no puede compararse usando los operadores lógicos habituales, para ver si un valor es igual a NaN se debe usar la función incorporada isNaN

NEGATIVE_INFINITY

Una constante para indicar infinito positivo, es decir, un valor superior al MAX_VALUE

POSITIVE_INFINITY

Una constante para indicar infinito negativo, es decir, un valor superior al MAX_VALUE con signo negativo

20.7.9. Objeto String

El objeto String se usa para manipular cadenas de caracteres. En JavaScript todo texto encerrado entre comillas, dobles o simples, se interpreta como una cadena, así '45' no es el número cuarenta y cinco sino la cadena formada por los caracteres 4 y 5. El objeto String permite realizar operaciones con cadenas como concatenar o dividir cadenas, buscar texto, extraer parte de un texto, etc.. La operación de crear una variable de este tipo se lleva a cabo como es habitual con el operador new pudiéndole pasar un argumento para inicializar la variable. Al usar un método o referirnos a una propiedad podemos usar el nombre de la variable o una constante de cadena así el ejemplo var mitexto = "Esta es una cadena"; var pos = mitexto.indexOf("una")

Page 201: Php-Mysql

JAVASCRIPT

187

puede también escribirse en la siguiente forma: var pos = "Esta es una cadena". indexOf("una");

20.7.9.1. Propiedades

length:

devuelve la longitud de la cadena.

prototype:

permite agregar métodos y propiedades al objeto

20.7.9.2. Métodos

anchor fromCharCode small big indexOf split

blink italics strike bold lastindexOf sub

charAt link substr charCodeAt match substring

concat replace sup fixed search toLowerCase

fontcolor slice toUpperCase fontsize

Vamos algunos de los más usados o algunos que puedan llevar a confusión por su similitud.

nota: algunos métodos como bold, o big, italics… alteran el estilo visual usando etiquetas como <b></b> etc… Por lo que se aconseja utilizar mejor cambios de estilos css para hacerlo lo más genérico posible, ya que quizás dependiendo de un diseño web, usar un tipo de resaltado u otro.

charAt(atrent)

Este método aplicado a una cadena devuelve el carácter que se encuentra en la posición dada por el atributo atrent, teniendo en cuenta que el índice del primer carácter a la izquierda de la cadena es 0 y el último es una unidad menor que longitud de la cadena. Si el valor del atributo no es válido (igual o mayor que la longitud de la cadena o negativo) el método devuelve el valor undefined. Por ejemplo el siguiente código devuelve la posición del tercer carácter de la cadena nombre: var nombre = "abcdefghij"; var car3 = nombre.charAt(2);

Devolverá “c”, que es el tercer carácter por la izquierda (índice igual a 2).

charCodeAt(atrent)

Este método aplicado a una cadena devuelve el código Unicode del carácter que se encuentra en la posición dada por el atributo atrent, teniendo en cuenta que el índice del primer carácter a la izquierda de la cadena es 0 y el último es una unidad menor que longitud de la cadena. Si el valor del atributo no es válido (igual o mayor que la longitud de la cadena o negativo) el método devuelve el valor NAN. Por ejemplo el siguiente código devuelve el Unicode del tercer carácter de la cadena nombre:

Page 202: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

188

var nombre = "abcdefghij"; var car3 = nombre.charAt(2);

Devolverá 99, que es el código de la letra 'c', el tercer carácter por la izquierda (índice igual a 2).

concat(atrcad)

Este método aplicado a una cadena le agrega la cadena pasada como atributo, atrcad, que será una variable o constante literal, cualquier otro tipo es convertido a cadena. Por ejemplo el siguiente código concatena 'Buenos ' y 'días': var saludo = "Buenos "; var hola = saludo.concat("días");

La variable hola contendrá “Buenos días”, es lo mismo que si se hubiera escrito: var hola = saludo + "días"

indexOf( atrcad, desde)

Este método devuelve la primera posición dentro del objeto String donde comienza la subcadena pasada como argumento en atrcad. Admite un segundo argumento opcional que indica desde que posición debe realizar la búsqueda, si se omite comienza a buscar por el primer carácter de la izquierda. Valores del segundo argumento negativos o mayores que la longitud de la cadena se consideran 0. Si la subcadena no se encuentra el

valor devuelto es -1. Por ejemplo: var cadena = "[email protected]"; var arroba = cadena.indexOf('@'); var punto = cadena.indexOf('.',arroba);

Este ejemplo devuelve en arroba la posición 9 mientras que punto contiene la 14 pues la búsqueda se hizo desde la posición donde está el carácter arroba y encuentra el segundo punto. Recuerda que las posiciones en las cadenas se cuentan desde 0.

lastIndexOf(atrcad, desde)

Este método devuelve la primera posición dentro del objeto String donde comienza la subcadena pasada como argumento en atrcad, pero realizando la búsqueda de derecha a izquierda. Admite un segundo argumento opcional que indica desde que posición debe realizar la búsqueda, si se omite comienza a buscar por el primer carácter de la derecha, valores negativos o mayores que la longitud de la cadena se consideran 0. Si la subcadena no se encuentra el valor devuelto es -1. Por ejemplo: var cadena = "[email protected]"; var arroba = cadena.lastIndexOf('@'); var punto = cadena.lastIndexOf('.',arroba);

Este ejemplo devuelve en arroba la posición 9 mientras que punto contiene la 2 pues la búsqueda se hizo desde la posición donde está el carácter arroba hacia el principio de la cadena encontrando el primer punto. Recuerda que las posiciones en las cadenas se cuentan desde 0.

Métodos de String: slice ( inicio, ultimo )

Este método devuelve la porción de cadena comprendida entre las posiciones dadas por los argumentos inicio y ultimo, o el final de la cadena si se omite este segundo argumento. Si ultimo es negativo, se interpreta como número de posiciones contadas desde el final de la cadena. Si los argumentos no son números enteros, por ejemplo cadenas, se convierten a números enteros como haría el método Number.parseInt().

Page 203: Php-Mysql

JAVASCRIPT

189

var frase = "Autor: Pepe Almodóvar"; var nombre = frase.slice(7);

La variable nombre contendrá “Pepe Almodóvar”. En este otro ejemplo usamos un segundo argumento: var frase = "Autor: Pepe Almodóvar"; var nombre = frase.slice(7, -10);

nombre contendrá “Pepe”', es decir desde la posición 7 hasta 10 posiciones antes del final.

split (separ)

Devuelve un array conteniendo las porciones en que queda separada la cadena por el separador indicado mediante el argumento separ, que será una expresión regular o una cadena literal. Si este separador es una cadena vacía el texto queda desglosado en todos sus caracteres. Si se omite el separador el resultado es un array de un elemento con la cadena completa. var linea=new String("Título: El portero"); var lista = linea.split(/:\s*/);

La variable lista es un array con dos elementos “Título” y “El portero”. También podríamos haberlo escrito como var linea=new String("Título: El portero"); lista = linea.split(":"); document.write(lista);

en este caso el primer elemento de lista es “Título” y el segundo ” El portero” con un espacio por delante. Por último si el separador es una cadena vacía: var linea=new String("Título: El portero"); lista = linea.split(""); document.write(lista);

la variable lista contendrá T,í,t,u,l,o,:, ,E,l, ,p,o,r,t,e,r,o.

substr(inicio, largo)

Devuelve una subcadena extraída del objeto string comenzando por la posición dada por el primer argumento, inicio, y con un número de caracteres dado por el segundo argumento, largo. Si se omite este último argumento la subcadena extraída va desde inicio hasta el final de la cadena. var linea=new String("Mi página es ideal); var lista = linea.substr(3);

La variable lista contendrá “página es ideal”. var linea=new String("Mi página es ideal); var lista = linea.substr(3, 6);

ahora la variable lista contendrá “página”.

substring(ind1,ind2)

Devuelve una subcadena del objeto string que comienza en la posición dada por el menor de los argumentos y finaliza en la posición dada por el otro argumento. Si se omite este último argumento la subcadena extraída va desde la posición indicada por el único argumento hasta el final de la cadena. Si los argumentos son literales se convierten a enteros como un parseInt(). var linea=new String("Mi página es ideal); var lista = linea.substr(3);

Page 204: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

190

La variable lista contendrá “página es ideal”. var linea=new String("Mi página es ideal); var lista = linea.substr(3, 9);

ahora la variable lista contendrá “página”, al igual que en var linea=new String("Mi página es ideal); var lista = linea.substr(9, 3);

toLowerCase()

Devuelve una cadena igual a la original pero con todos los caracteres en minúsculas. No afecta como es lógico a caracteres no alfabéticos, o sea, a los números, letras acentuadas y caracteres especiales como la Ñ

var linea=new String(" ́Hoy es Domingo"); linea = linea.toLowerCasesubstr();

La variable lista contendrá “hoy es domingo”.

toUpperCase()

Devuelve una cadena igual a la original pero con todos los caracteres en mayúsculas. No afecta como es lógico a caracteres no alfabéticos, o sea, a los números, letras acentuadas y caracteres especiales como la Ñ. Es muy útil a la hora de comparar cadenas para asegurarse que dos cadenas no difieran sólo por que algún carácter esté en mayúscula o minúscula. var linea=new String(" ́Hoy es Domingo"); linea = linea.toUpperCase();

La variable lista contendrá “HOY ES DOMINGO”.

20.7.10. Objeto Date

El objeto Date contiene un valor que representa fecha y hora de un instante dado. Para crear una instancia de este objeto usamos alguna de las siguientes sintaxis: var fecha= new Date() var fecha= new date(número) var fecha= new date(cadena) var fecha= new date(año, mes, día[, hora[, minutos[, seg[,ms]]]])

Los argumentos encerrados entre corchetes son opcionales. En la primera forma la variable fecha contendrá la fecha del día actual. La segunda opción almacena en fecha la fecha dada por el argumento como el número de milisegundos transcurridos desde la media noche del 1 de Enero de 1970. El tercer tipo se usa cuando la fecha se pasa en forma de cadena. Por último la fecha puede crearse pasándole como argumento los números de año, mes, día, hora y opcionalmente, hora, minuto, segundo y milisegundo. Los años posteriores a 1970 puede escribirse con dos dígitos, pero es aconsejable usar siempre cuatro dígitos por aquello de los efectos 2000. var hoy = new date() /*fecha del día en hoy */ var evento = new Date("November 10 1990"); var otro = new Date("10 Nov 1990"); var otro = new Date("10/02/2000"); //Oct, 2, 2000 var instante = new Date(1990, 11, 10, 20,00);

Estas son tres posibles formas de declarar objetos de tipo fecha. Las dos últimas almacenan el mismo día, pero en la última además se guarda la hora. Donde se usen cadenas para indicar una fecha podemos añadir al final las siglas GMT (o UTC) para indicar que la hora se refiere a hora del meridiano Greenwich, si no se toma como hora local, o sea, según la zona horaria configurada en el ordenador donde de ejecute el script.

Page 205: Php-Mysql

JAVASCRIPT

191

Métodos

getDate parse getDay setDate

getFullYear setFullYear getHours SetHours

getMilliseconds setMilliseconds getMinutes setMinutes getMonth setMonth

getSeconds setSeconds getTime setTime

getTimezoneOffset setYear getYear toGMT

Object.toString toLocaleString Object.valueOf toUTCString

20.7.10.1. getDate()

Nos devuelve el día del mes del objeto fecha al que se aplica. Este método controla por supuesto el número de días de cada mes y contempla el caso de años bisiestos, incluida la excepción del 2000. En el siguiente ejemplo se presenta en pantalla Hoy es día 2, suponiendo que la fecha del sistema es 2-10-200. Primero creamos la variable fecha instanciada como un objeto Date() para a continuación escribir directamente el valor de getDate() aplicado a fecha var fecha = new Date(); document.write("Hoy es día: "+fecha.getDate());

20.7.10.2. getDay()

Nos devuelve el día de la semana del objeto fecha al que se aplica en forma numérica con una cifra entre 0 para el domingo y 6 para el sábado. En el siguiente ejemplo se presenta en pantalla Hoy es 1, suponiendo que la fecha del sistema es 2-Octubre-2000, o sea, lunes. Primero creamos la variable fecha instanciada como un objeto Date() para a continuación escribir directamente el valor de getDay() aplicado a fecha var fecha = new Date(); document.write("Hoy es "+fecha.getDay());

Si echamos manos de un array podemos mejorar un poquito este ejemplo presentando el nombre del DIA de la semana: var fecha = new Date(); var diaSemana = new Array('domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes','sábado'); var dia = fecha.getDay(); document.write("Hoy es "+diaSemana[dia]);

Ahora se obtendría la más amigable frase Hoy es lunes.

20.7.10.3. getFullYear()

Nos devuelve el año correspondiente del objeto fecha en formato completo es decir incluyendo el siglo. Así si la fecha contiene 2-Octubre-2000, esta función nos dará 2000. Por ejemplo creemos la variable fecha instanciada como un objeto Date() para a continuación se presenta directamente el valor de getFullYear() aplicado a fecha, o sea, 2000.

Page 206: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

192

var fecha = new Date(); document.write("El año actual es "+fecha.getFullYear());

Este método evitaba el famoso efecto 2000 al presentar los años siempre con cuatro dígitos.

20.7.10.4. getHours()

Nos devuelve la sección horas en formato 0-24 almacenada en la parte dedicada a la hora del objeto fecha al que se aplica. Así si la fecha contiene 12:40:00, esta función nos dará 12, pero si contiene 5:40:00 nos dará 17. Igualmente el método interpreta los modificadores am / pm pero siempre devuelve la hora en formato de 24 horas. Por ejemplo creemos la variable fecha instanciada como un objeto Date(), si son las 17:30:10 el valor de getHoursr() presentará 17. var fecha = new Date(); document.write("Son las "+fecha.getHours()+" horas.");

Puedes probar que ocurre con otros valores sin necesidad de cambiar la fecha y hora del sistema de la siguiente manera: var fecha = new Date("10-02-2000 08:20:00 pm"); document.write("Son las "+fecha.getHours()+" horas.");

Este caso presentará en pantalla Son las 20 horas

20.7.10.5. getMilliseconds()

Nos devuelve los minutos de la sección dedicada a la hora almacenada en el objeto fecha al que se aplica. Así si la fecha contiene en su parte de hora 12:40:08:640, esta función nos dará 640. Por ejemplo creemos la variable fecha instanciada como un objeto Date(), si son las 17:30:08:550 el valor de getMilliseconds() presentará 550. var fecha = new Date(); document.write("Son las "+fecha.getHours() ); document.write(":" + fecha.getMinutes() ); document.write(":" + fecha.getSeconds() ); document.write(":" + fecha.getMilliseconds());

20.7.10.6. getMinutes()

Nos devuelve los minutos de la sección dedicada a la hora almacenada en el objeto fecha al que se aplica. Así si la fecha contiene en su parte de hora 12:40:08, esta función nos dará 24. Por ejemplo creemos la variable fecha instanciada como un objeto Date(), si son las 17:30:08 el valor de getMinutes() presentará 8. var fecha = new Date(); document.write("Son las "+fecha.getHours() ); document.write(":" + fecha.getMinutes() ); document.write(":" + fecha.getSeconds() );

Si queremos que quede más presentable podemos completar con ceros por la izquierda cuando el número (de horas, minutos o segundos) sea menor que 10. Esto es tan fácil como se ve en el ejemplo: var fecha = new Date(); var horas = fecha.getHours(); var mins = fecha.getMinutes(); var segs = fecha.getSeconds(); horas = (horas < 10)?"0"+horas:horas; mins = (mins < 10)?"0"+mins:mins;

Page 207: Php-Mysql

JAVASCRIPT

193

segs = (segs<10)?"0"+segs:segs; document.write("Son las "+horas); document.write(":" + mins); document.write(":" + segs);

20.7.10.7. getMonth()

Nos devuelve en forma numérica el mes correspondiente al objeto fecha al que se aplica. Así para la fecha correspondiente al 10/Oct/2000, esta función nos dará 10, el número de orden de Octubre. Por ejemplo creemos la variable fecha instanciada como un objeto Date() var fecha = new Date(); document.write("Este mes es el "+fecha.getMonth() );

Si queremos que aparezca el nombre del mes en lugar del número debemos crear primero un array de doce elementos y rellenarlos con los nombres de los meses, luego usamos el resultado de getMonth() como índice a ese array var array = new meses(); var fecha = new Date(); var nmes = fecha.getMonth(); mes[1] = "Enero"; mes[2] = "Febrero"; mes[3] = "Marzo"; mes[4] = "Abril"; ... ... document.write("Mes actual:" + meses[nmes]);

20.7.10.8. getSeconds()

Nos devuelve los segundos de la sección dedicada a la hora almacenada en el objeto fecha al que se aplica. Así si la fecha contiene en su parte de hora 12:40:08, esta función nos dará 8. Por ejemplo creemos la variable fecha instanciada como un objeto Date(), si son las 17:30:08 el valor de getSeconds() presentará 8. var fecha = new Date(); document.write("Son las "+fecha.getHours() ); document.write(":" + fecha.getMinutes() ); document.write(":" + fecha.getSeconds() );

Si queremos que quede mas presentable podemos completar con ceros por la izquierda cuando el número (de horas, minutos o segundos) sea menor que 10. Esto es tan fácil como se ve en el ejemplo: var fecha = new Date(); var horas = fecha.getHours(); var mins = fecha.getMinutes(); var segs = fecha.getSeconds(); horas = (horas < 10)?"0"+horas:horas; mins = (mins < 10)?"0"+mins:mins; segs = (segs<10)?"0"+segs:segs; document.write("Son las "+horas); document.write(":" + mins); document.write(":" + segs);

20.7.10.9. getTime()

Nos devuelve la cantidad de milisegundos transcurridos desde el 1 de Enero de 1970 hasta la hora almacenada en el objeto fecha al que se aplica. En el ejemplo que sigue creamos un objeto Date con la fecha actual, a continuación escribimos el número de milisegundos dado por este función, verás que este número habitualmente es muy grande, realmente esta función puede ser útil para calcular el tiempo transcurrido entre dos instantes, por ejemplo en un puzzle podría ser útil para calcular el tiempo que el

Page 208: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

194

jugador emplea en resolver el puzzle, restando el getTime() obtenido al final del juego del getTime() obtenido al inicio. var ahora = new Date(); document.write(ahora.getTime());

20.7.10.10. getTimezoneOffset()

Esta función nos da la diferencia horaria en minutos del ordenador con respecto al meridiano de Greenwich. El valor depende por tanto de la zona o huso horario para el que esté configurado el ordenador, pudiendo ser negativo o positivo según esté en la zona oriental u occidental. El ejemplo que muestra el uso de la función define la variable ahora con la fecha actual y devuelve en minutos la diferencia horaria con la GMT, el resultado depende de tu ordenador. var ahora = new Date(); document.write(ahora.getTimezoneOffset());

20.7.10.11. getYear()

Nos devuelve en forma numérica el mes correspondiente al objeto fecha al que se aplica. Por ejemplo creamos la variable fecha instanciada como un objeto Date(), y luego extraemos el año var fecha = new Date(); document.write("Este año es el "+fecha.getYear());

20.7.10.12. Object.toString() y Object.valueOf

Los casos Object.toString, y Object.valueOf, ya fueron explicados en el apartado E) Objeto Object.

20.7.10.13. parse(fecha)

Nos devuelve la cantidad de milisegundos transcurridos desde el 1 de Enero de 1970 00:00:00 hasta la hora pasada en el argumento fecha como una cadena de caracteres. Este método es un método global del objeto y por tanto no es necesario crear un objeto Date para usarlo, como vemos en este ejemplo. var transcurridos = Date.parse("1/1/2000 00:00:00"); document.write(transcurridos);

20.7.10.14. setDate(diames)

Nos permite cambiar el día del mes del objeto fecha al que se aplica para poner el valor que se pasado en el argumento diames. Este método controla por supuesto el número de días de cada mes y contempla el caso de años bisiestos, incluida la excepción del 2000, de forma que si pasamos como argumento 31 y el mes es de 30 días la función corrige la fecha completa pasándola al día 1 del mes siguiente. Esto lo vemos en el ejemplo que sigue: creamos una variable como un objeto Date con el último día de Septiembre (mes de 30 días) e intentamos poner el día a 31, luego comprobamos la fecha almacenada: var fecha = new Date("1 Sep 2000"); fecha.setDate(31); document.write("Hoy es día: "+fecha.toString());

Como verás si pruebas el ejemplo la fecha es corregida y pasa a 1 de Octubre.

Page 209: Php-Mysql

JAVASCRIPT

195

20.7.10.15. setFullYear()

Nos permite cambiar el año del objeto fecha por el valor pasado como argumento, un número interpretado como año completo, o sea, que para poner el año 1995 se debe pasar 1995, no el 95. El ejemplo pone precisamente este valor en el campo año de la variable fecha. var fecha = new Date(); fecha.setFullYear(1995) document.write(fecha.toString());

20.7.10.16. setHours()

Nos permite modificar la hora almacenada en el objeto fecha al que se aplica y poner la que se pasa como argumento. Lógicamente este argumento estará entre 0 y 24, aunque si se usa un valor fuera de este rango la fecha es corregida en consecuencia. Por ejemplo si intentamos poner la hora en 30 la fecha se adelanta 24 horas y se pone en las 6 horas, cambiando además el día. Igualmente si se usa un número negativo en el argumento se toma como horas antes de la última media noche del mismo día. Observa todo esto en el ejemplo, donde al final de cada acción se presenta la fecha completa en forma de cadena: var fecha = new Date("10 Sep 2000 00:00:00"); var nl="<br>"; fecha.setHours(20); document.write("A las 20: "+fecha.toString()+nl); fecha.setHours(30); document.write("A las 30: "+fecha.toString()+nl); fecha.setHours(-2); document.write("A las -2: "+fecha.toString()+nl);

20.7.10.17. setMilliseconds()

Nos permite modificar el número de milisegundos de la hora almacenada en el objeto fecha al que se aplica, poniendo los milisegundos al valor pasado como argumento. Habitualmente el argumento estará comprendido entre 0 y 1000. var fecha = new Date("10 Sep 2000 00:00:00"); var nl="<br>"; fecha.setMilliSeconds(900); document.write(fecha.toString()+nl);

20.7.10.18. setMinutes(minact)

Nos permite ajustar los minutos de la sección dedicada a la hora almacenada en el objeto fecha al que se aplica. El nuevo valor para los minutos se pasa como argumento, que habitualmente estará entre 0 y 59, aunque un valor fuera de este rango no da error sino que ajusta el resto de la hora. Así 68 en el argumento adelanta el reloj una hora pone los minutos a 8, mientras que un -4 pone los minutos a 56 (60 menos 4). Puedes ver lo que ocurre en este ejemplo. var fecha = new Date("10 Sep 2000 00:00:00"); var nl="<br>"; fecha.setMinutes(20); document.write("Minact 20: "+fecha.toString()+nl); fecha.setMinutes(68); document.write("Minact 68: "+fecha.toString()+nl); fecha.setMinutes(-4); document.write("Minact -4: "+fecha.toString()+nl);

Como ves si es necesario, se ajusta la hora cuando el número de minutos supera el valor 59

Page 210: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

196

20.7.10.19. setMonth(nummes)

Esta función se usa para modificar el mes del objeto fecha al que se aplica. El nuevo valor se pasa como un número en el argumento. El valor deberá ser como es lógico numérico o convertible a numérico y comprendido entre 0 (Enero) y 11 (Diciembre). Si el valor está fuera del rango se toma el exceso sobre 11 y se corrige adecuadamente la fecha, y si es negativo se toma como número de meses antes de Enero (-1 sería Diciembre, -2 sería Noviembre, etc.). El ejemplo es muy sencillo, en este caso se cambia el mes de Septiembre por Marzo. var fecha = new Date("10 Sep 2000 00:00:00"); fecha.setMonth(2); document.write("Minact 20: "+fecha.toString());

20.7.10.20. setSeconds(miliseg)

Nos permite modificar el número de segundos de la hora almacenada en el objeto fecha al que se aplica, poniendo los segundos al valor pasado como argumento. Habitualmente el argumento estará comprendido entre 0 y 60. var fecha = new Date("10 Sep 2000 00:00:00"); var nl="<br>"; fecha.setSeconds(90); document.write(fecha.toString()+nl);

20.7.10.21. setTime()

Nos devuelve la cantidad de milisegundos transcurridos desde el 1 de Enero de 1970 hasta la hora almacenada en el objeto fecha al que se aplica. En el ejemplo que sigue creamos un objeto Date con la fecha actual, a continuación escribimos el número de milisegundos dado por este función, verás que este número habitualmente es muy grande, realmente esta función puede ser útil para calcular el tiempo transcurrido entre dos instantes, por ejemplo en un puzzle podría ser útil para calcular el tiempo que el jugador emplea en resolver el puzzle, restando el setTime() obtenido al final del juego del setTime() obtenido al inicio. var ahora = new Date(); document.write(ahora.setTime());

20.7.10.22. setYear()

Nos permite cambiar el año del objeto fecha por el valor pasado como argumento, un número interpretado como año completo, o sea, que para poner el año 1995 se debe pasar 1995, no el 95. El ejemplo pone precisamente este valor en el campo año de la variable fecha. var fecha = new Date(); fecha.setFullYear(1995) document.write(fecha.toString());

20.7.10.23. toLocaleString()

Esta función se usa para transformar el objeto fecha al que se aplica a una cadena de caracteres según el estándar UTC (Universal Time Coordinates), denominación actual del GMT (Greenwich Meridian Time). La hora se ajusta según la configuración del ordenador. En el ejemplo que sigue la cadena devuelta será “Mon, 10 Apr 2000 02:00:00 UTC” var fecha = new Date("10 Apr 2000 02:00:00"); document.write(fecha.toUTCString());

Page 211: Php-Mysql

JAVASCRIPT

197

Como ves existe una diferencia en la hora almacenada y la devuelta por la función, esto es debido a que la cadena devuelta es la hora correspondiente a Greenwich, no la local del ordenador.

Existe una función similar, la toGMTString(), que es considerada como obsoleta y que se mantiene por cuestiones de compatibilidad.

20.7.10.24. toUTCString(fecha)

Nos devuelve la cantidad de milisegundos transcurridos desde el 1 de Enero de 1970 00:00:00 hasta la hora pasada en el argumento fecha. Este argumento se pasa como una serie de números separados por comas en el orden: Año, mes, día, y opcionalmente: hora, minuto, segundos. Este método es un método global del objeto y por tanto no es necesario crear un objeto Date para usarlo, como vemos en este ejemplo que toma como fecha actual el 1 de Noviembre de 2000 a las 00:00:00. var transc= Date.UTC(2000,10,1); document.write(transc);

20.7.11. Objeto Math

Es el objeto que usa JavaScript para dotar al lenguaje de funciones matemáticas avanzadas y de constantes predefinidas, como el número PI.

Propiedades

Son las habituales constantes como el número e, PI y algunos otros valores habituales en cálculos matemáticos.

E LN10 LOG10E SQRT1_2 LN2 LOG2E PI SQRT2 Constante de Euler, la base para los

logaritmos naturales

Logaritmo natural de

10

Logaritmo en base 10

de E

Raíz cuadrada de 0.5 o sea la

inversa de la raiz de 2

Logaritmo natural de

2

Logaritmo en base 2

de E

El conocido número pi

Raíz cuadrada de

2

20.7.11.1. Métodos

Metodo Descripción abs Valor absoluto cos coseno pow Potencia de acos Arco coseno exp Exponencial

random Número al azar asin Arco seno floor Redondeo inferior found Redondear atan Arco tangente log Logaritmo natural sin Seno

atan2 Arco tangente

Page 212: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

198

max máximo sqrt Raíz cuadrada ceil Redondeo superior min Mínimo Tan Tangente

Veamos algunos de los más usados

abs(exprnum)

Devuelve el valor absoluto, o sea, sin signo, del argumento. Si el argumento fuera no entero será convertido a numérico siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var numabs = Math.abs( - 45)

la variable numabs contendrá el valor 45.

ceil(exprnum)

Devuelve el valor del argumento redondeado por exceso, es decir el menor número entero mayor o igual al argumento. Si el argumento fuera no numérico será convertido a numérico siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var redexceso = Math.ceil( 4.25)

la variable redexceso contendrá el valor 5.

floor(exprnum)

Devuelve el valor del argumento redondeado por defecto, es decir, el mayor número entero menor o igual al argumento. Si el argumento fuera no numérico será convertido a numérico siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var redexceso = Math.floor( 4.75)

la variable redexceso contendrá el valor 4.

max(num1, num2)

Devuelve el mayor de los dos números o expresiones numéricas pasadas como argumentos. Si alguno de los argumentos fuera no numérico será convertido a numérico siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var mayor = Math.wax( 12, 5)

la variable mayor contendrá el valor 12.

min(num1, num2)

Devuelve el menor de los dos números o expresiones numéricas pasadas como argumentos. Si alguno de los argumentos fuera no numérico será convertido a numéricos siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var menor = Math.min( 12, 5

la variable menor contendrá el valor 5.

random()

Page 213: Php-Mysql

JAVASCRIPT

199

Calcula un número aleatorio, realmente seudo-aleatorio, comprendido entre 0 y 1 ambos inclusive. Cada vez que se carga el intérprete de JavaScript se genera una semilla base para el cálculo. No lleva argumentos y su sintaxis es tan simple como el ejemplo: var azar = Math.random()*10

la variable azar contendrá un número al azar entre 0 y 10.

round(exprnum)

Devuelve el valor entero mas próximo al número pasado como argumento, es decir, redondea. Si la parte decimal del argumento es 0.5 o mayor devuelve el primer entero por encima del argumento (redondeo por exceso) en caso contrario devuelve el entero anterior al argumento (redondeo por defecto). Si el argumento fuera no entero será convertido a numérico siguiendo las reglas de la función parseInt() o parseFloat(). Su sintaxis es tan simple como el ejemplo: var entero1 = Math.random(4.25) var entero2 = Math.random(4.65)

la variable entero1 contendrá el valor 4 mientras entero1 que contendrá 5.

20.7.12. Objeto Regular Expession

Antes de ver este objeto, debemos saber saber algo acerca de las expresiones regulares.

20.7.12.1. Qué son las expresiones regulares

Las expresiones regulares constituyen un mecanismo bastante potente para realizar manipulaciones de cadenas de texto. El proceso para el que se usan estas expresiones, presente en el mundo el UNIX y el lenguaje Perl, es el de buscar y/o sustituir una subcadena de texto dentro de otra cadena. En principio esto puede hacerse usando los métodos del objeto string, pero el problema surge cuando no tenemos una subcadena fija y concreta sino que queremos buscar un texto que responda a un cierto esquema, como por ejemplo: buscar aquellas palabras que comienzan con http: y finalizan con una \, o buscar palabras que contengan una serie de números consecutivos, etc.; es en estos casos cuando las expresiones regulares muestran toda su potencia. La subcadena que buscamos en el texto es lo que se llama un patrón y se construye encerrando entre dos barras inclinadas ( / ) una serie de caracteres normales y símbolos especiales llamados comodines o metacaracteres, (algo parecido a la orden dir *.bat usada en el DOS cuando queríamos listar los ficheros con extensión bat). Este patrón es una descripción del texto que se está buscando y JavaScript encontrará las subcadenas que concuerdan con ese patrón o definición. Las expresiones regulares se usan con el objeto Regular Expresion y también dentro de los métodos String.match, String.replace, String.search y String.split.

En la tabla que sigue se muestran los caracteres comodín usados para crear los patrones y su significado, junto a un pequeño ejemplo de su utilización.

Carácter Significado Ejemplo Resultado \ Marca de carácter

especial /\$ftp/ Busca la palabra $ftp

^ Comienzo de una línea /^-/ Líneas que comienzan por -

$ Final de una línea /s$/ Líneas que terminan por s

. Cualquier carácter /\b.\b/ Palabras de una sola

Page 214: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

200

(menos salto de línea) letra | Indica opciones /(L|l|f|)ocal/ Busca Local, local,

focal ( ) Agrupar caracteres /(vocal)/ Busca vocal [ ] Conjunto de caracteres

opcionales /escrib[aoe]/ Vale escriba, escribo,

escribe

La tabla que sigue describe los modificadores que se pueden usar con los caracteres que forman el patrón. Cada modificador actúa sobre el carácter o el paréntesis inmediatamente anterior.

Carácter Descripción Ejemplo Resultado * Repetir 0 o mas veces /l*234/ Valen 234, 1234,

11234… + Repetir 1 o mas veces /a*mar/ Valen amar, aamar,

aaamar… ? 1 o 0 veces /a?mar/ Valen amar, mar.

{n} Exactamente n veces /p{2}sado/ Vale ppsado {n,} Al menos n veces /(m){2}ala/ Vale mmala,

mmmala…. {m,n} entre m y n veces /tal{1,3}a/ Vale tala, talla, tallla

Los siguientes son caracteres especiales o metacaracteres para indicar caracteres de texto no imprimibles, como puedan ser el fin de línea o un tabulador, o grupos predefinidos de caracteres (alfabéticos, numéricos, etc…)

Caracteres Descripción Ejemplo Resultado \b Principio o final de

palabra /\bver\b/ Encuentra ver en “ver

de”, pero no en “verde” \B Frontera entre no-

palabras /\Bver\B/ Empareja ver con

“Valverde” pero no con “verde”

\d Un dígito /[A-Z]\d/ No falla en “A4” \D Alfabético (no dígito) /[A-Z]\D/ Fallaría en “A4” \O Carácter nulo \t Caracter ASCII 9

(tabulador)

\f Salto de página \n Salto de línea \w Cualquier

alfanumérico, [a-zA-Z0-9_ ]

/\w+/ Encuentra frase en “frase.”, pero no el .

(punto). \W Opuesto a \w ([^a-zA-

Z0-9_ ]) /\W/ Hallaría sólo el punto

(.) \s Carácter tipo espacio

(como tab) /\sSi\s/ Encuentra Si en “Digo

Si ”, pero no en “Digo Sientate”

\S Opuesto a \s \cX Carácter de control X \c9 El tabulador

\oNN Carácter octal NN \xhh El hexadecimal hh /\x41/ Encuentra la A (ASCII

Hex41) en “letra A”

Y después de esta introducción, ahora sí.

Page 215: Php-Mysql

JAVASCRIPT

201

20.7.12.2. El objeto RegExp

JavaScript usa este objeto para trabajar con patrones de expresiones regulares, estos patrones se crean como cualquier otro objeto mediante su inicialización directo o bien mediante el constructor new RegExp(), como podemos ver en el ejemplo: var mipatron = /^[aeiou]/gi var mipatron2 = new RegExp("^[aeiou]", "gi")

Ambas formas conducen al mismo patrón, en este ejemplo define palabras que comienzan con una vocal. El patrón puede llevar modificadores o flags para matizar la forma de buscar, en el ejemplo se usan dos: g i Estos modificadores tienen los siguientes significados:

flags Significado g Explorar la cadena completa i No distinguir mayúsculas de minúsculas m Permite usar varios ^ y $ en el patrón

Estos patrones poseen en total tres métodos exec(), test(), compile() además de los métodos ya citados del objeto String que también usan patrones como son: match(), replace(), search() y split(). La única propiedad que funciona en estos objetos es la propiedad source que refleja el contenido del patrón. En el patrón pueden aparecer caracteres o grupos de caracteres encerrados entre paréntesis, posteriormente podemos usar un índice para referirnos individualmente al contenido de esos paréntesis.

Por ejemplo vamos a sustituir por un - todas los dígitos situados tras una letra en la cadena a explorar. var cadexp = "234879x089h9y7"; var patron = /([a-z])(\d)/ig; document.write(cadexp+'<br> '); cadexp = cadexp.replace(patron, "$2-"); document.write(cadexp)

Como ves donde antes existía un dígito seguido de una letra ahora hay un dígito seguido de un guión. Las coincidencias con el primer paréntesis del patrón están en $1 y con el segundo en $2. La primera coincidencia hallada es x0, luego $1 contiene x y $2 contiene 0, sustituyo lo hallado con -$2, o sea, quito $1 y pongo un guión y me quedará -0 en lugar de x0. Como se ha usado el flag g (global) esta operación se realiza en toda la cadena.

compile (cadpatr)

Un patrón de búsqueda puede construirse mediante una simple asignación o mediante el constructor new RegExp y ser utilizada tal cual, pero se puede mejorar bastante la búsqueda usando este método que convierte el patrón en un formato interno para optimizar su uso. Utiliza como argumento una cadena que representa la expresión regular que se quiere compilar var patron = new RegExp(); patron.compile("\\D-"); var busq = patron.exec("1234u90t-789"); document.write('Buscando '+patron.source+'<br>'); document.write(busq[0]+' está en la posición ' + busq.index +' de busq.input');

En este ejemplo se busca cualquier no numérico seguido de un guión en la cadena “1234u90t-789”. Primero se declara la variable patron y se compila con el patrón \D- que indica cualquier carácter no numérico seguido de guión. Por último muestra el patrón usado y los resultados de la búsqueda: coincidencia encontrada, posición y cadena explorada.

Page 216: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

202

exec (cadexplor)

Este método busca la primera concordancia del patrón con el contenido de la cadena de texto donde se busca, que se le pasa como argumento. Si no encuentra ninguna concordancia devuelve null, pero encuentra una secuencia de caracteres que se adapte al patrón de búsqueda devuelve un array cuyo primer elemento indica la concordancia encontrada y las restantes indican los resultados de acuerdo a los paréntesis que aparezcan en la expresión regular. Además este array posee dos propiedades: index,para indicar la posición de la subcadena encontrada, y input, que contiene la cadena de caracteres que se está explorando. Además modifica las propiedades de una variable global RegExp con datos relativos a la búsqueda. En el ejemplo que sigue buscamos cualquier letra seguida de un número y de un guión, el patrón de búsqueda será /[a..z]\d- /i, [a..z] representa todas las letras del abecedario, \d representa cualquier número y el modificador i se usa para no diferenciar mayúsculas de minúsculas. patron = /[a..z]D\d-/i; var busca = new Array() busca = patron.exec("3c491a-9d1d6-91br"); if (busca != null){ document.write("Concuerda en: "+busca.index + '<br>'); document.write("Explorando:" +busca.input + '<br>'); document.write("Hallado: " + busca[0] + '<br>'); } document.write("Resto " + RegExp.rightContext + '<br>');

test (cadexp)

Este es el método más simple del objeto expresión regular, tan sólo comprueba si existe alguna coincidencia en la cadena explorada, pasada como argumento, con el patrón de búsqueda. Si existe tal coincidencia devuelve un valor booleano true y en caso contrario devuelve false. Además afecta a las propiedades del objeto global RegExp. var patron = new RegExp("Lunes","gi"); var cadexpl = "La reunión es el lunes o el martes."; var eslunes = patron.test(cadexpl); document.write("¿Es el lunes? "+eslunes+'<br>'); document.write("Hallado en "+RegExp.index);

En este sencillo ejemplo se comprueba si la cadena explorada, cadexpl, contiene la palabra “lunes”, sin considerar la caja (mayúsculas o minúsculas). El resultado lo guarda en la variable eslunes.

20.7.12.3. Variable global RegExp

Se trata de una variable global usada por JavaScript cuando realiza operaciones donde intervengan expresiones regulares. Cada vez que se realiza una de estas operaciones se modifican las propiedades de esta variable. Es una variable que puede consultarse pero que no se puede modificar directamente, es de sólo lectura. No tiene ningún método asociado y sus propiedades siempre hacen referencia a una operación de búsqueda, sea con los métodos de un objeto Regular Expresion o del objeto string.

Propiedades

$1..$9:

Estos índices contienen las partes agrupadas con paréntesis en el patrón de búsqueda.

input

Cadena que se ha explorado.

Page 217: Php-Mysql

JAVASCRIPT

203

lastmatch

Última coincidencia encontrada.

multiline

Variable booleana que indica si la cadena explorada incluye saltos de línea.

lastParen

Última coincidencia encontrada con un patrón entre paréntesis.

leftContext

Toda la cadena hasta la coincidencia hallada.

rightContext

Toda la cadena desde la coincidencia hasta el final de la cadena. Estas propiedades sólo son de lectura y son actualizadas cada vez que se realiza alguna búsqueda con patrón, sea con los métodos de una expresión regular o con los de String. En el siguiente ejemplo se puede observar estos valores tras una operación de búsqueda. var patron= /\D(\d)(\D)/g; var buscaren = "abde5fghj45oi"; var hallado = patron.exec(buscaren); var item; document.write("$1: "+RegExp.$1+"<br>"); document.write("$2: "+RegExp.$2+"<br> "); document.write("input: "+RegExp.input+"<br> "); document.write("index: "+RegExp.index+"<br> "); document.write("lastIndex: "+RegExp.lastIndex+"<br> ") ; document.write("multiline: "+RegExp.multiline+"<br>"); document.write("lastMatch: "+RegExp.lastMatch+"<br>"); document.write("lastParen: "+RegExp.lastParen +"<br>"); document.write("leftContext: "+RegExp.leftContext +"<br>"); document.write("rightContext:"+RegExp.rightContext+"<br>");

Es posible que no todas las propiedades sean reconocidas por todos los navegadores.

20.8. Eventos

20.8.1. Eventos en JavaScript

En JavaScript, la interacción con el usuario se consigue mediante la captura de los eventos que éste produce. Un evento es una acción del usuario ante la cual puede realizarse algún proceso (por ejemplo, el cambio del valor de un formulario, o la pulsación de un enlace).

Los eventos se capturan mediante los manejadores de eventos. El proceso a realizar se programa mediante funciones JavaScript llamadas por los manejadores de eventos.

La siguiente tabla muestra los manejadores de eventos que pueden utilizarse en JavaScript, la versión a partir de la cual están soportados y su significado.

Page 218: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

204

Manejador Versión Se produce cuando… onAbort 1.1 El usuario interrumpe la carga

de una imagen

onBlur 1.0 Un elemento de formulario, una ventana o un marco pierden el

foco onChange 1.0 (1.1 para FileUpload) El valor de un campo de

formulario cambia onClick 1.0 Se hace click en un objeto o

formulario onDblClick 1.2 (no en Mac) Se hace click doble en un

objeto o formulario onDragDrop 1.2 El usuario arrastra y suelta un

objeto en la ventana onError 1.1 La carga de un documento o

imagen produce un error onFocus 1.1 (1.2 para Layer) Una ventana, marco o elemento

de formulario recibe el foco onKeyDown 1.2 El usuario pulsa una tecla onKeyPress 1.2 El usuario mantiene pulsada

una tecla onKeyUp 1.2 El usuario libera una tecla onLoad 1.0 (1.1 para image) El navegador termina la carga

de una ventana onMouseDown 1.2 El usuario pulsa un botón del

ratón onMouseMove 1.2 El usuario mueve el puntero onMouseOut 1.1 El puntero abando una área o

enlace onMouseOver 1.0 (1.1 para area) El puntero entra en una área o

imagen onMouseUp 1.2 El usuario libera un botón del

ratón onMove 1.2 Se mueve una ventana o un

marco onReset 1.1 El usuario limpia un formulario onResize 1.2 Se cambia el tamaño de una

ventana o marco onSelect 1.0 Se selecciona el texto del

campo texto o área de texto de un formulario

onSubmit 1.0 El usuario envía un formulario onUnload 1.0 El usuario abandona una página

Ejemplo de evento: <INPUT TYPE="text" onChange="CompruebaCampo(this)">

En este ejemplo, CompruebaCampo() es una función JavaScript definida en alguna parte del documento HTML (habitualmente en la cabecera del mismo). El identificador this es una palabra propia del lenguaje, y se refiere al objeto desde el cual se efectua la llamada a la función (en este caso, el campo del formulario).

Page 219: Php-Mysql

JAVASCRIPT

205

La siguiente tabla muestra los eventos que pueden utilizarse con los objetos del modelo de objetos JavaScript del Navigator.

Manejador de evento Objetos para los que está definido onAbort Image onBlur Button, Checkbox, FileUpload, Layer,

Password, Radio, Reset, Select, Submit, Text, Textarea, window

onChange FileUpload, Select, Text, Textarea onClick Button, document, Checkbox, Link, Radio,

Reset, Submit onDblClick document, Link onDragDrop window

onError Image, window onFocus Button, Checkbox, FileUpload, Layer,

Password, Radio, Reset, Select, Submit, Text, Textarea, window

onKeyDown document, Image, Link, Textarea onKeyPress document, Image, Link, Textarea onKeyUp document, Image, Link, Textarea onLoad Image, Layer, window

onMouseDown Button, document, Link onMouseMove Ninguno (debe asociarse a uno) onMouseOut Layer, Link onMouseOver Layer, Link onMouseUp Button, document, Link

onMove window onReset Form onResize window onSelect Text, Textarea onSubmit Form onUnload window

20.8.2. Métodos de evento disponibles en JavaScript

Los siguientes métodos de evento pueden utilizarse en JavaScript:

Métodos de evento Función que realizan blur() Elimina el foco del objeto desde el que se llame click() Simula la realización de un click sobre el objeto

desde el que se llame focus() Lleva el foco al objeto desde el que se llame select() Selecciona el área de texto del campo desde el

que se llame submit() Realiza el envío del formulario desde el que se

llame

Ejemplo:

Page 220: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

206

<HTML> <HEAD><TITLE>Eventos</TITLE> <SCRIPT> <!-- function Reacciona(campo) { alert("¡Introduzca un valor!") campo.focus() } //--> </SCRIPT></HEAD> <BODY> <FORM METHOD=POST> <INPUT TYPE=text NAME=campo onFocus="Reacciona(this)"> </FORM> </BODY> </HTML>

20.8.2.1. Eventos onLoad y onUnload

Se usan como atributos del tag <BODY> de HTML.

Ejemplo: <BODY onLoad="Hola()" onUnload="Adios()">

La función Hola() se ejecutará antes de que se cargue la página y la función Adios() al abandonarla.

Ejemplo: <HTML> <HEAD> <TITLE>Ejemplo onLoad y onUnload</TITLE> </HEAD> <BODY onLoad="alert('¡Bienvenido a mi página!')" onUnload="alert('¡Vuelva pronto!')"> ... </BODY> </HTML>

20.9. Actividades

Con las actividades veremos tambien algunos eventos.

20.9.1. Actividad 1

Realiza una página que contenga código JavaScript para escribir en el documento directamente el mensaje “Hola a todos”. Haz que el script se ejecute al cargarse la página.

20.9.2. Actividad 2

Realiza una página que muestre el mensaje “Hola a todos” en una ventana haciendo una llamada a una función JavaScript al pulsar un boton. Utilizar la función Alert().

20.9.3. Actividad 3

Page 221: Php-Mysql

JAVASCRIPT

207

Entrada y salida de página. Realiza una página que muestre el mensaje “Bienvenido” al entrar en la página y muestre el mensaje “Adios” al salir de la página mediante Alert(). (Eventos onLoad y onUnload)

20.9.4. Actividad 4

Realiza una página para calcular los números primos entre 1 y 100.

20.9.5. Actividad 5

OnMouseOver(). Realiza una página que muestre cinco cuadrados de diferentes colores. Cuando el raton pase por encima de alguno de ellos el color de fondo será del color de relleno del cuadrado.

20.9.6. Actividad 6

Conversor monetario. Realiza una página que muestre un formulario para la conversión de Euros a Pesetas o viceversa. Los campos del formulario han de poder ser limpiados.

20.9.7. Actividad 7

Saludo. Realiza una página que pregunte el nombre de entrada y muestre una página con un saludo. Distinguir la hora del día para saber si es por la mañana, por la tarde o por la noche.

20.9.8. Actividad 8

Arrays. Leer una cadena de texto en un formulario y generar un array con la función split(). Posteriormente, mostrar la siguiente información: Número de palabras, primera palabra, última palabra, las palabras colocadas en orden inverso, las palabras ordenadas de la a la z y las palabras ordenadas de la z a la a. Sacar toda esta información en una ventana nueva.

20.9.9. Actividad 9

Coordenadas de ratón en la barra de estado. Realiza una página que capture las coordenadas de ratón y las muestre en la barra de estado.

20.9.10. Actividad 10

Reloj edit box. Realiza una página que muestre la fecha y la hora actual en un reloj que se va actualizando.

20.9.11. Actividad 11

Page 222: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

208

Verficación formulario. Realiza una página que muestre un formulario y verifique la entrada de un número que esté comprendido entre 1..100.

20.9.12. Actividad 12

Test radio button. Realiza una página que efectúe test de evaluación a través de radio button de tres opciones. La página prporcionará la evaluación y las respuesta correctas a petición del usuario.

20.9.13. Actividad 13

Calculadora tabla formulario. Realiza una página implemente una calculadora aritmética. Para ello haz uso de una tabla y un formulario.

20.9.14. Actividad 14

Cambio de imágenes. Realiza una página que muestre una imagen que cambie cuando el ratón en pase por encima de la imagen y que vuelva a cambiar cuando salga de ella.

20.9.15. Actividad 15

Dado. Hacer una página que simule el lanzamiento de un dado.

20.9.16. Actividad 16

Esconder elementos. Realiza una página haga desaparecer elementos al paso del ratón y los muestre con un click de ratón sobre texto.

20.9.17. Actividad 17

Formulario Select. Realizar una página que permita modificar (añadir, borrar, modificar) al gusto del usuario los contenidos de un elemento SELECT de un formulario.

20.9.18. Actividad 18

Posición y tamaño. Realizar una página que permita controlar la posición y tamaño de otra ventana a través de un pequeño formulario.

20.9.19. Actividad 19

Estadística de cadenas de texto. Realiza una página que contenga una función JavaScript para hacer estadísticas sobre una cadena de texto que se le pase, contando el número de veces que aparece cada letra. Utilizar un Array para almacenar la información estadística.

Page 223: Php-Mysql

JAVASCRIPT

209

20.10. Introducción a XML

XML, siglas en inglés de Extensible Markup Language (lenguaje de marcas extensible), es un metalenguaje extensible de etiquetas desarrollado por el World Wide Web Consortium (W3C). Es una simplificación y adaptación del SGML y permite definir la gramática de lenguajes específicos (de la misma manera que HTML es a su vez un lenguaje definido por SGML). Por lo tanto XML no es realmente un lenguaje en particular, sino una manera de definir lenguajes para diferentes necesidades. Algunos de estos lenguajes que usan XML para su definición son XHTML, SVG, MathML.

XML no ha nacido sólo para su aplicación en Internet, sino que se propone como un estándar para el intercambio de información estructurada entre diferentes plataformas. Se puede usar en bases de datos, editores de texto, hojas de cálculo y casi cualquier cosa imaginable.

XML es una tecnología sencilla que tiene a su alrededor otras que la complementan y la hacen mucho más grande y con unas posibilidades mucho mayores. Tiene un papel muy importante en la actualidad ya que permite la compatibilidad entre sistemas para compartir la información de una manera segura, fiable y fácil.

20.10.1. Historia

XML proviene de un lenguaje inventado por IBM en los años setenta, llamado GML (Generalized Markup Language), que surgió por la necesidad que tenía la empresa de almacenar grandes cantidades de información. Este lenguaje gustó a la ISO, por lo que en 1986 trabajaron para normalizarlo, creando SGML (Standard Generalized Markup Language), capaz de adaptarse a un gran abanico de problemas. A partir de él se han creado otros sistemas para almacenar información.

En el año 1989 Tim Berners Lee creó la web, y junto con ella el lenguaje HTML. Este lenguaje se definió en el marco de SGML y fue de lejos la aplicación más conocida de este estándar. Los navegadores web sin embargo siempre han puesto pocas exigencias al código HTML que interpretan y así las páginas web son caóticas y no cumplen con la sintaxis. Estas páginas web dependen fuertemente de una forma específica de lidiar con los errores y las ambigüedades, lo que hace a las páginas más frágiles y a los navegadores más complejos.

Se buscó entonces definir un subconjunto del SGML que permitiera:

Mezclar elementos de diferentes lenguajes. Es decir que los lenguajes sean extensibles.

La creación de analizadores simples, sin ninguna lógica especial para cada lenguaje.

Empezar de cero y hacer hincapié en que no se acepte nunca un documento con errores de sintaxis.

Para hacer esto XML deja de lado muchas características de SGML que estaban pensadas para facilitar la escritura manual de documentos. XML en cambio está orientado a hacer las cosas más sencillas para los programas automáticos que necesiten interpretar el documento.

20.10.2. Ventajas del XML

Page 224: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

210

Es extensible: Después de diseñado y puesto en producción, es posible extender XML con la adición de nuevas etiquetas, de modo que se pueda continuar utilizando sin complicación alguna.

El analizador es un componente estándar, no es necesario crear un analizador específico para cada versión de lenguaje XML. Esto posibilita el empleo de cualquiera de los analizadores disponibles. De esta manera se evitan bugs y se acelera el desarrollo de aplicaciones.

Si un tercero decide usar un documento creado en XML, es sencillo entender su estructura y procesarla. Mejora la compatibilidad entre aplicaciones.

20.10.3. XHTML

En el caso de HTML sucede que cada documento pertenece a un vocabulario fijo, establecido por otro fichero llamado “DTD”, que explicaremos más adelante. No se pueden combinar elementos de diferentes vocabularios. Asimismo es imposible para un intérprete (por ejemplo un navegador) analizar el documento sin tener conocimiento de su gramática (del DTD). Por ejemplo, el navegador sabe que antes de una etiqueta <div> debe haberse cerrado cualquier <p> previamente abierto. Los navegadores resolvieron esto incluyendo lógica ad hoc para el HTML, en vez de incluir un analizador genérico. Ambas opciones, de todos modos, son muy complejas para los navegadores. Para resolver estos problemas de compatibilidad entre XML y HTML, vino a la palestra, XHTML.

XHTML, acrónimo en inglés de eXtensible Hypertext Markup Language (lenguaje extensible de marcado de hipertexto), es el lenguaje de marcado pensado para sustituir a HTML como estándar para las páginas web. En su versión 1.0, XHTML es solamente la versión XML de HTML, por lo que tiene, básicamente, las mismas funcionalidades, pero cumple las especificaciones, más estrictas, de XML. Su objetivo es avanzar en el proyecto del World Wide Web Consortium de lograr una web semántica, donde la información, y la forma de presentarla estén claramente separadas. La versión 1.1 es similar, pero parte a la especificación en módulos. En sucesivas versiones la W3C planea romper con los tags clásicos traídos de HTML.

20.10.4. Estructura de un documento XML

La tecnología XML busca dar solución al problema de expresar información estructurada de la manera más abstracta y reutilizable posible. Que la información sea estructurada quiere decir que se compone de partes bien definidas, y que esas partes se componen a su vez de otras partes. Entonces se tiene un árbol de pedazos de información. Ejemplos son un tema musical, que se compone de compases, que están formados a su vez por notas. Estas partes se llaman elementos, y se las señala mediante etiquetas.

Una etiqueta consiste en una marca hecha en el documento, que señala una porción de éste como un elemento. Un pedazo de información con un sentido claro y definido. Las etiquetas tienen la forma <nombre>, donde nombre es el nombre del elemento que se está señalando.

20.10.4.1. Ejemplo código de XML

A continuación se muestra un ejemplo para entender la estructura de un documento XML: <?xml version="1.0" encoding="UTF-8" ?>

Page 225: Php-Mysql

JAVASCRIPT

211

<!--se utiliza UTF-8 debido a que acepta casi todo tipo de caracteres el cual es recomendado--> <!DOCTYPE Edit_Mensaje SYSTEM "Lista_datos_mensaje.dtd" [<!ELEMENT Edit_Mensaje (Mensaje)*>]> <Edit_Mensaje> <Mensaje> <Remitente> <Nombre>Nombre del remitente</Nombre> <Mail> Correo del remitente </Mail> </Remitente> <Destinatario> <Nombre>Nombre del destinatario</Nombre> <Mail>Correo del destinatario</Mail> </Destinatario> <Texto> <Asunto> Este es mi documento con una estructura muy sencilla no contiene atributos ni entidades.... </Asunto> <Parrafo> Este es mi documento con una estructura muy sencilla no contiene atributos ni entidades.... </Parrafo> </Texto> </Mensaje> </Edit_Mensaje>

Aquí está el ejemplo de código del DTD del documento “Edit_Mensaje”: <?xml version="1.0" encoding="ISO-8859-1" ?> <!-- Este es el DTD de Edit_Mensaje --> <!ELEMENT Mensaje (Remitente, Destinatario, Texto)*> <!ELEMENT Remitente (Nombre, Mail)> <!ELEMENT Nombre (#PCDATA)> <!ELEMENT Mail (#PCDATA)> <!ELEMENT Destinatario (Nombre, Mail)> <!ELEMENT Nombre (#PCDATA)> <!ELEMENT Mail (#PCDATA)> <!ELEMENT Texto (Asunto, Parrafo)> <!ELEMENT Asunto (#PCDATA)> <!ELEMENT Parrafo (#PCDATA)>

20.10.4.2. Documentos XML bien formados

Los documentos denominados como “bien formados” (del inglés well formed) son aquellos que cumplen con todas las definiciones básicas de formato y pueden, por lo tanto, analizarse correctamente por cualquier analizador sintáctico (parser) que cumpla con la norma. Se separa esto del concepto de validez que se explica más adelante.

Los documentos han de seguir una estructura estrictamente jerárquica con lo que respecta a las etiquetas que delimitan sus elementos. Una etiqueta debe estar

Page 226: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

212

correctamente incluida en otra, es decir, las etiquetas deben estar correctamente anidadas. Los elementos con contenido deben estar correctamente cerrados.

Los documentos XML sólo permiten un elemento raíz del que todos los demás sean parte, es decir, solo pueden tener un elemento inicial.

Los valores atributos en XML siempre deben estar encerrados entre comillas simples o dobles.

El XML es sensible a mayúsculas y minúsculas. Existe un conjunto de caracteres llamados espacios en blanco (espacios, tabuladores, retornos de carro, saltos de línea) que los procesadores XML tratan de forma diferente en el marcado XML.

Es necesario asignar nombres a las estructuras, tipos de elementos, entidades, elementos particulares, etc. En XML los nombres tienen alguna característica en común.

Las construcciones como etiquetas, referencias de entidad y declaraciones se denominan marcas; son partes del documento que el procesador XML espera entender. El resto del documento entre marcas son los datos “entendibles” por las personas.

20.10.5. Partes de un documento XML

Un documento XML está formado por el prólogo y por el cuerpo del documento así como texto de etiquetas que contiene una gran variedad de efectos positivos o negativos en la referencia opcional a la que se refiere el documento, hay que tener mucho cuidado de esa parte de la gramática léxica para que se componga de manera uniforme. Prólogo [editar]

Aunque no es obligatorio, los documentos XML pueden empezar con unas líneas que describen la versión XML, el tipo de documento y otras cosas.

El prólogo de un documento XML contiene:

Una declaración XML. Es la sentencia que declara al documento como un documento XML.

Una declaración de tipo de documento. Enlaza el documento con su DTD (definición de tipo de documento), o el DTD puede estar incluido en la propia declaración o ambas cosas al mismo tiempo.

Uno o más comentarios e instrucciones de procesamiento.

20.10.5.1. Cuerpo

A diferencia del prólogo, el cuerpo no es opcional en un documento XML, el cuerpo debe contener un y solo un elemento raíz, característica indispensable también para que el documento esté bien formado. Sin embargo es necesaria la adquisición de datos para su buen funcionamiento Elementos [editar]

Los elementos XML pueden tener contenido (más elementos, caracteres o ambos), o bien ser elementos vacíos.

20.10.5.2. Atributos

Los elementos pueden tener atributos, que son una manera de incorporar características o propiedades a los elementos de un documento. Deben ir entre comillas.

Page 227: Php-Mysql

JAVASCRIPT

213

Por ejemplo, un elemento “chiste” puede tener un atributo “tipo” y un atributo “calidad”, con valores “vascos” y “bueno” respectivamente. <chiste tipo="vascos" calidad="bueno">Esto es un día que Patxi y Josu van paseando…</chiste>

20.10.5.3. Entidades predefinidas

Entidades para representar caracteres especiales para que, de esta forma, no sean interpretados como marcado en el procesador XML.

Ejemplo: Entidad Predefinida: & amp; Caracter &

20.10.5.4. Secciones CDATA

Es una construcción en XML para especificar datos utilizando cualquier carácter sin que se interprete como marcado XML. No confundir con 2(#PCDATA) que es para los elementos. Permite que caracteres especiales no rompan la estructura. Ej: <![CDATA[ contenido especial: áéíóúñ&]] >

20.10.5.5. Comentarios

Comentarios a modo informativo para el programador que han de ser ignorados por el procesador.

Los comentarios en XML tienen el siguiente formato: <!--- Esto es un comentario ---> <!-- Otro comentario -->

20.10.6. Document Type Definition (DTD)

Una definición de tipo de documento o DTD (siglas en inglés de document type definition) es una descripción de estructura y sintaxis de un documento XML o SGML. Su función básica es la descripción del formato de datos, para usar un formato común y mantener la consistencia entre todos los documentos que utilicen la misma DTD. De esta forma, dichos documentos, pueden ser validados, conocen la estructura de los elementos y la descripción de los datos que trae consigo cada documento, y pueden además compartir la misma descripción y forma de validación dentro de un grupo de trabajo que usa el mismo tipo de información.

20.10.6.1. Definición

La DTD es una definición, en un documento SGML o XML, que especifica restricciones en la estructura y sintaxis del mismo. La DTD se puede incluir dentro del archivo del documento, pero normalmente se almacena en un fichero ASCII de texto separado. La sintaxis de las DTD para SGML y XML es similar pero no idéntica.

La definición de una DTD especifica la sintaxis de una aplicación de SGML o XML, que puede ser un estándar ampliamente utilizado como XHTML o una aplicación local.

20.10.6.2. ¿Qué describe una DTD?

Las DTD se emplean generalmente para determinar la estructura de un documento mediante etiquetas (en inglés tags) XML o SGML. Una DTD describe:

Page 228: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

214

* Elementos: indican qué etiquetas son permitidas y el contenido de dichas etiquetas. * Estructura: indica el orden en que van las etiquetas en el documento. * Anidamiento: indica qué etiquetas van dentro de otras.

20.10.6.3. Ejemplos

* Un ejemplo de una DTD XML muy simple, para describir una lista de personas: <!ELEMENT lista_de_personas (persona*)> <!ELEMENT persona (nombre, fechanacimiento?, sexo?, numeroseguridadsocial?)> <!ELEMENT nombre (#PCDATA) > <!ELEMENT fechanacimiento (#PCDATA) > <!ELEMENT sexo (#PCDATA) > <!ELEMENT numeroseguridadsocial (#PCDATA)>

Observándolo línea a línea nos dice: # <lista_de_personas> es un nombre de elemento válido. El * indica que puede haber 0 o más elementos de persona. # <persona> es un nombre de elemento válido. Éste contiene obligatoriamente el elemento nombre mientras que el resto son opcionales. Y lo son porque nos lo indica el símbolo ”?”. # <nombre> es un nombre de elemento válido. Contiene caracteres. # <sexo> es un nombre de elemento válido. Contiene caracteres. # <fechanacimiento> es un nombre de elemento válido. # <numeroseguridadsocial> es un nombre de elemento válido.

* Un ejemplo de un fichero XML que hace uso de esta DTD: <source lang=xml> <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE lista_de_personas SYSTEM "ejemplo.dtd"> <lista_de_personas> <persona> <nombre>José García</nombre> <fechanacimiento>25/04/1984</fechanacimiento> <sexo>Varón</sexo> </persona> </lista_de_personas> </source>

La DTD mostrada más arriba requiere un elemento “nombre” dentro de cada elemento “persona”; el elemento “lista_de_personas” es también obligatorio, pero el resto son opcionales.

Es posible renderizar este documento en un navegador habilitado para XML pegando y guardando la DTD de más arriba en un archivo de texto llamado ejemplo.dtd y el fichero.xml a un fichero de texto denominado de forma diferente, y abriendo el archivo.xml con el navegador. Ambos ficheros deben estar guardados en el mismo directorio (o carpeta). No obstante, algunos navegadores no comprueban que un documento XML sigue las reglas de la DTD; solamente se requieren para comprobar que la DTD es sintácticamente correcta.

Limitaciones de la DTD

Un esquema basado en una DTD tiene bastantes limitaciones. Una DTD no permite definir elementos locales que sólo sean válidos dentro de otros elementos. Por ejemplo, si queremos tener un elemento <Manager> que describa al gestor de una compañía o al de una delegación, y la definición de Manager es diferente en cada caso, con una DTD tendríamos que crear los elementos “CompanyManager” y “DelegationManager” para evitar el conflicto de nombres. Es decir, la falta de jerarquía en una DTD obliga a introducir una jerarquía a base de guiones o puntos en el espacio de nombres (Namespace). En una DTD es poco flexible la definición de elementos con contenido mixto, es decir, que incluyan otros elementos además de texto. Además no es posible

Page 229: Php-Mysql

JAVASCRIPT

215

indicar a qué tipo de dato (número, fecha, moneda) ha de corresponder un atributo o el texto de un elemento.

La necesidad de superar estas limitaciones propicia la aparición de otros lenguajes de esquema como XML Schema, herramientas más completas de descripción que son una alternativa a las DTD.

20.10.7. XML Schemas

XML Schema es un lenguaje de esquema utilizado para describir la estructura y las restricciones de los contenidos de los documentos XML de una forma muy precisa, más allá de las normas sintácticas impuestas por el propio lenguaje XML. Se consigue así una percepción del tipo de documento con un nivel alto de abstracción. Fue desarrollado por el World Wide Web Consortium (W3C) y alcanzó el nivel de recomendación en mayo de 2001.

20.10.7.1. Terminología

El término “XML Schema” es utilizado con varios significados dentro del mismo contexto de descripción de documentos, y es importante tener en cuenta las siguientes consideraciones:

“XML Schema” (Esquema XML) es el nombre oficial otorgado a la recomendación del W3C, que elaboró el primer lenguaje de esquema separado de XML (la definición de tipo de documentos (DTD) forma parte de XML).

Es habitual referirse a los esquemas como “XML schema” de forma genérica, pero se recomienda utilizar el término “documento esquema” (schema document) o “definición de esquema”(schema definition), y reservar “XML Schema” para la denominación de este lenguaje específico.

Aunque genéricamente se utilice “XML schemas”, XSDL (XML Schema Definition Language) es el nombre técnico de los lenguajes de esquema de XML como:

Definición de Tipo de Documento (DTD)

XML Schema

RELAX NG

Schematron

Namespace Routing Language (NRL)

Document Schema Definition Languages (DSDL)

Document Definition Markup Language (DDML)

Document Structure Description (DSD)

SGML

Schema for Object-Oriented XML (SOX)

Page 230: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

216

20.10.7.2. W3C Schema XML

El World Wide Web Consortium (W3C) empezó a trabajar en XML Schema en 1998. La primera versión se convirtió en una recomendación oficial en mayo de 2001. Una segunda edición revisada está disponible desde octubre de 2004.

Esta recomendación está desarrollada en tres partes:

XML Schema Parte 0 Primer: es una introducción no normativa al lenguaje, que proporciona una gran cantidad de ejemplos y explicaciones detalladas para una primera aproximación a XML Schema.

XML Schema Parte 1 Structures: es una extensa descripción de los componentes del lenguaje.

XML Schema Parte 2 Datatypes: complementa la Parte 1 con la definición de los tipos de datos incorporados en XML Schema y sus restricciones.

20.10.7.3. Componentes

XML Schema es un lenguaje de esquema escrito en XML, basado en la gramática y pensado para proporcionar una mayor potencia expresiva que las DTD, menos capaces al describir los documentos a nivel formal.

Los documentos esquema (usualmente con extensión .xsd de XML Schema Definition (XSD)) se concibieron como una alternativa a las DTD, más complejas, intentando superar sus puntos débiles y buscar nuevas capacidades a la hora de definir estructuras para documentos XML. El principal aporte de XML Schema es el gran número de tipos de datos que incorpora. De esta manera, XML Schema aumenta las posibilidades y funcionalidades de aplicaciones de procesado de datos, incluyendo tipos de datos complejos como fechas, números y strings. Tipos de componentes [editar]

Los esquemas XML Schema superan muchas de las limitaciones y debilidades de las DTDs. Fue diseñado completamente alrededor de namespaces y soporta tipos de datos típicos de los lenguajes de programación, como también tipos personalizados simples y complejos. Un esquema se define pensando en su uso final.

Namespaces

La programación en Schema XML se basa en Namespaces. Podemos encontrar una analogía entre éstos y los llamados packages en Java. Cada Namespace contiene elementos y atributos que están estrechamente relacionados con el Namespace. Así, a la hora de definir un elemento o un atributo de un Namespace, siempre se creará una conexión entre los diferentes campos de éste. Además, esta forma de trabajar nos permite relacionar elementos que no están en el mismo Namespace.

Después de escribir un Schema XML se puede confirmar la correcta realización mediante la validación de esquemas XML: Validación XML.

Ejemplo

Un ejemplo de la estructura de un documento esquema vacío sería el siguiente: <?xml version="1.0" encoding="ISO-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="0.1" xml:lang="es"> </xsd:schema>

Un ejemplo de definición con XML Schema sería el siguiente:

Page 231: Php-Mysql

JAVASCRIPT

217

<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="Libro"> <xsd:complexType> <xsd:sequence> <xsd:element name="Título" type="xsd:string"/> <xsd:element name="Autores" type="xsd:string" maxOccurs="10"/> <xsd:element name="Editorial" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="precio" type="xsd:double"/> </xsd:complexType> </xsd:element> </xsd:schema>

Podemos ver como en ambos casos se inician las declaraciones indicando la versión de XML que se va a utilizar y la codificación que se usa. Estos dos campos son necesarios para poder interpretar el esquema. Además, en la siguiente línea de código podemos ver como se redirecciona al usuario a la página que ofrece las pautas de creación de XML Schema en las que se basará la descripción del esquema.

El elemento raíz se llama “Libro” y tiene tres hijos (elementos anidados) y un atributo. Los hijos son “Titulo”,”Editorial” que deben aparecer una vez y “Autores” que puede aparecer de una a diez veces. El hecho de que estén agrupados en una secuencia indica que los elementos deben aparecer en orden, es decir, primero el “Titulo”, luego los “Autores” y por último la “Editorial”. Los tres elementos son de tipo string. El atributo de libro se llama “precio” y es de tipo double.

20.10.8. Extended Style Language (XSL)

XSLT es pues, un lenguaje que se usa para convertir documentos XML en otros documentos XML; puede convertir un documento XML que obedezca a un DTD a otro que obedezca otro diferente, un documento XML bien formado a otro que siga un DTD, o, lo más habitual, convertirlo a “formatos finales”, tales como WML (usado en los móviles WAP) o XHTML.

Los programas XSLT están escritos en XML, y generalmente, se necesita un procesador de hojas de estilo, o stylesheet processor para procesarlas, aplicándolas a un fichero XML.

El estilo de programación con las hojas XSLT es totalmente diferente a los otros lenguajes a los que estamos acostumbrados (tales como C++ o Perl), pareciéndose más a “lenguajes” tales como el AWK, o a otros lenguajes funcionales, tales como ML o Scheme. En la práctica, eso significa dos cosas:

No hay efectos secundarios. Una instrucción debe de hacer lo mismo cualquier que sea el camino de ejecución que llegue hasta ella. O sea, no va a haber variables globales (¡Cielos!), ni bucles en los que se incremente el valor de una variable, o tenga un test de fin de bucle, ni nada por el estilo. En realidad, esto no es tan grave, y se puede simular usando recursión, como se verá.

La programación está basada en reglas: cuando ocurre algo en la entrada, se hace algo en la salida. En eso, se parece al AWK, o a cierto estilo de programación en PERL, pero no en el resto de las cosas. Al fin y al cabo, no hay efectos secundarios.

En resumen, programar con las hojas XSLT (en inglés se les llama stylesheets o logicsheets) puede ser un poco frustante, pero cuando uno aprende a usarlas, no puede vivir sin ellas. En realidad, son la única alternativa cuando uno quiere adaptar un contenido descrito con XML a diferentes clientes (por ejemplo, móviles de diferente tamaño, diferentes navegadores), y la mejor alternativa cuando uno quiere procesar

Page 232: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

218

documentos XML (aunque haya otras: filtros SAX, expresiones regulares…). Otra alternativa, sobre todo si se está trabajando ya con un documento XML en forma de DOM (Document object model) es trabajar directamente sobre él. En este claso, de todas formas, se pueden usar transformaciones XSL, sólo que se aplicarán en memoria, en vez de leerlas desde un fichero.

Lo que consiguen las hojas de estilo es separar la información (almacenada en un documento XML) de su presentación, usando en cada caso las transformaciones que sean necesarias para que el contenido aparezca de la forma más adecuada en el cliente. Es más, se pueden usar diferentes hojas de estilo, o incluso la misma, para presentar la información de diferentes maneras dependiendo de los deseos o de las condiciones del usuario.

Aparte del hecho habitual de procesar documentos XML, XSLT es un lenguaje de programación, y por tanto se podría hacer cualquier cosa con ellas; incluso calcular la célebre criba de Eratóstenes o ejecutar un algoritmo genético. Pero a nosotros nos va a interesar más como simple herramienta de transformación de XML.

Actualmente hay varias versiones del estándar XSLT: la versión 1.0, que es la que implementan la mayoría de los procesadores, y se denomina “recomendación”, es decir, para el consorcio W3, lo equivalente a un estándar, y la versión 2.0 , que, a fecha de 4 de noviembre del 2004, es un “working draft”, o borrador de trabajo, que es el paso previo a un estándar. Algunos procesadores, tales como el Saxon, implementan ya esta última versión. Hay algunas diferencias importantes: el tratamiento uniforme de los árboles (técnicamente, se pueden convertir fragmentos de árboles de resultados en nodesets), uso de múltiples documentos de salida, y funciones definidas por el usuario que se pueden definir en XSLT, y no sólo en Java u otro lenguaje, como sucedía en estándares anteriores.

Para Windows, en sus diferentes versiones, hay dos herramientas que permiten editar XML y hojas de estilo XSLT, y aplicar directamente la una a la otra. Una de ellas es XMLSpy, que tiene un IDE muy bonito, pero que casca con relativa frecuencia. De hecho, he sido incapaz de aplicar una hoja de estilo a un documento XML. Otra opción es usar eXcelon Stylus, un buen de programa, pero que sólo está disponible para WindowsNT/2000 (y no sé si XP); la versión 3.0 beta es gratuita para desarrolladores.

En realidad, para editar XML y XSLT no hace falta ningún editor especial, pero viene bien un editor de XML o incluso un entorno integrado que te ayude a indentar bien el código, e incluso a cerrar las etiquetas en el orden correcto, o te saque la etiqueta y atributos admisibles en cada momento en función del DTD. En ese sentido, si se trabaja en Windows, el mejor es el eXcelon Stylus; en Linux, se puede uno apañar bien con el XEmacs (que te valida usando un DTD, si es necesario).

20.10.8.1. Cómo se usan las hojas de estilo

Hay muchas formas de usar las hojas de estilo. Lo más normal es usarlas dentro de un entorno de publicación tal como el Cocoon, o el IBM Transcoding Publisher, AxKit u otros por el estilo. Un entorno de publicación de XML permite mantener sitios completos basados en XML, y generar páginas en diferentes formatos a partir de ellos. En general, recomendamos Cocoon, que es una herramienta gratuita y Open Source basada en Java, y además una de las más avanzadas en el sector. Para una solución profesional, es mejor el IBM TP, pues forma parte del servidor de aplicaciones WebSphere, y cuenta con interfaz gráfico avanzado; el problema es el coste. La principal diferencia entre la versión 2 de Xalan y las anteriores es que implementa el llamado TrAX, una API para poder aplicar transformaciones a árboles XML; probablemente incorpore también la versión 1.1 de XSLT

En muchos casos, lo que se necesita es aplicar hojas de estilo dentro de una aplicación, o usarlas desde línea de comandos a partir de otra aplicación o otro lenguaje de

Page 233: Php-Mysql

JAVASCRIPT

219

programación. En ese caso, lo más útil es usar un procesador de hojas de estilo, que habitualmente se encuentra en conjunción con un parser XML, con o sin validación. De estos, hay los siguientes:

Xalan, que será el que más usemos en este tutorial, y que además es gratuito. La versión actual es la 2.6. Es una herramienta escrita en Java, y lo único que se necesita para hacerla funcionar es una máquina virtual Java (JVM), tal como la de Microsoft, Sun o IBM. Xalan necesita un parser XML para funcionar, tal como el Xerces, aunque el fichero correspondiente (xerces.jar) viene incluido en la distribución.

Saxon, un procesador bastante rápido, también escrito en Java, con su propio parser incluido, aunque se puede usar uno externo. Hay una versión denominada Instant Saxon, un procesador rápido, y fácil de usar, sólo para Windows. Por lo pronto, es el único que implementa la versión 2.0 de XSLT.

Hay otros muchos procesadores, tales como el XT de James Clark, xsltproc o el Sablotron. Todos ellos y muchos más se pueden encontrar en la página de procesadores XSLT de XMLSoftware.com. En Linux recomiendo el xsltproc, basado en la librería XML/XSL de gnome; es muy rápido, es un ejecutable y no hace falta instalar Java para usarlo.

A su vez, los procesadores de hojas de estilo se pueden usar como librerías de clases, o desde otros lenguajes. Por ejemplo, el módulo XML::XSLT para Perl. Estos módulos se pueden usar para poder trabajar con XSLT fuera de entornos de publicación, como por ejemplo un servidor web normal. xalan es en realidad una librería que se puede usar también desde programas en Java.

Algunos navegadores también lo implementan, o lo harán en el futuro. En concreto, el Mozilla debería incluirlo a partir de la versión 0.9; desde la versión 0.7 se podía incluir un plugin llamado TransforMiiX, que teóricamente aplica XSLT. En realidad, casi todos los navegadores modernos, con mayor o menor fortuna, lo incluyen. Firefox, por ejemplo, lo toma sin problemas.

Finalmente, para este curso, se puede usar un formulario simple que aplica hojas de estilo XSLT a documentos XML usando Perl: aplicador de hojas de estilo.

20.10.8.2. Hojas de estilo básicas

Para empezar, vamos a tratar de presentar una hoja XML de lo más simple (tienda0.xml): <?xml version="1.0" encoding='ISO-8859-1'?> <?xml-stylesheet href="tienda0.xsl" type="text/xsl"?> <tienda> <nombre>La tiendecilla </nombre> <telefono>953 87 12 23 </telefono> </tienda>

Este ejemplo lo iremos extendiendo hasta que contenga un catálogo de una tienda virtual. Por lo pronto incluimos solamente datos básicos sobre la tienda.

Para convertirlo en HTML, usaremos la siguiente hoja de estilo (tienda-html.xsl): 1 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match='/'> <html> <head> <title>Generado con tienda-html.xsl</title> </head> <body>

Page 234: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

220

<h1> <xsl:apply-templates /> </h1> </body> </html> </xsl:template> </xsl:stylesheet>

Tal como está, se puede cargar directamente con Firefox, que mostrará algo similar a la imagen. Asimismo se puede usar cualquier entorno integrado que incluya la posibilidad de hacer transformaciones, como el XMLShell o XMLSpy mencionados anteriormente.

20.10.9. Xlink, Xpath y Xpointer

XPath identifica partes de un documento XML concreto, como pueden ser sus atributos, elementos, etc.

XLink por su lado, describe un camino estándar para añadir hiperenlaces en un archivo XML. Es decir, es un mecanismo de vinculación a otros documentos XML. Funciona de forma similar a un enlace en una página Web, es decir, funciona como lo haría <a href=””>, sólo que a href es un enlace unidireccional. Sin embargo, XLink permite crear vínculos bidireccionales, lo que implica la posibilidad de moverse en dos direcciones. Esto facilita la obtención de información remota como recursos en lugar de simplemente como páginas Web.

XPointer funciona como una sintaxis que apunta a ciertas partes de un documento XML, es como una extensión de XPath. Se utiliza para llegar a ciertas partes de un documento XML. Primero, XLink permite establece el enlace con el recurso XML y luego es XPointer el que va a un punto específico del documento. Su funcionamiento es muy similar al de los identificadores de fragmentos en un documento HTML ya que se añade al final de una URI y después lo que hace es encontrar el lugar especificado en el documento XML. Al ser XPointer una extensión de XPath, XPointer tiene todas las ventajas de XPath y además permite establecer un rango en un documento XML, es decir, con XPointer es posible establecer un punto final y un punto de inicio, lo que incluye todos los elementos XML dentro de esos dos puntos.

Finalmente, XQL, lenguaje de consultas, se basa en operadores de búsqueda de un modelo de datos para documentos XML que puede realizar consultas en infinidad de tipos de documentos como son documentos estructurados, colecciones de documentos, bases de datos, estructuras DOM, catálogos, etc.

20.10.9.1. Ejemplos de uso

Ejemplo de documento XML: <?xml version="1.0" encoding="ISO-8859-1"?> <libro> <titulo></titulo> <capitulo> <titulo></titulo> <seccion> <titulo></titulo> </seccion> </capitulo> </libro>

Ejemplo de transformación XSL: <!-- Transforma el documento XML anterior en un documento XHTML --> <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:strip-space elements="libro capitulo titulo"/> <xsl:output

Page 235: Php-Mysql

JAVASCRIPT

221

method="xml" indent="yes" encoding="iso-8859-1" doctype-public="-//W3C//DTD XHTML 1.1//EN" doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/> <!-- Utiliza el título del libro como título del documento XHTML --> <xsl:template match="libro"> <html> <head> <title> <xsl:value-of select="titulo"/> </title> </head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <!-- Y también como título de nivel H1 --> <xsl:template match="libro/titulo"> <h1> <xsl:apply-templates/> </h1> </xsl:template> <!-- Los títulos de los capítulos aparecerán como H2 --> <xsl:template match="capitulo/titulo"> <h2> <xsl:apply-templates/> </h2> </xsl:template> <!-- Los títulos de las secciones aparecerán como H3 --> <xsl:template match="seccion/titulo"> <h3> <xsl:apply-templates/> </h3> </xsl:template> </xsl:stylesheet>

Ejemplo de código XPath: <!-- Toma todos los elementos titulo dentro del elemento capítulo y los elementos autor dentro del elemento capitulo --> /doc/capitulo/titulo | /doc/capitulo/autor

Ejemplo de código XLink: <my:crossReference xlink:href="libro.xml" xlink:role="http://www.example.com/linkprops/listalibros" xlink:title="Lista de libros"> Lista actual de libros </my:crossReference>

Ejemplo de código XPointer: documento.xml#xpointer( /libro/capitulo[@public])xpointer(/libro/capitulo[@num="1"])

Ejemplo de código de XQuery: <!-- Libros escritos por Vargas Llosa después de 1991 --> <bib> { for $b in doc("http://libro.example.com/bib.xml")/bib/libro where $b/autor = "Vargas Llosa" and $b/@anio > 1991

Page 236: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

222

return <libro anio="{ $b/@anio }"> { $b/titulo } </libro> } </bib>

20.10.10. SAX y DOM

Las herramientas o programas que leen el lenguaje XML y comprueban si el documento es válido sintácticamente, se denominan analizadores o “parsers”. Un parser XML es un módulo, biblioteca o programa que se ocupa de transformar un archivo de texto en una representación interna. En el caso de XML, como el formato siempre es el mismo, no necesitamos crear un parser cada vez que hacemos un programa, sino que existen un gran número de parsers o analizadores sintácticos disponibles que pueden averiguar si un documento XML cumple con una determinada gramática. Entre esos analizadores o parsers cabe destacar DOM y SAX.

DOM y SAX, son pues dos herramientas que sirven para analizar el lenguaje XML y definir la estructura de un documento, aunque existen otras muchas. Podemos hacer una distinción entre las herramientas que son validantes y las que son No validantes. Las primeras verifican que el documento, además de estar bien formado de acuerdo a las reglas de XML, responda a una estructura definida en una Definición del Tipo de Documento (DTD).

Los parsers DOM y SAX son independientes del lenguaje de programación y existen versiones particulares para Java, VisualBasic, C, Java, PHP, etc.

20.10.10.1. DOM

El Modelo de Objetos del Documento parser Document Object Model (DOM) es un modelo de objetos estandarizado para documentos HTML y XML. DOM es un conjunto de interfaces para describir una estructura abstracta para un documento XML. Los programas que acceden a la estructura de un documento a través de la interfaz de DOM pueden insertarse arbitrariamente, borrarse y reordenar los nodos de un documento XML, esto es, con DOM se puede modificar el contenido, la estructura y el estilo o presentación de los documentos. Todas estas funciones se realizan mediante llamadas a funciones y procedimientos que permiten acceder, cambiar, borrar o añadir nodos de información (datos o metadatos) de los documentos XML.

DOM es una una interfaz de programación de aplicaciones (API) para documentos HTML y XML. Define la estructura lógica de los documentos y el modo en que se accede y manipula un documento. El término documento en DOM se entiende de una forma amplia, pues XML se utiliza cada vez más como un medio para representar muchas clases diferentes de información que puede ser almacenada en sistemas diversos, y mucha de esta información se vería, en términos tradicionales, más como datos que como documentos. Sin embargo, XML presenta estos datos como documentos, y se puede usar el DOM para manipular estos datos.

Con el Modelo de Objetos del Documento los programadores pueden construir documentos, navegar por su estructura, y añadir, modificar o eliminar elementos y contenido. Se puede acceder a cualquier cosa que se encuentre en un documento HTML o XML, y se puede modificar, eliminar o añadir usando el Modelo de Objetos del Documento, salvo algunas excepciones.

Siendo una especificación del W3C, uno de los objetivos importantes del Modelo de Objetos del Documento es proporcionar una interfaz estándar de programación que pueda utilizarse en una amplia variedad de entornos y aplicaciones. El DOM se ha

Page 237: Php-Mysql

JAVASCRIPT

223

diseñado para utilizarse en cualquier lenguaje de programación como Java o ECMAScript (un lenguaje de scripts industrial basado en JavaScript y JScript.

Cuando nos referimos a interfaz al hablar de DOM (o de SAX), no nos estamos refiriendo a interfaz gráfica, sino a interfaz de aplicaciones. Una interfaz es un dispositivo que permite comunicar dos sistemas que no hablan el mismo lenguaje. Una Interfaz de Programación de Aplicaciones Niveles o interfaceso API (Application Programming interface) es un conjunto de funciones o métodos usados para acceder a cierta funcionalidad. La interfaz se encarga de mantener el diálogo con los datos para poder tener acceso a ellos y manipularlos.

La utilización de APIs es muy común cuando tenemos un conjunto de datos que queremos tratar o manipular y se aplica, sobre todo, para acceder a bases de datos y realizar tareas que están a caballo entre las aplicaciones y las bases de datos. Estas tareas se realizan bien a través del servidor de base de datos, o bien a través del cliente. Esto quiere decir, que puede darse el caso de que el cliente conste de las tres primeras interfaces o niveles, o que se encuentren las dos últimas en el servidor (ver imagen adjunta). La interfaz correspondiente a la base de datos, es donde se encontrará el servidor y toda la información depositada en él.

El DOM es, pues, un API o interfaz de programación para documentos. DOM guarda una gran similitud con la estructura del documento al que modeliza y muestra los documentos con una estructura lógica que es muy parecida a un árbol.

Sin embargo, el DOM no especifica que los documentos deban ser desarrollados como un árbol o un bosque, ni tampoco especifica cómo deben implementarse las relaciones entre objetos. El DOM es un modelo lógico que puede desarrollarse de la manera que sea más conveniente, por eso se debe hablar de un modelo de estructura en general, y no de estructura en forma de árbol, en particular.

Una propiedad importante de los modelos de estructura del DOM es su isomorfismo estructural: si dos desarrollos cualesquiera del Modelo de Objetos del Documento se usan para crear una representación del mismo documento, ambos crearán el mismo modelo de estructura, con exactamente los mismos objetos y relaciones.

El nombre de DOM o “Modelo de Objetos del Documento” se adoptó porque se trata de un “modelo de objetos” en el sentido tradicional del diseño orientado a objetos: los documentos se modelizan usando objetos, y el modelo comprende no solamente la estructura de un documento, sino también su comportamiento y el de los objetos de los cuales se compone. Esto significa que los nodos del diagrama obtenido mediante DOM no representan una estructura de datos, sino que representan objetos, los cuales pueden tener funciones e identidad. Como modelo de objetos, el DOM identifica:

las interfaces y objetos usados para representar y manipular un documento

la semántica de estas interfaces y objetos, incluyendo comportamiento y atributos

las relaciones y colaboraciones entre estas interfaces y objetos

Tradicionalmente, la estructura de los documentos SGML se ha representado mediante un modelo de datos abstractos, no con un modelo de objetos. En un modelo de datos abstractos, el modelo se centra en los datos. En los lenguajes de programación orientados a objetos, los datos se encapsulan en objetos que ocultan los datos, protegiéndolos de su manipulación directa desde el exterior. Las funciones asociadas con estos objetos determinan cómo pueden manipularse los objetos, y son parte del modelo de objetos.

El Modelo de Objetos del Documento no es un conjunto de estructuras de datos, sino un modelo de objetos que especifica interfaces. Aunque la especificación del W3C contiene diagramas que muestran relaciones padre/hijo, éstas son relaciones lógicas definidas

Page 238: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

224

por las interfaces de programación, no representaciones de ninguna estructura interna de datos particular.

El Modelo de Objetos del Documento no define “la semántica interna real” de los lenguajes XML o de HTML. El DOM es un modelo de programación diseñado para respetar las semánticas establecidas por el W3C en otras especificaciones. El DOM no tiene ninguna consecuencia en el modo en que se escriben los documentos XML y HTML; cualquier documento que pueda escribirse con estos lenguajes puede ser representado en el DOM.

Así pues, DOM es un conjunto de interfaces y objetos diseñado para manipular documentos HTML y XML que se puede desarrollar usando otros sistemas y lenguajes específicos.

Las especificaciones del W3C que regulan el Modelo de Objetos del Documento son las siguientes:

Document Object Model (DOM) Level 1Specification. http://www.w3.org/TR/REC-DOM-Level-1/ (trad. al castellano: POZO, Juan R. Especificación del Modelo de Objetos del Documento (DOM). Nivel 1. http://html.conclase.net/w3c/dom1-es/cover.html

En esta especificación se define el Nivel 1 del Modelo de Objetos del Documento, una interfaz independiente de la plataforma y del lenguaje que permite a programas y scripts acceder y actualizar dinámicamente los contenidos, la estructura y el estilo de los documentos. El Modelo de Objetos del Documento proporciona un conjunto estándar de objetos para representar documentos HTML y XML, un modelo estándar de cómo pueden combinarse estos objetos y una interfaz estándar para acceder a ellos y manipularlos. Las compañías pueden dar soporte al DOM como interfaz para sus estructuras de datos y APIs propietarias, y los autores de contenido pueden escribir para las interfaces estándar del DOM en lugar de para las APIs específicas de cada producto, lo cual incrementa la interoperabilidad en la Web.

El objetivo de la especificación DOM es definir una interfaz programable para HTML y XML. La especificación del Nivel 1 del DOM se divide en dos partes: Núcleo y HTML. El núcleo proporciona un conjunto de interfaces fundamentales de bajo de nivel que pueden representar cualquier documento estructurado, al mismo tiempo que define interfaces extendidas para representar documentos XML. La sección de HTML proporciona interfaces adicionales de alto nivel que se utilizan con las interfaces fundamentales definidas en la sección sobre el Núcleo del Nivel 1 para proporcionar una visión más conveniente de los documentos HTML.

Document Object Model (DOM) Level 2 agrupa las siguientes especificaciones:

Core Specification http://www.w3.org/TR/DOM-Level-2-Core/

Views Specification http://www.w3.org/TR/DOM-Level-2-Views/

Events Specification http://www.w3.org/TR/DOM-Level-2-Events/

Style Specification http://www.w3.org/TR/DOM-Level-2-Style/

Traversal and Range Specification http://www.w3.org/TR/DOM-Level-2-Traversal-Range/

HTML Specification http://www.w3.org/TR/DOM-Level-2-HTML/

Estas Recomendaciones definen el Document Object Model Nivel 2 que se construye sobre el Document Object Model Nivel, pero añadiendo un conjunto de interfaces especializadas para crear y manipular la estructura y el contenido del documento.

Document Object Model (DOM) Level 3 agrupa las siguientes especificaciones:

Page 239: Php-Mysql

JAVASCRIPT

225

Core Specification. http://www.w3.org/TR/DOM-Level-3-Core/

Validation Specification. http://www.w3.org/TR/DOM-Level-3-Val/

El Document Object Model Core Level 3 se construye sobre el Document Object Model Level 2, completa el mapeado entre DOM y el conjunto de información XML [XML Information Set: http://www.w3.org/TR/xml-infoset/] , incluyendo soporte para XML Base [http://www.w3.org/TR/xmlbase/], añade la posibilidad de adjuntar información del usuario a los nodos DOM, ofreciendo mecanismos para resolver los prefijos de los espacios de nombre o para manipular atributos “ID” para tipificar la información, etc.

Otros informes técnicos de interés elaborados por el W3C en relación a DOM son:

Document Object Model FAQ. http://www.w3.org/DOM/faq.html

What does your user agent claim to support? http://www.w3.org/2003/02/06-dom-support.html (trad. al castellano: GUTIÉRREZ FERRERÍAS, Fernando.¿Qué afirma soportar su Agente de Usuario? http://ferguweb.tx.com.ru/w3/06-dom-support.html)

20.10.10.2. SAX

El Simple API for XML (SAX) es una interfaz simple para aplicaciones XML. Fácil e intuitiva, muchos programadores de Java la utilizan, ya que se usa especialmente en situaciones en los que los archivos XML ya están en una forma que es estructuralmente similar a la que deseamos obtener.

Por lo general, se usa SAX cuando la información almacenada en los documentos XML, es decir, los datos, han sido generados por máquina o son legible por máquina. En este caso, SAX es la forma más directa de API para que los programas tengan acceso a esa información. Los datos generados y legibles por máquina incluyen algunos elementos como los siguientes:

Propiedades de objetos Java almacenados en formato XML

Consultas (queries) formuladas usando alguna clase de texto basada en lenguajes de interrogación (SQL, XQL, OQL, etc.)

El conjunto resultante se genera basándose en conjunto de resultados que se generan basándose en consultas (queries) (éste debería incluir datos en tablas de bases de datos relacionales codificadas en XML).

Así, los datos generados por la máquina son información que normalmente tenemos creada en estructuras de datos y clases para Java. Un ejemplo simple de este tipo, puede ser una libreta de direcciones. La libreta en un archivo XML contiene puramente datos que pueden ser codificados como texto usando XML, no se trata, pues de algo similar a un documento creado con un procesador de textos, sino a datos en sí mismos.

Cuanto los datos son de este tipo, lo corriente es crear una estructura de datos y clases, es decir, un modelo de objetos (object models) para poder ordenar, manipular y almacenar estos datos. SAX permite crear rápidamente una herramienta u operador de clase que puede crear instancias de los modelos de objetos basados en el almacenamiento de datos de los documentos. Por ejemplo, un operador de documentos SAX que lee un documento XML que contiene una Libreta de direcciones y crea una clase Libreta de direcciones que puede usarse para acceder a esta información. El documento XML Libreta de direcciones contiene elementos Persona, los cuales contienen, por ejemplo, los elementos nombre y correo electrónico. El modelo de objeto Libreta de direcciones contendría las siguientes clases:

Clases Libreta de Direcciones, que es un contenedor para objetos Persona.

Page 240: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

226

Clase Persona, que es un contenedor para la cadena de objetos nombre y correo electrónico.

Así el operador del documento Libreta de direcciones SAX, es el responsable de colocar los elementos persona dentro de los objetos Persona, y almacena todo en un objeto: Libreta de Direcciones. Este documento coloca los elementos nombre y correo electrónico dentro de una cadena de objetos.

20.10.10.3. Comparación entre SAX y DOM

Un analizador (parser) SAX es una herramienta más versátil, más veloz y menos potente que un analizador (parser) DOM. SAX requiere una mayor programación, pero puede ser muy útil si lo que interesa es rescatar un fragmento de un documento o buscar sólo un elemento en particular.

En contraste, un DOM es menos versátil, más lento, pero una vez usado no hay que desarrollar nada más. Con DOM se obtiene el árbol ya construido y listo para poder funcionar.

Los parsers DOM y SAX trabajan de diferente manera. SAX necesita menos código y menos memoria, aunque tiene menos capacidad que DOM. El funcionamiento es el siguiente: primero se comienza a leer el documento, luego se detectan los eventos de parsing (como por ejemplo comienzos o finales de un elemento), la aplicación procesa esa parte leída y, por último, se reutiliza la memoria y se vuelve a leer hasta un nuevo evento. Así pues, el parser SAX procesa el documento XML analizando la corriente de entrada XML, pasando los eventos SAX a un método para operar con una programación definida.

Un parser DOM, por el contrario, opera con la corriente completa de entrada XML, es decir, lee todo el documento completo y devuelve un Document Object. Document, esto es, construye un árbol en memoria que refleja toda la estructura del documento. La aplicación recorre el árbol realizando su procesamiento ya que el documento devuelto por el parser DOM tiene un API que permite manipular el árbol (virtual) de Node objects. Éste representa la estructura de la entrada XML.

La principal diferencia entre DOM y SAX es que mientras el primero tiene acceso al documento completo, esto es, que todos los elementos y atributos están disponibles a la vez, en SAX sólo está disponible el elemento actual.

20.10.10.4. Cuándo usar DOM y cuándo usar SAX

Si los documentos XML contienen documentos de datos almacenados en un formato XML, entonces lo natural es usar DOM. Si por ejemplo, se está creando alguna clase de sistema de gestión de la información y se tiene un gran número de documentos de datos de diferentes tipo (como archivos de Word o Excel) y esos documentos pueden organizarse e indexarse desde toda clase de documentos fuente, DOM permitirá acceder a los programas que almacenan la información en esos documentos.

En DOM, se pueden generar consultas (queries) usando XPAth. Con este lenguaje, se pueden expresar cosas tales como: dame todos los nodos que se llaman “x” y que tienen un nodo hijo llamado “y” con el conjunto de atributos “z” para un valor cierto.

Sin embargo, si se está tratando principalmente con estructuras de datos, DOM no es la mejor elección. En ese caso es mejor usar SAX.

20.10.11. Actividades

Page 241: Php-Mysql

JAVASCRIPT

227

Responde a las siguientes preguntas:

Describe XML con tus propias palabras

¿Qué es XHTML respecto a XML?

¿Para que sirven las XSLT?

¿Cómo se pueden enlazar dos archivos XML?

¿Cómo se puede localizar un recurso dentro de un fichero XML?

Si un fichero XML está cargado en memoria, ¿Que tipo de parser utilizarías?

20.10.12. Referencias

XML: http://es.wikipedia.org/wiki/Extensible_Markup_Language

XHTML: http://es.wikipedia.org/wiki/XHTML

DTD: http://es.wikipedia.org/wiki/Definici%C3%B3n_de_tipo_de_documento

XML Schema: http://es.wikipedia.org/wiki/XML_Schema

XSL y XSLT: http://geneura.ugr.es/~jmerelo/XSLT/

Xlink: http://geneura.ugr.es/~victor/cursillos/xml/XLink/

W3c: http://www.w3c.es/divulgacion/guiasbreves/tecnologiasxml

Guia sax y dom: http://www.hipertexto.info/documentos/dom.htm

Page 242: Php-Mysql
Page 243: Php-Mysql

JAVASCRIPT EN LOS DISTINTOS NAVEGADORES

229

Javascript en los distintos navegadores

Desgraciadamente, la implementación de Javascript en los diferentes navegadores no es igual, y nos podemos encontrar con scripts que no funcionen correctamente en todos los navegadores (incluso que solo lleguen a funcionar en uno).

En http://www.quirksmode.org/dom/w3c_html.html tenemos un listado de propiedades y métodos de javascript y sus compatibilidades en los diferentes navegadores.

La gente de ImpressiveWeb hizo un listado con 7 diferencias entre los 2 navegadores más conocidos: Internet Explorer y Firefox que deberíamos tener en cuenta a la hora de hacer nuestros scripts.

21.1. La propiedad “float” de CSS

Generalmente cuando accedemos a una propiedad relacionada al estilo de un elemento solemos usar element.style.propiedad, pero para la propiedad float usar el sistema element.style.float no nos va a ser posible. // IE document.getElementById("elem").style.styleFloat = "left"; // right // FF document.getElementById("elem").style.cssFloat = "left"; // right

Page 244: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

230

21.2. Estilos computados de un elemento

Si queremos acceder a los estilos procesados ya por el navegador nos encontramos con una diferencia significante en el sintaxis para ambos navegadores. // IE var myObject = document.getElementById("header"); var myStyle = myObject.currentStyle.backgroundColor; // FF var myObject = document.getElementById("header"); var myComputedStyle = document.defaultView.getComputedStyle(myObject, null); var myStyle = myComputedStyle.backgroundColor; // MIX var myObject = document.getElementById("header"); var myStyle = myObject.currentStyle ? myObject.currentStyle.backgroundColor : document.defaultView.getComputedStyle(myObject, null).backgroundColor;

21.3. Accediendo al “class” de un elemento

Debido a la especificación de Internet Explorer, cuando queremos acceder al class de un elemento usando getAttribute() debemos modificar el nombre que solicitamos. // IE var myObject = document.getElementById("header"); var myAttribute = myObject.getAttribute("className"); // FF var myObject = document.getElementById("header"); var myAttribute = myObject.getAttribute("class");

21.4. Accediendo al atributo “for” de las etiquetas <label />

Exactamente lo mismo ocurre con el atributo for de las etiquetas <label /> que en Internet Explorer para solicitar esta información, debemos reemplazar el nombre que pedimos. // IE var myObject = document.getElementById("myLabel"); var myAttribute = myObject.getAttribute("htmlFor"); // FF var myObject = document.getElementById("myLabel"); var myAttribute = myObject.getAttribute("for");

21.5. Obtener la posición del puntero del ratón

Page 245: Php-Mysql

JAVASCRIPT EN LOS DISTINTOS NAVEGADORES

231

Otra diferencia y que mucho nos hace agrandar nuestro código es la localización del puntero. // IE var myCursorPosition = [0, 0]; myCursorPosition[0] = event.clientX; myCursorPosition[1] = event.clientY; // FF var myCursorPosition = [0, 0]; myCursorPosition[0] = event.page; myCursorPosition[1] = event.pageY; // MIX var myCursorPosition = [0, 0]; myCursorPosition[0] = event.clientX || event.page; myCursorPosition[1] = event.clientY ||event.pageY;

21.6. Obtener el tamaño del navegador o del área visible

Al obtener el tamaño de la pantalla y del area visible nos encontramos con el mismo problema. Parece que no se ponen de acuerdo en que nombre ponerle a las propiedades comunes. // IE var myBrowserSize = [0, 0]; myBrowserSize[0] = document.documentElement.clientWidth; myBrowserSize[1] = document.documentElement.clientHeight; // FF var myBrowserSize = [0, 0]; myBrowserSize[0] = window.innerWidth; myBrowserSize[1] = window.innerHeight;

Aquí hay que hacer una pequeña aclaración:

window.innerWidth/innerHeight y document.documentElement.clientWidth/Height no representan exactamente lo mismo:

window.innerWidth/innerHeight están implementadas en Firefox, Opera y Safari (pero no en IE) y nos proporcionan las dimensiones del viewport incluyendo el tamaño de las barras de scroll si las hubiese. document.documentElement.clientWidth/Height están implementadas en todos y contienen las dimensiones del viewport (sin incluir barras de scroll).

21.7. Transparencias

Si las transparencias en CSS ya eran un desastre donde nos veíamos obligados a usar hacks dependiendo del navegador, en javascript nos encontramos el mismo problema. // CSS #myElement { filter: alpha(opacity=50); // IE opacity: 0.5; // FF } // IE var myObject = document.getElementById("myElement");

Page 246: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

232

myObject.style.filter = "alpha(opacity=80)"; // FF var myObject = document.getElementById("myElement"); myObject.style.opacity = "0.5";

Page 247: Php-Mysql

MANEJO DEL DOM

233

Manejo del DOM

Javascript permite acceder a cada uno de los elementos de una página utilizando tan sólo algunos métodos y propiedades.

La forma básica de acceder a un elemento es mediante el atributo id, gracias al método getElementById. <p> <a id="contacto" href="contactos.html">Contáctenos</a> </p>

Puede usarse el atributo id del elemento a para acceder al mismo: var elementoContacto = document.getElementById("contacto");

Ahora el valor de la variable elementoContacto está referida al elemento [a] y cualquier operación sobre la misma afectará el hiperenlace.

El método getElementById es adecuado para operar sobre un elemento en específico, sin embargo, en ocasiones se necesita trabajar sobre un grupo de elementos por lo que en este caso puede utilizarse el método getElementsByTagName. Este retorna todos los elementos de un mismo tipo. Asumiendo la siguiente lista desordenada: <ul> <li><a href="editorial.html">Editorial</a></li> <li><a href="semblanza.html">Autores</a></li> <li><a href="noticias.html">Noticias</a></li> <li><a href="contactos.html">Contáctenos</a></li> </ul>

Page 248: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

234

Puede obtenerse todos los hipervínculos de la siguiente manera: var hipervinculos= document.getElementsByTagName("a");

El valor de la variable hipervinculos es una colección de elementos [a]. Las colecciones son arreglos pudiéndose acceder a cada elemento a través de la ya conocida notación con corchetes.

Los elementos devueltos por getElementsByTagName serán ordenado según el orden que aparezcan en el código fuente. Por tanto para el caso anterior quedaría así:

hipervinculos[0] el elemento [a] para “Editorial”

hipervinculos[1] el elemento [a] para “Autores”

hipervinculos[2] el elemento [a] para “Noticias”

hipervinculos[3] el elemento [a] para “Contáctenos”

Otra maneras de acceder a un elemento usando su id es document.all[“id”] la cual fue introducida en Internet Explorer 4 y document.layers[“id”] introducida por Netscape 5 por que el W3C todavía no había estandarizado la manera de acceder a los elementos mediante su id. Sin embargo, no se recomienda su uso porque al estar fuera de los estándares actuales hay navegadores que no soportan estos métodos.

Por otro lado existen varios elementos en un documento HTML que pueden ser accedidos de otras maneras. El elemento body de un documento puede accederse a través de la forma document.body, mientras que el conjunto de todos los formularios en un documento puede encontrase en document.forms, así mismo el conjunto de todas las imágenes sería mediante document.images.

Actualmente la mayoría de los navegadores soportan esto métodos aún así es recomendable el uso del método getElementsByTagName, véase el siguiente ejemplo para acceder al elemento body: var body = document.getElementsByTagName("body")[0];

22.1. Creando elementos y textos

La creación de nodos es posible mediante el uso de dos métodos disponibles en el objeto document. Dichos métodos son:

createElement(Tipo cadena): Crea un nuevo elemento del tipo especificado y devuelve un referencia a dicho elemento.

createTextNode(Cadena de texto): Crea un nuevo nodo de texto con el contenido especificado en la cadena de texto.

El siguiente ejemplo muestra cómo se crea un nuevo elemento de párrafo vacío: var nuevoEnlace = document.createElement("a");

La variable nuevoEnlace ahora referencia un nuevo enlace listo para ser insertado en el documento. El texto que va dentro del elemento [a] es un nodo de texto hijo, por lo que debe ser creado por separado. var nodoTexto = document.createTextNode("Semblanza");

Page 249: Php-Mysql

MANEJO DEL DOM

235

Luego si desea modificar el nodo de texto ya existente, puede utilizarse la propiedad nodeValue, esta permite coger y poner el nodo de texto: var textoViejo = nodoTexto.nodeValue; nodoTexto.nodeValue = "Novedades";

El valor de la variable textoViejo es ahora “Semblanza” y el nuevo texto “Novedades”. Se puede insertar un elemento o texto (nodo) como último hijo de un nodo ya existente usando el método appendChild. Este método coloca el nuevo nodo después de todos los hijos del nodo. NuevoEnlace.appendChild(nodoTexto);

Ahora todo lo que se necesita es insertar el enlace en el cuerpo del documento. Para hacer esto, se necesita una referencia al elemento body del documento, teniendo como guía los estándares siguientes: var cuerpoRef = document.getElementsByTagName("body")[0]; cuerpoRef.appendChild(nuevoEnlace);

Otra manera sería utilizando el método getElementById. Para ello se asume que la etiqueta <body> tiene asignado un valor para el atributo id. <body id=”cuerpo”> <script> var cuerpoRef = document.getElementById("cuerpo"); cuerpoRef.appendChild(nuevoEnlace); </script>

Existen básicamente tres maneras mediante las cuales un nuevo elemento o nodo de texto puede ser insertado en una página Web. Todo ello depende del punto en el cual se desee insertar el nuevo nodo: como último hijo de un elemento, antes de otro nodo o reemplazo para un nodo.

El caso de apertura de un nuevo hijo ya fue visto en el ejemplo anterior, luego para insertar el nodo antes de otro nodo se realiza utilizando el método insertBefore de su elemento padre, mientras que el reemplazo de nodo se utiliza el método replaceChild de su elemento padre.

Al usar insertBefore, se necesita tener referencias al nodo que va ser insertado y donde va a ser insertado, considérese el siguiente código HTML: <p id="mwEnlaces"> <a id="editor" href="editorial.html">Editorial</a> </p>

Luego el nuevo enlace será insertado antes de enlace ya existente llamando el método insertBefore desde el nodo padre (párrafo): var anclaTexto = document.createTextNode("Actualidad"); var nuevoAncla = document.createElement("a"); nuevoAncla.appendChild(anclaTexto); var anclaExistente = document.getElementById("editor"); var padre = anclaExistente.parentNode; var nuevoHijo = padre.insertBefore(nuevoAncla, anclaExistente);

Si se hiciera una traducción del DOM hacia HTML después de esta operación el resultado sería el siguiente: <p id="mwEnlaces"> <a> Actualidad </a><a id="editor" href="editorial.html">Editorial</a> </p>

Page 250: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

236

En el caso de reemplazar el enlace usando replaceChild: var nuevoHijo = padre.replaceChild(nuevoAncla, anclaExistente);

El DOM lucirá así: <p id="mwEnlaces"> <a> Actualidad </a> </p>

22.2. Usando innerHTML

En aplicaciones complejas donde es necesario crear varios elementos a la vez, el código JavaScript generado puede ser extenso recurriéndose a la propiedad innerHTML. Dicha propiedad fue introducida por Microsoft permitiendo leer y escribir el contenido HTML de un elemento.

Por ejemplo, puede crearse fácilmente una tabla con múltiples celdas e insertarla luego en la página con innerHTML: var tabla = '<table border="0">'; tabla += '<tr><td>Celda 1</td><td>Celda 2</td><td> Celda 3</td></tr>'; tabla += '</table>'; document.getElementById("datos").innerHTML = tabla;

22.3. Eliminando un elemento o nodo de texto

Se pueden eliminar nodos existentes y nuevos. El método removeChild permite eliminar nodos hijos a cualquier nodo con tan sólo pasarle las referencias del nodo hijo [a] eliminar y su correspondiente padre. Para mejor compresión volvamos al ejemplo anterior: <p id="mwEnlaces"> <a id="editor" href="editorial.html">Editorial</a> </p>

El método removeChild será usado para eliminar el hipervínculo del elemento padre párrafo: var ancla = document.getElementById("editor"); var padre = ancla.parentNode; var hijoRemovido = padre.removeChild(ancla);

La variable hijoRemovido todavía hace referencia al elemento, de manera que fue removido pero no destruido, no pudiéndose localizar en ninguna parte del DOM. Este se encuentra disponible en memoria como si fuera creado usando el método createElement. Esto permite posicionarlo en cualquier otra parte de la página. Lectura y escritura de los atributos de un elemento

Las partes más frecuentemente usadas de un elemento HTML son sus atributos, tales como: id, class, href., title, estilos CSS, entre muchas otras piezas de información que pueden se incluidas en una etiqueta HTML.

Los atributos de una etiqueta son traducidos por el navegador en propiedades de un objeto. Dos métodos existen para leer y escribir los atributos de un elemento, getAttribute permite leer el valor de un atributo mientras que setAttribute permite su escritura.

En ocasiones se hace necesario ver las propiedades y métodos de un determinado elemento, esto puede realizarse mediante la siguiente función utilitaria:

Page 251: Php-Mysql

MANEJO DEL DOM

237

function inspector(el) { var str =””; for (var i in el){ str+=I + “: ” + el.getAttribute(i) + “\n”; } alert(str); }

Para usar la función inspector() tan sólo debe pasarle la referencia al elemento, continuando con el ejemplo anterior resulta: var ancla = document.getElementById("editor"); inspector(ancla);

Para modificar el atributo title del hipervínculo, elemento referenciado por la variable ancla, se usará el setAttribute, pasándole el nombre del atributo y el valor: var ancla = document.getElementById("editor"); ancla.setAttribute("title", "Artículos de programación"); var nuevoTitulo = ancla.getAttribute("title"); //El valor de la variable nuevoTitulo es ahora “Artículos de programación”.

22.4. Manipulando los estilos de los elementos

Como se ha visto, los atributos que le son asignados a las etiquetas HTML están disponibles como propiedades de sus correspondientes nodos en el DOM. Las propiedades de estilo pueden ser aplicadas a través del DOM.

Cada atributo CSS posee una propiedad del DOM equivalente, formándose con el mismo nombre del atributo CSS pero sin los guiones y llevando la primera letra de las palabras a mayúsculas. Véase el siguiente ejemplo para mayor entendimiento donde se utiliza un atributo CSS modelo:

algun-atributo-css

Tendrá como equivalente la siguiente propiedad o método en Javascript:

algunAtributoCss

Por tanto, para cambiar el atributo CSS font-family de un elemento, podría realizarse de lo siguiente: ancla.style.fontFamily = 'sans-serif';

Los valores CSS en Javascript serán en su mayoría del tipo cadena; por ejemplo: font-size, pues posee dimensiones tales como “px”, “%”. Sólo los atributos completamente numéricos, tales como z-index serán del tipo entero.

En muchos casos es necesario aparecer y desaparecer un determinado elemento, para ellos se utiliza el atributo CSS display, por ejemplo, para desaparecer: ancla.style.display = 'none';

Luego para volverlo a mostrar se le asigna otro valor: ancla.style.display = 'inline';

22.5. Actividades

Page 252: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

238

22.5.1. Actividad 1

Crea un formulario, con el que se puedan subir ficheros. Con javascript, añade la posibilidad que después de pulsar un botón (evento onclick), se añada un campo más para subir ficheros. Ten en cuenta de que los campos de los ficheros deberán tener el atributo “name” diferente, para que se pueda coger después con PHP.

22.5.2. Actividad 2

Crea un cronómetro con Javascript, que tenga los botones de Inicio/Pausa (Cuando se inicie, botón pasará a ser pausa y viceversa), y Parada (Vuelta a 0). Deberá contemplar milisegundos, segundos, minutos y horas.

Page 253: Php-Mysql

BIBLIOTECAS JAVASCRIPT BASICAS: JCUERY Y MOOTOOLS

239

Bibliotecas Javascript básicas: Jquery y Mootools

Al igual que podemos encontrarnos bibliotecas y frameworks en PHP con los que tenemos mucho código resuelto, en javascript nos pasa lo mismo. Dos de las bibliotecas que más destacan hoy dia son JQuery (http://jquery.com) y MooTools (http://mootools.net).

Pasemos a pegar un breve vistazo sobre JQuery y MooTools.

23.1.1.1. JQuery

jQuery consiste en un único fichero JavaScript que contiene las funcionalidades comunes de DOM, eventos, efectos y AJAX.

La característica principal de la biblioteca es que permite cambiar el contenido de una página web sin necesidad de recargarla, mediante la manipulación del árbol DOM y peticiones AJAX. Para ello utiliza las funciones $() o jQuery().

A partir de este fichero Javascript, nos podemos encontrar más bibliotecas que va creando la comunidad del software libre que usen JQuery, como para crear pequeños calendarios, o funcionalidades enteras como para simular por ejemplo el comportamiento de las cajas de iGoogle.

Función $()

Page 254: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

240

La forma de interactuar con la página es mediante la función $() (un alias de jQuery()) que recibe como parámetro una expresión CSS o el nombre de una etiqueta HTML y devuelve todos los nodos (elementos) que concuerden con la expresión. $("#tablaAlumnos") //Devolverá el elemento con id="tablaAlumnos" $(".activo") //Devolverá una matriz de elementos que contenga el estilo "activo"

Una vez obtenidos los nodos, se les puede aplicar cualquiera de las funciones que facilita la biblioteca. // Una vez obtenidos todos los nodos que contenga el estilo "activo" // se les elimina ese estilo (removeClass()) y se les aplica uno nuevo (addClass()) $(".activo").removeClass("activo").addClass("inactivo");

23.1.1.2. MooTools

A diferencia de JQuery, donde el framework al completo se encuentra en un solo fichero, mootools, se divide en varios ficheros donde se encuentran diferentes funcionalidades. De hecho, al descargar mootools desde su web, es posible descargar sólo las partes que tiene pensado utilizar y sus dependencias necesarias:

Core: colección de funciones de apoyo de las que hace uso el resto de components.

Class: es la biblioteca base de MooTools para la instanciación de objetos

Natives: Colección de mejoras al objeto nativo JavaScript, añadiendo funcionalidades, compatibilidad y nuevos métodos que simplifican el código.

Element: multitud de mejoras y compatibilidades al objeto HTML

Effects: API avanzada para animar Elements

Remote: proporciona una interfaz para peticiones XHR, Cookie y herramientas para JSON

Window: Proporciona una interfaz, válida para cualquier navegador, para obtener información del cliente, por ejemplo el tamaño de la ventana

Las funciones $() y $$()

Al igual que JQuery en MooTools existe $(), pero su diferencia radica en que en MooTools con $() solo podremos hacer referencia a un elemento con un identificativo en concreto, es decir, ni clases CSS ni elementos HTML.

con $$() podremos seleccionar varios elementos a la vez, como por ejemplo todos los elementos “a” y elementos “h1” //Seleccionamos todos los enlaces y h1. var misElementos = $$('a', 'h1');

23.2. Validaciones de formularios con JavaScript.

Ahora que ya hemos visto como acceder a elementos del DOM a mano, veremos como hacer una validación de formularios gracias a JQuery y MooTools. Pero antes de hacerlo, solo recordar algo importante. JavaScript, puede estar desactivado por el usuario, así que para aumentar nuestra seguridad, deberíamos hacer tambien una validación en nuestro código PHP, para evitar posibles errores. ¿Que adelantaríamos entonces poniendo una comprobación en javascript además de la que hagamos en

Page 255: Php-Mysql

BIBLIOTECAS JAVASCRIPT BASICAS: JCUERY Y MOOTOOLS

241

PHP? Pues por ejemplo que el usuario no tenga que recargar la página. Lo que se podría traducir en ahorro de ancho de banda si tuviésemos una cantidad crítica de usuarios y formularios, por poner un ejemplo: Facebook tiene a dia de hoy más de 300 millones de usuarios poniendo comentarios donde se comprueba continuamente el máximo de caracteres… Al hacer una comprobación previa, nos podríamos evitar muchas recargas de la web y por tanto, mucho ancho de banda.

23.2.1. Validación con JQuery

Para este ejemplo usaremos el plugin validate (http://docs.jquery.com/Plugins/Validation#Example)

Primero en el head, incluiremos los ficheros de JQuery necesarios, y pondremos unos estilos básicos. <head> <script type="text/javascript" src="jquery-1.2.6.pack.js"></script> <script type="text/javascript" src="jquery.validate.min.js"></script> <script type="text/javascript" src="jquery.metadata.js"></script> <style> form {width:700px;height:520px;display:inline;float:left;margin:20px 0 0

0} label { color: #000; font-size: 1em; line-height: 140%; margin: 10px 0

.2em 90px; display: block; } input.textField { width: 350px; color: #000; font-size: 1.1em; padding:

4px; background: #fff; border: 1px solid #999; margin: 0 0 20px 0; display: inline;margin: 0 0 .2em 90px; }

textarea.textArea { width: 500px; height: 150px; color: #000; font-family: Tahoma,tahoma,sans-serif,Arial,Tahoma,Verdana;font-size: 1em; padding: 4px; background: #fff; border: 1px solid #999; margin: 0 0 .2em 90px; overflow: auto; }

.error-message, label.error { color: #a10052; margin: 0 0 .5em 90px; display: block; font-size: 1em !important;font-weight:bold; }

</style> </head>

Acto seguido, crearemos nuestro formulario de ejemplo (si vas a incluir esto como ejemplo, no olvides poner las etiquietas <body> y </body>) <form id="frmContact" method="post"> <fieldset style="display:none;"> <input type="hidden" name="_method" value="POST" /> </fieldset> <label for="ContactName">NOMBRE</label> <input name="data[Contact][name]" type="text" class="textField"

maxlength="255" value="" id="ContactName" /> <label for="ContactRecipient">CORREO ELECTRÓNICO</label> <input name="data[Contact][recipient]" type="text" class="textField "

value="" id="ContactRecipient" /> <label for="ContactPhone">TELÉFONO</label> <input name="data[Contact][phone]" type="text" class="textField"

maxlength="255" value="" id="ContactPhone" /> <label for="ContactMessage">MENSAJE / CONSULTA</label> <textarea name="data[Contact][message]" cols="5" rows="3"

class="textArea" id="ContactMessage" ></textarea> <input type="submit" name="Enviar" value="Enviar" /> </form>

Y finalmente, implementamos nuestra validación al final del fichero html o enlazándolo (pero en este caso, siempre al final del fichero): $(document).ready(function(){ $("#frmContact").validate({ event: "blur", rules: {

Page 256: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

242

'data[Contact][name]': "required", 'data[Contact][recipient]': { required: true, email: true }, 'data[Contact][message]': "required" }, messages: { 'data[Contact][name]': "Por favor ingrese su nombre", 'data[Contact][recipient]': "Ingrese una dirección de e-mail válida", 'data[Contact][message]': "Por favor, ingrese su mensaje o consulta" }, debug: true, errorElement: "label", errorContainer: $("#errores"), submitHandler: function(form){ $.ajax({ type: "POST", url: "contacto.asp", data: "nombre="+$('#ContactName').val()+"&email="+$('#ContactRecipient').val()+"&telefono="+$('#ContactPhone').val()+"&comentario="+$('#ContactMessage').val(), success: function(msg){ if(msg==1){ $("#mensaje").html("El mensaje se ha enviado correctamente"); } } }); } }); });

23.2.2. Validación con MooTools

Al igual que en JQuery, enlazaremos temas y bibliotecas necesarias. En este caso usaremos el plugin FormCheck http://mootools.floor.ch/en/demos/formcheck/ <script type="text/javascript" src="/js/mootools/core.js"></script> <script type="text/javascript" src="/js/mootools/more.js"></script> <script type="text/javascript" src="/js/formcheck/lang/es.js"> </script> <script type="text/javascript" src="/js/formcheck/formcheck.js"> </script> <link rel="stylesheet" href="/js/formcheck/theme/classic/formcheck.css" type="text/css" media="screen" />

este sería el código que usaríamos para activar la validación en nuestro formulario llamado “myform”. Notar que se puede poner antes de <body> ya que usa el evento domready, es decir, cuando se han terminado de cargar los elementos del DOM <script type="text/javascript"> window.addEvent('domready', function(){ new FormCheck('myform'); }); </script>

y después usaríamos construiríamos nuestro formulario. Veamos algunos ejemplos de inputs <form name="myform" method="post" action="mi_url"> URL <input class="validate['required','url']" /><BR /> TELEFONO <input class="validate['required','phone']" /><BR /> Contraseña <input type="password" class="validate['required']" name="password" id="password" /><BR /> Confirma contraseña <input type="text"

Page 257: Php-Mysql

BIBLIOTECAS JAVASCRIPT BASICAS: JCUERY Y MOOTOOLS

243

class="validate['confirm[password]']" name="confirm" /> <input type="submit" value="Enviar" name="submit"> </form>

23.3. Manejo dinámico de elementos HTML

23.3.1.1. JQuery

En http://api.jquery.com/category/manipulation/ tenemos todo el listado de funciones para manipular el DOM. Vamos a ver un pequeño listado de las más habituales.

Crear nuevo elementos html utilizar $() (función factoría).

Veremos como usarla justo en el siguiente ejemplo.

Insertar un nuevo/s elemento/s, dentro de cada elemento/s correspondiente/s:

.append()

.appendTo()

.prepend()

.prependTo()

La diferencia entre metodo y metodoTo, radica en que en el primero, el selector precede al contenido insertado, y en el segundo es al revés, el contenido precede al selector.

Veamoslo mejor con un ejemplo. <h2>Saludos</h2> <div class="container"> <div class="inner">Hola</div> <div class="inner">Adios</div> </div> <script type="text/javascript"> $('.inner').append('<p>Test</p>'); //como se ve, primero aparece el selector, y se le dice cual es el contenido que va a ir dentro. $('<p>Test</p>').appendTo('.inner'); //En este otro caso, primero se crea el contenido con la función factoria $() y //se le dice que ese contenido, irá dentro del selector </script>

Y el código resultante sería en el caso de append: <h2>Saludos</h2> <div class="container"> <div class="inner"> Hola <p>Test</p> </div> <div class="inner"> Adios <p>Test</p> </div> </div>

En el caso de prepend, el bloque p con la palabra test, irían antes de de Hola y Adios.

Insertar nuevo/s elemento/s adyacentes al elemento/s correspondiente/s:

Page 258: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

244

.after()

.insertAfter()

.before()

.insertBefore()

Exactamente el mismo caso: <h2>Saludos</h2> <div class="container"> <div class="inner">Hola</div> <div class="inner">Adios</div> </div> <script type="text/javascript"> $('.inner').after('<p>Test</p>'); //como se ve, primero aparece el selector, y se le dice cual es el contenido que va a ir dentro. $('<p>Test</p>').insertAfter('.inner'); //En este otro caso, primero se crea el contenido con la función factoria $() y //se le dice que ese contenido, irá dentro del selector </script> <!-- código resultante con after/insertAfter --> <div class="container"> <h2>Saludos</h2> <div class="inner">Hola</div> <p>Test</p> <div class="inner">Adios</div> <p>Test</p> </div> <!-- si usásemos before insertBefore, se encontrarían antes de los divs con la clase inner.

Con after/before/insertAfter/insertBefore podemos hacer otras cosas como esto: $('h2').insertAfter($('.container'));

Con lo cual moveríamos el titulo h2 de la siguiente forma: <div class="container"> <div class="inner">Hola</div> <div class="inner">Adios</div> </div> <h2>Saludos</h2>

Reemplazar cada elemento/s correspondiente/s con un nuevo/s elemento/s:

.html()

Con .html podremos coger el contenido de un elemento si lo usamos como getter o incluirlo si lo usamos como setter. Veamos un ejemplo:

Imaginemos el siguiente div: <div class="demo-container"><p>hola</p></div> var myhtml = $('div.demo-container').html(); //aqui estariamos usandolo como "getter". la variable myhtml tendria el valor <p>hola</p> //en este otro caso $('div.demo-container').html("<p>adios</p>); //estamos usandolo como "setter" y cambiando el contenido del div a <p>adios</p> borrando el contenido <p>hola</p>

Page 259: Php-Mysql

BIBLIOTECAS JAVASCRIPT BASICAS: JCUERY Y MOOTOOLS

245

Eliminar elemento/s para cada correspondiente/s elemento/s:

.empty()

Eliminar para cada correspondiente/s elemento/s y sus descendientes, pero sin borrarlos del DOM:

.remove()

La diferencia básica entre empty y remove, es que empty elimina el contenido del elemento del dom, mientras que remove elimina el elemento en sí: <h2>Saludos</h2> <div class="container"> <div class="hola">Hola</div> <div class="adios">Adios</div> </div> <script type="text/javascript"> $('.hola').empty(); </script> <!-- codigo resultante con empty --> <h2>Saludos</h2> <div class="container"> <div class="hola"></div> <!--notese que falta el contenido--> <div class="adios">Adios</div> </div> <script type="text/javascript"> $('.hola').remove(); </script> <!-- codigo resultante con remove --> <h2>Saludos</h2> <div class="container"> <div class="adios">Adios</div><!-- Ahora falta el elemento por completo--> </div>

23.3.1.2. MooTools

Creando un Elemento var miElemento = new Element(tipoElemento, {opciones});

Donde tipo elemento le tenemos que indicar que elemento del dom queremos crear, y en opciones pondremos los parámetros. Veamoslo con un ancla (<a>) var miEnlace = new Element('a', { 'class': 'mi-clase', 'id': 'mi-id', 'href': 'http://sitio.com' });

injectBefore / injectAfter / injectInside: Con esto conseguiremos insertar antes, después o dentro de otro elemento respectivamente. Por ejemplo: <div id="otroElemento"></div>

Y usamos var elemento = new Element('div', {'id':'MiElemento'}); elemento.injectBefore('otroElemento');

Nos quedaría:

Page 260: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

246

<div id="MiElemento"></div> <!-- se ha insertado justo antes (before) del otro elemento --> <div id="otroElemento"></div>

Si hiciéramos lo mismo con After, se insertaría inmediatamente después, y con Inside, dentro.

Si quisiéramos introducir texto dentro de un elemento, usaríamos appendText(texto). Recuerda que si quieres insertar html hay que usar injectInside, ya que appendText traduciría los caracteres especiales a código html. <div id="elemento"></div> <script type="text/javascript"> $('elemento').appendText('Mi textoooooo'); </script> <!-- codigo resultante --> <div id="elemento">Mi textoooooo</div>

Para borrar un elemento, en MooTools tambien existe el metodo .remove: <div id="miElemento"> <div id="aborrar"></div> </div> <script type="text/javascript"> $('aborrar').remove() </script> <!-- codigo resultante --> <div id="miElemento"> </div>

En http://www.jourmoly.com.ar/ hay una buena recopilación con más métodos en castellano de como modificar el DOM con MooTools, aunque si quieres una documentación mas amplia, es mejor ir a la propia documentación de Mootools (en este caso, para el DOM) http://mootools.net/docs/core/Element/Element

23.4. Actividades

23.4.1.1. Actividad 1

Busca más ejemplos de JQuery y MooTools de funcionalidades parecidas, y compara como lo hacen cada uno.

23.4.1.2. Actividad 2

Después de tu experiencia con JQuery y Mootools ¿Con cual te quedarías?. Participa en un debate con el resto de tus compañeros y compañeras, defendiendo tu elección.

Page 261: Php-Mysql

INTRODUCCION A AJAX

247

Introducción a Ajax

Ajax, acrónimo de Asynchronous JavaScript And XML (JavaScript asíncrono y XML), es una técnica de desarrollo web para crear aplicaciones interactivas o RIA (Rich Internet Applications). Estas aplicaciones se ejecutan en el cliente, es decir, en el navegador web de los usuarios mientras se mantiene la comunicación asíncrona con el servidor en segundo plano. De esta forma es posible realizar cambios sobre las páginas sin necesidad de recargarlas, lo que significa aumentar la interactividad, velocidad y usabilidad en las aplicaciones.

Ajax es una tecnología asíncrona, en el sentido de que los datos adicionales se requieren al servidor y se cargan en segundo plano sin interferir con la visualización ni el comportamiento de la página. JavaScript es el lenguaje interpretado (scripting language) en el que normalmente se efectúan las funciones de llamada de Ajax mientras que el acceso a los datos se realiza mediante XMLHttpRequest, objeto disponible en los navegadores actuales. En cualquier caso, no es necesario que el contenido asíncrono esté formateado en XML.

Ajax es una técnica válida para múltiples plataformas y utilizable en muchos sistemas operativos y navegadores dado que está basado en estándares abiertos como JavaScript y Document Object Model (DOM).

24.1. Tecnologías incluidas en Ajax

Ajax es una combinación de cuatro tecnologías ya existentes:

Page 262: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

248

XHTML o HTML y CSS para el diseño que acompaña a la información.

DOM accedido con un lenguaje de scripting por parte del usuario, especialmente implementaciones ECMAScript como JavaScript y JScript, para mostrar e interactuar dinámicamente con la información presentada.

El objeto XMLHttpRequest para intercambiar datos de forma asíncrona con el servidor web. En algunos frameworks y en algunas situaciones concretas, se usa un objeto iframe en lugar del XMLHttpRequest para realizar dichos intercambios.

XML es el formato usado generalmente para la transferencia de datos solicitados al servidor, aunque cualquier formato puede funcionar, incluyendo HTML preformateado, texto plano, JSON, YAML.

Como el DHTML, o LAMP, Ajax no constituye una tecnología en sí, sino que es un término que engloba a un grupo de éstas que trabajan conjuntamente.

24.2. Problemas e Inconvenientes

Las páginas con AJAX son mas difíciles de desarrollar que las páginas estáticas.

Las páginas creadas dinámicamente mediante peticiones sucesivas AJAX, no son registradas de forma automática en el historial del navegador, así que haciendo clic en el botón de “volver” del navegador, el usuario no sera devuelto a un estado anterior de la página, en cambio puede volver a la última página que visitó. Soluciones incluyen el uso de IFrames invisible para desencadenar cambios en el historial del navegador y el cambio de la porción de anclaje de la dirección (después de un #).

Los motores de búsquedas no entienden JavaScript. La información en la página dinámica no se almacena en los registros del buscador.

Hay problemas usando Ajax entre nombres de dominios. Eso es una función de seguridad.

El sitio con Ajax usa más recursos en el servidor.

Es posible que páginas con Ajax no puedan funcionar en teléfonos móviles, PDA u otros aparatos. Ajax no es compatible con todos los software para ciegos u otras discapacidades.

24.3. Métodos HTTP

Un mensaje http consiste en una petición de un cliente al servidor y en la respuesta del servidor al cliente.

24.3.1.1. Método OPTIONS

Este método representa un petición de información sobre las opciones de comunicación disponibles en la cadena petición-respuesta identificada por la URI de la petición.

Page 263: Php-Mysql

INTRODUCCION A AJAX

249

24.3.1.2. Método GET

El método GET requiere la devolución de información al cliente identificada por la URI.

24.3.1.3. Método HEAD

El método HEAD es igual que el método GET, salvo que el servidor no tiene que devolver el contenido, sólo las cabeceras.

24.3.1.4. Método POST

El método POST se usa para hacer peticiones en las que el servidor destino acepta el contenido de la petición como un nuevo subordinado del recurso pedido.

24.3.1.5. Método PUT

El método PUT permite guardar el contenido de la petición en el servidor bajo la URI de la petición.

24.3.1.6. Método DELETE

Este método se usa para que el servidor borre el recurso indicado por la URI de la petición.

24.3.1.7. Método TRACE

Este método se usa para saber si existe el receptor del mensaje y usar la información para hacer un diagnóstico.

24.4. Objeto XMLHTTPRequest

*XMLHttpRequest*, es una API empleada para realizar peticiones HTTP y HTTPS a servidores Web. Para los datos transferidos se usa cualquier codificación basada en texto, incluyendo: texto plano, XML, JSON, HTML y codificaciones particulares específicas. La interfaz se presenta como una clase de la que una aplicación cliente puede generar tantas instancias como necesite para manejar el diálogo con el servidor.

El uso más popular, si bien no el único, de esta interfaz es proporcionar contenido dinámico y actualizaciones asíncronas en páginas WEB mediante tecnologías construidas sobre ella como por ejemplo AJAX.

Historia

La primera versión de la interfaz XMLHttpRequest fue desarrollada por Microsoft que la introdujo en la versión 5.0 de Internet Explorer. Esta primera versión se publicó utilizando un objeto ActiveX, lo que significa que puede ser utilizada desde cualquier entorno de desarrollo de software con soporte para esta tecnología, es decir, la práctica totalidad de plataformas generalistas de desarrollo para Microsoft Windows. Microsoft ha seguido manteniendo y actualizando esta tecnología incluyendo la funcionalidad dentro del *Microsoft XML Parser (MSXML)* en sus sucesivas versiones. A partir de la versión 7 de Internet Explorer la interfaz se ofrece de manera integrada. Al ser integrada, el acceso a

Page 264: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

250

la interfaz se realiza enteramente con objetos (JScript o VBScript) proporcionados por el navegador y no mediante bibliotecas externas.

El proyecto Mozilla incorporó la primera implementación integrada de XMLHttpRequest en la versión 1.0 de la Suite Mozilla en 2002. Esta implementación sería seguida por Apple a partir de Safari 1.2, Konqueror, Opera Software a partir del Opera 8.0 e iCab desde la versión 3.0b352.

El W3C (World Wide Web Consortium) presentó el 27 de septiembre de 2006 el primer borrador de una especificación estándar de la interfaz. La versión actual de 15 de abril de 2008, etiquetada como borrador final, es el resultado de varias revisiones.

Mientras no se alcance una versión definitiva, los desarrolladores de aplicaciones WEB deberán tener en cuenta las diferencias entre implementaciones o bien utilizar paquetes o frameworks que realicen esta función.

Evolución de la interfaz

El 25 de febrero de 2008 se publicó la primera versión de la especificación *XMLHttpRequest Level 2*. Esta nueva especificación, que se inicia antes de haber publicado la versión definitiva de la interfaz, pretende añadir nuevas funciones como: peticiones entre dominios (*cross-site*), eventos de progreso y manejo de flujos de bytes (*streams*) tanto para el envío como para la recepción.

Implementación y uso de la interfaz

La interfaz se presenta encapsulada en una clase. Para utilizarlo, la aplicación cliente debe crear una nueva instancia mediante el constructor adecuado. Es posible realizar peticiones síncronas y asíncronas al servidor; en una llamada asíncrona el flujo de proceso no se detiene a esperar la respuesta como se haría en una llamada síncrona, si no que se define una función que se ejecutará cuando se complete la petición: un manejador de evento.

XMLHttpRequest es una interfaz para realizar llamadas mediante HTTP, por lo que es recomendable un buen conocimiento de este protocolo. Es importante el manejo correcto de la cache en el servidor HTTP, en los proxy cache intermedios y en el navegador WEB.

Otro elemento importante es el manejo de juegos de caracteres, la codificación y decodificación de texto y su identificación mediante cabeceras HTTP y MIME. El estándar XMLHttpRequest recomienda UTF-8 para la codificación de cadenas de texto. La codificación particular de los datos transmitidos se determina según el siguiente algoritmo, utilizando la primera opción que corresponda.

Si los datos transmitidos son XML o HTML, y así se identifica mediante la correspondiente cabecera Content-Type de HTTP, la codificación se detectará basándose en las reglas estándar de XML o HTML según corresponda.

Si la cabecera HTTP especifica un tipo MIME mediante Content-Type e identifica un charset se utiliza dicho charset.

Si los datos enviados especifican un BOM (byte order mark) válido, se utilizará la variante UTF determinada por dicho BOM. (Es decir UTF-8, UTF-16 o UTF-32).

Utilizar UTF-8.

Es importante tener esto en cuenta en entornos dónde se mezclen varias codificaciones, por ejemplo, pueden producirse errores de visualización de caracteres al incorporar funcionalidad AJAX a una página WEB codificada con ISO 8859-1.

Page 265: Php-Mysql

INTRODUCCION A AJAX

251

24.4.1.1. Atributos

Atributo Descripción readyState Devuelve el estado del objeto como sigue: 0 =

sin inicializar, 1 = abierto, 2 = cabeceras recibidas, 3 = cargando y 4 = completado.

responseBody (Level 2) Devuelve la respuesta como un array de bytes

responseText Devuelve la respuesta como una cadena responseXML Devuelve la respuesta como XML. Esta

propiedad devuelve un objeto documento XML, que puede ser examinado usando las

propiedades y métodos del árbol del DOM. status Devuelve el estado como un número (p. ej. 404

para “Not Found” y 200 para “OK”). statusText Devuelve el estado como una cadena (p. ej. “Not

Found” o “OK”).

24.4.1.2. Métodos

Método Descripción abort() Cancela la petición en curso

getAllResponseHeaders() Devuelve el conjunto de cabeceras HTTP como una cadena.

getResponseHeader( nombreCabecera ) Devuelve el valor de la cabecera HTTP especificada.

open( método, URL [, asíncrono[, nombreUsuario [, clave]]] )

Especifica el método, URL y otros atributos opcionales de una petición. El parámetro de

método puede tomar los valores “GET”, “POST”, o “PUT” (“GET” y “POST” son dos

formas para solicitar datos, con “GET” los parámetros de la petición se codifican en la URL

y con “POST” en las cabeceras de HTTP). El parámetro URL puede ser una URL relativa o

completa. El parámetro asíncrono especifica si la petición será gestionada asíncronamente o no. Un valor true indica que el proceso del

script continúa después del método send(), sin esperar a la respuesta, y false indica que el

script se detiene hasta que se complete la operación, tras lo cual se reanuda la ejecución.

En el caso asíncrono se especifican manejadores de eventos, que se ejecutan ante cada cambio de

estado y permiten tratar los resultados de la consulta una vez que se reciben, o bien gestionar

eventuales errores. send([datos]) Envía la petición

setRequestHeader( etiqueta, valor ) Añade un par etiqueta/valor a la cabecera HTTP a enviar.

24.4.1.3. Eventos

Propiedad Descripción onreadystatechange Evento que se dispara con cada cambio de

estado.

Page 266: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

252

onabort (Level 2) Evento que se dispara al abortar la operación.

onload (Level 2) Evento que se dispara al completar la carga.

onloadstart (Level 2) Evento que se dispara al iniciar la carga.

onprogress (Level 2) Evento que se dispara periódicamente con información de estado.

La propuesta inicial de W3C no incluye propiedades y eventos presentes en implementaciones reales, como por ejemplo los eventos onload, onerror, onprogress, onabort y ontimeout. Algunos de ellos sí son recogidos por la nueva especificación Level 2, como puede verse en el cuadro anterior.

Instanciación del objeto

A continuación se muestra un posible código JavaScript que permite crear el objeto teniendo en cuenta las diferencias entre los navegadores más populares. var httpRequest; if (window.XMLHttpRequest) { //El explorador implementa la interfaz de forma nativa httpRequest = new XMLHttpRequest(); } else if (window.ActiveXObject) { //El explorador permite crear objetos ActiveX try { httpRequest = new ActiveXObject("MSXML2.XMLHTTP"); } catch (e) { try { httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!httpRequest) { alert("No ha sido posible crear una instancia de XMLHttpRequest"); }

24.5. Formatos de intercambio de Información

Para poder cambiar información en servicios web, lo más normal es usar un formato marcado para dicho intercambio. Como son XML, JSON y YAML. XML ya lo hemos visto anteriormente en el curso, y JSON y YAML siguen más o menos la misma finalidad. Aunque YAML no es del todo utilizado a la hora de desarrollar aplicaciones AJAX ya que se utiliza mejor JSON para este tipo de menesteres (o XML), si es más normal verlo por otros servicios web realizados por ejemplo con SOAP.

Veremos ahora la misma información parseada con los diferentes formatos, y en el caso de JSON y YAML un poco más de información debido a que no lo hemos visto anteriormente en el curso.

XML <menu id="file" value="File"> <popup> <menuitem value="New" onclick="CreateNewDoc()" />

Page 267: Php-Mysql

INTRODUCCION A AJAX

253

<menuitem value="Open" onclick="OpenDoc()" /> <menuitem value="Close" onclick="CloseDoc()" /> </popup> </menu>

JSON {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }}

JSON, acrónimo de JavaScript Object Notation, es un formato ligero para el intercambio de datos. JSON es un subconjunto de la notación literal de objetos de JavaScript que no requiere el uso de XML.

La simplicidad de JSON ha dado lugar a la generalización de su uso, especialmente como alternativa a XML en AJAX. Una de las supuestas ventajas de JSON sobre XML como formato de intercambio de datos en este contexto es que es mucho más sencillo escribir un analizador semántico de JSON. En JavaScript, un texto JSON se puede analizar fácilmente usando el procedimiento eval(), lo cual ha sido fundamental para que JSON haya sido aceptado por parte de la comunidad de desarrolladores AJAX, debido a la ubicuidad de JavaScript en casi cualquier navegador web.

En la práctica, los argumentos a favor de la facilidad de desarrollo de analizadores o del rendimiento de los mismos son poco relevantes, debido a las cuestiones de seguridad que plantea el uso de eval() y el auge del procesamiento nativo de XML incorporado en los navegadores modernos. Por esa razón, JSON se emplea habitualmente en entornos donde el tamaño del flujo de datos entre cliente y servidor es de vital importancia (de aquí su uso por Yahoo, Google, etc, que atienden a millones de usuarios) cuando la fuente de datos es explícitamente de fiar y donde no es importante el no disponer de procesamiento XSLT para manipular los datos en el cliente.

Si bien es frecuente ver JSON posicionado contra XML, también es frecuente el uso de JSON y XML en la misma aplicación. Por ejemplo, una aplicación de cliente que integra datos de Google Maps con datos meteorológicos en SOAP hacen necesario soportar ambos formatos.

Cada vez hay más soporte de JSON mediante el uso de paquetes escritos por terceras partes. La lista de lenguajes soportados incluye ActionScript, C, C++, C#, ColdFusion, Common Lisp, Delphi, E, Eiffel, Java, JavaScript, ML, Objective CAML, Perl, PHP, Python, Rebol, Ruby, y Lua.

En diciembre de 2005 Yahoo! comenzó a dar soporte opcional de JSON en algunos de sus servicios web.

El término JSON está altamente difundido en los medios de programación, sin embargo, es un término mal descrito ya que en realidad es solo una parte de la definición del estándar ECMA-262 en que está basado Javascript. De ahí que ni Yahoo, ni Google emplean JSON, sino LJS. Una de las cualidades intrínsecas de Javascript denominada LJS (Literal Javascript) facilita el flujo de datos e incluso de funciones, para la cual no requiere la función eval() si son datos los que se transfieren como en el caso de xml. Todo lo referente a transferencia de datos en todos sus tipos, incluyendo arrays, booleans, integers, etc. no requieren de la función eval(), y es precisamente en eso en donde supera por mucho JavaScript al XML, si se utiliza el LJS y no la incorrecta definición de JSON.

Page 268: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

254

YAML 'menu': 'id': 'file' 'popup': 'menuitem': - {'onclick': 'CreateNewDoc()', 'value': 'New'} - {'onclick': 'OpenDoc()', 'value': 'Open'} - {'onclick': 'CloseDoc()', 'value': 'Close'} 'value': 'File'

YAML fue creado bajo la creencia de que todos los datos pueden ser representados adecuadamente como combinaciones de listas, hashes (mapeos) y datos escalares (valores simples). La sintaxis es relativamente sencilla y fue diseñada teniendo en cuenta que fuera muy legible pero que a la vez fuese fácilmente mapeable a los tipos de datos más comunes en la mayoría de los lenguajes de alto nivel. Además, YAML utiliza una notación basada en el indentación y/o un conjunto de caracteres Sigil distintos de los que se usan en XML, haciendo que sea fácil componer ambos lenguajes.

Los contenidos en YAML se describen utilizando el conjunto de caracteres imprimibles de Unicode, bien en UTF-8 o UTF-16.

La estructura del documento se denota indentando con espacios en blanco; sin embargo no se permite el uso de caracteres de tabulación para indentar.

Los miembros de las listas se denotan encabezados por un guión ( - ) con un miembro por cada línea, o bien entre corchetes ( [ &nbsp; ] ) y separados por coma espacio ( , &nbsp; ).

Los arrays asociativos se representan usando los dos puntos seguidos por un espacio. en la forma “clave: valor”, bien uno por línea o entre llaves ( { &nbsp; } ) y separados por coma seguida de espacio ( , &nbsp; ).

Un valor de un array asociativo viene precedida por un signo de interrogación ( ? ), lo que permite que se construyan claves complejas sin ambigüedad.

Los valores sencillos (o escalares) por lo general aparecen sin entrecomillar, pero pueden incluirse entre comillas dobles ( ” ), o comillas simples ( ' ).

En las comillas dobles, los caracteres espaciales se pueden representar con secuencias de escape similares a las del lenguaje de programación C, que comienzan con una barra invertida ( \ ).

Se pueden incluir mútliples documentos dentro de un único flujo, separándolos por tres guiones ( — ); los tres puntos ( … ) indican el fin de un documento dentro de un flujo.

Los nodos repetidos se pueden denotar con un ampersand ( &amp; ) y ser referidos posteriormente usando el asterisco ( * )

Los comentarios vienen encabezados por la almohadilla ( # ) y continúan hasta el final de la línea.

Los nodos pueden etiquetarse con un tipo o etiqueta utilizando el signo de exclamación( ! ) seguido de una cadena que puede ser expandida en una URL.

Los documentos YAML pueden ser precedidos por directivas compuestas por un signo de porcentaje ( % ) seguidos de un nombre y parámetros delimitados por espacios.. Hay definidas dos directivas en YAML 1.1:

La directiva %YAML se utiliza para identificar la versión de YAML en un documento dado.

Page 269: Php-Mysql

INTRODUCCION A AJAX

255

La directiva %TAG se utiliza como atajo para los prefijos de URIs. Estos atajos pueden ser usados en las etiquetas de tipos de nodos.

YAML requiere que las comas y puntos y comas que se utilicen como separadores en las listas sean seguidos por un espacio, de forma que los valores escalares que contengan signos de puntuación (como 5,280 o http://www.url.com) se puedan representar sin necesidad de utilizar comillas.

Hay dos caracteres adicionales que están reservados en YAML para su posible estandarización en un futuro: la arroba ( @ ) y el acento grave ( ` ).

Page 270: Php-Mysql
Page 271: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

257

Construcción de servicios web en PHP.

25.1. Introducción a los servicios web

Un Web Service o servicio web es un conjunto de protocolos y estándares que sirven para intercambiar datos entre aplicaciones. Distintas aplicaciones de software desarrolladas en lenguajes de programación diferentes, y ejecutadas sobre cualquier plataforma, pueden utilizar los servicios web para intercambiar datos tanto en red como a traves de Internet. La interoperabilidad se consigue mediante la adopción de estándares abiertos. Las organizaciones OASIS y W3C son los comités responsables de la arquitectura y reglamentación de los servicios Web. Para mejorar la interoperabilidad entre distintas implementaciones de servicios Web se ha creado el organismo WS-I, encargado de desarrollar diversos perfiles para definir de manera más exhaustiva estos estándares.

25.1.1. Soap

SOAP (siglas de Simple Object Access Protocol) es un protocolo estándar que define cómo dos objetos en diferentes procesos pueden comunicarse por medio de intercambio de datos XML. Este protocolo deriva de un protocolo creado por David Winer en 1998, llamado XML-RPC. SOAP fue creado por Microsoft, IBM y otros y está actualmente bajo el auspicio de la W3C. Es uno de los protocolos utilizados en los servicios Web.

Page 272: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

258

Desde PHP5 el soporte para SOAP es nativo, por lo que al programador se le facilita mucho más la vida gracias a las clases SoapServer y SoapClient. La documentación la podemos encontrar aquí: http://www.php.net/manual/es/book.soap.php

25.1.2. REST

REST o Transferencia de Estado Representacional (Representational State Transfer) es una técnica de arquitectura software para sistemas hipermedia distribuidos como la World Wide Web. El término se originó en el año 2000, en una tesis doctoral sobre la web escrita por Roy Fielding, uno de los principales autores de la especificación del protocolo HTTP y ha pasado a ser ampliamente utilizado por la comunidad de desarrollo.

Si bien el término REST se refería originalmente a un conjunto de principios de arquitectura —descritos más abajo—, en la actualidad se usa en el sentido más amplio para describir cualquier interfaz web simple que utiliza XML y HTTP, sin las abstracciones adicionales de los protocolos basados en patrones de intercambio de mensajes como el protocolo de SOAP. Es posible diseñar sistemas de servicios web de acuerdo con el estilo arquitectural REST de Fielding y también es posible diseñar interfaces XMLHttpRequest de acuerdo con el estilo de llamada a procedimiento remoto (también conocido como RPC) pero sin usar SOAP. Estos dos usos diferentes del término REST causan cierta confusión en las discusiones técnicas, aunque RPC no es un ejemplo de REST.

Los sistemas que siguen los principios REST se llaman con frecuencia RESTful; los defensores más acérrimos de REST se llaman a sí mismos RESTafaris.

REST afirma que la web ha disfrutado de escalabilidad como resultado de una serie de diseños fundamentales clave:

Un protocolo cliente/servidor sin estado: cada mensaje HTTP contiene toda la información necesaria para comprender la petición. Como resultado, ni el cliente ni el servidor necesitan recordar ningún estado de las comunicaciones entre mensajes. Sin embargo, en la práctica, muchas aplicaciones basadas en HTTP utilizan cookies y otros mecanismos para mantener el estado de la sesión (algunas de estas prácticas, como la reescritura de URLs, no son permitidas por REST)

Un conjunto de operaciones bien definidas que se aplican a todos los recursos de información: HTTP en sí define un conjunto pequeño de operaciones, las más importantes son POST, GET, PUT y DELETE. Con frecuencia estas operaciones se equiparan a las operaciones CRUD que se requieren para la persistencia de datos, aunque POST no encaja exactamente en este esquema.

Una sintaxis universal para identificar los recursos. En un sistema REST, cada recurso es direccionable únicamente a través de su Uniform Resource Identifier (URI).

El uso de hipermedios, tanto para la información de la aplicación como para las transiciones de estado de la aplicación: la representación de este estado en un sistema REST son típicamente HTML o XML. Como resultado de esto, es posible navegar de un recurso REST a muchos otros, simplemente siguiendo enlaces sin requerir el uso de registros u otra infraestructura adicional.

25.1.3. En otras palabras

Para diferenciar SOAP y REST, vamos a verlo de la siguiente forma. Nota: Es una explicación muy a grosso modo, que la veremos más a fondo en los ejemplos que pongamos en los siguientes puntos.

Page 273: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

259

Con SOAP, imaginemos que tenemos una aplicación servidor en la que se nos ofrece una serie de métodos definidos en un fichero xml (llamado wsdl), como pueden ser por ejemplo: getUsers(); getUser($id); ...

Y nosotros desde nuestra aplicación cliente, lo que hacemos es utilizar dichas funciones (utilizando como referencia el fichero wsdl).

Mientras que desde REST, lo que hacemos es uso de los métodos HTTP antes nombrados (GET, POST, PUT, DELETE…) y dependiendo de la ruta de acceso haremos unas cosas u otras.

Por ejemplo

a través de miaplicacion.com/users/ con un metodo GET accederemos al listado de usuarios

a traves de miaplicacion.com/users/1 con un metodo GET accederemos a la descripción del usuario con identificativo 1

a traves de miaplicacion.com/users/1 con un metodo PUT accederemos a la modificación del usuario con identificativo 1

Como observamos, la estructura de la URL es muy específica, y no se usa el formato típico de ”?variable=valor&variable2=valor2” si no que se utiliza una estructura de “Pretty URL”. Que gracias a ella, es mucho más sencillo de entender para los humanos. Si queremos usar pretty urls en nuestro servidor, habrá que habilitarlo mediante la directiva mod_rewrite. Mientras que desde REST

25.2. Actividad

Busca webs que ofrezcan APIs de acceso a sus datos via web service, ya sea por SOAP o por REST

25.3. Desarrollo de servicios web

Para poder comprender a la perfección un servicio web, veamos un ejemplo hecho con SOAP. (Nota: Si se quiere usar estos ejemplos, es necesario instalar la extensión de PHP5 adecuada, en nuestro caso php-soap. En ubuntu con hacer un “sudo aptitude install php-soap” valdria).

Fichero WSDL inventory.wsdl <?xml version='1.0' encoding='UTF-8' ?> <definitions name='Inventory' targetNamespace='urn:TestInventario' xmlns:tns='urn:TestInventario' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'

Page 274: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

260

xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/' xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/' xmlns='http://schemas.xmlsoap.org/wsdl/'> <message name='getItemCountRequest'> <part name='upc' type='xsd:string'/> </message> <message name='getItemCountResponse'> <part name='Result' type='xsd:integer'/> </message> <portType name='InventoryPortType'> <operation name='getItemCount'> <input message='tns:getItemCountRequest'/> <output message='tns:getItemCountResponse'/> </operation> </portType> <binding name='InventoryBinding' type='tns:InventoryPortType'> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='getItemCount'> <soap:operation soapAction='urn:xmethods-delayed-quotes#getItemCount'/> <input> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </input> <output> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </output> </operation> </binding>

Page 275: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

261

<service name='InventoryService'> <port name='InventoryPort' binding='InventoryBinding'> <soap:address location='http://direccion_de_mi_servidor/server.php'/> </port> </service> </definitions>

Fichero server.php <?php require 'inventory_functions.php'; ini_set("soap.wsdl_cache_enabled", "0"); // Para nuestro ejemplo no necesitamos el cacheado del WSDL, asi que lo desactivamos $server = new SoapServer("inventory.wsdl"); $server->addFunction("getItemCount"); $server->handle(); ?>

Nota: En este ejemplo se usan solamente funciones mediante el método “addFunction()”, pero es posible incluir clases enteras gracias a la método “addClass()”.

Nuestro fichero con las funciones necesarias inventory_functions.php. <?php function getItemCount($upc){ //in reality, this data would be coming from a database $items = array('12345'=>5,'19283'=>100,'23489'=>'234'); return $items[$upc]; } ?>

Y por último nuestra aplicación cliente. <?php ini_set("soap.wsdl_cache_enabled", "0"); // disabling WSDL cache $client = new SoapClient("http://ruta_a_servidor_con_fichero_wsdl/inventory.wsdl"); $return = $client->getItemCount('12345'); print_r($return); ?>

Page 276: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

262

Todo servicio web necesita de 3 pasos: Captura de parámetros, Tratamiento de datos y Exportación de datos. Tanto en la captura de parámetros como en la exportación de datos, necesitamos saber que tipo de dato estamos pasando, así como las reglas de intercambio (si vamos a pasarlo como texto plano,un JSON, un XML…)

En SOAP y gracias a el soporte nativo de PHP5 de este protocolo, todo esto es muy sencillo como se ha podido ver. En nuestro ejemplo, para hacer la captura de parámetros y la exportación de datos, (entre otras cosas), usamos el fichero WSDL. Que no es más que un fichero en XML que detalla toda la lógica de negocio de dónde está nuestro servidor, que funciones disponibles hay, y qué parámetros se pueden usar (tipo de dato del parámetro) y qué nos van a devolver las funciones.

Captura de parámetros y exportación de datos

Por ejemplo: <service name='InventoryService'> <port name='InventoryPort' binding='InventoryBinding'> <soap:address location='http://direccion_de_mi_servidor/server.php'/> </port> </service>

En esta parte diríamos donde está nuestro servidor.

En esta otra parte: <message name='getItemCountRequest'> <part name='upc' type='xsd:string'/> </message> <message name='getItemCountResponse'> <part name='Result' type='xsd:integer'/> </message> <portType name='InventoryPortType'> <operation name='getItemCount'> <input message='tns:getItemCountRequest'/> <output message='tns:getItemCountResponse'/> </operation> </portType>

Definimos los métodos disponibles, y qué parámetros y valores acepta y devuelve respectivamente. Donde se ve, que tenemos disponible la operación getItemCount, y en el Request(captura de parámetros) necesitamos una cadena de texto (string) y nos devuelve en el Response (parámetros devueltos) un entero (integer)

En el resto del fichero, la parte de los bindings, es la parte en la que le decimos la codificación que vamos a usar en dicha comunicación, en este caso usaremos un XML

Page 277: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

263

genérico disponible en schemas.xmlsoap.org, y que la comunicación será tipo “RPC” (no olvidemos que SOAP está basada en RPC): <binding name='InventoryBinding' type='tns:InventoryPortType'> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='getItemCount'> <soap:operation soapAction='urn:xmethods-delayed-quotes#getItemCount'/> <input> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </input> <output> <soap:body use='encoded' namespace='urn:xmethods-delayed-quotes' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/> </output> </operation> </binding>

Tratamiento de datos

El tratamiento de datos es la lógica que nosotros queramos darle a nuestro servicio. Acceder a BBDD, tratar cadenas, etc… En nuestro ejemplo SOAP, las funciones estarían en el fichero inventory_functions.php. donde en este caso sólo devolvemos un valor de un array. <?php function getItemCount($upc){ //estos datos deberian venir desde BBDD $items = array('12345'=>5,'19283'=>100,'23489'=>'234'); return $items[$upc]; } ?>

25.4. Ejemplo de uso de un servicio REST: CRUDL

Para este ejemplo usaremos una aplicación servidor escrita en php, y una aplicación cliente que sera la consumidora. Además tomaremos json como formato por defecto.

En el caso de la aplicación consumidora, tendremos un cliente REST genérico.

Page 278: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

264

Además tenemos que tener en cuenta que vamos a usar prettyurls por lo que el servidor apache tendrá que estar correctamente configurado.

Script de configuración de apache Alias /rest /var/www/REST <Directory "/var/www/REST"> Options Indexes FollowSymLinks MultiViews AllowOverride All Order allow,deny Allow from all </Directory> <Location /rest> #Para activar la reescritura RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L] </Location>

Según este Script, tendremos nuestro código en la carpeta /var/www/REST, y accederemos a el, a traves de nuestro navegador en la ruta http://localhost/rest/

Veamos ahora el código de nuestro servidor REST:

Nota: este servidor esta hecho de forma que sea fácil entender REST, pero no es la forma más óptima de implementarlo, ya que podría estar perfectamente integrado en un sistema MVC y con más comprobaciones de seguridad para que no nos pasen más o menos parámetros que los que necesitamos etc… Además toda la parte de modelo, se está haciendo con un array asociativo, y lo suyo es que fuese una aplicación con bases de datos.

index.php <?php class RestUtils { public static function processRequest() { // cogemos el metodo $request_method = strtolower($_SERVER['REQUEST_METHOD']); $return_obj = new RestRequest(); // aqui almacenaremos los datos $data = array(); switch ($request_method) { // para get y post esto sera sencillo case 'get': $data = $_GET; break; case 'post': $data = $_POST; break; // Aqui esta lo "complicado" case 'put': //para put y delete usamos una cadena desde una localizacion de input especial de PHP y la parseamos con parse_str. parse_str(file_get_contents('php://input'), $put_vars); $data = $put_vars; break; case 'delete': $data=''; //delete no acepta parametros

Page 279: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

265

break; } // almacenamos el metodo $return_obj->setMethod($request_method); // Almacenamos los parametros pasados en crudo, por si necesitamos acceder a ellos $return_obj->setRequestVars($data); if(isset($data['data'])) { // asumimos que los datos estan pasados en forjato JSON $return_obj->setData(json_decode($data['data'])); } else if($request_method == "get"){ $return_obj->setData($data); } return $return_obj; } public static function sendResponse($status = 200, $body = '', $content_type = 'text/html') { $status_header = 'HTTP/1.1 ' . $status . ' ' . RestUtils::getStatusCodeMessage($status); // establecemos status header($status_header); // el tipo de contenido header('Content-type: ' . $content_type); // mostramos exclusivamente el cuerpo si está creado if($body != '') { echo $body; exit; } // en caso de que el cuerpo del mensaje sea vacio, necesitaremos construirlo else { // creamos la variable $message = ''; // Esta parte es opcional pero quedara mas presentable a los usuarios switch($status) { case 401: $message = 'Debes estar autorizado para ver esta pagina.'; break; case 404: $message = 'La URL solicitada ' . $_SERVER['REQUEST_URI'] . ' no existe.'; break; case 500: $message = 'Se ha encontrado un error al procesar la peticion.'; break; case 501: $message = 'El metodo solicitado no esta implementado.'; break; } // A veces la firma del servidor no esta activa (es la directiva apache

Page 280: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

266

"ServerSignature On") $signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE']; // Lo suyo es que esta parte este en una plantilla $body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <title>' . $status . ' ' . RestUtils::getStatusCodeMessage($status) . '</title> </head> <body> <h1>' . RestUtils::getStatusCodeMessage($status) . '</h1> <p>' . $message . '</p> <hr /> <address>' . $signature . '</address> </body> </html>'; echo $body; exit; } } public static function getStatusCodeMessage($status) { // Esto podria estar en un fichero de texto y parseado mas tarde pero por ahora nos vale $codes = Array( 100 => 'Continue', 101 => 'Switching Protocols', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type',

Page 281: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

267

416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported' ); return (isset($codes[$status])) ? $codes[$status] : ''; } } class RestRequest { private $request_vars; private $data; private $http_accept; private $method; public function __construct() { $this->request_vars = array(); $this->data = ''; $this->http_accept = (strpos($_SERVER['HTTP_ACCEPT'], 'json')) ? 'json' : 'xml'; $this->method = 'get'; } public function setData($data) { $this->data = $data; } public function setMethod($method) { $this->method = $method; } public function setRequestVars($request_vars) { $this->request_vars = $request_vars; } public function getData() { return $this->data; } public function getMethod() { return $this->method; } public function getHttpAccept() { return $this->http_accept; } public function getRequestVars() { return $this->request_vars; } }

Page 282: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

268

function send($data, $send_data){ //dependiendo de si nuestro cliente quiere json o xml se lo enviaremos de una forma u otra. if($data->getHttpAccept() == 'json') { RestUtils::sendResponse(200, json_encode($send_data), 'application/json'); } else if ($data->getHttpAccept() == 'xml') { // Usamos el serializador de xml de PEAR $options = array ( 'indent' => ' ', 'addDecl' => false, 'rootName' => $fc->getAction(), XML_SERIALIZER_OPTION_RETURN_RESULT => true ); $serializer = new XML_Serializer($options); RestUtils::sendResponse(200, $serializer->serialize($send_data), 'application/xml'); } } $data = RestUtils::processRequest(); require 'users.inc.php'; switch($data->getMethod()) { // this is a request for all users, not one in particular case 'get': $user_data = processGet($data); send($data, $user_data); break; // creamos un usuario case 'post': $user_data = processPost($data); send($data, $user_data); break; case 'put': $user_data = processPut($data); send($data, $user_data); break; case 'delete': $user_data = processDelete($data); send($data, $user_data); break; } function processGet($data){ $exploded = explode ("/", $_SERVER['REQUEST_URI']); //en nuestro caso si el 3 elemento es numerico, es que estamos pasando el identificativo $mydata = $data->getData(); if(strpos($_SERVER['REQUEST_URI'], 'user') && is_numeric($exploded[3])) return getUser($exploded[3]); if(strpos($_SERVER['REQUEST_URI'], 'user') && isset($mydata["name"])) //busqueda de usuario return getUserSearch($mydata["name"]); if(strpos($_SERVER['REQUEST_URI'], 'user'))//listado de usuarios return getUserList(); } function processPost($data){

Page 283: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

269

return addUser($data->getData()->username, $data->getData()->password); } function processPut($data){ $exploded = explode ("/", $_SERVER['REQUEST_URI']); return modifyUser($exploded[3], $data->getData()->username, $data->getData()->password); } function processDelete($data){ $exploded = explode ("/", $_SERVER['REQUEST_URI']); return deleteUser($exploded[3]); }

Las funciones de acceso a datos, fichero users.inc.php: <?php $users = array('1' => array("user" => "juan", "password" => "nauj" ), '2' => array("user" => "pepe", "password" => "epep" ), '3' => array("user" => "antonio", "password" => "tonitoni" )); function getUserList(){ global $users; return $users; } function getUser($userid){ global $users; return $users[$userid]; } function getUserSearch($cond){ global $users; for ($i=1; $i<=count($users); $i++){ if ($users[$i]["user"] == $cond) return $users[$i]; } return null; } function addUser($name, $password){ global $users; $users[count($users)+1]["name"] = $name; $users[count($users)]["password"] = $password; //aqui solo usamos count a secas ya que se ha creado al asignar el name return $users; } function modifyUser($id, $name, $password){ global $users; $users[$id]["user"] = $name; $users[$id]["password"] = $password; return $users; } function deleteUser($userid){ global $users; unset($users[$userid]); return $users; }

Ahora veamos el código de nuestro cliente genérico de REST. Para desarrollarlo hemos usado la libreria cURL http://php.net/manual/en/book.curl.php

Page 284: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

270

Fichero RestRequest.inc.php <?php class RestRequest { protected $url; protected $verb; protected $requestBody; protected $requestLength; protected $acceptType; protected $responseBody; protected $responseInfo; public function __construct ($url = null, $verb = 'GET', $requestBody = null) { $this->url = $url; $this->verb = $verb; $this->requestBody = $requestBody; $this->requestLength = 0; $this->acceptType = 'application/json'; $this->responseBody = null; $this->responseInfo = null; if ($this->requestBody !== null) { $this->buildPostBody(); } } public function flush () { $this->requestBody = null; $this->requestLength = 0; $this->verb = 'GET'; $this->responseBody = null; $this->responseInfo = null; } public function execute () { $ch = curl_init(); try { switch (strtoupper($this->verb)) { case 'GET': $this->executeGet($ch); break; case 'POST': $this->executePost($ch); break; case 'PUT': $this->executePut($ch); break; case 'DELETE': $this->executeDelete($ch); break; default: throw new InvalidArgumentException('Current verb (' . $this->verb . ') is an invalid REST verb.'); } } catch (InvalidArgumentException $e)

Page 285: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

271

{ curl_close($ch); throw $e; } catch (Exception $e) { curl_close($ch); throw $e; } } public function buildPostBody ($data = null) { $data = ($data !== null) ? $data : $this->requestBody; if (!is_array($data)) { throw new InvalidArgumentException('Invalid data input for postBody. Array expected'); } $data = http_build_query($data, '', '&'); $this->requestBody = $data; } protected function executeGet ($ch) { $this->doExecute($ch); } protected function executePost ($ch) { if (!is_string($this->requestBody)) { $this->buildPostBody(); } curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody); curl_setopt($ch, CURLOPT_POST, 1); $this->doExecute($ch); } protected function executePut ($ch) { if (!is_string($this->requestBody)) { $this->buildPostBody(); } $this->requestLength = strlen($this->requestBody); $fh = fopen('php://memory', 'rw'); fwrite($fh, $this->requestBody); rewind($fh); curl_setopt($ch, CURLOPT_INFILE, $fh); curl_setopt($ch, CURLOPT_INFILESIZE, $this->requestLength); curl_setopt($ch, CURLOPT_PUT, true); $this->doExecute($ch); fclose($fh); }

Page 286: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

272

protected function executeDelete ($ch) { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); $this->doExecute($ch); } protected function doExecute (&$curlHandle) { $this->setCurlOpts($curlHandle); $this->responseBody = curl_exec($curlHandle); $this->responseInfo = curl_getinfo($curlHandle); curl_close($curlHandle); } protected function setCurlOpts (&$curlHandle) { curl_setopt($curlHandle, CURLOPT_TIMEOUT, 10); curl_setopt($curlHandle, CURLOPT_URL, $this->url); curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true); curl_setopt($curlHandle, CURLOPT_HTTPHEADER, array ('Accept: ' . $this->acceptType)); } public function getAcceptType () { return $this->acceptType; } public function setAcceptType ($acceptType) { $this->acceptType = $acceptType; } public function getResponseBody () { return $this->responseBody; } public function getResponseInfo () { return $this->responseInfo; } public function getUrl () { return $this->url; } public function setUrl ($url) { $this->url = $url; } public function getVerb () { return $this->verb; } public function setVerb ($verb) { $this->verb = $verb;

Page 287: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

273

} }

Y antes de empezar con las funcionalidades, vamos a dejar claro como vamos a acceder a nuestro api.

listado con todos los usuarios metodo GET a la url http://localhost/rest/user/

añadir un usuario. metodo POST a la url http://localhost/rest/user/

modificar un usuario. metodo PUT a la url http://localhost/rest/user/id_del_usuario por ejemplo para el usuario con id = 1 sería: http://localhost/rest/user/1

ver un usuario. metodo GET a la url http://localhost/rest/user/id_del_usuario igual que con modificar.

borrar un usuario. metodo DELETE a la url http://localhost/rest/user/id_del_usuario igual que con modificar

busqueda de usuario. metodo GET a la url http://localhost/rest/user/ pero pasándole más parametros en la URL

En estos ejemplos, usaremos la clase cliente, y mostraremos el resultado en json. Evidentemente en una aplicación final, los datos deberán ser tratados para mostrar un html con sus estilos CSS.

25.4.1. Listado

Gracias a nuestra clase genérica vamos a tener una forma muy sencilla de hacer todas estas funcionalidades. Despues de ejecutar la consulta REST, dispondremos de 2 métodos. getResponseInfo() y getResponseBody(). getResponseBody() tiene todo el contenido de nuestro servicio, mientras que getResponseInfo() nos da información adicional no relevante para el usuario final, pero que a nosotros, los programadores nos puede ser muy util como tamaño de las cabeceras, tiempo total que ha llevado la consulta etc… Y ahora sí, empecemos por el listado: <?php require 'RestRequest.inc.php'; $MyRequest = new RestRequest('http://localhost/rest/user/', "GET"); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Como decíamos getResponseBody() tiene nuestro cuerpo. Por lo que este método debería mostrarnos Response body: {"1":{"user":"juan","password":"nauj"},"2":{"user":"pepe","password":"epep"},"3":{"user":"antonio","password":"tonitoni"}}

25.4.2. Mostrado

<?php

Page 288: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

274

require 'RestRequest.inc.php'; $MyRequest = new RestRequest('http://localhost/rest/user/3', "GET"); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Resultado: {"user":"antonio","password":"tonitoni"}

25.4.3. Inserción

<?php require 'RestRequest.inc.php'; $request["data"]='{"username": "miguel", "password": "miki"}'; $MyRequest = new RestRequest('http://localhost/rest/user/', "POST", $request); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Resultado: {"1":{"user":"juan","password":"nauj"},"2":{"user":"pepe","password":"epep"},"3":{"user":"antonio","password":"tonitoni"},"4":{"name":"miguel","password":"miki"}}

25.4.4. Modificación

<?php require 'RestRequest.inc.php'; $request["data"]='{"username": "miguel", "password": "miki"}'; $MyRequest = new RestRequest('http://localhost/rest/user/2/', "PUT", $request); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Resultado: {"1":{"user":"juan","password":"nauj"},"2":{"user":"miguel","password":"miki"},"3":{"user":"antonio","password":"tonitoni"}}

25.4.5. Borrado

<?php require 'RestRequest.inc.php';

Page 289: Php-Mysql

CONSTRUCCION DE SERVICIOS WEB EN PHP

275

$MyRequest = new RestRequest('http://localhost/rest/user/2/', "DELETE"); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Resultado: {"1":{"user":"juan","password":"nauj"},"3":{"user":"antonio","password":"tonitoni"}}

25.4.6. Búsqueda

<?php require 'RestRequest.inc.php'; $MyRequest = new RestRequest('http://localhost/rest/user/?name=pepe', "GET"); $MyRequest->execute(); print "Response info: <br />"; print_r ($MyRequest->getResponseInfo()); print "<br />Response body: <br />"; print ($MyRequest->getResponseBody());

Resultado: {"user":"pepe","password":"epep"}

25.5. Actividades

25.5.1. Actividad 1

Implementa el ejemplo CRUDL REST con un paradigma MVC. Tanto cliente como servidor. Puedes usar este ejemplo como base.

25.5.2. Actividad 2

De los servicios web en REST que has encontrado en el primer ejercicio del punto anterior, elige uno, y haz que el cliente rest php conecte contra el.

Es posible que necesites algún tipo de autenticación, ya que REST permite hacer una autenticacíon. cURL tambien ofrece la posibilidad de añadir autenticación.

Si lo necesitas, solo tienes que añadir lo siguiente al cliente rest del ejemplo anterior:

En la declaración de variables protected $username; protected $password;

En el constructor

Page 290: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

276

$this->username = null; $this->password = null;

En la función execute public function execute () { $ch = curl_init(); $this->setAuth($ch); /// <<<<<<---- ESTA LINEA

Y añadir estas funciones: protected function setAuth (&$curlHandle) { if ($this->username !== null && $this->password !== null) { curl_setopt($curlHandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); curl_setopt($curlHandle, CURLOPT_USERPWD, $this->username . ':' . $this->password); } } public function getPassword () { return $this->password; } public function setPassword ($password) { $this->password = $password; } public function getUsername () { return $this->username; } public function setUsername ($username) { $this->username = $username; }

Page 291: Php-Mysql

CONSULTAS DE SERVICIOS WEB EN JAVASCRIPT:JQUERY

277

Consulta de servicios web en JavaScript: Jquery

Antes de ver como hacer unas consultas con JQuery, veamos como hacerlas “a mano” directamente con el objeto XMLHttpRequest.

26.1. Manejo de consultas: uso del objeto XMLHTTPRequest

Antes de seguir con el objeto XMLHTTPRequest, debemos tener una cosa en cuenta. No todos los navegadores web tienen implementado los métodos PUT y DELETE, aunque los navegadores web más modernos empiezan a hacerlo. En el caso de que nuestro navegador no lo soporte, podríamos implementar PUT y DELETE a través de POST mandando algún parámetro extra, y haciendo el control extra en nuestro script PHP.

En primer lugar crearemos nuestro objeto ActiveX en IExplorer y un objeto nativo en el resto de navegadores que lo soportan, y es por ello que tendremos que ver qué objeto creamos, controlándolo con diferentes condiciones, con esto conseguimos que el navegador cree una instancia del objeto apropiado, dependiendo del navegador usado por el usuario. function nuevoAjax(){ var xmlhttp=false; try {

Page 292: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

278

xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP”); } catch (e) { try { xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”); } catch (E) { xmlhttp = false; } } if (!xmlhttp && typeof XMLHttpRequest!=’undefined’) { xmlhttp = new XMLHttpRequest(); } return xmlhttp; }

Ahora repasemos los métodos y propiedades del objeto XMLHttpRequest que hemos visto al principio del módulo.

Métodos

abort() – Detiene la petición en curso.

getAllResponseHeaders() – Devuelve todas las cabeceras de la respuesta (etiquetas y valores) como una cadena.

getResponseHeader(etiqueta) – Devuelve el valor de la etiqueta en las cabecerasde la respuesta.

open(método,URL,asíncrona,nombre,password) – Abre una conexión con esa URL mediante ese metodo (GET o POST)

send(contenido) – Envía el contenido al servidor.

setRequestHeader(etiqueta,valor) – Establece el valor de una etiqueta de las cabeceras de petición.

De está lista nos detendremos en el método open que es uno de los más utilizados y el que nos permitirá utilizar la mejor característica de Ajax que es la carga de datos externos a la página sin necesidad de recargar la misma.

26.1.1. Método Open

El método open prepara una conexión HTTP a través del objeto XMLHttpRequest con un método y una URL especificados. XMLHttpRequest.open ( string Metodo, string URL [, boolean Sincronia [, string Usuario [, string Contraseña ] ] ] );

Metodo es la cadena que nos indicara el tipo de conexión (GET o POST) URL es la url a la que realizamos la petición Sincronia es un campo booleano con el que podemos utilizar modo asíncrono o síncrono, si lo fijamos en “false” modo síncrono perderiamos las mejores características de AJAX, los datos Usuario y Pwd son opcionales por si queremos dotar de una autenticación.

Al llamar a open el atributo readyState a 1, resetea los headers de envío y devuelve los atributos responseText, responseXML, status y statusText a sus valores iniciales

Propiedades

onreadystatechange – Contiene el nombre de la función que se ejecuta cada vez que el estado de la conexión cambie.

Page 293: Php-Mysql

CONSULTAS DE SERVICIOS WEB EN JAVASCRIPT:JQUERY

279

readyState – Estado de la conexión, puede valer desde 0 (no iniciada) hasta 4 (completado).

responseText – Datos devueltos por el servidor en formato cadena.

responseXML – Datos devueltos por el servidor en forma de documento XML que puede ser recorrido mediante las funciones del DOM (getEementsByTagName, etc).

status – Código enviado por el servidor, del tipo 404 (documento no encotrado) o (OK), 401 (No autorizado), 405 (Metodo no implementado)

statusText – Mensaje de texto enviado por el servidor junto al código (status), para el caso de código 200 contendrá “OK”.

Y ahora pasemos a coger información con GET function cargarContenido(){ var module, userid, contenedor; contenedor = document.getElementById(‘contenedor’); module = document.getElementById(‘module�).value; userid = document.getElementById(‘userid�).value; ajax=nuevoAjax(); ajax.open(“GET”, module+"/"+userid,true); ajax.onreadystatechange=function() { if (ajax.readyState==4) { contenedor.innerHTML = ajax.responseText } } ajax.send(null) }

26.1.1.1. Ejemplo de envío de datos “POST”

Unicamente debemos cambiar algunas cosas en nuestra función: Adicción de una línea adicional: setRequestHeader que especifica qué tipo de datos llegarán al servidor. Cambio del parametro que especifica el método a “POST” y por último utilizaremos parametros para el “send”. function cargarContenido(){ var t1, t2, contenedor; contenedor = document.getElementById(‘contenedor’); t1 = document.getElementById(‘texto1�).value; t2 = document.getElementById(‘texto2�).value; ajax=nuevoAjax(); ajax.open(“POST”, “ejemploajax2.php”,true); ajax.onreadystatechange=function() { if (ajax.readyState==4) { contenedor.innerHTML = ajax.responseText } } ajax.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”); ajax.send(“t1=”+t1+”&t2=”+t2) }

Al mandar por post la información, podemos mandarla con el formato variable=valor&variable2=valor2, o incluso podemos mandar contenido en formato json y por supuesto, en el caso del GET, usar la función eval() para leer el contenido.

Para los metodos PUT y DELETE, el código seria prácticamente el mismo que en POST y en GET respectivamente. Poniendo parametros en el send() en el caso de PUT, y poniendo null en el send() en el caso del DELETE.

Page 294: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

280

26.2. Importación y exportación de datos

Veamos como recibir y mandar datos con JQuery.

Uso de la función load. $(document).ready(function(){ $("#enlaceajax").click(function(evento){ evento.preventDefault(); $("#destino").load("recibe-parametros.php", {nombre: "Pepe", edad: 45}, function(){ alert("recibidos los datos por ajax"); }); }); })

esta función tiene el formato: .load(string URL, parametros, callback)

Donde en:

URL ponemos una string con la dirección de nuestro servidor REST.

parametros, si ponemos null o una cadena de texto, la petición se mandará vía GET, y si mandamos en notación de objeto, como en el ejemplo, se mandara por POST

aquí definimos una función que se ejecutará a modo de callback.

Ojo, si el contenido de nuestro servicio REST nos devuelve html en sí, podremos usar load para GET sin ningún tipo de problema, ya que esa función introduce dentro del contenido de nuestro elemento HTML (un div por ejemplo) los datos del servidor, como si usaramos innerHTML().

Si nuestro servicio REST nos va a mandar otro tipo de contenido (un json por ejemplo), debermos usar la funcion $().get(). También tenemos la posibilidad de usar $().post() en vez de .load()

Por ejemplo //Con get podemos usar esta notacion, $.get("servidor.php", { name: "John", time: "2pm" }, function(data){ alert("Data Loaded: " + data); }); //o esta otra, si no queremos mandar parametros $.get("servidor.php", function(data){ alert("Data Loaded: " + data); });

load() solo implementa GET y POST por la razón que comentábamos antes, de que PUT y DELETE no están implementados en varios navegadores, pero podemos extender JQuery y crearnos nuestras propias funciones para el caso de PUT y DELETE. function _ajax_request(url, data, callback, type, method) { if (jQuery.isFunction(data)) { callback = data; data = {}; } return jQuery.ajax({ type: method,

Page 295: Php-Mysql

CONSULTAS DE SERVICIOS WEB EN JAVASCRIPT:JQUERY

281

url: url, data: data, success: callback, dataType: type }); } jQuery.extend({ put: function(url, data, callback, type) { return _ajax_request(url, data, callback, type, 'PUT'); }, delete_: function(url, data, callback, type) { return _ajax_request(url, data, callback, type, 'DELETE'); } });

Y de esta forma lo tendríamos listo para usar JQuery.put() o JQuery.delete()

26.3. Manejo de los datos y su uso en el DOM

Como hemos comentado, a la hora de recibir datos, podriamos recibirlos de varias formas. Un html ya formado, u otro contenido por ejemplo json.

Con JQuery, si recibimos en un GET, unos datos ya formados en html, con utilizar la función load nos valdría, ya que con usarlo sobre el identificativo, todo se hace de forma automática. $(document).ready(function(){ $("#enlaceajax").click(function(evento){ evento.preventDefault(); $("#destino").load("recibe-parametros.php", {nombre: "Pepe", edad: 45}, function(){ alert("recibidos los datos por ajax"); }); }); })

En este caso el contenido de nuestro elemento HTML con identificativo ”#destino” se verá modificado automáticamente.

Por el contrario si recibiésemos un JSON mediante la función $.get(), la forma de convertirlo en un objeto javascript, es la siguiente: var myObject = eval('(' + myJSONtext + ')');

Por ejemplo: var myObject = null; $.get("servidor.php", function(data){ myObject = eval('(' + data + ')'); });

Nota: Para mandar datos en formato json, con mandar un objeto javascript es suficiente.

A partir de que tengamos nuestros datos JSON, para modificar el DOM solo tendremos que usar las funciones típicas de JQuery para crear nuevos elementos con el contenido que nosotros queramos.

26.4. Actividad

Page 296: Php-Mysql

EXPERTO EN DESARROLLO DE SOLUCIONES CORPORATIVAS EN SOFTWARE LIBRE

282

Implementa con javascript la posibilidad de ejecutar desde el navegador las funciones ofrecidas por nuestro servidor de REST. Si quieres usar la funcion load directamente recuerda que todo tiene que ir ya creado en html. Añade Smarty a nuestro paradigma MVC si no lo habías hecho y busca la función en su API que nos devuelve una template ya “compilada”