Desarrollo Web con PHPOscar Capuñay Uceda Contenido DEDICATORIA AGRADECIMIENTOS INTRODUCCIÓN I. PREPARANDO LA PLATAFORMA DE DESARROLLO 7 7 9 11 11 11 16 16 19 19 22 23 25 28 31 38 45 61 62 62 63 64 64 65 68 70 71 75 77 78 79 82 83 88 90 91 95 97 INSTALACIÓN DEL SERVIDOR WEB Y PHP INSTALACIÓN EN WINDOWS II. DHTML HTML FORMATO DE TEXTO CON HTML LISTAS COMENTARIOS NO VISIBLES EN LA PANTALLA CARACTERES ESPECIALES ENLACES O HIPERVÍNCULOS IMÁGENES TABLAS FORMULARIOS HTML 4 JAVASCRIPT ELEMENTOS BÁSICOS COMENTARIOS LITERALES TIPOS DE DATOS VARIABLES OPERADORES ESTRUCTURAS DE CONTROL OBJETOS OBJETOS PREDEFINIDOS EVENTOS DEFINICIÓN MEDIANTE CÓDIGO MODELO DE OBJETOS DEL DOCUMENTO OBJETO WINDOW OBJETO DOCUMENT OBJETO FORM OTROS OBJETOS FICHEROS .JS HOJAS DE ESTILO EN CASCADA SINTAXIS Y TIPOS BÁSICOS DE DATOS EN CSS2 PALABRAS CLAVE III. INICIANDO LA PROGRAMACIÓN CON PHP QUE ES PHP? VARIABLES CONSTANTES TIPOS DE DATOS EXPRESIONES OPERADORES OPERADORES DE ARITMÉTICA OPERADORES DE ASIGNACIÓN OPERADORES DE COMPARACIÓN OPERADORES DE CONTROL DE ERRORES OPERADORES DE EJECUCIÓN OPERADORES DE INCREMENTO/DECREMENTO OPERADORES DE LÓGICA OPERADORES DE CADENA OPERADORES DE MATRICES OPERADORES DE TIPO IV. ESTRUCTURAS DE CONTROL SI (CONDICIONAL): IF ELSE ELSEIF FOR WHILE DO..WHILE 99 99 99 99 100 100 102 103 103 104 105 106 106 108 108 109 110 113 113 114 114 115 115 115 117 124 129 132 132 137 143 151 158 165 170 177 187 187 187 188 V. ACCESO A DATOS CON PHP FORMULARIOS HTML Y PHP SUBIENDO ARCHIVOS AL SERVIDOR ACCESO A BASES DE DATOS CREANDO UNA BASE DE DATOS MYSQL EN MYSQL ADMINISTRATOR CREANDO UNA BASE DE DATOS MYSQL EN PHPMYADMIN ACCESO A MYSQL DESDE PHP INSTALACIÓN DE POSTGRESQL SOBRE WINDOWS XP CREANDO UNA BASE DE DATOS POSTGRESQL EN PGADMIN III CREANDO UNA BASE DE DATOS POSTGRESQL EN PHPPGADMIN ACCESO A POSTGRESQL DESDE PHP ACCESO A MS SQL-SERVER DESDE PHP VI. PHP ORIENTADO A OBJETOS CLASES EN PHP INSTANCIA DE UN OBJETO EXTENDIENDO OBJETOS AUTO CARGA DE OBJETOS ACCESO A MYSQL CON PHP ORIENTADO A OBJETOS MYSQLI MYSQLI_STMT MYSQLI_RESULT PAGINANDO RESULTADOS ARQUITECTURA MVC MVC CON PHP MVC Y PHP CON ACCESO A BASE DE DATOS PDO – PHP DATA OBJECT CLASES PREDEFINIDAS CONEXIONES CON PDO EJECUCIÓN DE SENTENCIAS PREPARADAS CON PDO 189 191 191 193 194 202 205 205 212 215 215 218 221 225 225 227 229 242 246 248 253 257 257 264 264 274 281 281 282 291 293 298 299 301 301 306 308 313 314 VII. SEGURIDAD WEB SEGURIDAD EN EL SISTEMA DE ARCHIVOS SEGURIDAD EN BASE DE DATOS INYECCIÓN SQL SESIONES AUTENTIFICACIÓN HTTP CON PHP LOGIN CAPTCHA VIII. GENERACIÓN DE ARCHIVOS CON PHP IMÁGENES ARCHIVOS PDF FPDF ARCHIVOS XLS IX. PHP + AJAX AJAX XAJAX EVENTOS CON XAJAX TRABAJO CON FORMULARIOS EN XAJAX ERROR COMÚN BÚSQUEDA EN BASE DE DATOS CON XAJAX ADMINISTRACIÓN DE DATOS CON AJAX CONTROLADOR CON AJAX CAPA DE DATOS CON AJAX VISTA CON AJAX X. REFERENCIAS BIBLIOGRAFICAS XI. ANEXOS LISTA DE EJEMPLOS LISTA DE TABLAS LISTA DE FIGURAS 314 318 319 Dedicatoria Este libro lo dedico a Dios, a mi esposa Kelly, y a mi hijo Oscar Armando. Agradecimientos Este libro es gracias a la bendición de Dios, al apoyo y aliento de mis padres, a la colaboración de mis hermanos Carlos, Jaime y Benjamín y al amor de mi esposa Kelly. Introducción Introducción PHP desde el año 1997 ha crecido aceleradamente, su versión 4 lanzada en el 2000 ganó mucha popularidad y logró estar instalado en mas de la cuarta parte de los servidores Web a nivel mundial, esto la convirtió en el 2003 en la plataforma Web con mayor presencia en Internet en comparación con sus similares. En la actualidad muchas empresas han optado por el desarrollo de sus aplicaciones con PHP, esto ha generado una creciente demanda de profesionales con habilidades y conocimiento de este lenguaje, es por este motivo que decidí escribir este libro, y aportar algunos conocimientos basados en la experiencia obtenida en los últimos seis años desarrollando aplicaciones Web. Oscar E Capuñay Uceda 9 Preparando la plataforma de desarrollo I. Preparando la plataforma de desarrollo Instalación del servidor Web y PHP Instalación en Windows Para trabajar con PHP vamos a utilizar WAMP un software que instala el servidor Web APACHE, PHP y el manejador de base de datos MySQL. Veamos a continuación los pasos de la instalación: Figura 1. Inicio de la instalación de WAMP Oscar E Capuñay Uceda 11 Preparando la plataforma de desarrollo Figura 2. Licencia de uso de WAMP Si estamos de acuerdo con los términos de la licencia, seleccionamos “I accept the agreement” y presionamos el botón “Next” para continuar. Figura 3. Destino de la instalación de WAMP Luego seleccionamos la ubicación de los paquetes que vamos a instalar. Oscar E Capuñay Uceda 12 Preparando la plataforma de desarrollo Figura 4. Seleccionar menú de inicio de WAMP Luego indicamos el nombre del acceso directo que nos permitirá cargar WAMP desde el menú de inicio. Figura 5. Inicio de WAMP en el arranque del Sistema Operativo. Después elegimos si queremos que WAMP se inicie automáticamente cuando se inicie una sesión en el sistema operativo. Oscar E Capuñay Uceda 13 Preparando la plataforma de desarrollo Figura 6. Resumen de la configuración de la instalación Ahora nos muestra el resumen de la configuración elegida antes del inicio de la instalación. Sólo nos queda presionar el botón “Install” para instalar los programas. Figura 7. Instalando WAMP Oscar E Capuñay Uceda 14 Preparando la plataforma de desarrollo Figura 8. Instalación de WAMP completa Finalmente la instalación termina y nos muestra la pantalla anterior en la que podemos elegir si se carga WAMP en ese momento o posteriormente. Hay que cerciorarnos que cuando WAMP se inicie los servicios deben estar iniciados correctamente, haciendo clic en el icono que aparece en la barra de tareas: . Luego de hacer clic aparecerá un menú: Figura 9. Menú de WAMP Oscar E Capuñay Uceda 15 DHTML II. DHTML Para desarrollar aplicaciones Web con PHP es necesario tener conocimientos de HTML Dinámico – DHTML, debido a que en los documentos Web no sólo se escribe un lenguaje sino que es necesario utilizar diferentes lenguajes para la implementación de las diversas rutinas que se pueden requerir para un buen funcionamiento de la aplicación. Debido a esto a continuación veremos un repaso rápido de los temas relacionados con DHTML. HTML HTML es un lenguaje que permite definir los elementos que conforman una página Web. Los diseñadores y programadores de páginas Web utilizan el lenguaje HTML de modo que los navegadores que utilizamos los usuarios muestran las páginas Web después de interpretar su contenido HTML. El W3C define el lenguaje HTML como “un lenguaje reconocido universalmente y que permite publicar información de forma global”. Desde su primera definición, el lenguaje HTML ha sido un lenguaje utilizado exclusivamente para crear documentos electrónicos pero es un lenguaje que se utiliza en la mayoría de aplicaciones electrónicas (aplicaciones Web comerciales, educativas, financieras y también muy utilizada en buscadores, etc.). El lenguaje HTML, cuenta con un conjunto de etiquetas o también llamadas "Tags", las cuales funcionan de la siguiente manera: <tag> Modelo de Inicio de una etiqueta. </tag> modelo de Cierre de una etiqueta. El texto o cualquier elemento de la página Web, que esté entre ambas etiquetas (de inicio y cierre), estará influenciado por la acción que éstas realicen. Por ejemplo, todo el documento HTML debe estar entre las etiquetas <HTML> y </HTML>. <HTML> [Documento Web] </HTML> Hay que considerar que no todos los tags tienen etiqueta de cierre. Aunque se recomienda que las etiquetas o tags que no tienen incluyan un “/” antes del cierre. Por ejemplo la etiqueta BR se recomienda escribirla así: <br />. Es indiferente escribir las etiquetas en mayúsculas o minúsculas. Pero se recomienda escribirlas en minúsculas. Para diferenciarlas del texto común, las escribiremos en mayúsculas. Oscar E Capuñay Uceda 16 DHTML Toda página Web, esta dividida en dos partes bien definidas: la primera es la “cabecera” o “encabezado” y la segunda es el “cuerpo“ o “contenido” del documento. La cabecera se define con la etiqueta <HEAD> y su finalización es con </HEAD>. En la cabecera se coloca la información sobre la página Web, pero hay que tener en cuenta que esta información no se muestra en el navegador, excepto el título de la página que se muestra en la barra de título de la ventana del navegador, el cual se encuentra entre las etiquetas <TITLE> y </TITLE>. El cuerpo, está comprendido entre las etiquetas <BODY> y </BODY>. Dentro de éste está todo lo que queremos que aparezca en la pantalla principal (texto, imágenes, etc.) Por lo mencionado anteriormente, podemos concluir que la estructura de un documento Web (página Web) tiene dos partes: el encabezado y el cuerpo, y que de acuerdo a las etiquetas utilizadas para delimitar estas partes, las etiquetas HTML para construir una página Web deben estar en el siguiente orden: <HTML> <HEAD> <TITLE> Título de la página </TITLE> </HEAD> <BODY> [En este lugar escribiremos el contenido de la página] </BODY> </HTML> Antes de crear nuestra primera página Web, debemos tener ciertas consideraciones sobre el texto que vamos a incluir en el documento: No hay necesidad de tratar de justificar el texto al ancho del navegador, pues el texto de una página Web se caracteriza por justificarse de acuerdo al ancho que tome la ventana, además cuando queramos pasar a un nuevo párrafo, es necesario utilizar la etiqueta <P>. El contenido de la página puede tener varios títulos, los cuales escribiremos entre las etiquetas <H1> y </H1>, <H2> y </H2>, etc. (hasta H6), el número en la etiqueta de título indica el tamaño de los caracteres de la frase o palabra. El tamaño mayor es el correspondiente al número 1. Una etiqueta muy interesante es la de centrado <CENTER> y </CENTER> (debemos tomar en cuenta que a esta etiqueta no la soportan todos los navegadores, aunque sí la mayoría de ellos). Esta etiqueta centra todo lo que esté dentro de ella, ya sea texto, imágenes, etc. Existen otros tags como por ejemplo, los separadores horizontales (horizontal rules), que se insertan con la etiqueta <HR> (este tag no tiene la correspondiente etiqueta de cierre). Con ella se obtiene una raya horizontal Oscar E Capuñay Uceda 17 DHTML tan ancha como la pantalla, y con la apariencia de estar embutida sobre el fondo, o podemos también especificar su ancho en píxeles o en porcentaje respecto al ancho de la ventana. Ejemplo 1: Ejercicio01.html Primera página Web <HTML> <HEAD> <TITLE> Mi Primer Ejercicio </TITLE> </HEAD> <BODY> <H1> <CENTER> Ejercicio 1 </CENTER> </H1> <HR> Esta es mi primera página Web programando con HTML, aun es muy sencillo el diseño pero pronto haremos páginas más complejas. <P> Este es el segundo párrafo. </BODY> </HTML> Resultado Web Figura 10. Resultado de ejercicio01.html Cuando programemos, tratemos de colocar algunas líneas en blanco cuando sea necesario, mayormente para separar la cabecera del cuerpo de la página, y además justificar a la izquierda las líneas en varios niveles, para identificar con mucha mayor claridad el código que se encuentra dentro de ciertas etiquetas, como lo podemos notar en el ejemplo anterior. De hecho, todo el código podría estar escrito dentro de una sola línea. Lo importante es el orden correcto de las etiquetas. Por cierto, una etiqueta puede estar anidada dentro de otra. En el ejemplo podemos notar la etiqueta <CENTER> dentro de la etiqueta <H1>. Es muy importante, en estos casos, que las etiquetas de inicio y de cierre vayan en el orden correcto, pues de lo contrario se producirían errores. Oscar E Capuñay Uceda 18 DHTML Formato de Texto con HTML En ejemplo anterior, podemos notar que cuando colocamos texto, este aparece sin ningún formato en especial. Sólo, cuando quisimos crear un nuevo párrafo, utilizamos la etiqueta <P>, esta etiqueta inserta una línea en blanco después de la última del párrafo anterior. Pero si deseamos realizar un salto de línea, es decir pasar a la siguiente línea sin incluir una en blanco, utilizaremos el tag <BR>. Esta etiqueta por su funcionamiento no tiene una etiqueta de cierre. Negrita y Cursiva Cuando trabajamos con texto formateado, las características más utilizadas son: negrita y cursiva. Pues en HTML, podemos darle esas características al texto utilizando las etiquetas: <B> para poner el texto en negrita, y <I> para formato cursiva. Cada una de ellas si cuenta con su respectiva etiqueta de cierre (</B> y </I>). Espacios en blanco Al escribir el texto, si ponemos más de un espacio en blanco entre dos palabras observamos que el navegador sólo reconoce uno de ellos. Si queremos forzarle a que lo haga, debemos poner el código " " (nonbreaking space). Superíndices y Subíndices En las fórmulas matemáticas puede interesar poder escribir índices y subíndices, que se consiguen con las etiquetas <SUP> </SUP> y <SUB> </SUB> respectivamente. Por ejemplo: m2 se obtiene con: m<SUP>2</SUP> y vx con: v<SUB>x</SUB>. Listas Cuando tenemos un conjunto de elementos es necesario mostrarlos en forma de listas, las cuales pueden ser de diferentes tipos: 1. Listas sin orden (sin numerar) 2. Listas ordenadas (numeradas) 3. Listas de definición. Una lista sin orden (Unordered List) sirve para presentar cosas que, por no tener un orden determinado, no necesitan ir precedidas por un número. Su estructura es la siguiente: <UL> <LI> Naranja <LI> Manzana <LI> Fresa <LI> Etc. </UL> Como se puede apreciar, para crear una lista de este tipo se utiliza la etiqueta <UL>, y luego para cada elemento la etiqueta <LI> (List Item). Oscar E Capuñay Uceda 19 DHTML Resultado Web Figura 11. Lista sin orden Además podemos anidar una lista dentro de otra. Por ejemplo: <UL> <LI> Mamíferos <LI> Peces <UL> <LI> Sardina <LI> Bacalao </UL> <LI> Aves </UL> Resultado Web Figura 12. Listas sin orden anidadas Las Listas Ordenadas (Ordered Lists) sirven para presentar ítems en un orden determinado. Su estructura es muy similar a la anterior. La diferencia está en que en el resultado aparecerá automáticamente un número correlativo para cada elemento de la lista. <OL> <LI> Introduccion <LI> Conceptos Basicos <LI> Aplicaciones Oscar E Capuñay Uceda 20 DHTML <LI> Bibliografia </OL> El texto aparecerá de la siguiente forma: Figura 13. Lista ordenada Al igual que las listas sin orden, también se pueden anidar las listas ordenadas. El tercer tipo lo forman las listas de definición. Como su nombre indica, son apropiadas para glosarios (o definiciones de términos). Toda la lista debe ir englobada entre las etiquetas <DL> y </DL>. Y a diferencia de las dos que hemos visto, cada renglón de la lista tiene dos partes: 1) el nombre de la cosa a definir, que se consigue con la etiqueta <DT> (definition term) y 2) la definición de dicha cosa, que se consigue con la etiqueta <DD> (definition definition). <DL> <DT> HTML <DD> Son las iniciales de HyperText Markup Language <DT> WWW <DD> Son las iniciales de World Wide Web </DL> Su resultado es: Figura 14. Lista de definiciones Oscar E Capuñay Uceda 21 DHTML Comentarios no visibles en la pantalla A veces es muy útil escribir comentarios en el documento HTML sobre todo cuando creamos páginas dinámicas, el código que escribimos, nos pueden servir para recordar posteriormente sobre lo que hicimos, y que no queremos que se vean en pantalla. Esto se consigue encerrando dichos comentarios entre estos dos símbolos: <!-- y --> . Por ejemplo: <!-- Esto es un comentario que puedo incluir en cualquier parte --> Ejemplo 2: Ejercicio02.html Comentarios <HTML> <HEAD> <TITLE> Ejercicio 2 </TITLE> </HEAD> <BODY> <CENTER> <H1> Mis Cursos </H1> </CENTER> <HR> Sin un orden particular, mis <B> cursos </B> son los siguientes: <UL> <LI> Redes de computadoras <LI> Ingenieria de Software <UL> <LI> Herramientas Case <LI> Software de Aplicación I <LI> Software de Aplicación II </UL> <LI> Sistemas de Información Gerencial </UL> Los cursos que me gustan son <I> (en orden de preferencia): </I> <OL> <LI> Ingenieria de Software <LI> Sistemas de Información Gerencial <LI> Redes de Computadoras </OL> </BODY> </HTML> Oscar E Capuñay Uceda 22 DHTML Resultado Web: Figura 15. Resultado de ejercicio02.html Caracteres especiales Hemos podido notar en los ejemplos anteriores, que las palabras no aparecen con tildes, y no hemos utilizado algunos otros caracteres especiales, esto debido a que existen algunas limitaciones para escribir el texto. Una de ellas es debido a que las etiquetas se forman como un comando escrito entre los símbolos "<" y ">". Por tanto, si se quisieran escribir estos caracteres como parte normal del texto, provocaría una ambigüedad, ya que el navegador podría interpretarlos como el comienzo o final de una etiqueta, en vez de un carácter más del texto. Para superar estas limitaciones, existen códigos para escribir estos caracteres y otros relacionados junto con las etiquetas. Tabla 1. Códigos HTML para caracteres especiales < > & " obtenemos obtenemos obtenemos obtenemos < (less than, menor que) > (greater than, mayor que) & (ampersand) " (double quotation) Podemos ver, que estos códigos empiezan siempre con el signo “&“ y acaban siempre con “;”. De igual manera, existen códigos para escribir letras específicas de distintos idiomas. Los códigos de las vocales acentuadas se Oscar E Capuñay Uceda 23 DHTML forman comenzando con &, seguido de la vocal en cuestión, seguido de la palabra acute (aguda) y terminando con el signo: “;” (punto y coma). Tabla 2. Códigos HTML para caracteres especiales Á - á É - é Í - í Ó - ó Ú - ú Ñ - ñ ¿ - ¿ Á - Á É - É Í - Í Ó - Ó Ú - Ú Ñ - Ñ ¡ - ¡ Todo esto, que como se ve es muy laborioso, puede parecer inútil ya que si escribimos nuestro texto sin hacer ningún caso de estas convenciones, escribiendo las letras acentuadas y demás signos directamente, es muy posible que el resultado lo veamos correctamente en nuestro navegador, pero nunca podremos estar seguros que les ocurra lo mismo a todos los que accedan a nuestras páginas con otros navegadores distintos. Para corregir el ejercicio anterior con vocales acentuadas utilizaremos el siguiente ejemplo. Ejemplo 3: Ejercicio03.html Uso de tildes <HTML> <HEAD> <TITLE> Ejercicio 3 </TITLE> </HEAD> <BODY> <CENTER> <H1> Mis Cursos </H1> </CENTER> <HR> Sin un orden particular, mis <B> cursos </B> son los siguientes: <UL> <LI> Redes de computadoras <LI> Ingeniería de Software <UL> <LI> Herramientas Case <LI> Software de Aplicación I <LI> Software de Aplicación II </UL> <LI> Sistemas de Información Gerencial </UL> Los cursos que me gustan son <I> (en orden de preferencia): </I> <OL> <LI> Ingeniería de Software Oscar E Capuñay Uceda 24 DHTML <LI> Sistemas de Información Gerencial <LI> Redes de Computadoras </OL> </BODY> </HTML> Resultado Web: Figura 16. Resultado de ejercicio03.html Enlaces o hipervínculos El éxito de la Web, se basa justamente en este elemento: el “Hipervínculo” o enlace, pues nos da la posibilidad de unir los distintos documentos repartidos por todo el mundo. Estructura de los enlaces Los enlaces, en general, tienen la siguiente estructura: <A REF = "xxx" > yyy </A> xxx : es el destino del hipervínculo. yyy : es el texto que generalmente aparece subrayado y con un color especial, el cual indicará en la pantalla la existencia de un enlace. Oscar E Capuñay Uceda 25 DHTML Tipos de enlaces Los enlaces los podemos clasificar en cuatro tipos: Enlaces dentro de la misma página Enlaces con otra página nuestra Enlaces con una página fuera de nuestro sistema Enlaces con una dirección de correo electrónico • Enlaces dentro de la misma página Cuando tenemos documentos (o páginas Web) muy extensos, es adecuado trabajar con este tipo de enlaces, pues nos permite dar un salto desde una posición a otra determinada, dentro de la misma página. En este caso, lo que antes hemos llamado XXX, es decir, el destino del enlace, en este caso el sitio dentro de la página a donde queremos saltar, se sustituye por #marcador (la palabra marcador puede ser cualquier palabra). Lo que hemos llamado antes YYY es la palabra (o palabras) que aparecerán en la pantalla en color (en forma de hipertexto). Su estructura es, entonces: <A HREF="#marcador"> YYY </A>. En el sitio exacto a donde queremos saltar, debemos poner la siguiente etiqueta: <A NAME="marcador"> </A> Por ejemplo, si quiero saltar desde aquí a la pantalla final, pongo la siguiente etiqueta:<A HREF="#final"> Haga Click aquí para ir al final</A>. En el final del documento se inserta esta etiqueta: <A NAME="final"> </A>. • Enlaces con otra página nuestra Generalmente cuando vamos a crear un Sitio Web, contamos con varias páginas, las cuales necesitamos enlazar unas con otras. Contamos siempre con una página que será la Inicial o principal y otras enlazadas a ella. Supongamos que queremos enlazar con la página creada en el ejemplo del capítulo anterior, que la hemos llamado ejemplo2.html. En este caso, simplemente sustituimos lo que hemos llamado XXX (el destino del enlace) por el nombre del archivo: <A HREF="ejemplo2.html"> Ejemplo 2 </A> Si queremos que vaya a un sitio concreto de otra página nuestra en vez de ir al principio de la página, adonde va por defecto, en ese sitio tenemos que colocar una marca o marcador (ver sección anterior), y completar el enlace con la referencia a ese marcador. En este ejemplo podremos hacer un enlace de este tipo: Deseo poner un enlace desde aquí a otra página (supongamos que se llame pag5.html), pero a un sitio concreto de esa página, donde he puesto el marcador <A NAME="cursos"></A>. Entonces la etiqueta tiene que ser: <A HREF="pag5.html#cursos"> Cursos </A>. Oscar E Capuñay Uceda 26 DHTML Si la página a la que quiero saltar está, por ejemplo en el subdirectorio cursos, entonces en la etiqueta tendría que haber puesto "cursos/pag5.html". Según el párrafo anterior, la etiqueta tiene que ser: <A HREF="cursos/pag5.html#cursos"> Cursos </A>. Y a la inversa, si quiero saltar desde una página a otra que está en un directorio anterior o nivel superior, en la etiqueta tendría que haber puesto "../pag5.html". Esos dos puntos (..) hace que se dirija al directorio anterior. Obsérvese que se debe utilizar el símbolo / para indicar los subdirectorios, y no este otro \, que es propio únicamente de Windows. Podemos evitar todas estas complicaciones colocando todos los archivos en un solo directorio, pero si tenemos muchas páginas lo mejor es tenerlas en directorios, pues nos facilitará el mantenimiento de ellas. • Enlaces con una página fuera de nuestro sistema Si queremos enlazar con una página que esté fuera de nuestro Sitio Web (es decir, que esté en un servidor distinto), es necesario conocer su dirección completa, o URL (Uniform Resource Locator). El URL podría ser, además de la dirección de una página del Web, una dirección de ftp, gopher, etc. Una vez conocida la dirección (o URL), la colocamos en vez de lo que hemos llamado anteriormente xxx (el destino del enlace). Si queremos enlazar con la página de la Nasa (cuyo URL es: http://www.nasa.com), la etiqueta sería: <A HREF="http://www.nasa.com/">Página inicial de la Nasa </A> Es importante escribir estas direcciones correctamente (respetando las mayúsculas y minúsculas, pues los servidores UNIX sí las distinguen) • Enlaces con una dirección de Correo Electrónico En este caso, sustituimos lo que se ha llamado antes xxx (el destino del enlace) por mailto: seguido de la dirección de correo electrónico. La estructura de la etiqueta es: <A HREF="mailto: usuario@servidoremail">Texto del enlace</A> Ejemplo 4: Enlaces <HTML><HEAD><TITLE> Ejercicio 4 </TITLE></HEAD> <BODY> <CENTER><H1> Mis páginas favoritas </H1></CENTER> <HR> Estas son mis páginas favoritas: <P><A HREF="http://www.desarrolloweb.com">Desarrollo Web</A> <BR><A HREF="http://www.forosdelweb.com">Foros del Web</A> <BR> <A HREF="http://www.google.com">Google</A> </BODY> </HTML> Oscar E Capuñay Uceda 27 DHTML Resultado Web: Figura 17. Resultado de ejercicio04.html Imágenes La etiqueta que nos sirve para incluir imágenes en las páginas Web es muy similar a la de enlaces a otras páginas. A esta etiqueta se le indica el nombre y la localización de un archivo que contiene una imagen. La estructura de la etiqueta es: <IMG SRC="imagen.gif"> Con el comando IMG SRC (Image Source, origen o fuente de la imagen) se indica que se quiere mostrar una imagen llamada imagen.gif (el nombre que tenga el archivo). Dentro de la etiqueta se pueden añadir otros comandos, tal como ALT <IMG SRC="imagen.gif" ALT="descripción"> Con ALT se inserta una descripción (una palabra o una frase breve) de la imagen. ALT se puede omitir, es en beneficio de los que accedan a nuestra página con un programa navegador en forma de texto sólo. Ya que no son capaces de ver la imagen, por lo menos pueden hacerse una idea sobre ella. Si el archivo se encuentra en el mismo directorio, es suficiente escribir el nombre. Pero si se encontrara en otro lugar es necesario indicar su ubicación exacta, utilizando los criterios que vimos en la parte de enlaces. Un aspecto muy importante a tener en cuenta es el tamaño de las imágenes, pues una imagen grande supone un archivo grande, y esto puede resultar en un tiempo excesivo de carga, con el consiguiente riesgo de que quien esté intentando cargar nuestra página se canse de esperar, y desista de ello. Oscar E Capuñay Uceda 28 DHTML Para elegir la posición de la imagen con respecto al texto hay distintas posibilidades. La más sencilla es colocarla entre dos párrafos, con un titular a un lado. De momento nos vamos a limitar a escoger la posición del titular con respecto a la imagen (si es que queremos ponerle un titular, claro está). Se puede poner arriba, en medio o abajo del lado de la imagen. Para ello se añade el comando ALIGN a la etiqueta, de la siguiente manera: <IMG SRC="isla.gif" ALIGN=TOP> Titular alineado arriba <IMG SRC="isla.gif" ALIGN=MIDDLE> Titular alineado en medio <IMG SRC="isla.gif" ALIGN=BOTTOM> Titular alineado abajo Otra posibilidad muy interesante es la de utilizar una imagen como enlace a otra página. Para estos casos se utilizan generalmente imágenes pequeñas (iconos), aunque se puede usar cualquier tipo de imagen. Según vimos anteriormente, la estructura general de un enlace es: <A HREF="xxx"> yyy </A>. Donde xxx era el destino del enlace e yyy el texto del enlace (o más generalmente hablando, lo que aparece en la pantalla como el enlace; anteriormente era un texto, y en éste va a ser una imagen). En este caso sustituimos xxx por el nombre del archivo de la página a la que queremos acceder. Y en lugar de yyy ponemos la etiqueta completa de la imagen (que queda así englobada dentro de la etiqueta del enlace). Como ejemplo vamos a utilizar la imagen (flecha.gif) para acceder al ejercicio 2 (ejercicio2.html): <A HREF="ejercicio2.html"><IMG SRC="flecha.gif"></A> Pulsando la imagen comprobamos cómo efectivamente enlaza con la página deseada. Obsérvese además que la imagen está rodeada de un rectágulo del color normal en los enlaces. Si no se desea que aparezca ese rectángulo, hay que incluir dentro de la etiqueta de la imagen el atributo BORDER=0, es decir: <A HREF="ejercicio2.html"> <IMG SRC="flecha.gif" BORDER=0> </A> Posicionando el cursor sobre esta última imagen, comprobamos que actúa también como enlace aunque carezca del rectángulo de color. Esto puede resultar más estético, pero se corre el riesgo de que el usuario no se dé cuenta de que la imagen sirve de enlace. Ejemplo 5: Imágenes <HTML> <HEAD> Oscar E Capuñay Uceda 29 DHTML <TITLE> Ejercicio 5 </TITLE> </HEAD> <BODY> <CENTER><H1>Ejercicio 5</H1></CENTER> <HR> Esta es una página Web. Tiene todos los elementos básicos sobre todo imágenes. <P><A HREF ="ejercicio1.html"> <IMG SRC ="iconos/nuevo.gif" width="20" height="22" border="0"> </A> Mi primera pagina Web. <P><A HREF ="ejercicio2.html"> <IMG SRC ="iconos/buscar.gif" width="15" height="15" border="0"> </A> Mis Cursos <CENTER> <H3> Desarrollo Web con PHP </H3> <IMG SRC="imagenes/teclado.jpg" ALT="playa" height="145"> </CENTER> </BODY> </HTML> Resultado Web: Figura 18. Resultado de ejercicio05.html Oscar E Capuñay Uceda 30 DHTML Tablas Las etiquetas necesarias para crear tablas son: <TABLE> Y </TABLE> para especificar el inicio y final de la tabla. A esta etiqueta le podemos añadir un comando: BORDER, que sirve para especificar el grosor del borde de las celdas. La manera de especificar esta característica es la siguiente: <TABLE BORDER=[espesor]> [resto de las etiquetas] </TABLE> Por ejemplo: si queremos una tabla con un borde de una unidad de espesor, escribiremos el siguiente código: <TABLE BORDER=1> [resto de las etiquetas] </TABLE> Dentro de estas etiquetas, es necesario especificar las filas y columnas que contendrá la tabla. Las etiquetas para formar cada fila (row) de la tabla, que son: <TR> y </TR>. Estas etiquetas tenemos que repetirlas tantas veces como filas queremos que tenga la tabla. Las etiquetas para crear columnas son: <TD> y </TD>, que engloban el contenido de cada celda concreta (texto, imágenes, etc.). Hay que repetirla tantas veces como celdas queremos que haya en esa fila. Ejemplo 6: Tablas Ejercicio06.html <HTML> <HEAD><TITLE> Ejercicio 6 </TITLE></HEAD> <BODY BGCOLOR="#CCFFFF" TEXT="#AA0000"> <CENTER> <H1> Ejercicio 6 </H1> </CENTER> <!-- Línea horizontal con 75% de ancho de la ventana --> <HR width=75%> <A HREF="ejercicio01.html"> <IMG SRC="iconos/nuevo.gif" WIDTH=20 HEIGHT=22 border="0"> </A> <TABLE BORDER=1> <TR><TD>fila1-celda1</TD> <TD>fila1-celda2</TD> <TD>fila1-celda3</TD></TR> <TR><TD>fila2-celda1</TD> <TD>fila2-celda2</TD> <TD>fila2-celda3</TD></TR> </TABLE> </BODY> </HTML> Oscar E Capuñay Uceda 31 DHTML Resultado Web: Figura 19. Tabla HTML ¿Que pasaría si creamos filas con diferente numero de columnas?, el navegador creará un espacio vacío en dicha posición. Si en la tabla del ejercicio 6 eliminamos la tercera celda de la segunda fila, es decir si borramos <TD>fila2-celda3</TD>, resultará: Figura 20. Tabla sin una celda Titular de la tabla Se puede añadir un titular a la tabla, es decir un texto situado en la parte superior de la tabla que indica cuál es su contenido. Éste titular se consigue con las etiquetas: <CAPTION> y </CAPTION> para su inicio y finalización, respectivamente. Tomando en cuenta el ejercicio anterior, vemos como podemos utilizar esta etiqueta: <table BORDER="1"> <caption>Ejemplo de filas desiguales </caption> <tr> Oscar E Capuñay Uceda 32 DHTML <td>fila1-celda1</td> <td>fila1-celda2</td> <td>fila1-celda3</td> </tr> <tr> <td>fila2-celda1</td> <td>fila2-celda2</td> </tr> </table> Resultado Web: Figura 21. Tabla con etiqueta CAPTION Además de las celdas que contienen datos normales, podemos poner, si nos conviene, celdas de cabecera, que se distinguen por estar el texto de dichas celdas en negrita y centrado. Estas celdas se insertan escribiendo la etiqueta: <TH> y </TH>. Vamos a añadir, en el ejemplo anterior, una fila de estas celdas de cabecera, antes de las otras dos que ya existían: <TABLE BORDER="1"> <CAPTION>Ejemplo de filas desiguales </CAPTION> <TR> <TH>Columna 1</TH> <TH>Columna 2</TH> <TH>Columna 3</TH> </TR> <TR> <TD>fila1-celda1</TD> <TD>fila1-celda2</TD> <TD>fila1-celda3</TD> </TR> <TR> <TD>fila2-celda1</TD> <TD>fila2-celda2</TD> </TR> </TABLE> Oscar E Capuñay Uceda 33 DHTML Resultado Web Figura 22. Tabla con etiqueta TH Ubicación contenido dentro de la celda El contenido de una celda por defecto está alineado a la izquierda. Pero se puede cambiar añadiendo dentro de la etiqueta de la celda los siguientes atributos: <TD ALIGN=CENTER> Al centro </TD> <TD ALIGN=RIGHT> A la derecha </TD> <TH ALIGN=LEFT> Cabecera a la izquierda </TH> En el caso de la etiqueta <TH>, por defecto el texto esta en el centro de la celda. Por defecto, las celdas tienen alineación vertical es en el medio. Esto también se puede cambiar, añadiendo dentro de la etiqueta de la celda los siguientes atributos: <TD VALIGN=TOP> Arriba </TD> <TD VALIGN=CENTER> Centro </TD> <TD VALIGN=BOTTOM> Abajo </TD> Cambiando las dimensiones de la tabla El navegador normalmente dimensiona el tamaño de la tabla de acuerdo con el número de filas, de columnas, por el contenido de las celdas, espesor de los bordes, etc. Pero nosotros por medio de atributos también podemos modificar las dimensiones de una tabla. Estos atributos son: WIDTH y HEIGHT (ancho y alto), los cuales pueden estar expresados en pixeles o en porcentaje de la dimensión de la pantalla. Celdas que abarcan a otras varias A veces puede interesarnos que una celda se extienda sobre otras varias. Esto se consigue añadiéndo dentro de la etiqueta de la celda los atributos COLSPAN=número para extenderse sobre un número determinado de Oscar E Capuñay Uceda 34 DHTML columnas, o ROWSPAN=número para extenderse verticalmente sobre un número determinado de filas. Por ejemplo, en la tabla anterior vamos a añadir una fila con una sola celda, que abarca a tres columnas: <TABLE BORDER="1"> <CAPTION>Ejemplo de filas desiguales </CAPTION> <TR> <TH>Columna 1</TH> <TH>Columna 2</TH> <TH>Columna 3</TH> </TR> <TR> <TD COLSPAN=3> Celda sobre 3 columnas </TD> <TR> <TR> <TD>fila1-celda1</TD> <TD>fila1-celda2</TD> <TD>fila1-celda3</TD> </TR> <TR> <TD>fila2-celda1</TD> <TD>fila2-celda2</TD> </TR> </TABLE> Resultado Web Figura 23. Tabla con COLSPAN O, en la misma tabla, vamos a añadir una celda en la primera fila. pero que abarque también a la siguiente: <TABLE BORDER="1"> <CAPTION>Ejemplo de filas desiguales </CAPTION> <TR> Oscar E Capuñay Uceda 35 DHTML <TH>Columna 1</TH> <TH>Columna 2</TH> <TH>Columna 3</TH> </TR> <TR> <TD COLSPAN=3> Celda sobre 3 columnas </TD> <TR> <TR> <TD>fila1-celda1</TD> <TD>fila1-celda2</TD> <TD ROWSPAN=2> Celda junto a 2 filas </TD> </TR> <TR> <TD>fila2-celda1</TD> <TD>fila2-celda2</TD> </TR> </TABLE> Resultado Web Figura 24. Tabla con ROWSPAN Separación entre las celdas de una tabla Por defecto, la separación entre celdas de una tabla es de dos pixels. Pero se puede variar esto con el atributo CELLSPACING, que se pone dentro de la etiqueta <TABLE>. Por ejemplo, para obtener una separación de 20 pixels entre celdas ponemos: <TABLE BORDER CELLSPACING=20> Separación entre el borde y el contenido dentro de las celdas La separación entre el borde y el contenido dentro de las celdas es de un pixel. Si queremos cambiar esto, lo hacemos con el atributo CELLPADDING, que se pone dentro de la etiqueta <TABLE>. Por ejemplo, para obtener una separación de 20 pixels entre el contenido y los bordes, dentro de cada celda: <TABLE BORDER CELLPADDING=20> Oscar E Capuñay Uceda 36 DHTML Se puede combinar este atributo con CELLSPACING, visto líneas atrás. Por ejemplo, una tabla con bordes de 5 de espesor, separación entre celdas de 15 y separación del contenido con respecto a los bordes de las celdas de 20, lo obtendríamos con: <TABLE BORDER=5 CELLSPACING=15 CELLPADDING=20> Resultado Web Figura 25. Tabla con CELLSPACING y CELLPADDING Ejemplo 7: ejemplo06.html Ejemplo de Tablas en HTML <HTML> <HEAD> <TITLE> Tablas </TITLE> </HEAD> <BODY> <CENTER> <H1> Tablas </H1> </CENTER> <HR width=75%> Oscar E Capuñay Uceda 37 DHTML <TABLE BORDER=3 CELLSPACING=10 CELLPADDING=8> <TR> <TD>fila1-celda1</TD> <TD>fila1-celda2</TD> <TD>fila1-celda3</TD> </TR> <TR> <TD>fila2-celda1</TD> <TD>fila2-celda2</TD> <TD>fila2-celda3</TD> </TR> </TABLE> </BODY> </HTML> Resultado Web Figura 26. Resultado de ejemplo06.html Formularios Los formularios permiten a los usuarios enviar información al servidor, en el cual hay instalado(s) programa(s) que procesan esta información. Estructura de un formulario La estructura de un formulario es la siguiente: • • • • Etiqueta de inicio: Cuerpo del formulario, con los distintos elementos para poder introducir los datos. Botones de envío y de borrado. Etiqueta de cierre </FORM> Oscar E Capuñay Uceda 38 DHTML Etiqueta de inicio <FORM ACTION=mailto:email METHOD="POST" ENCTYPE = "TEXT/PLAIN"> El atributo ACTION indica la acción que se debe efectuar. El atributo METHOD=POST indica que los datos sean inmediatamente enviados a la dirección de email u a otro destino establecido según el atributo ACTION. Con el atributo ENCTYPE="TEXT/PLAIN" se consigue que las respuestas las recibamos como un archivo de texto, perfectamente legible y sin codificar. Elementos para introducir los datos Existen tres tipos de elementos: 1. Introducción por medio de texto 2. Introducción por medio de menús 3. Introducción por medio de botones La introducción de los datos se consigue por medio de la etiqueta: <INPUT TYPE="xxx" NAME="yyy" VALUE="zzz"> En donde: xxx es la palabra que indica el tipo de introducción. yyy es el nombre que le asignamos nosotros a la variable de introducción del dato. zzz es el nombre de la variable que contendrá el valor del elemento. Introducción por medio de texto (una línea) En este caso es xxx=text, es decir, INPUT TYPE="text". El atributo VALUE no procede en este caso. Vamos a poner un ejemplo: solicitamos el apellido del usuario. <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> Escribe tu apellido: <BR><INPUT TYPE="text" NAME="Apellido"> </FORM> Si el usuario introduce su apellido, por ejemplo: Ruiz, y pulsa el botón de envío (que veremos más adelante), recibiremos un email suyo con el siguiente texto: Apellido=Ruiz La longitud de esta caja de texto es por defecto de 20 caracteres. Se puede variar incluyendo en la etiqueta el atributo SIZE="número". Por otra parte, sea cual sea la longitud, si no se indica nada, el usuario puede introducir el número de caracteres que quiera. Se puede limitar esto, incluyendo en la etiqueta el atributo MAXLENGTH="número". Oscar E Capuñay Uceda 39 DHTML En el caso que hemos visto, si hubiéramos cambiado la etiqueta correspondiente por: <INPUT TYPE="text" NAME="Apellido" SIZE="10" MAXLENGTH="12"> También se puede hacer que el texto introducido no sea reconocible, es decir que todos los caracteres se representen por asteriscos. Basta con cambiar en la etiqueta INPUT TYPE="text" por INPUT TYPE="password". En el último ejemplo, si cambiamos la etiquea correspondiente por: <INPUT TYPE="password" NAME="Apellido" SIZE="10" MAXLENGTH="12"> Los caracteres introducidos se representan por asteriscos. Introducción por medio de texto (múltiples líneas) Cuando el texto a introducir puede alcanzar una gran longitud, por ejemplo un comentario, es conveniente utilizar un formulario de texto de múltiples líneas. Esto se consigue con la etiqueta de inicio: <TEXTAREA NAME="yyy" ROWS="número" COLS="número"> (en donde no se utiliza INPUT TYPE y donde ROWS representa el número de filas, y COLS el de columnas). y la de cierre: </TEXTAREA> Ejemplo 8: Formulario solicitando los comentarios del usuario: <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> Introduce tus comentarios: <BR> <TEXTAREA NAME="Comentarios" ROWS="6" COLS="40"> </TEXTAREA> </FORM> Resultado Web: Figura 27. Resultado de ejemplo08.html Oscar E Capuñay Uceda 40 DHTML Introducción por medio de Listas Desplegables Si queremos que el usuario, en vez de introducir un texto, como hemos visto en los casos anteriores, escoja entre varias opciones que le presentamos nosotros, haremos uso de un formulario en forma de listas desplegables. Se consigue con la etiqueta de inicio <SELECT NAME="yyy"> y la de cierre </SELECT>. Las distintas opciones a escoger se consiguen con la etiqueta <OPTION>. Ejemplo: Pedimos al usuario que elija su color preferido: <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> ¿Cuál es tu color preferido? <BR> <SELECT NAME="ColorPreferido"> <OPTION>Rojo </OPTION> <OPTION>Verde </OPTION> <OPTION>Azul </OPTION> </SELECT > </FORM> Si el usuario escoge, por ejemplo: Azul y ha pulsado el botón de envío, recibiremos un email suyo con el texto: ColorPreferido=Azul. En el ejemplo anterior, sólo es visible en el formulario una opción. Si queremos que sean visibles múltiples opciones a la vez, añadimos en la etiqueta los atributos MÚLTIPLE SIZE="número", donde especificamos el número de opciones visibles. Formulario de confirmación (checkbox) Si queremos que el usuario confirme una opción determinada, podemos hacer uso de un formulario de confirmación, o checkbox, que se consigue con la etiqueta: <INPUT TYPE="checkbox" NAME="yyy"> Ejemplo 9: Confirmación de la inclusión en una lista de correo: <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> <INPUT TYPE="checkbox" NAME="Lista"> Sí, deseo ser incluido en la lista de correo. </FORM> Si el usuario marca este formulario y pulsa el botón de envío, recibiremos un email suyo con el texto: Lista=On. Si queremos que el formulario aparezca inicialmente como marcado (el usuario no necesitará hacerlo), basta con añadir el atributo CHECKED dentro de la etiqueta. Ejemplo: <INPUT TYPE="checkbox" NAME="Lista" CHECKED> Oscar E Capuñay Uceda 41 DHTML Botones de radio Cuando queremos que el usuario elija una única opción entre varias, podemos hacer uso de los botones de radio, que se consiguen con la etiqueta: <INPUT TYPE="radio" NAME="yyy" VALUE="zzz"> Donde yyy es el nombre que le ponemos a la variable que se trata de elegir, y zzz es el nombre de cada una de las opciones en concreto. Ejemplo: solicitamos al usuario que defina cuál es su sistema operativo preferido: <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> ¿Cuál es tu sistema operativo preferido? <BR> <INPUT TYPE="radio" NAME="SistemaOperativo" VALUE="PC" CHECKED> PC <INPUT TYPE="radio" NAME="SistemaOperativo" VALUE="Mac"> Mac <INPUT TYPE="radio" NAME="SistemaOperativo" VALUE="Unix"> Unix </FORM> Obsérvese el atributo opcional CHECKED que se ha añadido en la primera etiqueta. Esa será la opción que aparece marcada por defecto. Si el usuario ha escogido la opción PC y pulsa el botón de envío, recibiremos un email suyo con el texto: SistemaOperativo=PC. Botones de envío y de borrado Hasta ahora, en todos los ejemplos que hemos visto, faltaba un elemento esencial en cualquier formulario, y es el botón de envío de los datos, que se consigue con la etiqueta: <INPUT TYPE="submit" VALUE="Enviar"> En donde zzz es el texto que queremos que aparezca en el botón. Ejemplo: <FORM ACTION=mailto:email METHOD="POST" ENCTYPE="TEXT/PLAIN"> Escribe tu apellido: <BR><INPUT TYPE="text" NAME="Apellido"> <P><INPUT TYPE="submit" VALUE="Enviar datos"> </FORM> Otro botón interesante es el de borrado de los datos introducidos, muy conveniente en un formulario con muchos elementos. Es muy similar al de envío, pues se consigue con la etiqueta: <INPUT TYPE="reset" VALUE="zzz"> En donde zzz es el texto que queremos que aparezca en el botón. Si añadimos al ejemplo anterior la etiqueta: Oscar E Capuñay Uceda 42 DHTML <P><INPUT TYPE="reset" VALUE="Borrar datos"> Se puede comprobar su funcionamiento, escribiendo algo en el formulario y pulsando luego el botón de borrado. Consideraciones finales Hasta ahora hemos visto uno a uno los diferentes elementos que se pueden utilizar. Pero no hay ningún inconveniente en usar, dentro del mismo formulario, distintos tipos de introducción de datos. Al pulsar el usuario el botón de envío recibiríamos en email suyo con las distintas parejas NAME=VALUE de cada elemento, encadenadas con el símbolo &. Ejemplo 10: Ejercicio10.html Formulario 2 <HTML> <HEAD><TITLE>LIBRO DE VISITAS</TITLE></HEAD> <BODY> <P><CENTER> <H2>Libro de visitas</H2> <P> <FORM ACTION=mailto:xy@ab METHOD="POST" ENCTYPE="TEXT/PLAIN"> Tu nombre: <BR><INPUT TYPE="text" NAME="Nombre"> <P>Escribe tus comentarios: <BR><TEXTAREA NAME="Comentarios" ROWS="6" COLS="40"> </TEXTAREA> <P><INPUT TYPE="submit" VALUE="Enviar datos"> <INPUT TYPE="reset" VALUE="Borrar datos"> </FORM> <P><HR><P> </BODY> </HTML> Resultado Web: Oscar E Capuñay Uceda 43 DHTML Resultado de ejercicio10.html Oscar E Capuñay Uceda 44 DHTML HTML 4 La especificación 4.0 de HTML, nos trae algunas novedades respecto a la versión 3.2, las cuales serán comentadas a continuación: Elementos nuevos Los nuevos elementos en HTML 4.0 son: ABBR, ACRONYM, BDO, BUTTON, COL, COLGROUP, DEL, FIELDSET, FRAME, FRAMESET, IFRAME, INS, LABEL, LEGEND, NOFRAMES, NOSCRIPT, OBJECT, OPTGROUP, PARAM, SPAN, TBODY, TFOOT, THEAD y Q. Cambios en los atributos • Casi todos los atributos que especifican el formato (tamaño, color, alineación, etc) de un documento HTML han sido desaprobados en favor de las hojas de estilo en cascada. • La lista de atributos del apéndice indica qué atributos han sido desaprobados. • Los atributos id y class permiten a los autores asignar información de nombre y clase a los elementos para las hojas de estilo, como identificadores de vínculo, para los scripts, para declaraciones de objetos, para tratamientos genéricos del documento, etc. Veamos a continuación detalles de algunas nuevas etiquetas: Frames Frames (en inglés, marcos o cuadros) es un procedimiento del lenguaje HTML para dividir la pantalla en diferentes zonas, o ventanas, que pueden actuar independientemente unas de otras, como si se trataran de páginas diferentes, pues incluso cada una de ellas pueden tener sus propias barras de desplazamiento. Los navegadores que lo implementan son el Netscape 2.0, y el Explorer 2.0 en adelante. Una de sus características más importantes es que pulsando un enlace situado en un frame, se puede cargar en otro frame una página determinada. Esto se utiliza frecuentemente para tener un frame estrecho en la parte lateral (o superior) con un índice del contenido en forma de diferentes enlaces, que, al ser pulsados cargan en la ventana principal las distintas páginas. De esta manera se facilita la navegación entre las páginas, pues aunque se vaya pasando de unas a otras, siempre estará a la vista el índice del conjunto. Para comprender los distintos conceptos vamos a desarrollar un ejemplo, creando una página con dos frames. El de la izquierda va a servir de índice de lo que veamos en el de la derecha, y en éste veremos inicialmente una página de presentación. Se podrá acceder también aquí a las páginas creadas anteriormente, si se pulsa un enlace en el frame de la izquierda. Documento de definición de los frames Lo primero que tenemos que hacer es crear un documento HTML en el que definiremos cuántas zonas va a haber, qué distribución y tamaño van a tener, y cuál va ser el contenido de cada una de ellas. Oscar E Capuñay Uceda 45 DHTML En el ejemplo que vamos a desarrollar, la página va a tener dos frames distribuidos en columnas (es decir, uno al lado del otro, en vez de uno encima del otro, lo que sería una distribución en filas). Con respecto al tamaño, haremos que el primero (el de la izquierda) ocupe el 20% del ancho de la pantalla, y el otro, el 80% restante. Y con respecto al contenido, el frame de la izquierda va a contener un documento HTML que va a servir de índice de lo que veamos en el otro (y que vamos a llamar pagind.html), y el de la derecha otro documento HTML que va a servir de página de presentación (al que llamaremos pagpre.html). Todo lo anterior se refleja en el siguiente documento HTML: Ejemplo 11: Ejercicio11.html Uso de frames <HTML> <HEAD> <TITLE>Mi página con frames</TITLE> </HEAD> <FRAMESET COLS="20%, 80%"> <FRAME SRC="ejercicio11a.html"> <FRAME SRC="ejercicio11b.html" NAME="principal"> </FRAMESET> <NOFRAMES> Estas utilizando un navegador que no soporta frames. <A HREF="ejercicio12.html"> ir a página sin frames </A>. </NOFRAMES> </HTML> Ejercicio11a.html <html> <head> <title>marco 1</title> </head> <body> marco 1 </body> </html> Ejercicio11b.html <html> <head> <title>marco 2</title> </head> <body> marco 2 </body> </html> Oscar E Capuñay Uceda 46 DHTML Resultado Web Figura 28. Marcos o Frames Es un documento parecido a los que conocíamos hasta ahora. La diferencia está en que en vez de utilizar la etiqueta BODY, que sirve normalmente para delimitar lo que se va a ver en la pantalla, se hace uso de la etiqueta FRAMESET (definir los frames). En este caso, con la etiqueta <FRAMESET COLS="20%, 80%"> se define que va a haber dos frames y que van a ir en columnas. Si hubiéramos querido que fueran en filas, habríamos puesto ROWS (filas, en inglés). También se define el ancho que van a ocupar cada uno de ellos en la pantalla. Se ha puesto como porcentajes del total, pero se podría también haber puesto una cifra absoluta, que representaría el número de píxeles a ocupar. Ya se ha definido el número de frames, su distribución y su tamaño, pero falta por definir el contenido de cada frame. Esto se hace con las etiquetas: <FRAME SRC="ejercicio11a.html"> <FRAME SRC="ejercicio11b.html" NAME="principal"> Con esto se define que el contenido del primer frame (el de la izquierda) sea el documento HTML ejercicio11a.html y el del segundo (el de la derecha) sea el documento HTML ejercicio11b.html. Podemos ver en la etiqueta del segundo marco que se ha incluido el atributo NAME="principal", pero no así en el primero, debido a que se necesita dar un nombre al segundo frame, pues, podríamos utilizar hipervínculos en el primer marco que muestren páginas Web en el segundo, utilizando la etiqueta TARGET, por ejemplo: <a href=”ejercicio12.html” TARGET=”principal”>ejercicio 12</a>. Según este ejemplo la página ejercicio12.html se abrirá en el frame del lado derecho de la página. Para el caso que el navegador no soporte FRAMES se utiliza la etiqueta <NOFRAMES> y </NOFRAMES>. Se añaden al final del documento de definición de los frames, y a se pone entre ambas lo que queremos que vean los que acceden con un navegador que no soporta frames. Puede incluso Oscar E Capuñay Uceda 47 DHTML ser el código HTML de una página completa (lo que normalmente va entre las etiquetas <BODY> y </BODY>) Un segundo diseño con frames podría ser dividiendo la página de manera horizontal. Ejemplo11c.html <HTML> <HEAD> <TITLE>Mi página con frames</TITLE> </HEAD> <FRAMESET ROWS="20%, 80%"> <FRAME SRC="ejercicio11a.html"> <FRAME SRC="ejercicio11b.html" NAME="principal"> </FRAMESET> <NOFRAMES> Estas utilizando un navegador que no soporta frames. <A HREF="ejercicio12.html"> ir a página sin frames </A>. </NOFRAMES> </HTML> Resultado Web: Figura 29. Marcos con división horizontal Oscar E Capuñay Uceda 48 DHTML Etiqueta ACRONYM Indica un acrónimo (es la suma de los significados de las palabras que lo forman. Por ejemplo HTML, (Hyper Text Markup Language). Etiqueta ABBR Indica una forma abreviada (etc, Dr, Ing, Corp, etc.). Los elementos ABBR y ACRONYM permiten a los autores indicar claramente la aparición de abreviaturas y acrónimos. Ejemplo 12: Ejemplo12.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Documento sin título</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <ACRONYM title="World Wide Web">WWW</ACRONYM> <ACRONYM lang="en" title="Hyper Text Markup language"> HTML </ACRONYM> <br> <ABBR lang="es" title="Doctor">Dr</ABBR> <ABBR title="Señor">Sr</ABBR> </body> </html> Resultado Web: Acrónimos y Abreviaturas Figura 30. Acrónimos y abreviaturas Etiqueta Q Esta etiqueta inserta comillas dobles en una frase. Se utiliza para citar frases. Ejemplo 13: Frase entre comillas Ejercicio13.html Oscar E Capuñay Uceda 49 DHTML Carlos dice: <Q lang="es"> Estoy aprendiendo HTML </Q><br> Jaime dice: <Q lang="es"> Es un lenguaje fácil de aprender </Q> Resultado Web: Figura 31. Frase entre comillas Etiquetas INS y DEL INS y DEL se usan para marcar secciones del documento que han sido insertadas o borradas con respecto a una versión diferente de un documento. Estos dos elementos son especiales dentro de HTML, ya que pueden actuar o bien como elementos en bloque o bien como elementos en línea (pero no como ambos a la vez). Pueden contener una o más palabras dentro de un párrafo o uno o más elementos en bloque como párrafos, listas y tablas. Ejemplo 14: Ejercicio14.html <INS datetime="2008-09-25T08:15:30-05:00" cite="http://oscar.capunay.com/index.php">Ejemplo de texto nuevo. Este texto fue agregado. </INS> <P> Esta frase tiene <DEL>una palabra borrada</DEL> algo borrado. </P> Resultado Web: INS y DEL Figura 32. Acrónimos y abreviaturas Oscar E Capuñay Uceda 50 DHTML OBJECT Esta etiqueta se usa cuando un elemento Web será representado utilizando un plug-in de algún software externo al agente o navegador utilizado. PARAM Las etiquetas PARAM especifican un conjunto de valores que pueden ser necesarios para un objeto en tiempo de ejecución. Puede aparecer cualquier número de elementos PARAM en el contenido de un elemento OBJECT o APPLET, y en cualquier orden, pero deben ser colocados al principio del contenido del elemento OBJECT o APPLET que los contienen. Ejemplo 15: Ejemplo15.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ejemplo de OBJECT, PARAM y EMBED</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swfl ash.cab#version=6,0,0,0" WIDTH="100%" HEIGHT="100%" ALIGN="" id="intro2"> <PARAM NAME=movie VALUE="intro2.swf"> <PARAM NAME=loop VALUE=false> <PARAM NAME=menu VALUE=false> <PARAM NAME=quality VALUE=high> <PARAM NAME=scale VALUE=exactfit> <PARAM NAME=bgcolor VALUE=#080638> <EMBED src="intro2.swf" loop=false menu=false quality=high scale=exactfit bgcolor=#080638 WIDTH="100%" HEIGHT="100%" NAME="intro2" ALIGN="" TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer"></EMBED > </OBJECT> </body> </html> Resultado Web: OBJECT Y PARAM Oscar E Capuñay Uceda 51 DHTML Figura 33. Animación flash TABLAS Grupos de filas: los elementos THEAD, TFOOT y TBODY Las filas de una tabla pueden agruparse en una cabecera de tabla, un pie de tabla, y una o más secciones de cuerpo de tabla, usando los elementos THEAD, TFOOT y TBODY, respectivamente. Esta división permite a los agentes de usuario ofrecer la posibilidad de desplazar la información de los cuerpos de la tabla independientemente de la cabecera y el pie. Cuando se imprimen tablas largas, la información de cabecera y pie de tabla puede repetirse en todas las páginas que contengan datos de la tabla. La cabecera de tabla y el pie de tabla deberían contener información sobre las columnas de la tabla. El cuerpo de tabla debería contener filas de datos de tabla. En caso de estar presentes, cada elemento THEAD, TFOOT y TBODY contiene un grupo de filas. Cada grupo de filas debe contener al menos una fila. Ejemplo 16: Ejercicio16.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ejemplo de THEAD, TFOOT y TBODY</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> Oscar E Capuñay Uceda 52 Uso de TABLA, THEAD, TFOOT y TBODY DHTML <table> <thead> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> </tr> </thead> <tfoot> <tr> <th colspan="3">Pie de la tabla</th> </tr> </tfoot> <tbody> <tr><td>1</td> <td>Kelly</td> <td>Quiroz Ch</td> </tr> <tr> <td>2</td> <td>Carlos</td> <td>Capuñay Uceda</td> </tr> <tr> <td>3</td> <td>Marco</td> <td>Quiroz Chavil</td> </tr> <tr> <td>4</td> <td>Jaime</td> <td>Capuñay Uceda</td> </tr> </tbody> </table> </body> </html> Resultado Web: Figura 34. Tabla con THEAD, TFOOT Y TBODY TFOOT debe aparecer antes de TBODY dentro de una definición de TABLE de modo que el navegador pueda representar el pie antes de recibir todas las (potencialmente numerosas) filas de datos. A continuación se resume qué etiquetas son obligatorias y cuáles pueden omitirse: Oscar E Capuñay Uceda 53 DHTML FORMULARIOS El elemento BUTTON Los botones creados con el elemento BUTTON funcionan exactamente igual que los botones creados con el elemento INPUT, pero ofrecen posibilidades más ricas de representación: el elemento BUTTON puede tener contenido. Por ejemplo, un elemento BUTTON que contenga una imagen se parece y funciona como un elemento INPUT cuyo atributo type sea igual a "image", pero el tipo de elemento BUTTON permite un contenido. Los navegadores pueden representar los botones BUTTON con un relieve y un movimiento arriba/abajo al pulsarlos, mientras que pueden representar los botones INPUT como imágenes "planas". El siguiente ejemplo extiende un ejemplo previo, pero creando los botones de envío y de restablecer con BUTTON en lugar de INPUT. Los botones contienen imágenes sacadas de elementos IMG. Ejemplo 17: Ejercicio17.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ejemplo de BUTTON</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <FORM action="http://oscar.capunay.com/datos/formulario" method="post"> <P> Nombre: <INPUT type="text" name="txtnombre"><BR> Apellido: <INPUT type="text" name="txtapellido"><BR> email: <INPUT type="text" name="txtemail"><BR> sexo: <INPUT type="radio" name="optsexo" value="H"> Hombre <INPUT type="radio" name="optsexo" value="M"> Mujer<BR> <BUTTON name="enviar" value="enviar" type="submit"> Editar<IMG src="iconos/editar.gif" alt="Enviar Datos"></BUTTON> <BUTTON name="reiniciar" type="reset"> Restablecer<IMG src="iconos/nuevo.gif" alt="Limpiar" width="12"></BUTTON> </P> </FORM> </body> </html> Resultado Web: Button con imagen Oscar E Capuñay Uceda 54 DHTML Figura 35. BUTTON con imagen El elemento OPTGROUP El elemento OPTGROUP permite a los autores agrupar opciones lógicamente. Esto es particularmente útil cuando el usuario debe elegir de entre una larga lista de opciones; es más fácil apreciar y recordar grupos de opciones relacionadas que una larga lista de opciones sueltas. En HTML 4, todos los elementos OPTGROUP deben especificarse directamente dentro de un elemento SELECT (es decir, no pueden anidarse unos grupos dentro de otros). Ejemplo 18: Ejercicio18.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ejemplo de OPTGROUP</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <FORM action="http://oscar.capunay.com/datos/registro.php" method="post"> <P> <SELECT name="Producto" size="1"> <OPTION selected label="ninguno" value="ninguno"> Ninguno</OPTION> <OPTGROUP label="Limpieza"> <OPTION label="escoba" value="limp001">Escoba</OPTION> <OPTION label="jabón" value="limp002">jabón</OPTION> <OPTION label="detergente" value="limp003">Detergente</OPTION> </OPTGROUP> <OPTGROUP label="Dulces"> <OPTION label="chocolate" value="dulc001">Chocolate</OPTION> Oscar E Capuñay Uceda 55 Formulario con OPTGROUP DHTML <OPTION label="caramelo" value="dulc002">Caramelo</OPTION> <OPTION label="gelatina" value="dulc003">Gelatina</OPTION> </OPTGROUP> <OPTGROUP label="Bebidas"> <OPTION label="pepsi" value="bebi001">PEPSI</OPTION> <OPTION label="cola-cola" value="bebi002">Coca Cola</OPTION> </OPTGROUP> </OPTGROUP> </SELECT> </FORM> </body> </html> Resultado Web: Figura 36. Lista con OPTGROUP Estructura a los formularios: los elementos FIELDSET y LEGEND La etiqueta FIELDSET agrupa controles, lo que permite a los usuarios entender su propósito y al mismo tiempo facilita la navegación. El uso correcto de esta etiqueta le da mayor nivel de accesibilidad al documento Web. La etiqueta LEGEND permite asignar un título a un FIELDSET. La leyenda mejora la accesibilidad cuando el FIELDSET no se representa visualmente. Ejemplo 19: Ejercicio19.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Ejemplo FIELDSET y LEGEND</title> Oscar E Capuñay Uceda 56 Ejemplo de Conjunto de Campos DHTML <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <FORM action="data/proceso1.php" method="post"> <FIELDSET> <LEGEND>Datos Personales </LEGEND> Nombres:<INPUT name="txtnombres" type="text" tabindex="1"><br> Apellidos:<INPUT name="txtapellidos" type="text" tabindex="2"><br> Ciudad: <INPUT name="txtciudad" type="text" tabindex="3"><br> Teléfono: <INPUT name="txtfono" type="text" tabindex="4"><br> </FIELDSET> <FIELDSET> <LEGEND>Datos Internet</LEGEND> Página personal:<INPUT name="txtpagina" type="text" size="50" tabindex="5"><br> Blog:<INPUT name="txtblog" type="text" size="40" tabindex="2"><br> Correo Electrónico: <INPUT name="txtcorreo" type="text" size="30" tabindex="3"><br> Skype: <INPUT name="txtfono" type="text" size="10" tabindex="4"><br> ICQ: <INPUT name="txtfono" type="text" size="10" tabindex="4"><br> </FIELDSET> <button type="submit">Enviar</button> </FORM> </body> </html> Resultado Web: Figura 37. Formulario con agrupamiento de controles Oscar E Capuñay Uceda 57 DHTML Etiquetas DIV y SPAN Las etiquetas DIV y SPAN, junto con los atributos id y class, ofrecen un mecanismo genérico para añadir estructura a los documentos. Estos elementos especifican si su contenido es en línea (SPAN) o en bloque (DIV) pero no imponen ningún otro estilo de presentación al contenido, por este motivo, se pueden aplicar hojas de estilo en cascada a estas etiquetas. Ejemplo 20: Ejercicio20.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <script type="text/javascript"> <!-function toggle(obj){ var objID = document.getElementById(obj); objID.style.display = (objID.style.display == "none")?"":"none"; } // --> </script> <title>menu</title> </head> <body> <table> <tr> <th width="16"><a href="#" onClick="toggle('tablas');return false;" title="Ocultar o Mostrar Menu"> <img src="iconos/nuevo.gif" alt="despliegue" width="16" height="16" border="0"></a></th> <th><SPAN>Tablas</SPAN></th> </tr> </table> <div id="tablas" style="display: none;"> <table> <tr> <td><a href="universidad.php" target="principal">Universidades</a></td> </tr> <tr> <td><a href="facultad.php" target="principal">Facultades</a></td> </tr> <tr> <td><a href="escuela.php" target="principal">Escuelas</a></td> </tr> <tr> <td><a href="semestre.php" target="principal">Semestre</a></td> </tr> Oscar E Capuñay Uceda 58 DIV y SPAN DHTML </table> </div> <table> <tr> <th width="16"><a href="#" onClick="toggle('academico');return false;" title="Ocultar o Mostrar Menu"> <img src="iconos/nuevo.gif" alt="despliegue2" width="16" height="16" border="0"></a></th> <th><SPAN>Maestros</SPAN></th> </tr> </table> <div id="academico" style="display: block;"> <table> <tr> <td><a href="alumno.php" target="principal">Alumnos</a></td> </tr> <tr> <td><a href="curso.php" target="principal">Cursos</a></td> </tr> <tr> <td><a href="evaluacion.php" target="principal"> Evaluaciones </a></td> </tr> <tr> <td><a href="registro.php" target="principal">Registro</a></td> </tr> <tr> <td><a href="asistencia.php" target="principal">Inasistencias</a></td> </tr> <tr> <td><a href="resultado.php" target="principal">Resultados</a></td> </tr> <tr> <td><a href="mensaje.php" target="principal">Mensajes</a></td> </tr> <tr> <td><a href="encuesta.php" target="principal">Encuestas</a></td> </tr> </table> </div> </body> </html> Podemos ver en este ejemplo que podemos ocultar o hacer visible las DIV. Resultado Web: Oscar E Capuñay Uceda 59 DHTML Figura 38. Ejemplo de página con DIVs y SPANs Oscar E Capuñay Uceda 60 DHTML JavaScript JavaScript, al igual que Java o VRML, es una de las múltiples maneras que han surgido para extender las capacidades del lenguaje HTML. Al ser la más sencilla, es por el momento la más extendida. Es importante saber que: JavaScript no es un lenguaje de programación propiamente dicho. Es un lenguaje script u orientado a documento, como pueden ser los lenguajes de macros que tienen muchos procesadores de texto. Nunca se podrá hacer un programa con JavaScript, tan sólo se podrá mejorar una página Web con algunas cosas sencillas. JavaScript y Java son dos cosas distintas, principalmente porque Java sí que es un lenguaje de programación completo. Lo único que comparten es la misma sintaxis. Existen tres versiones de JavaScript. Casi todo lo que se ha escrito en este documento funciona con la versión 1.0, que nació con el Netscape Navigator 2.0. También existe una versión 1.3, introducida en la versión 4.06. Esta versión es una pequeña revisión de la 1.2 creada para ajustarse al estándar internacional ECMA que regula el lenguaje JavaScript. Vamos a realizar nuestro primer "programa" en JavaScript. Haremos surgir una ventana que nos muestre el mensaje "hola, Web". Así podremos ver los elementos principales del lenguaje. El siguiente código es una página Web completa con un botón que, al pulsarlo, muestra el mensaje. Ejemplo 21: HolaWeb.html función alert <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> function HolaWeb() { alert("¡Hola, Web!"); } </SCRIPT> </HEAD> <BODY> <FORM> <INPUT TYPE="button" NAME="Boton" VALUE="Pulsame" onClick="HolaWeb()"> </FORM> </BODY> </HTML> Ahora vamos a ver, paso por paso, que significa cada uno de los elementos extraños que tiene la página anterior: <SCRIPT LANGUAGE="JavaScript"> </SCRIPT> Oscar E Capuñay Uceda 61 DHTML Dentro de estos elementos será donde se puedan poner funciones en JavaScript. Por otra parte el código de JavaScript puede ser incluido en la página Web de la siguiente manera: <script language="JavaScript" src ="archivo.js"> </script> El archivo externo simplemente es un archivo del texto que contiene código JavaScript, y cuyo nombre acaba con la extensión js. El código de Java Script puede ser escrito en cualquier lugar de la página Web, en este ejemplo, se ha escrito en la cabecera con la finalidad de hacer el código más legible. Si un navegador no acepta JavaScript no leerá lo que hay entre estos elementos. function HolaWeb() { alert("¡Hola, Web!"); } Aunque JavaScript esté orientado a objetos no es de ningún modo tan estricto como Java, donde nada está fuera de un objeto. En el código de la función vemos una llamada al método alert (que pertenece al objeto window) que es la que se encarga de mostrar el mensaje en pantalla. <FORM> <INPUT TYPE="button" NAME="Boton" VALUE="Pulsame" onClick="HolaWeb()"> </FORM> Dentro del elemento que usamos para mostrar un botón vemos una cosa nueva: onClick. Es un controlador de evento. Cuando el usuario pulsa el botón, el evento click se dispara y ejecuta el código que tenga entre comillas el controlador de evento onClick, en este caso la llamada a la función HolaWeb(), que tendremos que haber definido con anterioridad. Existen muchos más eventos que iremos descubriendo según avancemos. En realidad, podríamos haber escrito lo siguiente: <FORM> <INPUT TYPE="button" NAME="Boton" VALUE="Pulsame" onClick="alert('¡Hola,Mundo!')"> </FORM> Elementos básicos Comentarios Un comentario es una parte de nuestro programa que el ordenador ignora y que, por tanto, no realiza ninguna tarea. Se utilizan generalmente para poner Oscar E Capuñay Uceda 62 DHTML en lenguaje humano lo que estamos haciendo en el lenguaje de programación y así hacer que el código sea más comprensible. En JavaScript existen dos tipos de comentarios. El primero nos permite que el resto de la línea sea un comentario. Para ello se utilizan dos barras inclinadas: var i = 1; // Aqui esta el comentario Sin embargo, también permite un tipo de comentario que puede tener las líneas que queramos. Estos comentario comienzan con: /* y terminan por */. Literales Se llama así a los valores que puede tomar una variable o una constante. Aparte de los distintos tipos de números y valores booleanos: "Soy una cadena" 3434 3.43 true, false También podemos especificar arrayso vectores: vacaciones = ["Navidad", "Semana Santa", "Verano"]; alert(vacaciones[0]); Dentro de las cadenas podemos indicar varios caracteres especiales, con significados especiales. Estos son los más usados: Tabla 3. Caracteres especiales para cadenas en JavaScript Carácter \n \t \' \" \\ \999 Significado Nueva línea Tabulador Comilla simple Comilla doble Barra invertida El número ASCII (según la codificación Latin-1) del carácter en hexadecimal De este modo, el siguiente literal: "Javascript (\xA9 2002)" se corresponde con la cadena: Javascript (© 2002) Por último, también se pueden especificar objetos como literales, aunque no funcione en más que en Netscape 4 y superiores: Oscar E Capuñay Uceda 63 DHTML miNavegador = {nombre: "Netscape", version: 4.5, idioma: "Español", plataforma: "PC"}; alert(miNavegador.plataforma); Sentencias y bloques En Javascript las sentencias se separan con un punto y coma, y se agrupan mediante llaves ({ y }). Tipos de datos En Javascript los tipos de datos se asignan dinámicamente según asignamos valores a las distintas variables y son los clásicos: cadenas de texto, varios tipos de enteros y reales, valores booleanos, vectores, matrices, referencias y objetos. Variables Las variables son nombres que ponemos a los lugares donde almacenamos la información. En Javascript, deben comenzar por una letra o un subrayado (_), pudiendo haber además dígitos entre los demás caracteres. No es necesario declarar una variable, pero cuando se hace es por medio de la palabra reservada var. Una variable, cuando no es declarada, tiene siempre ámbito global, mientras que en caso contrario será de ámbito global si está definida fuera de una función, y local si está definida dentro: var x; // Accesible fuera y dentro de pruebas y = 2; // Accesible fuera y dentro de pruebas function pruebas() { var z; // Accesible sólo dentro de pruebas w = 1; // Accesible fuera y dentro de pruebas } Se pueden declarar varias variables en una misma sentencia separándolos por comas: var x, y, z; El tipo de datos de la variable será aquel que tenga el valor que asignemos a la misma, a no ser que le asignemos un objeto por medio del operador new. Vectores y matrices Estos tipos de datos complejos son un conjunto ordenado de elementos, cada uno de los cuales es en sí mismo una variable distinta. En Javascript, los vectores y las matrices son objetos. Como veremos que hacen todos los objetos, se declaran utilizando el operador new: miVector = new Array(20) Oscar E Capuñay Uceda 64 DHTML El vector tendrá inicialmente 20 elementos (desde el 0 hasta el 19). Si queremos ampliarlo no tenemos más que asignar un valor a un elemento que esté fuera de los límites del vector: miEstupendoVector[25] = "Algún valor" De hecho, podemos utilizar de índices cualquier expresión que deseemos utilizar. Ni siquiera necesitamos especificar la longitud inicial del vector si no queremos: vectorRaro = new Array(); vectorRaro["insertar en los favoritos"] = "Esto es Javascript"; Hacer una matriz bidimensional es más complicado, ya que tenemos que hacer un bucle que cree un vector nuevo en cada elemento del vector original. Nota importante: JavaScript es sensible a mayúsculas y minúsculas, todos los elementos de JavaScript deben referenciarse cómo se definieron, no es lo mismo "Salto" que "salto". Operadores Los operadores nos permiten unir identificadores y literales para formar expresiones. Las expresiones son el resultado de operaciones matemáticas o lógicas. Un literal o una variable son expresiones, pero también lo son esos mismos literales y variables unidos entre sí mediante operadores. JavaScript dispone de muchos más operadores que la mayoría de los lenguajes, si exceptuamos a sus padres C, C++ y Java. Algunos de ellos no los estudiaremos debido a su escasa utilidad y con algunos otros (especialmente el condicional) deberemos andarnos con cuidado, ya que puede lograr que nuestro código no lo entendamos ni nosotros. Operadores aritméticos JavaScript dispone de los operadores aritméticos clásicos y algún que otro más: Tabla 4. Operadores aritméticos Descripción Multiplicación División Símbolo * / Expresión ejemplo 2*4 5/2 5%2 2+2 7-2 ++2 --2 de Resultado ejemplo 8 2.5 1 4 5 3 1 del Resto de una división % entera Suma Resta Incremento Decremento + ++ -- Oscar E Capuñay Uceda 65 DHTML Menos unario -(2+4) -6 Los operadores de incremento y decremento merecen una explicación auxiliar. Se pueden colocar tanto antes como después de la expresión que deseemos modificar pero sólo devuelven el valor modificado si están delante. a = 1; b = ++a; En este primer caso, a valdrá 2 y b 2 también. Sin embargo: a = 1; b = a++; Ahora, a sigue valiendo 2, pero b es ahora 1. Es decir, estos operadores modifican siempre a su operando, pero si se colocan detrás del mismo se ejecutan después de todas las demás operaciones. Operadores de comparación Podemos usar los siguientes: Tabla 5. Operadores de comparación Descripción Igualdad Desigualdad Igualdad estricta Menor que Mayor que Menor o igual que Mayor o igual que Símbolo Expresión de ejemplo Resultado del ejemplo == != === < > <= >= 2 == '2' 2 != 2 2 === '2' 2 !== 2 2<2 3>2 2 <= 2 1 >= 2 Verdadero Falso Falso Falso Falso Verdadero Verdadero Falso Desigualdad estricta !== La igualdad y desigualdad estricta son iguales a las normales pero hacen una comprobación estricta de tipo. Han sido incluidos en el estándar ECMAScript y lo soportan Netscape 4.06 y superiores y Explorer 3 y superiores. Hay que indicar que versiones más antiguas de Netscape tratan la igualdad normal como si fuera estricta. Operadores lógicos Estos operadores permiten realizar expresiones lógicas complejas: Tabla 6. Operadores lógicos Descripción Símbolo Expresión de ejemplo Resultado del ejemplo Negación ! !(2 = 2) Falso Oscar E Capuñay Uceda 66 DHTML Y Ó && || (2 = 2) && (2 >= 0) (2 = 2) || (2 <> 2) Verdadero Verdadero Operadores de asignación Normalmente los lenguajes tienen un único operador de asignación, que en JavaScript es el símbolo =. Pero en este lenguaje, dicho operador se puede combinar con operadores aritméticos y lógicos para dar los siguientes: Tabla 7. Operadores de asignación Operador Significado Operador Significado x += y x /= y x%y x=x+y x=x/y x=x%y x -= y x *= y x=x-y x=x*y Operadores Especiales Vamos a incluir en este apartado operadores que no hayan sido incluidos en los anteriores. La concatenación de cadenas, por ejemplo, se realiza con el símbolo +. El operador condicional tiene esta estructura: condición ? valor1 : valor2 Si la condición se cumple devuelve el primer valor y, en caso contrario, el segundo. El siguiente ejemplo asignaría a la variable a un 2: a=2>3?1:2 Para tratar con objetos disponemos de tres operadores: Tabla 8. Operadores especiales Descripción Crear un objeto Borrar un objeto Referencia al objeto actual Símbolo Ejemplo new delete this Resultado del ejemplo Elimina el anteriormente creado vector a = new Array() a es ahora un vector delete a this se suele utilizar en el código de los métodos de un objeto para referirse a otros métodos o a propiedades de su mismo objeto. Oscar E Capuñay Uceda 67 DHTML Estructuras de control Estas estructuras se pueden clasificar en dos grandes grupos: bifurcaciones condicionales y bucles. Aparte de los dos tipos clásicos de estructuras de control, en JavaScript disponemos de algunas estructuras adicionales para facilitar el manejo de objetos. a) Bifurcaciones condicionales Una bifurcación condicional en una estructura que realiza una tarea u otra dependiendo del resultado de evaluar una condición. La primera que vamos a estudiar es la estructura if...else. Esta estructura es la más sencilla y antigua de todas: a=5; b=7; if (a>b) alert(“a es mayor que b”); else alert(“a no es mayor que b”); Hay que indicar que el else es opcional.. La siguiente estructura bifurca según los distintos valores que pueda tomar una variable específica. Es la sentencia switch: switch(color) { case "azul": alert(“ El color elegido es el azul”); break; case "rojo": alert(“ El color elegido es el rojo”); break; default: alert(“ El color por defecto es negro”); } Hay que indicar que no es compatible con estándar ECMA y no es soportado por el Explorer 3. Bucles Un bucle es una estructura que permite repetir una tarea un número de veces, determinado por una condición. Para hacer bucles podemos utilizar las estructuras while y do...while. Estos bucles iteran indefinidamente mientras se cumpla una condición. La diferencia entre ellas es que la primera comprueba dicha condición antes de realizar cada iteración y la segunda lo hace después: var numero=0; Oscar E Capuñay Uceda 68 DHTML while (numero==1) { alert('Soy un while'); } do { alert('Soy un do...while'); } while (numero==1); En este caso solo veríamos aparecer una ventana diciendo que es un do...while. ¿Qué por qué? Veamos. El while comprueba primero si numero es igual a 1 y, como no lo es, no ejecutaría el código que tiene dentro del bucle. En cambio, el do...while primero ejecuta el código y luego, viendo que la condición es falsa, saldría. Hay que resaltar que do...while no pertenece al estándar y no es soportado por el Explorer 3. En Javascript, el bucle for es singularmente potente. No se reduce a casos numéricos como en muchos otros lenguajes sino que nos da mucha más libertad. Tiene la siguiente estructura: for (inicio; condición; incremento) código El código contenido en el bucle se ejecutará mientras la condición se cumpla. Antes de comenzar la primera iteración del bucle se ejecutará la sentencia inicio y en cada iteración lo hará incremento. La manera más habitual de usar estas posibilidades es, claro está, la numérica: var numero = 4; for (n = 2, factorial = 1; n <= numero; n++) factorial *= n; Por último, hay que decir que la ejecución de la sentencia break dentro de cualquier parte del bucle provoca la salida inmediata del mismo. Aunque a veces no hay más remedio que utilizarlo, es mejor evitarlo para mejorar la legibilidad y elegancia del código. Estructuras de manejo de objetos JavaScript dispone de dos bien distintas. La primera es el bucle for...in, que nos permitirá recorrer todas las propiedades de un objeto. Se usa principalmente con vectores. Por ejemplo: var vector = [1, 2, 2, 5]; for (i in vector) vector[i] += 2; Oscar E Capuñay Uceda 69 DHTML Este ejemplo sumaría dos a todos los elementos del vector. Sin embargo, conviene tener cuidado ya que, de los navegadores de Microsoft, sólo la versión 5 lo soporta. La otra estructura es with, que nos permitirá una mayor comodidad cuando tengamos que tratar con muyas propiedades de un mismo objeto. En lugar de tener que referirnos a todas ellas con un objeto.propiedad podemos hacer: with (objeto) { propiedad1 = ... propiedad2 = ... ... } Objetos Un objeto es una estructura que contiene tanto variables (llamadas propiedades) como las funciones que manipulan dichas variables (llamadas métodos). A partir de esta estructura se ha creado un nuevo modelo de programación (la programación orientada a objetos) que atribuye a los objetos propiedades como herencia o polimorfismo. Como veremos, JavaScript simplifica en algo este modelo. Creación mediante constructores Un constructor es una función que inicializa un objeto. Cuando creamos un objeto nuevo del tipo que sea, lo que hacemos en realidad es llamar al constructor pasándole argumentos. Por ejemplo, si creamos un objeto Array de esta manera: vector = new Array(9); En realidad, estamos llamando a un constructor llamado Array que admite un parámetro. Sería algo así: function Array(longitud) { ... } Vamos a crear nuestro primero objeto. Supongamos que queremos codificar en Javascript una aplicación que lleve nuestra biblioteca de libros técnicos de Informática. Para lograrlo, crearemos un objeto Libro que guarde toda la información de cada libro. Este sería el constructor: function Libro(titulo, autor, tema) { this.titulo = titulo; this.autor = autor; this.tema = tema; } Oscar E Capuñay Uceda 70 DHTML Como vemos, accederemos a las propiedades y métodos de nuestros objetos por medio de la referencia this. Ahora podemos crear y acceder a nuestros objetos tipo Libro: miLibro = new "JavaScript"); alert(miLibro.autor); Libro("JavaScript Bible", "Danny Goodman", Los métodos también podemos incluirlos de la siguiente forma: function escribirLibro() { alert("El libro " + this.titulo + " de " + this.autor + " trata sobre " + this.tema); } Para incluirlo en nuestro objeto añadimos la siguiente línea a nuestra función constructora: this.escribir = escribirLibro; Y podremos acceder al mismo de la manera normal: miLibro.escribir(); Objetos predefinidos JavaScript dispone de varios objetos predefinidos para acceder a muchas de las funciones normales de cualquier lenguaje, como puede ser el manejo de vectores o el de fechas. En algunos casos estaremos tratando con objetos aunque no nos demos cuenta, ya que los usos más habituales de los mismos disponen de abreviaturas que esconden el hecho de que sean objetos. a) Objeto Array Como dijimos antes, este objeto permite crear vectores. Se inicializa de cualquiera de las siguientes maneras: vector = new Array(longitud); vector = new Array(elemento1, elemento2, ..., elementoN); En el primer caso crearemos un vector con el número especificado de elementos, mientras que en el segundo tendremos un vector que contiene los elementos indicados y de longitud N. Para acceder al mismo debemos recordar que el primero elemento es el número cero. El objeto Array tiene, entre otros, los siguientes métodos y propiedades: length: Propiedad que contiene el número de elementos del vector. Oscar E Capuñay Uceda 71 DHTML concat(vector2): Añade los elementos de vector2 al final de los del vector que invoca el método, devolviendo el resultado. No funciona en Explorer 3 y no forma parte del estándar ECMA. sort(funcionComparacion): Ordena los elementos del vector alfabéticamente. Si se añade una función de comparación como parámetro los ordenará utilizando ésta. Dicha función debe aceptar dos parámetros y devolver 0 si son iguales, menor que cero si el primer parámetro es menor que el segundo y mayor que cero si es al revés. function compararEnteros(a,b) { return a<b ? -1 : (a==b ? 0 : 1); } Usando esta función ordenaría numéricamente (y de menor a mayor) los elementos del vector. b) Objeto Date Este objeto nos permitirá manejar fechas y horas. Se invoca así: fecha = new Date(); fecha = new Date(año, mes, dia); fecha = new Date(año, mes, dia, hora, minuto, segundo); Si no utilizamos parámetros, el objeto fecha contendrá la fecha y hora actuales, obtenidas del reloj del sistema. En caso contrario hay que tener en cuenta que los meses comienzan por cero. Así, por ejemplo: navidad99 = new Date(1999, 11, 25) El objeto Date dispone, entre otros, de los siguientes métodos: getTime() setTime(milisegundos) Obtienen y ponen, respectivamente, la fecha y la hora tomados como milisegundos transcurridos desde el 1 de enero de 1970. getYear() setYear(año) Obtienen y poner, respectivamente, el año de la fecha. Éste se devuelven como números de 4 dígitos excepto en el caso en que estén entre 1900 y 1999, en cuyo caso se devolverán las dos últimas cifras. Hay que tener cuidado, ya que la implementación de éstos métodos puede variar en las últimas versiones de Netscape. getFullYear() setFullYear(año) Oscar E Capuñay Uceda 72 DHTML Realizan la misma función que los anteriores, pero sin tantos líos, ya que siempre devuelven números con todos sus dígitos. Funciona en Explorer 4 y Netscape 4.06 y superiores. getMonth() setMonth(mes) getDate() setDate(dia) getHours() setHours(horas) getMinutes() setMinutes(minutos) getSeconds() setSeconds(segundos) Obtienen y ponen, respectivamente, el mes, día, hora, minuto y segundo de la fecha, también respectivamente, respectivamente hablando. getDay() Devuelve el día de la semana de la fecha en forma de número que va del 0 (domingo) al 6 (sábado). c) Objeto Math Este objeto no está construido para que tengamos nuestras variables Math, sino como un contenedor donde meter diversas constantes (como Math.E y Math.PI) y los siguientes métodos matemáticos: Tabla 9. Métodos matemáticos del Objeto Math Método abs Descripción Valor absoluto Expresión ejemplo Math.abs(-2) de Resultado del ejemplo 2 Funciones sin, cos, reciben el tan radianes asin, acos, atan exp, log ceil floor Funciones inversas trigonométricas, argumento en Math.cos(Math.PI) -1 trigonométricas y logaritmo, Math.asin(1) Math.log(Math.E) 1.57 1 -2 -3 Exponenciación base E Devuelve el entero más pequeño mayor o igual al Math.ceil(-2.7) argumento Devuelve el entero más grande Math.floor(-2.7) menor o igual al argumento Oscar E Capuñay Uceda 73 DHTML round min, max pow sqrt Devuelve el entero más Math.round(-2.7) cercano o igual al argumento Devuelve el menor (o mayor) de Math.min(2,4) sus dos argumentos Exponenciación, siendo el primer argumento la base y el Math.pow(2,4) segundo el exponente Raíz cuadrada Math.sqrt(4) -3 2 16 2 d) Objeto Number Al igual que en el caso anterior, no se pueden crear objetos de tipo Number, sino que debemos referirnos al genérico. Este objeto contiene como propiedades los siguientes valores numéricos. Tabla 10. Propiedades del objeto Number Propiedad NaN MAX_VALUE y MIN_VALUE NEGATIVE_INFINITIVE POSITIVE_INFINITIVE y Descripción Valor que significa "no es un número" Máximo y mínimo número representable Infinito negativo y positivo, se utilizan cuando hay desbordamiento al realizar alguna operación matemática e) Objeto String Al crear una cadena estamos creando a la vez un objeto String asociado. Su utilidad está en sus métodos, entre los que cabe destacar: charAt(pos) y charCodeAt(pos) Devuelven el caracter o el código numérico del carácter que está en la posición indicada de la cadena. indexOf(subcadena) Devuelven la posición de la subcadena dentro de la cadena, o -1 en caso de no estar. split(separador) Devuelven un vector con subcadenas obtenidas separando la cadena por el carácter separador. No funciona en Explorer 3. cadena = "Navidad,Semana Santa,Verano"; vector = cadena.split(","); En el ejemplo, el vector tendrá tres elementos con cada una de las vacaciones de un escolar español normal. concat(cadena2) Devuelve el resultado de concatenar cadena2 al final de la cadena. No funciona en Explorer 3 y no forma parte del estándar ECMA. Oscar E Capuñay Uceda 74 DHTML substr(indice,longitud) y substring(indice1, indice2) Devuelven una subcadena de la cadena, ya sea cogiendo un número de caracteres a partir de un índice o pillando todos los caracteres entre dos índices. toLowerCase()y toUpperCase() Transforman la cadena a minúsculas y mayúsculas, respectivamente. Eventos Un evento, como su mismo nombre indica, es algo que ocurre. Para que una rutina nuestra se ejecute sólo cuando suceda algo extraño deberemos llamarla desde un controlador de eventos. Estos controladores se asocian a un elemento HTML y se incluyen así: <A HREF="http://home.netscape.com" onMouseOver="MiFuncion()"> Lista de eventos Aquí tienes una pequeña guía de eventos definidos en JavaScript. Tabla 11. Eventos de JavaScript Evento OnLoad OnUnLoad Descripción Elementos que lo admiten Terminar de cargarse una <BODY...> página <FRAMESET...> Salir de una (descargarla) página <BODY...><FRAMESET...> <A <AREA...> HREF..> HREF..> onMouseOver Pasar el ratón por encima onMouseOut onSubmit onClick onBlur OnChange OnFocus OnSelect Que el ratón deje de estar <A encima <AREA...> Enviar un formulario Pulsar un elemento Perder el cursor <FORM...> <INPUT TYPE="button, checkbox, link, radio"...> <INPUT <TEXTAREA...> TYPE="text"...> TYPE="text"...> TYPE="text"...> TYPE="text"...> Cambiar de contenido o <INPUT perder el cursor <TEXTAREA...> Conseguir el cursor Seleccionar texto <INPUT <TEXTAREA...> <INPUT <TEXTAREA...> Como ejemplo, vamos a hacer que una ventana aparezca automáticamente en cuanto pasemos un cursor por encima de un elemento <A> (e Oscar E Capuñay Uceda 75 DHTML impidiendo, de paso, que quien esté viendo la página pueda hacer uso del mismo). Ejemplo 22: Eventos eventos.html <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- Los comentarios esconden el código a navegadores sin JavaScript function Alarma() { alert("Se activo la función Alarma"); return true; } // --> </SCRIPT> </HEAD> <BODY> <A HREF="eventos.html" onMouseOver="Alarma()"> Pasa por aquí encima </A> </BODY> </HTML> Resultado Web: Figura 39. Resultado de eventos.html Figura 40. Resultado del método alert Oscar E Capuñay Uceda 76 DHTML Definición mediante código Hemos visto como declarar un controlador de eventos desde etiquetas HTML. Sin embargo, y desde las versiones 3 de Netscape y 4 de Explorer, existe otro modo de hacerlo mediante código. Muchos objetos cuyas etiquetas HTML correspondientes permiten atributos que definen controladores de evento, permiten el acceso a dichos controladores por medio de propiedades con el mismo nombre. Por ejemplo, la página: Ejemplo 23: load1.html <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- Los comentarios ocultan el código a browsers sin JScript function Saludo() { alert("Hola"); } // --> </SCRIPT> </HEAD> <BODY onLoad="Saludo()"> ... </BODY> </HTML> Definición mediante código Figura 41. Resultado de load1.html Oscar E Capuñay Uceda 77 DHTML Figura 42. Resultado del método alert Se puede reescribir como: load2.html <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> <!-- Los comentarios esconden el código a navegadores sin JS function Saludo() { alert("Hola"); } window.onload = Saludo; // --> </SCRIPT> </HEAD> <BODY> ... </BODY> </HTML> Modelo de objetos del documento Cuando funciona en un navegador, el lenguaje JavaScript dispone de una serie de objetos que se refieren a cosas como la ventana actual, el documento sobre el que trabajamos, o el navegador que estamos utilizando. Para los más iniciados en la programación orientada a objetos, conviene aclarar que en esta jerarquía, contra lo que pueda parecer, no existe herencia alguna. Los objetos se relacionan por composición, es decir, un objeto Window se compone (entre otras cosas) de un objeto Document, y éste a su vez se compone de diversos objetos Form, Image, etc.. El padre de esta jerarquía es el objeto Window, que representa una ventana de nuestro navegador. Dado que cada marco se considera una ventana distinta, cada uno de ellos dispone de su propio objeto Window. El objeto Document representa el documento HTML y cada uno de los objetos que lo componen se corresponde con diversas etiquetas HTML. Oscar E Capuñay Uceda 78 DHTML Objeto Window Es el objeto principal. Define la ventana sobre la que estamos trabajando e incluye los objetos referentes a la barra de tareas, el documento o la secuencia de direcciones de la última sesión. En este capítulo veremos los métodos y propiedades más utilizadas, al menos por mí, dejando el estudio de dichos objetos para sus capítulos correspondientes. Aún cuando el objeto se llame Window, disponemos siempre de una referencia a él llamada window (recuerde que Javascript distingue entre mayúsculas y minúsculas). Será con esa referencia con la que trabajemos. Por último, indicar que en Javascript, se supone que todas las propiedades y métodos que llamamos sin utilizar ninguna referencia, en realidad se hacen utilizando esa referencia window. Así, por ejemplo, cuando ejecutamos el método alert en realidad lo que estamos haciendo es ejecutar el método window.alert. [Variable=][window.]open(URL, nombre, propiedades) Permite crear (y abrir) una nueva ventana. Si queremos tener acceso a ella desde la ventana donde la creamos deberemos asignarle una variable, si no simplemente invocamos el método: el navegador automáticamente sabrá que pertenece al objeto window. El parámetro URL es una cadena que contendrá la dirección de la ventana que estamos abriendo: si está en blanco, la ventana se abrirá con una página en blanco. El nombre será el que queramos que se utilice como parámetro de un TARGET y las propiedades son una lista separada por comas de algunos de los siguientes elementos: toolbar[=yes|no] location[=yes|no] directories[=yes|no] status[=yes|no] menubar[=yes|no] scrollbars[=yes|no] resizable[=yes|no] width=pixels height=pixels Debemos tener cuidado con las propiedades que modifiquemos, es posible que algunas combinaciones de los mismos no funcionen en todos los navegadores. El Explorer 4, por ejemplo, da error ante la combinación toolbar=no, directories=no, menubar=no. Veamos un ejemplo: Ejemplo 24: ventanas.html Función open() <HTML> <HEAD> <SCRIPT LANGUAGE="JavaScript"> Oscar E Capuñay Uceda 79 DHTML function AbrirVentana() { MiVentana=open("","ventana2","toolbar=no,directories=no,menubar=no,status=yes"); MiVentana.document.write("<HEAD><TITLE>Una nueva ventana</TITLE></HEAD>"); MiVentana.document.write("<CENTER><H1><B>Texto de prueba</B></H1></CENTER>"); } </SCRIPT> </HEAD> <BODY> <FORM> <INPUT TYPE="button" NAME="Boton1" VALUE="Abrir otra ventana" onClick="AbrirVentana()"> </FORM> </BODY> </HTML> Este ejemplo muestra la posibilidad de abrir nuevas ventanas de nuestro navegador con JavaScript. Se llama a la función AbrirVentana desde el evento onClick, como ya sabemos hacer desde el primer ejemplo. Esta función crea la nueva ventana MiVentana y escribe en ella por medio del objeto Document todo el código HTML de la página. Resultado Web: Figura 43. Resultado de ventanas.html Oscar E Capuñay Uceda 80 DHTML Figura 44. La nueva ventana abierta close() Cierra la ventana. A no ser que hayamos acabado de abrirla nosotros mostrará al usuario una ventana de confirmación para que decida él si quiere o no cerrarla. Esto se hace por motivos de seguridad, ya que sería demasiado fácil hacer un script de esos mal intencionados que nos cerrase la ventana del navegador, con lo que fastidia eso. alert(mensaje) Muestra una ventana de diálogo con el mensaje especificado. confirm(mensaje) Muestra una ventana de diálogo con el mensaje especificado y dos botones. Si el usuario pulsa OK, el método devuelve true. Si, en cambio, pulsa Cancelar, devolverá false. prompt(mensaje, sugerencia) Muestra una ventana de diálogo con el mensaje especificado y un campo de texto en el que el usuario pueda teclear, cuyo valor inicial será igual a sugerencia. Si el usuario pulsa OK, el método devuelve la cadena introducida en el campo de texto. Si, por el contrario, pulsa Cancelar, devolverá el valor null. Dado que este valor se considera igual a false, podemos comprabarlo directamente en una condición para ver que ha hecho el usuario. Por ejemplo, el siguiente código muestra un saludo sólo si el usuario ha pulsado el botón de Aceptar: var contestacion = prompt("¿Cómo te llamas, criatura?", ""); if (contestacion) alert("Hola, " + contestacion); status Define la cadena de caracteres que saldrá en la barra de estado en un momento dado. defaultStatus Oscar E Capuñay Uceda 81 DHTML Define la cadena de caracteres que saldrá por defecto en la barra de estado. Cuando no la especificamos, defaultStatus será igual al último valor que tomó status. setTimeout("función",tiempo) Llama a función cuando hayan pasado tiempo milisegundos. Imprescindible a la hora de realizar cualquier rutina que deba ejecutarse a cierta velocidad. Objeto Document Este objeto representa el documento HTML en el que estamos. Se accede a él por medio de la referencia document. Su mayor importancia viene por el número de vectores que posee, que referencian a objetos Image, Form o Link, los cuales permiten acceder a las imágenes, formularios y enlaces del documento, respectivamente. lastModified Contiene la fecha y hora en que se modificó el documento por última vez y se suele usar en conjunción con write para añadir al final del documento estas características. bgColor Modifica el color de fondo del documento. El color deberá estar en el formato usado en HTML. Es decir, puede ser red o FF0000. forms[] Vector que contiene los formularios del documento. El primero será el número 0, el segundo el 1, etc.. images[] Vector que contiene las imágenes del documento. Se ordenan igual que en el anterior caso, aunque también permiten ser accedidas con el nombre como índice. Es decir, a una imagen definida como <IMG SRC=".." NAME="miImagen"> se puede acceder con document.inages["miImagen"]. links[] Vector que contiene los enlaces del documento. Se ordenan igual que en los dos anterioers, aunque no se suele utilizar en el código Javascript. Su razón de ser es que, al ser los enlaces objetos, permiten incluir código Javascript en ellos por medio de la pseudo-URL javascript:codigo. write(cadena) y writeln(cadena) Escribe el código HTML indicado en cadena en nuestro documento HTML. writeln hace lo mismo, pero incluyendo al final un retorno de carro. close() Cierra el documento, impidiendo escribir de nuevo en él. Oscar E Capuñay Uceda 82 DHTML Cómo escribir en el documento A la hora de escribir en un documento por medio de write o writeln hay que tener en cuenta un hecho fundamental. Para poder escribir en un documento, éste debe estar abierto y, al abrirlo, se destruye todo el código que haya en él. Ejemplo 25: escribir.html Escribir HTML con javascript <HTML> <HEAD> <TITLE>Escribe y no sobreescribe</TITLE> </HEAD> <BODY> Esta página fue modificada por última vez el día <script language="JavaScript" type="text/javascript"> document.write(document.lastModified); </SCRIPT> </BODY> </HTML> Resultado Web: Figura 45. Resultado de escribir.html Objeto Form Los formularios siempre han sido la mejor manera de facilitar la comunicación entre los usuarios y los creadores de una Web. Sin embargo, la implementación de los mismos en el lenguaje HTML ha provocado ciertos problemas debido a sus carencias. Estos problemas han intentado solventarse con scripts, situados tanto en el servidor como en el navegador. Los programas que se ejecutan en el navegador suelen estar escritos en JavaScript, y realizan tareas simples de validación. En muchas ocasiones están combinados con scripts CGI que modifican el mensaje generado por un formulario para facilitar su lectura y manejo. Oscar E Capuñay Uceda 83 DHTML El vector document.forms contiene todos los formularios de un documento. Así, se accedería al primer formulario definido como document.forms[0]. Sin embargo, si usamos el parámetro NAME en la etiqueta HTML: <FORM NAME="miFormulario"> Entonces podremos acceder al formulario con document.miFormulario, que resulta bastante más cómodo y estable ante la posibilidad de variación del número y posición de formularios en el documento. Estos son los métodos y propiedades del objeto Form: submit() Envía el formulario. reset() Devuelve los valores de un formulario a su estado inicial. elements[] Contiene todos y cada uno de los elementos de los que consta el formulario, es decir, los botones, cajas de textos, listas desplegables, etc. que componen un formulario. Cada elemento puede ser un objeto distinto, por lo que deberemos averiguar de qué tipo son por medio de la propiedad común type. Objetos Text Cuatro elementos HTML distintos (text, textarea, password y hidden) son, desde el punto de vista del DOM, objetos tan parecidos entre sí que vamos a estudiarlos conjuntamente. En realidad, sólo tienen tres propiedades verdaderamente importantes: name, type y value. Los métodos que podemos utilizar en estos objetos son: blur(). Pierde el foco del ratón sobre el objeto especificado. focus(). Obtiene el foco del ratón sobre el objeto especificado. select(). Selecciona el texto dentro del objeto dado. Como ejemplo de su uso, vamos a ver ahora el código de nuestro primer formulario con validación, que comprueba si la dirección de correo electrónico que introduce el usuario es correcta: formularios.html <HTML> <HEAD> <TITLE>Ejemplo de formularios</TITLE> <SCRIPT LANGUAGE="JavaScript"> function validar(direccion) { if (direccion.indexOf("@") != -1) return true; else { alert('Debe escribir una dirección válida'); Oscar E Capuñay Uceda 84 DHTML return false; } } </SCRIPT> </HEAD> <BODY> <FORM NAME="form1" METHOD="POST" ACTION="mailto:
[email protected]" ENCTYPE="text/plain" onSubmit="return validar(this.email.value)"> Envíame tu e-mail: <INPUT NAME="email" TYPE="text"><BR> <INPUT TYPE="submit" VALUE="Enviame tu e-mail"> </FORM> </BODY> </HTML> Resultado Web Figura 46. Resultado de formularios.html Figura 47. Mensaje de validación Oscar E Capuñay Uceda 85 DHTML El código es sencillo: el código llamado por el controlador de evento onSubmit debe devolver false si deseamos que el formulario no sea enviado. Así pues, llamamos a la función que comprueba si hay alguna arroba en el campo email del formulario. La manera de llamar a esta función es quizás lo más complicado. La función validar recibe una cadena de caracteres, devolviendo verdadero o falso dependiendo de que haya o no una arroba dentro de ella. El controlador utiliza para llamar a esta función lo siguiente: this.email.value this es una referencia estándar. Cuando veamos this en algún código en realidad deberemos sustituirlo mentalmente por el nombre del objeto en el que está el código. En este caso, como estamos dentro de miFormulario, this será equivalente a document.miFormulario. email es el nombre del campo que queremos investigar y value el atributo que contiene lo que haya tecleado el usuario. Objetos Checkbox y Radio En estos objetos, tanto el atributo HTML VALUE como su correspondiente propiedad value accesible desde Javascript no corresponden a nada visible. En ambos casos, el estado del elemento es de tipo lógico: puede estar seleccionado o no. Este valor lógico se contiene en la propiedad checked. Por tanto, para comprobar si está pulsado o no una caja de confirmación o un botón de selección específico deberemos preguntar por dicha propiedad. Objetos Select y Option El objeto Select es, con mucho, el más complicado. Esto es debido a que contiene en su interior un vector de objetos Option. Dispone de dos propiedades interesantes: selectedIndex Empezando a contar a partir de cero, indica qué opción está seleccionada. Si hay varias seleccionadas, indica la opción con el índice más bajo. options[] Vector que contiene los objetos Option correspondientes a todas y cada una de las opciones. El objeto Option, por otro lado, dispone de otras dos propiedades a estudiar (aparte de las comunes, como type o value): selected: Valor lógico que será verdadero si la opción está seleccionada. Text : Texto que acompaña a la opción. Como ejemplo, vamos a ver una lista desplegable que nos permita navegar por diversas páginas. Cada etiqueta OPTION tendrá como parámetro VALUE la dirección de la página Web e incluiremos un controlador del Oscar E Capuñay Uceda 86 DHTML evento onChange (que se ejecuta cuando el usuario cambia la opción escogida en la lista) que llamará a una rutina que explicamos más adelante: Ejemplo 26: select.html Select con javascript <HTML> <HEAD> <TITLE>Ejemplo de Select</TITLE> <SCRIPT LANGUAGE="JavaScript"> function irA(menu){ window.location.href = menu.options[menu.selectedIndex].value; } </SCRIPT> </HEAD> <BODY> <FORM name="formulario"> <SELECT NAME="menu" SIZE=1 onChange ="irA(this)"> <OPTION VALUE="">Visitar <OPTION VALUE="http://www.w3c.org">W3C <OPTION VALUE="http://www.capunay.com">Capunay <OPTION VALUE="http://www.google.com.pe">Google </SELECT> </FORM> </BODY> </HTML> La función irA simplemente utiliza la opción elegida para obtener por medio de su valor la dirección de la página a la que debe acudir. Resultado Web: Figura 48. Resultado de select.html Oscar E Capuñay Uceda 87 DHTML Otros objetos El modelo de objetos del documento define varios objetos, por así decirlo, "menores", que no tienen relación con nada físico de la página en la que estamos. Es decir, no guardan relación con las etiquetas HTML que estén en ellas escritas. Objeto History Se accede a este objeto por medio de la referencia document.history y contiene todas las direcciones que se han visitado en la sesión actual. Aunque no permite acceder a ellas, dispone de varios métodos para sustituir el documento actual por alguno que el usuario ya haya visitado: back() Volver a la página anterior. Es muy sencillo de utilizar: <A HREF="javascript:window.history.back()"> forward() Ir a la página siguiente. go(donde) Ir a donde se indique, siendo donde un número tal que go(1)=forward() y go(-1)=back(). Objeto Location Se accede a este objeto por medio de la referencia document.location y contiene información sobre la dirección de la página actual en varias propiedades. href Permite el acceso a la dirección de la página actual. Si lo cambiamos, pues cambiaremos de página. protocol Protocolo de la página actual. Habitualmente http. host Máquina donde se alberga la página actual. pathname Camino de la página actual. hash Si hemos accedido a una página por medio de un ancla, contiene una almohadilla seguida de ese ancla. Por ejemplo, #location. search Oscar E Capuñay Uceda 88 DHTML Puede que hallas notado que muchas páginas (especialmente en los motores de búsqueda) tienen unas direcciones inmensas con una estructura como: pagina.php?busq=HTML+en+espanol&tipo=Y. Esta propiedad permite acceder a esa última parte de la dirección (a partir de la interrogación, inclusive). Puede ser útil para pasar parámetros de una página a otra. Objeto Navigator Se accede a él por medio de la referencia navigator y nos permite averiguar varias características del navegador que usamos. Por ejemplo: appName Nombre del navegador. appVer Número principal de versión. language Idioma del mismo. platform Plataforma donde esta ejecutándose. No podemos sobreescribir estos atributos, pero sí leerlos. Objeto Screen Como cabía esperarse, se puede acceder a este objeto por medio de la referencia screen. Nos permitirá conocer la configuración de la pantalla del usuario. Al igual que en el anterior objeto, todos sus atributos son de sólo lectura. Conviene indicar que este objeto sólo está disponible desde las versiones 4.0 de ambos navegadores. height :Altura de la resolución de la pantalla. width :Anchura de la resolución de la pantalla. pixelDepth :Número de bits por pixel. Ejemplo: if (window.screen) texto=screen.width + "x" + screen.height + "x" + Math.pow(2,screen.colorDepth) + " colores."; else texto="quien sabe cuantos colores, necesito que tengas Communicator o IE4 para averiguarlo."; document.write(texto); Puede verse que antes de acceder al objeto, investigo si éste existe, mostrando un mensaje de circunstancias en caso de que no sea así. Oscar E Capuñay Uceda 89 DHTML Ficheros .js Un fichero .js es un archivo donde podremos guardar funciones y variables globales que podrán leerse desde cualquier página HTML. Gracias a ellos podremos evitar el tener que duplicar funciones que se necesiten en más de un documento. Podremos incorporarlos a nuestras páginas de esta manera: Ejemplo 27: externo.html Uso de archivos js <HTML> <HEAD> <TITLE>Mi Página</TITLE> <SCRIPT LANGUAGE="Javascript" SRC="funciones.js"> <!-alert('Error con el fichero js'); // --> </SCRIPT> </HEAD> <BODY> Lo que sea. </BODY> </HTML> El código que incluyamos entre un <SCRIPT SRC> y un </SCRIPT> sólo se ejecutará en caso de que la lectura del fichero .js falle. Por otra parte, hay que indicar que el fichero en cuestión contendrá sólo código en Javascript, no etiquetas HTML de ningún tipo, ni siquiera las de apertura y cierre de SCRIPT. Oscar E Capuñay Uceda 90 DHTML HOJAS DE ESTILO EN CASCADA CSS – Cascade Style Sheet (Hojas de Estilo en Cascada). Dentro del diseño de páginas Web, se presenta esta como la vanguardia en cuanto a definición de estilos dentro de las plantillas de diseño. A través de instrucciones en código HTML se definen los estándares del conjunto de páginas que conforman el proyecto. CSS2, como fue antes CSS1, se basa en una serie de reglas de diseño: • Compatibilidad hacia atrás y hacia adelante. Las aplicaciones del usuario CSS2 serán capaces de entender las hojas de estilo CSS1. Las aplicaciones del usuario CSS1 podrán leer las hojas de estilo CSS2 y descartar las partes que no entienden. Además, las aplicaciones del usuario que no soporten CSS serán capaces de mostrar los documentos estilísticamente mejorados. Por supuesto, el efecto estilístico hecho posible por CSS no será procesado, pero todo el contenido será presentado. • Complementariedad con documentos estructurados. Las hojas de estilo complementan los documentos estructurados (ej., HTML y aplicaciones XML) proveyendo información estilística del texto marcado. Debe ser fácil cambiar la hoja de estilo con poco o ningún impacto en el sistema de marcas. • Independencia del vendedor, la plataforma y el dispositivo. Las hojas de estilo permiten a los documentos permanecer independientes del vendedor, la plataforma y el dispositivo. Las mismas hojas de estilo son también independientes del vendedor y la plataforma, pero CSS2 permite dirigir una hoja de estilo a un grupo de dispositivos (ej., impresoras). • Mantenibilidad. Apuntando a una hoja de estilo desde los documentos, los responsables de los sitios en la Web pueden simplificar el mantenimiento y conservar un estilo y un efecto consistente a todo lo largo del sitio. Por ejemplo, si el color del fondo de las páginas de una organización cambia, sólo un archivo necesita ser cambiado. • Simplicidad. CSS2 es más compleja que CSS1, pero sigue siendo un lenguaje de estilo simple que es humanamente legible y posible de escribir. Las propiedades CSS se mantienen independientes unas de otras en la medida de lo posible y generalmente sólo hay un modo de conseguir un efecto determinado. • Rendimiento de la red. CSS proporciona una compacta codificación para presentar los contenidos. Comparado con los archivos de imágenes o de audio que son usados frecuentemente por los autores para conseguir ciertos efectos en el procesamiento, las hojas de estilo, la mayoría de las veces, disminuyen el tamaño del contenido. Además, menos conexiones de la red tienen que ser abiertas, lo cual ayuda a incrementar el rendimiento de la red. • Flexibilidad. Las CSS pueden ser aplicadas al contenido de varias maneras. La característica clave es la capacidad de formar una cascada de estilos con la información especificada en la hoja de Oscar E Capuñay Uceda 91 DHTML estilo predeterminada (aplicación del usuario), las hojas de estilo del usuario, las hojas de estilo vinculadas, el encabezamiento del documento y en los atributos de los elementos que forman el cuerpo del documento. Riqueza. Proporcionando a los autores un abundante juego de efectos de procesamiento, aumenta la riqueza de la Web como medio de expresión. Los diseñadores han estado ambicionando la funcionalidad comúnmente encontrada en los programas de edición y de presentaciones gráficas. Algunos de los efectos requeridos entran en conflicto con la independencia del dispositivo, pero CSS2 llega muy lejos satisfaciendo las demandas de los diseñadores. Combinación con lenguajes alternativos. El juego de propiedades de CSS descriptas en esta especificación conforman un sólido modelo de aplicación de formatos para presentaciones visuales y auditivas. Este modelo puede ser accedido mediante el lenguaje CSS, pero la combinación con otros lenguajes también es posible. Por ejemplo, un programa en JavaScript puede cambiar dinámicamente el valor de la propiedad 'color' de un determinado elemento. Accesibilidad. Varias características de CSS harán a la Web más accesible para los usuarios con discapacidades: Las propiedades para controlar la apariencia de las fuentes permiten a los autores eliminar las inaccesibles imágenes de texto renderizado. Las propiedades de posicionamiento permite a los autores eliminar los artilugios con el sistema de marcas (ej., imágenes invisibles) para forzar la composición. La semántica de las reglas !important indica que los usuarios con particulares requerimientos de presentación pueden suplantar las hojas de estilo del autor. El nuevo valor 'inherit' (heredado) para todas las propiedades mejora la generalidad del funcionamiento en cascada y permite una más fácil y consistente sintonía en el estilo. El avanzado soporte de medios, incluyendo grupos de medios y los tipos de medios braille, de relieve y tty permitirán a los usuarios y autores confeccionar páginas para esos dispositivos. Las propiedades auditivas ofrecen control sobre la salida de voz y audio. Los selectores de atributos, la función 'attr()' y la propiedad 'content' brindan acceso al contenido alterno. Los contadores y la numeración de secciones y párrafos pueden mejorar la navegabilidad del documento y economizar espacio de sangrado (importante en los dispositivos braille). Las propiedades 'word-spacing' y 'text-indent' también eliminan la necesidad de usar espacios en blanco extras en el documento. • • • Aquí Mostraremos cuán fácil puede ser diseñar unas simples hojas de estilo. Para esta guía, necesitará saber un poco del código HTML y alguna terminología básica de composición gráfica. Comenzamos con un pequeño documento HTML: Ejemplo 28: HTML y CSS 92 Oscar E Capuñay Uceda DHTML <HTML> <HEAD> <TITLE>La Web de OscarCap</TITLE> </HEAD> <BODY> <H1>La Web de OscarCap</H1> <P>Esta página le ayudará a diseñar páginas Web. </BODY> </HTML> Para establecer el color azul para el texto de los elementos H1, puede escribir la siguiente regla CSS: H1 { color: blue } Una regla CSS consta de dos partes principales: un selector ('H1') y una declaración ('color: blue'). La declaración tiene dos partes: una propiedad ('color') y un valor ('blue'). La especificación HTML 4.0 define de qué manera las reglas de las hojas de estilo pueden especificarse para los documentos HTML: ya sea dentro del documento HTML o a través de una hoja de estilo externa. Para poner la hoja de estilo dentro del documento, use el elemento STYLE: Ejemplo 29: Style <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <HTML> <HEAD> <TITLE> ---- La Web de OscarCap ---- </TITLE> <STYLE type="text/css"> H1 { color: blue } </STYLE> </HEAD> <BODY> <H1>La Web de OscarCap</H1> <P>Esta página Web te enseñará mucho. </BODY> </HTML> Para una mayor flexibilidad, recomiendo que los diseñadores especifiquen hojas de estilo externas; ellas pueden cambiarse sin modificar el documento fuente HTML y pueden compartirse entre varios documentos. Para vincular una hoja de estilo externa puede usar el elemento LINK: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <HTML> <HEAD> <TITLE>La Web de OscarCap</TITLE> <LINK rel="stylesheet" href="oscar.css" type="text/css"> </HEAD> <BODY> <H1>La Web de OscarCap</H1> <P> Esta página Web te enseñará mucho. Oscar E Capuñay Uceda 93 DHTML </BODY> </HTML> El elemento LINK especifica: el tipo de vínculo: a una hoja de estilo ("stylesheet"). la ubicación de la hoja de estilo a través del atributo "href". el tipo de hoja de estilo que se vincula: "text/css". Para mostrar la íntima relación entre una hoja de estilo y el sistema estructurado de marcas, continuamos usando el elemento STYLE en esta guía. Agreguemos más colores: Ejemplo 30: Colores con CSS <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <HTML> <HEAD> <TITLE> ---- La Web de OscarCap ---- </TITLE> <STYLE type="text/css"> BODY { color: red } H1 { color: blue } </STYLE> </HEAD> <BODY> <H1>La Web de OscarCap</H1> <P> Esta página Web te enseñará mucho. </BODY> </HTML> La hoja de estilo contiene ahora dos reglas: la primera establece el color del elemento BODY como 'red' , en tanto la segunda coloca el color del elemento H1 en 'blue'. Como no se ha especificado ningún valor para el color del elemento P, éste heredará el color de su elemento padre, es decir, BODY. El elemento H1 también es un elemento hijo de BODY pero la segunda regla reemplaza el valor heredado. En CSS existen a menudo tales conflictos entre diferentes valores y esta especificación describe cómo resolverlos. CSS2 tiene más de 100 propiedades diferentes, incluyendo 'color'. Veamos algunos otros: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <HTML> <HEAD> <TITLE> ---- La Web de OscarCap ---- </TITLE> <STYLE type="text/css"> BODY { font-family: "Gill Sans", sans-serif; font-size: 12pt; margin: 3em; } </STYLE> </HEAD> <BODY> Oscar E Capuñay Uceda 94 DHTML <H1>La Web de OscarCap</H1> <P> Esta página Web te enseñará mucho. </BODY> </HTML> Lo primero que se puede observar es que varias declaraciones se agrupan en un bloque encerrado por llaves ({...}) y separado por un punto y coma, no obstante la última declaración también debe estar seguida por un punto y coma. La primera declaración en el elemento BODY establece la familia de fuentes "Gill Sans". Si esa fuente no está disponible, el navegador del usuario usará la familia 'sans-serif' que es una de las cinco familias de fuentes genéricas que todas las aplicaciones del usuario reconocen. Los elementos hijos de BODY heredarán el valor de la propiedad 'font-family'. La segunda declaración establece el tamaño de la fuente del elemento BODY en 12 puntos. La unidad de medida "punto" es normalmente usada en la tipografía impresa para indicar el tamaño de la fuente y otras dimensiones. Es un ejemplo de unidad de medida absoluta que no varía según el entorno. La tercera declaración usa una unidad de medida relativa que varía de acuerdo a las circunstancias. La unidad "eme" está relacionada con el tamaño de la fuente del elemento. En este caso el resultado es que el margen alrededor del elemento BODY es tres veces mayor que el tamaño de la fuente. Sintaxis y tipos básicos de datos en CSS2 Esta sección describe una gramática (y reglas de análisis con compatibilidad futura) común a cualquier versión de CSS (incluyendo CSS2). Las futuras versiones de CSS adherirán a esta sintaxis central, aunque pueden agregar restricciones sintácticas adicionales. Comandos Todos los niveles de CSS --nivel 1, nivel 2 y cualquier futuro nivel-- usan la misma sintaxis central. Los diseñadores pueden usar esta característica para crear hojas de estilo que funcionen con aplicaciones de usuario antiguas, mientras ejercitan también las posibilidades de los niveles más nuevos de CSS. A nivel de léxico, las hojas de estilo CSS consisten de una secuencia de comandos. La lista de comandos para CSS2 es la que sigue. Las definiciones usan expresiones regulares al estilo de Lex. Los códigos octales se refieren a ISO 10646. Como en Lex, en caso de múltiples equivalencias, la equivalencia más larga determina el comando. Tabla 12. Comando CSS Comando IDENT ATKEYWORD STRING Oscar E Capuñay Uceda Definición {ident} @{ident} {string} 95 DHTML Comando HASH NUMBER PERCENTAGE DIMENSION URI UNICODERANGE CDO CDC ; { } ( ) [ ] S COMMENT FUNCTION INCLUDES DASHMATCH DELIM Definición #{name} {num} {num}% {num}{ident} url\({w}{string}{w}\) |url\({w}([!#$%&*~]|{nonascii}|{escape})*{w}\) U\+[0-9A-F?]{1,6}(-[0-9A-F]{1,6})? <!---> ; \{ \} \( \) \[ \] [ \t\r\n\f]+ \/\*[^*]*\*+([^/][^*]*\*+)*\/ {ident}\( ~= |= cualquier otro carácter no equivalente con las reglas anteriores Las macros entre llaves ({}) arriba son definidas como sigue: Tabla 13. Macros CSS Macro Ident name nmstart nonascii unicode escape Definición {nmstart}{nmchar}* {nmchar}+ [a-zA-Z]|{nonascii}|{escape} [^\0-\177] \\[0-9a-f]{1,6}[ \n\r\t\f]? {unicode}|\\[ -~\200-\4177777] nmchar [a-zA-Z0-9]|{nonascii}|{escape} [0-9]+|[0-9]*\.[0-9]+ num {string1}|{string2} string Oscar E Capuñay Uceda 96 DHTML Macro Definición string1 \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" string2 \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' \n|\r\n|\r|\f nl [ \t\r\n\f]* w Abajo está la sintaxis central para CSS. Las secciones siguientes describen cómo usarla. Tabla 14. Secciones CSS hoja de estilo estamento regla-arroba bloque regla selector declaración propiedad valor otros [ CDO | CDC | S | estamento ]*; regla | regla-arroba; ATKEYWORD S* otros* [ bloque | ';' S* ]; '{' S* [ otros | bloque | ATKEYWORD S* | ';' ]* '}' S*; selector? '{' S* declaración? [ ';' S* declaración? ]* '}' S*; otros+; propiedad ':' S* valor; IDENT S*; [ otros | bloque | ATKEYWORD S* ]+; [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES | FUNCTION | DASHMATCH | '(' otros* ')' | '[' otros* ']' ] S*; Los comandos COMMENT no aparecen en la gramática (para mantenerla legible), pero cualquier cantidad de estos comandos pueden aparecer en cualquier lugar entre otros comandos. El comando S en la gramática anterior está colocado para los espacios en blanco. Solamente los caracteres "espacio" (código 32 en Unicode), "tabulador" (9), "avance de línea" (10), "retorno de carro" (13) y "avance de hoja" (12) pueden aparecer en los espacios en blanco. Otros caracteres que producen espacios, tales como "espacio eme" (8195) y "espacio ideográfico" (12288) nunca forman parte de los espacios en blanco. Palabras clave Las palabras clave toman la forma de identificadores. Las palabras clave no deben ir entre comillas ("..." o '...'). De este modo, red es una palabra clave, pero "red" no lo es. (Es una cadena.) Otros ejemplos ilícitos: width: "auto"; border: "none"; font-family: "serif"; background: "red"; Oscar E Capuñay Uceda 97 Iniciando la programación con PHP III. Iniciando la programación con PHP Para iniciar debemos conocer algunos conceptos básicos, para ello nos haremos una pregunta: Que es PHP? PHP (acrónimo de "PHP: Hypertext Preprocessor") es un lenguaje de "código abierto" interpretado, de alto nivel, embebido en páginas HTML y ejecutado en el servidor [1]. Este lenguaje se caracteriza porque solo es interpretado pero no compilado, y es embebido en el código HTML, lo que le da una alto rendimiento y potencia. A diferencia de otros lenguajes script como JavaScript, PHP es un lenguaje script que se ejecuta en el servidor Web, de tal manera que, solamente el resultado de su ejecución es enviado al cliente Web (navegador). Tomando en cuenta lo escrito anteriormente podemos decir que, el código fuente escrito en PHP no aparecerá en el código fuente de la página Web que muestra el navegador. Viendo el lenguaje desde el punto de vista del programador podemos decir que es un lenguaje con una sintaxis similar a C; se puede usar en tres campos: el primero - el mas tradicional - es en los scripts del lado del servidor, el segundo es la ejecución de scripts en la línea de comandos del sistema operativo (Linux o Windows); y el tercero en el desarrollo de aplicaciones de interfaz gráfica con PHP-GTK. Variables Las variables en PHP pueden almacenar datos de diferentes tipos, sin necesidad de ser declaradas previamente. La sintaxis para el uso de variables esta definido por el siguiente modelo: $var , es decir, toda variable debe iniciar con el símbolo de dólar ($) y luego se escribe el nombre de la variable. Por ejemplo para hacer referencia a la variable “edad” se escribe $edad. Constantes Se puede definir una constante usando la función define(). Una vez definida, no puede ser modificada ni eliminada. Para obtener el valor de una constante solo es necesario especificar su nombre. A diferencia de las variables, no se tiene que especificar el prefijo $. Estas son las diferencias entre constantes y variables: • • • • Las constantes solo pueden ser definidas usando la función define(), nunca por simple asignación Las constantes pueden ser definidas y accedidas sin tener en cuenta las reglas de alcance del ámbito. Las constantes no pueden ser redefinidas o eliminadas después de establecerse; y Las constantes solo puede albergar valores escalares 99 Oscar E Capuñay Uceda Iniciando la programación con PHP Ejemplo 31: Definición de constantes <?php define("CONSTANT", "Desarrollo Web."); echo CONSTANT; // imprime "Desarrollo Web" ?> Tipos de datos PHP soporta ocho tipos primitivos. Cuatro tipos escalares: bolean Integer, float (número de punto-flotante, también conocido como 'double'), string Dos tipos compuestos: array, object Y finalmente dos tipos especiales: resource y NULL. Expresiones Las expresiones son la piedra angular de PHP. En PHP, casi cualquier cosa que escribes es una expresión. La forma más simple y ajustada de definir una expresión es "cualquier cosa que tiene un valor". Las formas más básicas de expresiones son las constantes y las variables. Cuando escribes "$a = 5", estás asignando '5' a $a. '5', obviamente, tiene el valor 5 ó, en otras palabras '5' es una expresión con el valor 5 (en este caso, '5' es una constante entera). Las funciones son un ejemplo algo más complejo de expresiones. Ejemplo 32: <?php function foo () { return 5; } ?> Suponiendo que estés familiarizado con el concepto de funciones, asumirás que escribir $c = foo() es esencialmente lo mismo que escribir $c = 5, y has acertado. Las funciones son expresiones que valen el valor que retornan. Como foo() devuelve 5, el valor de la expresión 'foo()' es 5. Normalmente las funciones no devuelven un valor fijo, sino que suele ser calculado. Desde luego, los valores en PHP no se limitan a enteros, y lo más normal es que no lo sean. PHP soporta tres tipos escalares: enteros, punto flotante y cadenas (los tipos escalares son aquellos cuyos valores no pueden 'dividirse' en partes menores, no como los arrays, por ejemplo). PHP también soporta dos tipos compuestos (no escalares): arrays y objetos. Se puede asignar cada uno de estos tipos de valor a variables o bien retornarse de funciones, sin ningún tipo de limitación. Considera la siguiente función Oscar E Capuñay Uceda 100 Iniciando la programación con PHP PHP lleva las expresiones mucho más allá, al igual que otros lenguajes. PHP es un lenguaje orientado a expresiones, en el sentido de que casi todo es una expresión. Considera el ejemplo anterior '$a = 5'. Es sencillo ver que hay dos valores involucrados, el valor de la constante entera '5', y el valor de $a que está siendo actualizado también a 5. Pero la verdad es que hay un valor adicional implicado aquí, y es el valor de la propia asignación. La asignación misma se evalúa al valor asignado, en este caso 5. En la práctica, quiere decir que '$a = 5', independientemente de lo que hace, es una expresión con el valor 5. De esta manera, escribir algo como '$b = ($a = 5)' es como escribir '$a = 5; $b = 5;' (un punto y coma marca el final de una instrucción). Como las asignaciones se evalúan de derecha a izquierda, puedes escribir también '$b = $a = 5'. En PHP, como en C, hay dos tipos de incremento - pre-incremento y postincremento. Ambos, en esencia, incrementan la variable y el efecto en la variable es idéntico. La diferencia radica en el valor de la propia expresión incremento. El preincremento, escrito '++$variable', se evalúa al valor incrementado (PHP incrementa la variable antes de leer su valor, de ahí el nombre 'preincremento'). El postincremento, escrito '$variable++', se evalúa al valor original de $variable antes de realizar el incremento (PHP incrementa la variable después de leer su valor, de ahí el nombre 'postincremento'). Un tipo muy corriente de expresiones son las expresiones de comparación. Estas expresiones se evalúan a 0 o 1, significando FALSO (FALSE) o VERDADERO (TRUE), respectivamente. PHP soporta > (mayor que), >= (mayor o igual que), == (igual que), != (distinto), < (menor que) y <= (menor o igual que). Estas expresiones se usan frecuentemente dentro de la ejecución condicional como la instrucción if. El último tipo de expresiones que trataremos, es la combinación operadorasignación. Ya sabes que si quieres incrementar $a en 1, basta con escribir '$a++' o ++$a'. Pero qué pasa si quieres añadir más de 1, por ejemplo 3? Podrías escribir '$a++' múltiples veces, pero no es una forma de hacerlo ni eficiente ni cómoda. Una práctica mucho más corriente es escribir '$a = $a + 3'. '$a + 3' se evalúa al valor de $a más 3, y se asigna de nuevo a $a, lo que resulta en incrementar $a en 3. En PHP, como en otros lenguajes como C, puedes escribir esto de una forma más concisa, que con el tiempo será más clara y también fácil de entender. Añadir 3 al valor actual de $a se puede escribir como '$a += 3'. Esto quiere decir exactamente "toma el valor de $a, súmale 3, y asígnalo otra vez a $a". Además de ser más corto y claro, también resulta en una ejecución más rápida. El valor de '$a += 3', como el valor de una asignación normal y corriente, es el valor asignado. Ten en cuenta que NO es 3, sino el valor combinado de $a más 3 (ése es el valor asignado a $a). Cualquier operación binaria puede ser usada en forma de operador-asignación, por ejemplo '$a -= 5' (restar 5 del valor de $a), '$b *= 7' (multiplicar el valor de $b por 7), etc. Hay otra expresión que puede parecer extraña si no la has visto en otros lenguajes, el operador condicional ternario: <?php Oscar E Capuñay Uceda 101 Iniciando la programación con PHP $first ? $second : $third ?> Si el valor de la primera subexpresión es verdadero (distinto de cero), entonces se evalúa la segunda subexpresión, si no, se evalúa la tercera y ése es el valor. El siguiente ejemplo te ayudará a comprender un poco mejor el pre y post incremento y las expresiones en general: <?php function double($i) { return $i*2; } $b = $a = 5; /* asignar el valor cinco a las variables $a y $b */ $c = $a++; /* postincremento, asignar el valor original de $a (5) a $c */ $e = $d = ++$b; /* preincremento, asignar el valor incrementado de $b (6) a $d y a $e */ /* En este punto, tanto $d como $e son iguales a 6 */ $f = double($d++); /* asignar el doble del valor de $d antes del incremento, 2*6 = 12 a $f */ $g = double(++$e); /* asignar el doble del valor de $e después del incremento, 2*7 = 14 a $g */ $h = $g += 10; /* primero, $g es incrementado en 10 y termina valiendo 24. Después el valor de la asignación (24) se asigna a $h, y $h también acaba valiendo 24. */ ?> No todas las expresiones son instrucciones. En este caso, una instrucción tiene la forma 'expr' ';', es decir, una expresión seguida de un punto y coma. En '$b=$a=5;', $a=5 es una expresión válida, pero no es una instrucción en sí misma. Por otro lado '$b=$a=5:' sí es una instrucción válida [3]. Operadores Un operador es algo a lo recibe uno o más valores y produce otro valor. Existen tres tipos de operadores: El operador unario, el cual opera sobre un único valor, por ejemplo: ! (operador de negación) o ++ (operador de incremento). Segundo, los operadores binarios; este grupo contiene la mayoría de operadores que soporta PHP. Y el operador ternario: ?:. Éste debe ser usado para seleccionar entre dos expresiones, en base a una tercera, en lugar de seleccionar dos sentencias o rutas de ejecución. Rodear las expresiones ternarias con paréntesis es una muy buena idea. [4] Existen varios tipos de operadores, a continuación veremos algunas clases: Oscar E Capuñay Uceda 102 Iniciando la programación con PHP Operadores de Aritmética Tabla 15. Operadores aritméticos de PHP Ejemplo -$a $a + $b $a - $b $a * $b $a / $b $a % $b Operador Negación Adición Substracción Multiplicación División Módulo Resultado El opuesto de $a Suma de $a y $b. Diferencia entre $a y $b. Producto de $a y $b. Cociente de $a y $b. Resto de $a dividido por $b. El operador de división ("/") devuelve un valor flotante en todos los casos, incluso si los dos operandos son enteros (o cadenas que son convertidas a enteros). Nota: El resto de $a % $b es negativo para valores negativos de $a. Operadores de Asignación El operador básico de asignación es "=". A primera vista, usted podría pensar en él como "es igual a". No lo haga. Lo que quiere decir en realidad es que el operando de la izquierda recibe el valor de la expresión a la derecha (es decir, "se define a"). El valor de una expresión de asignación es el valor que se asigna. Es decir, el valor de "$a = 3" es 3. Ejemplo 33: Operador de asignación <?php $a = ($b = 4) + 5; // $a es igual a 9 ahora, y $b ha sido definido a 4. ?> En conjunto con el operador básico de asignación, existen "operadores combinados" para todos los operadores de aritmética binaria, unión de matrices y de cadenas, que le permiten usar un valor en una expresión y luego definir su valor como el resultado de esa expresión. Ejemplo 34: Operadores de asignación combinados <?php $a = 3; $a += 5; // define $a como 8, como si hubiésemos dicho: $a = $a + 5; $b = "¡Hola "; $b .= "a todos!"; // (Ojo con el punto “.” Después de la variable $b) define $b como "¡Hola a todos!", tal como $b = $b . "a todos!"; ?> Note que la asignación copia la variable original en la nueva (asignación por valor), de modo que cualquier cambio a una no afecta a la otra. Esto puede resultar de importancia si necesita copiar algo como una matriz de gran Oscar E Capuñay Uceda 103 Iniciando la programación con PHP tamaño al interior de un ciclo reducido. A partir de PHP4, es soportada la asignación por referencia, usando la sintaxis $var = &$otra_var;, pero esto no es posible en PHP3. Operadores de Comparación Estos operadores permiten comparar dos valores y son los siguientes: Tabla 16. Operadores de comparación de PHP Ejemplo $a == $b $a === $b $a != $b $a <> $b $a !== $b $a < $b $a > $b $a <= $b $a >= $b Operador Igual Idéntico Diferente Diferente No idénticos Menor que Mayor que Menor o igual que Mayor o igual que Resultado TRUE si $a es igual a $b. TRUE si $a es igual a $b, y son del mismo tipo. TRUE si $a no es igual a $b. TRUE si $a no es igual a $b. TRUE si $a no es igual a $b, o si no son del mismo tipo. TRUE si $a es estrictamente menor que $b. TRUE si $a es estrictamente mayor que $b. TRUE si $a es menor o igual que $b. TRUE si $a es mayor o igual que $b. Si compara un entero con una cadena, la cadena es convertida a un número. Si compara dos cadenas numéricas, ellas son comparadas como enteros. Estas reglas también se aplican a la sentencia switch. <?php var_dump(0 == "a"); // 0 == 0 -> true var_dump("1" == "01"); // 1 == 1 -> true switch ("a") { case 0: echo "0"; break; case "a": // nunca se ejecuta ya que "a" ya ha coincidido con 0 echo "a"; break; } ?> Operador Ternario Otro operador condicional es el operador "?:" (o ternario). Ejemplo 35: <?php Oscar E Capuñay Uceda 104 Operador ternario Iniciando la programación con PHP // Ejemplo de uso de: el Operador Ternario $accion = (empty($_POST['accion'])) ? 'predeterminada' : $_POST['accion']; // La línea anterior es idéntica a esta sentencia if/else if (empty($_POST['accion'])) { $accion = 'predeterminada'; } else { $accion = $_POST['accion']; } ?> La expresión (expr1) ? (expr2) : (expr3) evalúa a expr2 si expr1 evalúa a TRUE, y expr3 si expr1 evalúa a FALSE. Nota: Por favor note que el operador ternario es una sentencia, y que no evalúa a una variable, sino al resultado de una sentencia. Es importante saber esto si se desea devolver una variable por referencia. La sentencia: return $var == 42 ? $a : $b; en una función con retorno-por-referencia no funcionará por lo que se ha mencionado y una advertencia es generada en versiones posteriores de PHP. Nota: Es recomendable que evite "apilar" las expresiones ternarias. El comportamiento de PHP cuando se usa más de un operador ternario al interior de una sentencia no es obvio: Ejemplo 36: Comportamiento Ternario No-Obvio <?php // a primera vista, lo siguiente parece imprimir 'true' echo (true?'true':false?'t':'f'); // sin embargo, la salida real de la línea anterior es 't' // esto se debe a que las expresiones ternarias // son evaluadas de izquierda a derecha // la siguiente es una versión más obvia del código // presentado anteriormente echo ((true ? 'true' : 'false') ? 't' : 'f'); // aquí puede ver que la primera expresión // es evaluada como 'true', la cual // en su lugar evalúa a (bool)true, devolviendo por lo tanto // la rama de verdad de la segunda expresión ternaria. ?> Operadores de Control de Errores PHP ofrece soporte para un operador de control de errores: el signo de arroba (@). Cuando es colocado al comienzo de una expresión en PHP, cualquier mensaje de error que pudiera generarse a causa de esa expresión será ignorado. Oscar E Capuñay Uceda 105 Iniciando la programación con PHP Si la característica track_errors está habilitada, cualquier mensaje de error generado por la expresión será almacenado en la variable $php_errormsg. La variable será sobrescrita en cada instancia de error, así que realice sus chequeos de forma temprana si quiere usarla. Ejemplo 37: Control de errores <?php /* Error intencional de archivo */ $mi_archivo = @file ('archivo_que_no_existe') or die ("La apertura de archivo ha fallado: el error fue '$php_errormsg'"); // esto funciona con cualquier expresión, no solo con funciones: $valor = @$cache[$llave]; // no producirá una anotación si el índice $llave no existe. ?> Nota: El operador @ trabaja sólo sobre expresiones. Una simple regla de oro es: si usted puede tomar el valor de algo, entonces puede usar el operador @ sobre ese algo. Por ejemplo, puede usarlo al inicio de variables, llamadas a funciones y sencencias include(), constantes, y así sucesivamente. No puede usarlo sobre definiciones de función o clase, ni sobre estructuras condicionales como if y foreach, y así sucesivamente. Operadores de ejecución PHP soporta un operador de ejecución: las comillas invertidas (``). PHP ejecuta el contenido entre las comillas como si se tratara de un comando del intérprete de comandos; su salida será devuelta (puede ser asignada a una variable).El uso del operador de comillas invertidas es idéntico al de shell_exec(). Ejemplo 38: Operador de ejecución <?php $salida = `dir *.*`; echo "<pre>$salida</pre>"; ?> Nota: El operador de comillas invertidas es deshabilitado cuando se encuentra activo safe mode o cuando se deshabilita shell_exec(). Operadores de Incremento/Decremento PHP ofrece soporte de operadores de pre- y post-incremento y decremento, estilo lenguaje C. Nota: Los operadores de incremento/decremento no afectan a los valores booleanos. Decrementar valores NULL tampoco tiene efecto, aunque incrementarlos resulta en 1. Tabla 17. Operadores de incremento y decremento de PHP Ejemplo Operador Efecto 106 Oscar E Capuñay Uceda Iniciando la programación con PHP ++$a $a++ --$a $a-Pre-incremento Post-incremento Pre-decremento Post-decremento Incrementa $a en uno, y luego devuelve $a. Devuelve $a, y luego incrementa $a en uno. Decrementa $a en uno, luego devuelve $a. Devuelve $a, luego decrementa $a en uno. Ejemplo 39: Operadores de incremento y decremento <?php echo "<h3>Postincremento</h3>"; $a = 5; echo "Debe ser 5: " . $a++ . "<br />\n"; echo "Debe ser 6: " . $a . "<br />\n"; echo "<h3>Preincremento</h3>"; $a = 5; echo "Debe ser 6: " . ++$a . "<br />\n"; echo "Debe ser 6: " . $a . "<br />\n"; echo "<h3>Postdecremento</h3>"; $a = 5; echo "Debe ser 5: " . $a-- . "<br />\n"; echo "Debe ser 4: " . $a . "<br />\n"; echo "<h3>Predecremento</h3>"; $a = 5; echo "Debe ser 4: " . --$a . "<br />\n"; echo "Debe ser 4: " . $a . "<br />\n"; ?> Note como se trabaja los incrementos y decrementos sobre variables de caracter. Ejemplo 40: Incremento y decremento con variables tipo carácter. operadores_i.php <?php $i = 'W'; for ($n=0; $n<6; $n++) { echo ++$i . "\n"; } ?> Resultado Web: Oscar E Capuñay Uceda 107 Iniciando la programación con PHP Figura 49. Resultado de operadores_i.php Nota: Los operadores de incremento/decremento no afectan a los valores booleanos. Decrementar valores NULL tampoco tiene efecto, aunque incrementarlos resulta en 1. Operadores de Lógica Tabla 18. Operadores lógicos Ejemplo $a and $b $a && $b $a or $b $a || $b $a xor $b ! $a Operador Y O O exclusivo (Xor) Negación Resultado TRUE si tanto $a como $b son TRUE. TRUE si cualquiera de $a o $b es TRUE. TRUE si $a o $b es TRUE, pero no ambos. TRUE si $a no es TRUE. La razón para tener las dos variaciones diferentes de los operadores "and" y "or" es que ellos operan con precedencias diferentes. Para el caso de "and": "&&" tiene mayor precedencia que "and", analógicamente ocurre con "or". Operadores de Cadena Existen dos operadores para datos tipo string. El primero es el operador de concatenación ('.'), el cual devuelve el resultado de concatenar sus argumentas a lado derecho e izquierdo. El segundo es el operador de asignación sobre concatenación ('.='), el cual adiciona el argumento del lado derecho al argumento en el lado izquierdo. Ejemplo 41: Operadores de cadena <?php $a = "¡Hola "; $b = $a . "Mundo!"; // ahora $b contiene "¡Hola Mundo!" $a = "¡Hola "; $a .= "Mundo!"; ?> // ahora $a contiene "¡Hola Mundo!" Oscar E Capuñay Uceda 108 Iniciando la programación con PHP Operadores de Matrices Tabla 19. Operadores de matrices Ejemplo $a + $b $a == $b $a === $b Operador Unión Igualdad Identidad $a != $b $a <> $b $a !== $b No-igualdad No-igualdad No-identidad Resultado Unión de $a y $b. TRUE si $a y $b tienen las mismas parejas llave/valor. TRUE si $a y $b tienen las mismas parejas llave/valor en el mismo orden y de los mismos tipos. TRUE si $a no es igual a $b. TRUE si $a no es igual a $b. TRUE si $a no es idéntico a $b. El operador + adiciona la matriz del lado derecho a aquél al lado izquierdo, al mismo tiempo que cualquier llave duplicada NO es sobrescrita. Ejemplo 42: Operadores de matrices operadores_m.php <?php $a = array("a" => "manzana", "b" => "banano"); $b = array("a" => "pera", "b" => "fresa", "c" => "cereza"); $c = $a + $b; // Unión de $a y $b echo "<br>Unión de \$a y \$b: <br>"; var_dump($c); $c = $b + $a; // Unión de $b y $a echo "<br>Unión de \$b y \$a: <br>"; var_dump($c); ?> Resultado Web: Figura 50. Resultado de operadores_m.php Oscar E Capuñay Uceda 109 Iniciando la programación con PHP Los elementos de las matrices son considerados equivalentes en la comparación si éstos tienen la misma clave y valor. Ejemplo 43: Comparación de matrices comp_matrices.php <?php $a = array("manzana", "plátano"); $b = array(1 => "plátano", "0" => "manzana"); var_dump($a == $b); // bool(true) var_dump($a === $b); // bool(false) ?> Resultado Web: Figura 51. Resultado de comp_matrices.php Operadores de Tipo instanceof es usado para determinar si una variable PHP es una instancia de objeto de cierta clase: Ejemplo 44: instanciade.php <?php class MiClase { } class NoMiClase { } $a = new MiClase; var_dump($a instanceof MiClase); var_dump($a instanceof NoMiClase); ?> Resultado Web: Uso de instanceof con clases Oscar E Capuñay Uceda 110 Iniciando la programación con PHP Figura 52. Resultado de instanciade.php instanceof puede ser usado también para determinar si una variable es una instancia de objeto de una clase que hereda de una clase padre: Ejemplo 45: Uso de instanceof con clases heredadas instanciadehe.php <?php class ClasePadre { } class MiClase extends ClasePadre { } $a = new MiClase; var_dump($a instanceof MiClase); var_dump($a instanceof ClasePadre); ?> Resultado Web: Figura 53. Resultado de instanciadehe.php Por último, instanceof puede ser usado también para determinar si una variable es una instancia de objeto de una clase que implementa una interfaz: Ejemplo 46: Uso de instanceof para una clase <?php interface MiInterfaz { } class MiClase implements MiInterfaz { } Oscar E Capuñay Uceda 111 Iniciando la programación con PHP $a = new MiClase; var_dump($a instanceof MiClase); var_dump($a instanceof MiInterfaz); ?> El resultado del ejemplo seria: bool(true) bool(true) Aunque instanceof es usado por lo general con un nombre de clase literal, también puede usarse con otro objeto o una variable tipo cadena: Ejemplo 47: Uso de instanceof con otras variables <?php interface MiInterfaz { } class MiClase implements MiInterfaz { } $a = new MiClase; $b = new MiClase; $c = 'MiClase'; $d = 'NoMiClase'; var_dump($a instanceof $b); // $b es un objeto de la clase MiClase var_dump($a instanceof $c); // $c es una cadena 'MiClase' var_dump($a instanceof $d); // $d es una cadena 'NoMiClase' ?> El resultado del ejemplo sería: bool(true) bool(true) bool(false) El operador instanceof fue introducido en PHP 5. Anteriormente is_a() era usado, pero desde entonces is_a() ha sido marcada como función obsoleta, prefiriéndose el uso de instanceof. Oscar E Capuñay Uceda 112 Estructuras de Control IV. Estructuras de Control Una sentencia puede ser una asignación, una llamada a función, un bucle, una sentencia condicional e incluso una sentencia que no haga nada (una sentencia vacía). Las sentencias normalmente acaban con punto y coma. Además, las sentencias pueden estar compuestas por un grupo de sentencias delimitadas con llaves. Un grupo de sentencias es también una sentencia. En este capítulo veremos diferentes tipos de sentencias. Iniciaremos viendo las sentencias condicionales: Si (condicional): if Permite la ejecución condicional de ordenes o comandos, tomando como base el resultado de una o varias condiciones. La sentencia if en PHP tiene la misma sintaxis básica utilizada en el lenguaje C. <?php if (expresión condicional) { Sentencia(s) cuando la expresión es verdadera } ?> Ejemplo 48: If ejecuta una sentencia si la condición es verdadera <?php if ($a > $b) print "a es mayor que b"; ?> El ejemplo mostraría “a es mayor que b” si la variable $a fuera mayor que $b. El uso de las llaves es para la ejecución de un conjunto de sentencias. Ejemplo 49: If con varias sentencias si la condición es verdadera <?php if ($a > $b) { echo "a es mayor que b"; $mayor = $a; $menor = $b; } ?> Las sentencias if se pueden anidar indefinidamente dentro de otras. Oscar E Capuñay Uceda 113 Estructuras de Control Ejemplo 50: If anidado <?php If ( $a > $b ) If ( $a % $c == 0 ) { echo “a es múltiplo y mayor que b”; $mayor = $a; } } ?> Else La sentencia else es un complemento de if debido que muchas veces queremos indicar la ejecución de sentencias en caso la expresión condicional del if resulte falsa. Ejemplo 51: Uso de else en una sentencia if <?php if ($a > $b) { echo "a es mayor que b"; } else { echo "a NO es mayor que b"; } ?> elseif También se puede escribir else if (con espacio entre las palabras). elseif es una combinación de if y else. En caso la sentencia condicional resulte falsa, y existan varios casos que puedan cumplirse se puede usar elseif para cada uno de dichos casos. Ejemplo 52: Uso de elseif <?php if ($a > $b) { echo "a es mayor que b"; } elseif ($a < $b) { echo "a es menor que b"; } else { echo "a es igual que b"; } ?> Puede haber varios elseifs dentro de la misma sentencia if. La primera expresión elseif (si hay alguna) que resulte verdadera se ejecuta. La sentencia elseif se ejecuta sólo si la expresión if precedente y cualquier expresión elseif precedente se resulta falsa. Oscar E Capuñay Uceda 114 Estructuras de Control for Los bucles for son los bucles más complejos en PHP. Su comportamiento y sintaxis es similar a la definida en el lenguaje C. for (expr1; expr2; expr3) sentencia La primera expresión (expr1) se ejecuta una vez al principio del bucle. Al comienzo de cada iteración, se evalúa expr2. Si resulta verdadera, el bucle continúa y las sentencias anidadas se ejecutan. Si resulta falsa, la ejecución del bucle finaliza. Al final de cada iteración, se ejecuta expr3. Ejemplo 53: Imprimir los números del 1 al 10 utilizando la sentencia for <?php for ($i = 1; $i <= 10; $i++) { print $i; } while Los bucles while son los tipos de bucle más simples en PHP. Se comportan como su contrapartida en C. La forma clásica de una sentencia while es: while (expr) { Sentencias } Como con la sentencia if, se pueden agrupar multiples sentencias dentro del mismo bucle while encerrando un grupo de sentencias con llaves, o usando la sintaxis alternativa: while (expr): sentencia ... endwhile; do..while Los bucles do..while son muy similares a los bucles while, excepto que las condiciones se comprueban al final de cada iteración en vez de al principio. La principal diferencia frente a los bucles regulares while es que se garantiza la ejecución de la primera iteración de un bucle do..while (la condición se comprueba sólo al final de la iteración), mientras que puede no ser necesariamente ejecutada con un bucle while regular (la condición se comprueba al principio de cada iteración, si esta se evalúa como FALSE desde el principio la ejecución del bucle finalizará inmediatamente). Hay una sola sintaxis para los bucles do..while: Oscar E Capuñay Uceda 115 Estructuras de Control Ejemplo 54: <?php $i = 0; do { print $i; } while ($i>0); ?> El bucle de arriba se ejecutaría exactamente una sola vez, después de la primera iteración, cuando la condición se comprueba, se evalúa como FALSE ($i no es más grande que 0) y la ejecución del bucle finaliza. Imprimir los números del 1 al 10 utilizando while Oscar E Capuñay Uceda 116 Acceso a Datos con PHP V. Acceso a Datos con PHP Lo primero que tenemos que aprender es como insertar código PHP en el documento HTML. En HTML se trabaja en base a marcas, las cuales tienen la siguiente forma <ETIQUETA> </ETIQUETA>. Debido a esto, hay que indicar dentro del conjunto de etiquetas que componen el documento Web el inicio y fin del código PHP insertado, para ello hay que utilizar los siguientes símbolos: Para iniciar PHP: <?php Para finalizar PHP: ?> Ejemplo 55: Pagina01.php <HTML> <HEAD> <TITLE> Primer Ejemplo PHP </TITLE> </HEAD> <BODY> El siguiente código imprime “Hipertext Preprocessor”<BR> <?php echo "Hipertext Preprocessor"; ?> </BODY> </HTML> Cuando un cliente Web (navegador o browser) hace una solicitud a un servidor Web, éste ubica el archivo solicitado y verifica si contiene código PHP o no, en caso que sólo sea HTML, el archivo es enviado directamente al cliente, pero en caso que tenga código PHP es enviado a ser procesado el documento que ha sido solicitado para ser procesado y luego enviar el resultado del procesamiento al cliente. Según el ejemplo anterior, el documento sería enviado a ser procesado, en este proceso se interpretaría las líneas de código y después el resultado sería enviado al cliente. A continuación veremos el resultado de la solicitud y procesamiento de la página programada anteriormente (pagina01.php). Pagina01.php <HTML> <HEAD> <TITLE> Primer Ejemplo PHP </TITLE> </HEAD> <BODY> El siguiente código imprime “Hipertext Preprocessor”<BR> Hipertext Preprocessor Oscar E Capuñay Uceda 117 Acceso a Datos con PHP </BODY> </HTML> Este código resultante es interpretado en el navegador y se visualiza de la siguiente como aparece en la figura 28. Figura 54. Resultado de pagina01.php Existen otras maneras de insertar código PHP en el documento HTML, por ejemplo: 1.- <? echo ("esta es la más simple, una instrucción de procesado SGML \n"); ?> <?= expression ?> Esto es una abreviatura de "<? echo expression ?>" 2.- <script language="php"> echo ("muchos editores (como FrontPage) no aceptan instrucciones de procesado"); </script> 3.- <% echo ("Opcionalmente, puedes usar las etiquetas ASP"); %> <%= $variable; # Esto es una abreviatura de "<% echo . . ." %> El método uno, no siempre está disponible. El formato corto de etiquetas está disponible con la función short_tags() (sólo PHP 3), activando el parámetro del fichero de configuración de PHP short_open_tag, o compilando PHP con la opción --enable-short-tags del comando configure. Aunque esté activa por defecto en php.ini-dist, no se aconseja el uso del formato de etiquetas corto. El método tres sólo está disponible si se han activado las etiquetas ASP en el fichero de configuración: asp_tags. Nota: No se debe usar el formato corto de etiquetas cuando se desarrollen aplicaciones o bibliotecas con intención de redistribuirlas, o cuando se desarrolle para servidores que no están bajo nuestro control, porque puede ser que el formato corto de etiquetas no esté soportado en el servidor. Para generar código portable y redistribuíble, asegúrate de no usar el formato corto de etiquetas. Oscar E Capuñay Uceda 118 Acceso a Datos con PHP La etiqueta de fin de bloque incluirá tras ella la siguiente línea si hay alguna presente. Además, la etiqueta de fin de bloque lleva implícito el punto y coma; no necesitas por lo tanto añadir el punto y coma final de la última línea del bloque PHP. En el desarrollo de software son muy importantes los comentarios en los scripts, en el caso de PHP, los comentarios tienen la siguiente sintaxis: • Cuando es un comentario de una línea se usa: // • Cunado un comentarios es de varias líneas, se delimita el comentario utilizando: /* y */ Ejemplo 56: Comentarios <?php // Este es un ejemplo de una línea /* Este es otro ejemplo, pero tiene varias líneas comentadas */ ?> Ejemplo 57: pagina02.php <HTML> <HEAD> <TITLE> Ejemplo de la sentencia if </TITLE> </HEAD> <BODY> El siguiente código utiliza la sentencia if de php<BR> <?php $nota=12; if($nota>=10.5) echo "<em>Felicitaciones<em>, Ud. obtuvo el calificativo de <strong>$nota</strong> (APROBADO)"; else echo "Ud. obtuvo el calificativo de <strong>$nota</strong> (DESAPROBADO)"; ?> </BODY> </HTML> Ejemplo 58: pagina03.php <HTML> Oscar E Capuñay Uceda 119 Sentencia if (1) Sentencia if (2) Acceso a Datos con PHP <HEAD> <TITLE> Ejemplo de la sentencia if </TITLE> </HEAD> <BODY> El siguiente código utiliza la sentencia if de php<BR> <?php $nota=12; if($nota>=10.5) { echo "<em>Felicitaciones<em>, Ud. obtuvo el calificativo de <strong>".$nota."</strong> (APROBADO)"; } else { echo "Ud. obtuvo el calificativo de <strong>".$nota."</strong> (DESAPROBADO)"; } ?> </BODY> </HTML> Ejemplo 59: pagina04.php <HTML> <HEAD> <TITLE> Ejemplo de la sentencia if </TITLE> </HEAD> <BODY> El siguiente código utiliza la sentencia if de php<BR> <?php $nota=12; if($nota>=10.5) { ?> <em>Felicitaciones<em>, Ud. obtuvo el calificativo de <strong><?php echo $nota ?></strong> (APROBADO) <?php } else { ?> Ud. obtuvo el calificativo de <strong><?php echo $nota ?></strong> (DESAPROBADO) <?php } ?> </BODY> </HTML> Todos los ejemplos de la sentencia if generan la siguiente salida Web. Sentencia if (3) Oscar E Capuñay Uceda 120 Acceso a Datos con PHP Figura 55. Resultado de pagina04.php Ahora veamos el uso de la sentencia for para la generación de tablas html. En este primer ejemplo generamos una tabla con una columna y n filas. Ejemplo 60: Pagina05.php <HTML> <HEAD> <TITLE> Ejemplo de la sentencia for </TITLE> </HEAD> <BODY> Uso de la sentencia for de php<BR> <?php $filas=15; echo "<table border=\"1\">"; //iniciamos la tabla for($i=1;$i<=$filas;$i++) //creamos varias filas con el for { echo "<tr><td>$i</td><tr>"; // escribir fila con el valor de: i } echo "</table>"; //cerramos la tabla ?> </BODY> </HTML> Resultado Web Sentencia for (1) Oscar E Capuñay Uceda 121 Acceso a Datos con PHP Figura 56. Resultado de pagina05.php Ejemplo 61: pagina06.php <HTML> <HEAD><TITLE> Ejemplo de la sentencia for </TITLE></HEAD> <BODY> Uso de la sentencia for de php<BR> <?php $filas=15; $columnas=5; echo "<table border=\"1\">"; //iniciamos la tabla for($i=1;$i<=$filas;$i++) //creamos varias filas con el for { echo "<tr>"; // crear fila for($j=1;$j<=$columnas;$j++) { echo "<td>$i $j</td>"; //escribir columnas (celdas) } echo "<tr>"; // terminar la fila } echo "</table>"; //cerramos la tabla ?> </BODY> </HTML> Oscar E Capuñay Uceda 122 Sentencia for (2) Acceso a Datos con PHP Resultado Web Figura 57. Resultado de pagina06.php Ejemplo 62: Sentencia for (3) Con el siguiente código obtenemos la tabla del ejemplo anterior. pagina07.php <HTML> <HEAD><TITLE> Ejemplo de la sentencia for </TITLE></HEAD> <BODY> Uso de la sentencia for de php<BR> <?php $filas=15; $columnas=5; ?> <table border="1"> <?php for($i=1;$i<=$filas;$i++) //creamos varias filas con el for { ?> <tr> <?php for($j=1;$j<=$columnas;$j++) { ?> <td><?php echo "$i $j" ?></td> <?php } ?> <tr> <?php } ?> </table> </BODY> Oscar E Capuñay Uceda 123 Acceso a Datos con PHP </HTML> La mayor parte de aplicaciones Web suelen trabajar con PHP utilizando variables y objetos ingresados por los usuarios a través de formularios HTML. Formularios HTML y PHP Veamos un ejemplo sencillo en el que se envían datos a una página PHP utilizando los métodos POST y GET, respectivamente. Ejemplo 63: Envío de datos de un formulario a una página PHP formulario01.html <html> <head> <title>Formulario</title> </head> <body> <form name="form1" method="post" action="pagina08.php"> Ingresa tu nombre <input name="txtnombre" type="text" id="txtnombre"> <input type="submit" name="Submit" value="Enviar"> </form> </body> </html> En la etiqueta form, en su propiedad action, especificamos el destino de los datos, es decir, la página PHP que recibirá los datos del formulario. En este caso pagina08.php, y no olvidemos que en el método estamos especificando POST. Además debemos tomar en cuenta el nombre del objeto (caja de texto – input tipo text) “txtnombre”, pues será en nombre que usaremos en la página de destino. pagina08.php <HTML> <HEAD><TITLE> Ejemplo de envio de datos</TITLE></HEAD> <BODY> Tu nombre es: <?php echo $_POST[txtnombre]; ?> </table> </BODY> </HTML> En esta página podemos ver que usamos el array $_POST de PHP para acceder a los datos enviados a través de este método. Tambien podemos Oscar E Capuñay Uceda 124 Acceso a Datos con PHP observar que en la barra de dirección no aparece ninguna variable, solamente el nombre de la página PHP. Resultado Web Figura 58. Resultado de formulario01.html Figura 59. Resultado de pagina08.php Ahora veamos como sería este ejemplo utilizando el método GET. Formulario02.html <html> <head> <title>Formulario</title> </head> <body> <form name="form1" method="get" action="pagina09.php"> Ingresa tu nombre <input name="txtnombre" type="text" id="txtnombre"> <input type="submit" name="Submit" value="Enviar"> </form> </body> </html> pagina09.php <HTML> <HEAD><TITLE> Ejemplo de envio de datos</TITLE></HEAD> <BODY> Tu nombre es: <?php Oscar E Capuñay Uceda 125 Acceso a Datos con PHP echo $_GET[txtnombre]; ?> </table> </BODY> </HTML> Resultado Web: Figura 60. Resultado de formulario02.html Figura 61. Resultado de pagina09.php Figura 62. URL incluyendo datos enviados En la figura 36 podemos ver en la barra de dirección los datos enviados a través del método GET, por lo que debemos utilizar el array $_GET de PHP para acceder a ellos. Ahora utilizaremos algunos objetos adicionales en el formulario, tipo INPUT: checkbox, radio, y hidden. formulario03.html <html> <head> Oscar E Capuñay Uceda 126 Acceso a Datos con PHP <title>Formulario</title> </head> <body> <form name="form1" method="post" action="pagina10.php"> <input type="hidden" name="oculto" value="XYZ"> <table width="90%" border="0"> <tr> <td>Temas de interés: <input name="tema[]" type="checkbox" id="tema[]" value="red">Redes de computadoras <input name="tema[]" type="checkbox" id="tema[]" value="web">World Wide Web <input name="tema[]" type="checkbox" id="tema[]" value="seguridad">Seguridad Informática</td> </tr> <tr> <td>Sexo: <input name="sexo" type="radio" value="M"> Masculino <input name="sexo" type="radio" value="F"> Femenino</td> </tr> <tr> <th><input type="submit" name="Submit" value="Enviar"></th> </tr> </table> </form> </body> </html> En esta página encontramos tres objetos checkbox que tienen el mismo nombre y que serán enviados como array de datos al archivo pagina10.php, pero cada uno de ellos tiene un valor distinto para poder diferenciarlos. Cuando estos objetos lleguen a su destino solo podremos leer los valores de aquellos objetos que fueron chequeados. En el caso de los botones de opción pasa algo similar pero esta técnica siempre la utilizo pues nos sirve para agrupar radio-botones (botones de opción). Resultado Web: Figura 63. Resultado de formulario03.html Oscar E Capuñay Uceda 127 Acceso a Datos con PHP Al presionar el botón “Enviar” enviamos los datos del formulario al archivo: pagina10.php que se detalla a continuación: pagina10.php <HTML> <HEAD><TITLE> Ejemplo de envio de datos</TITLE></HEAD> <BODY> El valor del objeto oculto es: <?php echo $_POST[oculto]?><br> El sexo seleccionado: <?php echo $_POST[sexo]?><br> Los temas seleccionados son:<br> <?php if(count($_POST[tema])>0) { foreach($_POST[tema] as $k => $v) { echo "- ".$v."<br>"; } } else { echo "(No hay temas seleccionados)"; } ?> </table> </BODY> </HTML> En este script podemos encontrar la función “count”, esta función permite determinar la cantidad de elementos que tiene un array de datos, en este caso, el array $_POST[tema]. También encontramos la sentencia “foreach” que sirve para recorrer un array de datos, extrayendo sus elementos: índice y valor, que en el script están representados por $k y $v respectivamente. El resultado del procesamiento del archivo pagina10.php es: Figura 64. Resultado de pagina10.php Segundo caso: aquí observamos que no hay tema seleccionado. Oscar E Capuñay Uceda 128 Acceso a Datos con PHP Figura 65. Resultado de formulario03.html (segundo caso) Figura 66. Resultado de pagina10.php (segundo caso) Subiendo archivos al servidor En muchas aplicaciones Web es necesario enviar o subir archivos al servidor Web, es por ello que veremos a continuación el procedimiento que nos permita realizar esta tarea sin ningún problema. Figura 67. Resultado de formulario04.html Ejemplo 64: Subir un archivo al servidor Web formulario04.html <html> <head> Oscar E Capuñay Uceda 129 Acceso a Datos con PHP <title>Subir archivos</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body> <form action="pagina11.php" method="post" enctype="multipart/form-data" name="form1"> Seleccione un archivo <input type="file" name="archivo" size="50"> <input type="submit" name="Submit" value="Enviar"> </form> </body> </html> Figura 68. Selección de un archivo en un formulario Es muy importante indicar en el formulario la propiedad enctype para el envío de datos, tal y como lo apreciamos en el código anterior (formulario04.html): enctype="multipart/form-data". En este formulario seleccionamos el archivo que deseamos subir y luego presionamos el botón “Enviar”. pagina11.php <?php //leyendo los datos del archivo recibido $nombre_real=$_FILES[archivo][name]; $tamano=$_FILES[archivo][size]; $tipo=$_FILES[archivo][type]; //este es el nombre que tiene el archivo cuando llega al server $nombre_temporal=$_FILES[archivo][tmp_name]; //imprimimos los datos echo "Archivo: " . $nombre_real . " - Tipo:" . $tipo . " Tamaño:" . $tamano . " - Temporal:" . $nombre_temporal . "<br>"; //movemos el archivo al directorio destino. $carpeta="archivos"; $destino=$carpeta."\\".$nombre_real; if(move_uploaded_file ($nombre_temporal,$destino)) echo "archivo subido exitosamente"; else echo "El archivo no logró subir al servidor"; ?> En el script podemos ver que debemos recibir los datos del archivo a través del array $_FILES[], indicando el nombre del objeto HTML que insertamos en Oscar E Capuñay Uceda 130 Acceso a Datos con PHP el formulario y luego en la siguiente dimensión del array especificamos el dato que queremos leer. La función move_uploaded_file, realiza un chequeo para asegurar que el archivo $nombre_temporal sea un archivo cargado válido (lo que quiere decir que fue cargado a través del mecanismo de carga HTTP POST de PHP). Si el archivo es válido, será movido al nombre de archivo dado por $destino. Si $nombre_temporal no es un archivo cargado válido, entonces no se tomará ninguna acción, y move_uploaded_file() devolverá FALSE, de lo contrario devolverá TRUE. Figura 69. Datos de un archivo enviado al servidor Oscar E Capuñay Uceda 131 Acceso a Datos con PHP Acceso a Bases de Datos Para aprender a acceder a una base de datos tomaremos como manejador de base de datos a MySQL. Creando una base de datos MySQL en MySQL Administrator Crearemos paso a paso la base de datos dbdemo y una tabla llamada persona. Primero abrimos MySQL Administrator e ingresamos los datos solicitados. Figura 70. Conexión al servidor MySQL con MySQL Administrador Figura 71. Inicio de MySQL Administrator Oscar E Capuñay Uceda 132 Acceso a Datos con PHP Luego hacemos clic con el botón derecho del Mouse sobre una de las bases de datos para crear una nueva seleccionando “Create New Schema”. Figura 72. Menú de MySQL Administrator Demos escribir el nombre de la nueva base de datos y presionar “OK”. Figura 73. Creando una base de datos Una vez que presionamos “OK” tenemos creada la base de datos. Oscar E Capuñay Uceda 133 Acceso a Datos con PHP Figura 74. Base de datos creada en MySQL Administrator Ahora creamos la tabla persona, para ello hacemos click en el botón “Create Table”. Figura 75. Creando una tabla Oscar E Capuñay Uceda 134 Acceso a Datos con PHP Escribimos el nombre de la tabla: persona Figura 76. Ingreso del nombre de la tabla Luego, agregamos el primer campo: idpersona haciendo doble click en la primera celda de la sección “Columns and Indices” Figura 77. Definición de campos de la tabla Podemos notar que por defecto se establece al campo como clave primaria, tipo entero y autoincrementable. Luego de ingresar todos los datos de los campos de la tabla tenemos: Figura 78. Estructura de la tabla Luego presionamos el botón “Apply changes”. Oscar E Capuñay Uceda 135 Acceso a Datos con PHP Figura 79. Confirmación para la creación de la tabla Confirmamos el resultado y presionamos “Execute” para terminar. Figura 80. Lista de elementos incluyendo la tabla recientemente creada Oscar E Capuñay Uceda 136 Acceso a Datos con PHP Creando una base de datos MySQL en phpmyadmin El primer paso es crear una base de datos utilizando PHPMyADMIN una aplicación Web que nos permite administrar nuestras bases de datos MySQL desde la plataforma Web. En nuestro navegador escribiremos la siguiente dirección: http://localhost/phpmyadmin/ La palabra “”localhost” de la dirección anterior se refiere al nombre con el que se ha configurado a nuestro servidor APACHE que hemos instalado con WAMP, es decir, hacemos referencia al servidor Web que esta instalado en nuestra máquina, por lo que no necesitamos de una conexión a Internet para desarrollar todos los ejemplos que veremos a continuación. Figura 81. Interfaz de phpMyAdmin Vemos la página de inicio de phpmyadmin con la lista de bases de datos que ha encontrado en el servidor. En caso que recién este utilizando MySQL sólo verá las bases de datos que vienen por defecto con la instalación. En el lado derecho de la página tenemos una caja de texto que nos permite escribir el nombre de una nueva base de datos. Oscar E Capuñay Uceda 137 Acceso a Datos con PHP Figura 82. Interfaz para cear una nueva base de datos Escribimos el nombre de la base de datos y luego elegimos el cotejamiento o conjunto de caracteres que se utilizará para guardar los datos en la base. Figura 83. Creando la base de datos dbdemo. Una vez creada la base de datos podemos crear las tablas que necesitemos, en nuestro caso crearemos la tabla “persona”, la cual estará compuesta por cinco campos. Oscar E Capuñay Uceda 138 Acceso a Datos con PHP Figura 84. Creando la tabla persona. Al presionar el botón “Continuar” aparecerá la siguiente página: Figura 85. Especificación de los campos de la tabla En esta página debemos especificar los atributos de cada campo. Por ejemplo el campo idpersona será la clave primaria y además será autoincrementable. Figura 86. Autoincremento en el campo idpersona. A continuación se detalla la estructura de la tabla persona: Idpersona int(11) autoincrement PK nombres varchar(50) apellidos varchar(50) email varchar(100) telefono varchar(15) Una vez ingresados estos datos presionamos el botón “Grabar”. Oscar E Capuñay Uceda 139 Acceso a Datos con PHP Figura 87. Estructura de la tabla creada Una vez creada la tabla aparecerá en la lista ubicada en el lado izquierdo de la página. Ahora agregaremos registros a la tabla: Figura 88. Menú de operaciones que se pueden realizar sobre las tablas de la base de datos. En la parte superior de la página encontramos varios enlaces. Seleccionamos “Insertar”. Oscar E Capuñay Uceda 140 Acceso a Datos con PHP Figura 89. Formularios para la inserción de registros Esta interfaz nos permite ingresar nuevos registros a la tabla. En nuestro caso no hay necesidad de ingresar el valor para idpersona debido a que es un campo autoincrementable. Luego presionamos el botón “Continuar”. Figura 90. Datos para los nuevos registros Oscar E Capuñay Uceda 141 Acceso a Datos con PHP Figura 91. Operación realizada con éxito y el script SQL que ha sido ejecutado. Siempre phpmyadmin nos mostrará el script SQL que acabamos de ejecutar, en este caso la orden de inserción en la tabla persona. Luego podemos ver la lista de registros haciendo click en “Examinar”. Figura 92. Listado de registros de la tabla persona Oscar E Capuñay Uceda 142 Acceso a Datos con PHP Acceso a MySQL desde PHP En esta sección primero veremos las funciones que nos permitirán conectarnos a un servidor de base de datos y luego elegir la base. Luego desarrollaremos las acciones básicas sobre una tabla como: inserción, edición, eliminación y búsqueda. Ejemplo 65: pagina12.php <?php $conex=mysql_connect("localhost","root","") or die(mysql_error()); mysql_select_db("dbdemo",$conex) or die(mysql_error()); ?> La función mysql_connect abre una conexión a un servidor MySQL, y necesita para ello tres parámetros: el nombre o dirección del servidor de base de datos, un nombre de usuario y su contraseña. Podemos observar luego de la función mysql_connect que aparece el operador OR el cual nos permite ejecutar la orden die() en caso que la conexión fallara. La orden die() imprime un mensaje y termina el script actual, en este caso el mensaje será el resultado de la ejecución de la función mysql_error() retorna el texto del error de la última función MySQL o '' (cadena vacía) si no ocurrió error. Una vez hecha la conexión almacenamos en la variable $conex el identificador de enlace de dicha conexión. Esta variable la utilizaremos para seleccionar la base de datos a la cual accederemos mediante la función mysql_select_db() que tiene como primer parámetro el nombre de la base de datos. Ahora veremos una página que incluye el script escrito en pagina12.php para realizar la conexión y luego hacer una consulta de todos los registros de la tabla persona. Ejemplo 66: Listado de registros Conexión a MySQL pagina13.php <?php include "pagina12.php"; //incluimos la conexion $sql="select * from persona"; //consulta sql $rspersona=mysql_query($sql) or die(mysql_error());//ejecucion de la sentencia sql while($reg=mysql_fetch_array($rspersona)) { echo $reg[idpersona]." - ".$reg[nombres]." ".$reg[apellidos]."<br>"; } ?> Podemos ver en el script que con la función mysql_query podemos ejecutar una sentencia SQL la cual almacena el resultado en la variable $rspersona. Oscar E Capuñay Uceda 143 Acceso a Datos con PHP Una vez hecho esto leemos los registros con la función mysql_fetch_array() la cual devuelve una matriz que corresponde a la sentencia extraída, o falso si no quedan más filas. La función mysql_fetch_array() es una versión extendida de mysql_fetch_row(). Además de guardar los datos en el índice numérico de la matriz, guarda también los datos en los índices asociativos, usando el nombre de campo como clave. De esta forma leemos cada uno de los registros hasta llegar al final del conjunto de registros obtenidos en la consulta. Podemos deducir que cada vez que esta función es ejecutada, el puntero interno se desplaza al siguiente registro. Resultado Web Figura 93. Resultado de pagina13.php Ejemplo 67: Listado de registros en una tabla Ahora le daremos una mejor presentación al listado. pagina14.php <?php include "pagina12.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=mysql_query($sql) or die(mysql_error()); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=mysql_fetch_array($rspersona)) Oscar E Capuñay Uceda 144 Acceso a Datos con PHP { ?> <tr> <td><?php echo "$registro[idpersona]"?></td> <td><?php echo "$registro[nombres]"?></td> <td><?php echo "$registro[apellidos]"?></td> <td><a href="pagina16.php?idpersona=<?php echo "$registro[idpersona]"?>">editar</a></td> <td><a href="pagina18.php?idpersona=<?php echo "$registro[idpersona]"?>">eliminar</a></td> </tr> <?php } ?> </table> <br> <a href="formulario05.html">Agregar Registro</a> Resultado Web Figura 94. Resultado de pagina14.php Ahora pasaremos a programar el formulario y la página PHP para la inserción de registros. Ejemplo 68: Inserción de registros en una tabla Formulario05.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina15.php"> Oscar E Capuñay Uceda 145 Acceso a Datos con PHP <table width="80%" border="0" align="center"> <tr> <th colspan="2">Nuevo Registro</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" /></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="password" id="telefono" maxlength="15" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina14.php'" /></th> </tr> </table> </form> </body> </html> Como resultado del cógio HTML obtenemos este formulario, el cual enviará los datos a pagina15.php. Figura 95. Formulario05.html Oscar E Capuñay Uceda 146 Acceso a Datos con PHP Pagina15.php <?php include "pagina12.php"; //sentencia para insertar el usuario $sql="insert into persona values('','$_POST[nombres]','$_POST[apellidos]','$_POST[email]','$_POST[t elefono]')"; //ejecutar sentencia mysql_query($sql) or die(mysql_error()); echo "La persona fue registrada exitosamente<br>"; echo "<a href='pagina14.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 96. Resultado de pagina15.php Ejemplo 69: Pagina16.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include "pagina12.php"; $sql="select * from persona where idpersona='$_GET[idpersona]'"; $rs=mysql_query($sql) or die(mysql_error()); //ejecutar sentencia if(mysql_num_rows($rs)>0) Edición de registros Oscar E Capuñay Uceda 147 Acceso a Datos con PHP $registro=mysql_fetch_array($rs); ?> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina17.php"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Edición de Persona</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" value="<?php echo $registro[nombres]?>" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" value="<?php echo $registro[apellidos]?>" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" value="<?php echo $registro[email]?>"/></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" value="<?php echo $registro[telefono]?>"/></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina14.php'" /></th> </tr> </table> </form> </body> </html> Resultado Web: Oscar E Capuñay Uceda 148 Acceso a Datos con PHP Figura 97. Formulario de edición de un registro pagina17.php <?php include "pagina12.php"; //sentencia para editar el registro $sql="update persona set nombres='$_POST[nombres]', apellidos='$_POST[apellidos]', email='$_POST[email]', telefono='$_POST[telefono]' where idpersona='$_POST[idpersona]'"; //ejecutar sentencia mysql_query($sql) or die(mysql_error()); echo "La persona fue actualizada exitosamente<br>"; echo "<a href='pagina14.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 98. Resultado de pagina17.php Ejemplo 70: pagina18.php <?php include "pagina12.php"; //sentencia para eliminar el registro $sql="delete from persona where idpersona='$_GET[idpersona]'"; Oscar E Capuñay Uceda 149 Eliminación de registros Acceso a Datos con PHP //ejecutar sentencia mysql_query($sql) or die(mysql_error()); echo "La persona fue eliminada exitosamente<br>"; echo "<a href='pagina14.php'>Listado de Personas</a>"; ?> En la siguiente sección veremos el acceso a una base de datos PostgreSQL. Oscar E Capuñay Uceda 150 Acceso a Datos con PHP Instalación de PostgreSQL sobre Windows XP Para instalar PostgreSQL debemos descargar el instalador de la sección “Download” de http://www.postgresql.org. Una vez descargado el archivo zip, lo descomprimimos y tendremos los siguientes archivos: Figura 99. Archivos de instalación de PostgreSQL Ejecutamos el archivo postgresql-8.3 Figura 100. Asistente de instalación de PostgreSQL Seleccionamos el idioma que se usará en la instalación (English) y presionamos “Start”. Oscar E Capuñay Uceda 151 Acceso a Datos con PHP Figura 101. Inicio del asistente de instalación Se recomienda cerrar los programas abiertos y y luego leemos las instrucciones necesarias para empezar. Figura 102. Notas de instalación Oscar E Capuñay Uceda 152 Acceso a Datos con PHP Figura 103. Opciones de instalación Seleccionamos las herramientas e interfaces que deseamos instalar. Figura 104. onfiguración del servicio Luego ingresamos el password para la cuenta postgres. Oscar E Capuñay Uceda 153 Acceso a Datos con PHP Figura 105. Error en la cuenta Si el usuario postgres no existe aparecerá el mensaje anterior para preguntar si deseamos crearlo – responderemos “Si”. Figura 106. Password aleatorio Si no ingresamos un password lo suficientemente seguro nos aparecerá este mensaje para asignarnos un password aleatorio. Si deseamos conservar nuestro password ingresado anteriormente presionaremos “No”. Figura 107. Cuenta del superusuario Ingresamos otro password para el super-usuario del sistema de base de datos (por razones de seguridad, se recomienda no utilizar el password anterior). Oscar E Capuñay Uceda 154 Acceso a Datos con PHP Figura 108. Habilitar lenguaje procedural Seleccionamos el lenguaje procedural y presionamos “Next” para luego seleccionar los módulos adicionales que podemos instalar. Figura 109. El asistente está listo para iniciar la instalación Ahora ya esta todo listo para la instalación. Oscar E Capuñay Uceda 155 Acceso a Datos con PHP Figura 110. Instalando PostgreSQL Figura 111. Instalación completa Finalmente nos aparecerá esta ventana que nos indica el final de la instalación. Si no queremos correr el Stack Builder quitamos el check y presionamos “Finish”. Una vez instalado vamos al menú “Inicio” – Programas y seleccionamos el menú de PostgreSQL. En este menú abrimos PgAdmin III. Oscar E Capuñay Uceda 156 Acceso a Datos con PHP Figura 112. pgAdmin III Si hacemos doble click sobre el servidor “PostgreSQL Database Server 8.3” aparecerá la siguiente ventana para logearnos. Figura 113. Conexión al servidor desde pgAdmin III Oscar E Capuñay Uceda 157 Acceso a Datos con PHP Creando una base de datos PostgreSQL en pgAdmin III Al ingresar a pgAdmin ya podemos administrar nuestras bases de datos. Figura 114. Listado de elementos del servidor Creamos una base de datos. Figura 115. Creando una base de datos Ingresamos los datos de la nueva base de datos (dbdemo). Oscar E Capuñay Uceda 158 Acceso a Datos con PHP Figura 116. Datos de la nueva base de datos Luego creamos la tabla persona, haciendo click con el botón derecho del mouse y seleccionando “New table…” Figura 117. Creando una nueva tabla Oscar E Capuñay Uceda 159 Acceso a Datos con PHP Figura 118. Propiedades de la tabla Especificamos los datos de la tabla y luego los campos. Cuando el tipo de dato es autoincrementable seleccionamos el tipo serial. Figura 119. Propiedades de una nueva columna Oscar E Capuñay Uceda 160 Acceso a Datos con PHP Figura 120. Columna nombres de la tabla persona Luego especificamos la clave primaria de la clave Figura 121. Clave primaria de la tabla persona Luego de especificar el nombre del constraint seleccionamos los campos de la clave primaria. Oscar E Capuñay Uceda 161 Acceso a Datos con PHP Figura 122. Columnas pertenecientes a la clave primaria Finalmente registramos el constraint y luego podemos ver el script de la tabla. Figura 123. Script SQL generado para la creación de la tabla Oscar E Capuñay Uceda 162 Acceso a Datos con PHP Figura 124. Final de la creación de la tabla Haciendo click derecho sobre la tabla persona seleccionamos “View Data” para ver los registros. Figura 125. Menú desplegable de la tabla Oscar E Capuñay Uceda 163 Acceso a Datos con PHP Figura 126. Vista de datos de la tabla Hacemos doble click sobre la primera fila e ingresamos luego los datos. Figura 127. Editando datos en la tabla Ahora veremos la creación de la base de datos con otra herramienta. Oscar E Capuñay Uceda 164 Acceso a Datos con PHP Creando una base de datos PostgreSQL en phpPgAdmin El primer paso es crear una base de datos utilizando phpPgAdmin una aplicación Web que nos permite administrar nuestras bases de datos Postgres. Escribiremos la siguiente dirección: http://localhost/phppgadmin/ Figura 128. Interfaz de phpPgAdmin Ingresamos el usuario y password para tener acceso a las bases de datos. Figura 129. Logeo de usuarios al servidor PostgreSQL Una vez ingresados los datos presionamos el botón “Autenticar” para ingresar. Oscar E Capuñay Uceda 165 Acceso a Datos con PHP Figura 130. Interfaz de ingreso a phpPgAdmin Ahora crearemos una base de datos PostgreSQL, haciendo clic en el hipervínculo: “Crear base de datos”. Figura 131. Creando una nueva base de datos Ahora nuestra base de datos “dbdemo” aparece en el margen izquierdo de la aplicación Web. Oscar E Capuñay Uceda 166 Acceso a Datos con PHP Figura 132. Base de datos dbdemo creada Seleccionamos la base de datos para crear la tabla “persona”. Figura 133. Menú de elementos de la base de datos Figura 134. creando la tabla persona Ingresamos el nombre de la tabla y especificamos la cantidad de campos que vamos a crear y luego presionamos “Próximo”. Oscar E Capuñay Uceda 167 Acceso a Datos con PHP Figura 135. Ingresando los campos de la tabla Al igual que en MySQL seleccionamos “autoincrement” para la clave primaria de la tabla (el valor del campo se auto-incrementa en cada nuevo registro insertado), en este caso indicaremos lo mismo a través de “SERIAL”. Figura 136. Autoincremento para la clave primaria Figura 137. Estructura de la tabla Haciendo clic en el hipervínculo “Insertar”, agregaremos registros a la tabla. Oscar E Capuñay Uceda 168 Acceso a Datos con PHP Figura 138. Formulario de ingreso de nuevos registros Figura 139. Listado de registros Para conectarnos a PostgreSQL desde PHP debemos aseguarrnos que las librerías de PHP para PostgreSQL estén disponibles, para ello vamos a menú de WAMP y listamos las extensiones de PHP. Oscar E Capuñay Uceda 169 Acceso a Datos con PHP Figura 140. Activando la extensión php_pgsql Una vez verificado procedemos a programar la página de conexión: Acceso a PostgreSQL desde PHP Ejemplo 71: pagina22.php <?php //conexion al servidor PostgreSQL $conex=pg_connect("host=localhost dbname=dbdemo port=5432 user=oscar password=123456") or die("Error en la conexión"); ?> Conexión a PostgreSQL pagina23.php <?php include "pagina22.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=pg_query($sql) or die(pg_last_error($conex)); while($reg=pg_fetch_array($rspersona)) { echo $reg[idpersona]." - ".$reg[nombres]." ".$reg[apellidos]."<br>"; } ?> La función pg_last_error() muestra el último error ocurrido en la conexión activa, la cual es el parámetro. Oscar E Capuñay Uceda 170 Acceso a Datos con PHP Resultado Web: Figura 141. Resultado de pagina23.php Ejemplo 72: pagina24.php <?php include "pagina22.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=pg_query($sql) or die(pg_last_error($conex)); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=pg_fetch_array($rspersona)) { ?> <tr> <td><?php echo "$registro[idpersona]"?></td> <td><?php echo "$registro[nombres]"?></td> <td><?php echo "$registro[apellidos]"?></td> <td><a href="pagina26.php?idpersona=<?php echo "$registro[idpersona]"?>">editar</a></td> <td><a href="pagina28.php?idpersona=<?php echo "$registro[idpersona]"?>">eliminar</a></td> </tr> <?php } //Liberar conjunto de resultados pg_free_result($rspersona); Oscar E Capuñay Uceda 171 Listado de registros en una tabla HTML. Acceso a Datos con PHP // Cerrar conexion pg_close($conex); ?> </table> <br> <a href="formulario06.html">Agregar Registro</a> </body> </html> Resultado Web: Figura 142. Resultado de pagina24.php Ejemplo 73: Inserción de registro en PostgreSQL. formulario06.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina25.php"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Nuevo Registro</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" /></td> </tr> <tr> Oscar E Capuñay Uceda 172 Acceso a Datos con PHP <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" /></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina14.php'" /></th> </tr> </table> </form> </body> </html> El destino de los datos de este formulario es: pagina25.php. Resultado Web: Figura 143. Resultado de formulario06.html pagina25.php <?php include "pagina22.php"; //sentencia para insertar el usuario $sql="insert into persona (nombres, apellidos, email, telefono ) values ('$_POST[nombres]','$_POST[apellidos]','$_POST[email]','$_POST[telefono]' )"; //ejecutar sentencia pg_query($sql) or die(pg_last_error($conex)); echo "La persona fue registrada exitosamente<br>"; echo "<a href='pagina24.php'>Listado de Personas</a>"; ?> Oscar E Capuñay Uceda 173 Acceso a Datos con PHP Resultado Web: Figura 144. Resultado de pagina25.php Ejemplo 74: pagina26.php <html> <head> <?php include "pagina22.php"; $sql="select * from persona where idpersona='$_GET[idpersona]'"; $rs=pg_query($sql) or die(pg_last_error()); if(pg_num_rows($rs)>0) $registro=pg_fetch_array($rs); ?> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Edición de registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina27.php"> <input type="hidden" name="idpersona" value="<?php echo $_GET[idpersona]?>"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Edición de Persona</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" value="<?php echo $registro[nombres]?>" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" value="<?php echo $registro[apellidos]?>" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" value="<?php echo $registro[email]?>"/></td> </tr> Oscar E Capuñay Uceda 174 Edición de registro en PostgreSQL. Acceso a Datos con PHP <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" value="<?php echo $registro[telefono]?>"/></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina24.php'" /></th> </tr> </table> </form> </body> </html> Resultado Web: Figura 145. Resultado de pagina26.php pagina27.php <?php include "pagina22.php"; //sentencia para editar el registro $sql="update persona set nombres='$_POST[nombres]', apellidos='$_POST[apellidos]', email='$_POST[email]', telefono='$_POST[telefono]' where idpersona='$_POST[idpersona]'"; pg_query($sql) or die(pg_last_error($conex)); echo "La persona fue actualizada exitosamente<br>"; echo "<a href='pagina24.php'>Listado de Personas</a>"; ?> Resultado Web: Oscar E Capuñay Uceda 175 Acceso a Datos con PHP Figura 146. Resultado de pagina27.php Ejemplo 75: pagina28.php <?php include "pagina22.php"; //sentencia para eliminar el registro $sql="delete from persona where idpersona='$_GET[idpersona]'"; //ejecutar sentencia pg_query($sql) or die(pg_last_error()); echo "La persona fue eliminada exitosamente<br>"; echo "<a href='pagina24.php'>Listado de Personas</a>"; ?> Eliminación de registro en PostgreSQL. Figura 147. Resultado de pagina28.php Oscar E Capuñay Uceda 176 Acceso a Datos con PHP Acceso a MS SQL-Server desde PHP Ahora es el turno de MS SQLServer, para crear una base de datos vamos a abrir el Administrador Corporativo y luego crearemos una base de datos llamada dbdemo. Figura 148. Creando un nueva base de datos Figura 149. Nombre de la nueva base de datos Oscar E Capuñay Uceda 177 Acceso a Datos con PHP Luego creamos la tabla persona. Figura 150. Creando una nueva tabla Figura 151. Especificación de los campos de la tabla Verificamos si la librería para MS-SQLServer está disponible. Oscar E Capuñay Uceda 178 Acceso a Datos con PHP Figura 152. Activando la extensión php_mssql Luego ingresamos algunos registros para probar los scripts. Figura 153. Creando un usuario para acceso a la base de datos Creamos un usuario para el acceso a la base de datos que hemos creado y establecemos los permisos. Oscar E Capuñay Uceda 179 Acceso a Datos con PHP Figura 154. Establecimiento de los permisos del usuario Ejemplo 76: pagina29.php <?php //conexion al servidor MS-SQLServer $conex=mssql_connect("LAPTOP\\","oscar","123456") or die("Error en la conexión"); mssql_select_db("dbdemo",$conex) or die("Error al seleccionar la BD"); ?> Ahora probemos listando los registros. pagina30.php <?php include "pagina29.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=mssql_query($sql) or die("Error sql"); while($reg=mssql_fetch_array($rspersona)) { echo $reg[idpersona]." - ".$reg[nombres]." ".$reg[apellidos]."<br>"; } ?> Resultado Web: Conexión a MS-SQLServer Oscar E Capuñay Uceda 180 Acceso a Datos con PHP Figura 155. Resultado de pagina30.php Ejemplo 77: pagina31.php <?php include "pagina29.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=mssql_query($sql) or die("error en la consulta"); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=mssql_fetch_array($rspersona)) { ?> <tr> <td><?php echo "$registro[idpersona]"?></td> <td><?php echo "$registro[nombres]"?></td> <td><?php echo "$registro[apellidos]"?></td> <td><a href="pagina33.php?idpersona=<?php echo "$registro[idpersona]"?>">editar</a></td> <td><a href="pagina35.php?idpersona=<?php echo "$registro[idpersona]"?>">eliminar</a></td> </tr> <?php } //Liberar conjunto de resultados mssql_free_result($rspersona); // Cerrar conexion mssql_close($conex); ?> Listado de registros Oscar E Capuñay Uceda 181 Acceso a Datos con PHP </table> <br> <a href="formulario07.html">Agregar Registro</a> Ejemplo 78: Inserción de registro en MS-SQLServer formulario07.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina32.php"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Nuevo Registro</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" /></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina14.php'" /></th> </tr> </table> </form> </body> </html> Oscar E Capuñay Uceda 182 Acceso a Datos con PHP pagina32.php <?php include "pagina29.php"; //sentencia para insertar la persona $sql="insert into persona (nombres, apellidos, email, telefono ) values ('$_POST[nombres]','$_POST[apellidos]','$_POST[email]','$_POST[telefono]' )"; mssql_query($sql) or die("error al insertar el registro"); echo "La persona fue registrada exitosamente<br>"; echo "<a href='pagina31.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 156. Resultado de pagina32.php Oscar E Capuñay Uceda 183 Acceso a Datos con PHP Ejemplo 79: pagina33.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include "pagina29.php"; $sql="select * from persona where idpersona='$_GET[idpersona]'"; $rs=mssql_query($sql) or die("error en la consulta"); //ejecutar sentencia if(mssql_num_rows($rs)>0) $registro=mssql_fetch_array($rs); ?> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Edición de registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pagina34.php"> <input type="hidden" name="idpersona" value="<?php echo $_GET[idpersona]?>"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Edición de Persona</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" value="<?php echo $registro[nombres]?>" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" value="<?php echo $registro[apellidos]?>" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" value="<?php echo $registro[email]?>"/></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" value="<?php echo $registro[telefono]?>"/></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pagina31.php'" /></th> </tr> </table> </form> Oscar E Capuñay Uceda 184 Edición de registro en MS-SQLServer Acceso a Datos con PHP </body> </html> Resultado Web: Figura 157. Resultado de pagina33.php pagina34.php <?php include "pagina29.php"; //sentencia para editar el registro $sql="update persona set nombres='$_POST[nombres]', apellidos='$_POST[apellidos]', email='$_POST[email]', telefono='$_POST[telefono]' where idpersona='$_POST[idpersona]'"; //ejecutar sentencia mssql_query($sql) or die("error al editar el registro"); echo "La persona fue actualizada exitosamente<br>"; echo "<a href='pagina31.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 158. Resultado de pagina34.php Ejemplo 80: pagina35.php <?php include "pagina29.php"; //sentencia para eliminar el registro $sql="delete from persona where idpersona='$_GET[idpersona]'"; //ejecutar sentencia Oscar E Capuñay Uceda 185 Eliminación de registros en MS-SQLServer Acceso a Datos con PHP mssql_query($sql) or die("Error al eliminar el registro"); echo "La persona fue eliminada exitosamente<br>"; echo "<a href='pagina31.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 159. Resultado de pagina35.php Oscar E Capuñay Uceda 186 PHP Orientado a Objetos VI. PHP Orientado a Objetos Clases en PHP Cada definición de clase empieza con la palabra "class", seguida por un nombre de clase, el cual puede ser cualquier nombre que no esté en la lista de palabras reservadas en PHP. [3] Ejemplo 81: pagina19.php <?php class MiClase { // Declaración de un miembro de la clase public $variable = 'demo'; // demo es el valor por defecto de $variable // Declaración de un método public function ver() { echo $this->variable; //imprime el valor de $variable } } ?> Definición de una clase Instancia de un Objeto Para crear una instancia de un objeto, un nuevo objeto debe ser creado y asignado a una variable. Un objeto siempre será asignado cuando se crea un objeto nuevo a menos que el objeto tenga un constructor definido que arroje una excepción en caso de error. Las clases deben ser definidas antes de crear las instancias (y en algunos casos esto es un requerido). Cuando se asigna una instancia de un objeto previamente creado a una nueva variable, la nueva variable accesará a la misma instancia que la del objeto a la que fue asignada. Este comportamiento es el mismo cuando se pasan instancias a una función. Una nueva instancia de un objeto previamente creado puede ser hecha clonándolo. [3] Ejemplo 82: pagina20.php <?php include "pagina19.php"; //definición de MiClase //Creando una instancia $instancia = new MiClase(); // Asignación del Objeto $asignado = $instancia; $referencia =& $instancia; Oscar E Capuñay Uceda 187 Creando una instancia PHP Orientado a Objetos $instancia->variable = '$asignado tendrá este valor'; $instancia = null; // $instancia y $referencia serán nulos var_dump($instancia); var_dump($referencia); var_dump($asignado); ?> Resultado Web Figura 160. Resultado de pagina20.php Extendiendo objetos Una clase puede heredar métodos y miembros de otra clase usando la palabra 'extends' en la declaración. No es posible extender de múltiples clases, una clase puede heredar solo de una clase base. Los métodos heredados y sus miembros pueden ser evitados, redeclarándolos con el mismo nombre con el que los definió la clase padre, a menos que la clase padre haya definido un método como final. Es posible accesar a los métodos o miembros redeclarados haciendo referencia a ellos con parent:: Ejemplo 83: pagina21.php <?php include "pagina19.php"; class ExtendClass extends MiClase { // Redefinición de método function ver() { echo "clase con nuevo método\n"; parent::ver(); } } $extended = new ExtendClass(); $extended->ver(); ?> Herencia simple de una Clase Oscar E Capuñay Uceda 188 PHP Orientado a Objetos Resultado Web Figura 161. Resultado de pagina21.php Auto carga de Objetos Cuando se escriben aplicaciones con programación orientada a objetos crean un archivo fuente PHP por cada definición de clase. Una de las molestias más grandes es tener que escribir una larga lista de includes necesarios al principio de cada script (uno para cada clase). En PHP 5, esto ya no es necesario. Puede definir una función __autoload la cual es llamada automáticamente en caso de que intente usar una clase que no ha sido definida aún. Al llamar esta función la ejecución del script da una última oportunidad de cargar la clase antes de que PHP falle con un error. Nota: Las excepciones arrojadas en la función __autoload no pueden ser capturadas en el bloque catch y resultan en el despliegue de un error fatal. Nota: La autocarga no esta disponible en PHP si se usa el modo interactivo CLI. En el siguiente ejemplo se intenta cargar las clases clase1 y clase2 de los archivos clase1.php y clase2.php respectivamente utilizando la función __autoload para después ejecutar los métodos de cada clase. Ejemplo 84: clase1.php <?php class clase1 { // Declaración de un miembro de la clase public $texto = 'esta es la clase1'; // Declaración de un método public function mostrar() { echo $this->texto; //imprime el valor de $variable } } ?> Oscar E Capuñay Uceda 189 Auto carga PHP Orientado a Objetos clase2.php <?php class clase2 { // Declaración de un miembro de la clase public $mi_texto = 'texto de la clase2'; // Declaración de un método public function display() { echo $this->mi_texto; //imprime el valor de $variable } } ?> autocarga.php <?php function __autoload($nombre_clase) { require_once $nombre_clase . '.php'; } $obj1 = new clase1(); $obj2 = new clase2(); $obj1->mostrar(); ?> <br> <?php $obj2->display(); ?> Resultado Web: Figura 162. Resultado de autocarga.php Oscar E Capuñay Uceda 190 PHP Orientado a Objetos Acceso a MySQL con PHP Orientado a Objetos PHP 5.x viene con una extensión mejorada para trabajar con la funcionalidad provista por MySQL 4.1 y superior. Veamos a continuación una breve referencia es clases y métodos. Clases predefinidas mysqli Representa una conexión entres PHP y la base de datos MySQL. Constructor mysqli - constructor de un nuevo objeto mysqli Métodos autocommit - cambia en ON u OFF las modificaciones de auto-commiting en la base de datos. change_user - cambia el usuario del identificador de enlace especificado. character_set_name - regresa el conjunto de caracteres del identificador de enlace especificado. close - cierra una conexión previamente abierta. commit - completa la transacción actual. connect - abre una nueva conexión al servidor de MySQL. debug - realiza operaciones de rastreo. dump_debug_info - vacía información de rastreo. get_client_info - retorna la versión del cliente. get_host_info - retorna el tipo de conexión usada. get_server_info - retorna la versión del servidor MySQL. get_server_version - retorna la versión del servidor MySQL init - inicializa el objeto mysqli. info - obtiene información acerca de la consulta más recientemente ejecutada. kill - solicita al servidor destruir un thread de mysql. Oscar E Capuñay Uceda 191 PHP Orientado a Objetos multi_query - realiza consultas de SQL múltiples. more_results - verifica si existen mas resultados de la consulta múltiple actualmente ejecutada. next_result - lee el siguiente resultado de la consulta múltiple actualmente ejecutada. options - fija opciones extra en la conexión. ping - llama una conexión con el servidor o reconecta si no hay conexión. prepare - prepara una sentencia SQL. query - ejecuta una sentencia SQL. real_connect - intenta abrir una conexión al servidor de base de datos MySQL. escape_string - caracteres especiales de escape para ser usados en una sentencia SQL, tomando en cuenta el conjunto de caracteres actual de la conexión. rollback - deshace la transacción actual. select_db - selecciona la base de datos por defecto. ssl_set - fija los parámetros SSL. stat - obtiene el estado actual del sistema. stmt_init - inicializa una sentencia para ser usada con mysqli_stmt_prepare. store_result - transfiere un resultado de la última consulta. use_result - transfiere un resultado sin almacenamiento intermedio de la última consulta. thread_safe - retorna si se ha dado thread_safety o no. Propiedades affected_rows - obtiene el número de filas afectadas en la operación MySQL previa. client_info - retorna en una cadena la versión del cliente de MySQL. client_version - retorna en un entero la versión del cliente de MySQL. errno - retorna el código de error para la llamada a función más reciente. Oscar E Capuñay Uceda 192 PHP Orientado a Objetos error - retorna la cadena de error para la llamada a función más reciente. field_count - retorna el número de columnas para la consulta más reciente. host_info - retorna la cadena representando el tipo de conexión usado. info - retorna información acerca de la consulta ejecutada más recientemente. insert_id - retorna el identificador generado automáticamente usado en la última consulta. protocol_version - retorna la versión del protocolo usado por MySQL. sqlstate - retorna una cadena que contiene el código de error SQLSTATE para el último error. thread_id - retorna el identificador del THREAD para la conexión actual. warning_count - retorna el número de alertas generadas durante la ejecución del enunciado SQL previo. mysqli_stmt Representa una sentencia preparada. Métodos bind_param - enlaza variables a una sentencia preparada. bind_result - enlaza variables a una sentencia preparada para el almacenamiento del resultado. close - cierra la sentencia preparada. data_seek - busca a una fila arbitrariamente en el resultado. execute - ejecuta una sentencia preparada. fetch - obtiene el resultado de la sentencia preparada en variables límite. free_result - libera la memoria del resultado almacenado para el manejador de la sentencia dada. result_metadata - obtiene un resultado de la sentencia preparada para información de metadatos. prepare - prepara una consulta SQL. send_long_data - envía datos en partes. reset - resetea una sentencia preparada. Oscar E Capuñay Uceda 193 PHP Orientado a Objetos store_result - almacena el resultado completo de la sentencia preparada. Propiedades affected_rows - retorna las filas afectadas de la última sentencia ejecutada. errno - retorna el código de error para la llamada a función más reciente. error - retorna el mensaje de error para la llamada a función más reciente. param_count - retorna el numero de parámetros para la sentencia preparada dada. sqlstate - retorna una cadena conteniendo el código de error SQLSTATE para la llamada a función más reciente. mysqli_result Representa el resultado obtenido de la consulta hecha en la base de datos. Métodos close - cierra el resultado. data_seek - mueve el puntero interno del resultado. fetch_field - obtiene la información de la columna en el resultado. fetch_fields - obtiene la información para todas las columnas del resultado. fetch_field_direct - obtiene información de la columna para la columna dada. fetch_array - recupera una fila como una matriz asociativa, una matriz numérica, o ambos. fetch_assoc - obtiene una fuka como una matriz asociativa. fetch_object - obtiene una fila como un objeto. fetch_row - obtiene una fila como una matriz enumerada. close - libera la memoria ocupada por el resultado. field_seek - fija el apuntador del resultado a la posición especificada. Propiedades current_field - retorna la posición de puntero actual. field_count - retorna el número de campos en el resultado. Oscar E Capuñay Uceda 194 PHP Orientado a Objetos lengths - retorna una matriz con la longitud de los campos. num_rows - retorna el número de filas en el resultado. Nos conectaremos a la base de datos “dbdemo” y administraremos la tabla “persona”. Ejemplo 85: Conexión a MySQL con mysqli mysqli-connect.php <?php $mysqli = new mysqli("localhost", "root", "", "dbdemo"); /* verifica la conexión */ if (mysqli_connect_errno()) { printf("Conexión fallida:<br> %s\n", mysqli_connect_error()); exit(); } printf("Server MySQL:<br> %s\n", $mysqli->host_info); /* Cerrar la conexión */ $mysqli->close(); ?> Resultado Web: Figura 163. Resultado de mysqli-connect.php Modificaremos el archivo anterior para utilizarlo en las conexiones de las próximas páginas. mysqli-conexion.php <?php $mysqli = new mysqli("localhost", "root", "", "dbdemo"); /* verifica la conexión */ if (mysqli_connect_errno()) { Oscar E Capuñay Uceda 195 PHP Orientado a Objetos printf("Error en la conexión:<br> %s\n", mysqli_connect_error()); exit(); } ?> Ejemplo 86: mysqli-lista.php Listado con mysqli <?php include "mysqli-conexion.php"; //incluimos la conexión //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); //listado while($reg=$rspersona->fetch_object()) { echo $reg->idpersona." - ".$reg->nombres." ".$reg->apellidos."<br>"; } ?> Resultado Web: Figura 164. Resultado de mysqli-lista.php mysqli-listado.php <?php include "mysqli-conexion.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> Oscar E Capuñay Uceda 196 PHP Orientado a Objetos <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> <td><?php echo "$registro->apellidos"?></td> <td><a href="mysqli-editar.php?idpersona=<?php echo "$registro>idpersona"?>">editar</a></td> <td><a href="mysqli-eliminar.php?idpersona=<?php echo "$registro>idpersona"?>">eliminar</a></td> </tr> <?php } $rspersona->close(); //cerramos resultado de la consulta $mysqli->close(); //cerramos la conexión ?> </table> <br> <a href="formulario08.html">Agregar Registro</a> </body> </html> Resultado Web: Figura 165. Resultado de mysqli-listado.php Ejemplo 87: Inserción de registro con mysqli formulario08.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> Oscar E Capuñay Uceda 197 PHP Orientado a Objetos <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="mysqli-insertar.php"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Nuevo Registro</th></tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" /></td> </tr> <tr> <td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" /></td> </tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" /></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location=' mysqli-listado.php'" /></th> </tr> </table> </form> </body> </html> Resultado Web: Figura 166. Resultado de formulario08.htm Oscar E Capuñay Uceda 198 PHP Orientado a Objetos mysqli-insertar.php <?php include "mysqli-conexion.php"; //sentencia para insertar el usuario $sql="insert into persona values('','$_POST[nombres]','$_POST[apellidos]','$_POST[email]','$_POST[t elefono]')"; //ejecutar sentencia $mysqli->query($sql) or die($mysqli->error); echo "La persona fue registrada exitosamente<br>"; echo "<a href='mysqli-listado.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 167. Resultado de mysqli-insertar.php Ejemplo 88: Edición de registro con mysqli mysqli-editar.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include "mysqli-conexion.php"; $sql="select * from persona where idpersona='$_GET[idpersona]'"; $rs=$mysqli->query($sql) or die($mysqli->error); //ejecutar sentencia if($rs->num_rows>0) $registro=$rs->fetch_object(); ?> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Edición de registro</title> </head> Oscar E Capuñay Uceda 199 PHP Orientado a Objetos <body> <form id="form1" name="form1" method="post" action="mysqliactualizar.php"> <input type="hidden" name="idpersona" value="<?php echo $_GET[idpersona]?>"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Edición de Persona</th></tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" value="<?php echo $registro>nombres?>" /></td> </tr> <tr><td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" value="<?php echo $registro>apellidos?>" /></td></tr> <tr> <td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" value="<?php echo $registro->email?>"/></td> </tr> <tr> <td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" value="<?php echo $registro>telefono?>"/></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location=' mysqli-listado.php'" /></th> </tr> </table> </form> <?php $rs->close(); $mysqli->close(); ?> </body> </html> Resultado Web: Figura 168. Resultado de mysqli-editar.php Oscar E Capuñay Uceda 200 PHP Orientado a Objetos mysqli-actualizar.php <?php include "mysqli-conexion.php"; //sentencia para editar el registro $sql="update persona set nombres='$_POST[nombres]', apellidos='$_POST[apellidos]', email='$_POST[email]', telefono='$_POST[telefono]' where idpersona='$_POST[idpersona]'"; //ejecutar sentencia $mysqli->query($sql) or die($mysqli->error()); echo "La persona fue actualizada exitosamente<br>"; echo "<a href='mysqli-listado.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 169. Resultado de mysqli-actualizar.php Ejemplo 89: Eliminación de registros con mysqli mysql-eliminar.php <?php include "mysqli-conexion.php"; //sentencia para eliminar el registro $sql="delete from persona where idpersona='$_GET[idpersona]'"; //ejecutar sentencia $mysqli->query($sql) or die($mysqli->error()); echo "La persona fue eliminada exitosamente<br>"; echo "<a href='mysqli-listado.php'>Listado de Personas</a>"; ?> Resultado Web: Figura 170. Resultado de mysqli-eliminar.php Oscar E Capuñay Uceda 201 PHP Orientado a Objetos Paginando resultados Ejemplo 90: Paginación de resultados mysqli-listado-paginacion.php <?php include "mysqli-conexion.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); $numreg=$rspersona->num_rows; $regxpag=3; if(!isset($_GET['p']))$_GET['p']=1; $inicio=$regxpag*($_GET['p']-1); $sql=$sql ." limit $inicio,$regxpag"; $numpag=ceil($numreg/$regxpag); $rspersona=$mysqli->query($sql) or die($mysqli->error); echo "Registros encontrados:" . $numreg; ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> <td><?php echo "$registro->apellidos"?></td> <td><a href="mysqli-editar.php?idpersona=<?php echo "$registro>idpersona"?>">editar</a></td> <td><a href="mysqli-eliminar.php?idpersona=<?php echo "$registro>idpersona"?>">eliminar</a></td> </tr> <?php } $rspersona->close(); //cerramos resultado de la consulta $mysqli->close(); //cerr=amos la conexión ?> </table> Oscar E Capuñay Uceda 202 PHP Orientado a Objetos Página: <?php for($i=1;$i<=$numpag;$i++) { echo "<a href='mysqli-listado-paginacion.php?p=$i'>$i</a> "; } ?> <br> <a href="formulario08.html">Agregar Registro</a> Resultado Web: Figura 171. Resultado de mysqli-listado-paginacion.php Explicación: Primero incluimos el archivo para la conexión a la base de datos include "mysqli-conexion.php"; //incluimos la conexión Consultamos los registros de la tabla persona //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); Hallamos la cantidad de registros de la tabla para dividirlo en páginas. $numreg=$rspersona->num_rows; Establecemos la cantidad de registros por página. $regxpag=3; Verificamos si la variable “p” que indica la página que se va a mostrar, tiene algun valor. Si la variable no tiene valor, se le asigna 1 (pagina por defecto). if(!isset($_GET['p']))$_GET['p']=1; Hallamos el registro inicial de la página $inicio=$regxpag*($_GET['p']-1); Complementamos la sentencia SQL para mostrar solamente los registros de la página seleccionada Oscar E Capuñay Uceda 203 PHP Orientado a Objetos $sql=$sql ." limit $inicio,$regxpag"; Hallamos el número de páginas. La función ceil redondea fracciones hacia arriba. $numpag=ceil($numreg/$regxpag); Ejecutamos la consulta SQL para obtener los registros de la página seleccionada. $rspersona=$mysqli->query($sql) or die($mysqli->error); Imprimir la cantidad de registros total. echo "Registros encontrados:" . $numreg; En la parte inferior de la página web aparecen las páginas de resultados. A través de un bucle creamos los hipervínculos para visualizar las páginas. <?php for($i=1;$i<=$numpag;$i++) { echo "<a href='mysqli-listado-paginacion.php?p=$i'>$i</a> "; } Oscar E Capuñay Uceda 204 PHP Orientado a Objetos Arquitectura MVC Todos los que estamos inmersos en el mundo de la programación sabemos que en todo programa los datos que se procesan pueden ser ingresados y mostrados en formas diferentes dependiendo del tipo y diseño de la interfaz, y sobre todo en el desarrollo Web esto se ve aun más acentuado debido a que los desarrolladores Web muchas veces son muy buenos programando pero no diseñando interfaces, por lo general las empresas de este rubro optan por utilizar dos equipos de trabajo: los codificadores quienes se encargan de implementar los algoritmos y los diseñadores para darle un buena presentación a la aplicación, pero las dificultades inician cuando alguna parte del código que un equipo hace influye sobre el diseño que realiza el otro equipo. Para dar solución a este tipo de problemas han surgido arquitecturas de desarrollo que nos permiten desarrollar aplicaciones separando la lógica del diseño de la interfaz, una de ellas es la Arquitectura MVC (Modelo – Vista – Controlador). MVC con PHP Lo que se muestra a continuación es un artículo muy interesante extraído de http://www.phpizza.com/es/ en el que se explica de una forma fácil y sencilla el uso de MVC con PHP. Esta arquitectura va más allá de esa división abstracta en dos capas e implementa 3 partes: Figura 172. MVC Fuente: http://www.phpizza.com En el esquema de arriba las flechas oscuras significan una interacción directa y las claras la indirecta. Esto básicamente quiere decir que las verdes son las respuestas a las azules. Oscar E Capuñay Uceda 205 PHP Orientado a Objetos La capa de Presentación se divide en dos componentes: Controlador y la Vista. La capa de Datos tiene un componente: el Modelo. Controlador Algunos al hablar de Controlador se referirán a su acometido bajo los nombres de Lógica de Negocio o Lógica Empresarial. Lo de la lógica de negocio probablemente venga de los tiempos en los que los programas sobre todo hacían cosas relacionadas con informes contables. Como su propio nombre indica el Controlador controla lo que sucede a partir de que se haya producido una interacción por parte del usuario sobre la Vista. La Vista le comunica los eventos al Controlador. El Controlador usa el Modelo para conseguir los datos o almacenarlos y por fin, el Controlador vuelve a usar la Vista para comunicar al usuario que resultado provocó su acción. Modelo El acometido de esta parte llamada Modelo es el Acceso A Datos. Al hablar de Datos uno piensa en una Base de Datos o un Sistema de Gestión de Bases de Datos (SGBD): MySQL, PostgreSQL, Oracle etc. En realidad el Modelo encapsula la Capa de Acceso a Datos de tal forma que se supone que nos podemos olvidar de que tipo de SGBD estamos usando. El Modelo, en realidad, es el objeto en sí. Vista La tercera parte es la Vista. Es en realidad la Capa de Presentación. Sirve para que el usuario pueda interactuar a través de los eventos con el Controlador y también para que pueda ver los resultados. Estos resultados serán aportados por el Controlador a través del Modelo. Esta es la diferencia con la simple programación por capas (también llamada escalonada o multi-escalonada) y sin conocerla se suelen confundir los términos. Oscar E Capuñay Uceda 206 PHP Orientado a Objetos Figura 173. Tres capas Fuente: http://www.phpizza.com En una arquitectura de separación por capas – que es una manera de llevar a cabo la separación abstracta de 2 capas– la Capa de Acceso a Datos nunca interfiere directamente con la Vista. Lo hace siempre a través del Controlador. El Controlador interpreta los eventos que le llegan de la Vista, usa los objetos o funciones de la Capa de Acceso A Datos y envía datos a la Vista. Pero la Vista no ejecuta los métodos de los objetos. En MVC, sin embargo, la Vista sí puede mostrar datos a través de los métodos de un objeto que el Controlador le ha pasado.[5] MVC Web Traducido al mundo de la programación Web paso por paso: 1. el Controlador recibe una petición. Esto puede ocurrir de forma directa poniendo el usuario en el navegador la URL del Controlador http://localhost/controlador.php, o mediante un evento a través de una Vista ya renderizada (envío de un formulario por ejemplo), o por una petición ajax. 2. el Controlador analiza la petición y usa un Modelo para obtener datos de algún tipo. 3. el Modelo puede leer datos y/o escribirlos en una base de datos. Normalmente sucede esto, aunque no siempre. 4. el Controlador usa una Vista para poder presentar los resultados al usuario. Oscar E Capuñay Uceda 207 PHP Orientado a Objetos 5. la Vista usa el Modelo, de tal forma, que algún tipo de respuesta obtenido por la acción previa será presentado en la Vista. 6. la Vista está renderizada con los datos del Modelo y el Controlador envía esta respuesta al usuario. 7. El usuario obtiene la respuesta El Modelo Vista Controlador no es una cosa reciente. Lo inventaron en los años 70 al empezar a hacer aplicaciones medianamente grandes que manejaban muchos datos. Es el llamado “Modelo* 2” en la jerga Sun. *Aquí la palabra Modelo no tiene que ver con el Modelo de Modelo Vista Controlador sino con el nombre de la arquitectura. Hablando de la interacción entre el Modelo y la Vista - en Java también es posible implementar un componente llamado Observador que después de constatar algún cambio en el Modelo, puede realizar ciertas operaciones. Por ejemplo: el usuario confirma la compra en una tienda on-line y el Observer implementado ve que hay un cambio en el Modelo (en la propia base de datos) y manda un email de confirmación o actualiza la Vista. Pero los Observadores no se implementan en PHP porque este lenguaje se ejecuta de manera distinta a como se ejecutan los procesos de Java. Normalmente al tener un tiempo limitado de ejecución los procesos PHP no hacen de observadores. Sinceramente - hacer una aplicación usando la arquitectura MVC te costará más trabajo que si haces páginas monolíticas, mezclándolo todo - el php y el html en lo que se llama popularmente el código spaghetti. El MVC supone más trabajo: Primero tendrás que definir los Modelos y convertirlos en Objetos de tal manera que sus atributos y métodos sean el conjunto de propiedades y acciones verdaderamente necesarias y representativas. Tendrás que planificar las Vistas por separado y trabajar los Controladores. Al principio de la implementación te será más rápido hacer páginas monolíticas… ¿Por qué usarlo entonces? Pues, cuando quieras cambiar tu aplicación – para añadir, quitar o cambiar alguna funcionalidad - la vida te resultará muy dura. Un proyecto medianamente grande se convertirá en un infierno en muy poco tiempo sobre todo cuando quieras cambiar algo y ello afecte al funcionamiento de más de una de tus páginas. El MVC básicamente te permitirá poder cambiar las Capas de presentación sin que afecten a la de acceso de datos y viceversa. Hay gente que te dirá que el PHP fue concebido como algo sencillo y práctico. Como un lenguaje que permite hacer páginas Web dinámicas y Oscar E Capuñay Uceda 208 PHP Orientado a Objetos procesar formularios de una manera simple. Que complicar las cosas más allá de eso es impropio de este lenguaje. Y les doy la razón. ¡Claro! El asunto es que ese primer PHP no tenía mucho que ver con el PHP5 actual. No había objetos por ejemplo. Hay pequeñas diferencias en como implementan el MVC distintos frameworks, pero los fundamentos son los mismos. También puedes usar motores de plantillas como por ejemplo Smarty para implementar el MVC, pero en realidad no necesitas nada más que el PHP puro. Ejemplo 91: _modelo.php <?php class ClaseX { protected $plantilla_propia = "_listar.php"; protected $arrayx= array(); public function show() { include ($this->plantilla_propia); }//fun public function CargarDatos() { $this->arrayx = array("Abel", "Marco","Pedro"); }//fun }//class ?> Ejemplo 92: _listar.php <?php foreach ($this->arrayx as $elemento) { echo $elemento["nombre"]; echo ""; }//foreach ?> Oscar E Capuñay Uceda 209 MODELO – MVC con PHP Una plantilla usada por el modelo PHP Orientado a Objetos Ejemplo 93: CONTROLADOR MVC con PHP _controlador.php <?php include ("./_modelo.php"); $objX = new ClaseX(); //aquí habría que implementar una clase que //determine las caracteristicas de la pagina //pero para poner un ejemplo sencillo vamos //a saltarnos esa parte en este artículo $titulo = "pagina nueva"; $objX->CargarDatos(); include ("_vista.php"); ?> Ejemplo 94: _vista.php <html> <head> <title><?php echo $titulo; ?></title> </head> <body> <?php $objX->show(); ?> </body> </html> El punto clave en una Vista como la de este ejemplo es que no uses instrucciones PHP más allá de las que muestren datos. ¿Por qué? Pues si la lógica de tu aplicación se está decidiendo en la Vista entonces ¿para qué queremos el Controlador? ;) Simplificando mucho el concepto eso quiere decir que uses echo y metodos de tus objetos (Modelo) que hagan echo de alguna forma aunque tu los llames show o muestra_datos o lo que tú quieras. El inventor y gurú del PHP Rasmus Lerdorf, publicó hace algún tiempo, en febrero del año 2006 un bastante mal entendido artículo, titulado “The no framework PHP MVC framework”… Aquí, Rasmus nos habla sobre como implementar un sencillo MVC usando solo PHP puro. Bueno, estoy de acuerdo hasta un cierto punto con este artículo y es que implementar el MVC sin usar un framework que vaya más allá de nuestras necesidades nos va a beneficiar en cuanto a la memoria que usa cada script PHP. Más tarde hablaremos sobre la optimización. Algunos Oscar E Capuñay Uceda 210 VISTA MVC con PHP PHP Orientado a Objetos han interpretado que Rasmus en este artículo defendía la programación procedural en contra de la Orientada a Objetos. El mismo dice que no es asíque podía haber hecho todo el ejemplo usando más objetos y estoy de acuerdo. Pero si observas detenidamente la parte titulada “View –add.html” que es el ejemplo de Vista que nos pone su autor, te darás cuenta que la Vista hace al principio una inclusión del Controlador: include './ui.inc'; // Common View Helper functions include './add_c.inc'; // Controller head(); Vale, pues – eso no es MVC aunque lo diga mi admirado Rasmus. Es un framework con división de capas en tres partes pero no es MVC. La Vista no debe ser la que controla la aparición de un Controlador sino todo lo contrario: el Controlador usa las Vistas. Oscar E Capuñay Uceda 211 PHP Orientado a Objetos MVC y PHP con acceso a Base de Datos Tomando como guía el artículo anterior desarrollaremos un listado de los registros de la tabla persona creada en la sección anterior. Ejemplo 95: <?php class BaseDatos { protected $servidor="localhost"; protected $usuario="root"; protected $password=""; protected $link; public $rs; public function conectar() { $this->link=mysql_connect($this->servidor,$this>usuario,$this->password) or die(mysql_error()); mysql_select_db("dbdemo",$this->link) or die(mysql_error()); } public function consultar($sql) { $this->rs=mysql_query($sql) or die(mysql_error()); } } //fin clase class ClaseDatos { protected $plantilla_listado = "lista_bd.php"; protected $data= array(); protected $recset; protected $registro; * public function show() { include ($this->plantilla_listado); } modelo_bd.php public function leer_registro() { $this->registro=mysql_fetch_array($this>recset,MYSQL_ASSOC) or die(mysql_error()); return $this->registro; } Oscar E Capuñay Uceda 212 PHP Orientado a Objetos public function CargarDatos($sentencia) { $objBase = new BaseDatos(); $objBase->conectar(); $objBase->consultar($sentencia); $this->recset=$objBase->rs; } } //fin clase ?> Ejemplo 96: lista_bd.php <table border="1"> <?php while($this->leer_registro()) { ?> <tr> <?php foreach($this->registro as $k => $v){ ?> <td><?php echo $this->registro[$k]?></td> <?php } ?> </tr> <?php } ?> </table> Ejemplo 97: vista_bd.php <html> <head> <title><?php echo $titulo; ?></title> </head> <body> <?php $objData->show(); ?> </body> </html> Ejemplo 98: <?php include ("modelo_bd.php"); $objData = new ClaseDatos(); $sql="select * from persona"; Oscar E Capuñay Uceda 213 controlador_bd.php PHP Orientado a Objetos $titulo = "Lista de personas"; $objData->CargarDatos($sql); include ("vista_bd.php"); ?> Para ver el resultado abrimos en navegador el archivo controlador_bd.php. Figura 174. Resultado de controlador_bd.php Oscar E Capuñay Uceda 214 PHP Orientado a Objetos PDO – PHP Data Object PHP Data Objects (PDO) es una extensión de PHP que utilice controladores para acceder a datos de motores de bases de datos diversos como: MySQL, PostgreSQL, Microsoft SQL Server, Oracle, mSQL, etc. PDO provee una capa de abstracción de datos, con la cual, la codificación depende menos de la base de datos que estemos utilizando, debido a que los métodos tienen el mismo nombre para todas las bases de datos que soporta, es decir, ya no tendremos que escribir mysql_query para ejecutar una sentencia SQL en MySQL y cuando migremos a PostgreSQL tengamos que cambiarla a pg_query. PDO esta disponible desde PHP 5.1, y requiere las nuevas características de programación orientada a objetos que viene desde PHP 5, por lo que no corre en versiones anteriores. Los siguientes controladores están disponibles actualmente: Tabla 20. Controladores PDO Controlador PDO_DBLIB PDO_FIREBIRD PDO_IBM PDO_INFORMIX PDO_MYSQL PDO_OCI PDO_ODBC PDO_PGSQL PDO_SQLITE Base de Datos FreeTDS / Microsoft SQL Server / Sybase Firebird/Interbase 6 IBM DB2 IBM Informix Dynamic Server MySQL 3.x/4.x/5.x Oracle Call Interface ODBC v3 (IBM DB2, unixODBC and win32 ODBC) PostgreSQL SQLite 3 and SQLite 2 Clases predefinidas PDO Representa una conexión entre PHP y un servidor de base de datos. Constructor PDO - construye un nuevo objeto PDO Métodos beginTransaction – inicia una transacción. commit - efectúa la transacción. Oscar E Capuñay Uceda 215 PHP Orientado a Objetos errorCode – retorna un código de error, si ocurre alguno en la base de datos. errorInfo – retorna un arreglo de información del error, si ocurre alguno en la base de datos. exec – ejecuta una sentencia SQL y retorna el número de registros afectados. getAttribute – retorna los atributos de una conexión. lastInsertId – retorna el valor del ID del ultimo registro que fue insertado en la tabla. prepare - prepara una sentencia SQL para su ejecución. query – ejecuta una sentencia SQL y retorna un conjunto de registros. quote – retorna una cadena de texto con comillas para su uso en sentencias SQL. Recomendada para evitar inyección SQL. rollBack - Deshace una transacción setAttribute – establece un atributo para la conexión a una base de datos. PDOStatement Representa una sentencia preparada, luego que la sentencia es ejecutada, un conjunto de registros. Métodos bindColumn - relaciona variable a una columna de salida en un conjunto de registros. bindParam - relaciona una variable PHP a un parámetro en la sentencia preparada. bindValue - binds un valor a un parámetro en la sentencia preparada. closeCursor - cierra el cursor, permitiendo ejecutar nuevamente la sentencia. columnCount - retorna el número de columnas del conjunto de registros. errorCode - retorna un código de error, si lo hay, de la sentencia. errorInfo - retorna un arreglo de información de un error, si lo hay, de la sentencia. execute – ejecuta la sentencia preparada. fetch – lee un registro de un conjunto de registros. Oscar E Capuñay Uceda 216 PHP Orientado a Objetos fetchAll – asigna a un arreglo el contenido de todos los datos de un conjunto de registros. fetchColumn - retorna el dato de una columna en un conjunto de registros. getAttribute – retorna un atributo de un PDOStatement. getColumnMeta – retorna los metadatos de una columna en un conjunto de resultados. nextRowset – retorna el siguiente registro. rowCount - retorna el número de registros afectados por la ejecución de la sentencia SQL. setAttribute – establece un atributo PDOStatement. setFetchMode – establece el modo de lectura de registros de un PDOStatement. Oscar E Capuñay Uceda 217 PHP Orientado a Objetos Conexiones con PDO Para establecer una conexión a una base de datos debemos instanciar la clase PDO e indicar primero el nombre del motor de base de datos al cual nos conectaremos, seguido del nombre del servidor, nombre de la base de datos, usuario y finalmente la contraseña. En el siguiente podemos observar una conexión a MySQL y las siguientes líneas que están comentadas se conectan a Microsoft SQL Server y a PostgreSQL respectivamente. Ejemplo 99: Conexión a MySQL con PDO pdo-connect.php <?php $conn = new PDO('mysql:host=localhost;dbname=dbdemo',"root",""); //$conn = new PDO('mssql:host=localhost;dbname=dbmicro',"sa",""); //$conn = new PDO('pgsql:host=localhost;dbname=dbpos',"postgres","psql"); ?> Ahora veremos una lista simple obtenida de la tabla persona. Ejemplo 100: pdo-lista.php <?php try { include "pdo-connect.php"; foreach ($conn->query('SELECT * from persona') as $registro) { print_r($registro); } $conn = null; //cierre de conexión } catch (PDOException $e) { print "Error!: " . $e->getMessage() . "<br/>"; die(); } ?> Lista de personas con PDO y manejo de errores Oscar E Capuñay Uceda 218 PHP Orientado a Objetos Resultado Web Figura 175. Resultado de pdo-lista.php Ejemplo 101: pdo-listado.php <?php include "pdo-connect.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; $rspersona=$conn->query($sql); ?> <form name="form1" action="pdo-eliminar.php" method="post"> <table> <tr> <th>Eliminar</th> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch()) { ?> <tr> <td><input type="checkbox" name="chkelim[]" value="<?php $registro[idpersona]?>" /></td> <td><?php echo $registro[idpersona]?></td> <td><?php echo $registro[nombres]?></td> <td><?php echo $registro[apellidos]?></td> <td><a href="pdo-editar.php?idpersona=<?php $registro[idpersona]?>">editar</a></td> </tr> <?php Oscar E Capuñay Uceda Listado de registros con PDO, con eliminación múltiple echo echo 219 PHP Orientado a Objetos } $rspersona->closeCursor(); //cerramos resultado de la consulta $conn=null; //cerramos la conexión ?> <tr> <th><input type="submit" value="Eliminar" /></th> <th colspan="4"><input type="button" onclick="location='pdo-nuevo.php'" value="Nuevo" /></th> </tr> </table> </form> Resultado Web Figura 176. Resultado de pdo-listado.php Ejemplo 102: pdo-nuevo.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Nuevo registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pdo-insertar.php"> <table width="80%" border="0" align="center"> <tr> <th colspan="2">Nuevo Registro</th> </tr> <tr> <td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" /></td> Oscar E Capuñay Uceda 220 Inserción de registros con PDO PHP Orientado a Objetos </tr> <tr><td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" /></td> </tr> <tr><td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" /></td> </tr> <tr><td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" /></td> </tr> <tr><th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='mysqli-listado.php'" /></th> </tr> </table> </form> </body> </html> Resultado Web: Figura 177. Resultado de pdo-nuevo.php Ejecución de Sentencias Preparadas con PDO pdo-insertar.php <?php try { include "pdo-connect.php"; $sentencia = $conn->prepare("INSERT INTO persona (nombres, apellidos, email, telefono) VALUES (:nombres, :apellidos, :email, :telefono)"); Oscar E Capuñay Uceda 221 PHP Orientado a Objetos $sentencia->bindParam(':nombres', $_POST[nombres]); $sentencia->bindParam(':apellidos', $_POST[apellidos]); $sentencia->bindParam(':email', $_POST[email]); $sentencia->bindParam(':telefono', $_POST[telefono]); $sentencia->execute(); $conn = null; header("location: pdo-listado.php"); } catch (PDOException $e) { print "Error!: " . $e->getMessage() . "<br/>"; die(); } ?> Ejemplo 103: Eliminación múltiple de registros con PDO pdo-eliminar.php <?php include "pdo-connect.php"; $sentencia=$conn->prepare("delete from persona where idpersona=:id"); $sentencia->bindParam(':id',$valor); foreach($_POST[chkelim] as $indice => $valor) { $sentencia->execute(); } header("location: pdo-listado.php"); ?> Ejemplo 104: pdo-editar.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <?php include "pdo-connect.php"; $sql="select * from persona where idpersona=" . $_GET[idpersona]; $rspersona=$conn->query($sql); $registro=$rspersona->fetch(); ?> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Edición de registro</title> </head> <body> <form id="form1" name="form1" method="post" action="pdo-actualizar.php"> Oscar E Capuñay Uceda 222 Edición de registros con PDO. PHP Orientado a Objetos <input type="hidden" name="idpersona" value="<?php echo $_GET[idpersona]?>"> <table width="80%" border="0" align="center"> <tr><th colspan="2">Edición de Persona</th> </tr> <tr><td>Nombres</td> <td><input name="nombres" type="text" id="nombres" size="50" maxlength="50" value="<?php echo $registro[nombres]?>" /></td></tr> <tr><td>Apellidos</td> <td><input name="apellidos" type="text" id="apellidos" size="50" maxlength="50" value="<?php echo $registro[apellidos]?>" /></td></tr> <tr><td>E-Mail</td> <td><input name="email" type="text" id="email" size="50" maxlength="100" value="<?php echo $registro[email]?>"/></td></tr> <tr><td>Teléfono</td> <td><input name="telefono" type="text" id="telefono" maxlength="15" value="<?php echo $registro[telefono]?>"/></td></tr> <tr><th colspan="2"><input name="Submit" type="submit" class="boton" value="Guardar" /> <input name="Submit2" type="button" class="boton" value="Cancelar" onclick="location='pdo-listado.php'" /></th></tr> </table> </form> <?php $rspersona->closeCursor(); $conn=null; ?> </body> </html> Resultado Web: Figura 178. Resultado de pdo-editar.php pdo-actualizar.php <?php include "pdo-connect.php"; Oscar E Capuñay Uceda 223 PHP Orientado a Objetos $sentencia = $conn->prepare("UPDATE persona SET nombres=:nombres, apellidos=:apellidos, email=:email, telefono=:telefono where idpersona=:idpersona"); $sentencia->bindParam(':idpersona', $_POST[idpersona]); $sentencia->bindParam(':nombres', $_POST[nombres]); $sentencia->bindParam(':apellidos', $_POST[apellidos]); $sentencia->bindParam(':email', $_POST[email]); $sentencia->bindParam(':telefono', $_POST[telefono]); $sentencia->execute(); $conn = null; header("location: pdo-listado.php"); ?> Oscar E Capuñay Uceda 224 Seguridad Web VII. Seguridad Web Las aplicaciones Web por lo general están en línea y eso las expone a la visita de usuarios que llegan con objetivos distintos, uno de ellos el hacerse de fama violando la seguridad de sitios Web, valiéndose de diferentes estrategias y herramientas. Construir una aplicación completamente segura es imposible por tal motivo es imprescindible conocer y establecer barreras contra estos ataques y por otro lado desarrollar las aplicaciones evitando cometer errores en la codificación desde el punto de vista lógico, que nos puedan causar problemas de seguridad posteriormente, todo esto minimizará en lo posible la posibilidad de violación en la seguridad del sistema, tal como se menciona en las recomendaciones generales de seguridad en PHP: “Cuando realice pruebas, tenga en mente que no será capaz de probar todas las diferentes posibilidades, incluso para las páginas más simples. Los datos de entrada que usted puede esperar en sus aplicaciones no necesariamente tendrán relación alguna con el tipo de información que podría ingresar un empleado disgustado, un cracker con meses de tiempo entre sus manos, o un gato doméstico caminando sobre el teclado. Es por esto que es mejor observar el código desde una perspectiva lógica, para determinar en dónde podrían introducirse datos inesperados, y luego hacer un seguimiento de cómo esta información es modificada, reducida o amplificada”.1 A continuación veremos algunos temas sobre la seguridad en el desarrollo Web. Seguridad en el Sistema de archivos El sistema de archivos en todo sistema operativo es importante debido a que a través de él se puede violar la seguridad de un computador, por ejemplo a continuación veremos un caso en el que un usuario puede borrar un archivo importante del sistema operativo UNIX o LINUX debido a que no se tomaron ciertas medidas de precaución. Ejemplo 105: Borrar un archivo de un usuario Este caso presenta el supuesto que un usuario ingresa su nombre y el nombre de su archivo que desea eliminar de su directorio personal a través de la Web. El usuario ingresará los datos en un formulario y los enviará al siguiente archivo PHP. <?php // datos enviados a través del formulario $usuario = $_POST['nombre_usuario']; 1 http://www.php.net/manual/es/security.general.php 225 Oscar E Capuñay Uceda Seguridad Web $archivo = $_POST['archivo']; //generamos la ruta para el borrado del archivo – directorio del usuario $directorio = "/home/$usuario"; //orden de eliminación del archivo unlink("$directorio/$archivo"); echo "El archivo: $archivo ha sido eliminado!"; ?> Si alguien desea atacar el sistema de archivos podría escribir en el formulario datos para eliminar por ejemplo el archivo de passwords del sistema operativo, en el caso que PHP tuviera acceso de root. Ejemplo 106: Ataque mediante el borrado de archivos <?php // Para el caso del nombre del usuario enviamos: "../etc" // Para el caso del nombre del archivo enviamos: "passwd" $usuario = $_POST['nombre_usuario']; $archivo = $_POST['archivo']; //generando la ruta del directorio obtendríamos lo siguiente: "/home/../etc" $directorio = "/home/$nombre_usuario"; // El archivo que se va a eliminar es: "/home/../etc/passwd" unlink("$directiorio/$archivo"); echo "El archivo ha sido eliminado!"; ?> Para mejorar el control y la validación de los datos enviados por el usuario utilizaremos funciones que nos permitan verificar el tipo de datos correcto. Por ejemplo: if (!ctype_alnum($nombre_usuario) || !preg_match('/^(?:[a-z0-9_]|\.(?!\.))+$/iD', $archivo_usuario)) { die("Nombre de usuario o archivo incorrecto"); } ctype_alnum: es una función que devuelve TRUE cuando la cadena contiene solamente caracteres alfanuméricos, es decir, letras y/o números. preg_match: es una función que realiza una comparación en base a una expresión regular. Oscar E Capuñay Uceda 226 Seguridad Web Seguridad en Base de datos La seguridad de las aplicaciones Web también pasa por la etapa de diseño de la base de datos, al momento de establecer los tipos de usuarios y los privilegios que cada uno tendrá, es recomendable hacer esto y no dejar todo el control en la lógica de la aplicación. Respecto a la conexión con la base de datos es posible utilizar el protocolo SSL para encriptar la comunicación entre el servidor y los clientes, pero solamente cifra la información en el medio, y no cuando es almacenada en la base de datos. Para el caso del almacenamiento de contraseñas en la base de datos recomiendo el uso de uno de los resúmenes criptográficos más utilizados en la actualidad: MD5. En PHP el hash MD5 (acrónimo de Message-Digest Algorithm 5, Algoritmo de Resumen del Mensaje 5) puede ser utilizado a través de la función con el mismo nombre: md5().MD5 es uno de los algoritmos de reducción criptográficos diseñados por el profesor Ronald Rivest del MIT (Massachusetts Institute of Technology, Instituto Tecnológico de Massachusetts). Fue desarrollado en 1991 como reemplazo del algoritmo MD4 después de que Hans Dobbertin descubriese su debilidad. Veamos un ejemplo: Ejemplo 107: md5.php <?php $texto="miclavedeacceso"; $cifrado=md5($texto); echo "mi clave cifrada es:".$cifrado; // el texto cifrado con MD5 de 128bits genera una cadena de 32 caracteres de longitud. ?> Resultado Web: Md5 Figura 179. Resultado de md5.php Una cualidad de este algoritmo es que no tiene función para descifrar lo que lo hace mas seguro que otros debido a que un administrador de base de datos no podría, por ejemplo, ver las claves de los usuarios. Oscar E Capuñay Uceda 227 Seguridad Web Desarrollaremos ahora un formulario para el acceso de usuarios teniendo como supuesto que la tabla de usuarios se llama: “user”, y los campos donde están registrados los nombres de usuario y clave de acceso son: “user_nombre” y “user_clave” respectivamente. El script para este caso sería: Ejemplo 108: Script para acceso de usuarios acceso-md5.php <?php include "conexion.php"; //conexion a la BD //datos provenientes del formulario $usuario=$_POST[txtusuario]; $clave=$_POST[txtclave]; $clave_cifrada=md5($clave); $sql="select * from user user_clave='".$clave_cifrada."'"; where user_nombre='".$usuario."' and $rs=mysql_query($sql) or die(mysql_error()); //si existe un usuario con dichos datos if(mysql_num_rows($rs)==1) echo "Datos correctos"; else echo "Datos incorrectos"; ?> Con este script no sería suficiente para dar la seguridad adecuada a nuestra aplicación Web. A continuación veremos otro punto importante que debemos tomar en cuenta. Oscar E Capuñay Uceda 228 Seguridad Web Inyección SQL Una consulta SQL no es una orden confiable a la que no se le debe prestar la atención debida, sino por el contrario es en la que más cuidado debemos tener puesto que a través de ella se puede burlar los controles de acceso a cualquier sistema Web e incluso permitir el acceso a comandos del sistema operativo. La Inyección de comandos SQL es una técnica utilizada para alterar comandos SQL definidos en una aplicación con la finalidad de mostrar datos, sobrescribirlos, eliminarlos o ejecutar órdenes que no fueron establecidas por el desarrollador. La manera de realizar las alteraciones es a través de los datos enviados por un usuario y su combinación con parámetros utilizados en las sentencias SQL. A continuación veremos ejemplos que nos ayudarán a ver estos casos con mayor detalle. Ejemplo 109: <?php $sql="SELECT zona=’$zona’"; nombre, apellidos, direccion FROM cliente WHERE Inyección SQL en una sentencia SELECT $result = mysql_query($sql); ?> En este ejemplo la variable $zona es enviada por el usuario. Utilizando la variable $zona enviaremos la siguiente cadena: ‘ union select * from usuario -En la cadena podemos ver una comilla simple ( ‘ ) al inicio y doble guión ( -- ) al final. Si reemplazamos esta cadena en lugar de la variable $zona veremos que el resultado de la consulta mostrará todos los datos registrados en la tabla usuario. Utilizando como base el ejemplo anterior haremos inyección SQL en una página con un listado que utiliza hipervínculos para la paginación de resultados. Ejemplo 110: Paginación de resultados con Inyección SQL inyeccion01.php <?php include "mysqli-conexion.php"; //incluimos la conexion $cantidad=2; //numero de registros por pagina //verificamos si existe la variable Oscar E Capuñay Uceda 229 Seguridad Web if(!isset($_GET[p])) $_GET[p]=0; //hallamos el total de registros $sql="select * from persona"; $rspersona=$mysqli->query($sql) or die($mysqli->error); $nr=$rspersona->num_rows; //paginación de resultados $sql="select idpersona,nombres,apellidos from persona limit " . $_GET[p] . ",$cantidad"; $rspersona=$mysqli->query($sql) or die($mysqli->error); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> <td><?php echo "$registro->apellidos"?></td> <td><a href="mysqli-editar.php?idpersona=<?php echo "$registro>idpersona"?>">editar</a></td> <td><a href="mysqli-eliminar.php?idpersona=<?php echo "$registro>idpersona"?>">eliminar</a></td> </tr> <?php } ?> <tr><td colspan="5">Página: <?php for($i=1;$i<=ceil($nr/$cantidad);$i++) { $inicio=$cantidad*($i-1); echo "<a href='?p=$inicio'>$i</a> "; } ?> </td></tr> </table> <br> <a href="formulario08.html">Agregar Registro</a> <?php $rspersona->close(); //cerramos resultado de la consulta $mysqli->close(); //cerramos la conexión ?> Oscar E Capuñay Uceda 230 Seguridad Web Resultado Web: Figura 180. Resultado de inyeccion01.php Ahora hagamos clic en la página 2. (Ver la dirección URL) Figura 181. Nuevo resultado de inyeccion01.php Podemos ver en la imagen anterior que se envía a la página una variable p con el número de registro con el que inicia la página que se va a mostrar. Ahora aprovecharemos esta variable para inyectar algunas cadenas SQL valiéndonos de la función urlencode() para generar las cadenas. Primero tendremos que hacer algunas suposiciones como por ejemplo que la base de datos es MySQL y que se esta usando la orden LIMIT para la paginación de resultados y que el inicio es la variable p y que a continuación habrá una coma y luego la cantidad de registros en la sentencia SQL en la que será reemplazado. Parte de la cadena sería: LIMIT (la variable p),(cantidad) entonces para terminar correctamente la cadena enviaremos junto con la variable p una coma y un número que será la cantidad de registros y luego insertaremos UNION select * from usuario Cadena a insertar: 0,2 union select * from usuario -Aplicando urlencode tenemos: 0%2C2+union+select+%2A+from+usuario+--+ Esta cadena que hemos generado será el valor de p. Veremos que sucede: Oscar E Capuñay Uceda 231 Seguridad Web Figura 182. Tercer resultado de inyeccion01.php Nos aparece un mensaje que nos dice que la sentencia SELECT tiene diferente número de columnas (campos). Por ahora esto sólo nos dice que hemos podido inyectar una sentencia SELECT adicional pero nos queda saber el número de campos de la consulta del listado y luego hacer coincidir nuestro SELECT adicional con dicha cantidad. Ahora supondremos que la cantidad de campos que vemos en el listado es la cantidad del SELECT de la sentencia para el listado, ahora debemos probar agregando campos al SELECT inyectado. Agregaremos un campo al select inyectado. Cadena a insertar: 0,2 union select *,1 from usuario -Aplicando urlencode: 0%2C2+union+select+%2A%2C1+from+usuario+--+ La cadena URL sería: Figura 183. URL con inyección SQL Ahora tenemos: Figura 184. Resultado de la inyección SQL Podemos decir que el número de campos coincidió y además el nombre de la tabla. Sabiendo ahora lo que puede ocurrir, debemos prevenir este tipo de ataque utilizando una función que se encargue de anular cualquier cadena que Oscar E Capuñay Uceda 232 Seguridad Web pretenda inyectar SQL. Para el caso anterior debemos analizar y verificar que el valor de la variable p sea un número obligatoriamente, entonces añadimos la línea: if(!is_numeric($_GET[p])) $_GET[p]=0; is_numeric es una función que devuelve TRUE si el valor de la variable es numérico. En caso que no sea numérico le asignamos CERO, según la línea de código anterior. inyeccion02.php <?php include "mysqli-conexion.php"; //incluimos la conexion $cantidad=2; //numero de registros por pagina //verificamos si existe la variable if(!isset($_GET[p])) $_GET[p]=0; //hallamos el total de registros $sql="select * from persona"; $rspersona=$mysqli->query($sql) or die($mysqli->error); $nr=$rspersona->num_rows; //verificamos si es p tiene valor numérico if(!is_numeric($_GET[p])) $_GET[p]=0; //paginación de resultados $sql="select idpersona,nombres,apellidos from persona limit " . $_GET[p] . ",$cantidad"; $rspersona=$mysqli->query($sql) or die($mysqli->error); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> Oscar E Capuñay Uceda 233 Seguridad Web <td><?php echo "$registro->apellidos"?></td> <td><a href="mysqli-editar.php?idpersona=<?php >idpersona"?>">editar</a></td> <td><a href="mysqli-eliminar.php?idpersona=<?php >idpersona"?>">eliminar</a></td> </tr> <?php } ?> <tr><td colspan="5">Página: <?php for($i=1;$i<=ceil($nr/$cantidad);$i++) { $inicio=$cantidad*($i-1); echo "<a href='?p=$inicio'>$i</a> "; } ?></td></tr> </table> <br> <a href="formulario08.html">Agregar Registro</a> <?php $rspersona->close(); //cerramos resultado de la consulta $mysqli->close(); //cerramos la conexión ?> Con esta modificación ejecutaremos la misma URL: echo echo "$registro"$registro- Figura 185. Evitando la inyección SQL Resultado Web: Figura 186. Resultado sin inyección realizada Podemos ver ahora que la inyección SQL se evitó exitosamente. Pero los listados no solamente pueden ser utilizados para la Inyección SQL sino que los formularios de acceso o logeo de usuarios quizá sean los más propensos a estos ataques. Para ver este caso más de cerca primero debemos tener tabla usuario, para este ejemplo consideremos dos campos Oscar E Capuñay Uceda 234 Seguridad Web para esta tabla: login (nombre del usuario) y clave (password del usuario) y luego registramos algunos registros. Figura 187. Tabla usuario Ahora haremos un formulario para el acceso de usuarios. formulario09.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Acceso al sistema</title> </head> <body> <form id="form1" name="form1" method="post" action="inyeccion03.php"> <table width="50%" border="0" align="center"> <tr> <th colspan="2">Acceso al sistema</th> </tr> <tr> <td>Usuario</td> <td><input name="usuario" type="text" id="usuario" maxlength="20" /></td> </tr> <tr> <td>Password</td> <td><input name="passw" type="password" id="passw" maxlength="40" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Entrar" /> </th> </tr> </table> </form> </body> </html> Oscar E Capuñay Uceda 235 Seguridad Web Resultado Web: Figura 188. Resultado de formulario09.html El formulario anterior envía los datos a una página llamada inyeccion03.php. Veamos ahora el archivo inyeccion03.php quien se encargará de controlar el acceso de los usuarios. inyeccion03.php <?php $sql="SELECT * from usuario WHERE login='" . $_POST[usuario] . "' and clave='" . $_POST[passw] . "'"; //imprimir sentencia SQL echo $sql; ?> Con el script anterior imprimiremos la sentencia SQL que se crea cuando enviamos los datos del formulario. Escribiremos dos datos de ejemplo y los enviaremos: Figura 189. Resultado de inyeccion03.php La cadena resultante es la concatenación de la sentencia SQL con los datos escritos en el formulario (user, passuser). Pero ahora veamos lo que se puede hacer para evitar un control correcto de los usuarios. Analicemos la siguiente orden: Oscar E Capuñay Uceda 236 Seguridad Web SELECT * from usuario WHERE login='loquesea' AND password=’’ OR ‘’=’’ Si logramos generar una cadena como la anterior entonces no necesitaremos tener un nombre de usuario correcto ni su respectiva clave puesto que la condición (WHERE) siempre resultará verdadera y por lo tanto nos devolverá todos los registros de la tabla usuario. Pero para llegar a generar la última cadena debemos partir de la que suponemos se ha escrito en el script, en este caso la que está en nuestro archivo inyeccion03.php. Cadena inicial: $sql="SELECT * from usuario WHERE login='" . $_POST[usuario] . "' and clave='" . $_POST[passw] . "'"; Ahora a $_POST[usuario] le podemos dar cualquier valor, en este caso: loquesea y a $_POST[passw] le daremos el valor: ' OR ''=' , con estos valores resultaría: SELECT * from usuario WHERE login='loquesea' AND password=’’ OR ‘’=’’ Probemos esto en el navegador con nuestro formulario09.html Figura 190. Logeo con inyección SQL Podemos tener dos resultados según la configuración de las comillas mágicas gpc (Get/Post/Cookie) de PHP: Cuando magic_quotes se encuentra activo, todos los caracteres ' (comillasimple), " (comilla doble), \ (barra invertida) y NULs son escapados con una barra invertida automáticamente como se ve a continuación y por lo tanto la inyección SQL no tendría éxito. Figura 191. Nuevo resultado de inyeccion03.php Oscar E Capuñay Uceda 237 Seguridad Web Pero si magic_quotes se encuentra inactivo tendremos el siguiente resultado: Figura 192. Tercer resultado de inyeccion03.php En este resultado podemos ver que la inyección si se ejecutaría exitosamente y el atacante podría ingresar al sistema sin un nombre de usuario ni password válido. Podemos utilizar la función: get_magic_quotes_gpc la cual devuelve 0 si las comillas mágicas están deshabilitadas, 1 de lo contrario para hacer la verificación en tiempo de ejecución y la función addslashes. Con el formulario 10 probaremos un nuevo script que utilice estas dos últimas funciones, el formulario 10 solo varía en el valor del atributo action de la etiqueta form. formulario10.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Acceso al sistema</title> </head> <body> <form id="form1" name="form1" method="post" action="comillasmagicas.php"> <table width="50%" border="0" align="center"> <tr> <th colspan="2">Acceso al sistema</th> </tr> <tr> <td>Usuario</td> <td><input name="usuario" type="text" id="usuario" maxlength="20" /></td> </tr> <tr> <td>Password</td> <td><input name="passw" type="password" id="passw" maxlength="40" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Entrar" /> </th> Oscar E Capuñay Uceda 238 Seguridad Web </tr> </table> </form> </body> </html> Una vez cargado el formulario, ingresamos los datos de prueba. Resultado Web: Figura 193. Resultado de formulario10.html Ejemplo 111: get_magic_quotes_gpc y addslashes comillas-magicas.php <?php if (!get_magic_quotes_gpc()) { $password = addslashes($_POST['passw']); } else { $password = $_POST['passw']; } $sql="SELECT * from usuario WHERE login='" . $_POST[usuario] . "' and clave='" . $password . "'"; //imprimir sentencia SQL echo $sql; ?> Veamos ahora el resultado: Figura 194. Resultado de comillas-magicas.php Oscar E Capuñay Uceda 239 Seguridad Web Podemos notar que se le agrega un \ (slash) a cada comilla, sin importar la configuración de las comillas mágicas, el script anterior no ayudaría a evitar la inyección SQL. Con este script mejoramos el control del acceso a usuarios, pero cabe resaltar una función creada para evitar este tipo de inyecciones SQL en servidores MySQL, llamada: mysqli_real_escape_string (programación orientada a objetos) o mysql_real_escape_string (programación procedimental). Veamos un ejemplo con estilo orientado a objetos: Ejemplo 112: mysqli_real_escape_string formulario11.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Acceso al sistema</title> </head> <body> <form id="form1" name="form1" method="post" action="inyeccion04.php"> <table width="50%" border="0" align="center"> <tr> <th colspan="2">Acceso al sistema</th></tr> <tr> <td>Usuario</td> <td><input name="usuario" type="text" id="usuario" maxlength="20" /></td> </tr> <tr> <td>Password</td> <td><input name="passw" type="password" id="passw" maxlength="40" /></td> </tr> <tr> <th colspan="2"><input name="Submit" type="submit" class="boton" value="Entrar" /> </th> </tr> </table> </form> </body> </html> inyeccion04.php <?php //incluimos la conexion include "mysqli-conexion.php"; $usuario =$mysqli->real_escape_string($_POST['usuario']); $password=$mysqli->real_escape_string($_POST['passw']); $sql="SELECT * from usuario WHERE login='$usuario' clave='$password'"; //imprimir sentencia SQL Oscar E Capuñay Uceda and 240 Seguridad Web echo $sql; ?> Resultado Web: Figura 195. Resultado de inyeccion04.php Notamos que el control de la inyección SQL resultó exitoso con la función o método real_escape_string el cual protege de caracteres especiales en una cadena para ser usada en una sentencia SQL, tomando en cuenta el conjunto de caracteres para la conexión. Oscar E Capuñay Uceda 241 Seguridad Web Sesiones Las sesiones en PHP son un mecanismo para preservar datos a lo largo de varios accesos lo que permite construir aplicaciones Web más personalizadas. A cada visitante que accede a su Web se le asigna un identificador único, llamado "session id" (identificador de sesión). Éste se almacena en una cookie por parte del usuario o se propaga en la URL. Las Cookies sirven para almacenar datos en el navegador del usuario. Se pueden poner cookies usando la función setcookie(). Las Cookies son parte de la cabecera HTTP, por tanto la función setcookie() debe ser llamada antes de que se produzca cualquier salida al navegador. El soporte de las sesiones le permite registrar un número arbitrario de variables que se conservarán en las siguientes peticiones. Cuando un visitante acceda a su Web, PHP comprobará automáticamente (si session.auto_start está puesto a 1) o cuando usted lo especifique (de forma explícita mediante session_start() o implícita a través de session_register()) si se le ha enviado un "session id" específico con su petición, en cuyo caso se recrean las variables que se habían guardado anteriormente. Todas las variables registradas son almacenadas tras finalizar la petición. Las variables que están indefinidas se marcan como no definidas. En los subsiguientes accesos, no estarán definidas por el módulo de sesiones a menos que el usuario las defina más tarde. Las opciones de configuración track_vars y register_globals influyen notablemente en la forma en que las variables de la sesión se almacenan y restauran. A partir de PHP 4.0.3, track_vars siempre está activado. A partir de PHP 4.1.0, $_SESSION está disponible como variable global, al igual que $_POST, $_GET, $_REQUEST y demás. Al contrario que $HTTP_SESSION_VARS, $_SESSION siempre es global. Por tanto, no se debe usar global para $_SESSION. Si track_vars está activado y register_globals está desactivado, sólo los miembros del vector asociativo global $HTTP_SESSION_VARS pueden ser registrados como variables de la sesión. Las variables restauradas de la sesión sólo estarán disponibles en el vector $HTTP_SESSION_VARS. Se recomienda usar $_SESSION (o $HTTP_SESSION_VARS con PHP 4.0.6 o inferior) por seguridad y para hacer el código más legible. Con $_SESSION o $HTTP_SESSION_VARS, no es necesario usar las funciones session_register() / session_unregister() / session_is_registered(). Los usuarios pueden acceder a una variable de la sesión como si se tratase de una variable normal. Si register_globals está activado, todas las variables globales pueden ser registradas como variables de la sesión, y las variables de la sesión serán restauradas a sus correspondientes variables globales. Como PHP debe Oscar E Capuñay Uceda 242 Seguridad Web saber qué variables globales están registradas como variables de la sesión, los usuarios deben registrar las variables con la función session_register(), mientras que con $HTTP_SESSION_VARS/$_SESSION no es necesario usar session_register(). Si está usando $HTTP_SESSION_VARS/$_SESSION y desactiva register_globals, no use session_register(), session_is_registered() ni session_unregister(). Se recomienda desactivar register_globals por motivos de seguridad y rendimiento. Ejemplo 113: ingreso01.php <form action="verifica01.php" method="post"> <table width="70%" border="0" cellspacing="1" align="center"> <caption> Acceso al sistema </caption> Ingreso de un usuario a la aplicación cellpadding="2" <tr> <td>Usuario</td> <td><input type="text" name="txtusuario" id="txtusuario" maxlength="20"> </td> </tr> <tr> <td>Password</td> <td><input name="txtclave" type="password" id="txtclave" maxlength="50"></td> </tr> <?php if($_GET['error']==1) { ?> <tr><td colspan="2">Datos Incorrectos</td></tr> <?php } ?> <tr> <th colspan="2"><input type="submit" name="Submit" value="Entrar"></th> </tr> </table> </form> <?php echo "Su dirección IP es: ".$_SERVER['REMOTE_ADDR']; ?> <br> <?php echo "Navegador: ".$_SERVER['HTTP_USER_AGENT']; ?> Oscar E Capuñay Uceda 243 Seguridad Web <br> <?php echo "Idioma: ".$_SERVER['HTTP_ACCEPT_LANGUAGE']; ?> Resultado Web: Figura 196. Resultado de ingreso01.php Ejemplo 114: verifica01.php Verifica datos del usuario <?php include "mysqli-conexion.php"; //incluimos la conexion //Proteger de caracteres especiales a la sentencia SQL $usuario =$mysqli->real_escape_string($_POST['txtusuario']); $clave =$mysqli->real_escape_string($_POST['txtclave']); //ciframos la clave escrita por el usuario para compararla en la BD $clave=md5($clave); //sentencia sql $sql="select * from usuario where login='$usuario' and clave='$clave'"; //ejecutamos la consulta $rsusuario=$mysqli->query($sql) or die($mysqli->error); if($rsusuario->num_rows==1) { //datos correctos $reg=$rsusuario->fetch_object(); session_start(); $_SESSION['idusuario']=$reg->idusuario; $_SESSION['usuario']=$reg->usuario; Oscar E Capuñay Uceda 244 Seguridad Web $_SESSION['tipo']=$reg->tipo; } else header("location: ingreso01.php?error=1"); ?> Probamos con datos incorrectos. Figura 197. Ingreso01.php con datos incorrectos Figura 198. Logeo incorrecto La aplicación nos devuelve un mensaje de “Datos Incorrectos”. Oscar E Capuñay Uceda 245 Seguridad Web Autentificación HTTP con PHP Las características de autentificación HTTP en PHP solo están disponibles cuando se está ejecutando como un módulo en Apache y hasta ahora no lo están en la versión CGI. En un script PHP como módulo de Apache, se puede usar la función header() para enviar un mensaje de "Autentificación requerida" al navegador cliente haciendo que muestre una ventana de entrada emergente con nombre de usuario y contraseña. Una vez que el usuario ha rellenado el nombre y la contraseña, la URL que contiene el script PHP será llamada de nuevo con las variables predefinidas PHP_AUTH_USER, PHP_AUTH_PW, y AUTH_TYPE asignadas con el nombre de usuario, la contraseña y el tipo de autentificación respectivamente. Estas variables predefinidas se pueden encontrar en las matrices $_SERVER y $HTTP_SERVER_VARS. Sólo autentificación "Básica" está soportada en este momento. Ejemplo 115: auth01.php <?php if (!isset($_SERVER['PHP_AUTH_USER'])) { header('WWW-Authenticate: Basic realm="Sistema Web"'); header('HTTP/1.0 401 Unauthorized'); echo 'Operación cancelada'; exit; } else { echo "<p>Bienvenido {$_SERVER['PHP_AUTH_USER']}.</p>"; echo "<p>Acceso al sistema con password: {$_SERVER['PHP_AUTH_PW']}.</p>"; } ?> Resultado Web: Autenticación HTTP Figura 199. Autenticación http con PHP Oscar E Capuñay Uceda 246 Seguridad Web Si cancelamos la operación tenemos el siguiente resultado en el navegador, según lo establecido en el código. Figura 200. Resultado de auth01.php Si ingresamos datos y presionamos Aceptar tendremos: Figura 201. Autenticación con datos correctos Figura 202. Resultado de auth01.php con datos correctos Oscar E Capuñay Uceda 247 Seguridad Web Login Ahora que ya tenemos el script de autenticación de usuarios, desarrollaremos el script para verificar el nombre de usuario y contraseña en la base de datos. Utilizaremos una tabla usuario, con campos que contengan el nombre y contraseña del usuario. Figura 203. Tabla usuario Script sql: CREATE TABLE `usuario` ( `idusuario` int(11) NOT NULL auto_increment, `login` varchar(10) collate latin1_spanish_ci NOT NULL, `clave` varchar(32) collate latin1_spanish_ci NOT NULL, PRIMARY KEY (`idusuario`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_spanish_ci AUTO_INCREMENT=1; Una vez implementada la base de datos ingresaremos algunos registros para los casos de prueba necesarios para probar el script que desarrollaremos. Figura 204. registro de un usuario Oscar E Capuñay Uceda 248 Seguridad Web Como podemos observar en la figura anterior, para ingresar un nuevo registro debemos aplicar la función md5 a la contraseña del usuario. Ahora desarrollaremos el script de logeo de usuarios. Para ello podremos usar como mecanismo de ingreso de datos el script de autenticación desarrollado en el tema anterior o usar un formulario HTML como el siguiente: Ejemplo 116: entrar.php <HTML> <HEAD> <TITLE>Login</TITLE> </HEAD> <BODY> <form name="form1" action="logeo.php" method="post"> <table align="center" width="50%"> <tr><th colspan="2">Ingreso al sistema</th></tr> <tr><td>Usuario</td> <td><input type="text" name="txtusuario"></td></tr> <tr><td>Password</td> <td><input type="password" name="txtclave"></td></tr> <tr><th colspan="2"><input type="submit" value="Entrar"></th></tr> </table> <?php if($_GET['error']==1) echo "Datos Incorrectos"; if($_GET['error']==2) echo "Debe logearse"; ?> </form> </BODY> </HTML> Resultado Web: Formulario para el logeo de usuarios Figura 205. Resultado de entrar.php Oscar E Capuñay Uceda 249 Seguridad Web Ejemplo 117: logeo.php <?php include "mysqli-conexion.php"; $usuario=$mysqli->real_escape_string($_POST['txtusuario']); $clave=md5($_POST['txtclave']); $sql="select * from usuario where login='$usuario' and clave='$clave'"; $rsusuario=$mysqli->query($sql) or die($mysqli->error); if($rsusuario->num_rows==1) { $registro=$rsusuario->fetch_object(); session_start(); $_SESSION['sidusuario']= $registro->idusuario; $_SESSION['susuario']= $usuario; header("location: mysqli-listado-logeado.php"); } else header("location: entrar.php?error=1"); ?> En este script utilizamos el método real_escape_string. Esta función es usada para crear una cadena SQL sin inyección SQL. Los caracteres codificados son NULL (ASCII 0), \n, \r, \, ', ", y Control-Z. Además usamos la función md5 para cifrar la clave escrita en el formulario y compararla con la cadena cifrada guardada en la base de datos. Si el número de registros es 1 (uno), significa que los datos son correctos y pertenecen a uno y solo un usuario (no pueden haber varios usuarios con el mismo nombre). Por lo que debemos iniciar una sesión utilizando la función session_start. El apoyo que PHP proporciona para las sesiones consiste en una forma de conservar ciertos datos a lo largo de los subsiguientes accesos, lo cual le permite construir aplicaciones más personalizadas e incrementar el atractivo de su sitio Web. Utilizaremos también, al array $_SESSION[] para registrar las variables de sesión de nuestra aplicación, en este caso específico, para registrar el identificador del usuario (idusuario) y su nombre de usuario (usuario). A partir de PHP 4.1.0, $_SESSION está disponible como variable global, al igual que $_POST, $_GET, $_REQUEST y demás. Al contrario que $HTTP_SESSION_VARS, $_SESSION siempre es global. Por tanto, no se debe usar global para $_SESSION. Cuando los datos ingresados son incorrectos, retornará a la página inicial, de lo contrario el script redirecciona el navegador hacia el listado de personas (archivo: mysqli-listado.php), el cual, tiene dos nuevas líneas de código con respecto al ejemplo 76. Logeo de usuarios Oscar E Capuñay Uceda 250 Seguridad Web Resultado Web cuando los datos son incorrectos Figura 206. Resultado de entrar.php con datos incorrectos Si alguien quisiera ingresar a nuestro listado sin logearse podría escribir directamente la dirección de la página y lo podría hacer, pero ahora que hemos iniciado una sesión y hemos registrado algunas variables podremos controlar dicha acción y obligar a los usuarios a logearse antes de acceder a ciertas páginas. Veamos a continuación cuál sería la lógica del script. Ejemplo 118: Verifica si el usuario se ha logeado mysqli-listado-logeado.php <?php session_start(); if(!isset($_SESSION['sidusuario'])) header("location: entrar.php?error=2"); include "mysqli-conexion.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); echo "Usuario:" . $_SESSION['susuario']; ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>Editar</th> <th>Eliminar</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> <td><?php echo "$registro->apellidos"?></td> Oscar E Capuñay Uceda 251 Seguridad Web <td><a href="mysqli-editar.php?idpersona=<?php echo >idpersona"?>">editar</a></td> <td><a href="mysqli-eliminar.php?idpersona=<?php echo >idpersona"?>">eliminar</a></td> </tr> <?php } $rspersona->close(); //cerramos resultado de la consulta $mysqli->close(); //cerr=amos la conexión ?> </table> <br> <a href="formulario08.html">Agregar Registro</a> Resultado Web: "$registro"$registro- Figura 207. Resultado de mysqli-listadologeado.php En este script al iniciar la sesión (session_start()) podremos acceder a todas las variables de sesión y eso nos permitirá verificar si el usuario se ha logeado y lo haremos comprobando si existe la variable de sesión que se registra en el archivo logeo.php cuando los datos son correctos. En adelante, a toda página en la que el usuario haya tenido que identificarse se le debe insertar las primeras líneas escritas en el script. session_start(); if(!isset($_SESSION['sidusuario'])) header("location: entrar.php?error=2"); Oscar E Capuñay Uceda 252 Seguridad Web CAPTCHA Este nombre proviene del acrónimo de: Completely Automatic Public Turing Test to Tell Computers and Humans Apart, que traducido al español significa: Prueba de Turing pública y automática para diferenciar a máquinas y humanos. Se trata de una prueba desafío-respuesta utilizada en computación para determinar cuándo el usuario es o no humano. El término se empezó a utilizar en el año 2000 por Luis von Ahn, Manuel Blum y Nicholas J. Hopper de la Carnegie Mellon University, y John Langford de IBM. La típica prueba consiste en que el usuario introduzca un conjunto de caracteres que se muestran en una imagen distorsionada que aparece en pantalla. Se supone que una máquina no es capaz de comprender e introducir la secuencia de forma correcta por lo que solamente el humano podría hacerlo. Como el test es controlado por una máquina en lugar de un humano como en la Prueba de Turing, también se denomina Prueba de Turing Inversa. Los CAPTCHAs son utilizados para evitar que robots, también llamados spambots, puedan utilizar ciertos servicios. Por ejemplo, para que no puedan participar en encuestas, registrarse para usar cuentas de correo electrónico (o su uso para envío de correo basura) o, más recientemente, para evitar que correo basura pueda ser enviado por un robot (el remitente debe pasar el test antes de que se entregue al destinatario). [8] El sistema CAPTCHA tiene las siguientes características por definición: • Son completamente automatizados, es decir, no es necesario ningún tipo de mantenimiento / intervención humana para su realización. Esto supone grandes beneficios en cuanto a fiabilidad y coste. • El algoritmo utilizado es público. De esta forma la ruptura de un captcha pasa a ser un problema de inteligencia artificial y no la ruptura de un algoritmo secreto. A continuación construiremos con PHP un CAPTCHA. El primer paso es diseñar y programar el formulario en el que aparecerá nuestro CAPTCHA: Ejemplo 119: Formulario CAPTCHA form-catcha.php <?php session_start(); if(isset($_POST["palabra"])) { if($_POST["palabra"] == $_SESSION["oculto"]) die("¡Felicidades! Ha leído correctamente la palabra."); else Oscar E Capuñay Uceda 253 Seguridad Web die("No has adivinado la palabra. Prueba otra vez"); } else { ?> <form method="post" action=""> <img src="capu-captcha.php"> <input type="text" name="palabra"> <input type="submit" value="Comprobar"> </form> <?php } ?> Ejemplo 120: Generador CAPTCHA capu-captcha.php <?php session_start(); // estas cabeceras evitan que se almacene la imagen en el caché header ("Expires: Sat, 12 Jul 2008 09:00:00 GMT"); header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header ("Cache-Control: no-store, no-cache, must-revalidate"); header ("Cache-Control: post-check=0, pre-check=0", false); header ("Pragma: no-cache"); // creamos la imagen con el tamaño determinado $imagen = imagecreate(250, 100); // elegimos los colores para el fondo y el texto $rojo = mt_rand(150,200); $verde = mt_rand(150,200); $azul = mt_rand(200,250); $rojo_fondo = mt_rand(80,120); $verde_fondo = mt_rand(80,120); $azul_fondo = mt_rand(80,200); $rojo_basura = $rojo+55; $verde_basura = $verde+55; $azul_basura = $azul+5; $color_texto = imagecolorallocate($imagen,$rojo,$verde,$azul); $color_fondo = imagecolorallocate($imagen,$rojo_fondo,$verde_fondo,$azul_fondo); $color_basura = imagecolorallocate($imagen,$rojo_basura,$verde_basura,$azul_basura); //aplicamos el color de fondo imagefill($imagen,0, 0, $color_fondo); // construimos la palabra $caracteres = "ABCDEFGHJKMNPRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789"; Oscar E Capuñay Uceda 254 Seguridad Web //indicar la cantidad de caracteres que tendrá la palabra del CAPTCHA $cantidad=6; for($i=1;$i<=$cantidad;$i++) { $pos = mt_rand(0,strlen($caracteres)-1); $palabra.= substr($caracteres,$pos,1); } // comprobamos la existencia de la función ImageTTFText() $fontsList = array( "./fonts/VeraMoBd.ttf", "./fonts/VeraMoBI.ttf", "./fonts/VeraMono.ttf", "./fonts/VeraMoIt.ttf" ); $randFontNo = mt_rand(0, sizeof($fontsList)-1); $randFontPath = realpath($fontsList[ $randFontNo ]); // al azar las señales al fondo del respectivo texto ImageTTFText for($i=1;$i<20;$i++){ $x = mt_rand(0, 250); // pos x $y = mt_rand(0, 100); // pos y $car = chr(mt_rand(45, 250)); //caracter aleatorio $angulo = mt_rand(3,180); imagettftext($imagen, 12, $angulo, $x, $y, $color_basura, $randFontPath, $car); } // imprimir la palabra $x = mt_rand(10,120); $y = mt_rand(40,65); imagettftext($imagen, 28, mt_rand(-10,10), $x, $y, $color_texto, $randFontPath, $palabra); //ensuciamos la imagen con líneas for($i=1;$i<60;$i++){ $x = mt_rand(0, 250); $y = mt_rand(0, 100); imageline($imagen, $x, $y, $x+mt_rand(-40,40), $y+mt_rand(40,40), $color_basura); } // enviamos mediante la sesión la palabra elegida $_SESSION["oculto"] = $palabra; // enviamos la cabecera correspondiente al navegador y luego la imagen header("Content-type: image/png"); imagepng($imagen); // eliminamos la imagen imagedestroy($imagen); ?> Oscar E Capuñay Uceda 255 Seguridad Web Resultados Web: Podemos ver a continuación varios ejemplos de los CAPTCHAs generados. Figura 208. Ejemplo1 de CAPTCHA Figura 209. Ejemplo2 de CAPTCHA Figura 210. Ejemplo3 de CAPTCHA Oscar E Capuñay Uceda 256 Generación de archivos con PHP VIII. Generación de archivos con PHP Imágenes PHP tiene un conjunto de funciones destinadas a la manipulación de imágenes en varios formatos, utilizando la librería GD, debido a esto debemos verificar si el módulo está instalado y activado. Para hacer esto vamos a la “Configuración de PHP” en el menú de WAMP y luego seleccionamos “Extensiones de PHP” y luego seleccionamos la librería php_gd2 para activarla. Ejemplo 121: gdinfo.php <?php var_dump(gd_info()); ?> Resultado Web: Ver configuración GD Figura 211. Resultado de gdinfo.php Ejemplo 122: imagen01.php <?php $im = imagecreate(100, 50); $color_fondo = imagecolorallocate($im, 255, 55, 55); $color_texto = imagecolorallocate($im, 233, 214, 51); imagestring($im, 2, 5, 5, "Texto de prueba", $color_texto); header("Content-type: image/png"); imagepng($im); imagedestroy($im); ?> Oscar E Capuñay Uceda 257 Mi primera imagen Generación de archivos con PHP La función imagecreate crea una nueva imagen con una paleta de colores y sus parámetros son para especificar el ancho y el alto de la imagen en pixeles. La función imagecolorallocate reserva un color para ser usado en la imagen en los últimos tres parámetros se indica los valores de Rojo, Verde y Azul, de dicha mezcla resultará un color el cual será almacenado en una variable. La función imagestring dibuja una cadena de texto horizontalmente. El primer parámetro indica la imagen sobre la que se insertará el texto; el segundo es el tipo de fuente; el tercero y cuarto indican las coordenadas en la que se ubicará el texto; el quinto parámetro es la cadena de texto y el último es el color del texto. Resultado Web: Figura 212. Resultado de imagen01.php Ejemplo 123: Rectángulo y texto imagen02.php <?php $image = imagecreate(180,90); $bg=imagecolorallocate($image,250,250,50); $color1=imagecolorallocate($image,250,50,50); $color2=imagecolorallocate($image,50,250,250); imagefilledrectangle($image,5,5,150,60,$color2); imagestring($image, 5, 10, 18, 'Un rectangulo',$color1); header('Content-Type: image/jpeg'); imagejpeg($image); ?> Resultado Web: Figura 213. Resultado de imagen02.php Oscar E Capuñay Uceda 258 Generación de archivos con PHP Ejemplo 124: imagen03.php <?php header("Content-type: image/jpeg"); $img=imagecreate(500,500); $color_azul=imagecolorallocate($img,50,50,255); $color_amarillo=imagecolorallocate($img,255,255,0); $verde=imagecolorallocate($img,0,255,0); imageline($img,50,50,50,450,$color_amarillo); imageline($img,50,450,450,450,$color_amarillo); imagefilledrectangle($img,100,350,150,450,$verde); imagefilledrectangle($img,200,250,250,450,$verde); imagefilledrectangle($img,300,150,350,450,$verde); imagefilledrectangle($img,400,50,450,450,$verde); imagestring($img,4,220,30,"Grafico Ejemplo",$color_amarillo); imagejpeg($img); imagedestroy($img); ?> Resultado Web: Gráfico de barras Figura 214. Resultado de imagen03.php Oscar E Capuñay Uceda 259 Generación de archivos con PHP Ejemplo 125: Pie imagen04.php <?php header("Content-type: image/jpeg"); $img=imagecreate(400,400); $fondo=imagecolorallocate($img,225,225,225); $azul=imagecolorallocate($img,50,50,255); $azul2=imagecolorallocate($img,0,0,100); $amarillo=imagecolorallocate($img,255,255,0); $amarillo2=imagecolorallocate($img,100,100,0); $verde=imagecolorallocate($img,0,255,0); $rojo=imagecolorallocate($img,255,0,0); $ancho=300; $alto=180; $altura=40; for($i=1;$i<=$altura;$i++) { imagefilledarc($img,200,200+$i,$ancho,$alto,0,36,$azul2,2); imagefilledarc($img,200,200+$i,$ancho,$alto,36,108,$amarillo2,2); imagefilledarc($img,200,200+$i,$ancho,$alto,108,216,$azul2,2); } imagefilledarc($img,200,200,$ancho,$alto,0,36,$azul,0); imagefilledarc($img,200,200,$ancho,$alto,36,108,$amarillo,0); imagefilledarc($img,200,200,$ancho,$alto,108,216,$azul,0); imagefilledarc($img,200,200,$ancho,$alto,216,360,$amarillo,0); imagejpeg($img); imagedestroy($img); ?> Resultado Web: Figura 215. Resultado de imagen04.php Oscar E Capuñay Uceda 260 Generación de archivos con PHP imagen05.php <?php $aleatorio = rand(1,8); for($i=0;$i<=$aleatorio;$i++){$datos[$i]=rand(2,50);};//llenamos el array de datos. $ancho='600';$alto='400';//ancho y alto de la imagen $cx = '300';$cy ='150'; //coordenadas de la figura $sx = '600';$sy='300';$sz ='100';// dimensiones X,Y,Z $datos_sum = array_sum($datos); //angulos for($i=0;$i<=$aleatorio;$i++){ $angulo[$i] = (($datos[$i] / $datos_sum) * 360); $angulo_sum[$i] = array_sum($angulo); }; $im = imagecreate ($ancho,$alto); $fondo = imagecolorallocate($im, 255, 255, 255); //colores aleatorios for($i=0;$i<=$aleatorio;$i++){ $r=rand(50,255);$g=rand(50,255);$b=rand(50,255); $colors[$i] = imagecolorallocate($im,$r,$g,$b); $colord[$i] = imagecolorallocate($im,($r/1.5),($g/1.5),($b/1.5)); } for($z=1;$z<=$sz;$z++){ imagefilledarc($im,$cx,($cy+$sz)$z,$sx,$sy,0,$angulo_sum[0],$colord[0],IMG_ARC_EDGED); for($i=1;$i<=$aleatorio;$i++){ imagefilledarc($im,$cx,($cy+$sz)-$z,$sx,$sy,$angulo_sum[$i1],$angulo_sum[$i],$colord[$i],IMG_ARC_NOFILL); } } imagefilledarc($im,$cx,$cy,$sx,$sy,0 ,$angulo_sum[0], $colors[0], IMG_ARC_PIE); for($i=1;$i<=$aleatorio;$i++){ imagefilledarc($im,$cx,$cy,$sx,$sy,$angulo_sum[$i-1] ,$angulo_sum[$i], $colors[$i], IMG_ARC_PIE); } header('Content-type: image/png'); imagepng($im); imagedestroy($im); ?> La función rand tiene dos parámetros opcionales que sirven para especificar el valor mínimo y máximo del número aleatorio que se quiere obtener. Oscar E Capuñay Uceda 261 Generación de archivos con PHP Resultado Web: Figura 216. Resultado de imagen05.php Para dibujar un círculo hay que utilizar la función imagearc la cual dibuja una elipse parcial centrada en x, y (2do y 3er parámetro) en la imagen $img (ver ejemplo acontinuación), luego se especifican la anchura y altura respectivamente mientras que los puntos de inicio y final vienen indicados por los parámetros 6to y 7mo en grados. 0° se corresponde con la posición de las 3 en punto en un reloj y el arco se dibuja en el sentido de las agujas del reloj. Ejemplo 126: imagen06.php <?php // crear una imagen de 200*200 $img = imagecreate(200, 200); // definir los colores $white = imagecolorallocate($img, 255, 255, 255); $black = imagecolorallocate($img, 0, 0, 0); // dibujar un circulo negro imagearc($img, 100, 100, 150, 150, 0, 360, $black); Oscar E Capuñay Uceda 262 Círculo Generación de archivos con PHP // mostrar la imagen en el navegador header("Content-type: image/png"); imagepng($img); // liberar la memoria imagedestroy($img); ?> Resultado Web: Figura 217. Resultado de imagen06.php Oscar E Capuñay Uceda 263 Generación de archivos con PHP Archivos PDF Las funciones PDF en PHP pueden crear archivos PDF utilizando la biblioteca PDFlib. Esta biblioteca está disponible para descargar en http://www.pdflib.com/products/pdflib-family/, pero requiere la compra de una licencia para uso comercial. Debido a que la licencia de PDFLib tiene limitaciones para su uso comercial, en este libro veremos el uso de una clase que tiene el mismo fin, su nombre es: FPDF. FPDF FPDF es una clase escrita en PHP que permite generar documentos PDF directamente desde PHP, es decir, sin usar la biblioteca PDFlib. FPDF es freeware. No hay limitaciones de uso. Puede usarlo libre y gratuitamente en su aplicación comercial o no, con o sin modificaciones. Entre las ventajas más resaltantes de FPDF tenemos: funciones de alto nivel. Esta es una lista de sus principales características: • • • • • • • • • Elección de la unidad de medida, formato de página y márgenes Gestión de cabeceras y pies de página Salto de página automático Salto de línea y justificación del texto automáticos Admisión de imágenes (JPEG y PNG) Colores Enlaces Admisión de fuentes TrueType, Type1 y codificación Compresión de página FPDF no necesita de ninguna extensión para PHP (excepto la biblioteca zlib si se va a activar la opción de compresión) y funciona con PHP4 y PHP5. La clase genera documentos en muchos otros idiomas aparte de los europeos occidentales: europeo central, ciríloco, griego, báltico y tailandés, si se dispone de fuentes TrueType o Type1 con el conjunto de caracteres adecuado. El chino y el japonés también están admitidos. La velocidad de generación de un documento es menor que con PDFlib. Sin embargo, la desventaja en cuanto a rendimiento es muy razonable y se adecua a la mayoría de los casos, a no ser que sus documentos vayan a ser especialmente complejos o extensos. Para usar FPDF copiaremos el archivo fpdf.php que contiene todo lo necesario para la creación de nuestros archivos PDF. Luego crearemos un subdirectorio llamado font en donde copiaremos algunos archivos de fuentes que utilizaremos posteriormente. Veamos un ejemplo: Oscar E Capuñay Uceda 264 Generación de archivos con PHP Ejemplo 127: pdf01.php <?php define('FPDF_FONTPATH','font/'); //directorio de las fuentes require('fpdf.php'); //llamamos a la clase FPDF $pdf=new FPDF(); //instanciamos la clase $pdf->AddPage(); //agregamos la primera página $pdf->SetFont('Courier','',16);//establecemos la fuente y sus atributos $pdf->cell(10); //celda de 10mm de ancho //celda de 0 ancho y 10mm de alto $pdf->Cell(0,10,'Esta es una prueba FPDF',0,1); $pdf->Output(); ?> Resultado Web: FPDF Figura 218. Resultado de pdf01.php A continuación presento una lista de las propiedades y métodos que vienen implementados en FPDF. AcceptPageBreak - acepta o no un salto de página automático AddFont - adiciona una nueva fuente AddLink - crea una referencia interna AddPage - adiciona una nueva página AliasNbPages - define un alias para el número de páginas Cell - imprime una celda Close - termina el documento Error - error fatal Footer - Pie de página FPDF - constructor GetStringWidth - calcula la longitud de la cadena GetX - obtiene la posición actual de x GetY - obtiene la posición actual de y Header - cabecera de página Image - imprime una imagen Line - dibuja una línea Link - crea una referencia Ln - salto de línea Oscar E Capuñay Uceda 265 Generación de archivos con PHP MultiCell - imprime texto con saltos de línea Open - crea un documento Output - guarda o envía el documento PageNo - número de página Rect - dibuja un rectángulo SetAuthor - Establece el autor del documento SetAutoPageBreak - establece el modo de salto de página automático SetCompression - cambia la compresión en activo o inactivo SetCreator - establece el creador del documento SetDisplayMode - establece el modo de presentación SetDrawColor - establece el color de graficación SetFillColor - establece el color de relleno SetFont - establece la fuente SetFontSize - establece el tamaño de la fuente SetKeywords - asocia las palabras claves con el documento SetLeftMargin - establece el margen izquierdo SetLineWidth - establece el ancho de la línea SetLink - establece el enlace de destino SetMargins - establece los márgenes SetRightMargin - establece el margen derecho SetSubject - establece el tema del documento SetTextColor - establece el color del texto SetTitle - establece el título del documento SetTopMargin - Establece el margen superior SetX - Establece la posición actual de X SetXY - Establece la posición actual de X e Y SetY - Establece la posición actual de Y Text - imprime una cadena Write - imprime el siguiente texto Ya que Cell es uno de los métodos más usados de la clase veremos con más detalle los parámetros que se pueden utilizar. Sintaxis: Cell(float w [, float h [, string txt [, mixed border [, int ln [, string align [, int fill [, mixed link]]]]]]]) Descripción Imprime una celda (de área rectangular) bordes opcionales, color de fondo y secuencia de carácteres La esquina superir izquierda de la celda corresponde a la posición actual. El texto puede ser alineado o centrado. Después de invocar, la posición actual se desplaza a la derecha o la siguiente línea. Es posible poner una referencia en el texto. Si esta el salto de página automático habilitado y la celda esta por fuera del límite, es realizado un salto de página antes de producir la salida. Parámetros w : Ancho de Celda. Si es 0, la celda se extiende hasta la márgen derecha. h : Alto de celda. Valor por defecto: 0. Oscar E Capuñay Uceda 266 Generación de archivos con PHP txt : Cadena a ser impresa. Valor por defecto: cadena vacia. border : Indica si los bordes deben se dibujados alrededor de la celda. El valor puede ser un número: 0 -> sin borde , 1 -> marco o una cadena conteniendo alguno o todos de los siguientes caracteres (en cualquier orden): * L: izquierda * T: superior * R: derecha * B: inferior Valor por defecto: 0. ln : Indica donde la posición actual debería ir antes de invocar. Los valores posibles son: * 0: a la derecha * 1: al comienzo de la siguiente línea * 2: debajo Poner 1 es equivalente a poner 0 y llamar justo después Ln(). Valor por defecto: 0. align : Permite centrar o alinear el texto. Los posibles valores son: * L o una cadena vacia: alineación izquierda (valor por defecto) * C: centro * R: alineación derecha fill : Indica si el fondo de la celda debe ser dibujada (1) o transparente (0). Valor por defecto: 0. link : URL o identificador retornado por AddLink(). Veamos un segundo ejemplo. Ejemplo 128: PDF con salto de página <?php define('FPDF_FONTPATH','font/'); //directorio de las fuentes include('fpdf.php'); $pdf=new FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial','B',16); $pdf->Cell(180,10,'GENERANDO PDFs CON FPDF',0,1,'C'); Oscar E Capuñay Uceda 267 Generación de archivos con PHP $pdf->Ln(); $pdf->Ln(); $pdf->SetFont('Arial','',9); $pdf->MultiCell(180,5,'La clase FPDF esta escrita en PHP y permite generar documentos PDF directamente desde PHP, sin usar la biblioteca PDFLib, la ventaja es que, mientras que PDFLib tiene un costo para su uso comercial, FPDF es libre',0,1); $pdf->Cell(180,3,date("d/m/Y"),0,1,'R'); $pdf->Cell(180,3,date("H:i:s"),0,1,'R'); $pdf->AddPage(); $pdf->MultiCell(180,5,'Este texto aparecerá en la segunda página',0,1); $pdf->Output(); ?> Resultado Web: Figura 219. Resultado de pdf02.php Segunda página Figura 220. Segunda página de pdf01.php Oscar E Capuñay Uceda 268 Generación de archivos con PHP Ejemplo 129: pdf03.php <?php define('FPDF_FONTPATH','font/'); require('fpdf.php'); //extensión de la clase FPDF //extiende los métodos de encabezado (header) y pie de página (footer) class PDF extends FPDF { //Columna actual var $col=0; //Ordenada de comienzo de la columna var $y0; //personalizamos el encabezado function Header() { global $title; $this->SetFont('Arial','B',15); $this->SetX(30);//(210-$w)/2); $this->SetDrawColor(20,20,200); $this->SetFillColor(255,255,180); $this->SetTextColor(80,80,255); $this->SetLineWidth(1); $this->Cell(0,10,$title,1,1,'C',1); //imagen que aparecerá en el encabezado $this->Image('imagenes/correo.jpg',11,10,16); $this->Ln(10); //Guardar ordenada $this->y0=$this->GetY(); } //personalizamos el pie de página function Footer() { $this->SetY(-15); $this->SetFont('Arial','I',8); $this->SetTextColor(128); $this->Cell(0,10,'Página '.$this->PageNo(),0,0,'C'); } PDF con capítulos Oscar E Capuñay Uceda 269 Generación de archivos con PHP function SetCol($col) { //Establecer la posición de una columna dada $this->col=$col; $x=10+$col*65; $this->SetLeftMargin($x); $this->SetX($x); } function AcceptPageBreak() { //Método que acepta o no el salto automático de página if($this->col<2) { //Ir a la siguiente columna $this->SetCol($this->col+1); //Establecer la ordenada al principio $this->SetY($this->y0); //Seguir en esta página return false; } else { //Volver a la primera columna $this->SetCol(0); //Saltar página return true; } } function ChapterTitle($num,$titulo) { $this->SetFont('Arial','B',13); $this->SetFillColor(215,215,255); $this->Cell(0,6,"Capítulo $num : $titulo",0,1,'L',1); $this->Ln(4); $this->y0=$this->GetY(); } function ChapterBody($fichier) { $f=fopen($fichier,'r'); $txt=fread($f,filesize($fichier)); fclose($f); $this->SetFont('Arial','',12); Oscar E Capuñay Uceda 270 Generación de archivos con PHP //Imprimir texto en una columna de 6 cm de ancho $this->MultiCell(60,5,$txt); //Volver a la primera columna $this->SetCol(0); } function PrintChapter($num,$title,$file) { //imprimir el capítulo $this->AddPage(); $this->ChapterTitle($num,$title); $this->ChapterBody($file); } } //instanciamos la clase $pdf=new PDF(); //variable global utilizada en el método header $title='Ejemplo 3'; //título del documento $pdf->SetTitle($title); //Datos del autor del contenido $pdf->SetAuthor('Oscar Capuñay Uceda'); //Datos del creador – aplicación que creó el documento $pdf-> SetCreator(‘FPDF’); //primer capítulo $pdf->PrintChapter(1,'Phishing o Fraude Electrónico','phishing.txt'); //segundo capítulo $pdf->PrintChapter(2,'Esteganografía','esteganografia.txt'); //escribe el pdf en un archivo llamado prueba.pdf y obliga su descarga $pdf->Output('prueba.pdf','D'); ?> Oscar E Capuñay Uceda 271 Generación de archivos con PHP Resultado: Figura 221. Resultado de pdf03.php Ejemplo 130: pdf04.php <?php define('FPDF_FONTPATH','font/'); require_once "fpdf.php"; require_once "mysqli-conexion.php"; $sql="select * from persona"; $rspersona=$mysqli->query($sql) or die($mysqli->error); $pdf=new FPDF(); $pdf->AddPage(); $pdf->SetFont('Arial','B',16); $pdf->Cell(180,10,'Listado de Personas',0,1,'C'); $pdf->Ln(); Oscar E Capuñay Uceda 272 PDF con datos de MySQL Generación de archivos con PHP $pdf->Ln(); $pdf->SetFont('Arial','B',10); $pdf->Cell(10,6,"Id",1); $pdf->Cell(40,6,"Nombres",1); $pdf->Cell(40,6,"Apellidos",1); $pdf->Cell(40,6,"E-Mail",1); $pdf->Cell(20,6,"Telefono",1); $pdf->Ln(); $pdf->SetFont('Arial','',10); while($registro=$rspersona->fetch_object()) { $pdf->Cell(10,5,$registro->idpersona,0); $pdf->Cell(40,5,$registro->nombres,0); $pdf->Cell(40,5,$registro->apellidos,0); $pdf->Cell(40,5,$registro->email,0); $pdf->Cell(20,5,$registro->telefono,0); $pdf->Ln(); } $pdf->Output(); ?> Resultado: Figura 222. Resultado de pdf04.php Oscar E Capuñay Uceda 273 Generación de archivos con PHP Archivos XLS Los archivos XLS pueden ser generados en PHP utilizando la función header() para establecer los encabezados del archivo que vamos a generar, en este caso escribiremos: header("Content-type: application/vnd.ms-excel"); Veamos un primer ejemplo. Ejemplo 131: xls01.php <?php // Enviamos los encabezados de hoja de calculo header("Content-type: application/vnd.ms-excel"); // Creamos la tabla $letra = array ("A","B","C","D","E","F","G","H","I","J"); ?> <table> <?php $filas=10; $columnas=10; for ($i=0;$i<$filas;$i++){ ?> <tr> <?php for ($j=0;$j<$columnas;$j++){ ?> <td> <?php echo $i . $j; ?> </td> <?php } ?> </tr> <?php } ?> </table> Resultado: Note que aparece la ventana de descarga para el archivo xls01.php y es reconocido como archivo xls (Microsoft Office Excel). XLS simple Oscar E Capuñay Uceda 274 Generación de archivos con PHP Figura 223. Abriendo xls01.php Abrimos el archivo Figura 224. Hoja de calculo con xls01.php Ejemplo 132: xls02.php <?PHP header("Content-type: application/vnd.ms-excel"); //indicamos el nombre del archivo que se va a generar header("Content-Disposition: filename='resumen.xls'"); ?> <table border=1> XLS con fórmulas Oscar E Capuñay Uceda 275 Generación de archivos con PHP <tr><th> Departamento </th><th> 2006 </th><th> 2007 </th><th> 2008 </th> </tr> <tr><td> Tumbes </td><td>120 </td><td> 240 </td><td> 380 </td> </tr> <tr><td> Piura </td><td>150 </td><td> 350 </td><td> 330 </td> </tr> <tr><td> Lambayeque </td><td> 200 </td><td> 478 </td><td> 832 </td> /tr> <tr><td> Totales </td><td> =suma(b2:b4) </td><td> =c2+c3+c4 </td><td> =suma(d2:d4) </td> </tr> </table> El ejemplo anterior es una página muy simple compuesta en su mayoría por etiquetas HTML pero que se convierte en XLS por las primeras líneas escritas en PHP. Figura 225. Abriendo xls02.php Abrimos el archivo Figura 226. resumen.xls generado con xls02.php Oscar E Capuñay Uceda 276 Generación de archivos con PHP Podemos comprobar que las formulas escritas en HTML han hecho su trabajo. Ahora utilizaremos dos archivos (excel.php y excel-ext.php) creados por Ignatius Teo, los cuales permiten escribir y leer archivos XLS a través de una clase llamada: xlsStream. excel-ext.php <?php function createExcel($filename, $arrydata) { $excelfile = "xlsfile://./".$filename; $fp = fopen($excelfile, "wb"); if (!is_resource($fp)) die("Error al crear $excelfile"); fwrite($fp, serialize($arrydata)); fclose($fp); header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header ("Last-Modified: " . gmdate("D,d M YH:i:s") . " GMT"); header ("Cache-Control: no-cache, must-revalidate"); header ("Pragma: no-cache"); header ("Content-type: application/x-msexcel"); header ("Content-Disposition: attachment; filename=\"" . $filename . "\"" ); readfile($excelfile); } ?> Ejemplo 133: xls03.php XLS con xlsStream <?php //incluimos los archivos require_once("excel.php"); require_once("excel-ext.php"); //llenamos el array data con datos de prueba $data = array( array("Nombre"=>"Carlos", "Nota"=>18), array("Nombre"=>"Kelly", "Nota"=>18), array("Nombre"=>"Dante", "Nota"=>17), array("Nombre"=>"Oscar", "Nota"=>14) ); //creamos el archivo XLS createExcel("ejemplo3.xls", $data); ?> Oscar E Capuñay Uceda 277 Generación de archivos con PHP Resultado: Figura 227. Resultado de xls03.php Ahora pasemos a ver un ejemplo que se conecta a un servidor MySQL, selecciona la base de datos “dbdemo” y ejecuta una consulta que retorna todos los registros de la tabla “persona”. Ejemplo 134: xls04.php <?php //incluimos los archivos require_once("excel.php"); require_once("excel-ext.php"); //Conexion a MySQL $con = mysql_connect("localhost","root",""); mysql_select_db("dbdemo", $con); //sentencia sql $sql = "SELECT * FROM persona"; //ejecutar la sentencia sql $res = mysql_query($sql, $con) or die(mysql_error()); // Creamos el array con los datos while($reg = mysql_fetch_assoc($res)) $data[] = $reg; // Generamos el Excel createExcel("personas.xls", $data); ?> XLS con datos de MySQL Oscar E Capuñay Uceda 278 Generación de archivos con PHP Resultado: Figura 228. Resultado de xls04.php xls05.php <?php header("Content-type: application/vnd.ms-excel"); header("Content-Disposition: filename=\"listado.xls\""); include "mysqli-conexion.php"; //incluimos la conexion //consulta sql $sql="select * from persona"; //ejecucion de la sentencia sql $rspersona=$mysqli->query($sql) or die($mysqli->error); ?> <table> <tr> <th>Id</th> <th>Nombres</th> <th>Apellidos</th> <th>E-Mail</th> <th>Teléfono</th> </tr> <?php //mostrar los registros while($registro=$rspersona->fetch_object()) { ?> <tr> <td><?php echo "$registro->idpersona"?></td> <td><?php echo "$registro->nombres"?></td> <td><?php echo "$registro->apellidos"?></td> <td><?php echo "$registro->email"?></td> Oscar E Capuñay Uceda 279 Generación de archivos con PHP <td><?php echo "$registro->telefono"?></td> </tr> <?php } $mysqli->close(); //cerramos la conexión ?> </table> Resultado Web: Figura 229. Abriendo xls05.php Figura 230. Resultado de xls05.php Oscar E Capuñay Uceda 280 PHP + AJAX IX. PHP + AJAX En este libro veremos el uso de AJAX en PHP a través de la librería de clases XAJAX. 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). Éstas se ejecutan en el cliente, es decir, en el navegador de los usuarios y mantiene comunicación asíncrona con el servidor en segundo plano. De esta forma es posible realizar cambios sobre la misma página sin necesidad de recargarla. Esto significa aumentar la interactividad, velocidad y usabilidad en la misma. AJAX es una combinación de cuatro tecnologías ya existentes: • • XHTML (o HTML) y hojas de estilos en cascada (CSS) para el diseño que acompaña a la información. Document Object Model (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 asincrónicamente 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 comúnmente para la transferencia de vuelta al servidor, aunque cualquier formato puede funcionar, incluyendo HTML preformateado, texto plano, JSON y hasta EBML. • • Como el DHTML, LAMP o SPA, AJAX no constituye una tecnología en sí, sino que es un término que engloba a un grupo de éstas que trabajan conjuntamente. A pesar de que el término «AJAX» fuese creado en 2005, la historia de las tecnologías que permiten AJAX se remonta a una década antes con la iniciativa de Microsoft en el desarrollo de Scripting Remoto. Sin embargo, las técnicas para la carga asíncrona de contenidos en una página existente sin requerir recarga completa remontan al tiempo del elemento iframe (introducido en Internet Explorer 3 en 1996) y el tipo de elemento layer (introducido en Netscape 4 en 1997, abandonado durante las primeras etapas de desarrollo de Mozilla). Ambos tipos de elemento tenían el atributo src que podía tomar cualquier dirección URL externa, y cargando una página que contenga javascript que manipule la página paterna, pueden lograrse efectos parecidos al AJAX. El Microsoft's Remote Scripting (o MSRS, introducido en 1998) resultó un sustituto más elegante para estas técnicas, con envío de datos a través de un applet Java el cual se puede comunicar con el cliente usando JavaScript. Oscar E Capuñay Uceda 281 PHP + AJAX Esta técnica funcionó en ambos navegadores, Internet Explorer versión 4 y Netscape Navigator versión 4. Microsoft la utilizó en el Outlook Web Access provisto con la versión 2000 de Microsoft Exchange Server. La comunidad de desarrolladores web, primero colaborando por medio del grupo de noticias microsoft.public.scripting.remote y después usando blogs, desarrollaron una gama de técnicas de scripting remoto para conseguir los mismos resultados en diferentes navegadores. Los primeros ejemplos incluyen la librería JSRS en el año 2000, la introducción a la técnica imagen/cookie en el mismo año y la técnica JavaScript bajo demanda (JavaScript on Demand) en 2002. En ese año, se realizó una modificación por parte de la comunidad de usuarios al Microsoft's Remote Scripting para reemplazar el applet Java por XMLHttpRequest. Frameworks de Scripting Remoto como el ARSCIF aparecieron en 2003 poco antes de que Microsoft introdujera Callbacks en ASP. NET. Desde que XMLHttpRequest está implementado en la mayoría de los navegadores, raramente se usan técnicas alternativas. Sin embargo, todavía se utilizan donde se requiere una mayor compatibilidad, una reducida implementación, o acceso cruzado entre sitios Web. Una alternativa, el Terminal SVG (basado en SVG), emplea una conexión persistente para el intercambio continuo entre el navegador y el servidor.[6] XAJAX XAJAX es una librería PHP que Ud puede incluir en su script PHP para proveer una forma fácil en sus páginas Web la llamada a funciones o métodos de objetos usando AJAX (Asynchronous JavaScript And XML). Simplemente registra una o mas funciones/métodos con el objeto xajax quien retorna XML como respuesta y agrega una sentencia en su cabecera HTML para incluir un archivo de JavaScript y ejecutar un proceso que muestre el resultado desde alguna parte del HTML, para ello agregamos una simple llamada a una función de JavaScript en su HTML, y XAJAX se encarga del resto! [7] A mi parecer es una de las mejores librerías para trabajar con PHP y AJAX, la versión que utilizaremos es la 0.2.5 (estable). Esta librería ha sido desarrollada por: Jared White (
[email protected]), J. Max Wilson (
[email protected]) y Eion Robb (
[email protected]) y el sitio Web oficial es: http://www.xajaxproject.org. Veamos ahora algunos ejemplos. Ejemplo 135: xajax01.php <?php require ('xajax/xajax.inc.php'); Asignación de valores a propiedades de un objeto HTML Oscar E Capuñay Uceda 282 PHP + AJAX //implementamos la funcion que imprime el texto en el textbox function frase($texto) { $objResponse = new xajaxResponse(); //asignar $texto en la propiedad "value" del objeto "text1" $objResponse->addAssign("text1","value",$texto); return $objResponse; } // Instanciamos xajax. $xajax = new xajax(); // Funciones que serán llamadas desde JavaScript $xajax->registerFunction("frase"); // Procesar cualquier requerimiento // Debe ser llamado antes de cualquier cabecera o salida HTML $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax01</title> <?php //esta orden debe estar dentro de las etiquetas <head> y </head> $xajax->printJavascript('xajax'); // directorio donde se encuentra el archivo xajax.inc.php. ?> </head> <body style="text-align:center;"> <input type="text" id="text1" name="text1" value="" size="30" /> <input type="button" onclick="xajax_frase('esta es la frase de prueba')" value="Primera Frase" /> <input type="button" onclick="xajax_frase('esta es otra frase')" value="Otra Frase" /> </body> </html> Podemos notar en los botones la llamada a la función xajax_frase, la cual envía como parámetro la frase que aparecerá en la caja de texto. Resultado Web: Figura 231. Resultado de xajax01.php Oscar E Capuñay Uceda 283 PHP + AJAX Ejemplo 136: xajax02.php <?php require ('xajax/xajax.inc.php'); //implementamos la funcion que asugna HTML al DIV function asig_html() { $html="<h1>Título Asignado</h1>Este es el HTML asignado."; $objResponse = new xajaxResponse(); $objResponse->addAssign("div1","innerHTML",$html); return $objResponse; } // Instanciamos xajax. $xajax = new xajax(); //Registramos la función $xajax->registerFunction("asig_html"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax02</title> <?php //directorio donde se encuentra el archivo xajax.inc.php. $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <div id="div1"> texto inicial </div> <input type="button" onclick="xajax_asig_html()" value="Asignar HTML" /> </body> </html> Resultado Web: Asignación de HTML a innerHTML de una etiqueta DIV Figura 232. Resultado de xajax02.php Oscar E Capuñay Uceda 284 PHP + AJAX Al hacer click en el botón, aparecerá el siguiente resultado: Figura 233. Cambio de contenido con xajax02.php Ejemplo 137: xajax03.php <?php //incluimos la clase xajax require ('xajax/xajax.inc.php'); function prueba($num) { if ($num==0) $texto = "Primer mensaje de prueba"; else $texto = "Este es el segundo mensaje de prueba"; $objResponse = new xajaxResponse(); $objResponse->addAssign("division1","innerHTML",$texto); return $objResponse; } function setColor($sColor) { $objResponse = new xajaxResponse(); $objResponse->addAssign("division1","style.color", $sColor); return $objResponse; } // Instanciamos xajax. $xajax = new xajax(); // Funciones que serán llamadas desde JavaScript $xajax->registerFunction("prueba"); Oscar E Capuñay Uceda 285 Asignación de innerHTML y estilos con XAJAX PHP + AJAX $xajax->registerFunction("setColor"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax03</title> <?php //esta orden debe estar dentro de las etiquetas <head> y </head> $xajax->printJavascript('xajax'); // directorio donde se encuentra el archivo xajax.inc.php. ?> </head> <body style="text-align:center;"> <div id="division1" name="division1"> </div> <br/> <button onclick="xajax_prueba(0)">Primera Prueba</button> <button onclick="xajax_prueba(1)">Segunda prueba</button> <select id="colores" name="colores" onchange="xajax_setColor(document.getElementById('colores').value);"> <option value="black" selected="selected">Negro</option> <option value="red">Rojo</option> <option value="green">Verde</option> <option value="blue">Azul</option> </select> <script type="text/javascript"> // llama a la función de prueba al cargar la página xajax_prueba(0); // llama a la función SetColor al cargar la página xajax_setColor(document.getElementById('colores').value); </script> </body> </html> Resultado Web: Figura 234. Resultado de xajax03.php Oscar E Capuñay Uceda 286 PHP + AJAX Podemos comprobar en este ejemplo a través de nuestro navegador que la frase cambia dependiendo del botón que presionemos y del color que elijamos pero todo esto sin recargar la página, es decir, utilizando AJAX. Ejemplo 138: Ocultar y Mostrar un DIV xajax04.php <?php require ('xajax/xajax.inc.php'); function alternar($estado) { if($estado=="none") { $valor=""; $texto="Ocultar"; } else { $valor="none"; $texto="Ver"; } $objResponse = new xajaxResponse(); //asignación a la propiedad display $objResponse->addAssign("div1","style.display",$valor); //asignación del texto del botón $objResponse->addAssign("boton1","value",$texto); return $objResponse; } // Instanciamos xajax. $xajax = new xajax(); //Registramos la función $xajax->registerFunction("alternar"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax04</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <div id="div1" style="display: block"> texto del div </div> <input type="button" id="boton1" name="boton1" onclick="xajax_alternar(document.getElementById('div1').style.display)" value="Ocultar" /> </body> </html> Oscar E Capuñay Uceda 287 PHP + AJAX En este ejemplo analizamos “display” propiedad del estilo definido en la etiqueta DIV. Si display es igual a “none” entonces el DIV es invisible sino se puede ver su contenido. Por lo tanto, debemos modificar esa propiedad para cambiar de visible a invisible o viceversa. Para obtener el valor de “display” usamos la orden de javascript: document.getElementById() que sirve para hacer referencia a un objeto mediante su ID (Identificador), y luego especificamos la propiedad del estilo que queremos obtener. Una vez obtenido el valor, éste será enviado como parámetro a la función alternar (xajax_alternar). Resultado Web: Figura 235. Resultado de xajax04.php Para ocultar el DIV hacemos click en “Ocultar”. Figura 236. Ocultando un DIV Ejemplo 139: xajax05.php <?php require ('xajax/xajax.inc.php'); function numeros($numero) { for($i=1;$i<=$numero;$i++) { $resultado.= $i . " "; } Oscar E Capuñay Uceda 288 Imprimir números del 1 a N PHP + AJAX $objResponse = new xajaxResponse(); $objResponse->addAssign("div1","innerHTML",$resultado); return $objResponse; } // Instanciamos xajax. $xajax = new xajax(); $xajax->registerFunction("numeros"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax05</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <input type="text" id="text1" name="text1" onkeyup="xajax_numeros(this.value)" /> <div id="div1" style="display: block"> texto del div </div> </body> </html> Al final del ejemplo vemos la orden de javascript: this.value, la cual nos sirve para obtener el valor del objeto actual, es decir, de la caja de texto: text1. Resultado Web: Figura 237. Resultado de xajax05.php Ejemplo 140: xajax06.php <?php require ('xajax/xajax.inc.php'); function imagen($ruta) { Oscar E Capuñay Uceda 289 Cargar una imagen con XAJAX PHP + AJAX $resultado="<img src='$ruta' alt='imagen con xajax'>"; $objResponse = new xajaxResponse(); $objResponse->addAssign("divimagen","innerHTML",$resultado); return $objResponse; } $xajax = new xajax(); $xajax->registerFunction("imagen"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax06</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <div id="divimagen"></div> <select id="lista" name="lista" onchange="xajax_imagen(this.value)"> <option value="">[seleccione una imagen]</option> <option value="imagenes/correo.jpg">Correo</option> <option value="imagenes/grafico.jpg">Gráfico</option> <option value="imagenes/navegador.jpg">Navegador</option> <option value="imagenes/teclado.jpg">Teclado</option> </select> </body> </html> La función imagen definida en este ejemplo inserta la etiqueta IMG en el DIV para mostrar la imagen seleccionada a través de la lista desplegable, la cual, en su evento ochange envía la ruta de la imagen que se mostrará. Resultado Web: Figura 238. Resultado de xajax06.php Oscar E Capuñay Uceda 290 PHP + AJAX Al seleccionar un elemento de la lista se mostrará la imagen elegida. Figura 239. Imagen cargada con xajax06.php Figura 240. Segunda imagen cargada con xajax06.php Eventos con XAJAX Ejemplo 141: xajax07.php <?php require ('xajax/xajax.inc.php'); Oscar E Capuñay Uceda 291 Cambiar el código javascript establecido para un evento PHP + AJAX function nuevo_codigo($objeto,$codigo_js) { $objResponse = new xajaxResponse(); $objResponse->addEvent("$objeto","onclick",$codigo_js); return $objResponse->getXML(); } $xajax = new xajax(); $xajax->registerFunction("nuevo_codigo"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax07</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <input type="button" name="boton1" id="boton1" value="Boton 1" onclick="" /> <input type="button" value="abrir ventana" onclick="xajax_nuevo_codigo('boton1','open(\'md5.php\',\'w1\',\'\')')" /> <input type="button" value="alert" onclick="xajax_nuevo_codigo('boton1','alert(\'ejemplo de xajax\')')" /> </body> </html> Con el método addEvent se puede establecer el código de javascript que será ejecutado en un evento de un objeto determinado. Por lo tanto, necesitamos tres parámetros: objeto, evento y código. Resultado Web: Figura 241. Resultado de xajax07.php Al hacer click sobre el botón “Abrir ventana” al botón “Boton 1” se le asigna el nuevo código de javascript que se ejecutará en el evento onclick, en este caso abrir el archivo md5.php en una nueva ventana del navegador. Después de haber hecho click en “Abrir ventana” hacemos click en “Boton 1” para hacer la prueba. Oscar E Capuñay Uceda 292 PHP + AJAX Figura 242. Ventana nueva con xajax07.php Ahora haremos click en el botón “alert” para cambiar el código del “Boton 1” y luego haremos click en dicho objeto (Boton 1). Figura 243. Mensaje utilizando eventos en xajax07.php Podemos ver que ahora al hacer click en el “botón 1”, se ejecuta un alert() de javascript. Trabajo con formularios en XAJAX Ejemplo 142: xjax08.php <?php require ('xajax/xajax.inc.php'); function datos($formulario) { //los indices son los nombres de los objetos del formulario $frase=$formulario['text1']; //contamos los elementos seleccionados $cantidad=count($formulario['chk']); $resultado="la frase es:" . $frase . "\n"; $resultado.=$cantidad . " temas seleccionados"; $objResponse = new xajaxResponse(); $objResponse->addAlert($resultado); return $objResponse; } $xajax = new xajax(); Oscar E Capuñay Uceda 293 Obtener datos de un formulario PHP + AJAX $xajax->registerFunction("datos"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax08</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <form id="form1" name="form1"> Frase <input type="text" size="40" name="text1" id="text1" /><br /> Temas:<br /> <input type="checkbox" id="chk[]" name="chk[]" value="php" /> PHP<br /> <input type="checkbox" id="chk[]" name="chk[]" value="javascript" /> JavaScript<br /> <input type="checkbox" id="chk[]" name="chk[]" value="css" /> CSS<br /> <input type="button" name="boton1" id="boton1" value="Aceptar" onclick="xajax_datos(xajax.getFormValues('form1'))" /> </body> </html> El método addAlert ejecuta la función alert() de javascript desde el código AJAX. Para obtener los valores de los objetos del formulario utilizamos el método getFormValues de la clase xajax en javascript. Resultado Web: Figura 244. Resultado de xajax08.php Escribimos un valor en la frase y luego seleccionamos algunos temas. Oscar E Capuñay Uceda 294 PHP + AJAX Figura 245. Ingreso de datos en xajax08.php Ahora veamos el resultado al presionar el botón “Aceptar”. Figura 246. Mensaje resultante en xajax08.php Ejemplo 143: xajax09.php Obtener datos incluyendo objetos deshabilitados. <?php require ('xajax/xajax.inc.php'); function datos($formulario) { //los indices son los nombres de los objetos del formulario $frase=$formulario['text1']; //contamos los elementos seleccionados $cantidad=count($formulario['chk']); $resultado = "La frase es:" . $frase . "\n"; $resultado.= $cantidad . " temas seleccionados"; $objResponse = new xajaxResponse(); $objResponse->addAlert($resultado); return $objResponse; } $xajax = new xajax(); $xajax->registerFunction("datos"); $xajax->processRequests(); ?> Oscar E Capuñay Uceda 295 PHP + AJAX <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>xajax08</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> <form id="form1" name="form1"> Frase <input type="text" size="40" name="text1" id="text1" value="texto de prueba" disabled="disabled" /><br /> Temas:<br /> <input type="checkbox" id="chk[]" name="chk[]" value="php" /> PHP<br /> <input type="checkbox" id="chk[]" name="chk[]" value="javascript" /> JavaScript<br /> <input type="checkbox" id="chk[]" name="chk[]" value="css" /> CSS<br /> <input type="button" name="boton1" id="boton1" value="Enviar sin deshabilitados" onclick="xajax_datos(xajax.getFormValues('form1'))" /> <input type="button" name="boton1" id="boton1" value="Enviar con deshabilitados" onclick="xajax_datos(xajax.getFormValues('form1',true))" /> </body> </html> La diferencia está en el uso de la orden xajax.getFormValues, en la cual se debe incluir un segundo parámetro (true) para obtener los valores incluyendo los objetos deshabilitados. Resultado Web: Figura 247. Formulario de xajax09.php En este ejemplo, el objeto deshabilitado del formulario es la caja de texto: text1. Probemos con los dos botones de envío: Primer botón: sin el envío de los objetos deshabilitados. Oscar E Capuñay Uceda 296 PHP + AJAX Figura 248. Deshabilitando una caja de texto con xajax Obtenemos: Figura 249. Mensaje de resultado de xajax09.php Segundo botón: incluyendo objetos deshabilitados. Figura 250. Incluyendo objetos inhabilitados Obtenemos: Figura 251. Mensaje resultante incluyendo objetos inhabilitados Oscar E Capuñay Uceda 297 PHP + AJAX Error común Uno de los errores comunes que aparecen cuando usamos xajax, es el siguiente: Figura 252. Error comun en xajax Cuando aparece este mensaje, podemos ver al final del mismo la frase: You have whitespace in your response. (Ud tiene espacios en blanco en su response). Esto generalmente se debe a que hemos insertado algunas líneas en blanco o algún carácter en el código HTML antes de iniciar el código de XAJAX. Ejemplo 144: Archivo con una línea en blanco antes de iniciar PHP. xajax_errorcomun.php -- inicio del archivo --<?php require ('xajax/xajax.inc.php'); function datos($formulario) { $frase=$formulario['text1']; $cantidad=count($formulario['chk']); $resultado = "La frase es:" . $frase . "\n"; $resultado.= $cantidad . " temas seleccionados"; $objResponse = new xajaxResponse(); $objResponse->addAlert($resultado); return $objResponse; } $xajax = new xajax(); $xajax->registerFunction("datos"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -- continua el archivo --Oscar E Capuñay Uceda 298 PHP + AJAX Búsqueda en base de datos con XAJAX Ejemplo 145: Búsqueda del nombre según el código con XAJAX xajax_buscar.php <?php require "pagina12.php"; //conexion a la base de datos dbdemo require "xajax/xajax.inc.php"; function buscar($id) { if($id>0) { $rs=mysql_query("select * from persona where idpersona=$id"); if(mysql_num_rows($rs)>0) { $registro=mysql_fetch_array($rs); $nombrecompleto=$registro['nombres'] . " " . $registro['apellidos']; } else { $nombrecompleto="no se encontró el codigo ingresado"; } } $resultado=htmlentities($nombrecompleto); $objResponse = new xajaxResponse(); $objResponse->addAssign("label1","innerHTML",$resultado); return $objResponse; } $xajax = new xajax(); $xajax->registerFunction("buscar"); $xajax->processRequests(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Buscar</title> <?php $xajax->printJavascript('xajax'); ?> </head> <body style="text-align:center;"> IdPersona <input type="text" size="3" name="text1" id="text1" onkeyup="xajax_buscar(this.value)" /> <label id="label1"></label> </body> </html> Oscar E Capuñay Uceda 299 PHP + AJAX En el ejemplo, enviamos el ID de la persona a la función buscar (xajax_buscar) para que sea consultado y luego mostramos el nombre de la persona con dicho Id. Resultado Web: Figura 253. Resultado de xajax-buscar.php Escribimos un IdPersona para ver su nombre completo, si el Id no existe nos mostrará un mensaje adecuado. Figura 254. Datos de búsqueda en xajax-buscar.php Figura 255. Resultado de la búsqueda en xajax-buscar.php Oscar E Capuñay Uceda 300 PHP + AJAX Administración de datos con AJAX Ahora utilizaremos la librería XAJAX para administrar la tabla persona de la base de datos dbdemo. Veremos paso a paso la construcción de las páginas necesarias. Controlador con AJAX Ejemplo 146: Controlador para mantenimiento con AJAX xajax_controlador_persona.php <?php require_once ("xajax_modelo_persona.php"); include ("xajax_logica_persona.php"); $nrxp=5; //numero de registros por pagina $titulo = "Personas"; include ("xajax_vista_persona.php"); ?> xajax_logica_persona.php <?php require_once ("xajax/xajax.inc.php"); require_once ("xajax_modelo_persona.php"); $xajax = new xajax(); function guardar($formulario){ $objpersona = new clspersona(); if($formulario[accion]=="insertar"){ $ssql="insert into persona (nombres, apellidos, email, telefono) values ('".$formulario['nombres']."', '".$formulario['apellidos']."', '".$formulario['email']."','".$formulario['telefono']."')"; if ($objpersona->comando($ssql)) $salida = "Insertado correctamente"; else $salida = "No se ha insertado."; } else{ $sql="update persona set nombres='". $formulario['nombres'] ."', apellidos='". $formulario['apellidos'] ."', email='". $formulario['email'] ."', telefono='". $formulario['telefono'] ."' where idpersona='". $formulario['idpersona']. "'"; if ($objpersona->comando($sql)) $salida = "Editado correctamente"; else $salida = "No se ha editado."; } $respuesta = new xajaxResponse(); $respuesta->addAssign("mensaje","innerHTML",$salida); return $respuesta; } Oscar E Capuñay Uceda 301 PHP + AJAX function ver_datos($id){ $objpersona = new clspersona(); $ssql="select * from persona where idpersona='$id'"; $objpersona->consulta($ssql); $reg=$objpersona->leer_registro(); $respuesta = new xajaxResponse(); $respuesta->addAssign("nombres", "value", $reg['nombres']); $respuesta->addAssign("apellidos", "value", $reg['apellidos']); $respuesta->addAssign("email", "value", $reg['email']); $respuesta->addAssign("telefono", "value", $reg['telefono']); $respuesta->addAssign("accion", "value", "editar"); return $respuesta; } function limpiar(){ $respuesta = new xajaxResponse(); $respuesta->addAssign("nombres", "value", ""); $respuesta->addAssign("apellidos", "value", ""); $respuesta->addAssign("email", "value", ""); $respuesta->addAssign("telefono", "value", ""); $respuesta->addAssign("accion", "value", "insertar"); return $respuesta; } function eliminar($formulario){ $objpersona = new clspersona(); $lista=$formulario[chk]; if(count($lista)>0){ foreach($lista as $k => $v) { $ssql="delete from persona where idpersona='".$v."'"; $objpersona->comando($ssql); } $salida="Elementos eliminados correctamente"; } else $salida="No hay elementos seleccionados"; $respuesta = new xajaxResponse(); $respuesta->addAssign("mensaje","innerHTML",$salida); return $respuesta; } function registros($nrxp,$formulario,$frmbuscar,$pagina) { $objpersona = new clspersona(); $busqueda=" where $frmbuscar[campo] like '%$frmbuscar[texto]%'"; $sql="select * from persona $busqueda"; $objpersona->consulta($sql); $numreg=$objpersona->nr; $orden=$formulario[orden]; $sentido=$formulario[sentido]; Oscar E Capuñay Uceda 302 PHP + AJAX $campo_actual=$formulario[actual]; //sentido if($campo_actual==$orden) { if($sentido=="asc") $sentido="desc"; else $sentido="asc"; } else $sentido="asc"; //$pagina=$formulario[pagina]; $sql.=" order by ".$orden." ".$sentido; //resultados $inicio=($pagina-1)*$nrxp; $sql.=" limit $inicio,$nrxp"; $objpersona->consulta($sql); $nrt=$objpersona->nr; $salida="<table width=\"100%\" class=\"listado\" id=\"tab_registros\">"; for($i=1;$i<=$nrt;$i++){ $reg=$objpersona->leer_registro(); $salida.=" <tr onMouseDown=\"fila(this)\"> <td style=\"width:16\"><input type=\"checkbox\" name=\"chk[]\" value=\"$reg[idpersona]\" onClick=\"setPointer('#D0D090',this)\"></td> <td style=\"width:40px\"><a href=\"#\" onClick=\"xajax_ver_datos('$reg[idpersona]');ver_div('formulario');\"><img src=\"iconos/editar.gif\" border=\"0\"></a></td> <td style=\"width:23%\">$reg[nombres]</td> <td style=\"width:23%\">$reg[apellidos]</td> <td style=\"width:23%\">$reg[email]</td> <td style=\"width:23%\">$reg[telefono]</td> </tr>"; } $encontrados="$numreg registros encontrados"; $salida.="</table>"; $respuesta = new xajaxResponse(); $respuesta->addAssign("registros","innerHTML",$salida); $respuesta->addAssign("mensaje","innerHTML",$encontrados); $respuesta->addAssign("orden","value",$orden); $respuesta->addAssign("sentido","value",$sentido); return $respuesta; } function paginas($nrxp,$frmbuscar,$pagina) { $objpersona = new clspersona(); $busqueda=" where $frmbuscar[campo] like '%$frmbuscar[texto]%'"; $sql="select * from persona $busqueda"; $objpersona->consulta($sql); $mgp=10; //maximo grupo de páginas $salida="Páginas:"; $npag=ceil($objpersona->nr/$nrxp); Oscar E Capuñay Uceda 303 PHP + AJAX for($i=1;$i<=$npag;$i++){ if($i!=$pagina) $enlace="<a href='#' onClick=\"frm1.actual.value='';xajax_registros($nrxp,xajax.getFormValues('fr m1'),xajax.getFormValues('frmbuscar'),'$i');xajax_paginas($nrxp,xajax.getFor mValues('frmbuscar'),'$i');\">$i</a>"; else $enlace=" $i "; $salida.=$enlace." "; } $respuesta = new xajaxResponse(); $respuesta->addAssign("paginas","innerHTML",$salida); return $respuesta; } $xajax->registerFunction("guardar"); $xajax->registerFunction("ver_datos"); $xajax->registerFunction("limpiar"); $xajax->registerFunction("eliminar"); $xajax->registerFunction("registros"); $xajax->registerFunction("paginas"); $xajax->processRequests(); ?> Resultado Web: Listado de personas Figura 256. Listado de persona con xajax Oscar E Capuñay Uceda 304 PHP + AJAX Inserción de registro Figura 257. Inserción de registros con xajax Edición de registro Figura 258. Edición de registro con xajax Oscar E Capuñay Uceda 305 PHP + AJAX Selección de registros Figura 259. Selección de registros con xajax Búsqueda de registros Figura 260. Búsqueda de registros con xajax Capa de Datos con AJAX Ejemplo 147: Modelo para mantenimiento con AJAX xajax_modelo_persona.php <?php require_once "xajax_conexion.php"; class clspersona { protected $rs; //resultado de una sentencia sql public $nr; //numero de registros public function leer_registro() { Oscar E Capuñay Uceda 306 PHP + AJAX $reg=mysql_fetch_array($this->rs,MYSQL_ASSOC) or die(mysql_error()); return $reg; } public function consulta($sql) { $objBase = new BaseDatos(); $objBase->conectar(); $rs=$objBase->query($sql); $this->rs=$rs; $this->nr=$objBase->num_rows($this->rs); } public function comando($sql) { $objBase = new BaseDatos(); $objBase->conectar(); $rs=$objBase->query($sql); $this->rs=$rs; return $this->rs; } } ?> xajax_conexion.php <?php class BaseDatos { protected $servidor="localhost"; protected $usuario="root"; protected $password=""; public function conectar() { $link=mysql_connect($this->servidor,$this->usuario,$this>password) or die(mysql_error()); mysql_select_db("dbdemo",$link) or die(mysql_error()); } public function query($sql) { $rs=mysql_query($sql) or die(mysql_error()); return $rs; } public function num_rows($rs) { $nr=mysql_num_rows($rs) or die(mysql_error()); return $nr; } } ?> Oscar E Capuñay Uceda 307 PHP + AJAX Vista con AJAX Ejemplo 148: Vista para mantenimiento con AJAX xajax_vista_persona.php <html lang="es"> <head> <title>Personas</title> <script type="text/javascript" src="js/funciones.js"></script> <?php $xajax->printJavascript('xajax/');?> <link href="css/estilo.css" rel="stylesheet" type="text/css"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head> <body> <div id="menu"> <table width="100%"> <caption><?php echo $titulo?></caption> <tr> <td class="menu"> <a href="#" onClick="xajax_limpiar();ver_div('formulario');"><img src="iconos/nuevo.gif" height="16" alt="nuevo"></a> <a href="#" onClick="xajax_eliminar(xajax.getFormValues('frmlistado')); xajax_paginas(<?php echo $nrxp?>,xajax.getFormValues('frmbuscar'),frm1.pagina.value);xajax_registro s(<?php echo $nrxp?>,xajax.getFormValues('frm1'),xajax.getFormValues('frmbuscar'),'1');"> <img src="iconos/borrar.gif" height="16" alt="borrar"></a> <a href="#" onClick="ver_div('busqueda')"> <img src="iconos/buscar.gif" height="16" alt="buscar"></a> </td> </tr> </table> </div> <div id="busqueda" style="display: none;"> <form name="frmbuscar" id="frmbuscar" method="post" action=""> <table width="100%"> <tr><td class="etiqueta">Campo</td> <td> <select name="campo" class="campo"> <option value="nombres">Nombres</option> <option value="apellidos">Apellidos</option> <option value="email">E-Mail</option> <option value="telefono">Teléfono</option> </select> <input type="text" id="texto" name="texto" class="campo"> <input type="button" value="Buscar" onClick="xajax_registros(<?php echo $nrxp?>,xajax.getFormValues('frm1'),xajax.getFormValues('frmbuscar'),'1');x Oscar E Capuñay Uceda 308 PHP + AJAX ajax_paginas(<?php echo $nrxp?>,xajax.getFormValues('frmbuscar'),frm1.pagina.value);" class="boton"> <input type="button" onClick="frmbuscar.texto.value='';xajax_registros(<?php echo $nrxp?>,xajax.getFormValues('frm1'),xajax.getFormValues('frmbuscar'),'1');x ajax_paginas(<?php echo $nrxp?>,xajax.getFormValues('frmbuscar'),frm1.pagina.value);ocultar_div('bu squeda'); return false;" value="Ver Todos" class="boton"></td></tr> </table> </form> </div> <div id="formulario" style="display: none;"> <form name="frm1" id="frm1" action=""> <div id="ocultos"> <input type="hidden" name="accion" id="accion" value=""> <input type="hidden" name="orden" id="orden" value="1"> <input type="hidden" name="actual" id="actual" value=""> <input type="hidden" name="sentido" id="sentido" value="asc"> <input type="hidden" name="pagina" id="pagina" value="1"> </div> <table width="100%"> <tr> <td class="etiqueta">Nombres</td> <td><input name="nombres" type="text" class="campo" id="nombres" size="50"></td> </tr> <tr> <td class="etiqueta">Apellidos</td> <td><input name="apellidos" type="text" class="campo" id="apellidos" size="50"></td> </tr> <tr> <td class="etiqueta">E-Mail</td> <td><input name="email" type="text" class="campo" id="email" size="60"></td> </tr> <tr> <td class="etiqueta">Teléfono</td> <td><input name="telefono" type="text" class="campo" id="telefono" size="15"></td> </tr> <tr> <th colspan="2"> <input type="button" value="Guardar" onClick="xajax_guardar(xajax.getFormValues('frm1'));xajax_registros(<?php echo $nrxp?>,xajax.getFormValues('frm1'),xajax.getFormValues('frmbuscar'),'1');x ajax_paginas(<?php echo $nrxp?>,xajax.getFormValues('frmbuscar'),frm1.pagina.value);ocultar_div('for mulario')" class="boton"> Oscar E Capuñay Uceda 309 PHP + AJAX <input type="button" onClick="ocultar_div('formulario'); return false;" value="Cancelar" class="boton"></th> </tr> </table> </form> </div> <div id="mensaje" class="mensaje"> </div> <div id="encabezado"> <form action=""> <table width="100%" class="listado"> <tr> <th style="width:16px"><input type="checkbox" name="allcheck" value="checkbox" title="Selecciona todos" onClick="seleccionar_all('#D0D090',3);"></th> <th style="width:40px">Editar</th> <th style="width:24%"><?php enlacelis("Nombres",2,$nrxp,1) ?></th> <th style="width:24%"><?php enlacelis("Apellidos",3,$nrxp,1) ?></th> <th style="width:24%"><?php enlacelis("E-Mail",4,$nrxp,1) ?></th> <th style="width:24%"><?php enlacelis("Telefono",5,$nrxp,1) ?></th> </tr> </table> </form> </div> <form id="frmlistado" name="frmlistado" action=""> <div id="registros"> </div> </form> <div id="paginas" class="paginado"> </div> <script type="text/javascript"> xajax_registros(<?php echo $nrxp?>,xajax.getFormValues('frm1'),xajax.getFormValues('frmbuscar'),'1'); xajax_paginas(<?php echo $nrxp?>,xajax.getFormValues('frmbuscar'),frm1.pagina.value); </script> </html> <?php function enlacelis($titulo_columna,$campo_orden,$nrxp,$pagina) { echo "<a href=\"#\" onClick=\"frm1.orden.value='$campo_orden'; xajax_registros($nrxp,xajax.getFormValues('frm1'),xajax.getFormValues('frm buscar'),'$pagina'); xajax_paginas($nrxp,xajax.getFormValues('frmbuscar'),frm1.pagina.value); frm1.actual.value='$campo_orden';\">$titulo_columna</a>"; } ?> Ejemplo 149: Sombreado de registros con JavaScript Oscar E Capuñay Uceda 310 PHP + AJAX funciones.js <!-// JavaScript Document var filasel; function fila(filsel){ filasel = filsel; return filasel; } function setPointer(Color, check) { var theRow=filasel; var theCells = theRow.getElementsByTagName('td'); var theCells = theRow.cells; var rowCellsCnt = theCells.length; for (var c = 0; c < rowCellsCnt; c++) { if(check.checked==true){ theCells[c].style.backgroundColor = Color; }else { theCells[c].style.backgroundColor = ''; // #d6e7ef } } return true; } function seleccionar_all(Color,id){ var activo; Tab = document.all.tab_registros; id0=id-1; for(var x=0; x<document.forms[id].length; x++ ){ if(document.forms[id0].allcheck.checked && document.forms[id].elements[x].type=="checkbox"){ document.forms[id].elements[x].checked = true; }else{ document.forms[id].elements[x].checked = false; } } for (r=0; r<Tab.rows.length; r++){ for(c=0; c< Tab.rows[r].cells.length; c++){ if(Tab.rows[r].cells[c].tagName!="TH"){ if(document.forms[id0].allcheck.checked){ Tab.rows[r].cells[c].style.backgroundColor= Color; }else{ Tab.rows[r].cells[c].style.backgroundColor=""; } } } Oscar E Capuñay Uceda 311 PHP + AJAX } } function compCheck(){ var sw=0; for(var x=0; x<document.forms[0].length; x++ ){ if (document.forms[0].elements[x].checked){ sw=1; } } if(sw!=1){ alert ("Por favor, selecciona los registros quee deseas elimiar."); return(false); } } function toggle(obj){ var objID = document.getElementById(obj); objID.style.display = (objID.style.display == "none")?"":"none"; } function ver_div(obj){ var objID = document.getElementById(obj); objID.style.display ="block"; } function ocultar_div(obj){ var objID = document.getElementById(obj); objID.style.display ="none"; } --> Oscar E Capuñay Uceda 312 Referencias Bibliográficas X. REFERENCIAS BIBLIOGRAFICAS [1] ACHOUR Mehdi, BETZ Friedhelm, DOVGAL Antony, Manual Oficial de PHP – Que es PHP, http://www.php.net/docs.php, Abril 2007 [2] RAYA CABRERA José Luis. HTML 4 Guía de referencia y tutorial. http://www.bio.cam.ac.uk/cgi-lib/ [3] ACHOUR Mehdi, BETZ Friedhelm, DOVGAL Antony, Manual Oficial de PHP – Expresiones, http://www.php.net/docs.php, Abril 2007 [4] ACHOUR Mehdi, BETZ Friedhelm, DOVGAL Antony, Manual Oficial de PHP – Operadores, http://www.php.net/docs.php, Abril 2007 [5] OMER, MVC con PHP, http://www.phpizza.com/es/. 2007 [6] AJAX. http://es.wikipedia.org/wiki/AJAX . mayo 2007 [7] WHITE Jare, J. WILSON Max, ROBB Eion. XAJAX PHP Class Library. http://wiki.xajaxproject.org/0.2.5_Release_Notes. [8] CAPTCHA. http://www.wikipedia.org . Web visitada el 5 de junio del 2008. Oscar E Capuñay Uceda 313 Anexos XI. Anexos Lista de Ejemplos Ejemplo 1: Ejemplo 2: Ejemplo 3: Ejemplo 4: Ejemplo 5: Ejemplo 6: Ejemplo 7: Ejemplo 8: Ejemplo 9: Ejemplo 10: Ejemplo 11: Ejemplo 12: Ejemplo 13: Ejemplo 14: Ejemplo 15: Ejemplo 16: Ejemplo 17: Ejemplo 18: Ejemplo 19: Ejemplo 20: Ejemplo 21: Ejemplo 22: Ejemplo 23: Ejemplo 24: Ejemplo 25: Ejemplo 26: Ejemplo 27: Ejemplo 28: Ejemplo 29: Ejemplo 30: Ejemplo 31: Ejemplo 32: Ejemplo 33: Ejemplo 34: Ejemplo 35: Ejemplo 36: Ejemplo 37: Ejemplo 38: Ejemplo 39: Ejemplo 40: Ejemplo 41: Ejemplo 42: Ejemplo 43: Ejemplo 44: Ejemplo 45: TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT Primera página Web _______________________________ 18 Comentarios _____________________________________ 22 Uso de tildes _____________________________________ 24 Enlaces _________________________________________ 27 Imágenes ________________________________________ 29 Tablas __________________________________________ 31 Ejemplo de Tablas en HTML _________________________ 37 Formulario solicitando los comentarios del usuario: _______ 40 Confirmación de la inclusión en una lista de correo: _______ 41 Formulario 2 _____________________________________ 43 Uso de frames ___________________________________ 46 Acrónimos y Abreviaturas __________________________ 49 Frase entre comillas_______________________________ 49 INS y DEL ______________________________________ 50 OBJECT Y PARAM _______________________________ 51 Uso de TABLA, THEAD, TFOOT y TBODY _____________ 52 Button con imagen ________________________________ 54 Formulario con OPTGROUP ________________________ 55 Ejemplo de Conjunto de Campos ____________________ 56 DIV y SPAN _____________________________________ 58 función alert _____________________________________ 61 Eventos ________________________________________ 76 Definición mediante código _________________________ 77 Función open() ___________________________________ 79 Escribir HTML con javascript ________________________ 83 Select con javascript ______________________________ 87 Uso de archivos js ________________________________ 90 HTML y CSS ____________________________________ 92 Style ___________________________________________ 93 Colores con CSS _________________________________ 94 Definición de constantes __________________________ 100 Considera la siguiente función ______________________ 100 Operador de asignación___________________________ 103 Operadores de asignación combinados ______________ 103 Operador ternario _______________________________ 104 Comportamiento Ternario No-Obvio _________________ 105 Control de errores _______________________________ 106 Operador de ejecución____________________________ 106 Operadores de incremento y decremento _____________ 107 Incremento y decremento con variables tipo carácter. ___ 107 Operadores de cadena ___________________________ 108 Operadores de matrices __________________________ 109 Comparación de matrices _________________________ 110 Uso de instanceof con clases ______________________ 110 Uso de instanceof con clases heredadas _____________ 111 UT UT UT UT UT UT UT UT UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT Oscar E Capuñay Uceda 314 Anexos Ejemplo 46: Ejemplo 47: Ejemplo 48: Ejemplo 49: Ejemplo 50: Ejemplo 51: Ejemplo 52: Ejemplo 53: Ejemplo 54: Ejemplo 55: Ejemplo 56: Ejemplo 57: Ejemplo 58: Ejemplo 59: Ejemplo 60: Ejemplo 61: Ejemplo 62: Ejemplo 63: Ejemplo 64: Ejemplo 65: Ejemplo 66: Ejemplo 67: Ejemplo 68: Ejemplo 69: Ejemplo 70: Ejemplo 71: Ejemplo 72: Ejemplo 73: Ejemplo 74: Ejemplo 75: Ejemplo 76: Ejemplo 77: Ejemplo 78: Ejemplo 79: Ejemplo 80: Ejemplo 81: Ejemplo 82: Ejemplo 83: Ejemplo 84: Ejemplo 85: Ejemplo 86: Ejemplo 87: Ejemplo 88: Ejemplo 89: Ejemplo 90: Ejemplo 91: Ejemplo 92: Ejemplo 93: Ejemplo 94: Ejemplo 95: Ejemplo 96: TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU TU UT TU Uso de instanceof para una clase ___________________ 111 Uso de instanceof con otras variables ________________ 112 If ejecuta una sentencia si la condición es verdadera ____ 113 If con varias sentencias si la condición es verdadera ____ 113 If anidado ______________________________________ 114 Uso de else en una sentencia if _____________________ 114 Uso de elseif ___________________________________ 114 Imprimir los números del 1 al 10 utilizando la sentencia for 115 Imprimir los números del 1 al 10 utilizando while _______ 116 Pagina01.php ___________________________________ 117 Comentarios ___________________________________ 119 Sentencia if (1) __________________________________ 119 Sentencia if (2) __________________________________ 119 Sentencia if (3) __________________________________ 120 Sentencia for (1) ________________________________ 121 Sentencia for (2) ________________________________ 122 Sentencia for (3) ________________________________ 123 Envío de datos de un formulario a una página PHP _____ 124 Subir un archivo al servidor Web ____________________ 129 Conexión a MySQL ______________________________ 143 Listado de registros ______________________________ 143 Listado de registros en una tabla ____________________ 144 Inserción de registros en una tabla __________________ 145 Edición de registros ______________________________ 147 Eliminación de registros ___________________________ 149 Conexión a PostgreSQL __________________________ 170 Listado de registros en una tabla HTML. ______________ 171 Inserción de registro en PostgreSQL. ________________ 172 Edición de registro en PostgreSQL.__________________ 174 Eliminación de registro en PostgreSQL. ______________ 176 Conexión a MS-SQLServer ________________________ 180 Listado de registros ______________________________ 181 Inserción de registro en MS-SQLServer ______________ 182 Edición de registro en MS-SQLServer ________________ 184 Eliminación de registros en MS-SQLServer ___________ 185 Definición de una clase ___________________________ 187 Creando una instancia ____________________________ 187 Herencia simple de una Clase ______________________ 188 Auto carga _____________________________________ 189 Conexión a MySQL con mysqli _____________________ 195 Listado con mysqli _______________________________ 196 Inserción de registro con mysqli ____________________ 197 Edición de registro con mysqli ______________________ 199 Eliminación de registros con mysqli __________________ 201 Paginación de resultados__________________________ 202 MODELO – MVC con PHP ________________________ 209 Una plantilla usada por el modelo ___________________ 209 CONTROLADOR MVC con PHP ___________________ 210 VISTA MVC con PHP ____________________________ 210 modelo_bd.php _________________________________ 212 lista_bd.php ____________________________________ 213 UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT UT Oscar E Capuñay Uceda 315 Anexos Ejemplo 97: vista_bd.php ___________________________________ Ejemplo 98: controlador_bd.php ______________________________ Ejemplo 99: Conexión a MySQL con PDO ______________________ Ejemplo 100: Lista de personas con PDO y manejo de errores ______ Ejemplo 101: Listado de registros con PDO, con eliminación múltiple _ Ejemplo 102: Inserción de registros con PDO ____________________ Ejemplo 103: Eliminación múltiple de registros con PDO ___________ Ejemplo 104: Edición de registros con PDO. _____________________ Ejemplo 105: Borrar un archivo de un usuario____________________ Ejemplo 106: Ataque mediante el borrado de archivos _____________ Ejemplo 107: Md5 _________________________________________ Ejemplo 108: Script para acceso de usuarios ____________________ Ejemplo 109: Inyección SQL en una sentencia SELECT ___________ Ejemplo 110: Paginación de resultados con Inyección SQL _________ Ejemplo 111: get_magic_quotes_gpc y addslashes _______________ Ejemplo 112: mysqli_real_escape_string _______________________ Ejemplo 113: Ingreso de un usuario a la aplicación _______________ Ejemplo 114: Verifica datos del usuario_________________________ Ejemplo 115: Autenticación HTTP _____________________________ Ejemplo 116: Formulario para el logeo de usuarios _______________ Ejemplo 117: Logeo de usuarios ______________________________ Ejemplo 118: Verifica si el usuario se ha logeado _________________ Ejemplo 119: Formulario CAPTCHA ___________________________ Ejemplo 120: Generador CAPTCHA ___________________________ Ejemplo 121: Ver configuración GD____________________________ Ejemplo 122: Mi primera imagen ______________________________ Ejemplo 123: Rectángulo y texto ______________________________ Ejemplo 124: Gráfico de barras _______________________________ Ejemplo 125: Pie __________________________________________ Ejemplo 126: Círculo _______________________________________ Ejemplo 127: FPDF ________________________________________ Ejemplo 128: PDF con salto de página _________________________ Ejemplo 129: PDF con capítulos ______________________________ Ejemplo 130: PDF con datos de MySQL ________________________ Ejemplo 131: XLS simple ____________________________________ Ejemplo 132: XLS con fórmulas ______________________________ Ejemplo 133: XLS con xlsStream _____________________________ Ejemplo 134: XLS con datos de MySQL ________________________ Ejemplo 135: Asignación de valores a propiedades de un objeto HTML Ejemplo 136: Asignación de HTML a innerHTML de una etiqueta DIV _ Ejemplo 137: Asignación de innerHTML y estilos con XAJAX _______ Ejemplo 138: Ocultar y Mostrar un DIV _________________________ Ejemplo 139: Imprimir números del 1 a N _______________________ Ejemplo 140: Cargar una imagen con XAJAX ____________________ Ejemplo 141: Cambiar el código javascript establecido para un evento Ejemplo 142: Obtener datos de un formulario ____________________ Ejemplo 143: Obtener datos incluyendo objetos deshabilitados. _____ Ejemplo 144: Archivo con una línea en blanco antes de iniciar PHP. __ Ejemplo 145: Búsqueda del nombre según el código con XAJAX ____ Ejemplo 146: Controlador para mantenimiento con AJAX ___________ Ejemplo 147: Modelo para mantenimiento con AJAX ______________ TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT TU UT 213 213 218 218 219 220 222 222 225 226 227 228 229 229 239 240 243 244 246 249 250 251 253 254 257 257 258 259 260 262 265 267 269 272 274 275 277 278 282 284 285 287 288 289 291 293 295 298 299 301 306 316 Oscar E Capuñay Uceda Anexos Ejemplo 148: Ejemplo 149: TU UT TU TU UT TU Vista para mantenimiento con AJAX ________________ 308 Sombreado de registros con JavaScript _____________ 310 UT UT Oscar E Capuñay Uceda 317 Anexos Lista de Tablas Tabla 1. Tabla 2. Tabla 3. Tabla 4. Tabla 5. Tabla 6. Tabla 7. Tabla 8. Tabla 9. Tabla 10. Tabla 11. Tabla 12. Tabla 13. Tabla 14. Tabla 15. Tabla 16. Tabla 17. Tabla 18. Tabla 19. Tabla 20. T Códigos HTML para caracteres especiales ________________ 23 Códigos HTML para caracteres especiales ________________ 24 Caracteres especiales para cadenas en JavaScript __________ 63 Operadores aritméticos________________________________ 65 Operadores de comparación ___________________________ 66 Operadores lógicos___________________________________ 66 Operadores de asignación _____________________________ 67 Operadores especiales ________________________________ 67 Métodos matemáticos del Objeto Math____________________ 73 Propiedades del objeto Number _________________________ 74 Eventos de JavaScript ________________________________ 75 Comando CSS ______________________________________ 95 Macros CSS ________________________________________ 96 Secciones CSS ______________________________________ 97 Operadores aritméticos de PHP ________________________ 103 Operadores de comparación de PHP ____________________ 104 Operadores de incremento y decremento de PHP __________ 106 Operadores lógicos__________________________________ 108 Operadores de matrices ______________________________ 109 Controladores PDO__________________________________ 215 Oscar E Capuñay Uceda 318 Anexos Lista de Figuras Figura 1. Figura 2. Figura 3. Figura 4. Figura 5. Figura 6. Figura 7. Figura 8. Figura 9. Figura 10. Figura 11. Figura 12. Figura 13. Figura 14. Figura 15. Figura 16. Figura 17. Figura 18. Figura 19. Figura 20. Figura 21. Figura 22. Figura 23. Figura 24. Figura 25. Figura 26. Figura 27. Figura 28. Figura 29. Figura 30. Figura 31. Figura 32. Figura 33. Figura 34. Figura 35. Figura 36. Figura 37. Figura 38. Figura 39. Figura 40. Figura 41. Figura 42. Figura 43. Figura 44. Figura 45. Figura 46. Figura 47. Figura 48. U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U Inicio de la instalación de WAMP ______________________ Licencia de uso de WAMP____________________________ Destino de la instalación de WAMP_____________________ Seleccionar menú de inicio de WAMP___________________ Inicio de WAMP en el arranque del Sistema Operativo. _____ Resumen de la configuración de la instalación ____________ Instalando WAMP __________________________________ Instalación de WAMP completa________________________ Menú de WAMP____________________________________ Resultado de ejercicio01.html _________________________ Lista sin orden _____________________________________ Listas sin orden anidadas ____________________________ Lista ordenada _____________________________________ Lista de definiciones ________________________________ Resultado de ejercicio02.html _________________________ Resultado de ejercicio03.html _________________________ Resultado de ejercicio04.html _________________________ Resultado de ejercicio05.html _________________________ Tabla HTML _______________________________________ Tabla sin una celda _________________________________ Tabla con etiqueta CAPTION _________________________ Tabla con etiqueta TH _______________________________ Tabla con COLSPAN________________________________ Tabla con ROWSPAN _______________________________ Tabla con CELLSPACING y CELLPADDING _____________ Resultado de ejemplo06.html _________________________ Resultado de ejemplo08.html _________________________ Marcos o Frames___________________________________ Marcos con división horizontal_________________________ Acrónimos y abreviaturas ____________________________ Frase entre comillas ________________________________ Acrónimos y abreviaturas ____________________________ Animación flash ____________________________________ Tabla con THEAD, TFOOT Y TBODY ___________________ BUTTON con imagen _______________________________ Lista con OPTGROUP_______________________________ Formulario con agrupamiento de controles _______________ Ejemplo de página con DIVs y SPANs __________________ Resultado de eventos.html ___________________________ Resultado del método alert ___________________________ Resultado de load1.html _____________________________ Resultado del método alert ___________________________ Resultado de ventanas.html __________________________ La nueva ventana abierta ____________________________ Resultado de escribir.html ____________________________ Resultado de formularios.html _________________________ Mensaje de validación _______________________________ Resultado de select.html _____________________________ 11 12 12 13 13 14 14 15 15 18 20 20 21 21 23 25 28 30 32 32 33 34 35 36 37 38 40 47 48 49 50 50 52 53 55 56 57 60 76 76 77 78 80 81 83 85 85 87 319 Oscar E Capuñay Uceda Anexos Figura 49. Resultado de operadores_i.php_______________________ 108 Figura 50. Resultado de operadores_m.php _____________________ 109 Figura 51. Resultado de comp_matrices.php _____________________ 110 Figura 52. Resultado de instanciade.php ________________________ 111 Figura 53. Resultado de instanciadehe.php ______________________ 111 Figura 54. Resultado de pagina01.php__________________________ 118 Figura 55. Resultado de pagina04.php__________________________ 121 Figura 56. Resultado de pagina05.php__________________________ 122 Figura 57. Resultado de pagina06.php__________________________ 123 Figura 58. Resultado de formulario01.html_______________________ 125 Figura 59. Resultado de pagina08.php__________________________ 125 Figura 60. Resultado de formulario02.html_______________________ 126 Figura 61. Resultado de pagina09.php__________________________ 126 Figura 62. URL incluyendo datos enviados ______________________ 126 Figura 63. Resultado de formulario03.html_______________________ 127 Figura 64. Resultado de pagina10.php__________________________ 128 Figura 65. Resultado de formulario03.html (segundo caso) __________ 129 Figura 66. Resultado de pagina10.php (segundo caso) _____________ 129 Figura 67. Resultado de formulario04.html_______________________ 129 Figura 68. Selección de un archivo en un formulario _______________ 130 Figura 69. Datos de un archivo enviado al servidor ________________ 131 Figura 70. Conexión al servidor MySQL con MySQL Administrador ___ 132 Figura 71. Inicio de MySQL Administrator _______________________ 132 Figura 72. Menú de MySQL Administrator _______________________ 133 Figura 73. Creando una base de datos _________________________ 133 Figura 74. Base de datos creada en MySQL Administrator __________ 134 Figura 75. Creando una tabla _________________________________ 134 Figura 76. Ingreso del nombre de la tabla _______________________ 135 Figura 77. Definición de campos de la tabla______________________ 135 Figura 78. Estructura de la tabla_______________________________ 135 Figura 79. Confirmación para la creación de la tabla _______________ 136 Figura 80. Lista de elementos incluyendo la tabla recientemente creada 136 Figura 81. Interfaz de phpMyAdmin ____________________________ 137 Figura 82. Interfaz para cear una nueva base de datos _____________ 138 Figura 83. Creando la base de datos dbdemo.____________________ 138 Figura 84. Creando la tabla persona. ___________________________ 139 Figura 85. Especificación de los campos de la tabla _______________ 139 Figura 86. Autoincremento en el campo idpersona. ________________ 139 Figura 87. Estructura de la tabla creada_________________________ 140 Figura 88. Menú de operaciones que se pueden realizar sobre las tablas de la base de datos.____________________________________________ 140 Figura 89. Formularios para la inserción de registros_______________ 141 Figura 90. Datos para los nuevos registros ______________________ 141 Figura 91. Operación realizada con éxito y el script SQL que ha sido ejecutado. 142 Figura 92. Listado de registros de la tabla persona ________________ 142 Figura 93. Resultado de pagina13.php__________________________ 144 Figura 94. Resultado de pagina14.php__________________________ 145 Figura 95. Formulario05.html _________________________________ 146 Figura 96. Resultado de pagina15.php__________________________ 147 Figura 97. Formulario de edición de un registro ___________________ 149 U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U Oscar E Capuñay Uceda 320 Anexos Figura 98. Figura 99. Figura 100. Figura 101. Figura 102. Figura 103. Figura 104. Figura 105. Figura 106. Figura 107. Figura 108. Figura 109. Figura 110. Figura 111. Figura 112. Figura 113. Figura 114. Figura 115. Figura 116. Figura 117. Figura 118. Figura 119. Figura 120. Figura 121. Figura 122. Figura 123. Figura 124. Figura 125. Figura 126. Figura 127. Figura 128. Figura 129. Figura 130. Figura 131. Figura 132. Figura 133. Figura 134. Figura 135. Figura 136. Figura 137. Figura 138. Figura 139. Figura 140. Figura 141. Figura 142. Figura 143. Figura 144. Figura 145. Figura 146. Figura 147. Figura 148. U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U Resultado de pagina17.php__________________________ Archivos de instalación de PostgreSQL_________________ Asistente de instalación de PostgreSQL ________________ Inicio del asistente de instalación _____________________ Notas de instalación _______________________________ Opciones de instalación_____________________________ onfiguración del servicio ____________________________ Error en la cuenta _________________________________ Password aleatorio ________________________________ Cuenta del superusuario ____________________________ Habilitar lenguaje procedural _________________________ El asistente está listo para iniciar la instalación___________ Instalando PostgreSQL _____________________________ Instalación completa _______________________________ pgAdmin III_______________________________________ Conexión al servidor desde pgAdmin III ________________ Listado de elementos del servidor _____________________ Creando una base de datos _________________________ Datos de la nueva base de datos _____________________ Creando una nueva tabla ___________________________ Propiedades de la tabla _____________________________ Propiedades de una nueva columna ___________________ Columna nombres de la tabla persona _________________ Clave primaria de la tabla persona ____________________ Columnas pertenecientes a la clave primaria ____________ Script SQL generado para la creación de la tabla _________ Final de la creación de la tabla _______________________ Menú desplegable de la tabla ________________________ Vista de datos de la tabla ___________________________ Editando datos en la tabla ___________________________ Interfaz de phpPgAdmin ____________________________ Logeo de usuarios al servidor PostgreSQL ______________ Interfaz de ingreso a phpPgAdmin ____________________ Creando una nueva base de datos ____________________ Base de datos dbdemo creada _______________________ Menú de elementos de la base de datos ________________ creando la tabla persona ____________________________ Ingresando los campos de la tabla ____________________ Autoincremento para la clave primaria _________________ Estructura de la tabla_______________________________ Formulario de ingreso de nuevos registros ______________ Listado de registros ________________________________ Activando la extensión php_pgsql _____________________ Resultado de pagina23.php__________________________ Resultado de pagina24.php__________________________ Resultado de formulario06.html_______________________ Resultado de pagina25.php__________________________ Resultado de pagina26.php__________________________ Resultado de pagina27.php__________________________ Resultado de pagina28.php__________________________ Creando un nueva base de datos _____________________ 149 151 151 152 152 153 153 154 154 154 155 155 156 156 157 157 158 158 159 159 160 160 161 161 162 162 163 163 164 164 165 165 166 166 167 167 167 168 168 168 169 169 170 171 172 173 174 175 176 176 177 321 Oscar E Capuñay Uceda Anexos Figura 149. Figura 150. Figura 151. Figura 152. Figura 153. Figura 154. Figura 155. Figura 156. Figura 157. Figura 158. Figura 159. Figura 160. Figura 161. Figura 162. Figura 163. Figura 164. Figura 165. Figura 166. Figura 167. Figura 168. Figura 169. Figura 170. Figura 171. Figura 172. Figura 173. Figura 174. Figura 175. Figura 176. Figura 177. Figura 178. Figura 179. Figura 180. Figura 181. Figura 182. Figura 183. Figura 184. Figura 185. Figura 186. Figura 187. Figura 188. Figura 189. Figura 190. Figura 191. Figura 192. Figura 193. Figura 194. Figura 195. Figura 196. Figura 197. Figura 198. Figura 199. U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U Nombre de la nueva base de datos ____________________ Creando una nueva tabla ___________________________ Especificación de los campos de la tabla _______________ Activando la extensión php_mssql ____________________ Creando un usuario para acceso a la base de datos ______ Establecimiento de los permisos del usuario_____________ Resultado de pagina30.php__________________________ Resultado de pagina32.php__________________________ Resultado de pagina33.php__________________________ Resultado de pagina34.php__________________________ Resultado de pagina35.php__________________________ Resultado de pagina20.php__________________________ Resultado de pagina21.php__________________________ Resultado de autocarga.php _________________________ Resultado de mysqli-connect.php _____________________ Resultado de mysqli-lista.php ________________________ Resultado de mysqli-listado.php ______________________ Resultado de formulario08.htm _______________________ Resultado de mysqli-insertar.php _____________________ Resultado de mysqli-editar.php _______________________ Resultado de mysqli-actualizar.php____________________ Resultado de mysqli-eliminar.php _____________________ Resultado de mysqli-listado-paginacion.php _____________ MVC____________________________________________ Tres capas _______________________________________ Resultado de controlador_bd.php _____________________ Resultado de pdo-lista.php __________________________ Resultado de pdo-listado.php ________________________ Resultado de pdo-nuevo.php_________________________ Resultado de pdo-editar.php _________________________ Resultado de md5.php______________________________ Resultado de inyeccion01.php________________________ Nuevo resultado de inyeccion01.php___________________ Tercer resultado de inyeccion01.php___________________ URL con inyección SQL_____________________________ Resultado de la inyección SQL _______________________ Evitando la inyección SQL___________________________ Resultado sin inyección realizada _____________________ Tabla usuario _____________________________________ Resultado de formulario09.html_______________________ Resultado de inyeccion03.php________________________ Logeo con inyección SQL ___________________________ Nuevo resultado de inyeccion03.php___________________ Tercer resultado de inyeccion03.php___________________ Resultado de formulario10.html_______________________ Resultado de comillas-magicas.php ___________________ Resultado de inyeccion04.php________________________ Resultado de ingreso01.php _________________________ Ingreso01.php con datos incorrectos___________________ Logeo incorrecto __________________________________ Autenticación http con PHP __________________________ 177 178 178 179 179 180 181 183 185 185 186 188 189 190 195 196 197 198 199 200 201 201 203 205 207 214 219 220 221 223 227 231 231 232 232 232 234 234 235 236 236 237 237 238 239 239 241 244 245 245 246 322 Oscar E Capuñay Uceda Anexos Figura 200. Figura 201. Figura 202. Figura 203. Figura 204. Figura 205. Figura 206. Figura 207. Figura 208. Figura 209. Figura 210. Figura 211. Figura 212. Figura 213. Figura 214. Figura 215. Figura 216. Figura 217. Figura 218. Figura 219. Figura 220. Figura 221. Figura 222. Figura 223. Figura 224. Figura 225. Figura 226. Figura 227. Figura 228. Figura 229. Figura 230. Figura 231. Figura 232. Figura 233. Figura 234. Figura 235. Figura 236. Figura 237. Figura 238. Figura 239. Figura 240. Figura 241. Figura 242. Figura 243. Figura 244. Figura 245. Figura 246. Figura 247. Figura 248. Figura 249. Figura 250. U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U U Resultado de auth01.php____________________________ Autenticación con datos correctos_____________________ Resultado de auth01.php con datos correctos ___________ Tabla usuario _____________________________________ registro de un usuario ______________________________ Resultado de entrar.php ____________________________ Resultado de entrar.php con datos incorrectos ___________ Resultado de mysqli-listadologeado.php ________________ Ejemplo1 de CAPTCHA_____________________________ Ejemplo2 de CAPTCHA_____________________________ Ejemplo3 de CAPTCHA_____________________________ Resultado de gdinfo.php ____________________________ Resultado de imagen01.php _________________________ Resultado de imagen02.php _________________________ Resultado de imagen03.php _________________________ Resultado de imagen04.php _________________________ Resultado de imagen05.php _________________________ Resultado de imagen06.php _________________________ Resultado de pdf01.php_____________________________ Resultado de pdf02.php_____________________________ Segunda página de pdf01.php________________________ Resultado de pdf03.php_____________________________ Resultado de pdf04.php_____________________________ Abriendo xls01.php ________________________________ Hoja de calculo con xls01.php ________________________ Abriendo xls02.php ________________________________ resumen.xls generado con xls02.php __________________ Resultado de xls03.php _____________________________ Resultado de xls04.php _____________________________ Abriendo xls05.php ________________________________ Resultado de xls05.php _____________________________ Resultado de xajax01.php ___________________________ Resultado de xajax02.php ___________________________ Cambio de contenido con xajax02.php _________________ Resultado de xajax03.php ___________________________ Resultado de xajax04.php ___________________________ Ocultando un DIV _________________________________ Resultado de xajax05.php ___________________________ Resultado de xajax06.php ___________________________ Imagen cargada con xajax06.php _____________________ Segunda imagen cargada con xajax06.php______________ Resultado de xajax07.php ___________________________ Ventana nueva con xajax07.php ______________________ Mensaje utilizando eventos en xajax07.php _____________ Resultado de xajax08.php ___________________________ Ingreso de datos en xajax08.php______________________ Mensaje resultante en xajax08.php ____________________ Formulario de xajax09.php __________________________ Deshabilitando una caja de texto con xajax______________ Mensaje de resultado de xajax09.php __________________ Incluyendo objetos inhabilitados ______________________ 247 247 247 248 248 249 251 252 256 256 256 257 258 258 259 260 262 263 265 268 268 272 273 275 275 276 276 278 279 280 280 283 284 285 286 288 288 289 290 291 291 292 293 293 294 295 295 296 297 297 297 323 Oscar E Capuñay Uceda Anexos Figura 251. Figura 252. Figura 253. Figura 254. Figura 255. Figura 256. Figura 257. Figura 258. Figura 259. Figura 260. U U U U U U U U U U Mensaje resultante incluyendo objetos inhabilitados_______ Error comun en xajax_______________________________ Resultado de xajax-buscar.php _______________________ Datos de búsqueda en xajax-buscar.php _______________ Resultado de la búsqueda en xajax-buscar.php __________ Listado de persona con xajax ________________________ Inserción de registros con xajax ______________________ Edición de registro con xajax_________________________ Selección de registros con xajax ______________________ Búsqueda de registros con xajax______________________ 297 298 300 300 300 304 305 305 306 306 Oscar E Capuñay Uceda 324