Integrando AJAX & PHP

91
INTEGRANDO AJAX & PHP PRIMERA EDICIÓN ELISEO ORTIZ VALDEZ

description

El lector podrá comprender el funcionamiento de la tecnología AJAX, desde el manejo básico con el objeto XMLHttpRequest con código JavaScript hasta integrar librerías y Toolkits creando aplicaciones web de última generación, desarrollar servicios web que permitan manejo de datos con el servidor en distintos formatos (txt, XML, JSON), validación de datos e interfaces visuales intuitivas y ricas para el usuario, usando como lenguaje del lado del servidor el lenguaje PHP.

Transcript of Integrando AJAX & PHP

Page 1: Integrando AJAX & PHP

INTEGRANDO AJAX & PHP PRIMERA EDICIÓN

ELISEO ORTIZ VALDEZ

Page 2: Integrando AJAX & PHP

Objetivo ..........................................................................................................................................................3IntroducciónFundamentos de AJAX

Qué es AJAX..................................................................................................................................................7Tecnologías en AJAX.....................................................................................................................................9La interfaz XMLHttpRequest.......................................................................................................................10 Construyendo el Objeto XMLHttpRequest ................................................................................................11 Características de la Interfaz XMLHttpRequest.........................................................................................11Aplicaciones con AJAX ...............................................................................................................................14 Peticiones al Servidor ...............................................................................................................................15 XML & AJAX...........................................................................................................................................19

AJAX Frameworks y ToolkitsDojoToolkit ..................................................................................................................................................24 Instalación ...............................................................................................................................................25jQuery ...........................................................................................................................................................26 Instalación.....................................................................................................................................................27

Usando AJAXValidación de Datos......................................................................................................................................29 Caso 1. Registro de usuarios......................................................................................................................30Sugerencias automáticas...............................................................................................................................41 Caso 2. Auto-sugerencia...........................................................................................................................41 Caso 3. Sugerencia de búsqueda...............................................................................................................45Interfaz Gráfica de Usuario ..........................................................................................................................51 Caso 4. Monitoreo en tiempo real .............................................................................................................53 Caso 5. Visualizador de archivos ..............................................................................................................60

Herramientas para desarrollo de software y depuración de erroresRhino ............................................................................................................................................................73ShrinkSafe ....................................................................................................................................................74Depurando AJAX con Firebug .....................................................................................................................77Herramienta de desarrollo para Internet Explorer ........................................................................................80

Análisis de seguridad en aplicaciones AJAXParos Proxy...................................................................................................................................................86 Sprajax ..........................................................................................................................................................90

Por Hacer

CONTENIDO

Page 3: Integrando AJAX & PHP

Para quién es el libro Toda persona con experiencia básica en programación en lenguajes interpretados que este interesado en aplicar nuevas tecnologías en el desarrollo web, con tecnología LAMP (Linux, Apache, MySQL, PHP) y JavaScript como plataforma de desarrollo.

Objetivo El lector podrá comprender el funcionamiento de la tecnología AJAX, desde el manejo básico con el objeto XMLHttpRequest con código JavaScript hasta integrar librerías y Toolkits creando aplicaciones web de última generación, desarrollar servicios web que permitan manejo de datos con el servidor en distintos formatos (txt, XML, JSON), validación de datos e interfaces visuales intuitivas y ricas para el usuario, usando como lenguaje del lado del servidor el lenguaje PHP.

Page 4: Integrando AJAX & PHP

Introducción

