Vous êtes sur la page 1sur 91

INTEGRANDO

AJAX & PHP


PRIMERA EDICIÓN

ELISEO ORTIZ VALDEZ


CONTENIDO

Objetivo ..........................................................................................................................................................3

Introducción

Fundamentos de AJAX

Qué es AJAX ..................................................................................................................................................7

Tecnologías en AJAX.....................................................................................................................................9

La interfaz XMLHttpRequest.......................................................................................................................10
Construyendo el Objeto XMLHttpRequest ................................................................................................11
Características de la Interfaz XMLHttpRequest.........................................................................................11

Aplicaciones con AJAX ...............................................................................................................................14
Peticiones al Servidor ...............................................................................................................................15
XML & AJAX ...........................................................................................................................................19

AJAX Frameworks y Toolkits

DojoToolkit ..................................................................................................................................................24
Instalación ...............................................................................................................................................25

jQuery ...........................................................................................................................................................26
Instalación.....................................................................................................................................................27

Usando AJAX

Validación de Datos......................................................................................................................................29
Caso 1. Registro de usuarios......................................................................................................................30

Sugerencias automáticas...............................................................................................................................41
Caso 2. Auto-sugerencia...........................................................................................................................41
Caso 3. Sugerencia de búsqueda...............................................................................................................45

Interfaz 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 errores

Rhino ............................................................................................................................................................73

ShrinkSafe ....................................................................................................................................................74

Depurando AJAX con Firebug .....................................................................................................................77

Herramienta de desarrollo para Internet Explorer ........................................................................................80

Análisis de seguridad en aplicaciones AJAX

Paros Proxy...................................................................................................................................................86
Sprajax ..........................................................................................................................................................90

Por Hacer

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.
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
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.
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 Interactividad inmediata


cargada completamente

Modelo de comunicación síncrona Modelo de comunicación asíncrona. El cliente solo


“request/response” 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 Sensación del usuario de estar utilizando
proporcionadas dentro de los “tags” HTML 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.

6
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).

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

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

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

9
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/

10
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);

11
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 Descripción


Numérico
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

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

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

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

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

16
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

17
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


18
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')">

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

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

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

fig. 6. Visualización de las noticias RSS

22
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).

23
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
24
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>

25
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/

26
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"></s
cript>

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.
27
• 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>

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

29
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)

30
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>
31
<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 -->


32
<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
33
</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.

34
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

35
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

36
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

37
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

38
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";}

?>

39
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)

40
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`)

41
) 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>

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

var
dS_f1
=
new
dojo.data.ItemFileReadStore({url:
'data‐countries.json'});

var
filtSe_f1
=
new
dijit.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;
}
?>

43
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

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

45
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;}

46
#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');

47
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 ) :

48
$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.

49
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

50
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,
51
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
52
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.

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

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

55
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

o
bien
también
integrado
en
el
código
HTML
del
documento
como
se
muestra
a
continuació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


56
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

57
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;
}
?>

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

59
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;

60
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();
61
},
"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.

62
Las formas en como JSON se encuentra estructurado son:

• Objeto.
Un
conjunto
desordenado
de
pares
nombre/valor.
Un
objeto
comienza
con
una

{
(llave
de
apertura)
y
termina
con
}
(llave
de
cierre).
Cada
nombre
es
seguido
por
:
(dos
puntos)
y

los
pares
nombre/valor
están
separados
por
,
(coma).

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

(corchete
derecho).
Los
valores
se
separan
por
,
(coma).

• Value.
Un
valor
puede
ser
una
cadena
de
caracteres
con
comillas
dobles,
o
un
número,

o
true
o
false
o
null,

o
un
objeto
o
un
arreglo.
Estas
estructuras

pueden
anidarse.

• String.
Una
cadena
de
caracteres
es
una
colección
de
cero
o
más
caracteres
Unicode,

encerrados
 entre
 comillas
 dobles,
 usando
 barras
 divisoras
 como
 escape.
 Un
 carácter

esta
representado
por
una
cadena
de
caracteres
de
un
único
carácter.
Una
cadena
de

caracteres
es
parecida
a
una
cadena
de
caracteres
de
C
o
java.

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

formatos
octales
y
hexadecimales.


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;

}
?>

63






El
código
anterior
PHP
realiza
los
siguientes
procesos:

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

archivos
contenidos
en
el.

2. Cada
 archivo
 contenido
 en
 el
 directorio
 es
 analizado
 y
 se
 le
 añade
 parámetros

correspondientes
al
formato
JSON,
concatenados
en
la
variable
$string.

3. Una
 vez
 terminado
 el
 formato
 con
 cada
 archivo,
 se
 ejecuta
 una
 salida
 estándar
 con

echo
$string,
el
cual
contiene
un
documento
de
acuerdo
a
las
reglas
de
estructura
 de

datos
JSON,
similar
al
siguiente:


{"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);
64
$(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)
pertenece
a
la
clase
de
“Attributes”
de
la
API
JQuery.


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.
65
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, Contenido para añadir al final de un elemento


JQuery 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

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

67
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) {},
68
// 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

69
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
70
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.

71
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" />

72
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/

73
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");

74
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
75
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.

76
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.
77
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

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

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

80
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

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

82
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

83
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

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

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

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

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

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

89
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/

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


eliseo@ehecatl.com.mx
eliseo@eliseoov.org

91