La evolución que se ha visto en la Web desde sus inicios, ha cambiado notablemente la manera de ver la sociedad, pues no solamente es una transformación tecnológica, ya que trae con sigo un sin número de paradigmas que permiten realizar cada vez más actividades humanas a través de esta herramienta, emulando así la manera en como la sociedad se comunica, piensa, se relaciona y en un futuro la percepción de sensaciones, llevando este tipo de comunicación a un nivel donde la percepción de espacio-tiempo nos permite transportar de un lugar a otro en cuestión de segundos, comunicarnos con mayor número de grupos, personas, prestar servicios fuera de nuestro país de residencia, etc. La web nace en 1989 cuando Tim Berners-Lee creo la propuesta de la WWW, posteriormente inventó el primer servidor web “httpd” y el primer navegador en el año 1990, de igual manera el escribió la primera versión del “lenguaje de marcación de hipertexto” HTML, el cual llego a ser el primer formato para publicar en la web. Posteriormente otras lenguajes emergieron para solucionar diversos problemas, o bien tecnologías que permitían crear aplicaciones más eficientes, funcionales, atractivas. Tenemos el caso de XML en 1996 patrocinado por w3c, con el objetivo de crear documentos XML que puedan ser servidos, recibidos y procesados en el internet. Luego tenemos DOM, el cual es un modelo del documento, el cual permite modificar contenido y estilo (CSS) de un documento HTML a través de una aplicación como puede ser JavaScript, creando la sensación de un HTML dinámico DHTML. Entonces tenemos la tecnología estandarizada para el intercambio de información además de la ventaja de crear documentos presentables en el navegador con interactividad dinámica. Ahora esto es muy bueno cuando la información o datos que queremos presentar al usuario es estática, pero que sucede cuando la información que deseamos mostrar es dinámica. Bueno para esto tenemos las tecnologías que nos permiten obtener datos del un servidor web, como lo son: PHP, JSP, ASP .NET (utilizando C# o VB como lenguajes), ColdFusion o CGI/Perl. Las peticiones que son realizados a los navegadores a través de los ya conocidos métodos POST, GET requieren que sea enviado al servidor una URI para realizar dicha petición, lo que propicia a que la ventana inicial del navegador donde el usuario se encontraba al realizar la petición cambié a otra diferente, para mostrar la información que

Page 5: Integrando AJAX & PHP

fue requerida. Lo que se traduce en tiempos de espera, obtención de información previamente cargada en el navegador. Cada tecnología de la información trae con sigo herramientas tecnológicas que hacen posible su aplicación en el mundo real. Estas herramientas proporcionan al profesional de TI desarrollar ambientes web ahora más funcionales, mejorando la interactividad con el usuario, visual, manejo de información, y compatibilidad, etc. AJAX es una tecnología que permite evitar el refresco innecesario previamente explicado, permitiendo desarrollar aplicaciones mas eficientes con una experiencia rica al usuario. Esta tecnología nos permite además de cambiar de manera dinámica la apariencia del documento. Es entonces AJAX un conjunto de tecnologías trabajando en conjunto para un mejor aprovechamiento de los recursos de la web y en la funcionalidad. Actualmente nos encontramos con tendencias de web 2.0 y algunas luces de lo que pudiera ser web 3.0 aunque todavía no muy bien definidas. La web 3.0 apunta a la manera de darle sentido a la información que se encuentra en la web, pues bien, ciertamente conforme la web se va alimentando con mucha información, se requieren métodos cada vez mejores para la obtención de información sustancial, específica. Es por eso que diferentes grupos se encuentran ya trabajando en tecnologías para hacer posible compartir y reutilizar datos a través de aplicaciones, empresas, comunidades. Pasaremos tal vez a la era de las tecnologías de la información a la era de las tecnologías del conocimiento. Diversos proyectos en línea como http://www.govpulse.us y http://www.dataasher.org los cuales a partir de información obtenida en sitios como http://www.data.gov y algunos otros sitios federales generan información utilizando web semántica como herramienta en en análisis y comparación de la información obtenida. Freebase (freebase.com) es otro proyecto el cual motiva a desarrolladores para crear aplicaciones a partir de herramientas proporcionadas en este sitio donde se obtenga información relacionada de manera semántica con el tópico de interés. Por otro lado se encuentran ambientes colaborativos de carácter científico donde es posible obtener conocimiento a partir de información. Lo interesante de todos estos proyectos, es que es posible ahora obtener conocimiento a partir de información estructurada, desarrollando aplicaciones que la modelen y analicen de acuerdo a reglas especificadas y obtener así un sentido más claro de la información. Agregando una dimensión más a los datos que se tienen, pudiendo relacionar, comparar y obtener conclusiones aplicables al mundo real.

Page 6: Integrando AJAX & PHP

6

Fundamentos de AJAX

Las tecnologías RIA (Rich Internet Applications) son una nueva generación de aplicaciones Web, donde se le ofrece una rica experiencia, proporcionandole al usuario una satisfacción de uso, además de un incremento en la funcionalidad y disminución de tiempos de respuesta. Las aplicaciones RIA mezclan las ventajas de una aplicación web con las ventajas de una aplicación de escritorio. AJAX es por sí una tecnología que encaja dentro de las RIA. La mejor forma de definir que son las tecnologías RIA es por su funcionalidad y características, es por eso que a continuación se muestra una tabla con las características de las tecnologías RIA con respecto a las aplicaciones Web convencionales.

Aplicaciones Web Convencionales Aplicaciones Web con RIA

Cualquier petición requiere que la página sea cargada completamente

Interactividad inmediata

Modelo de comunicación síncrona “request/response”

Modelo de comunicación asíncrona. El cliente solo realiza la petición tipo “request” del dato solicitado

Interrupción en la operación del usuario El usuario no es interrumpido

Limitaciones de apariencia por las que son proporcionadas dentro de los “tags” HTML

Sensación del usuario de estar utilizando aplicaciones de escritorio

tabla 1. comparativa entre tecnologías RIA con aplicaciones web convencionales Algunas tecnologías RIA que se encuentran en el mercado son: AJAX, Adobe Air/Flex/Flash, Java WebStart, Java FX, Microsoft Silver Light, Java Applet.

Page 7: Integrando AJAX & PHP

7

Qué es AJAX Acrónimo de Asynchronous JavaScript and XML. AJAX es un conjunto de tecnologías que permiten desarrollar aplicaciones web proporcionando al usuario la experiencia de estar usando una aplicación de escritorio. AJAX continua con la evolución del desarrollo web como lo fue en su momento DHTML, para proporcionar al usuario Aplicaciones Ricas de Internet y la experiencia de web 2.0. AJAX es una tecnología que aventaja a las demás tecnologías RIA en la cuestión que no requiere que sea instalado algún software especial o plug-in en el cliente. Además de que pueden ser encontrados en la red Toolkits Open Source, para un desarrollo rápido y sin dolor. Las desventajas de AJAX en primer lugar la posibilidad de que se encuentre incompatibilidad entre distintos navegadores, sin embargo los Toolkits en sus librerías contienen código compatible para distintos navegadores. En segundo lugar tenemos la complicada depuración del código javaScript. La tecnología AJAX se ha posicionado últimamente como una tecnología categorizada dentro de la segunda generación de la web, conocida como web 2.0. AJAX entonces permite incrementar la productividad del usuario, manejo de información inmediata sin gasto innecesario de recursos, permitiendo el desarrollo de nuevas maneras de colaborar con otras aplicaciones. La tecnología que hace posible actualizaciones asíncronas es la API JavaScript XMLHttpRequest, el cual es un estándar abierto que puede ser utilizado por todos los navegadores. Esta API tipo script proporciona funcionalidad para transferencia de datos entre el modelo cliente- servidor, utilizando el objeto de JavaScript XHttpRequest (originalmente un control ActiveX creado por microsoft).

Page 8: Integrando AJAX & PHP

8

fuente: http://www.adaptivepath.com/ideas/essays/archives/0000385.php/

fig. 1. Funcionamiento de AJAX dentro del esquema cliente-servidor

Page 9: Integrando AJAX & PHP

9

Tecnologías en AJAX AJAX utiliza otras tecnologías que permiten actualizar los datos obtenidos por medio del objeto XMLHttpRequest en la página además de brindarle un estilo especifico a cada resultado que será desplegado en el navegador. Es entonces que AJAX trabaja con un conjunto de tecnologías todas unidas por JavaScript, a continuación describimos cada una de las tecnologías:

• JavaScript. Lenguaje de programación tipo script, funciones de javascript son mandadas a llamar cuando un evento dentro de la página HTML ocurra.

• DHTML (Dynamic HTML). Lenguaje que nos permite obtener HTML dinámico con la ayuda de JavaScript.

• DOM (Document Object Model). Es una plataforma y una interfaz de lenguaje central que permite a los programas o scripts para accesar dinámicamente y actualizar el contenido, estructra y documentos de estilo.

• CSS (Cascading Style Sheets). Mecanismo para añadir estilo visual a un documento Web.

• XML (Extensible Markup Language). Modo de enviar y recibir datos en modo texto a través de internet.

• XMLHttpRequest. Implementa una interfaz por medio de un script que sirve como un motor el cual permite a otros scripts ejecutar funciones del cliente hacia el servidor a través de HTTP de manera asíncrona.

Page 10: Integrando AJAX & PHP

10

La interfaz XMLHttpRequest Esta interfaz permite conectarse subyacentemente al servidor del cual fue originado por medio del procolo HTTP y HTTPS. Este objeto soporta cualquier tipo de datos en texto y XML. La interfaz contiene las siguientes propiedades:

• States. Permiten saber el estado en el que se encuentra el objeto XMLHttpRequest • Request. Contiene variables meta-datos como la dirección URL y método usado en

la petición. Además de métodos útiles para envío de peticiones al servidor. • Response. Atributos y métodos para el manejo de datos XML o TXT provenientes de

la respuesta enviada por el servidor A continuación la Interfaz: [NoInterfaceObject] interface XMLHttpRequestEventTarget : EventTarget { // for future use }; [Constructor] interface XMLHttpRequest : XMLHttpRequestEventTarget { // event handler attributes attribute Function onreadystatechange; // states const unsigned short UNSENT = 0; const unsigned short OPENED = 1; const unsigned short HEADERS_RECEIVED = 2; const unsigned short LOADING = 3; const unsigned short DONE = 4; readonly attribute unsigned short readyState; // request void open(DOMString method, DOMString url); void open(DOMString method, DOMString url, boolean async); void open(DOMString method, DOMString url, boolean async, DOMString? user); void open(DOMString method, DOMString url, boolean async, DOMString? user, DOMString? password); void setRequestHeader(DOMString header, DOMString value); void send(); void send(Document data); void send([AllowAny] DOMString? data); void abort(); // response readonly attribute unsigned short status; readonly attribute DOMString statusText; DOMString getResponseHeader(DOMString header); DOMString getAllResponseHeaders(); readonly attribute DOMString responseText; readonly attribute Document responseXML; };

fuente: http://www.w3.org/TR/XMLHttpRequest/

Page 11: Integrando AJAX & PHP

11

Construyendo el Objeto XMLHttpRequest El código básico JavaScript para crear nuestro objeto XMLHttpRequest es el siguiente: if (window.XMLHttpRequest) { myObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { myObject = new ActiveXObject("Microsoft.XMLHTTP"); }

El código anterior nos muestra dos condiciones al construir nuestro objeto, estas condiciones son necesarias para que el objeto sea compatible con diferentes tipos de navegador. El primer objeto creado myObject= new XMKHttpRequest(); es necesario para compatibilidad con navegadores Netscape (desde versión 7.0), Apple Safari (desde versión 1.2) ,Opera, Chrome, Firefox. El segundo objeto es creado para el navegador Internet Explorer.

Características de la Interfaz XMLHttpRequest Posteriormente añadimos una función a nuestro código para añadir interactividad con nuestro documento. function getData(dataSource, divID) { if(myObject) { var divData = document.getElementById(divID); myObject.open("GET", dataSource); myObject.onreadystatechange = function(){ if (myObject.readyState == 4 && myObject.status == 200) { divData.innerHTML = myObject.responseText; } } myObject.send(null); } } En la función anterior se encuentran dos variables, dataSource y DivID la primera variable es nuestro documento en texto que contendrá la información que queremos desplegar, DivID es la variable que contiene el objeto DOM de donde se insertará la información regresada obtenido por la interfaz XMLHttpRequest. En método open es utilizado par realizar una petición al servidor, este método es invocado de la siguiente manera: open(method, url, async, user, password) En el código anterior es invocado con: myObject.open("GET", dataSource);

Page 12: Integrando AJAX & PHP

12

El método que se usa es tipo “GET”, sin embargo este puede ser: CONNECT, DELETE, GET, HEAD, OPTIONS, POST, PUT, TRACE, TRACK. En el caso de que se requiera usar método POST, será necesario configurar el método setRequestHeader, de la siguiente manera. En el caso de que el dato obtenido sea DOMString: XMLHttpRequestObject.setRequestHeader('Content-Type','textplain;charset=UTF-8'); En el caso de que el dato obtenido sea un Document: XMLHttpRequestObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); Esta línea de código tendría que ser insertada después del método open. Para iniciar la petición al servidor es necesario utilizar el método send , en el código se realiza de la siguiente manera: myObject.send(null); En este caso el valor que se envía es null , valor usado para métodos GET o HEAD. Si se requiere mandar datos por método POST es necesario utilizar la sentencia, como se muestra a continuación. myObject.send(postVars); Donde vars será una variable que define las variables POST, de la siguiente manera: var postVars = “name=valor1&password=valor2”; El atributo onreadystatechange es utilizado para crear funciones que nos permitirán recibir la información requerida del servidor, además de brindarnos información a cerca del estado de la petición. La manera de saber si nuestra petición ha sido obtenida exitosamente es necesario valernos de los estados del objeto, por medio del atributo readyState , los estados que este puede tener son:

Estado Valor Numérico

Descripción

UNSENT 0 La petición no ha sido iniciada

OPENED 1 La petición ha sido configurada

HEADERS_RECEIVED 2 La petición ha sido enviada

LOADING 3 La petición se encuentra en proceso

DONE 4 La petición se ha completado

tabla1. Estados del atributo readyState

Page 13: Integrando AJAX & PHP

13

Para determinar si nuestra respuesta se encuentra lista, se utilizó la siguiente condición: if (myObject.readyState == 4 && myObject.status == 200) {...} Esta condición se realiza si el valor del atributo readyState es igual a 4, es decir si nos devuelve un estado DONE y si el estado del código recibido por el servidor tiene un valor de 200, es decir OK. Los códigos que puede regresar el servidor, son los siguientes:

• 200 OK • 202 accepted • 400 bad request • 403 forbidden • 408 request time out

← Estos estados nos arrojaran resultados muy útiles cuando algo va mal en el lado del servidor. Pueden ser visualizados directamente añadiendo código JavaScript o bien utilizando firebug, herramienta vista a detalle en el apéndice. Dentro de la condición es necesario definir una variable que se encuentre dentro de nuestro documento HTML con ayuda de DOM con la siguiente sentencia: var divData = document.getElementById(divID); Esta variable que definimos será la que recibirá el resultado obtenido por medio del atributo responseText . De la siguiente manera: divData.innerHTML = myObject.responseText; A su vez se encuentra responseXML para manejar XML proveniente del servidor.

Page 14: Integrando AJAX & PHP

14

Aplicaciones con AJAX Las aplicaciones AJAX como bien se mencionó anteriormente están constituidas por varias tecnologías como es CSS, HTML, DOM, JavaScript. Utilizando un esquema general de como cualquier aplicación utiliza estas tecnologías en conjunto, podemos realizarlo de la siguiente manera:

1. La página es cargada en el navegador del usuario, esta contiene un estilo definido con CSS y diversos elementos donde el usuario podrá interactuar por medio de menús, botones o widgets o bien con el solo hecho posicionar el cursor del mouse encima de ellos.

2. Se realiza una petición X al servidor, al ejecutarse un evento determinado. Esta petición puede ser realizada al cargar la página Web o bien al ejecutar cualquier evento dentro del navegador.

3. El objeto XMLHttpRequest, gestiona la comunicación con el servidor, obteniendo los datos solicitados de acuerdo a las peticiones realizadas.

4. En la parte del servidor, se ejecuta la petición por medio de lenguajes como: PHP, ASP, Python, etc., de la información requerida, el resultado de esta petición es devuelta en formato TXT, XML, JSON.

5. Una vez obtenidos los datos, estos son insertado dentro de elementos especificados pertenecientes a la página por medio de DOM o bien también pueden ser remplazados los datos contenidos en los elementos por otros nuevos.

6. El usuario observa como distintos bloques del documento HTML han cambiado de forma variable tanto el estilo visual como los datos de información, todo esto sin necesidad de que el usuario tenga que cambiarse de página o recargar la misma completamente.

Para amplificar el conocimiento de estas diferentes tecnologías trabajando en una sinfonía en común desarrollaremos aplicaciones que nos mostrarán lo necesario para empezar a trabajar con la tecnología AJAX.

Page 15: Integrando AJAX & PHP

15

Peticiones al Servidor Para realizar nuestras primeras pruebas se creará un objeto XMLHttpRequest con las directivas necesarias, dentro de un documento HTML y posteriormente se realizará una interacción con un documento PHP para realizar una petición de datos por medio del método GET. Los archivos que se necesitan para este ejemplo son: ejemplo-ajax.html, show-example.php, data.txt

ejemplo-ajax.html <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>Ejemplo Usando AJAX </title> <meta name="Author" content="Eliseo Ortiz"> <meta name="keywords" lang="es" content="ajax, XMLHttpRequest"> <script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 3) { obj.innerHTML= "LOADING....";} if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } function getExample(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function(){ if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script> </head> <body> <h1>Ejemplo usando Ajax</h1> <input type = "button" value = "Visualiza el mensaje" onClick = "getExample('showexample.php?number=1', 'showExample')"> <p>Usando XMLHttpRequest y metodo tipo "GET"</p><br/><br/> <div id="showExample"> </div> </body> </html>

Page 16: Integrando AJAX & PHP

16

En el ejemplo anterior tenemos dos funciones,getExample y getData, el primero se manda a llamar a través del evento onClik que se encuentra dentro del <input> en el <body> del documento. La función getExample, realizará entonces una petición al servidor por medio del método GET con la siguiente URL: show-example.php?number=1. Veamos el documento show-example.php

show-example.php <?php if(isset($_GET[‘number’)){ $example_number = $_GET['number']; if($example_number == '1'){ $string = "<h2>Ejemplo 1 Ajax</h2> <form> <input type = \"button\" value = \"Visualiza el mensaje\" onclick = \"getData('data.txt', 'showMessage')\"> </form> <div id=\"showMessage\"> <p>El mensaje aparecerá aquí</p> </div>"; } echo $string; } ?> El código PHP anterior, nos permite primero validar si existe un valor para la variable number obtenido por método GET. Posteriormente tenemos la condición para verificar el número de ejemplo que se quiere visualizar, en este caso solamente es el número “1”. Por último realizamos un echo de la variable $string. Veremos como se ve en el navegador cuando mandamos a llamar la función getExample.

Page 17: Integrando AJAX & PHP

17

fig. 2. vista inicial del ejemplo

Cuando el botón “Visualiza el Ejemplo” dispare el evento evento onClick será desplegado de manera asíncrona en el <div id=”showExample”> la información que sea obtenida del documento show-example.php, la cual seá insertada por medio de innerHTML (propiedad DOM que inserta texto a partir de una liga).

fig. 3. Comunicación con show-exaple.php

Page 18: Integrando AJAX & PHP

18

En esta figura observamos ya el ejemplo desplegado, además de un texto debajo del botón que nos esta mostrando donde aparecerá el nuevo mensaje que se obtendrá a partir de un documento de texto. El texto que manda a llamar el ejemplo 1, se encuentra en el documento data.txt

data.txt Pajarillo, pajarillo,

Pajarillo barranqueño

¡Qué bonitos ojos tienes!

Lástima que tengan dueño.

Qué pajarillo es aquél

Que canta en aquella lima?

Anda y dile que no cante,

Que mi corazón lastima.

El botón del segundo ejemplo manda a llamar a la función getData que manda como parámetro de fuente de datos data.txt y el objeto showExample. A continuación se muestra la visualización el desplegado de la información que se encuentra en data.txt, al mandar a llamar la función getData.

fig. 4. Desplegando la información en data.txt

Page 19: Integrando AJAX & PHP

19

XML & AJAX Con los conocimientos previos de como crear un objecto XMLHttpRequest y de como usar sus métodos, se desarrollará una aplicación con nombre de “RSS reader” . La función de la aplicación es leer datos XML a partir del archivo testFeed.xml el cual contiene información RSS(Realy Simple Syndication), una vez obtenidos los datos, serán manejados por JavaScript que integrará la información en elementos HTML para ser desplegadas en el documento ajax-xml.html.

ajax-xml.html <html> <head> <script type="text/javascript"> var ajaxObject = false; if (window.XMLHttpRequest) { ajaxObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { ajaxObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getXmlData(xmlSource, divID){ if(ajaxObject){ var divObj = document.getElementById(divID); ajaxObject.open("GET",xmlSource,true); ajaxObject.onreadystatechange = function(){ if(ajaxObject.readyState == 4 && ajaxObject.status == 200){ var xmldata=ajaxObject.responseXML var rssentries=xmldata.getElementsByTagName("item") var rssOut='<ul>' for (var i=0; i<rssentries.length; i++){ rssOut+='<li>' rssOut+='<a href="'+rssentries[i].getElementsByTagName('link')[0].firstChild.nodeValue+'">' rssOut+= rssentries[i].getElementsByTagName('title')[0].firstChild.nodeValue+'</a><br>' rssOut+= rssentries[i].getElementsByTagName('description')[0].firstChild.nodeValue+'<br>' rssOut+='Ultima actualizaci&oacute;n: '+rssentries[i].getElementsByTagName('lastBuildDate')[0].firstChild.nodeValue rssOut+='</li>' } rssOut+='</ul>' divObj.innerHTML=rssOut } } ajaxObject.send(null); }else{alert(“Navegador no soporta XMLHttpRequest”);} } function changeBG(obj){ obj.style.backgroundColor="#505050";} </script> </head> <body> <h1>Ejemplo usando Ajax y XML</h1> <input type = "button" value = "Visualiza los Datos" onclick = "getXmlData('testFeed.xml', 'xmlData')">

Page 20: Integrando AJAX & PHP

20

<div id="xmlData" onMouseOver="this.style.backgroundColor = '#909090'" onMouseOut="changeBG(this);"> </div> </body></html>

En el código anterior tenemos una función que es mandada a llamar cuando ocurre el evento onClick en el <input> del código HTML. Esta función realiza lo siguiente:

• Realiza una conexión con el documento testFeed.xml por método GET • Se obtiene la petición y se guarda en la variable xmldata • Se analiza la sintaxis del documento general dividido en una colección de objetos

con el nombre “item”, usando getElementsByTagName (método DOM). • Los sub-objetos contenidos en “item” son analizados uno por uno, guardando los

sub-objetos deseados en una variable más llamada rssOut, la cual contendrá nuestro código final en HTML listo para insertado en el <div> con id “xmlData”.

Para ver a detalle como se realiza el análisis de los datos XML, veamos primero que tenemos en el documento testFeed.xml.

testFeed.xml <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>Eliseo Ortiz Valdez WebLog</title> <link>http://www.eliseoov.org</link> <description>Tutoriales y más</description> <language>es</language> <item> <title>Seguridad Básica para redes 802.11</title> <link>http://www.eliseoov.org/se/?p=121</link> <description>El siguiente documento se encuentra basado en la recomendación que proporciona la NSA para asegurar redes que se encuentren dentro del estándar IEEE 802.11.</description> <lastBuildDate>Tue, 19 Oct 2009 20:00:00 GMT</lastBuildDate> <language>es</language> </item> <item> <title>Comandos para mantenimiento de BD MySQL</title> <link>http://www.eliseoov.org/se/?p=114</link> <description>Entre unas de las actividades del SYSDBA es realizar respaldos de la base de datos, importar, exportar datos. Pues bien, en este caso presento comandos básicos para mantenimientos de bases de datos MySQL usando comandos como mysqldump o simplemente mysql.</description> <lastBuildDate>Mon, 18 Oct 2009 19:00:00 GMT</lastBuildDate> <language>es</language> </item> <item> <title>Directiva Options en configuración Aapache</title> <link>http://www.eliseoov.org/se/?p=105</link> <description>La directiva “Options”, nos es importante cuando queramos añadir o disminuir alguna caracteristica especiales del servidor apache a algún directorio en especifico de nuestro servidor.</description>

Page 21: Integrando AJAX & PHP

21

<lastBuildDate>Sun, 17 Oct 2009 18:00:00 GMT</lastBuildDate> <language>es</language> </item> </channel> </rss> El formato RSS anterior es usado para expresar contenido de sindicalización, es un dialecto de XML, todos los archivos RSS deben de cumplir con la especificación 1.0 XML públicada en el sitio W3C http://www.w3.org/TR/REC-xml/. Para válidar un código RSS se puede obtener ayuda del motor de validación: http://validator.w3.org/feed/ Para poder analizar este código objeto por objeto se utiliza el siguiente código JavaScript: var rssentries=xmldata.getElementsByTagName("item") var rssOut='<ul>' for (var i=0; i<rssentries.length; i++){ rssOut+='<li>' rssOut+='<a href="'+rssentries[i].getElementsByTagName('link')[0].firstChild.nodeValue+'">' rssOut+= rssentries[i].getElementsByTagName('title')[0].firstChild.nodeValue+'</a><br>' rssOut+= rssentries[i].getElementsByTagName('description')[0].firstChild.nodeValue+'<br>' rssOut+='Ultima actualizaci&oacute;n: '+rssentries[i].getElementsByTagName('lastBuildDate')[0].firstChild.nodeValue rssOut+='</li>' } rssOut+='</ul>' El cual contiene un ciclo donde se analiza cada sub-objeto contenido en el objeto “item”. Así si queremos obtener el dato contenido en la “etiqueta” <link> utilizamos la siguiente línea: rssentries[i].getElementsByTagName('link')[0].firstChild.nodeValue Luego obtenemos el dato que se encuentra dentro del “elemento” <title>, utilizando la siguiente línea: rssentries[i].getElementsByTagName('title')[0].firstChild.nodeValue Y así se continua con el “tag” <description> y <lastBuildDate>. Las líneas de código JavaScript anteriores obtienen el dato del sub-objeto contenido en “item” con la “etiqueta” especificada nuevamente utilizando el método getElementsByTagName luego accedemos al valor por medio de la propiedad del objeto con firstChild.NodeValue. Así como esta propiedad de Nodo de objeto, donde las mas usuales son: childNodes, lastChilld, nodeName, todas soportadas por navegadores como: IE, Firefox, Opera, etc.

Page 22: Integrando AJAX & PHP

22

fig. 5. vista inicial de la aplicación RSS Reader

fig. 6. Visualización de las noticias RSS

Page 23: Integrando AJAX & PHP

23

La salida estándar de las noticias vista en la figura anterior se encuentra maquillada con un estilo que las diferencia de todo el documento. Si observamos que es lo que tenemos en el código HTML observamos lo siguiente: <div id="xmlData" onMouseOver="this.style.backgroundColor = '#909090'" onMouseOut="changeBG(this);"> </div> Dentro de este contenedor o elemento tipo “div” se encuentran expresados los eventos onMouseOver y onMouseOut . Estos elementos son usados para cambiar el estilo del contenido dentro de <div> . Para onMouseOver se utilizó: this.style.backgroundColor. Sin embargo para onMouseOut se manda a llamar una función, en este caso changeBG, esta función se manda a llamar, no por que no pueda usarse la sentencia : this.style.backgroundColor, si no para mostrar otra manera de como realizar esta actividad con una función, muy útil, cuando queremos realizar más cambios dentro del objeto. El código de la función que se manda a llamar es el siguiente: function changeBG(obj){ obj.style.backgroundColor="#505050";} Esta sentencia, realiza el cambio del estilo del objeto que se especifique como parámetro de la función changeBG, con esto estamos utilizando HTML+CSS+JavaScript, lo que se conoce como DHTML(Dynamic HTML).

Page 24: Integrando AJAX & PHP

24

AJAX Frameworks y Toolkits

Las librerías JavaScript, permiten desarrollar aplicaciones o sitios web, de una manera mas sencilla y rápida, brindan portabilidad entre navegadores, creación de widgets, efectos de visualización, entre otros. Además que es posible estar utilizando AJAX sin necesidad de escribir una sola línea de JavaScript. En este apéndice se mostrará como configurar y utilizar algunas de los Toolkits mas populares de JavaScript con utilidades AJAX.

DojoToolkit Esta librería es “Open Source”, esta librería esta constituida de la siguiente manera:

1. Base. Es una librería compacta y optimizada, el cual es el fundamento de todo lo que se encuentra en el DojoToolkit. Las utilidades de AJAX vienen en esta librería. A continuación sus características:

• Detección de tipo de navegador • Codificación y decodificación JSON • Soporte AJAX • Soporte en animaciones (incluyendo animaciones de colores) • Soporte en la programación Asíncrona (dojo.Deferred) • Alto desempeño para motor de peticiones CSS3 • Utilidades para lenguajes • Hojas de Estilos CSS y utilidades de posicionamiento • Soporte para programación Orientada a Objetos • Protección contra escape de memoria Integración con Firebug

2. Core. Librería que nos permite integrar las siguientes características:

• Herramientas universales de depuración • Drag and Drop • Soporte i18n • Localizaciones • Fechas en formato • Números en formato • Utilidades para manejo de cadenas de caracteres • Transporte avanzado de AJAX (IFrame, JASON-P) • Manejo de Cookies • Animaciones extendidas • Llamadas a procedimientos remotos (RPC), incluyendo JSON-P • Manejo del botón de regreso

Page 25: Integrando AJAX & PHP

25

Estilos base CSS 3. Dijit. Paquete listo para usar que contiene widgets de dojo como controles para las

formas, fingertips, tabs, etc. Desarrollando aplicaciones que proveerán al usuario una experiencia rica en su uso.

4. Dojox. Es una colección de sub-proyectos, que aunque algunos son solamente de carácter experimental cuenta con código estable para la creación de widgets, pero que simplemente no pueden ser clasificados dentro de Dijit o Core.

5. Util. Esta librería contiene herramientas necesarias para la construcción de versiones de Dojo adecuadas a las necesidades de producción. Lo que realizan estas herramientas es la compresión del tamaño de nuestro código JavaScript, además de añadir archivos JavaScript que nuestra aplicación vaya a necesitar, lo que se refleja en un menor tiempo de descarga de la aplicación en producción.

Instalación Para poder empezar a utilizar la librería DojoToolkit es necesario bajar el código que se encuentra en la siguiente liga: http://www.dojotoolkit.org/downloads Donde encontraremos 2 paquetes, descritos a continuación: El primero es el Dojo Base, el cual contiene como el nombre lo dice, solamente la librería Base en versión compilada, no enfocada a desarrollo, es decir no para editar código JavaScript. El segundo paquete que encontraremos es la versión de lanzamiento, el cual contiene el DojoToolkit con las librerías Base+Dijit+Dojox. Esta es la versión que utilizaremos para nuestros fines. El paquete que descargamos es parecido a dojo-release-1.3.2.tar.gz Una vez obtenido el paquete lo descomprimimos en una carpeta dedicada a las librerías Dojo, dentro de nuestro “directorio raíz” de nuestro servidor Web. Para empezar a utilizar Dojo, ahora necesitamos insertar el código JavaScript dentro de la cabecera de código HTML donde será utilizado. Como se muestra a continuación: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Página de prueba deDojo Toolkit</title> <!-- cargando el dojo toolkit base --> <script type="text/javascript" src="scripts/dojotoolkit/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug:true"></script> </head> <body> <h1>Página de prueba de DOJO</h1> </body> </html>

Page 26: Integrando AJAX & PHP

26

En este caso se supone que nuestro código dojo, se encuentra dentro de la carpeta scripts de nuestro directorio raíz. Dojo tiene varias opciones de configuración dentro del tiempo de ejecución, estas pueden ser configuradas por medio de djConfig. Los más usuales son:

• parseOnLoad. Analiza el código HTML en búsqueda de “widgets” al momento de ser cargado.

• isDebug. El cual habilita o deshabilita mensajes de depuración. •

También es necesario configurar el estilo que dojo usará, por default se encuentran tres “temas de estilo” listo para usar, estos temas son: soria, tundra, nihilo. Para la integración de cualquier tema es necesario vincular la hoja de estilo correspondiente al tema elegido, dentro del código fuente de nuestro documento, como se muestra a continuación: <style type="text/css"> @import "scripts/dojo/dojo/resources/dojo.css"; @import "scripts/dojo/dijit/themes/tundra/tundra.css"; </style>

Del mismo modo se tiene que definir la clase de estilo para la etiqueta <body>. <body class="tundra"> Si deseamos utilizar un tema diferente, es necesario cambiar el valor de class por el de cualquiera de los temas disponibles como: nihilo, soria, o bien algún tema de nuestra creación.

jQuery Esta librería es muy popular para el desarrollo de aplicaciones AJAX , que se esta adoptando muy rápidamente dentro de la comunidad el Software Libre, por su facilidad de uso además de que diversas empresas como Google, digd, NBC, Dell implementan jQuery en sus páginas y proyectos como Drupal y Wordpress lo utilizan en sus frameworks. El uso de jQuery es permitido para uso personal o proyectos con fines comerciales bajo licencias MIT o GPL, permitiendo al usuario elegir la que mas le convenga. La documentación de jQuery a cerca del uso de la API se puede encontrar en: http://view.jquery.com/trunk/tools/api-browser/

Page 27: Integrando AJAX & PHP

27

Instalación El código se encuentra disponible en dos formatos:

• versión comprimida, lista para empezar a usarse, con una reducción de tamaño bastante considerable con respecto a la versión no comprimida, usada para producción

• versión sin comprimir, usada para desarrollo. Cualquiera de las dos versiones pueden encontrarse en la siguiente liga: http://docs.jquery.com/Downloading_jQuery Para comenzar a utilizar jQuery ahora es necesario integrarlo al documento HTML, de la siguiente manera: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <!-- integrando libreria jQuery --> <script type="text/javascript" src="jquery.js"></script> </head> <body> <a href="http://jquery.com/">Página del proyecto jQuery</a> </body> </html>

También podemos utilizar la librería jquery a través de googleapis como se muestra a continuación: <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>

Para poder utilizar componentes como temas de estilo, widgets, efectos avanzados, animaciones, etc. será necesario descargar la libreria UI (user interface) de jquery. Esta esta librería puede ser adaptable, de acuerdo a las necesidades específicas que se tengan, siendo no necesario descargar la librería completa si no se requieren de todos los componentes o módulos. La liga para descargar esta librería es: http://jqueryui.com/download Los componentes de jqueryui a seleccionar en la descarga se encuentran categorizados de la siguiente manera:

• UI Core. Esta es una librería requerida para el funcionamiento de jqueryui, pues contiene las funciones básicas e iniciadores.

• Interactions. Usados por los componentes de jqueryui “widgets” y “effects” añadiendo comportamientos básicos a estos y a cualquier otro elemento.

Page 28: Integrando AJAX & PHP

28

• Widgets. Controles adaptables, con opciones variadas para la interfaz de usuario. • Effects. API para efectos y listo para usarse.

Una vez seleccionados los componentes a utilizar, se descargara un paquete comprimido en formato “zip”, conteniendo los siguientes archivos:

• /css/ • /development-bundle/ • /js/ • index.html

Para integrar esta librería en la página de desarrollo, solo es necesario integrar las siguientes ligas, dentro del elemento <head> del documento html en desarrollo: <link type="text/css" href="css/themename/jquery-ui-1.7.1.custom.css" rel="Stylesheet" /> <script type="text/javascript" src="js/jquery-1.3.2.min.js"></script> <script type="text/javascript" src="js/jquery-ui-1.7.1.custom.min.js"></script>

Page 29: Integrando AJAX & PHP

29

Usando AJAX

En este capitulo se verán casos de aplicaciones AJAX, para estos casos no seraán necesarios crear nuestras propias librerías javaScript para el manejo de XMLHttpRequest pues usaremos ToolKits de desarrollo que son librerías JavaScript que proporcionan APIʼs listas para implementar AJAX en nuestras aplicaciones. Concentrándonos más en qué quiero que mi aplicación realice y no en el cómo. Los ToolKits fueron seleccionados de acuerdo a características como: soporte por la comunidad, popularidad de uso, funciones AJAX, madurez del proyecto. Sin embargo no excluimos otras librerías que pueden ser de mucha utilidad para el desarrollo web, pero para fines prácticos de este libro nos desviaríamos de nuestro objetivo. En cada aplicación desarrollada en este capitulo, se informará que ToolKit se estará utilizando, con la finalidad que el lector se remita a los apéndices donde se encontrará de manera detallada la información necesaria para tener configurado e instalado el ToolKit en el ambiente básico de desarrollo.

Validación de Datos Los “formularios” o “formas” son utilizados en la web, para el registro de información de usuario, estas contienen distintas características para cada entrada, según el tipo de dato que se requiera. A su vez los formularios necesitan ser validados por un una aplicación que realice un análisis detallado de cada dato ingresado en el, donde con ayuda de “reglas” previamente establecidas se validará cada dato particular como verdadero o falso, regresando a su vez al usuario una retroalimentación de la respuesta proveniente de este programa de validación. El programa de validación puede estar situada en el lado del cliente, o en e lado del servidor. En este caso usaremos validación desde el lado del cliente utilizando AJAX, aunque la recomendación también es asegurar esta validación en las 2 partes, por métodos de seguridad. Las ventajas de utilizar validación utilizando AJAX son las siguientes:

• Validación de tipo de dato en tiempo real • Validación de datos en conjunción con otros datos registrados en BD • Mensajes visuales al usuario para recomendaciones y/o errores de ingreso de datos • El conjunto de datos de la forma no será enviada al servidor hasta que la validación

de cada dato de la forma, que requiera ser analizado sea completado.

Page 30: Integrando AJAX & PHP

30

Caso 1. Registro de usuarios Este caso se encuentra constituido por una forma web, que requiere información del usuario, la cual será validada según las reglas que definamos para cada dato. También usaremos un código en el servidor escrito en lenguaje PHP, que insertará los datos del nuevo registro. Librería AJAX a utilizar: DojoToolkit. EL RDBMS (Relational Database Management System) a utilizar en este caso y en todos los ejercicios que se verán en este libro es MySQL. El lector de este libro debe tener ya configurado e instalado esta base de datos para realizar los ejercicios. La documentación de MySQL puede encontrarse en la siguiente liga: http://dev.mysql.com/doc/ Como paso inicial vamos a crear nuestra base de datos que llamaremos ”ajax_devel” entrando en el CLI(command line inteface) de MySQL como “super usuario”. $ mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 33 Server version: 5.1.32 MySQL Community Server (GPL) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> create database ajax_devel; Query OK, 1 row affected (0.08 sec) Ahora es necesario crear nuestra tabla que llamaremos “userdata”, dentro de la base de datos “ajax_devel”. Como se muestra a continuación: mysql> use database ajax_devel; mysql> CREATE TABLE `userdata` ( `id_user` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `lastname` varchar(255) NOT NULL, `phone` varchar(255) NOT NULL, `address` text NOT NULL, `email` varchar(255) NOT NULL, `user` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id_user`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; Posteriormente crearemos un usuario al cual le vamos a dar privilegios para la base de datos creada: mysql> CREATE USER ‘testuser’@‘localhost’ INDENTIFY BY ‘password’; Query OK, 0 rows affected (0.18 sec) mysql> grant all on ajax_devel.* to testuser@localhost; Query OK, 0 rows affected (0.10 sec)

Page 31: Integrando AJAX & PHP

31

Para nuestros casos prácticos usaremos como tecnología de almacenamiento de datos MyISAM por ser apropiado para desarrollo web, sin embargo se encuentra también la opción InnoDB si necesitamos que nuestra aplicación tenga soporte para ACID(Atomicity, Consistency, Isolation and Durability) y bloqueo de registros. En este caso usaremos los siguientes archivos: new-user.html, insert-user.php, check-user.php. El primero es el documento HTML donde se mostrará la forma para registrar un nuevo usuario, en el segundo como el nombre lo dice inserta un nuevo usuario en la base de datos y el tercero es otra aplicación que analizará si el usuario a escoger se encuentra en uso. El árbol de la recomendación para el arreglo de ficheros es el siguiente:

fig. 7. árbol de ficheros para caso 1 Como se observa en la figura anterior, ya se encuentran las librerías dojo dentro de la carpeta “scripts” y también tenemos un archivo llamado default.css dentro de la carpeta style, para nuestras modificaciones personales de estilo. También tenemos dos archivos PHP que nos ayudarán para manejar la BD estos son: ez_sql_core.php y ez_sql_mysql.php, estos se verán a detalle más adelante. A continuación el código new-user.html.

new-user.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=UTF-8" /> <title>MM Create Client</title> <style type="text/css"> @import "scripts/dojo/dojo/resources/dojo.css"; @import "scripts/dojo/dijit/themes/tundra/tundra.css"; @import "style/default.css"; </style> <script type="text/javascript" src="scripts/dojo/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug:false"></script>

Page 32: Integrando AJAX & PHP

32

<script type="text/javascript"> dojo.require("dijit.form.Form"); dojo.require("dijit.form.Button"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.Dialog"); dojo.addOnLoad(function(){ dojo.connect(dijit.byId("submitCreate01"), "onClick", function(event){ var xhrArgs = { form: dojo.byId("Form01"), url: "insert-user.php", handleAs: "text", load: function(data){ dojo.byId("textMsg").innerHTML = data; dijit.byId("showMsg").show(); }, error: function(error){ alert ("Un error ha ocurrido: " + error); }, timeout: 2000, } var deferred = dojo.xhrPost(xhrArgs); }); dojo.connect(dijit.byId("user"), "onChange", function(event){ var user_value = dojo.byId("user").value; var deferred = dojo.xhrGet( { url: "check-user.php?q="+ user_value, handleAs: "text", load: function(data){ if(data == "success"){ dijit.byId("submitCreate01").setAttribute("disabled",false); }else{ var msg = "Nombre de usuario en uso"; dojo.byId("textMsg").innerHTML = msg; dijit.byId("showMsg").show(); dijit.byId("submitCreate01").setAttribute("disabled",true); } }, error: function(error){ alert ("Un error ha ocurrido: " + error); }, timeout: 2000, }); }); }); </script> </head> <body class="tundra"> <div id="content"> <div id="header"><h1>REGISTRO DE USUARIO</strong></h1></div> <div id="horizontal-nav"> <div id="showMsg" dojoType="dijit.Dialog" class="box" title="Aviso Usuario"> <div id="textMsg"> </div> </div> <!-- comienza la forma de registro del cliente -->

Page 33: Integrando AJAX & PHP

33

<form dojoType="dijit.form.Form" id="Form01" jsId="Form01" method="post"> <table width="500" class="clients"> <th colspan="2"><h2>Ingresa datos de nuevo Cliente:</h2></th> <tr> <td><label>Nombre: *</label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="name" id="name" size="20px" tabindex="20" required="true" invalidMessage="Nombre es requerido" trim="true" promptMessage="Ingresa tu nombre"/></td> </tr> <tr> <td><label>Apellido: </label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="lname" id="lname" size="20px" tabindex="20" trim="true"/></td> </tr> <tr> <td><label>Dirección: </label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="addr" id="addr" size="40px" tabindex="40" required="false"/></td> </tr> <tr> <td><label>Teléfono: *</label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="phone" id="phone" size="20px" tabindex="20" required="true"regExp="\d{3}([\-]\d{7})?$|\d{10}$" invalidMessage="Teléfono inválido (NNN-NNNNNNN) o (NNNNNNNNNN)" promptMessage="(229-9333333)"/></td> </tr> <tr> <td><label>Email: *</label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="email_0"id="email_0" size="20px" tabindex="20" required="true"regExp="\b[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b" invalidMessage="Correo inválido" trim="true" promptMessage="Introduce correo válido"/></td> </tr> <tr> <td><label>Confirma Email: *</label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="email_1" id="email_1" size="20px" tabindex="20" required="true" regExp="\b[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b" invalidMessage="Correo inválido" trim="true" promptMessage="Introduce correo válido"/></td> </tr> <tr> <td><label>Usuario: </label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="user" id="user" size="40px" tabindex="40" required="true"/></td> </tr> <tr> <tr> <td><label>Contraseña: </label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="password" name="password" id="password" size="40px" tabindex="40" required="true"/></td> </tr> <tr> <td>&nbsp;</td> <td><p> * Campos Obligatorios <br/> <button dojoType="dijit.form.Button" id="submitCreate01"> Crear </button>&nbsp; <button dojoType="dijit.form.Button" type="reset"> Limpiar

Page 34: Integrando AJAX & PHP

34

</button></p> </td> </tr> </table> </form> <!-- Termina la forma de registro --> </div> <div id="footer"><p>Lorem ipsum dolor sit amet</p></div> </div> </body> </html> </body> </html> El código anterior contiene el código necesario HTML para interactuar en una esta forma de registro. Como se dijo anteriormente para esta aplicación, tenemos ayuda de la librería Dojo. En este caso estamos utilizando “widgets” de la librería dijit, para eventos de validación en tiempo real para las entradas de datos. Estos “widgets” son cargados al inicio en el navegador del usuario. Las validaciones que se utilizan en el código anterior con la ayuda de la librería dijit son las siguientes:

• Análisis de los campos requeridos, si el usuario no ingresa valores en estos campos, aparecerá advertencia.

• Análisis de expresiones regulares para campos determinados, por ejemplo, en el caso que se requiera validar un correo electrónico o números telefónicos.

Examinemos primeramente como configurar los objetos del documento para utilizar la librería dijit. Tomemos por ejemplo la entrada de dato para nombre, que se encuentra en la forma del código new-user.html. <th colspan="2"><h2>Ingresa datos de nuevo Cliente:</h2></th> <tr> <td><label>Nombre: *</label></td> <td><input dojoType="dijit.form.ValidationTextBox" type="text" name="name" id="name" size="20px" tabindex="20" required="true" invalidMessage="Nombre es requerido" trim="true" promptMessage="Ingresa tu nombre"/></td>

Observemos que en la etiqueta <input> se encuentra la siguiente propiedad: dojoType:”dijit.form.ValidationTextBox” este “widget” se utiliza para analizar si el dato que ingrese el usuario es válido o bien dando información al usuario a cerca de esa entrada asumiendo la funcionalidad de a etiqueta <input>. Hay que tener en cuenta que esta validación no previene entradas inválidas por envío de formas (submits). Para poder utilizar este “widget” es necesario primero configurar los atributos dentro de la etiqueta <input> y mandar a llamar el módulo que contiene esta función.

Page 35: Integrando AJAX & PHP

35

Existen otros atributos configurables para este widget como: propercase, upercase, maxlenght, rangeMessage, etc, por lo que se recomienda revisar la página del proyecto para ver a detalle. Los atributos configurados son:

Atributo Tipo Descripción

required Boolean false este puede ser de valor “true” o “false”

promptMessage String Cadena de caracteres visibles cuando el usuario se posicione en la entrada

invalidMessage String Cadena de caracteres visibles cuando el dato es inválido

trim Boolean false Elimina espacios en blanco si esta configurado como “true”

← tabla 2. atributos configurables para dijit.form.ValidationTextBox La manera de como se manda a llamar el módulo del cual depende el widget anterior se como se muestra: dojo.require("dijit.form.ValidationTextBox");

A continuación la visualización en el navegador de esta aplicación, cuando carga por vez primera:

fig. 8. vista inicial del documento new-client.html

Page 36: Integrando AJAX & PHP

36

En la figura anterior podemos ver como un “tooltip” se activa al momento de situar el puntero del “mouse” en el rectángulo para ingresar texto. También observamos que el estilo de los botones son diferentes, a los que comúnmente ofrece html por “default”. Ahora analicemos que es lo que realiza dojo, con la función: dojo.addOnLoad(); Esta función registrará las funciones que serán ejecutadas cuando el DOM se encuentre listo y todos los widgets declarados en las etiquetas hayan sido iniciados. Del mismo modo, esta función espera hasta que todas las dependencias llamadas por dojo.require() sean cargadas. El modo de uso es el siguiente: var foo=dojo.addOnLoad(obj: Object?, functionName: String|Function); Donde obj es el nombre de la función y Object es una cadena de caracteres o bien la función. Dentro de dojo.addOnLoad() se encuentra una función, la cual encapsula a otras dos más que utilizan la siguiente función: dojo.connect(); Esta función nos permite conectar un método a un evento. La manera general de uso de dicha función es: var foo=dojo.connect(obj: Object|null, event: String, context: Object|null, method: String|Function, dontFix: Boolean);

parámetro tipo descripción

obj Object | null El objeto determinado para función del evento. Si obj es un objeto tipo DOM, la conexión es delegada al manejador de eventos DOM (al menos que dontFix sea configurado con valor de “true”)

event String Nombre de la función del evento en obj.

context Object | null El objeto que “method” recivirá como “this”

method String | Function Una función de referencia o nombre de la función en contexto.

dontFix Boolean Configurar con valor de “true” para prevenir la delegación de la conexión al manejador de eventos DOM.

tabla 3. Características de la función dojo.connect

Page 37: Integrando AJAX & PHP

37

Veamos el primer uso de la función dojo.connect en el código: dojo.connect(dijit.byId("submitCreate01"), "onClick", function(event){ var xhrArgs = { form: dojo.byId("Form01"), url: "insert-user.php", handleAs: "text", load: function(data){ dojo.byId("textMsg").innerHTML = data; dijit.byId("showMsg").show(); }, error: function(error){ alert ("Un error ha ocurrido: " + error); }, timeout: 2000, } var deferred = dojo.xhrPost(xhrArgs); }); En el código anterior se realiza una conexión al objeto DOM con ID “submitCreate01”, esperando que ocurra un evento tipo “onClick” para disparar la función que realizará una conexión por medio de XMLHttpRequest con la función dojo.xhrPost(), realizando una petición al servidor tipo POST en insert-user.php. Ahora veamos a detalle la función dojo.xhrPost(). El uso de esta función es la siguiente: var foo: dojo.Deferred=dojo.xhrPost(args: dojo.__XhrArgs); Donde dojo._XhrArgs contiene las siguientes propiedades permitidas a su vez para los demás métodos dojo.xhr*

Campo Tipo Descripción

content Object Contiene propiedades con valores de cadenas

error Function Función que se activa cuando ocurrió un error, ya sea por url incorrecta, problema con el servidor, etc.

form DOMNode El nodo DOM de la forma

handle Function Esta función se activará al final de cada petición, ya sea que ocurra o no un error.

handleAs String Los valores aceptados son: text(default), json, json-comment-optional, json-comment-filtered, javascript, xml

headers Object Cabeceras adicionales (Headers) para mandar en la petición

load Function Esta función se activará cuando ocurra una respuesta de código HTTP exitoso

Page 38: Integrando AJAX & PHP

38

Campo Tipo Descripción

preventCache Boolean Valor “false” por default, si es configurado como “true” el parámetro “dojo.preventCache” es mandado en la petición con un valor variable (timestamp) en cada vez que se realice

sync Boolean Valor “false” (default), indica si la petición debe ser síncrona

timeout Integer Milisegundos de espera para la respuesta. Si el tiempo es superado, entonces se manda a llamar un error Callback

url String URL para la petición tabla 4. Características de la función dojo._XhrArgs

Los campos que fueron configurados en la función anterior son: url, handleAs, load, error, timeout. En el campo url tenemos como valor insert-user.php, a esta URL serán enviados los datos por método POST obtenidos de la forma de registro. El código PHP que se encuentra en dicha URL realizará entonces una inserción de los datos en la base de datos que creamos previamente.

insert-user.php <?php include('ez_sql_mysql.php'); if($_POST['name'] != "" && $_POST['phone'] != "" && $_POST['email_0'] != "" && $_POST['email_1'] != "" && $_POST['user'] != "" && $_POST['password'] != ""){ if($_POST['email_0'] == $_POST['email_1']){ global $mdb; $name = $_POST['name']; $lname = $_POST['lname']; $phone = $_POST['phone']; $address = $_POST['addr']; $email = $_POST['email_0']; $user = $_POST['user']; $password = $_POST['password']; $query = "INSERT INTO ajax_devel.userdata (name,lastname,phone,address,email,user,password) VALUES('$name','$lname','$phone','$address','$email','$user','$password')"; if($mdb->query($query)){ echo "Usted se ha registrado exitósamente"; }else{ echo "Error interno, intente de nuevo"; } }else{ echo "El correo electrónico no coincide"; } }else{ echo "Los campos con * son obligatorios";} ?>

El código anterior realiza lo siguiente:

• Realiza un análisis de los campos obligatorios para descartar la inserción del nuevo registro, si estos valores se encuentran vacíos

• Analiza las variables de email_0 y email_1 para determinar si coinciden los campos exactamente

• Se inserta en la base de datos el nuevo registro con campos obtenidas a partir de las variables POST

Page 39: Integrando AJAX & PHP

39

Para el manejo de la base de datos, usamos una librería ezSQL_mysql del programador Justin Vincent, la cual es incluida en el código anterior para ejecutar el “query” en el apéndice se puede encontrar más información a cerca de esta librería. El segundo uso de la función dojo.connect, es la siguiente: dojo.connect(dijit.byId("user"), "onChange", function(event){ var user_value = dojo.byId("user").value; var deferred = dojo.xhrGet({ url: "check-user.php?q="+ user_value, handleAs: "text", load: function(data){ if(data == "success"){ dijit.byId("submitCreate01").setAttribute("disabled",false); }else{ var msg = "Nombre de usuario en uso"; dojo.byId("textMsg").innerHTML = msg; dijit.byId("showMsg").show(); dijit.byId("submitCreate01").setAttribute("disabled",true); } }, error: function(error){ alert ("Un error ha ocurrido: " + error); }, timeout: 2000, }); });

La función contenida para comunicarnos con el servidor en este caso es xhrGet(), donde el objetivo es enviar al servidor el valor del campo “user” al realizarse un evento de tipo “onChange”, posteriormente el código PHP contenido en check-user.php realizará un análisis en la base de datos a parir del dato obtenido por método GET, para determinar si ese nombre de usuario se encuentra ya en uso. Si este no se encuentra en uso regresará el valor “success”, si no regresará una cadena de caracteres con detalles del error.

check-user.php <? include('ez_sql_mysql.php'); global $mdb; $prev_user = $_GET['q']; $query = "SELECT user FROM ajax_devel.userdata WHERE user='$prev_user'"; if(!($mdb->get_results($query))){ echo "success"; }else{ echo "El usuario se encuentra en uso, intente otro diferente";} ?>

Page 40: Integrando AJAX & PHP

40

En el lado del cliente, cuando el usuario termine de escribir el usuario automáticamente se invocará este código y si este usuario se encuentra ya ocupado, se desplegará una ventana de dialogo de error. A continuación del mensaje que aparecerá en el navegador si este escoge un nombre de usuario en uso:

fig. 9. visualización del dialogo

El cuadro de dialogo es mandado a llamar automáticamente cuando no se recibe la cadena de caracteres “success”, indicando que el usuario se encuentra en uso. Observemos el código JavaScript de esto. if(data == "success"){ dijit.byId("submitCreate01").setAttribute("disabled",false); }else{ var msg = "Nombre de usuario en uso"; dojo.byId("textMsg").innerHTML = msg; dijit.byId("showMsg").show(); dijit.byId("submitCreate01").setAttribute("disabled",true); }

Una vez que se despliega el mensaje por medio de la función dijit.byId(“showMsg”).show() se deshabilita el botón “crear” de la forma de registro con la función dijit.byId(“submitCreate01”).setAttribute(“disabled”,true). Si el nombre de usuario no se encuentra en uso entonces el botón “crear” permanece activo, si es que no se ingreso un usuario inválido anteriormente, o bien se vuelve a activar con dijit.byId(“submitCreate01”).setAttribute(“disabled”,false)

Page 41: Integrando AJAX & PHP

41

Sugerencias automáticas Las sugerencias automáticas en que el usuario tenga que ingresar alguna información en la entrada de un campo son útiles en los casos siguientes:

• Evitar al usuario teclear el dato completo y así agilizar el llenado de la forma • Si el usuario desconoce la sintaxis exacta del dato que se encuentra ingresando,

de modo que con la sugerencia este pueda elegir el dato deseado.

Caso 2. Auto-sugerencia Supongamos que el usuario tiene que llenar un formulario donde en uno de los datos ingresados se le solicita que ingrese el dato del país de procedencia. Pues bien, generalmente se utiliza utiliza el elemento <select> para este tipo de casos, si esta lista es extensa, el tiempo de selección puede ser agilizado por medio del tipo de sugerencia que veremos en este caso. Los archivos a utilizar serán: select-country.html, countries.php. Librería AJAX a utilizar: DojoToolkit. El árbol de como se encuentran configurados los ficheros para este caso es el siguiente:

fig. 10. Arreglo de ficheros para caso 2

Primeramente creamos nuestra tabla dentro de la base de datos ajax_devel, de la siguiente manera: mysql -force -quick -h localhost -utestuser -ppassword ajax_devel < countries.sql

El código countries.sql, crea una tabla con nombre countries y posteriormente inserta información a cerca de países de todo el mundo, como se muestra a continuación: SET NAMES latin1; SET FOREIGN_KEY_CHECKS = 0; CREATE TABLE `countries` ( `id` int(6) NOT NULL auto_increment, `country` varchar(250) NOT NULL default '', PRIMARY KEY (`id`)

Page 42: Integrando AJAX & PHP

42

) ENGINE=MyISAM AUTO_INCREMENT=243 DEFAULT CHARSET=latin1; insert into `countries` values('1','Afghanistan'),('2','Aringland Islands'), ('3','Albania'),('4','Algeria'),('5','American Samoa'),('6','Andorra'), ('7','Angola'),('8','Anguilla'),('9','Antarctica'), ('10','Antigua and Barbuda'),('11','Argentina'), ('241','Zimbabwe'); SET FOREIGN_KEY_CHECKS = 1;

Para fines prácticos solo mostramos en el código anterior solamente 12 registros. Ahora veamos el código que aparecerá en el navegador del usuario:

select-country.php <?php include("countries.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=UTF-8" /> <title>Select Country</title> <style type="text/css"> @import "scripts/dojo/dojo/resources/dojo.css"; @import "scripts/dojo/dijit/themes/tundra/tundra.css"; #content{margin 0 auto;} #content #header{text-align:center;} #content #info{margin:100px 200px 100px 200px; position:relative;} label{font-size:14px;} </style> <script type="text/javascript" src="scripts/dojo/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug:false"></script> <script type="text/javascript"> dojo.require("dijit.form.FilteringSelect"); dojo.addOnLoad(function(){ dojo.connect(dijit.byId("country"), "onChange", function(event){ var msg = "Usted seleccionó: "+ dijit.byId('country').attr('value') alert(msg) }); }); </script> </head> <body class="tundra"> <div id="content"> <div id="header"><h1>Caso 2. Auto-Sugerencia</h1></div> <div id="info"> <table> <tbody> <tr> <td><label>País de procedencia:</label></td> <td><select id="country" name="country_user" dojoType="dijit.form.FilteringSelect" autoComplete="true"> <?php show_Op_Countries();?> </select> </td> </tr> </tbody> </table> <div> <div id="footer"><p></p></div> </div> </body> </html> </body> </html>

Page 43: Integrando AJAX & PHP

43

En el código anterior nos encontramos utilizando una vez mas la libreria dijit de dojo, la cual nos va a proporcionar un <select> con mejoras muy interesantes para interactuar con datos. Para utilizar este “widget” solamente basta con declararlo de la manera siguiente en el código HTML: <select id="country" name="country_user" dojoType="dijit.form.FilteringSelect" autoComplete="true">

El API de dojo, nos indica que este componente, depende de la librería “dijit.form.FilteringSelect”, es por eso que realizamos lo siguiente, dentro del código JavaScript: dojo.require("dijit.form.FilteringSelect"). Otra manera de crear el widget anterior es por medio de código JavaScript, a esta forma se le denomina “programatically” (programáticamente). Como se muestra a continuación: vardS_f1=newdojo.data.ItemFileReadStore({url:'data‐countries.json'});varfiltSe_f1=newdijit.form.FilteringSelect({ id:'country', name:'county_user', store:dS_f1, searchAttr:'name' },dojo.byId("nodefilter"));La diferencia de la creación de este widget por medio de JavaScript al otro insertado directamente en el código HTML es que el primero debe de ser cargado cuando inicia la descarga de la página por medio de una función referenciada en dojo.addOnLoad(); además de que el nodo con id “nodefilter” debe de situarse dentro del documento HTML el cual contendrá el widget específicado. Además de que el origen de los datos en este caso es debe de estar en formato JSON en la url especificada en la función dojo.data.ItemFileReadStore(). El funcionamiento del código anterior es mostrar al usuario un “select” donde este ingresará el dato solicitado a cerca del país de procedencia. El elemento <select> fue previamente precargado por dojo puesto que tenemos activado el parámetro parseOnLoad, además de haber cargado los elementos “options” a través de una función en PHP que le permitirán al usuario tener una lista de los países en todo el mundo. Para poder desplegar la lista es necesario insertar el siguiente código PHP: <?php show_Op_countries(); ?>

Esta función puede ser invocada debido a que al inicio del documento incluimos el documento que contiene esa función. <?php include('ez_sql_mysql.php'); function show_Op_Countries(){ global $mdb; $query = "SELECT * FROM ajax_devel.countries"; $data = $mdb->get_results($query); $select_option = "<option selected='true'></option>"; foreach ( $data as $col ){ $select_option .= "<option value='".$col->country."'>".$col->country. "</option>"; } echo $select_option; } ?>

Page 44: Integrando AJAX & PHP

44

El código PHP anterior nos muestra como se realiza una petición a la base de datos, donde se encuentra la tabla “countries” previamente creada, esta tabla entonces contiene la información que es utilizada en los valores de los elementos <option> que serán

desplegados al usuario. fig. 10. visualización inicial de Auto-Sugerencia

fig. 11. Alerta al elegir un país

Page 45: Integrando AJAX & PHP

45

La figura anterior, nos muestra como el usuario al teclear completamente su país de procedencia o bien seleccionar un país de la lista con el cursor del mouse. Automáticamente aparece una alerta, con la información que el usuario registró. Esta alerta se dispara cuando ocurre un evento onChange, utilizando el siguiente código contenido en el documento select-country.php: dojo.connect(dijit.byId("country"), "onChange", function(event){ var msg = "Usted seleccionó: "+ dijit.byId('country').attr('value') alert(msg) }); Esta función es cargada al inicio en el navegador y permite estar en escucha del evento “onChange” en el elemento <select>, para que en el momento que ocurra dicho evento, se despliegue una alerta en el navegador del usuario con el valor que este haya seleccionado.

Caso 3. Sugerencia de búsqueda Las formas de búsqueda son muy útiles para encontrar información de manera rápida y precisa. En todos los portales ya es casi obligatorio tener una herramienta de búsqueda de este tipo y mejor aún si esta tiene integrada una función de sugerencia. Esta solución es la que veremos en este caso. Librería AJAX a utilizar: jQuery. Esta aplicación será un Buscador de noticias, el cual a través de una forma de búsqueda, el usuario ingresará alguna letra en la entrada, apareciendo automáticamente las sugerencias de búsqueda, a partir de un documento RSS XML. Los archivos a utilizar son: buscador.html y autosuggest.php, como se muestra en la siguiente figura:

fig. Arreglo de ficheros para caso 3 En la figura anterior se encuentra el archivo secfocus-news.xml, este archivo no es más que un archivo XML en formato RSS v2.0 donde la empresa Security Focus (http://www.securityfocus.com) experta en la seguridad de información actualiza sus noticias. Este documento XML nos servirá para obtener información de nuestro buscador.

Page 46: Integrando AJAX & PHP

46

Asimismo en este caso guardamos el archivo jquery.js dentro de la carpeta scripts. El código donde se encuentra el motor de búsqueda es el siguiente:

buscador.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=UTF-8" /> <title>Buscador de noticias</title> <script type="text/javascript" src="scripts/jquery.js"></script> <script> function suggestInfo(inputString){ if(inputString.length == 0) { $('#suggestions').fadeOut(); } else { $('#newsInfo').addClass('load'); $.post("autosuggest.php", {queryString: ""+inputString+""}, function(data){ if(data.length >0) { $('#suggestions').fadeIn(); $('#suggestionsList').html(data); $('#newsInfo').removeClass('load'); } }); } } function fillInput(thisValue,anotherValue,justAnotherValue) { $('#newsInfo').val(thisValue); setTimeout("$('#suggestions').fadeOut();", 400); var linkNew = "<a href='"+anotherValue+"'>"+justAnotherValue+"</a>"; $('#newDesc').html(linkNew) } </script> <style> #content {margin 0 auto;} #content #info {margin:50px 0 200px; position:relative;} #info h1{text-align:center;} #content #info #result { height:20px;font-size:16px;font-family:Arial, Helvetica, sans-serif; color:#333;padding:5px;margin-bottom:10px;background-color:#FFFF99;} #content #info #newsInfo{padding:3px;border:1px #CCC solid;font-size:17px;} #content #info .suggestionsBox { position: relative;left:300px;margin: 26px 0px 0px 0px;width: 200px; padding:0px;background-color: #000;border-top: 3px solid #000;color: #fff;} #content #info .suggestionList {margin: 0px;padding: 0px;} #content #info .suggestionList ul li { list-style:none;margin: 0px;padding: 6px; border-bottom:1px dotted #666;cursor: pointer;} #content #info .suggestionList ul li:hover { background-color: #FC3;color:#000;} #content #info ul { font-family:Arial, Helvetica, sans-serif;font-size:11px; color:#FFF;padding:0;margin:0;} #content #info .load{ background-image:url(loader.gif);background-position:right; background-repeat:no-repeat;} #content #info #suggest {position:relative;text-align:center;}

Page 47: Integrando AJAX & PHP

47

#content #info #newDesc{margin:0px auto;position relative;text-align:center;} </style> </head> <body> <div id="content"> <div id="info"> <h1>Caso 3. Sugerencia de Búsqueda</h1> <form id="form" action="#"> <div id="suggest">Búsqueda de Información: <br /> <input type="text" size="25" value="" id="newsInfo" onkeyup="suggestInfo(this.value);" class="" /> <div class="suggestionsBox" id="suggestions" style="display: none;"> <img src="arrow.png" style="position: relative; top: -12px; left: 30px;" alt="upArrow" /> <div class="suggestionList" id="suggestionsList"> &nbsp; </div> </div> </div> </form> <div id="newDesc"> </div> </div> </div> </body> </html> El funcionamiento del código anterior es el siguiente:

• La entrada en el elmento <input> se encuentra en escucha del evento onKeyup, cuando este evento sea ejecutado la función en JavaScript suggestInfo() se disparará.

• La función suggestInfo, pide información al servidor por medio del objeto XMLHttpRequest, en este caso como se utiliza la librería jQuery se usa la función $.post()

A continuación el modo de uso de la función $.post(), en el código anterior: $.post("autosuggest.php", {queryString: ""+inputString+""}, function(data){ if(data.length >0) { $('#suggestions').fadeIn(); $('#suggestionsList').html(data); $('#newsInfo').removeClass('load'); } }); Como observamos en el código anterior la URL a la que le será realizada la petición es autosuggest.php, mandando la cadena de caracteres inputString, y los datos regresados por el servidor son insertados en el elemento DOM con ID: #suggestionsList. Además de que se “deshabilita” el gift de “loading” eliminando la clase “load” del elemento <input>, añadido anteriormente con: $('#newsInfo').addClass('load');

Page 48: Integrando AJAX & PHP

48

Ahora veamos que se realiza en la parte del servidor con los datos enviados por método POST.

autosuggest.php <?php $xmlDoc = new DOMDocument(); $xmlDoc->load("secfocus-news.xml"); $x=$xmlDoc->getElementsByTagName('item'); $queryString=$_POST["queryString"]; if (strlen($queryString) > 0){ $stringSuggestions=""; for($i=0; $i<($x->length); $i++){ $title=$x->item($i)->getElementsByTagName('title'); $link=$x->item($i)->getElementsByTagName('link'); $desc=$x->item($i)->getElementsByTagName('description'); if ($title->item(0)->nodeType==1){ if (stristr($title->item(0)->childNodes->item(0)->nodeValue,$queryString)){ if ($stringSuggestions==""){ $stringSuggestions = "<li onClick='fillInput(\"".$title->item(0)->childNodes->item(0)->nodeValue."\",\"".$link->item(0)->childNodes->item(0)->nodeValue."\",\"".$desc->item(0)->childNodes->item(0)->nodeValue."\")'>".$title->item(0)->childNodes->item(0)->nodeValue."</li>"; }else{ $stringSuggestions .= "<li onClick='fillInput(\"".$title->item(0)->childNodes->item(0)->nodeValue."\",\"".$link->item(0)->childNodes->item(0)->nodeValue."\",\"".$desc->item(0)->childNodes->item(0)->nodeValue."\")'>".$title->item(0)->childNodes->item(0)->nodeValue."</li>"; } } } } } if ($stringSuggestions == ""){ $response="sin sugerencia"; }else{ $response="<ul>$stringSuggestions</ul>"; } echo $response; ?> El código anterior, realiza una búsqueda de la cadena de caracteres recibida por POST, en el documento XML llamado secfocus-news.xml. Posteriormente se devuelve una lista de resultados en forma de lista dentro de elementos <li> para que sean mostrados en el motor de búsqueda del usuario con un estilo definido. Analizando las líneas en el código anterior se comienza creando un nuevo documento DOM, para esto nos ayudamos de una API de PHP5 para manejo de documentos XML, si se esta utilizando PHP4 se puede utilizar DOM XML como se muestra a continuación: $xmlDoc = new DOMDocument();

Se carga un archivo por medio del método mixed load(string $filename[,int $options = 0]): $xmlDoc->load("secfocus-news.xml");

Entonces se obtienen los elementos dados por el elemento “item” a través del método DOMNodeList getElementsByTagName ( string $name ) :

Page 49: Integrando AJAX & PHP

49

$x=$xmlDoc->getElementsByTagName('item');

Se asigna la variable obtenida por POST a $queryString: $queryString=$_POST["queryString"]; Posteriormente dentro del ciclo for asignamos las variables de los elementos para obtener la información que se encuentra dentro de los elementos. for($i=0; $i<($x->length); $i++){ $title=$x->item($i)->getElementsByTagName('title'); $link=$x->item($i)->getElementsByTagName('link'); $desc=$x->item($i)->getElementsByTagName('description'); Ahora analizamos el tipo de nodo con la función int DomNode->node_type (int), de la siguiente manera: if ($title->item(0)->nodeType==1){ Los valores que se pueden obtener a partir de nodeType son unas constantes predefinidas por la extensión de PHP, donde el 1 quiere decir que el nodo es un elemento tipo DOM (DOMElement). Posteriormente se analiza el elemento <title> en búsqueda de coincidencias con la cadena que se encuentra ingresando el usuario, si se encuentra alguna coincidencia, se crea la lista de sugerencia a través de los valores que se encuentran en los elementos <link>, <title>: if (stristr($title->item(0)->childNodes->item(0)->nodeValue,$queryString)){ if ($stringSuggestions==""){ $stringSuggestions = "<li onClick='fillInput(\"".$title->item(0)->childNodes->item(0)->nodeValue."\",\"".$link->item(0)->childNodes->item(0)->nodeValue."\",\"".$desc->item(0)->childNodes->item(0)->nodeValue."\")'>".$title->item(0)->childNodes->item(0)->nodeValue."</li>"; }else{ $stringSuggestions .= "<li onClick='fillInput(\"".$title->item(0)->childNodes->item(0)->nodeValue."\",\"".$link->item(0)->childNodes->item(0)->nodeValue."\",\"".$desc->item(0)->childNodes->item(0)->nodeValue."\")'>".$title->item(0)->childNodes->item(0)->nodeValue."</li>"; } } El código anterior observamos que cada elemento <li> creado para la lista de sugerencia, contiene una función javaScript que se llama fillnput(), la cual se dispara cuando el evento onClick es activada, esta función la describiremos mas adelante. Si existen sugerencias la lista de elementos es enviada como respuesta a través del objeto XMLHttpRequest, si ninguna sugerencia fue encontrada, entonces se manda como respuesta “sin sugerencia” al navegador del usuario.

Page 50: Integrando AJAX & PHP

50

fig. 11. sugerencia de búsqueda para el usuario

Desde que el usuario ingrese un carácter la función de suggestInfo() estará trabajando en búsqueda de sugerencias, en el caso de la figura anterior, solamente basto que se teclearan tres caracteres para que la lista de sugerencias sea visualizada de manera inmediata. Ahora observemos que sucede al dispararse el evento fillInput(), contenido en cada elemento de la lista sugerida:

fig. 12. sugerencia seleccionada

Page 51: Integrando AJAX & PHP

51

Una vez que el usuario de click en alguna de las sugerencias, la función fillInput() se activa, realizando lo siguiente. El código JavaScript es el siguiente: function fillInput(thisValue,anotherValue,justAnotherValue) { $('#newsInfo').val(thisValue); setTimeout("$('#suggestions').fadeOut();", 400); var linkNew = "<a href='"+anotherValue+"'>"+justAnotherValue+"</a>"; $('#newDesc').html(linkNew) } La función anterior recibe tres valores a partir del evento onClick realizado en una sugerencia de la lista, la función entonces realiza las siguientes operaciones:

• El valor del input con id #newsInfo es puesto con el valor del elemento “title” seleccionado.

• Se crea una liga con la descripción de la noticia y con referencia hacia la página donde ella se encuentra en detalle.

• La liga creada anteriormente se inserta dentro del elemento con id #newDesc.

Interfaz Gráfica de Usuario En capítulos anteriores hemos estado utilizando interfaces gráficas, desde las formas para registrar usuarios, hasta las sugerencias mostradas en tiempo real. Sin embargo este capítulo veremos más a detalle cuales son los elementos visuales que son utilizados en AJAX, la funcionalidad de cada uno de ellos, y cuales nos proporcionan los toolkits AJAX. Configurarlos y realizar algunos casos de estudio para explotar sus cualidades junto con peticiones al servidor. Una Interfaz Gráfica de usuario (GUI) permite al usuario interactuar con funciones de la aplicación a través de elementos visuales. El elemento visual mas sencillo es un botón. AJAX nos proporciona la tecnología para que los elementos visuales sean intuitivos además de añadir una sensación al usuario de estar utilizando una aplicación de escritorio. La tecnología DHTML con ayuda de CSS y JavaScript, proporcionan una visualización dinámica del documento. Ahora bien, si le añadimos a esto la funcionalidad de que las funciones contenidas en la GUI interactuen con el servidor de manera asíncrona,

Page 52: Integrando AJAX & PHP

52

realizando peticiones, el resultado es una aplicación AJAX con una experiencia rica para el usuario. Los elementos gráficos que comúnmente pueden ser encontrados en los toolkits de desarrollo, podríamos dividirlos de acuerdo a su funcionamiento. Como elementos de disposición y elementos de control, eta división es arbitraria, pero nos permite realizar un estudio más categorizado: Elementos de disposición. Estos elementos proporcionan al usuario una interfaz gráfica arreglada en contenedores, estos tienen la capacidad, de cargar información obtenida a través de XMLHttpRequest según sea requerida, tener un estilo visual diferente al del documento, además de contener dentro de sí otros elementos de disposición o de control.

• Content / Panel. Contenedores generales, que sirven de marco para los demás elementos de disposición.

• Horizontal / Vertical Split Panel. Estos paneles pueden contener “widgets” además de que el usuario puede interactuar con ellos cambiando la proporción de ancho o alto del panel

• Tabs. Este elemento o “widget” permite interactuar al usuario dándole la sensación que este se encuentra navegando en pestañas de folders.

• Accordion. Este elemento interactua con el navegador por medio de otros sub-elementos contenidos en el, proporcionando información variable en cada uno de ellos solo que en manera animada al seleccionar cada uno, como un “acordeón”.

• Grid. Es un conjunto de “celdas” las cuales contienen distintos eventos dentro de ellas, ya sea por columna, líneas o bien por celda individual.

Elementos de Control. Elementos que se caracterizan por tener funciones de control, las cuales al interactuar con el usuario, afectan a otros elementos distintos a este, ya sea en su estilo visual o bien en modificación de información dentro de dichos elementos.

• Menú. Es un elemento que contiene a su vez sub-elementos que contienen funciones específicas que reaccionan con el cursor del mouse.

• ProgressBar. Indicadores que proveen información al usuario del estado de alguna petición de información que se este realizando.

• ColorPalette. Control que permite seleccionar un color, a partir de una gama de colores, para configuraciones especiales de estilo o bien, para obtener información de selección solamente.

• Editor. Comúnmente conocidos como WYSWYG(what you see is what you get). Este es mas bien un contenedor de varios controles, los cuales permiten al usuario

Page 53: Integrando AJAX & PHP

53

editar un texto y modificarlo con funciones comunes de edición como: cortar, pegar, cambio del estilo de texto, etc.

• Tree. Elemento que proporciona despliegue de información de una manera esquemática y arreglada en nodos que contienen a su vez sub-nodos.

• Dialog Box / Splash Screen. Cuadro de texto emergente en forma de ventana con información específica.

• Tool-tip. Proporciona al usuario información adicional, en tiempo real del elemento o cuadro de información donde se encuentra situado el cursor del mouse.

• Slider. Control usado en las formas, que permite recoger valores a partir de una imagen que “resbala” de manera horizontal o vertical.

• DatePicker / Date TextBox. Cuadro desplegable en forma de calendario, donde el usuario puede seleccionar de manera visual una fecha en especifica.

Caso 4. Monitoreo en tiempo real El siguiente caso de estudio,tiene como objetivo ser una herramienta sencilla de monitoreo para sistemas operativos tipo *nix, las funciones que de esta herramienta nos permite observar en tiempo real los siguientes datos:

• Estado de los procesos corriendo en el SO • Estado de la memoria virtual • Estado de la red • Últimos ingresos de usuarios y ttys • Que usuarios se encuentran en el SO • El tiempo transcurrido que el SO se encuentra activo

Librería AJAX a utilizar: dojoToolkit. A continuación el arreglo de ficheros recomendado:

fig. 12. Arreglo de ficheros para la aplicación de monitoreo Los archivos que son utilizados en este caso son: functions.php este archivo contiene las funciones necesarias para enviar los datos a la interfaz gráfica. El archivo monitor.php contiene la interfaz gráfica que visualizará al usuario los datos recibidos por functions.php.

Page 54: Integrando AJAX & PHP

54

monitor.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=UTF-8" /> <title>Monitor</title> <style type="text/css"> @import "scripts/dojo/dojo/resources/dojo.css"; @import "scripts/dojo/dijit/themes/tundra/tundra.css"; html, body { width: 100%; height: 100%; margin: 0; } #borderContainer { width: 100%; height: 100%; } </style> <script type="text/javascript" src="scripts/dojo/dojo/dojo.js" djConfig="parseOnLoad:true, isDebug:false"></script> <script type="text/javascript"> dojo.require("dijit.layout.AccordionContainer"); dojo.require("dijit.layout.StackContainer"); dojo.require("dijit.layout.BorderContainer"); dojo.require("dijit.form.Button"); var proc = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=proc", load: function(data){dojo.byId("process").innerHTML = data;}});}, 2000); var vm = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=vm", load: function(data){dojo.byId("vmemory").innerHTML = data;}});}, 2500); var net = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=net", load: function(data){dojo.byId("network").innerHTML = data;}});}, 2600); var lastlog = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=lastlog", load: function(data){dojo.byId("lastlog").innerHTML = data;}});}, 7600); var who = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=who", load: function(data){dojo.byId("who").innerHTML = data;}});}, 6600); var uptime = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=uptime", load: function(data){dojo.byId("uptime").innerHTML = data;}});}, 6600); </script> </head> <body class="tundra"> <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="true" liveSplitters="true" id="borderContainer"> <div dojoType="dijit.layout.ContentPane" splitter="true" region="leading" style="width: 600px;"> <div dojoType="dijit.layout.AccordionContainer" style="height: 400px;" selected="true"> <div dojoType="dijit.layout.ContentPane" title="Process Status"> <div id="process"> </div> </div> <div dojoType="dijit.layout.ContentPane" title="Virtual Memory Status"> <div id="vmemory"> </div> </div> <div dojoType="dijit.layout.ContentPane" title="Network status"> <div id="network"> </div> </div> </div> </div>

Page 55: Integrando AJAX & PHP

55

<div dojoType="dijit.layout.ContentPane" splitter="true" region="center"> <button id="previous" onClick="dijit.byId('stackContainer').back()" dojoType="dijit.form.Button"> <</button> <span dojoType="dijit.layout.StackController" containerId="stackContainer"> </span> <button id="next" onClick="dijit.byId('stackContainer').forward()" dojoType="dijit.form.Button"> > </button> <div dojoType="dijit.layout.StackContainer" id="stackContainer"> <div dojoType="dijit.layout.ContentPane" title="Last Logins"> <div id="lastlog"> </div> </div> <div dojoType="dijit.layout.ContentPane" title="who is logged"> <div id="who"> </div> </div> <div dojoType="dijit.layout.ContentPane" title="Uptime"> <div id="uptime"> </div> </div> </div> </div> </div> </body> </html> </body> </html>

En el código anterior, se encuentran integrados 3 “widgets” que nos permiten realizar una disposición visual de los elementos muy amigable. Estos “widgets” son: BorderContainer, AccordionContainer y StackContainer. Ahora analizaremos cada uno de ellos por separado, basandonos en la API de dojo. BorderContainer. Este “widget” es un contenedor que puede ser fraccionado hasta en 5 regiones: izquierda (leading), derecha (trailing), arriba (top), abajo(bottom), además de la parte central (center) que es obligatorio usar. Cada una de estas regiones puede tener una interfaz activada tipo “splitter” el cual es útil para realizar modificaciones en el tamaño de la región de manera manual. fuente: http://api.dojotoolkit.org/jsdoc/1.3/dijit.layout.BorderContainer Requerimiento de librería: dijit.layout.BorderContainer El modo de uso es el siguiente: var foo=new dijit.layout.BorderContainer(params: Object?, srcNodeRef: DomNode|String);

parámetro tipo descripción

params Object opcional

srcNodeRef DomNode | String

Page 56: Integrando AJAX & PHP

56

tabla 5. Características del widget dijit.layout.BorderContainer

o bien también podemos utilizar código HTML directamente en el documento: <div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="true" liveSplitters="true" id="borderContainer"> <div dojoType="dijit.layout.ContentPane" splitter="true" region="leading" style="width: 600px;"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer eget nisl lectus </div> <div dojoType="dijit.layout.ContentPane" splitter="true" region="center">

Cras non sapien quis lectus tempor viverra sit amet ut velit.

</div></div>

El código anterior nos muestra de forma sumarizada como se uso BorderContainer en monitor.php. AccordionContainer. Widget que contiene una configuración de paneles, donde el título se encuentra visible, pero solamente un panel es visible a la vez, el cambio entre paneles es visualizado como una animación donde estos resbalan hacia arriba o hacia abajo. Requerimiento de librería: dijit.layout.AccordionContainer Modo de uso: var foo=new dijit.layout.AccordionContainer(params: Object?, srcNodeRef: DomNode|String);

parámetro tipo descripción

params Object opcional

srcNodeRef DomNode | String

tabla 6. Características del widget dijit.layout.AccordionContainer

obientambiénintegradoenelcódigoHTMLdeldocumentocomosemuestraacontinuación: <div dojoType="dijit.layout.AccordionContainer" style="height: 400px;" selected="true"> <div dojoType="dijit.layout.ContentPane" title="Process Status"> </div> <div dojoType="dijit.layout.ContentPane" title="Virtual Memory Status"> </div> <div dojoType="dijit.layout.ContentPane" title="Network status"> </div> </div>

StackContainer. Este es un contenedor de “widgets”, que permite desplegar solamente un “widget” a la vez. Requerimiento de librería: dijit.layout.StackContainer

Page 57: Integrando AJAX & PHP

57

Modo de uso: var foo=new dijit.layout.StackContainer(params: Object?, srcNodeRef: DomNode|String);

parámetro tipo descripción

params Object opcional

srcNodeRef DomNode | String

tabla 7. Características del widget dijit.layout.StackContainer

de la misma manera puede ser integrado como código html: <div dojoType="dijit.layout.StackContainer" id="stackContainer"> <div dojoType="dijit.layout.ContentPane" title="Last Logins"> </div> <div dojoType="dijit.layout.ContentPane" title="who is logged"> </div> <div dojoType="dijit.layout.ContentPane" title="Uptime"> </div> </div>

El código javaScript se encuentra compuesto por cuatro funciones que realizan las peticiones al servidor de la siguiente manera:

1. El método DOM setInterval() , ejecuta una función cada determinado tiempo. 2. La función ejecutada utiliza dojo.xhrGet para realizar una petición a functions.php 3. El servidor devuelve la petición realizada y la información es insertada en un

elemento DOM configurado en la función anterior. El método DOM setInterval() llama a una función repetidamente, con intervalo de tiempo determinado para realizar esta llamada. Este método nos es útil pues ejecutará en el servidor una función que contiene un comando específico, el cual la salida estándar de la ejecución de dicho comando será regresado a monitor.php para ser desplegado en el navegador. El modo de uso, para setInterval() es el siguiente: intervalID = window.setInterval(func|code, delay[, param1, param2, ...]);

parámetro tipo descripción

intervalD ID parámetro que puede ser pasado a clearInterval()

func | code pointer puntero a una función o el código a ser ejecutado

delay int numero en milisegundos, donde la función de setInterval() esperará para ser mandada a llamar nuevamente

fuente: https://developer.mozilla.org/en/DOM/window.setInterval

Page 58: Integrando AJAX & PHP

58

tabla 8. Características del método DOM setInterval(). El intervalo “delay” puede ser cancelado mandando usando window.clearInterval(). O bien si se requiere que la función sea llamada una sola vez, después de un retraso especificiado usar window.setTimeout(). El método setInterval() es usado en monitor.php de la siguiente manera: var proc = self.setInterval(function(){dojo.xhrGet({ url:"functions.php?q=proc", load: function(data){dojo.byId("process").innerHTML = data;}});}, 2000);

Como se observa proc es el ID para el método setInterval(), el código de la función será ejecutado cada 2000 milisegundos. La función contenida realiza una petición a functions.php por método GET a través de la función dojo.xhrGet(), la respuesta obtenida por esta petición será insertado en el objeto DOM con ID “process”.

functions.php <?php if(isset($_GET['q'])){ $request = $_GET['q']; switch($request){ case 'proc': $output = show_Output_Command("ps aux | awk '{print $1,$2,$3,$4,$5,$6,$7,$8}'"); echo $output; break; case 'vm': $output = show_Output_Command("vm_stat"); echo $output; break; case 'net': $output = show_Output_command("netstat -an"); echo $output; break; case 'lastlog': $output = show_Output_command("last"); echo $output; break; case 'who': $output = show_Output_command("who"); echo $output; break; case 'uptime': $output = show_Output_command("uptime"); echo $output; break; default: break; } } function show_Output_Command($command){ exec($command,$output); $string = "<table></tbody>"; for($i=0;$i<count($output);$i++){ $string .= "<tr><td>".$output[$i]."</td></tr>"; } $string .= "</tbody></table>"; return $string; } ?>

Page 59: Integrando AJAX & PHP

59

El número total de peticiones diferentes realizadas a functions.php son seis, aquí se obtiene la petición por medio del método GET y posteriormente es analizada por medio de la declaración switch. Después de analizar que información se requiere con ayuda de la función show_Output_command(), se manda el comando unix a ejecutar, dando como resultado una salida estándar en txt, que será visualizado en el navegador. A continuación la vista del navegador para el usuario.

fig. 13. visualización de monitor.php

En la figura anterior se encuentran desplegadas dos de las cinco funciones, el estado de la red lo podemos ver del lado izquierdo en un contenedor tipo “acordeon”, y los últimos registros de usuarios del lado derecho contenido en un contenedor tipo “stack”. Toda la información desplegada se actualizará automáticamente de acuerdo al parámetro configurado en setInterval() en milisegundos. Cuando la información contenida dentro de los “widgets” supera la medidas de ancho o largo establecidas, se puede observar como automáticamente aparecen los “sliders” horizontales y/o verticales según sea el caso, para facilitar la visualización del contenido restante.

Page 60: Integrando AJAX & PHP

60

Caso 5. Visualizador de archivos En este caso se desarrollará un programa que permite administrar archivos en web se llamará “visualdoc”, las funciones de este programa son las siguientes:

• visualizar archivos cargados en el directorio específico • eliminar archivos • subir archivos a un directorio especifico • descargar archivos

Librería AJAX a utilizar: jquery. A continuación el arreglo de ficheros recomendado:

fig. 14. arreglo de ficheros para visualdoc. El programa se encuentra construido por medio de tres documentos php: visualdoc, readdir-json.php y functions.php. Además de las librerías javaScript: jquery, jquery-ui y ajaxupload.js. El documento visualdoc.php es la parte medular, que permite al usuario visualizar los documentos que se encuentran en la carpeta “uploads”, además de que es el panel donde el usuario interactua con las funciones del programa, descritas anteriormente. A continuación el código fuente de visualdoc.php:

visualdoc.php <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Visual Document</title> <meta name="author" content="eliseo"> <link type="text/css" href="scripts/jquery-ui/css/ui-lightness/jquery-ui-1.7.2.custom.css" rel="Stylesheet" /> <script src="scripts/jquery-ui/js/jquery-1.3.2.min.js" type="text/javascript"></script> <script src="scripts/jquery-ui/js/jquery-ui-1.7.2.custom.min.js" type="text/javascript"></script> <script src="scripts/ajaxupload.js" type="text/javascript"></script> <style type="text/css"> .toolbar { padding: .5em; margin: 0; width:50%; } .toolbar .fg-button { outline: 0; margin:0 1px 0 0; padding: .1em .5em; text-decoration:none !important; cursor:pointer; position: relative;

Page 61: Integrando AJAX & PHP

61

text-align: center; zoom: 1; display:inline; } .row{color:#3e4e5e;} table{ padding:1px; border-spacing:10px; border-collapse:separate;} tr.list:hover {background-color: #81eafe;color:#1e2e3e;} .clicked{background-color: #81effe;color:#1e2e3e;} #content{margin:0 px auto;margin-left:10em;} </style> <script type="text/javascript"> function showDocs(){ $.getJSON("readdir-json.php", function(data){ var path = "uploads"; $.each(data.items, function(i,item){ var div = $("<tr>").addClass("list row"+i).appendTo("#file-list"); var div2 = $("<td>").addClass("col"+i+1).appendTo(div); var div3 = $("<td>").addClass("col"+i+2).appendTo(div); var div4 = $("<td>").addClass("col"+i+3).appendTo(div); var div5 = $("<td>").addClass("col"+i+4).appendTo(div); $(div2).append("<input type=\"checkbox\" class=\"col"+i+3+"\" name=\"file"+i+"\" value=\""+item.nombre+"\"/>"); $(div3).html("<b class=\"name\">"+item.nombre+"</b>"); $(div4).html("<b class=\"tiempomod\">"+item.tiempomod+"</b>"); $(div5).html("<a id=\"col\" href=\""+path+"/"+item.nombre+"\" class=\"ui-state-default ui-corner-all fg-button\" style=\"width:70px;text-align:center;\">descargar</a>"); $("input.col"+i+3).bind("click", function(){ if(("tr.row"+i).is(".clicked")){ $("tr.row"+i).removeClass("clicked"); }else{ $("tr.row"+i).addClass("clicked"); } } ); }); }); } $(document).ready(function(){ showDocs(); $("#eliminar").hover(function(){ $(this).addClass("ui-state-hover"); }, function(){ $(this).removeClass("ui-state-hover"); }); $("#eliminar").click(function(){ $.post("functions.php?mod=delete", $("#form-list").serialize(), function(data){ alert(data); $("#file-list").html(""); showDocs();

Page 62: Integrando AJAX & PHP

62

}, "text" ); }); new AjaxUpload('#button3', { action: 'functions.php?mod=upload', name: 'userfile', onComplete : function(file){ $('<li></li>').appendTo($('#file-upload .files')).text(file); $("#file-list").html(""); showDocs(); } }); }); </script> </head> <body> <div id="content"> <h1 style="text-align:center;">Caso 5. Administrador de Documentos</h1> <div id="file-upload"> <p>Escoja el archivo para subir al servidor:</p> <input id="button3" type="file" name="userfile"/> <p>Últimos archivos:</p> <ol class="files"></ol> <div id="newFiles"> </div> </div> <br /><br/> <form id="form-list"> <div class="toolbar"> <div id="eliminar" name="eliminar" class="ui-state-default ui-corner-all fg-button" style="width:70px;text-align:center;">eliminar</div> </div> <table id="file-list"> <tr><th>&nbsp;</th><th>Nombre</th><th>Última Modificación</th></tr> </table> </form> </div> </body> </html> En el código javaScript anterior tenemos la función showDocs(), esta función tiene la característica de que al ser invocada, realiza una conexión por medio de XMLHttpRequest hacia readdir-json.php de donde se obtiene información a cerca de los archivos contenidos en el directorio uploads, esta información es obtenida en formato JSON, posteriormente esta información es analizada y cada dato de los elementos JSON es obtenida y se le da un formato html para visualizar dentro de un elemento DOM. Antes de continuar entendamos que es JSON. JSON (JavaScript Object Notation) es un formato para intercambio de datos ligero. Fácil de lectura y escritura para los humanos y fácil para las máquinas analizar y generar. Aunque JSON es un formato de texto es completamente independiente de cualquier lenguaje sin embargo usa convenciones que son familiar a programadores de lenguajes provenientes de la familia del lenguaje de programación C, incluyendo C++, C#, java, JavaScript, Perl, Python y muchos otros. Lo que hacen que JSON sea el formato ideal para intercambio de datos.

Page 63: Integrando AJAX & PHP

63

Las formas en como JSON se encuentra estructurado son:

• Objeto.Unconjuntodesordenadodeparesnombre/valor.Unobjetocomienzaconuna{(llavedeapertura)yterminacon}(llavedecierre).Cadanombreesseguidopor:(dospuntos)ylosparesnombre/valorestánseparadospor,(coma).

• Array. Colección de valores. Comienza con una [ (corchete izquierdo) y termina con ](corchetederecho).Losvaloresseseparanpor,(coma).

• Value.Unvalorpuedeserunacadenadecaracteresconcomillasdobles,ounnúmero,otrueofalseonull,ounobjetoounarreglo.Estasestructuraspuedenanidarse.

• String.UnacadenadecaracteresesunacoleccióndeceroomáscaracteresUnicode,encerrados entre comillas dobles, usandobarrasdivisoras comoescape.Un carácterestarepresentadoporunacadenadecaracteresdeunúnicocarácter.UnacadenadecaracteresesparecidaaunacadenadecaracteresdeCojava.

• Number. Un número es similar a un número de C o Java, excepto que no se usanformatosoctalesyhexadecimales.

Los espacios en blanco pueden insertarse en cualquier par de símbolos. Exceptuando pequeños detalles de encoding, esto se describe completamente el lenguaje. fuente: http://www.json.org/ Ahora vemos el código fuente del documento con el cual se construye un documento con estructura JSON:

readdir-json.php <?php $path = "uploads"; dirList($path); function dirList ($directory){ $string =""; $string .= "{\"fichero\": \"File\", \"items\": ["; $handler = opendir($directory); while ($file = readdir($handler)) { $path = $directory."/".$file; $type = filetype($path); $stat_vars = stat($path); if ($file != "." && $file != ".." && $type != "dir"){ $string .= "{\"nombre\": \"". $file . "\","; $string .= "\"tipo\": \"". $type . "\","; if($type == "file"){ $string .= "\"tamaño\": \"".filesize($path)."\","; $string .= "\"tiempomod\": \"".date("F d g:i",$stat_vars["mtime"])."\""; } $string .= "},"; } } $string .= "]}"; closedir($handler); echo $string; } ?>

Page 64: Integrando AJAX & PHP

64

ElcódigoanteriorPHPrealizalossiguientesprocesos:

1. Realiza una lectura de un directorio especificado para obtener datos a cerca de losarchivoscontenidosenel.

2. Cada archivo contenido en el directorio es analizado y se le añade parámetroscorrespondientesalformatoJSON,concatenadosenlavariable$string.

3. Una vez terminado el formato con cada archivo, se ejecuta una salida estándar conecho$string,elcualcontieneundocumentodeacuerdoa lasreglasdeestructuradedatosJSON,similaralsiguiente:

{"fichero": "File", "items": [{"nombre": ".DS_Store","tipo": "file","tamaño": "12292","tiempomod": "September 15 10:40"},{"nombre": "10_best_sec_practices.rtf","tipo": "file","tamaño": "3387","tiempomod": "September 19 5:50"},{"nombre": "ccp-erlang.pdf","tipo": "file","tamaño": "329659","tiempomod": "May 15 11:10"},{"nombre": "El arte de poporear.pdf","tipo": "file","tamaño": "140211","tiempomod": "September 15 3:14"},{"nombre": "manual.pdf","tipo": "file","tamaño": "756318","tiempomod": "May 15 7:15"},{"nombre": "Practical_Unix_Security.pdf","tipo": "file","tamaño": "439978","tiempomod": "September 17 6:51"},{"nombre": "prueba.txt","tipo": "file","tamaño": "3126","tiempomod": "September 14 5:45"},{"nombre": "SIFT-Log-Injection-Intelligence-Report-v1-00.pdf","tipo": "file","tamaño": "224782","tiempomod": "May 15 9:36"},{"nombre": "unidades_energia.pdf","tipo": "file","tamaño": "62959","tiempomod": "May 15 7:40"},]} Los datos anteriores son los que serán analizados por la función showDocs() de JavaScript, contenido en el documento visualdoc.php. Dentro de la función anterior se encuentra otra función jquery utilizada para XMLHttpRequest de datos tipo JSON, dicha función es $.getJSON(), a continuación modo de uso: jquery.getJSON(url, [data], [callback])

parámetro tipo descripción

url string La URL de la página a cargar

data Map Pares de Llave/valor que serán enviadas al servidor

callback function función a ejecutarse en cualquier momento que el dato haya sido obtenido correctamente

tabla 9. Características de jquery.getJSON() Ahora analicemos como es usada esta función dentro del código JavaScript del documento visualdoc.php. $.getJSON("readdir-json.php", function(data){ var path = "uploads"; $.each(data.items, function(i,item){ var div = $("<tr>").addClass("list row"+i).appendTo("#file-list"); var div2 = $("<td>").addClass("col"+i+1).appendTo(div); var div3 = $("<td>").addClass("col"+i+2).appendTo(div); var div4 = $("<td>").addClass("col"+i+3).appendTo(div); var div5 = $("<td>").addClass("col"+i+4).appendTo(div);

Page 65: Integrando AJAX & PHP

65

$(div2).append("<input type=\"checkbox\" class=\"col"+i+3+"\" name=\"file"+i+"\" value=\""+item.nombre+"\"/>"); $(div3).html("<b class=\"name\">"+item.nombre+"</b>"); $(div4).html("<b class=\"tiempomod\">"+item.tiempomod+"</b>"); $(div5).html("<a id=\"col\" href=\""+path+"/"+item.nombre+"\" class=\"ui-state-default ui-corner-all fg-button\" style=\"width:70px;text-align:center;\">descargar</a>"); $("input.col"+i+3).bind("click", function(){ if ($("tr.row"+i).is(".clicked")){ $("tr.row"+i).removeClass("clicked"); }else{ $("tr.row"+i).addClass("clicked"); } }); });

La función $.each(), nos permite “analizar” cada uno de los valores del arreglo contenido en el documento json. El modo de uso es el siguiente: jQuery.each(object,callback)

parámetro tipo descripción

object object Objeto o arreglo (array) para iterar

callback Function Función que será ejecutada en cada objeto

tabla 10. Características de jQuery.each() Esta función entonces nos permite navegar en cada elemento tipo “item” obtenido desde readdir-json.php añadiendole el código html correspondiente para que sea insertado en un elemento DOM especificado, con ayuda de addClass, appendTo, append, html. A continuación la explicación de cada uno de ellos. addClass(class) pertenecealaclasede“Attributes”delaAPIJQuery.

parámetro tipo descripción

class string Una o más clases para añadir a los elementos, separados cada uno por espacios

tabla 11. Características de addClass() Esta función añade las clases especificadas a cada uno de los elementos configurados appendTo(selector) pertenece a la clase de “Manipulation” de la API JQuery.

Page 66: Integrando AJAX & PHP

66

parámetro tipo descripción

selector selector objetivo donde el contenido será añadido al final del elemento.

tabla 11. Características de appendTo()

Esta función añade otro elemento al final del elemento seleccionado como un “hijo” de este. append(content) pertenece a la clase de “Manipulation” de la API JQuery.

parámetro tipo descripción

selector String, Element, JQuery

Contenido para añadir al final de un elemento específicado

tabla 12. Características de append()

Esta función añade contenido al final de un elemento especificado para cada elemento seleccionado. html(val) pertenece a la clase de “Manipulation” de la API JQuery.

parámetro tipo descripción

val String Declara el contenido html a un valor especificado

tabla 13. Características de html() Configura el contenido HTML para cada elemento seleccionado. Además de las funciones JQuery descritas anteriormente, hay una que se utiliza en el código JavaScript de visualdoc.php para añadir interactividad en el caso que ocurra un evento click. Para esto usamos la función descrita a continuación: bind(type, [data], fn) pertenece clase de “Events” de la API JQuery.

parámetro tipo descripción

type String Uno o más tipos de eventos separados por un espacio

data Object Datos adicionales pasados al manejador de eventos como event.data

Page 67: Integrando AJAX & PHP

67

parámetro tipo descripción

fn Function Una función para ser “atada” (bind) al evento de cada uno de los elementos seleccionados pasados como un objeto de evento

tabla 14. Características de bind()

Esta función “ata”(bind) un “manejador (handler) a uno o más eventos para cada elemento correspondiente, también puede atar eventos propios. Los posibles valores de eventos son: blur, focus, load, resize, scroll, unload, beforeunload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error. La función descrita anteriormente es usada para que al efectuarse un evento “onclick” en cualquiera de un elemento <input> se efectúe una función que permitirá realizar un cambio de visualización en la fila a la que corresponde el elemento <input> descrito anterior. A continuación el código que realiza esto: $("input.col"+i+3).bind("click", function(){ if ($("tr.row"+i).is(".clicked")){ $("tr.row"+i).removeClass("clicked"); }else{ $("tr.row"+i).addClass("clicked"); } }); En el caso anterior, se especifica el elemento que será atado la función cuando se realice el evento “click”. El mecanismo de la función es realizar un cambio en el estilo de la fila, añadiendo una clase o quitándola según sea el caso, este estilo se encuentra especificado en el documento visualdoc.php en la especificación de estilo CSS. El código de la clase es el que se muestra a continuación: .clicked{background-color: #81effe;color:#1e2e3e;}

Entonces cuando el usuario de click en cualquiera <input> tipo “checkbox” automáticamente el contenido HTML de esa fila de la tabla cambiará de color de fondo y de color de texto. Veamos la visualización de esto en el navegador del usuario:

Page 68: Integrando AJAX & PHP

68

fig. 15 vista de visualdoc en el navegador del usuario

En la figura anterior se observa el panel de la aplicación, este se encuentra dividido en 2 secciones, la primera tiene la función de subir documentos nuevos al directorio “uploads” del servidor, la segunda sección tiene la función de visualizar los archivos del directorio, además de añadir más interactividad permitiendo al usuario eliminar uno o varios archivos seleccionados a la vez y descargar cualquiera de ellos. También podemos ver que cuando se selecciona un documento por medio del <input> tipo “checkbox”, es modificado el estilo de esa fila. Para subir un documento al directorio especificado, utilizamos el código JavaScript ajaxupload.js, programa desarrollado por Andris Valums liberado bajo licencia tipo MIT. Para más información visitar: http://valums.com/ajax-upload/ . La manera general de configuración para ajax upload es el siguiente: new AjaxUpload('#upload_button_id', { action: 'upload.php', //programa en el lado del servidor que gestionará el upload name: 'userfile', //nombre del arcvhivo a subir //Datos adicionales para mandar data: { example_key1 : 'example_value', example_key2 : 'example_value2' }, // Realizar un “submit” automático después de la selección autoSubmit: true, // el tipo de dato que se espera del servidor. // HTML (text) y XML son detectados automáticamente. responseType: false, // Ejecutado una vez que el archivo haya sido seleccionado // Bastante útil cuando se encuentra deshabilitado autoSubmit // Es posible regresar false para cancelar el upload onChange: function(file, extension){}, // Ejecutado antes de que el archivo sea subido al servidor // Se puede regresar false para cancelar upload onSubmit: function(file, extension) {},

Page 69: Integrando AJAX & PHP

69

// Ejecutado cuando el upload haya sido completado // Advertencia! no usar false valor de regreso onComplete: function(file, response) {} }); La configuración de ajax upload utilizado en visualdoc.php es la siguiente: new AjaxUpload('#button3', { action: 'functions.php?mod=upload', name: 'userfile', onComplete : function(file){ $('<li></li>').appendTo($('#file-upload .files')).text(file); $("#file-list").html(""); showDocs(); } }); Donde #button3 es el elemento DOM tipo input utilizado para que el usuario seleccione el archivo a subir, functions.php?mod=upload es la URL que especifica el código en la parte del servidor que realizará el manejo del documento a subir pasado por ajax upload con nombre de userfile.

functions.php <?php $mod = $_GET['mod']; $directory = "uploads"; switch($mod){ case "delete": foreach ( $_POST as $key => $value ) { $path = $directory."/".$value; if(unlink($path)){ $string_log .= "Archivo: ".$value."eliminado"."\n"; }else{ $string_log .= "Archivo:".$value."no eliminado"."\n";} } echo $string_log; break; case "upload": $uploaddir = 'uploads/'; $uploadfile = $uploaddir . basename($_FILES['userfile']['name']); if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) { echo "success"; } else { echo "error"; } break; default: break; } ?>

El código anterior nos muestra la declaración switch con dos casos, el primero para eliminar un archivo y el segundo para subir uno. Este último lo que realiza simplemente es

Page 70: Integrando AJAX & PHP

70

que a partir de un directorio especificado con la variable $uploaddir, se copia el archivo hacia el directorio especificado por medio de la función move_uploaded_file(). Esta función se encuentra en versiones de PHP >= 4.0.3. Antes de que el archivo sea copiado, es posible realizar un análisis para realizar un filtrado con fines de seguridad, esto con ayuda de la variable global $_FILES o $HTTP_POST_FILES, esta variable es un arreglo de caracteres que contienen información a cerca del archivo subido. Es posible realizar restricciones por tipo de archivo y por tamaño: • Tipo de archivo. Usando la variable $_FILES['userfile']['type'] • Tamaño de archivo. Usando la variable $_FILES['userfile']['size'] el cual nos proporciona información a cerca del tamaño del archivo en bytes

fig. 16 visualización al subir dos archivos al servidor

En la figura anterior se nos muestra como en el momento de que el usuario suba un archivo, se efectuarán dos acciones automáticamente en visualdoc, la primera es visualizar los últimos archivos subidos por el usuario y la segunda es actualizar el listado de archivos en la parte inferior para que los nuevos archivos subidos exitosamente sean listados. El listado de documentos tiene dos funciones, la primera es eliminar uno o más documentos seleccionados de la lista a través del botón “eliminar” que se encuentra en la

Page 71: Integrando AJAX & PHP

71

parte superior del listado, la segunda es descargar el documento de manera individual por medio del botón “descargar” correspondiente a cada archivo. Para poder efectuar la eliminación de los archivos de manera automática y utilizando AJAX se utiliza la siguiente función JavaScript: $("#eliminar").click(function(){ $.post("functions.php?mod=delete", $("#form-list").serialize(), function(data){ alert(data); $("#file-list").html(""); showDocs(); }, "text" ); }); La función anterior realiza la magia de eliminar un archivo, esta función se dispara con el evento “click”, lo que ocurre es que se realiza una petición XMLHttpRequest por medio de la función $.post() hacia functions.php?mod=delete. Después de obtener la información por parte del servidor esta se muestra al usuario por medio de una alerta y la información del listado es actualizado automáticamente mandando a llamar a showDocs(), función que ya ha sido explicada anteriormente. La manera de como mandar los datos de los archivos seleccionados del formulario para ser eliminados se realiza con la ayuda de la función serialize(). La función serialize(), es una función AJAX de JQuery. Esta función serializa un conjunto de elementos tipo input en una cadena de datos. Esta cadena de datos, es la que se envía por método post a functions.php, que se encuentra en la parte del servidor. Donde es allí donde se obtienen los datos de los archivos a eliminar y se procede a realizar esta acción. En realidad los archivos no son eliminados del servidor, si no que son “desligados” por medio de la función PHP unlink(). A continuación el código que realiza esto: foreach ( $_POST as $key => $value ) { $path = $directory."/".$value; if(unlink($path)){ $string_log .= "Archivo: ".$value."eliminado"."\n"; }else{ $string_log .= "Archivo:".$value."no eliminado"."\n";} } echo $string_log;

En el código anterior se muestra entonces como son manejados los valores recibidos por el método POST para que sean “eliminados” los archivos seleccionados previamente, además de que en la cadena $string_log se es almacenada información a cerca de si el archivo fue eliminado o no. Para que el botón eliminar tenga un efecto diferente de visualización cuando se posicione el cursor del mouse en este es necesario integrar la función JavaScript hover() dentro de $(document).ready, como se muestra a continuación.

Page 72: Integrando AJAX & PHP

72

El modo de uso de la función JQuery hover es la siguiente: hover(over, out) pertenece a la clase de “Events” de la API JQuery.

parámetro tipo descripción

over function Función que se ejecuta cuando el cursor del mouse se encuentra sobre el elemento indicado

out function Función que se ejecuta cuando el cursor del mouse es movido hacia afuera del elemento indicado

tabla 15. Características de hover()

Simula el movimiento tipo hover (mover el cursor del mouse dentro y fuera de un objeto). En nuestro código es usado esta función de la siguiente manera: $("#eliminar,#row").hover(function(){ $(this).addClass("ui-state-hover"); }, function(){ $(this).removeClass("ui-state-hover"); }); Esta función entonces nos permite que el objeto con id #eliminar, tenga efecto hover de acuerdo al estilo definido por la clase CSS ui-state-hover. Esta clase es parte del framework CSS de JQuery UI. De igual manera para que este elemento tenga la visualización de un botón es necesario añadir las clases: ui-state-default, ui-corner-all, fg-button de la siguiente manera:

<div id="eliminar" name="eliminar" class="ui-state-default ui-corner-all fg-button" style="width:70px;text-align:center;">eliminar</div>

Hay que recordar, que para utilizar estas clases es necesario integrar el documento de estilo de JQuery UI, de la siguiente manera:

<link type="text/css" href="scripts/jquery-ui/css/ui-lightness/jquery-ui-1.7.2.custom.css" rel="Stylesheet" />

Page 73: Integrando AJAX & PHP

73

Herramientas para desarrollo de software y depuración de errores

Ahora que hemos aprendido como usar las librerías AJAX e integrar estas con aplicaciones que interactuen con el servidor a través de código PHP es útil aprender algunas técnicas importantes para el desarrollo de aplicaciones AJAX en ambientes de producción. En este capitulo se observarán herramientas que tienen como objetivo optimizar y depurar aplicaciones AJAX, no revisaremos herramientas de depuración para código PHP puesto que nos saldríamos de nuestro objetivo. En cuanto a las herramientas para depuración de errores, algunas podrán usarse para probar otros tipos de aplicaciones web, sin embargo estaremos concentrados en probar aplicaciones AJAX solamente. Las herramientas que serán aquí mencionadas son de Código Abierto.

Rhino Rhino es una de ellas, esta herramienta pertenece al grupo de proyectos de mozilla, dentro de la categoría de tecnologías. Rhino es una implementación de código abierto de JavaScript escrito enteramente en Java, se encuentra típicamente embebido en aplicaciones Java para proveer “scripts” a usuarios finales. La documentación completa de este proyecto puede ser vista en la página oficial: http://www.mozilla.org/rhino/

Page 74: Integrando AJAX & PHP

74

ShrinkSafe ShrinkSafe es una herramienta de compresión de cósido JavaScript basado en el programa Rhino bajo licencia MPL(Mozilla Public License). En los casos de producción que nos encontremos utilizando librerías AJAX para desarrollo, estas no se encuentran optimizadas en tamaño para su puesta en producción, pues contienen espacios en blanco, saltos de líneas, etc. Es por eso que se hace necesario la reducción de estas peculiaridades con la finalidad de reducir los tamaños de los archivos JavaScript y así tener una mejor velocidad de descarga para el usuario final. ShrinkSafe nos resuelve este dilema del tamaño, reduciendo el código lo mejor posible reduciendo el tiempo de descarga, esta herramienta viene junto con el paquete tipo build de la librería DojoToolkit. Aunque esta herramienta pertenece al proyecto DojoToolkit, sirve para comprimir cualquier código JavaScript, para estos casos es necesario descargar la herramienta desde: http://shirnksafe.dojotoolkit.org Esta herramienta no cambia variables públicas o APIʼs usadas en el código JavaScript, lo que permite integrar automáticamente el código comprimido por ShrinkSafe sin realizar algún otro cambio en el código del cual hace uso este último. La librería Dojotoolkit se encuentra en dos tipos de distribuciones con cada versión, la versión de lanzamiento y la versión de lanzamiento para desarrollo. La versión de lanzamiento para desarrollo además de contener las librerías que distribuye Dojo, como se describió anteriormente contiene una carpeta con nombre utils, la cual contiene herramientas para optimización de código, es allí donde se encuentra la herramienta ShrinkSafe. Antes de poder utilizar esta herramienta es necesario construir “Profiles”. Los profiles son documentos con formato JSON que describen en forma esquemática los códigos utilizados para nuestros scripts junto con la ruta completa de donde se encuentran. Dentro del directorio util/buildscripts/profiles, se encuentran ejemplos para como construir los “Profiles”, los cuales se encuentran listos para ser utilizados por la herramienta ShrinkSafe. Para ejemplificar el formato que un profile debe de tener, realizaremos un profile para el Caso 1, visto anteriormente, dentro del código JavaScript, tenemos las siguientes dependencias: dojo.require("dijit.form.Form"); dojo.require("dijit.form.Button"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.Dialog");

Page 75: Integrando AJAX & PHP

75

El Profile necesario para las dependencias anteriores sería: dependencies ={ layers: [ { copyrightFile : "nuestros_derechos.txt", name: "new-user.js", dependencies: [ "dijit.form.Form", "dijit.form.Button", "dijit.form.ValidationTextBox", "dijit.Dialog" ] } ], prefixes: [ [ "dijit", "../dijit" ], [ "some_dir", "../../some_dir", "nuestros_derechos.txt" ] ] }; Donde layers, es un arreglo que contiene las capas a utilizar de código JavaScript en nuestro programa. Dentro de cada item de layers, se encuentran los parámetros: copyrightFile el cual definira un documento de los derechos de autor que aparecerá al inicio del documento JavaScript minimizado resultante, name es el nombre de dicho documento que se generará y dependecies las dependencias que carga el documento general con dojo.require(). En el arreglo de prefixes se encuentran definido las rutas relativas a util/buildscripts o bien la ruta absoluta. Este Profile debe de estar situado dentro del directorio profiles. Una manera de generar entonces el documento JavaScript minimizado con la herramienta ShrinkSafe es la siguiente: bash build.sh profile=new-user action=release optimize=shrinksafe releaseName=new-user version=0.0.1 releaseDir=../../release/

Donde profile es el nombre del Profile que ha sido creado; action es la acción a realizar para la construcción, esta puede ser “clean” o “release”; optimize especifica la manera de como serán optimizados los módulos si “comments” se encuentra especificado, los comentarios son entonces eliminados, si “shrinksafe” se encuentra especificado, Dojo ShrinkSafe será usado en los archivos, si “shrinksafe.KeepLines” se encuentra

Page 76: Integrando AJAX & PHP

76

especificado se usará ShrinkSafe respetando los retornos de carro, si “packer” se encuentra especificado el empaquetado “Dean Edwards” será utilizado; releaseName es el nombre que tendrá documento generado; version es el número que se le imprimirá al documento resultante; releaseDir el directorio donde será puesto el código generado. Si no se especifica ningún directorio en releaseDir el programa creará un directorio con los archivos en la parte raíz del árbol relativo a la carpeta donde se encuentre Dojo. Una vez generado los archivos minimizados ahora hay que copiar la carpeta al directorio scripts del programa, también es necesario realizar algunos cambios para especificar donde se encuentra el nuevo código JavaScript, como se muestra a continuación:

<script type="text/javascript" src="scripts/release/dojo/dojo/new-user.js"></script> También será posible eliminar los dojo.require(), puesto que el código necesario en nuestro programa será invocado automáticamente por new-user.js en una versión minimizada. De igual manera es necesario cambiar la ruta del código CSS añadiendo la ruta al directorio “release”, por ejemplo: <style type="text/css"> @import "scripts/release/dojo/dojo/resources/dojo.css"; @import "scripts/release/dojo/dijit/themes/tundra/tundra.css"; </style> Con estas acciones ahora se contará con un programa con un código JavaScript optimizado permitiendo disminuir notablemente el tiempo de descarga de los archivos. Esto lo podremos comprobar con la herramienta firebug, que se mostrará a detalle en el próximo capítulo.

Page 77: Integrando AJAX & PHP

77

Depurando AJAX con Firebug Firebug es complemento para el navegador Firefox Mozilla, con esta herramienta es posible depurar, editar y monitorear código HTML, CSS y JavaScript en tiempo real a través del navegador. Este complemento puede descargarse en: https://addons.mozilla.org/es-ES/firefox/addon/1843 Para ejemplificar alguno de los usos que nos puede dar esta herramienta, observaremos el tiempo de descarga de los archivos para caso 1, con y sin optimización de ShrinkSafe.

fig. 16. Latencia de descarga para los archivos de “New Client”

En total el tiempo de descarga es de 2.18 segundos, sin embargo hay que tener en cuenta que este programa se encuentra en localhost, en ambientes de producción es necesario tener en cuenta otros factores comunes para internet. También es posible filtrar la información que es descargada al navegador en vez de observar toda a la vez, esto a través de los botones que se encuentran en el sub menú de red, los cuales nos permiten visualizar de manera individual información a cerca de: HTML, CSS, JS, XHR, imágenes o flash. Ahora veamos el tiempo de descarga que nos muestra Firebug con el programa optimizado con ShrinkSafe.

Page 78: Integrando AJAX & PHP

78

fig. 17. Latencia de descarga para los archivos de “New Client” optimizado

Con una optimización de un poco más del 300% la aplicación de “New Client” se encuentra lista para ser lanzada al internet y ser usada por usuarios con distintas velocidad de conexión sin problemas de descarga. Ahora observemos que nos muestra firebug, cuando presionamos en botón enviar, sin mandar

Page 79: Integrando AJAX & PHP

79

ningún dato: fig. 18. Analizando petición de “New Client” optimizado

En la figura anterior es posible observar la petición realizada por medio de XMLHttpRequest hacia insert-user.php con método POST, sin embargo, como no fue enviado ningún dato nos devuelve un cuadro de diálogo un aviso de que “Los campos con * son obligatorios”. Por medio de firebug, entonces vemos información de: encabezados, envío, respuesta y el código HTML además del número de pedidos realizados, método utilizado, respuesta del servidor (en el caso anterior fue: 200 ok) y el tiempo de respuesta.

fig. 19. analizando las propiedades del elemento input en el documento

También es posible analizar el código HTML seleccionando elementos del documento por medio del cursor, presionando el icono enseguida del logo de firebug en el menú, esto permite que cuando el cursor se sitúe sobre un elemento, un rectángulo con borde coloreado marque el elemento, una vez allí se puede ir visualizando cada uno de ellos en sus propiedades de: código CSS, DOM y maquetación.

Page 80: Integrando AJAX & PHP

80

Herramienta de desarrollo para Internet Explorer Internet Explorer cuenta con una herramienta que permite crear páginas web, analizar y detectar errores en páginas web su nombre es “Internet Explorer Developer Toolbar”. Esta herramienta puede ser descargada en la siguiente liga: http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&displaylang=en Algunas de las características que contiene esta herramienta són:

• Explorar y modificar DOM de una página • Localizar y especificar elementos específicos a través de diversas técnicas • Deshabilitar configuraciones del Internet Explorer • Observar características de los elementos como: “Id”, “class”,”name” • Validación de ligas HTML, CSS, RSS, WAI • Desplegar dimensiones de imagenes y sus rutas, así como la información

alternativa • Eliminar caché del navegador y cookies de manera selectiva • Encontrar estilo específico para determinados elementos

Es importante tener en cuenta la compatibilidad de nuestro documento con los diferentes navegadores, en especial con las versiones de IE que puede ser algo graboso. Para forzar a que un navegador emule una versón específica, existe una meta-etiqueta que se incluye en el encabezado del documento, como se muestra a continuación:

<html> <head> <!-- Mimic Internet Explorer 7 --> <title>My Web Page</title> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> </head> <body><p>Lorem Ipsum Dolor sit Amet</p> </body> </html>

Page 81: Integrando AJAX & PHP

81

Donde el valor d content puede ser modificado según la versión del navegador que deseemos emular, pudiendo este contener valores como: IE=5, IE=7,IE=8 o bien IE=edge para indicar al Windown Internet explorer que utilice su máxima versón disponible. Además de lo anterior, es posible que nos sea de utilidad el siguiente código JavaScript:

engine = null; if (window.navigator.appName == "Microsoft Internet Explorer") { if (document.documentMode) // IE8 engine = document.documentMode; else // IE 5-7 { engine = 5; if (document.compatMode) { if (document.compatMode == "CSS1Compat") engine = 7; } }

} El código anterior nos permite obtener por medio de la variable “engine” que versión del Windows Internet Explorer es el navegador que se encuentra cargando el documento. Fuente: http://msdn.microsoft.com/es-mx/library/cc817574.aspx

Page 82: Integrando AJAX & PHP

82

Análisis de seguridad en aplicaciones AJAX

Toda aplicaciones de software tiene riesgos de seguridad, sin embargo el análisis de seguridad debe de ser considerado como un proceso necesario, para el “Ciclo de vida de desarrollo del sistema” (SDLC), donde los desarolladores tienen la obligación de integrar este proceso en cada una de las etapas desde el inicio del desarrollo hasta el lanzamiento, además de realizar pruebas periódicas en la etapa de mantenimiento, lo cual reduciría notablemente el costo a la organización en el caso de que un usuario malintencionado use mal uso de estos “fallos de seguridad”. Los problemas Web tradicionales son las principales fuentes de vulnerabilidades que pueden ser aprovechadas para atacar aplicaciones AJAX. Por lo que el mantener una aplicación AJAX segura, no solamente implica la aplicación si no su entorno, es decir, en donde se encuentra situada tal aplicación. La enumeración de los recursos. Es un tipo de ataque básico, que sin la necesidad de conocer los fallos de seguridad de la aplicación un intruso podría usar información que el servidor permite visualizar o bien son archivos que se encuentran en el servidor que no se encuentra propiamente ligada pero que posee información como respaldos, código, datos no públicos etc. Manipulación de parámetros. Otro tipo de ataque, en donde el atacante maneja los parámetros enviados entre el navegador y la aplicación web en el servidor. AJAX se ejecuta en la parte del navegador, por lo que un manejo de parámetros entre este y el servidor permitiría al atacante realizar acciones que no son permitidas por la aplicación, lo que ocasionaría un riesgo de seguridad, si el manejo de datos en la parte del servidor no tomara en cuenta los posibles vectores de riesgo en la validación de datos, fuera de los datos esperados normalmente por el navegador. Cross Site-Scripting. Conocido comúnmente como XSS este tipo de ataque es realizado de las siguientes maneras:

• mandando ligas con código tipo “script” malicioso, el cual tendrá por objetivo apoderarse de información privada del usuario como cookies o sesiones.

• insertando código malicioso en formas de sitios que no filtran correctamente los metacaracteres.

Page 83: Integrando AJAX & PHP

83

Una de las recomendaciones para eliminar vulnerabilidades XSS en aplicaciones web, es el realizar un filtrado minucioso de los metacaracteres, a continuación una tabla que nos muestra los caracteres “peligrosos” y los caracteres con su correspondiente conversión recomendada.:

caracter caracter convertido

< &lt;

> &gt;

&#40; &#34;

&#41; &#39;

# &#35

& &#38

tabla 16. caracteres peligrosos

Existen otros tipos de ataques a aplicaciones ya conocidas como: Cross Site Request Forgery, Pishing, sin embargo estas vulnerabilidades no son factores dependientes propias de las aplicaciones web. Este capitulo no pretender ser un manual de referencia o framework de seguridad, pues nos saldríamos del margen de nuestro objetivo, para esto recomendamos al lector remitirse a los siguientes proyectos: OWASP. Proyecto abierto en seguridad de aplicaciones Web, es una comunidad a nivel mundial enfocada en mejorar la seguridad en aplicaciones de software. Para más información sobre el proyecto visitar: http://www.owasp.org/index.php/Main_Page

Page 84: Integrando AJAX & PHP

84

A continuación una lista de guías, descargables desde su sitio oficial, las cuales tienen como objetivo trabajar en conjunto par proveer la base de conocimiento en cuanto a seguridad de aplicaciones se refiere:

• OWASP Application Security Desk Reference. Contiene definiciones básicas y descripciones de todos los importantes principios, amenazas, ataques, vulnerabilidades, contramedidas, impactos técnicos, impacto de las organizaciones en la aplicación de seguridad.

• OWASP Developerʼs Guide. Esta guía cubre todos los controles de seguridad que los desarrolladores de software deberían de poner en practica. Son las protecciones positivas que los desarrolladores deben de tomar en cuenta en la construcción de aplicaciones.

• OWASP Testing Guide. Esta guía se encarga de mostrar todos los procedimientos y herramientas para el análisis de seguridad en las aplicaciones.

• OWASP Code Review Guide. Una guía muy de la mano con la guía anterior, se encarga de verificar aplicaciones donde el costo de realizar un análisis de seguridad no es tan conveniente como una revisión de código.

ISSAF. El Framework de evaluación para la Seguridad en los sistemas de información (Information Security Systems Assessment Framework) es un Framework estructurado, que categoriza la evaluación de la seguridad en los sistemas de información en varios dominios & detalles para cada evaluación o criterio específico para cada uno de estos dominios. Su propósito es proveer campos de entrada en cuanto a la evaluación de la seguridad que refleje escenarios de la vida real. ISSAF debería de ser usado para llenar los requerimientos que tienen las organizaciones en cuanto a la evaluación de seguridad además de ser usado como referencia en el conocimiento de otras necesidades en la seguridad de información. La objetivos de ISSAF son los siguientes:

• Actuar como una referencia para la evaluación de la seguridad • Estandarizar los procesos del Evaluación de la seguridad en los sistemas • Configurar un mínimo nivel de aceptación • Proveer una línea base en donde una evaluación pueda o debería de ser ejecutada • Salva guardar los sistemas desarrollados en contra de accesos no autorizados • Actuar como una referencia para la implementación de la seguridad de la información • Realizar un vínculo más estrecho entre los procesos de seguridad y la tecnología

Este framework puede ser descargado desde el sitio oficial de Open Information Systems Security Group: http://www.oissg.org/ Una clasificación en cuanto las amenazas de seguridad en una organización según su perímetro de operación, pueden ser:

• Sistema Operativo • Aplicación • Red • Físico

Page 85: Integrando AJAX & PHP

85

Las herramientas para el análisis que veremos en este capítulo se encuentran dirigidas a las amenazas de seguridad a nivel de aplicación. Pues son herramientas que nos permiten ver posibles fallos de seguridad o vulnerabilidad en código, además de examinar las posibles maneras en las que un usuario mal intencionado pudiera tomar ventaja, de acuerdo a los métodos de explotación ya conocidos. Además de la posibilidad de prevenir futuros intentos penetración y robo de información por medio de la aplicación.

Page 86: Integrando AJAX & PHP

86

Paros Proxy Esta herramienta es un programa escrito en Java, con licencia completamente gratuito, el cual sirve para evaluar aplicaciones Web. Una de las funcionalidad de Paros Proxy es interceptar y modificar todos los datos entre el cliente y el servidor a través de HTTP/HTTPS incluyendo cookies, campos y formas. Para poder instalar esta herramienta es necesario contar con Java Runtime Enviroment 1.4 o superior, posteriormente Paros Proxy puede ser descargado desde el sitio oficial: http://www.parosproxy.org/download.shtml Paros proxy contiene a su vez las siguientes herramientas:

• MIM Proxy • Spider • Scanner

Ahora vamos a ejemplificar uno de los usos que tiene esta herramienta con el programa del caso 5 desarrollado anteriormente. Es necesario configurar el proxy de nuestro navegador para usar como proxy a Paros Proxy, los parámetros de host y puerto por default son localhost y 8080 respectivamente. A continuación la manera de configurar esto con dos tipos de navegadores: Utilizando Firefox: En la pestaña “firefox” elegir “preferencias”, posteriormente en el icono de “Avanzado”, seleccionar el botón “configuración” en la sección de conexión. Allí se mostrarán las opciones de Firefox para la configuración de proxy. Si Paros Proxy se encuentra instalado en el mismo ordenador, elegir configuración manual de proxy, entonces se activará la entrada con la etiqueta Proxy HTTP y puerto, allí se insertarán los datos por default de Paros Proxy o bien los que se hayan configurado en el de manera individual. Utilizando Safari: En la pestaña de “Safari” elegir “preferencias”, seleccionar el icono de “Avanzado”, posteriormente se mostrará un menú del lado izquierdo donde se selecciona “Proxy Web” y del lado derecho se activaran las entradas para los datos correspondientes de “Servidor de proxy Web” y “puerto”. Allí se insertan los parámetros configurados para Paros Proxy. Si se requiere cambiar los parámetros de configuración de Paros Proxy por default, dentro del programa ir a la pestaña de “Tools” luego elegir en el sub menú la opción “options”, posteriormente se desplegará un cuadro de visualización donde en el panel izquierdo aparece una lista de opciones, elegir “Local Proxy”. Una vez seleccionado este, del lado derecho aparecerán las entradas para modificar opciones de host y puerto. También es posible realizar otras configuraciones como añadir autenticación al proxy, configuración del spider, scanner, etc.

Page 87: Integrando AJAX & PHP

87

fig. 20. Paros Proxy “escuchando” las conexiones entre el navegador y visualdoc.php Siguiendo con el mismo caso, ahora jugaremos con los “request” que realiza el navegador. Paros Proxy nos permite realizar esto por medio del botón “Trap”, una vez presionado este botón activaremos los cuadros de selección de “Trap request” y “Trap response”. Lo que haremos es que en el navegador seleccionaremos cualquier archivo y pulsar el botón eliminar para tratar de eliminar ese archivo seleccionado. Posteriormente el navegador querrá realizar la conexión y mandar ese request, sin embargo el proxy detendrá esta conexión y no procederá hasta que se presione el botón “Continue” que se encuentra a un lado de los cuadros de selección usados anteriormente. Es aquí donde el juego se pone interesante, pues podemos cambiar a nuestro antojo, los datos que serán enviados a functions.php para que sea tratado.

Page 88: Integrando AJAX & PHP

88

fig. 21. Modificando valores POST En la figura anterior se observa como editamos el dato con nombre file7 para ser enviado por método POST a functions.php, el valor original fue modificado por un *.

Page 89: Integrando AJAX & PHP

89

fig. 22. Respuesta del servidor, después de mandar el dato modificado Ahora observamos la respuesta que nos regresa functions.php, esta respuesta es un Warnning, el cual informa que no se encontró el archivo o directorio mencionado y por lo consiguiente ninguno fue eliminado. También nos esta mostrando información extra que nos permite imaginarnos como esta constituido el código fuente para esta petición, pues este Warnning nos insinúa que se uso la función unlink() de PHP. Esta misma información de aviso será desplegado en un “alert” al usuario en el navegador. Ahora veamos si es posible eliminar un archivo arriba del árbol del directorio uploads.

fig. 23. Tratando de eliminar functions.php

Es importante observar que el usuario puede el nombre de código PHP al cual son realizadas las peticiones al servidor, además de información sobre las rutas relativas, ya sea por medio de esta herramienta o por el firebug, como se vio anteriormente. Por lo que es de vital importancia tener políticas de seguridad para los permisos de ficheros y subdirectorios, donde no queramos que algún visitante no invitado este husmeando. Además de eliminar códigos fuentes que no sean parte del sistema o que hayan servido de pruebas, pues el usuario malicioso puede ser mal uso de ellos.

Page 90: Integrando AJAX & PHP

90

fig. 24. Respuesta del servidor, al tratar de eliminar functions.php Afortunadamente functions.php cuenta con los permisos necesarios y no fue “eliminado” por medio del comando unlink.

Sprajax Sprajax es un “escanner” de seguridad usado para auditar la seguridad de aplicaciones con AJAX habilitado bajo licencia GNU/LGPL, a su vez es parte de los proyectos de OWASP. Sprajax puede formular “request” de prueba para identificar vulnerabilidades potenciales en los “frameworks” detectados por este mismo. Esta herramienta solamente soporta los siguientes tipos de aplicaciones:

• Microsoft Atlas Web Applications • Fuzzing de Web Services basados en la descripción WSDL

Uno de los propósitos del proyecto Sprajax es tener soporte también para diferentes frameworks AJAX y para Google Web Toolkit (GWT). Esta herramienta puede ser descargada desde http://code.google.com/p/sprajax/

Page 91: Integrando AJAX & PHP

91

Por Hacer

Este pequeño libro, ha sido un experimento por mi parte de utilizar una temática diferente a lo que plantean los libros de programación comunes. Este proyecto va a enfocado en prácticas reales y su explicación detallada, donde el usuario podrá visualizar las generalidades a partir de las particularidades y tener un panorama más amplio de lo que puede hacer teniendo em sus manos el como. Esta primera versión es el nacimiento, pero es la pauta para la realización de proyectos más refinados, donde el lector también juega un papel importante en la retroalimentación. Todo el código de estos ejemplos puede obtenerse en el sitio: http://www.eliseoov.org/

Pueden contactarme a través de los siguientes correos: [email protected]

[email protected]