<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tutoriales de Desarrollo y Diseño Web &#124; Web.Ontuts &#187; Tutoriales</title>
	<atom:link href="http://web.ontuts.com/category/tutoriales/feed/" rel="self" type="application/rss+xml" />
	<link>http://web.ontuts.com</link>
	<description>Tutoriales y Recursos Web de Calidad en Español</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:47:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Monográfico MVC: Introducción</title>
		<link>http://web.ontuts.com/tutoriales/monografico-mvc-introduccion/</link>
		<comments>http://web.ontuts.com/tutoriales/monografico-mvc-introduccion/#comments</comments>
		<pubDate>Mon, 27 Jun 2011 16:51:50 +0000</pubDate>
		<dc:creator>Roberto Luis Bisbé</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[ror]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=7345</guid>
		<description><![CDATA[La semana pasada me surgió la necesidad de hacer un sistema de gestión de eventos para el DotNetClub del que formo parte y, aprovechando que lo estábamos estudiando en la carrera, decidí emplear el patrón Modelo-Vista-Controlador (MVC) y crear esta serie de artículos.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/introduccion-a-object-relational-mapping-orm/' rel='bookmark' title='Permanent Link: Introducción a Object-Relational Mapping (ORM)'>Introducción a Object-Relational Mapping (ORM)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/grails-introduccion-a-desarrollo-web-java-para-dummies/' rel='bookmark' title='Permanent Link: Grails: Introducción a desarrollo web Java para &#8216;dummies&#8217;'>Grails: Introducción a desarrollo web Java para &#8216;dummies&#8217;</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>¿Por qué esta serie?</h3>
<p>La semana pasada me surgió la necesidad de hacer un sistema de gestión de eventos para el DotNetClub del que formo parte y, aprovechando que lo estábamos estudando en la carrera, decidí emplear el patrón Modelo-Vista-Controlador (MVC).</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/06/ror1.jpg" alt="Ror" /></center></p>
<p>El problema era que no me decidía si desarrollarlo en ASP.net o en Ruby on Rails, así que se me ha ocurrido hacer una pequeña implementación de la misma interfaz en los dos modelos para ver las diferencias, y ya que estaba, compartirlo con vosotros.</p>
<p>Como en un solo artículo es imposible dar siquiera una primera aproximación a cada una de las herramientas, lo hemos dividido en una serie, titulada <strong>Monográfico MVC</strong>.</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/06/asp.jpg" alt="ASP.net MVC" /></center></p>
<p>A lo largo de esta serie, veremos cómo partiendo de un diseño básico, podemos agregar la lógica MVC, y apreciar las diferencias entre dos tecnologías concretas, y muy diferentes:</p>
<ul>
<li><strong>Ruby on Rails</strong></li>
<li><strong>ASP.net MVC3</strong></li>
</ul>
<p>Comencemos pues la introducción al patrón MVC.</p>
<h3>Introducción: ¿Qué es MVC?</h3>
<p>De acuerdo con la definición de Wikipedia es:</p>
<blockquote><p>Patrón de arquitectura de software que separa los datos de una aplicación, la interfaz de usuario, y la lógica de control en tres componentes distintos.</p></blockquote>
<p>Esto significa que tendremos tres componentes principales en nuestra aplicación:</p>
<h4>Modelo</h4>
<p>El modelo lo podemos ver como la base de datos, o el sistema relacional que controla cómo se leen y se guardan los datos, así como cierta lógica de validación y relaciones entre ellos (Lo podemos llamar modelo relacional, si estamos trabajando con bases de datos)</p>
<h4>Vista</h4>
<p>La vista es lo que se muestra al usuario o a un servicio web, es decir, una vista puede ser una página HTML para que el usuario acceda a los datos, una interfaz en Silverlight, o incluso un fichero XML que se consuma desde un programa externo.</p>
<h4>Controlador</h4>
<p>El controlador es el enlace entre la vista y el modelo, se encarga de recibir los eventos desde la vista (por ejemplo un botón “Enviar” de un formulario o de un cuadro de login) y de exponer a la vista los datos desde el modelo.</p>
<p>Este modelo no es nuevo, sino que fue introducido en 1987 en el lenguaje de programación SmallTalk, si quereis echar un vistazo a la especificación original, la podeis encontrar aquí: <a href="http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html">http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html</a></p>
<p><a href="http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html"></a>Con el auge de las aplicaciones web, se ha demostrado ser un modo de programación que encaja bastante bien con internet, siendo tanto el modelo y el controlador ejecutados del lado del servidor, y la vista ejecutada del lado del cliente.</p>
<h3>Diseño inicial</h3>
<p>Para poder centrarnos en los diferentes sistemas y no centrarnos tanto en el diseño, partimos de un diseño HTML ya construido que contiene dos páginas:</p>
<ul>
<li><strong>Lista de eventos</strong></li>
<li><strong>Ventana de detalles</strong></li>
</ul>
<p>La lista de eventos contendrá la fecha, el título del evento, el ponente y una descripción.</p>
<p>La ventana de detalles contendrá, además, el edificio, el aula, y la hora, así como dos opciones para editar y/o borrar el evento.</p>
<p>Visto este diseño podemos extraer el conjunto de datos necesario, y su tipo:</p>
<ul>
<li>Id: <strong>Integer</strong></li>
<li>Titulo: <strong>String</strong></li>
<li>Fecha: <strong>Date</strong></li>
<li>Edificio:<strong> String</strong></li>
<li>Ponente: <strong>String</strong></li>
<li>Descripcion: <strong>String</strong></li>
</ul>
<p>A partir de este diseño, y usando técnicas de scaffolding, comprobaremos lo sencillo que puede ser empezar a trabajar.</p>
<p>En la próxima entrega veremos cómo agregamos lógica a esta web usando el primero de los jugadores: <em><strong>Ruby on Rails</strong></em>.</p>
<p>¡Nos vemos en la próxima publicación!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/introduccion-a-object-relational-mapping-orm/' rel='bookmark' title='Permanent Link: Introducción a Object-Relational Mapping (ORM)'>Introducción a Object-Relational Mapping (ORM)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/grails-introduccion-a-desarrollo-web-java-para-dummies/' rel='bookmark' title='Permanent Link: Grails: Introducción a desarrollo web Java para &#8216;dummies&#8217;'>Grails: Introducción a desarrollo web Java para &#8216;dummies&#8217;</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/monografico-mvc-introduccion/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Marcas de agua en imágenes usando PHP (I)</title>
		<link>http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/</link>
		<comments>http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/#comments</comments>
		<pubDate>Tue, 10 May 2011 16:26:02 +0000</pubDate>
		<dc:creator>Gonzalo Ayuso</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=7156</guid>
		<description><![CDATA[En este tutorial aprenderemos a crear marcas de agua en nuestras imágenes utilizando PHP y mod_rewrite. Como siempre paso a paso, bien explicado y con imágenes del resultado final. ¡No os lo perdáis!


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/aprendiendo-a-utilizar-la-libreria-curl-en-php/' rel='bookmark' title='Permanent Link: Aprendiendo a utilizar la librería cURL en PHP'>Aprendiendo a utilizar la librería cURL en PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Imaginando una biblioteca de imágenes&#8230; ¡Demasiado trabajo!</h3>
<p>Imaginemos que tenemos un biblioteca de imágenes y que queremos añadirles una marca de agua a todas ellas. Podemos abrir un editor de imágenes (Gimp o Photoshop, por ejemplo) y crear nuestra marca de agua manualmente a todas ellas.</p>
<p>Es un <strong>trabajo sencillo</strong> pero si nuestra biblioteca de imágenes es <strong>muy grande el trabajo</strong> se convierte en algo más duro. Podemos <strong>automatizar</strong> esta tarea, pero si las marcas de agua que queremos poner son dinámicas, tenemos que buscar otra solución. Como ejemplo imaginemos que lo que queremos poner es la fecha/hora en la que el usuario solicita la imagen al servidor. Para hacer esto vamos a usar la librería GD y PHP. Empecemos:</p>
<blockquote><p>Gracias a la librería GD podemos añadir de manera sencilla marcas de agua a nuestras imágenes. Esto Unido a mod_rewrite nos permite hacer el trabajo al vuelo.</p></blockquote>
<h3>¡Automaticemos el trabajo!</h3>
<p>La idea es simple. En lugar de abrir directamente la imagen, lo que vamos a hacer es crear un script PHP que modifique la imagen original con la función <a href="http://www.php.net/manual/en/function.imagecreatefromjpeg.php">imagecreatefromjpeg</a> y le añada un footer con la fecha/hora . Después le entregaremos al navegador la imagen modificada con las cabeceras necesarias.</p>
<p>Esta solución nos implica modificar todas nuestras etiquetas img y pasar de algo así:</p>
<pre name="code" class="html">
&lt;img src=&#039;/ruta/de/la/imagen.jpg&#039; alt=&#039;img&#039; /&gt;
</pre>
<p>A algo así:</p>
<pre name="code" class="html">
&lt;img src=&#039;/ruta/del/script.php&#039; alt=&#039;img&#039; /&gt;
</pre>
<p>Para evitar esto vamos a usar un pequeño truco que consiste en usar el módulo mod_rewrite de apache (los demás servidores Web tienen módulos similares). Creando este simple archivo .htaccess en la carpeta donde tengamos nuestras imágenes jpg, podemos redirigir cada petición de la imagen original a nuestro script PHP que la modifica y le añade la marca de agua.</p>
<pre name="code" class="php">
RewriteEngine on
RewriteRule !\.(php)$ watermark.php
</pre>
<p>Ahora creamos nuestro script watermark.php para hacer la modificación.</p>
<pre name="code" class="php">
&lt;?php
$uri = $_SERVER[&#039;REQUEST_URI&#039;];
$documentRoot = $_SERVER[&#039;DOCUMENT_ROOT&#039;];
$filename = $documentRoot . $uri;
if (realpath(__FILE__) == realpath($filename)) {
    exit();
}
$stringSize = 3;
$footerSize = ($stringSize==1) ? 12 : 15;
$footer = date(&#039;d/m/Y H:i:s&#039;);

list($width, $height, $image_type) = getimagesize($filename);
$im = imagecreatefromjpeg($filename);
imagefilledrectangle (
        $im,
        0,
        $height,
        $width,
        $height - $footerSize, imagecolorallocate($im, 49, 49, 156));

imagestring($im,
        $stringSize,
        $width-(imagefontwidth($stringSize)*strlen($footer)) - 2,
        $height-$footerSize,
        $footer,
        imagecolorallocate($im, 255, 255, 255));

header( &#039;Content-Type: image/jpeg&#039; );
imagejpeg($im);
</pre>
<p>Como vemos el script es muy sencillo. Podemos modificarlo y cambiarlo por nuestro logotipo, o introducir nuevos valores. Para que esto funcione tenemos que tener nuestra instalación de PHP compilada con soporte <a href="http://www.php.net/manual/en/image.installation.php">GD</a>.</p>
<p>Imagen Original:<br />
<center><img src="http://gonzalo123.files.wordpress.com/2011/02/original.jpg?w=300" alt="" /></center></p>
<p>Imagen transformada:<br />
<center><img src="http://gonzalo123.files.wordpress.com/2011/02/after.png?w=300" alt="" width="300" height="225" /></center></p>
<h3>Una pequeña reflexión final</h3>
<p>Y eso es todo. ¿Qué pega tiene esta técnica? Pues que estamos usando unos <strong>recursos del servidor elevados</strong>. Estamos transformando la imagen cada vez que la solicitamos. Si el volumen de peticiones es pequeño no hay problema, pero si crece podemos tirar el servidor.</p>
<p>Una solución sencilla es <strong>cachear la imagen resultante</strong>. De este modo liberamos al servidor, pero ¿que pasa si la marca de agua es dinámica?. En el siguiente artículo de esta mini serie veremos una posible solución al problema.</p>
<p>¡Nos vemos en el próximo capítulo!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/aprendiendo-a-utilizar-la-libreria-curl-en-php/' rel='bookmark' title='Permanent Link: Aprendiendo a utilizar la librería cURL en PHP'>Aprendiendo a utilizar la librería cURL en PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Creando servicios de red TCP con PHP y xinetd</title>
		<link>http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/</link>
		<comments>http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/#comments</comments>
		<pubDate>Thu, 17 Mar 2011 13:15:21 +0000</pubDate>
		<dc:creator>Gonzalo Ayuso</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[tcp]]></category>
		<category><![CDATA[xinetd]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=7053</guid>
		<description><![CDATA[Presentamos un nuevo y sencillo tutorial para crear servicios de red en Linux, usando PHP y el daemon xinet.d. Como siempre explicaciones paso a paso y fáciles de seguir.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/' rel='bookmark' title='Permanent Link: Marcas de agua en imágenes usando PHP (I)'>Marcas de agua en imágenes usando PHP (I)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/mini-aplicaciones-web-con-python-y-juno-parte-ii/' rel='bookmark' title='Permanent Link: Mini Aplicaciones Web con Python y Juno: Parte II'>Mini Aplicaciones Web con Python y Juno: Parte II</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción</h3>
<p>No todo en PHP es Web y HTTP. Podemos usar PHP para muchas otras cosas. Por ejemplo podemos crear de una forma muy sencilla servicios de red. Cuando creamos servicios de red necesitamos obviamente un <strong>servidor de red</strong> (bien sea TCP o UDP).</p>
<p>Cuando trabajamos con Web y HTTP este servidor suele ser Apache (o similares), pero si queremos crear un servicio específico (no HTTP), además del servicio de red que queramos crear, necesitaríamos <strong>crear un servidor</strong>.</p>
<blockquote><p>No todo en PHP es Web y HTTP. Podemos usar PHP para muchas otras cosas. Por ejemplo podemos crear de una forma muy sencilla servicios de red.</p></blockquote>
<p>Esto lo podemos hacer con C, Java e incluso con PHP, pero cuando trabajamos en entornos Linux existe un daemon que nos permite <strong>desplegar servicios de red</strong> de una forma muy sencilla, encargándose de la parte del servidor y dejándonos a nosotros la parte del servicio de red. Este daemon es <a href="http://www.xinetd.org/">xinetd</a>.</p>
<p>Vamos a ver cómo crear un sencillo servicio de red TCP con xinetd y PHP&#8230; ¡Empecemos!</p>
<h3>Creando el servicio de red TCP con Xinetd y PHP</h3>
<p>El ejemplo que vamos a realizar escuchará del puerto 69321, e inicialmente dirá &#8220;Hola&#8221; cuando alguien realice una petición TCP a dicho puerto. El script del ejemplo es sumamente complicado:</p>
<pre name="code" class="php">
// /home/gonzalo/tests/test1.php
echo "HELLO\n";
</pre>
<p>Bien. Ahora lo que queremos es que nuestro servicio de red escuche el puerto tcp 60321. Para esto tenemos que definir en nuestro archivo /etc/services el puerto en cuestión:</p>
<pre name="code" class="c">
// /etc/services
...
myService   60321/tcp # my hello service
</pre>
<p>Y finalmente creamos la configuración en el daemon xinetd. Para ello creamos el archivo /etc/xinetd.d/myService:</p>
<pre name="code" class="c">
# default: on
# description: my test service

service myService
{
        socket_type = stream
        protocol = tcp
        wait = no
        user = gonzalo
        server = /usr/local/bin/php-cli
        server_args = /home/gonzalo/tests/test1.php
        log_on_success += DURATION
        nice = 10
        disable = no
}
</pre>
<p>Reiniciamos el daemon para que lea la nueva configuración del servicio que hemos creado:</p>
<pre name="code" class="c">
sudo /etc/init.d/xinetd restart
</pre>
<p>Y listo. Ya tenemos nuestro servicio de red operativo y funcionando. Para probarlo podemos usar un simple telnet al puerto definido:</p>
<pre name="code" class="c">
telnet localhost 60321
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hola
Connection closed by foreign host.
</pre>
<p>¿Fácil, no? Sí pero útil, no mucho. Por esto vamos a cambiar un poco es script para que acepte variables de entrada. Esto no es HTTP por lo que no podemos usar las típicas variables $_POST y $_GET.</p>
<p>Lo que tenemos que hacer es leer del stdin. En PHP, al igual que con otros lenguajes, esto es muy sencillo:</p>
<pre name="code" class="php">
$handle = fopen('php://stdin','r');
$input = fgets($handle);
fclose($handle);

echo "Hola {$input}";
</pre>
<p>Reiniciamos el xinetd y tenemos nuestro servicio listo</p>
<pre name="code" class="c">
telnet localhost 60321
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
</pre>
<p>Vemos que el telnet se nos quedará a la espera que introduzcamos un texto. Escribimos: &#8220;<em>gonzalo</em>&#8221; y obtenemos:</p>
<pre name="code" class="c">
gonzalo
Hola gonzalo
Connection closed by foreign host.
</pre>
<h3>Conclusión</h3>
<p>Y esto es todo. Con este sencillo script vemos que, si bien PHP es un lenguaje destinado principalmente para el desarrollo Web, podemos usarlo para otras cosas, manteniendo su punto fuerte: la sencillez.</p>
<p>¿Para qué nos puede servir esto? Bueno. Para empezar nos sirve para <strong>leer datos de dispositivos de red</strong> que tengamos por ahi, como báculas, lectores de tarjetas, sensores&#8230; Muchos de estos dispositivos suelen permitirnos en su configuración establecer una IP/puerto a la que van a enviar información en forma de trama TCP.</p>
<p>También podemos usarlo para <strong>comunicar procesos de una manera simple</strong>, sin necesidad de meternos con servidores XMLRPC/Soap y demás. En fin que es una herramienta más que tenemos a nuestra disposición para afrontar nuestros desarrollos.</p>
<p>¡Nos vemos en el próximo artículo!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/' rel='bookmark' title='Permanent Link: Marcas de agua en imágenes usando PHP (I)'>Marcas de agua en imágenes usando PHP (I)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/mini-aplicaciones-web-con-python-y-juno-parte-ii/' rel='bookmark' title='Permanent Link: Mini Aplicaciones Web con Python y Juno: Parte II'>Mini Aplicaciones Web con Python y Juno: Parte II</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Apuntes sobre Seguridad Web</title>
		<link>http://web.ontuts.com/tutoriales/apuntes-sobre-seguridad-web/</link>
		<comments>http://web.ontuts.com/tutoriales/apuntes-sobre-seguridad-web/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 19:31:13 +0000</pubDate>
		<dc:creator>Iván Guardado</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[seguridad]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=7060</guid>
		<description><![CDATA[Que las aplicaciones web que desarrollas funcionen y sean escalables es importante, pero mucho más lo es que sean seguras de forma que no se vea comprometida la seguridad y privacidad de tus usuarios. En este artículo damos un repaso a los ataques más comunes y cómo defenderte de ellos.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/sesiones-en-php/' rel='bookmark' title='Permanent Link: Sesiones en PHP'>Sesiones en PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción</h3>
<p>Antes de ponerme a comentar los distintos tipos de vulnerabilidades conocidos y explotados de las aplicaciones web, quiero compartir el siguiente informe: <a href="http://www.verizonbusiness.com/go/2010databreachreport/">Informe de Investigación de Datos Violados 2010</a> (el informe se genera en 2010, por lo que analiza el año 2009) creado por <a href="http://www.verizonbusiness.com/">Verizon</a> en colaboración con el <a href="http://www.secretservice.gov/">USSS</a> (United States Secret Service).</p>
<p>Es un informe muy completo que analiza en profundidad <strong>los distintos tipos de ataques</strong> llevados a cabo con el objetivo final de robar información, bien sea a corporaciones o particulares. Os dejo un par de datos que me han parecido relevantes:</p>
<ul>
<li>40% de los robos fueron por hacking.</li>
<li>98% de los datos robados, procedían de servidores.</li>
<li>85% de los ataques fueron considerados fáciles.</li>
<li>96% de los robos serían evitables con medidas simples o intermedias.</li>
</ul>
<p>Solamente con ver estes datos, uno tiene razones más que suficientes para ponerse al día en el tema de seguridad web, y eso es lo que intentaré hacer en este artículo. A continuación le echamos un vistazo a los <strong>tipos de ataques más comunes</strong> para que por lo menos sepas que existen y los analices más profundamente si lo consideras necesario. Pero antes, os dejo unas cuantas gráficas extraídas del informe:</p>
<p><strong>Categorías de ataques por porcentaje de robos y registros</strong><br />
<a href="http://web.ontuts.com/wp-content/uploads/2011/03/img_1.png"><img src="http://web.ontuts.com/wp-content/uploads/2011/03/img_1.png" alt="" title="img_1" width="600" height="246" class="alignnone size-full wp-image-7105" /></a></p>
<p><strong>Tipos de hacking por porcentaje de robos y registros</strong><br />
<a href="http://web.ontuts.com/wp-content/uploads/2011/03/img_2.png"><img src="http://web.ontuts.com/wp-content/uploads/2011/03/img_2.png" alt="" title="img_2" width="600" height="620" class="alignnone size-full wp-image-7107" /></a></p>
<p><strong>Vías de ataque por porcentaje de robos y porcentaje de filas</strong><br />
<a href="http://web.ontuts.com/wp-content/uploads/2011/03/img_3.png"><img src="http://web.ontuts.com/wp-content/uploads/2011/03/img_3.png" alt="" title="img_3" width="600" height="272" class="alignnone size-full wp-image-7106" /></a></p>
<h3>Cross-Site Scripting (XSS)</h3>
<p>Es un tipo de vulnerabilidad web que permite a personas malintencionadas <strong>insertar código de lado de cliente</strong> (Javascript, VBScript, Flash&#8230;) en las páginas web accesibles por el resto de usuarios. Debido a esto, un atacante podría conseguir acceso a contenido sensible, cookies de sesión y demás información que el navegador almacene sobre el usuario atacado.</p>
<p>Un posible uso de esta vulnerabilidad, sería ejecutar un código Javascript que obtenga la cookie que almacena el identificador de sesión (SID) y lo envía al atacante, pudiendo así usar esa cookie para <strong>suplantar al usuario afectado</strong>.</p>
<p>Hay una pequeña categorización de este tipo de ataques, que los divide en dos:</p>
<blockquote><p>A través de XSS una persona malintencionada puede insertar código en una web, de forma que cualquier usuario que entre, estará expuesto a sus peligros.</p></blockquote>
<h4>No persistente</h4>
<p>Este es el tipo más común y se produce cuando un usuario envía datos al servidor, normalmente a través de la Query String (GET) o de un formulario (POST) e inmediatamente <strong>el código del servidor genera una respuesta usando esa misma información</strong> sin limpiar adecuadamente los datos.</p>
<p>Por ejemplo imagina que has programado un buscador para tu sitio web, que cuando no encuentra lo que acabas de buscar, genera una salida como “No se ha encontrado nada sobre gatos” en el caso que hayas buscado la palabra &#8220;gatos&#8221;. Bien, esto parece algo inofensivo pero&#8230;y si busco el siguiente texto?:</p>
<pre name="code" class="html">&lt;script&gt;alert(1)&lt;/script&gt;</pre>
<p>Pues que el servidor generará la siguiente salida:</p>
<pre name="code" class="html">No se ha encontrado nada sobre &lt;script&gt;alert(1)&lt;/script&gt;
</pre>
<p>De forma que el navegador, al encontrarse con la etiqueta &lt;script&gt;, <strong>ejecuta inmediatamente el código</strong>, en este caso, saltaría un inofensivo cuadro de diálogo.</p>
<p>A lo mejor ahora te estás preguntando, “<strong>¿pero cómo afecta esto a un usuario particular?</strong>”, “nadie que no sepa del tema, va a buscar eso y en cualquier caso, se está fastidiando a sí mismo”. Bien, imagina que tu buscador maneja las peticiones a través de parámetros GET de forma que si buscas “gatos”, accedes a la siguiente dirección:</p>
<pre name="code" class="html">http://example.com/search?q=gatos
</pre>
<p>Pues alguien malintencionado, puede generar la url:</p>
<pre name="code" class="html">http://example.com/search?q=&lt;script&gt;alert(1)&lt;/script&gt;
</pre>
<p>Simplemente tendría que enviar la URL a las personas que desea y listo.</p>
<h4>Persistente</h4>
<p>Este es un tipo <strong>más devastador</strong> ya que puede llegar a afectar a <strong>cualquier usuario que entre en tu web</strong>. Se trata de insertar y almacenar código malicioso en el servidor, de forma que se muestre a cualquier persona que acceda a dicha página. Esto es muy fácil de conseguir en las aplicaciones web que <strong>permiten a los usuarios generar contenido</strong>, como envíar comentarios, dar opinión en foros, etc&#8230;</p>
<p>Imagina que unos foros muy visitados no están limpiando bien los textos que los usuarios envían. Una persona que se haya dado cuenta, podría enviar un simple mensaje con:</p>
<pre  name="code" class="html">
&lt;script&gt;alert(1)&lt;/script&gt;
</pre>
<p>Ahora, cada persona que visite la página en la que has escrito, verá un inofensivo cuando de texto. Pero repito, podría ejecutar cualquier código, tan malicioso como uno quiera y la seguridad del navegador lo permita.</p>
<blockquote><p>La diferencia entre persistente y no persistente es que <strong>en los ataques persistentes</strong>, el código queda almacenada en el lado del servidor, mostrándose y ejecutándose en cada petición, <strong>mientras que los ataques no persistentes</strong>, inyectan el código de forma temporal como respuesta a una petición específica.</p></blockquote>
<h4>Cómo protegerse</h4>
<ul>
<li>Asegúrate de que <strong>todas las salidas generadas</strong> con textos 	potencialmente inseguros (enviados por usuarios) <strong>son completamente 	escapados</strong>. Para eso PHP nos ofrece algunas funciones como 	<a href="http://php.net/manual/en/function.htmlentities.php">htmlentities</a> o <a href="http://www.php.net/manual/en/function.htmlspecialchars.php">htmlspecialchars</a>, 	o como habíamos visto en un tutorial anterior, puedes <a href="../tutoriales/validar-y-sanear-datos-en-php/">Validar 	y sanear datos en PHP</a> de forma bastante sencilla.</li>
<li>Como ya he comentado, el principal objetivo de este tipo de 	ataques, es el <strong>robo de las cookies</strong>. Muchos sitios web, evitan que un 	atacante pueda suplantar cookies de otros usuarios <strong>vinculando la 	cookie a la dirección IP</strong> para la cual se había creado. De esta 	forma, alguien que intente usar una cookie desde otro ordenador, 	será considerado un usuario malicioso y se ignorará la cookie. 	Tambien existe la opción de <strong>especificar una cookie como HttpOnly</strong>, 	de forma que los navegadores no permiten acceder a dicha cookie al 	código ejecutado en el lado de cliente. Esta opción es soportada 	prácticamente por todos los navegadores modernos.</li>
</ul>
<h3>Cross-site request forgery (CSRF o XSRF)</h3>
<p>Esta vulnerabilidad <strong>explota la confianza que un sitio tiene un usuario</strong>, a diferencia del XSS, que explota la confianza que un usuario tiene en un sitio web. A grandes rasgos, consiste en que una persona malintencionada envía un link a una persona que sabe (o supone) que está identificada en una web, de forma que <strong>la persona ejecuta ciertos comandos sin enterarse</strong>.</p>
<p>Por ejemplo, imagina una web de un banco que dispone de la siguiente url para realizar una transacción:</p>
<pre  name="code" class="html">http://example.com/transaction?to=[ID USUARIO]&amp;amount=[CANTIDAD]
</pre>
<p>Sería realmente sencillo generar una url para que cualquier usuario identificado, te enviase dinero. Sería tan fácil como enviarle este link:</p>
<pre  name="code" class="html">http://example.com/transaction?to=ivan&amp;amount=1000
</pre>
<p>Ahora, imagina que en ese banco existen unos foros para que los usuarios registrados puedan opinar sobre distintos temas. <strong>Si no tienen los textos perfectamente saneados y escapados</strong>, una persona malintencionada podría insertar la siguiente etiqueta HTML:</p>
<pre name="code" class="html">&lt;img src=”http://example.com/transaction?to=ivan&amp;amount=1000” /&gt;
</pre>
<p>De esta forma, el navegador de cualquier usuario que entra en el foro, intentará descargar dicha imagen, pero en realidad, esa url no va a generar ninguna imagen, lo que va hacer <strong>es enviar una orden de transacción</strong> en caso de que el usuario esté identificado. Como ya he dicho, es un exceso de confianza del sitio web en las acciones del usuario.</p>
<h4>Cómo protegerse</h4>
<ul>
<li><strong>Requerir una clave secreta</strong> al usuario antes de llevar a cabo 	cualquier acción comprometida, como sería el caso del ejempl 	anterior.</li>
<li><strong>Limitar el tiempo de vida de la sesión</strong>: lo hacen en muchas 	webs de contenido sensible.</li>
<li><strong>Deshabilitar la opción de “Recordarme”</strong> ayuda a prevenir 	este tipo de ataques: si activas esa opción y luego te envían un 	exploit de CSRF, tienes muchas más posibilidades de que te afecte, 	pues el no estar logueado no te salva, ya que iniciarás la sesión 	automáticamente, ejecutando la acción que el exploit te envía.</li>
<li><strong>Comprobar la cabecera Referer</strong>: cualquier petición que no 	contenga esta cabecera debe ser denegada, debido a que existen 	formas sencillas de evitar el envío de esa cabecera. Además, esta 	validación podría tener problemas con navegadores o proxies que 	evitan el envío de esta cabecera por razones de privacidad. Sin 	embargo, si el sitio web requiere de máxima seguridad, es una 	opción más a tener en cuenta.</li>
<li><strong>Usar GET y POST debidamente</strong>: según los estandares, las 	peticiones GET nunca deben de tener efectos permanentes. Si bien los 	envíos POST tambien se pueden falsear, es una tarea más complicada 	en la que tienen que darse más vulnerabilidades.</li>
</ul>
<h3>SQL injection</h3>
<p>Es un tipo de ataque que <strong>explota la vulnerabilidad de la capa de base de datos</strong> de una aplicación. Se presenta cuando los <strong>filtros pasados a una sentencia SQL no son escapados correctamente</strong> y por lo tanto, un usuario malitencionado puede envíar caracteres con significado especial en SQL para <strong>modificar la consulta</strong>.</p>
<blockquote><p>En 2009, <strong>el 25% de los robos</strong> a través de hacking, fueron hechos usando SQL injection.</p></blockquote>
<p>Imagina la siguiente consulta SQL para comprobar que los datos de inicio de sesión que acaba de enviar un usuario son correctos:</p>
<pre name="code" class="php">
$query = “SELECT * FROM users WHERE login='{$username}' AND password='{$password}'”;
</pre>
<p>Si las variables son recibidas directamente del formulario enviado y <strong>no son escapadas</strong>, un usuario malintencionado podría hacer envíar lo siguiente:</p>
<ul>
<li><strong>Usuario:</strong> ivan</li>
<li><strong>Contraseña:</strong> &#8216; or &#8217;1&#8242;=&#8217;1</li>
</ul>
<p>Así, la query resultante sería:</p>
<pre name="code" class="sql">
SELECT * FROM users WHERE login='ivan' AND password=' ' or '1'='1' ;
</pre>
<p>Lo cual, hace que la condición siempre sea cierta y te puedas identificar como cualquier usuario.</p>
<p>La inyección SQL <strong>tiene muchas posibilidades</strong>, ya que una persona con experiencia podría poco a poco investigar la base de datos y llevar a cabo tareas como robar información valiosa, eliminar tablas importantes con el objetivo de hacer daño a tu sitio web, insertar contenido malicioso, dar permisos de administrador a su usuario&#8230;entre otras muchas, hay tantas posibilidades como ideas  maliciosas <img src='http://web.ontuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A continuación dejo un ejemplo para mostrar lo sencillo que es <strong>eliminar una tabla</strong> de un sitio web vulnerable a inyección SQl, para que te tomes siempre muy en serio este tipo de vulnerabilidad.</p>
<p>Siguiendo con el caso anterior, un usuario podría rellenar el formulario con lo siguiente:</p>
<ul>
<li><strong>Usuario:</strong> ivan</li>
<li><strong>Contraseña:</strong> &#8216;;DROP TABLE users; –</li>
</ul>
<p>Por lo que la consulta resultante sería:</p>
<pre name="code" class="sql">
SELECT * FROM users WHERE login='ivan' AND password=' ' ;DROP TABLE users; –';
</pre>
<p>Más vale que tuvieses bien configuradas las copias de seguridad <img src='http://web.ontuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h4>Como protegerse</h4>
<p>Una vez más, <strong>la solución es escapar los datos</strong> antes de incrustarlos en la consulta. En PHP disponemos de una función llamada <a href="http://php.net/manual/en/function.mysql-real-escape-string.php">mysql_real_escape_string</a> limpiará todos los caracteres que tienen significado especial para MySql y pueden modificar la consulta. Por lo tanto, la consulta de inicio de sesión que hemos visto, se corregiría ejecutándola de este modo:</p>
<pre  name="code" class="php">
$userName = mysql_real_escape_string($userName);
$password = mysql_real_escape_string($password);
$query = sprintf(“SELECT * FROM users WHERE login='%s' AND password='%s'”, $userName, $password);
</pre>
<p>También os podéis currar vuestro propio código para gestionar las consultas y que sea más cómodo. En un tutorial ya habíamos visto <a href="../tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/">Cómo crear una capa de conexión abstracta a la base de datos</a></p>
<h3>Session Fixation</h3>
<p>Este ataque se aprovecha de la vulnerabilidad de algunos sitios que <strong>permiten a un usuario fijar el identificador de sesión</strong> (SID) de otro usuario. La mejor forma entender esta vulnerabilidad es mediante un ejemplo (usados los nombres <a href="http://en.wikipedia.org/wiki/Alice_and_Bob">por convención</a>)</p>
<ul>
<li>Un usuario malintencionado llamado Mallory se percata de que 	en el sitio http://vulnerable.com <strong>existe la posibilidad de cambiar el SID</strong> de los usuarios.</li>
<li>Mallory, envía el siguiente link a Alice: 	http://vulnerable.com?SID=este_sera_tu_sid (con esto lo que hace es 	que cuando Alice entre en el sitio web, el servidor establecerá su 	SID con el valor “este_sera_tu_sid”, de forma, que <strong>Mallory sabe 	el SID de Alice</strong>).</li>
<li>Alice entra confiada en la web e inicia sesión.</li>
<li>Mallory, al conocer el SID de un usuario identificado en la 	web, <strong>puede suplantarlo</strong> simplemente accediendo a 	http://vulnerable.com?SID=este_sera_tu_sid</li>
</ul>
<p>Como puedes comprobar, es muy sencillo el proceso.</p>
<h4>Cómo protegerse</h4>
<p>La primera norma para evitar esto es <strong>no aceptar nunca identificadores de sesión a través de variables GET / POST</strong>. La mejor forma de manejar los SID de los usuarios es a través de cookies. Si usas PHP puedes configurarlo para que automáticamente maneje las sesiones a través de cookies e ignore cualquier forma de establecer el SID a través de otros medios. Esto se puede hacer configurando lo siguiente en el fichero php.ini:</p>
<pre name="code" class="php">
session.use_cookies = 1
session.use_only_cookies = 1
</pre>
<p>Otra medida para evitar la fijación de sesión, es <strong>regenerar el SID del usuario en cada petición</strong>. Haciendo esto, incluso aunque un atacante obtenga tu SID, el SID será inválido cuando el atacante intente suplantar al usuario. Esto es muy fácil hacerlo en PHP, simplemente hay que llamar a la función <a href="http://php.net/manual/en/function.session-regenerate-id.php">session_regenerate_id</a></p>
<h3>Conclusión</h3>
<p>Como habrás podido comprobar, las aplicaciones web están expuestas a múltiples vulnerabilidades que podrían tener <strong>efectos catastróficos</strong>. El simple envío de un comentario “infectado” podría tener como resultado el robo de información de cientos o miles de usuarios.</p>
<p>De todas formas, el objetivo de este tutorial no es el de sembrar el miedo entre los desarrolladores, sino el de informar sobre algo que (creo) muchas veces se obvia o se deja en segundo plano. Lo único que hay que hacer es investigar y aprender, <strong>si quieres derrotar a tu enemigo, ¡conócelo!</strong> <img src='http://web.ontuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/sesiones-en-php/' rel='bookmark' title='Permanent Link: Sesiones en PHP'>Sesiones en PHP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/apuntes-sobre-seguridad-web/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Qué son y cómo utilizar los custom fields de WordPress</title>
		<link>http://web.ontuts.com/tutoriales/que-son-y-como-utilizar-los-custom-fields-de-wordpress/</link>
		<comments>http://web.ontuts.com/tutoriales/que-son-y-como-utilizar-los-custom-fields-de-wordpress/#comments</comments>
		<pubDate>Thu, 10 Mar 2011 15:08:49 +0000</pubDate>
		<dc:creator>David Costales</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6966</guid>
		<description><![CDATA[En este nuevo tutorial realizaremos una explicación y casos de uso de los custom fields (campos personalizados) del gestor de contenidos Wordpress. Está destinado a aquellas personas que todavía no están familiarizadas con ello o simplemente se inician en el desarrollo para Wordpress.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/aprendiendo-a-utilizar-la-libreria-curl-en-php/' rel='bookmark' title='Permanent Link: Aprendiendo a utilizar la librería cURL en PHP'>Aprendiendo a utilizar la librería cURL en PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/' rel='bookmark' title='Permanent Link: Marcas de agua en imágenes usando PHP (I)'>Marcas de agua en imágenes usando PHP (I)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/' rel='bookmark' title='Permanent Link: Entendiendo los Layouts en Zend Framework PHP'>Entendiendo los Layouts en Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>¿Qué son los custom fields de WordPress?</h3>
<p>Los custom fields son campos personalizados que nos permiten añadir información extra en nuestros artículos y páginas de WordPress. A través de un nombre y un valor podemos mostrar cualquier cosa que deseemos, imágenes, texto, código&#8230; ofreciendonos un mundo de infinitas posibilidades.</p>
<h3>Cómo definir un custom field</h3>
<p>Lo primero que debemos hacer es identificarnos en nuestro panel de administración y crear una nueva entrada -o página-. Veremos una caja llamada <strong>&#8220;Campos personalizados&#8221;</strong> (<a href="http://codex.wordpress.org/es:Using_Custom_Fields">Custom fields</a> si nuestro WordPress está en inglés) en la parte inferior de nuestra pantalla. Rápidamente podemos diferenciar dos campos esenciales, que deberemos rellenar debidamente, <strong>Nombre</strong> y <strong>Valor</strong>:</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/03/custom_fields_1.jpg" alt="Custom Fields WordPress" /></center></p>
<p>A través de estos dos únicos campos podremos mostrar información o compararla con otra existente. Como ya os hemos comentado, las posibilidades que nos ofrece esta funcionalidad son casi infinitas. Vamos a ver un par de ejemplos para comprender rápidamente el funcionamiento de este tipo de campos.</p>
<h3>Mostrando imágenes en nuestros artículos</h3>
<p>Antes de que WordPress incluyera la posibilidad de añadir thumbnails a las entradas los custom fields eran casi la única forma de mostrar miniaturas que encabezasen las entradas, sin recurrir a plugins. Ahora os explicaré cómo.</p>
<p>Para este primer ejemplo necesitaremos una imagen de 200x200px, que previamente habremos subido a nuestro servidor, y modificar el archivo index.php para añadir la funcionalidad deseada. Para ello definiremos la etiqueta Nombre como <strong>&#8220;thumb&#8221;</strong> y la de Valor con la URL de nuestra imagen.</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/03/custom_fields_2.jpg" alt="Custom Fields WordPress" /></center></p>
<p>Le damos a <strong>&#8220;Añadir un campo personalizado&#8221;,</strong> el formulario se enviará y nos automáticamente creara nuestro primer custom field. Ahora le toca el turno a nuestro index.php, en el que tendremos que añadir un par de líneas de código PHP para que cargue la imagen que hemos guardado previamente.</p>
<blockquote><p>Una vez que hayamos creado nuestro primer custom field quedará almacenado y podremos acceder a el a través de un nuevo menú desplegable que aparecerá en la caja de &#8220;Campos personalizados&#8221;.</p></blockquote>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/03/custom_fields_3.jpg" alt="Custom Fields WordPress" /></center></p>
<p>Tendremos que identificar el comienzo del loop de WordPress ya que inmediatamente después tendremos que pegar el código que os muestro a continuación. Para aquellos que no lo sepan, el loop comienza justo después del primer condicional while.</p>
<pre name="code" class="php">
&lt;?php
while (have_posts()) : the_post();
$thumb = get_post_meta($post-&gt;ID, "thumb", $single = true);
?&gt;
</pre>
<p>Lo primero que hemos hecho es asignarle el valor del custom field <strong>&#8220;thumb&#8221;</strong> a la variable que lleva el mismo nombre, $thumb, para después poder interactuar con ella. En el siguiente paso comprobaremos que esta variable no está vacía con el fin de mostrar la imagen deseada, en caso contrario mostraremos una imagen por defecto.</p>
<pre name="code" class="php">
&lt;?php if($thumb !== '') { ?&gt;
    &lt;img class=&quot;left&quot; src=&quot;" width="200" height="200" alt="" /&gt;
&lt;?php } else { ?&gt;
    &lt;img class=&quot;left&quot; src=&quot;/images/default_thumb" width="200" height="200" alt="" /&gt;
&lt;?php } ?&gt;
</pre>
<p>Podéis comprobar que le hemos asignado la clase &#8220;left&#8221; a nuestra imagen, con el único propósito de que le haga un float: left; y se muestre inscrustada a la izquierda del contenido de nuestro artículo. El código CSS sería algo así:</p>
<pre name="code" class="php">
.left {
    float: left;
}
</pre>
<h3>Mostrando la música que estamos escuchando</h3>
<p>Ahora vamos a crear un <strong>custom field</strong> que nos permita mostrar la canción que estamos escuchando mientras escribíamos el artículo. Este pequeño campo podremos utilizarlo tanto en el index.php como en el single.php, a gusto del consumidor.</p>
<p>Primero localizaremos el formulario de &#8220;Campos personalizados&#8221; en la opción de &#8220;Editar entrada&#8221; dentro de nuestro panel de Administración. Definiremos el campo Nombre como &#8220;song&#8221; y el Valor con el nombre de la canción. Enviamos los datos a través del botón de &#8220;Añadir un campo personalizado&#8221; y guardamos la entrada.</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/03/custom_fields_4.jpg" alt="Custom Fields WordPress" /></center></p>
<p>Ahora que nuestro nuevo <strong>custom field</strong> está creado es hora de mostrarlo en nuestra plantilla. Para ello tendremos que editar nuestro single.php y colocar el siguiente código donde deseemos mostrar la información.</p>
<pre name="code" class="php">
$customField = get_post_custom_values("song");
if (isset($customField[0])) {
echo "Escuchaba: ".$customField[0];
</pre>
<p>Este mismo procedimiento podéis utilizarlo, por ejemplo, para mostrar publicidad de AdSense. Tan solo tendréis que definir los valores del campo personalizado atendiendo al código que nos otorga Google para mostrar su publicidad.</p>
<h3>Conclusión</h3>
<p>Hemos visto cómo gracias a los custom fields podemos vitaminar nuestras plantillas con el fin de mostrar otro tipo de contenido. Queda en la imaginación de cada uno el buscar otras formas de sacarle provecho a esta funcionalidad, ya que la capacidad de la misma es enorme.</p>
<p>¡Nos vemos en el próximo tutorial WordPress!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/aprendiendo-a-utilizar-la-libreria-curl-en-php/' rel='bookmark' title='Permanent Link: Aprendiendo a utilizar la librería cURL en PHP'>Aprendiendo a utilizar la librería cURL en PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/marcas-de-agua-en-imagenes-usando-php-i/' rel='bookmark' title='Permanent Link: Marcas de agua en imágenes usando PHP (I)'>Marcas de agua en imágenes usando PHP (I)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/' rel='bookmark' title='Permanent Link: Entendiendo los Layouts en Zend Framework PHP'>Entendiendo los Layouts en Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/que-son-y-como-utilizar-los-custom-fields-de-wordpress/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</title>
		<link>http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/</link>
		<comments>http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 12:33:28 +0000</pubDate>
		<dc:creator>Gonzalo Ayuso</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[optimización]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6940</guid>
		<description><![CDATA[Una de las reglas de oro cuando tratamos de mejorar el rendimiento en aplicaciones Web en reducir el uso de peticiones HTTP. Normalmente solemos tener varios archivos Javascript dentro de nuestros proyectos, lo que significa varias peticiones HTTP para descargarlos. Es una práctica recomendable unir todos estos archivos JavaScript en uno solo para reducir el número de peticiones. En este artículo veremos cómo hacer esto usando un script PHP.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/como-validar-un-formulario-con-php-y-javascript-jquery/' rel='bookmark' title='Permanent Link: Cómo validar un formulario utilizando PHP y Javascript (jQuery)'>Cómo validar un formulario utilizando PHP y Javascript (jQuery)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/' rel='bookmark' title='Permanent Link: Entendiendo los Layouts en Zend Framework PHP'>Entendiendo los Layouts en Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/reducir-el-tiempo-de-carga-web-minimiza-las-peticiones-http/' rel='bookmark' title='Permanent Link: Reducir el tiempo de carga Web: Minimiza las Peticiones HTTP'>Reducir el tiempo de carga Web: Minimiza las Peticiones HTTP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción</h3>
<p>Una de las reglas de oro cuando tratamos de mejorar el rendimiento en aplicaciones Web es reducir el uso de peticiones HTTP. Normalmente solemos tener varios archivos Javascript dentro de nuestros proyectos, lo que significa varias peticiones HTTP para descargarlos.</p>
<p>Es una práctica recomendable <strong>unir</strong> todos estos archivos Javascript en <strong>uno solo para reducir el número de peticiones</strong>. Podemos hacerlo de forma manual. No es difícil. Solo tenemos que cortar y pegar las fuentes Javascript en un único archivo. Incluso tenemos herramientas que nos ayudan a hacerlo, como <a href='http://developer.yahoo.com/yslow/'>Yslow</a>.</p>
<p>Esto es una buena solución si nuestro proyecto está terminado. Pero si nuestro proyecto está vivo y lo estamos modificando, suele ser útil (al menos para mí) separar los archivos Javascript para tener el código más organizado y mantenerlo.</p>
<p>En definitiva, que tenemos que decidir entre el rendimiento de nuestra aplicación en producción o ayudar al desarrollador. Es por esto que me gusta usar el script que os voy a mostrar. Un script PHP que junta todos los archivos .js dentro de un único archivo de forma dinámica. </p>
<h3>¿Cómo aceleramos los tiempos de carga de Javascript?</h3>
<p>La idea es la siguiente. Normalmente suelo tener los archivos .js guardados jerárquicamente dentro de una carpeta que se llama js (¿original, no?). También suelo tener un servidor de desarrollo y uno de producción (¿realmente original, no?). Cuando estoy desarrollando mi aplicación me gusta separar los archivos y en un formato legible, pero cuando están en producción combinarlos en uno solo e incluso minimizarlos para mejorar el tiempo de descarga.</p>
<p>El script que tengo para combinar todos los archivos .js en uno solo es el siguiente:</p>
<pre name="code" class="php">
//js.php
require 'jsmin.php';

function checkCanGzip(){
    if (array_key_exists('HTTP_ACCEPT_ENCODING', $_SERVER)) {
        if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false) return "gzip";
        if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip') !== false) return "x-gzip";
    }
    return false;
}

function gzDocOut($contents, $level=6){
    $return = array();
    $return[] = "\x1f\x8b\x08\x00\x00\x00\x00\x00";
    $size = strlen($contents);
    $crc = crc32($contents);
    $contents = gzcompress($contents,$level);
    $contents = substr($contents, 0, strlen($contents) - 4);
    $return[] = $contents;
    $return[] = pack('V',$crc);
    $return[] = pack('V',$size);
    return implode(null, $return);
}

$ite = new RecursiveDirectoryIterator(dirname(__FILE__));
foreach(new RecursiveIteratorIterator($ite) as $file =&gt; $fileInfo) {
    $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
    if ($extension == 'js') {
        $f = $fileInfo-&gt;openFile('r');
        $fdata = "";
        while ( ! $f-&gt;eof()) {
            $fdata .= $f-&gt;fgets();
        }
        $buffer[] = $fdata;
    }
}

$output = JSMin::minify(implode(";\n", $buffer));

header("Content-type: application/x-javascript; charset: UTF-8");
$forceGz    = filter_input(INPUT_GET, 'gz', FILTER_SANITIZE_STRING);
$forcePlain = filter_input(INPUT_GET, 'plain', FILTER_SANITIZE_STRING);

$encoding = checkCanGzip();
if ($forceGz) {
    header("Content-Encoding: {$encoding}");
    echo gzDocOut($output);
} elseif ($forcePlain) {
    echo $output;
} else {
    if ($encoding){
        header("Content-Encoding: {$encoding}");
        echo GzDocOut($output);
    } else {
        echo $output;
    }
}
</pre>
<p>Como podemos ver el script se <strong>recorre recursivamente los archivos Javascript</strong> dentro de una carpeta, los une e incluso le pasa la librería <a href='https://github.com/rgrove/jsmin-php/'>jsmin</a> para PHP para reducir el tamaño del archivo Javascript resultante, y mejorar así el tiempo total de descarga en el navegador.</p>
<p>Con este script en marcha, es muy sencillo crear un archivo HTML que dependiendo del entorno en el que nos encontremos (producción o desarrollo) incluya los tags HTML necesarios para usar la versión minimizada y unificada o todos los archivos Javascript por separado. Aquí pongo un ejemplo usando el motor de plantillas Smarty:</p>
<pre name="code" class="html">
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
        &lt;title&gt;&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        Hello World
{if $dev}
        &lt;script src=&quot;js1.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;js2.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;xxx/js1.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
{else}
        &lt;script src=&quot;js.php&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
{/if}
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Sí, lo sé. Hay un problema con esta solución. Quizás hemos mejorado el rendimiento en el cliente (navegador) reduciendo el número de peticiones HTTP, pero ¿Qué pasa con el rendimiento en servidor? Hemos pasado de servir archivos Javascript estáticos, a necesitar PHP para generar archivos estáticos. Ahora el servidor consume más CPU. Dependiendo del hosting que estemos usando, más CPU supone más caro.</p>
<blockquote><p>Alojar los recursos y archivos estáticos en servidores independientes al servidor web nos permite descargar en paralelo de forma más rápida y eficiente.</p></blockquote>
<p>Otra regla de oro del rendimiento Web es poner el <strong>contenido estático en un servidor dedicado</strong>, o CDN sin PHP. Con esta segunda regla de oro conseguimos realizar descargar múltiples más eficientes de nuestro contenido estático y reducir el consumo de CPU, ya que los servidores que sirven contenido estático no necesitan crear una instancia de PHP ni interpretar ningún código.</p>
<p>Por lo tanto una mejor solución en la siguiente: Generamos el archivo Javascript estático de forma offline cuando desplegamos nuestra aplicación a producción. Yo lo suelo hacer con un simple comando de curl, el un terminal:</p>
<pre name="code" class="php">
curl http://nov/js/js.php -o jsfull.minified.js
</pre>
<p>Ahora nuestra plantilla Smarty pasa a ser:</p>
<pre name="code" class="html">
&lt;html&gt;
    &lt;head&gt;
        &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot;&gt;
        &lt;title&gt;&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        Hello World
{if $dev}
        &lt;script src=&quot;js1.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;js2.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;xxx/js1.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
{else}
        &lt;script src=&quot;jsfull.minified.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
{/if}
    &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Además de esto es recomendable poner un prefijo a nuestro archivo js para que el nombre sea distinto y asegurarnos así que en navegador renueva la caché y se descarga la última versión. </p>
<pre name="code" class="html">
&lt;script src=&quot;jsfull.minified.20110216.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
</pre>
<h3>Conclusión final</h3>
<p>Y esto es todo. Como más de uno se habrá dado cuenta esta misma técnica podremos emplearla también para unir archivos CSS y reducir así los tiempos de carga de este tipo de archivos.</p>
<p>¡Nos vemos en la próxima publicación!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/como-validar-un-formulario-con-php-y-javascript-jquery/' rel='bookmark' title='Permanent Link: Cómo validar un formulario utilizando PHP y Javascript (jQuery)'>Cómo validar un formulario utilizando PHP y Javascript (jQuery)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/' rel='bookmark' title='Permanent Link: Entendiendo los Layouts en Zend Framework PHP'>Entendiendo los Layouts en Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/reducir-el-tiempo-de-carga-web-minimiza-las-peticiones-http/' rel='bookmark' title='Permanent Link: Reducir el tiempo de carga Web: Minimiza las Peticiones HTTP'>Reducir el tiempo de carga Web: Minimiza las Peticiones HTTP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Creando un temporizador con Silverlight y C#</title>
		<link>http://web.ontuts.com/tutoriales/creando-un-temporizador-con-silverlight-y-c/</link>
		<comments>http://web.ontuts.com/tutoriales/creando-un-temporizador-con-silverlight-y-c/#comments</comments>
		<pubDate>Thu, 27 Jan 2011 11:57:22 +0000</pubDate>
		<dc:creator>Roberto Luis Bisbé</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[silverlight]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6558</guid>
		<description><![CDATA[Seguimos ampliando el catálogo de tutoriales Silverlight, en esta ocasión vamos a realizar un pequeño proyecto con el cual podremos contabilizar el tiempo que transcurre durante por ejemplo una actividad, mostrándolo en pantalla. Mediante code-behind haremos toda la lógica del temporizador.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/que-son-y-como-utilizar-los-custom-fields-de-wordpress/' rel='bookmark' title='Permanent Link: Qué son y cómo utilizar los custom fields de WordPress'>Qué son y cómo utilizar los custom fields de WordPress</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción</h3>
<p>Es posible que trabajando en cualquier proyecto por pequeño que sea,  tengamos la necesidad de contar el tiempo que transcurre en una  determinada actividad y mostrarlo por pantalla, para ello crearemos una pequeña aplicación en Silverlight y mediante code-behind haremos toda la lógica del temporizador.</p>
<p>Una vez nos hemos decidido a medir el tiempo, necesitamos, para nuestro temporizador los siguientes elementos:</p>
<ul>
<li>Un botón para <strong>iniciar/detener</strong>.</li>
<li>Un campo de texto que nos indique el <strong>tiempo que está transcurriendo</strong>.</li>
<li>Un temporizador que <strong>actualice</strong> nuestro campo de texto (obvio, no?)</li>
</ul>
<p>El apartado gráfico lo crearemos usando XAML, mientras que la lógica de nuesra aplicación (es decir, la parte que va a contar realmente) la crearemos usando C#</p>
<h3>Paso 1: Creando la Interfaz</h3>
<p>Lo primero será crear la interfaz en XAML, para lo que necesitamos  únicamente un par de botones y una etiqueta. Para ello abrimos Visual  Studio 2010 y creamos una solución de tipo <strong>Aplicación de Silverlight</strong>.</p>
<p>Una vez cargada la aplicación, se nos muestra en el editor de Visual  Studio la ventana principal, dividida entre editor y código.  Posteriormente agregamos las siguientes líneas entre<strong> &lt;Grid x:Name=&#8221;LayoutRoot&#8221;&#8230;&gt; y &lt;/Grid&gt;</strong>:</p>
<pre name="code" class="xml">
&lt;StackPanel&gt;
&lt;TextBlock x:Name="text" Width="130" Height="40" Margin="10" Text="00:00:00" TextAlignment="Right" FontSize="26"/&gt;
&lt;Button x:Name="Start" Width="80" Height="30" Content="Iniciar" Click="Start_Click"/&gt;
&lt;/StackPanel&gt;
</pre>
<p>El resultado de lo que acabamos de crear sería algo similar a esto:</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2011/01/captura.png" alt="temporizador" /></center></p>
<p>Como se aprecia, hemos agregado una etiqueta, un botón, los hemos metido en  un StackPanel para que estén alineados, y hemos cambiado el tamaño de  nuestro campo de texto en unas pocas líneas.</p>
<h3>Paso 2: Agregando código C#</h3>
<p>Una vez tenemos nuestro campo de texto, vamos a darle vida, pero primeramente tenemos que crear e inicializar nuestro timer,  para lo cual vamos al fichero MainPage.xaml.cs, o bien hacemos click  derecho en el editor y seleccionamos la opción <strong>Ver código</strong>.</p>
<p>En el constructor de MainPage, justo después de IntializeComponent(); incializamos nuestro contador:</p>
<pre name="code" class="csharp">
//Agregamos un campo de tipo temporizador, y de carácter global para toda la clase, así como un entero que nos servirá para nuestro conteo
int i = 0;
System.Windows.Threading.DispatcherTimer temporizador;

public MainPage(){
InitializeComponent();
//Agregamos el siguiente código de control del temporizador.
temporizador = new System.Windows.Threading.DispatcherTimer();
temporizador.Interval = new TimeSpan(0, 0, 0, 1);
temporizador.Tick += new EventHandler(temporizador_Tick);
}
</pre>
<p>Como se aprecia, hemos inicializado nuestro temporizador, le hemos  asignado un intervalo de 1 segundo (La opción de TimeSpan que hemos  empleado tiene el formato: días, horas, minutos, segundos).</p>
<p>Por último hemos agregado un EventHandler que llamará a nuestra  función con cada Tick del temporizador (es decir, cada 1 segundo).</p>
<p>Nuestra función tiene el siguiente formato:</p>
<pre name="code" class="csharp">
void temporizador_Tick(object sender, EventArgs e)
{
i += 1;
int hour = i / 3600;
int min = i / 60;
int sec = i % 60;
text.Text = hour.ToString("00") + ":" + min.ToString("00") + ":" + sec.ToString("00");
}
</pre>
<p>Lo que estamos haciendo es dividir nuestro contador en horas, minutos  y segundos, y mostrar el resultado en el campo que hemos creado para  tal efecto.</p>
<p>Para que funcione, lo único que nos queda es crear el evento para el  click del botón, que se crea, curiosamente, haciendo doble click en el  botón.</p>
<pre name="code" class="csharp">
private void Start_Click(object sender, RoutedEventArgs e)
{
temporizador.Start();
}
</pre>
<p>Veamos ahora cómo extender el temporizador&#8230;</p>
<h3>Paso 3: Extendiendo nuestro temporizador</h3>
<p>Una vez que tenemos nuestro temporizador, puede que queramos hacer dos cosas más:</p>
<ul>
<li>Parar (o pausar) el contador.</li>
<li>Restaurarlo (volver a 0).</li>
</ul>
<p>Para poder parar o pausar el contador, necesitamos conocer cuándo  está funcionando nuestro temporizador, y realizar una acción acorde a  ello, para ello agregamos el siguiente código:</p>
<pre name="code" class="csharp">
private void Start_Click(object sender, RoutedEventArgs e)
{
if (temporizador.IsEnabled)     //Si está en funcionamiento, lo detenemos
{
temporizador.Stop();
Start.Content = "Iniciar";
}
else                            //Si no, lo iniciamos
{
temporizador.Start();
Start.Content = "Detener";
}
}
</pre>
<p>Ahora sólo nos queda agregar el botón con el que pararemos el reloj:</p>
<pre name="code" class="xml">
&lt;Button x:Name="Clear" Width="80" Height="30" Margin="10" Content="Restaurar" Click="Clear_Click" /&gt;
</pre>
<p>Y asociado al click, agregamos el siguiente código, que restaura los valores por defecto del contador:</p>
<pre name="code" class="csharp">
private void Clear_Click(object sender, RoutedEventArgs e)
{
temporizador.Stop();    //Paramos el contador
text.Text = "00:00:00"; //Ponemos el texto a 0
i = 0;                  //Restauramos el valor de nuestra variable
}
</pre>
<p>El resultado final se muestra a continuación:</p>
<p><center><a href="http://web.ontuts.com/wp-content/uploads/tutoriales/temporizador_silverlight/index.html"><img src="http://web.ontuts.com/wp-content/uploads/2011/01/captura1.png" alt="temporizador" /></a></center></p>
<p>Recordad: Para ejecutar el ejemplo es necesario tener Silverlight instalado, y para editar el código fuente os recomendaría utilizar o bien Visual Studio 2010, o Expression Blend 4&#8230; aunque ya se sabe para gustos&#8230; editores <img src='http://web.ontuts.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<h3>Reflexión final</h3>
<p>En este tutorial hemos visto cómo podemos, con pocas lineas de código, crear un contador. Hemos:</p>
<ul>
<li>Creado la interfaz usando un <a href="http://msdn.microsoft.com/es-es/library/system.windows.controls.stackpanel%28v=vs.95%29.aspx">Stackpanel</a> en el lenguaje <a href="http://msdn.microsoft.com/es-es/library/cc295302.aspx">XAML</a></li>
<li>Creado un objeto de tipo <a href="http://msdn.microsoft.com/es-es/library/system.windows.threading.dispatchertimer.aspx">DispatcherTimer</a></li>
<li>Usado <a href="http://msdn.microsoft.com/es-es/library/awbftdfh%28v=VS.100%29.aspx">eventos</a> para gestionar la función que se llama a cada &#8220;tick&#8221;</li>
</ul>
<p>Lo mejor de este sistema es la total separación entre interfaz y funcionalidad, de tal manera que todo el apartado XAML se puede realizar mediante Blend, una herramienta más enfocada al diseño, y el desarrollo se puede preparar con Visual Studio, finalmente para enlazarlo solamente necesitamos la etiqueta <strong><em>x:Name</em></strong>, que se corresponde con los elementos mostrados en el apartado de C#.</p>
<p>Espero que os haya resultado provechoso&#8230; ¡Nos vemos en la próxima publicación!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/que-son-y-como-utilizar-los-custom-fields-de-wordpress/' rel='bookmark' title='Permanent Link: Qué son y cómo utilizar los custom fields de WordPress'>Qué son y cómo utilizar los custom fields de WordPress</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/creando-un-temporizador-con-silverlight-y-c/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Namespacing en Javascript</title>
		<link>http://web.ontuts.com/tutoriales/namespacing-en-javascript/</link>
		<comments>http://web.ontuts.com/tutoriales/namespacing-en-javascript/#comments</comments>
		<pubDate>Mon, 17 Jan 2011 12:28:10 +0000</pubDate>
		<dc:creator>Carlos Benítez</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6541</guid>
		<description><![CDATA[Javascript es un lenguaje puramente orientado a objetos. En este artículo vamos a revisar las técnicas más recientes para la creación de objetos en Javascript. Gracias a estos patrones, podremos crear aplicaciones más organizadas, mantenibles y reusables.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/funciones-perezosas-lazy-functions-en-javascript/' rel='bookmark' title='Permanent Link: Funciones perezosas / Lazy functions en Javascript'>Funciones perezosas / Lazy functions en Javascript</a></li>
<li><a href='http://web.ontuts.com/tutoriales/como-validar-un-formulario-con-php-y-javascript-jquery/' rel='bookmark' title='Permanent Link: Cómo validar un formulario utilizando PHP y Javascript (jQuery)'>Cómo validar un formulario utilizando PHP y Javascript (jQuery)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/como-crear-un-menu-contextual-en-javascript-mediante-jquery/' rel='bookmark' title='Permanent Link: Cómo crear un Menú Contextual en Javascript mediante jQuery'>Cómo crear un Menú Contextual en Javascript mediante jQuery</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción</h3>
<p>Javascript es un lenguaje puramente orientado a objetos. Sin embargo, en muchas ocasiones comenzamos a programar <strong>sin un patrón de diseño</strong> y llenamos nuestra aplicación de variables y funciones globales. Esto se considera una <strong>mala práctica</strong> y puede dar lugar a errores como las colisiones o dificultades para mantener y reusar el código.</p>
<p>En este artículo vamos a revisar las técnicas más recientes para la creación de objetos en Javascript. Gracias a estos <strong>patrones</strong>, podremos crear aplicaciones <strong>más organizadas</strong>, <strong>mantenibles</strong> y <strong>reusables</strong>.</p>
<h3>Malas prácticas desde el día cero</h3>
<p>Cuando comenzamos a programar en Javascript es frecuente declarar un sin fin de variables globales que más tarde iremos utilizando en nuestro script conforme las necesitemos.</p>
<p>Sin embargo, la bibliografía moderna nos recomienda reservar el uso de este tipo de variables a aquellos objetos que tienen un impacto general en el entorno de nuestra aplicación. Evitando las variables globales reducimos el riesgo de colisión entre ellas a la vez que evitamos ambigüedades.</p>
<blockquote><p>Para la mayoría de autores, se resume con la misma frase: hay que evitar la creación de variables y funciones (objetos en general) globales siempre que no sean absolutamente necesarios.</p></blockquote>
<p>Para ilustrar esto, hay que recordar que en Javascript, cualquier variable global se asigna inmediatamente a un namespace (contexto) general: el objeto <strong>window</strong>. Esto permite que podamos acceder a ella directamente por su nombre, o como una propiedad del objeto general:</p>
<pre name="code" class="javascript">
var foo = 'bar'; // Definimos la variable como global
console.log( foo ); // Invocamos a la variable directamente por su nombre
console.log( window.foo ); // Invocamos a la variable como un método
</pre>
<p>No hay nada nuevo en todo esto. A partir de aquí, ya podemos buscar una estrategia para evitar el uso de variables globales. Para ello, lo ideal es crear un número pequeño de objetos que hagan de contenedores para estas variables o, lo que es lo mismo, recoger todo aquello global que participe de un mismo proceso dentro de un namespace (contexto) propio.</p>
<p>Autores como <a title="Douglas Crockford" href="http://www.crockford.com/">Douglas Crockford</a>, <a title="John Resig" href="http://www.google.es/url?sa=t&amp;source=web&amp;cd=1&amp;ved=0CCQQFjAA&amp;url=http%3A%2F%2Fejohn.org%2F&amp;rct=j&amp;q=john%20resig&amp;ei=lpIxTabnIIK64Qbmm-mwCg&amp;usg=AFQjCNF9r8BiCVJTGZLzXp2SvB1veguyew&amp;sig2=2yHFqnBkpiCZhTQlS0MPiQ&amp;cad=rja">John Resig</a>, <a title="Angus Croll" href="http://javascriptweblog.wordpress.com/">Angus Croll</a> o <a title="James Edwards" href="http://www.brothercake.com/">James Edwards</a> han elaborado sus propias aproximaciones a este modelo. Veamos algunas de ellas comentando sus ventajas e incovenientes&#8230;</p>
<h3>Creación de un objeto global y asignación de métodos por prefijo</h3>
<p>Es la <strong>opción más sencilla</strong> pero quizá algo desorganizada. En su favor, tenemos que es segura para refactorizar aquellos códigos que presentan un número considerable de variables globales haciendo difícil su reutilización en otros proyectos.</p>
<p>Tomemos el siguiente código:</p>
<pre name="code" class="javascript">
// Opción mala (antipattern)
var foo = 'Hello';
var bar = 'World';
function sum( param1, param2 ){
return param1 + param2;
}
function myMessage(){
return foo + ' ' + bar;
}

console.log( sum( 10, 5 ) ); // 15
console.log( myMessage() ); // Hello World
</pre>
<p>En el ejemplo anterior, definimos dos variables globales y dos funciones dentro del namespace general. Como ya hemos visto, esta forma de programar puede traernos problemas de colisión además de que el código no presenta ningua cohesión.</p>
<p>Si quisiéramos reaprovechar parte del script, tendríamos que tener cuidado de no olvidarnos alguna variable o función durante el proceso. Según el método de asignación directa que comentamos, el código anterior quedaría como sigue:</p>
<pre name="code" class="javascript">
var myApp = {}
myApp.foo = 'Hello';
myApp.bar = 'World';
myApp.sum = function( param1, param2 ){
return param1 + param2;
}
myApp.myMessage = function(){
return myApp.foo + ' ' + myApp.bar;
}

console.log( myApp.sum( 10, 5 ) ); // 15
console.log( myApp.myMessage() ); // Hello World
</pre>
<p>Hemos creado un único objeto global, myApp, que utilizamos como contenedor para el resto de variables y funciones. De este modo, ganamos legibilidad al poder identificar de un solo vistazo, aquellas partes de código que trabajan conjuntamente. A la hora de portar el código, solo tendríamos que preocuparnos de coger aquellas funciones cuyo prefijo coincida con su contexto.</p>
<p>En el código anterior podríamos utilizar la referencia <strong>this</strong> en el interior de las funciones para facilitar el mantenimiento en el futuro, pero esto puede dar lugar a errores inesperados. Probemos por ejemplo a asignar uno de los métodos que hemos creado a una nueva función:</p>
<pre name="code" class="javascript">
var newFunction = myApp.myMessage;
console.log( newFunction() ); // Hello World
</pre>
<p>Las referencias a las variables se conservan y nuestra nueva función accede a ellas siguiendo la ruta original (<strong>myApp.foo</strong> y <strong>myApp.bar</strong>).</p>
<p>Cambiemos ahora la referencia a las variables en el ejemplo original:</p>
<pre name="code" class="javascript">
// ...
myApp.myMessage = function(){
return this.foo + ' ' + this.bar;
}
// ...
console.log( myApp.myMessage); // Hello World
</pre>
<p>El código continúa funcionando correctamente pero, si volvemos a asignar el método a una nueva función, el resultado varía:</p>
<pre name="code" class="javascript">
var newFunction = myApp.myMessage;
console.log( newFunction() ); // Undefined. this está refiriendo al objeto global.
</pre>
<p>Este ejemplo viene a ilustrar una regla que cada vez <a title="Widgets without this" href="http://peter.michaux.ca/articles/javascript-widgets-without-this">más autores defienden</a>: nunca debemos referenciar un objeto que estamos utilizando como namespace (contexto) con &#8216;<strong>this</strong>&#8216; ya que podemos obtener errores cuando importamos métodos de un contexto a otro.</p>
<h3>Notación literal</h3>
<p>Utilizando la notación literal, podemos evitar hacer referencia al objeto global cada vez que necesitemos crear un nuevo método. Además, conseguimos un código más limpio y ordenado. Partiendo del ejemplo anterior, el resultado sería:</p>
<pre name="code" class="javascript">
var myApp = {
foo : 'Hello',
bar : 'World',
sum : function( param1, param2 ){
return param1 + param2;
},
myMessage : function(){
return this.foo + ' ' + this.bar;
}
};

console.log( myApp.sum( 10, 5 ) ); // 15
console.log( myApp.myMessage() ); // Hello World
</pre>
<p>Esta estrategia sería la más sencilla para la creación de una estructura básica de POO en Javascript. La portabilidad de los objetos resulta sencilla al tener &#8216;encapsulado&#8217; todo el proceso.</p>
<h3>Módulos</h3>
<p>El patrón que llamamos módulo se configura a partir de una función que actúa como contexto para nuestra aplicación. Por lo general, esta función se autoejecuta devolviendo el objeto que representa la interfaz pública de nuestro módulo.</p>
<p>Este modelo es más familiar para aquellos que provienen de otros lenguajes de programación orientados a objetos al permitir distinguir entre métodos públicos y privados. Ya que Javascript no implementa el concepto de clases de forma nativa, creamos funciones que actúen como tales.</p>
<p>Todas las variables y funciones definidas en el interior de nuestra &#8220;clase&#8221; se consideran métodos privados. Aquellos métodos que queremos hacer públicos los devolvemos mediantes el comando &#8220;<strong>return</strong>&#8221; al ámbito general (módulo) de la aplicación.</p>
<pre name="code" class="javascript">
var myApp = (function(){
var foo = 'Hello';
var bar = 'World';
var sum = function( param1, param2 ){
return param1 + param2;
}
return {
myMessage: function(){
return foo + ' ' + bar;
}
}
})();

console.log( myApp.myMessage() ); // Hello World
console.log( myApp.sum( 10, 5 ) ); // myApp.sum is not a function. sum es privada
</pre>
<p>En el código anterior, <strong>myApp.sum</strong> no se ha incluido en el objeto return por lo que permanece privada y visible únicamente dentro de su contexto. Sin embargo, <strong>myMessage</strong>, si que ha sido devuelta y añadida al entorno de<strong> myApp</strong>, por lo que funciona como se espera. Con este modelo, ya no es necesario referenciar a las variables con <strong>this</strong>, ya que comparten mismo contexto.</p>
<p>El aspecto negativo de este patrón es que accedemos de forma diferente a los métodos según sean públicos o privados. Esto supone que si queremos cambiar su visibilidad, tenemos que modificar el código moviendo funciones desde o hacia el método return. Otro inconveniente es que los métodos privados resultarán innacesibles para aquellas funciones que sean añadidas al objeto padre (módulo) con posterioridad a su definición.</p>
<h3>Contexto dinámico</h3>
<p>Si declaramos un entorno y lo pasamos como argumento de una función autoejecutable, evitamos tener que asignar variables y métodos al contexto mediante el comando return. Resulta por lo tanto una solución derivada de la anterior pero más legible e intuitiva.</p>
<pre name="code" class="javascript">
var myApp = {};
(function( context ){
var foo = 'Hello';
var bar = 'World';
context.sum = function( param1, param2 ){
return param1 + param2;
};
context.myMessage = function(){
return foo + ' ' + bar;
}
})( myApp );

console.log( myApp.sum( 10, 5 ) ); // 15
console.log( myApp.myMessage() ); // Hello World
</pre>
<p>Las variables <strong>foo </strong>y <strong>bar</strong>, permanecen como privadas, por lo que solo tienen visibilidad dentro de su contexto. Los métodos asignados al objeto contenedor, se convierten en públicos.</p>
</p>
<p>Siguiendo este patrón, incluso podemos asignar el contexto al objeto global tal y como hace, por ejemplo, la librería <a title="jQuery" href="http://jquery.com/">jQuery</a>. Esto permite al usuario elegir si los métodos de nuestra aplicación se convierten en globales o se restringen a la misma:</p>
<pre name="code" class="javascript">
(function( context ){
var foo = 'Hello';
var bar = 'World';
context.sum = function( param1, param2 ){
return param1 + param2;
};
context.myMessage = function(){
return foo + ' ' + bar;
}
})( this );

console.log( sum( 10, 5 ) ); // 15
console.log( myMessage() ); // Hello World
</pre>
<p>Echemos ahora un vistazo al patrón de James Edwards&#8230;</p>
<h3>Patrón de James Edwards &#8216;This namespaces proxy&#8217;</h3>
<p>James Edwards ha creado un patrón cuya simpleza esconde una joya en cuanto a arquitectura de código. Utilizando la referencia <strong>this </strong>para inyectar métodos al contexto, evita que éstos puedan ser reasignados accidentalmente más adelante.</p>
<pre name="code" class="javascript">
var myApp = {};
(function(){
var foo = 'Hello';
var bar = 'World';
this.sum = function( param1, param2 ){
return param1 + param2;
};
this.myMessage = function(){
return foo + ' ' + bar;
};
}).apply( myApp );

console.log( myApp.sum( 10, 5 ) ); // 15
console.log( myApp.myMessage() ); // Hello World
</pre>
<p>Simple y elegante: el uso de los comandos <strong>apply</strong> y <strong>call</strong> separan el contexto de los argumentos, lo que mejora aún más el diseño general. Siguiendo este patrón, podemos incluso asignar un mismo módulo a dos contextos direfentes consiguiendo implementaciones paralelas:</p>
<pre name="code" class="javascript">
var context1 = {}, context2 = {};
var incrementNumber = function( param1 ){
var startNumber = param1 || 0;
this.increment = function(){
return startNumber++;
}
};
incrementNumber.call( context1 );
incrementNumber.call( context2, 10 );

console.log( context1.increment() ); // 0
console.log( context1.increment() ); // 1
console.log( context1.increment() ); // 2
console.log( context2.increment() ); // 10
console.log( context2.increment() ); // 11
console.log( context2.increment() ); // 12
</pre>
<h3>Conclusión final</h3>
<p>En la programación Javascript moderna, evitar la creación de variables y métodos globales resulta básico: si pretendemos integrar librerías de terceros o escribir un código que pueda ser reutilizado, tenemos que estructurarlo correctamente para evitar los errores derivados de las colisiones y ambigüedades.</p>
<p>Para ello, recurrimos a la creación de objetos que actúen como contenedores de aquellas piezas de código que compartan funcionalidad. A lo largo del artículo hemos visto diferentes aproximaciones al mismo problema analizando tanto sus ventajas como los inconvenientes.</p>
<p>Corresponde ahora al desarrollador elegir aquel método que mejor se adapte a sus necesidades concretas o crear su propio patrón a partir de los mismos.</p>
<h3>Más información:</h3>
<p>Os dejamos algunos enlaces para curiosos que quieran seguir profundizando en el tema:</p>
<ul>
<li>James Edwards, <a title="My Favorite Javascript Design Pattern" href="http://blogs.sitepoint.com/2010/11/30/my-favorite-javascript-design-pattern/">My Favorite Javascript Design Pattern</a></li>
<li>Peter Michaux, <a title="Javascript Namespacing" href="http://michaux.ca/articles/javascript-namespacing">Javascript Namespacing</a></li>
<li>Angus Croll, <a title="Namespacing in Javascript" href="http://javascriptweblog.wordpress.com/2010/12/07/namespacing-in-javascript/">Namespacing in Javascript</a></li>
<li>Addy Osmani, <a title="Essential Javascript &amp; jQuery Design Patterns" href="http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/">Essential JavaScript &amp; jQuery Design Patterns For Beginners</a></li>
</ul>
<p>Nos vemos en la próxima publicación&#8230; ¡Un saludo!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/funciones-perezosas-lazy-functions-en-javascript/' rel='bookmark' title='Permanent Link: Funciones perezosas / Lazy functions en Javascript'>Funciones perezosas / Lazy functions en Javascript</a></li>
<li><a href='http://web.ontuts.com/tutoriales/como-validar-un-formulario-con-php-y-javascript-jquery/' rel='bookmark' title='Permanent Link: Cómo validar un formulario utilizando PHP y Javascript (jQuery)'>Cómo validar un formulario utilizando PHP y Javascript (jQuery)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-una-capa-de-conexion-abstracta-a-base-de-datos-con-php/' rel='bookmark' title='Permanent Link: Creando una capa de conexión abstracta a base de datos con PHP'>Creando una capa de conexión abstracta a base de datos con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/como-crear-un-menu-contextual-en-javascript-mediante-jquery/' rel='bookmark' title='Permanent Link: Cómo crear un Menú Contextual en Javascript mediante jQuery'>Cómo crear un Menú Contextual en Javascript mediante jQuery</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/namespacing-en-javascript/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Entendiendo los Layouts en Zend Framework PHP</title>
		<link>http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/</link>
		<comments>http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/#comments</comments>
		<pubDate>Mon, 06 Dec 2010 15:22:27 +0000</pubDate>
		<dc:creator>elericuz</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6197</guid>
		<description><![CDATA[En este segundo artículo de la serie de introducción a Zend Framework veremos cómo se trabaja con layouts y cómo nos ayudan a ahorrar tiempo durante la integración de nuestra programación con la maquetación web.


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/validar-y-sanear-datos-en-php/' rel='bookmark' title='Permanent Link: Validar y sanear datos en PHP'>Validar y sanear datos en PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Introducción: Qué son y para qué sirven los Layouts en Zend Framework</h3>
<p>Cuando desarrollamos una aplicación nos damos cuenta que varias de las pantallas son básicamente iguales y lo único que cambia son los contenidos interiores de estos. Para muestra un pequeño y sencillo ejemplo:</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2010/12/layouts.png" alt=""></center></p>
<p>Como podemos ver en el ejemplo, estructuralmente no hay mucha diferencia entre las dos páginas. En la primera mostramos el home, mientras que en la segunda otro texto cualquiera. Las dos tienen un encabezado y un cuerpo, pero si nos fijamos bien, veremos que solo varía el cuerpo.</p>
<p>En el artículo anterior <a href="http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/">Empezado con Zend Framework</a>, colocamos en las vistas todo el html, desde las etiquetas &lt;html&gt; lo cual está bien porque funciona bien. Pero si tuviésemos una aplicación con más 100 vistas (algo que puede darse perfectamente), entonces no sería práctico. Si hiciéramos <strong>algún cambio</strong> en la <strong>maquetación</strong>, tendríamos que hacerlo en <strong>todas las vistas</strong>. Imáginénlo, nunca terminaríamos.</p>
<blockquote><p>Los layouts suelen ser una gran ayuda durante la integración del php y el html. Nos ahorran mucho trabajo y aunque no es obligatorio su uso, debería ser un estándar en nuestro trabajo con ZF</p></blockquote>
<p>Por suerte existen los layouts. Estos incrustarán todo el contenido colocado en la vista y además podrán tener el contenido de otros layouts. Podemos crear todos los layouts que necesitemos, sin límite.</p>
<h4>Declarando el layout</h4>
<p>Habrá un layout principal para toda la aplicación. La ubicación de estos, debido a que es parte de la aplicación, debería estar dentro de la carpeta de la aplicación, aunque es posible especificar cualquier otra. Esto lo podemos definir en el archivo application.ini de la siguiente manera:</p>
<pre name="code" class="php">
;resources.layout
resources.layout.layoutPath        = APPLICATION_PATH "layouts/scripts"
resources.layout.layout            = "home"
</pre>
<p>El nombre del archivo del layout será el que nosotros querramos. En nuestro ejemplo home.phtml pero en application.ini no colocaremos la extensión.</p>
<blockquote><p>Si no declaramos la ruta de los layouts, ZF los buscará en layouts/scripts dentro de la carpeta de la aplicación.</p></blockquote>
<p>A menudo podremos necesitar layouts para contenido xml o json, o talvez un layout en blanco. Eso dependerá de lo que necesitemos.</p>
<h3>Escribiendo un layout</h3>
<p>Veamos un sencillo ejemplo de cómo se escribe un layout:</p>
<pre name="code" class="php">
&lt;?php echo $this-&gt;doctype(); ?&gt;
&lt;html&gt;
&lt;head&gt;
&lt;?php
$this-&gt;headMeta()-&gt;appendHttpEquiv('Content-Type', 'text/html; charset='.$this-&gt;getEncoding())
-&gt;appendHttpEquiv('Content-Language', 'es-ES');
echo $this-&gt;headMeta();
$this-&gt;headLink()-&gt;appendStylesheet('/css/miestilo.css');
echo $this-&gt;headLink();
echo $this-&gt;headTitle();
$this-&gt;headScript()-&gt;appendFile('/js/common.js');
echo $this-&gt;headScript();
?&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
&lt;div&gt;&lt;?php echo $this-&gt;layout()-&gt;content; ?&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Como podemos ver, el ejemplo anterior contiene las cabeceras más importantes del html, pero la línea siguiente:</p>
<pre name="code" class="php">
&lt;?php echo $this-&gt;layout()-&gt;content; ?&gt;</pre>
<p>es la encargada de insertar el contenido de la vista en el layout. Absolutamente todo lo que esté en la vista, se guardará en la variable de layout content.</p>
<p>¿Qué ocurre con las demás líneas de código? Pues ellas traen contenido declarado en los controladores o en el bootstrap.php. Veamos ahora como sería nuestra vista:</p>
<pre name="code" class="php">&lt;?php echo $this-&gt;mensaje; ?&gt;
 &lt;br /&gt;
 que tal mi aplicacion en ontuts &lt;img src="http://web.ontuts.com/wp-includes/images/smilies/icon_razz.gif" alt=":P"&gt;</pre>
<p>Podemos notar que el código dentro de la vista se ha reducido a solamente lo que necesitamos de ella.</p>
<p>Es importante darnos cuenta de un detalle: <strong>$this-&gt;layout()-&gt;content;</strong> almacena el contenido de la vista, pero está dentro del ámbito <strong>$this-&bt;layout()</strong> y a este también podemos asignarle otros valores desde el controlador.</p>
<h3>Variable de layout</h3>
<p>Antes de continuar, quiero regresar unas lineas arribas y que se den cuenta de algo que he escrito y es muy interesante: <strong>variable de layout</strong>. ¿Y qué es una variable de layout? Desde los controladores, les podemos pasar a las vistas cierta información en forma de variable de vista.</p>
<p>Ya lo hemos visto antes así: $this-&gt;view-&gt;mensaje. ¿lo recuerdan? El problema está en que este valor es solo para una vista específica y para aquella en la que hemos llamado a su Action().</p>
<blockquote><p>Las <strong>variables de layout</strong> nos permitirán reutilizar los valores de las variables en las distintas vistas de nuestra aplicación, en lugar de estar disponibles para una única vista en particular.</p></blockquote>
<p>Por el contrario, una <strong>variable de layout</strong>, estará <strong>disponible en todas las vistas</strong>, sin importar el Action en el que estemos. Es decir, tiene un entorno más amplio. Noten que digo vistas. Las variables de layouts, se pueden utilizar en todos los layouts y en todas las vistas. Es decir, en todos los archivos .phtml.</p>
<p>Pero&#8230; ¿para qué quiero una variable de layout? Supongamos que me autentifico en mi aplicación y quiero que en ella aparezca mi nickname (nombre de usuario), siempre en todas las páginas. Podría almacenar ese dato en una variable de layout.</p>
<p>La forma en la que declarao esta variable es muy sencilla:</p>
<pre name="code" class="php">$this-&gt;layout-&gt;nickname = 'elericuz';</pre>
<p>Por otro lado, en el layout o en la vista, lo único que necesito hacer para mostrarla es imprimir su valor mediante la función echo():</p>
<pre name="code" class="php">echo $this-&gt;layout()-&gt;nickname;</pre>
<h3>Controlando los layouts</h3>
<p>Más arriba mencioné que a menudo podríamos necesitar utilizar diferentes layouts para diferentes tareas. Piensen que el diseño del home será diferente al diseño de las páginas internas. En ese caso al menos, necesitaremos 2 layouts: home.phtml y internas.phtml</p>
<p><strong>home.phtml</strong></p>
<pre name="code" class="html">
&lt;?php echo $this-&gt;doctype(); ?&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;?php echo $this-&gt;headMeta(); ?&gt;
    &lt;?php echo $this-&gt;headTitle(); ?&gt;
    &lt;?php echo $this-&gt;headStyle(); ?&gt;
    &lt;?php echo $this-&gt;headScript(); ?&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div style="text-align: center;"&gt;&lt;?php echo $this-&gt;layout()-&gt;content; ?&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p><strong>internas.phtml</strong></p>
<pre name="code" class="html">
&lt;?php echo $this-&gt;doctype(); ?&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;?php echo $this-&gt;headMeta(); ?&gt;
    &lt;?php echo $this-&gt;headTitle(); ?&gt;
    &lt;?php echo $this-&gt;headStyle(); ?&gt;
    &lt;?php echo $this-&gt;headScript(); ?&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div&gt;&lt;a href="&lt;?php echo WWW_ROOT; ?&gt;"&gt;Home&lt;/a&gt; | &lt;a href="&lt;?php echo WWW_ROOT; ?&gt;prueba"&gt;Otro link&lt;/a&gt;&lt;/div&gt;
    &lt;br /&gt;
    &lt;?php echo $this-&gt;layout()-&gt;content; ?&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>En application.ini le hemos indicado a ZF que utilice home.phtml como layout predeterminado. Solo nos faltaría indicarle a ZF que cuando no estemos en el home de nuestra aplicación use internas.phtml como layout. Eso lo hacemos en el controlador/función que queramos así:</p>
<pre name="code" class="php">
$options = array(
  'layout'	 =&gt; 'internas',
);
Zend_Layout::startMvc($options);
</pre>
<p>De esta forma podremos cambiar de layout según nuestras necesidades en cualquier momento de manera cómoda y sencilla.</p>
<h3>Reflexión Final</h3>
<p>Como hemos visto, los layouts nos ahorran muchas líneas de código y eso los convierte en una herramienta muy importante para nosotros.</p>
<p>Si bien esta ha sido una breve explicación de lo que es un layout, En el siguiente artículo explicaré cómo hacer una estructura de layout y desarrollarlo en forma programática, siempre orientado a objetos.</p>
<p>¡Nos vemos en la próxima publicación!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/tutorial-introduccion-zend-framework-php/' rel='bookmark' title='Permanent Link: Introducción a Zend Framework PHP'>Introducción a Zend Framework PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/acelerando-los-tiempos-de-carga-uniendo-archivos-javascript-con-php/' rel='bookmark' title='Permanent Link: Acelerando los tiempos de carga uniendo archivos Javascript con PHP'>Acelerando los tiempos de carga uniendo archivos Javascript con PHP</a></li>
<li><a href='http://web.ontuts.com/tutoriales/creando-servicios-de-red-tcp-con-php-y-xinetd/' rel='bookmark' title='Permanent Link: Creando servicios de red TCP con PHP y xinetd'>Creando servicios de red TCP con PHP y xinetd</a></li>
<li><a href='http://web.ontuts.com/tutoriales/validar-y-sanear-datos-en-php/' rel='bookmark' title='Permanent Link: Validar y sanear datos en PHP'>Validar y sanear datos en PHP</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/entendiendo-los-layouts-en-zend-framework-php/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Grails: Introducción a desarrollo web Java para &#8216;dummies&#8217;</title>
		<link>http://web.ontuts.com/tutoriales/grails-introduccion-a-desarrollo-web-java-para-dummies/</link>
		<comments>http://web.ontuts.com/tutoriales/grails-introduccion-a-desarrollo-web-java-para-dummies/#comments</comments>
		<pubDate>Thu, 25 Nov 2010 11:40:02 +0000</pubDate>
		<dc:creator>Enrique Medina</dc:creator>
				<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[opinión]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://web.ontuts.com/?p=6242</guid>
		<description><![CDATA[Artículo de introducción a la plataforma de desarrollo Grails. ¿Qué pasaría si uniéramos en una misma plataforma de desarrollo, por un lado, un lenguaje dinámico basado en Java, y por el otro, los frameworks más utilizados y aceptados en la comunidad de libre distribución? ¡La solución dentro de este artículo!


Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/introduccion-a-object-relational-mapping-orm/' rel='bookmark' title='Permanent Link: Introducción a Object-Relational Mapping (ORM)'>Introducción a Object-Relational Mapping (ORM)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/introduccion-a-cookies-en-la-web/' rel='bookmark' title='Permanent Link: Introducción a Cookies en la Web'>Introducción a Cookies en la Web</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<h3>Historia del desarrollo web en Java (para iniciados, sufridores y escépticos)</h3>
<p>Desde que el lenguaje <a title="Java" href="http://es.wikipedia.org/wiki/Plataforma_Java" target="_blank">Java</a> fue diseñado a principio de la década de los 90, el principal hueco que pretendió ocupar fue el de alternativa mucho más sencilla y portable al lenguaje C++ (principalmente en términos de gestión de memoria y librerías de clases). Posteriormente, con la aparición en el año 1993 de la <a title="WWW" href="http://es.wikipedia.org/wiki/World_Wide_Web" target="_blank">WWW</a>, Java (y Sun) se adelantó al resto de sus competidores y se convirtió ipso-facto en el estándar de desarrollo de aplicaciones web empresariales, donde actualmente comparte la mayor parte del nicho de mercado junto con la tecnología <a title="Microsoft .NET" href="http://es.wikipedia.org/wiki/Microsoft_.NET" target="_blank">.NET</a> de Microsoft.</p>
<blockquote><p>Inicialmente Java se convirtió en poco tiempo en el estándar de desarrollo de aplicaciones empresariales. Hoy comparte el puesto con .NET de Microsoft.</p></blockquote>
<p>Sin embargo, la evolución que Java ha ido experimentando en términos de facilidad de uso y productividad a la hora del desarrollo de aplicaciones, principalmente web, se ha visto seriamente comprometida desde sus inicios por los tediosos y burócratas procesos establecidos por Sun en torno a sus <a title="Java Community Process" href="http://www.jcp.org/en/home/index" target="_blank">JCPs</a> (Java Community Process) para producir JSRs (Java Specification Request), esto es, especificaciones estándar para la tecnología Java.</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2010/11/versus.png" alt="Java VS .NET" /></center></p>
<p>De esta forma, hasta hace sólo unos pocos años, eran las grandes empresas de software las encargadas de decidir qué, cómo y cuándo se podía aplicar una determinada tecnología mediante una especificación a la plataforma Java, en la mayoría de los casos, inexplicablemente compleja y enreversada, como lo prueban ejemplos de sus primeras criaturas denominadas EJBs (Enterprise Java Bean).</p>
<blockquote><p>La comunidad libre impulsó con una cantidad masiva de proyectos la plataforma Java, mejorándola y haciéndola mucho más potente con adaptaciones de todo tipo.</p></blockquote>
<p>Como no hay mal que por bien no venga (o como dicen mis amigos americanos, es una bendición disfrazada), y puesto que Java acuñó desde sus inicios una <a title="Licencia Java" href="http://www.java.com/es/download/license_jre5.jsp" target="_blank">licencia</a> de uso completo y sin modificaciones para la ejecución de programas, esta actitud provocó la masiva respuesta de la comunidad de libre distribución (open-source) en forma de una ingente cantidad de proyectos.</p>
<p>Estos proyectos intentaban complementar las deficiencias de Java como plataforma de desarrollo (cuidado, el lenguaje en sí siempre ha estado a la altura), tanto a nivel web (Struts, Tapestry, Velocity, etc.) como de acceso a datos (Hibernate, iBatis, etc.) o incluso gestión de dependencias (Spring, Guice, etc.). Muchos de estos proyectos open-source son ahora referentes y estándares de-facto en el desarrollo Java, por mucho que desde el comité de JCPs se empeñen en obviarlos (aunque cada vez menos, al césar lo que es del césar).</p>
<h3>Lenguajes dinámicos o cómo evitar la verbosidad del lenguaje</h3>
<p>Seamos sinceros; a mi me encanta el lenguaje Java, amo el lenguaje Java y para los que jugueteamos, años ha, con Cobol, Fortran, Prologue, OS/2, Clipper, Basic, C/C++ y algunos otros que ya ni quiero recordar, supuso un regalo en forma de tecnología orientada a objetos imposible de rechazar.</p>
<p>Estableciendo esta premisa inicial, la crítica constructiva (aunque a veces pase por destructiva) es un ejercicio de salud tecnológica al que no podemos renunciar, y seguramente en mis primeros desarrollos estaba cegado por el árbol que no me dejaba ver el bosque. Y es que ese bosque apareció delante de mi, por sorpresa, sin realmente buscarlo, cuando tuve noticias del proyecto <a href="http://groovy.codehaus.org/" target="_blank">Groovy</a>, un lenguaje dinámico para Java. </p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2010/11/groovy.png" alt="Groovy" /></center></p>
<p>Por entonces, yo ya me tenía que pelear en ocasiones con <a title="Javascript" href="http://es.wikipedia.org/wiki/JavaScript" target="_blank">Javascript</a> (que recordemos no tiene nada que ver con Java, pero incorpora mucha de su sintaxis orientada a objetos, por lo que sus autores probablemente utilizaron el &#8220;bombo y platillos&#8221; en torno a Java para establecer su nombre), y he de reconocer que sentía una envidia sana por sus características dinámicas y su débil (por no decir inexistente) tipado. Pero ante mi surgió Groovy y mi vida de desarrollador cambió radicalmente a mejor, a mucho mejor, a volver a disfrutar desarrollando. Y no exagero, ni un ápice.</p>
<blockquote><p>Groovy nos permite ejecutar código precompilado en Java y también código Java en Groovy sin compilación previa.</p></blockquote>
<p>Para aquellos que no conozcáis Groovy, se trata de un lenguaje de scripting, ágil y orientado a objetos, que nace, vive y muere en la propia máquina virtual de Java. Esto quiere decir que podemos ejecutar código Groovy (previamente compilado a código Java) desde Java, y Java (sin ningún tipo de proceso de compilación) directamente en Groovy, abriéndose ante nosotros las puertas al infinito y más allá. Aunque no es el objetivo de este artículo el detallar las bondades de Groovy, sí me voy a permitir un ejemplo muy gráfico por eso de que &#8220;una imagen vale más que mil palabras&#8221;:</p>
<h4>Ejemplo en Java</h4>
<pre name="code" class="java">
import java.util.List;
import java.util.ArrayList;

class Erase {
    private List removeLongerThan(List strings, in length) {
        List result = new ArrayList();
        for (int i = 0; i &lt; strings.size(); i++) {
            String s = (String) strings.get(i);
            if (s.length() &lt;= length) {
                result.add(s);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        List names = new ArrayList();
        names.add(&quot;Enrique&quot;); names.add(&quot;Adrian&quot;);
        names.add(&quot;Javier&quot;); names.add(&quot;Marisa&quot;);
        System.out.println(names);
        Erase e = new Erase();
        List shortNames = e.removeLongerThan(names, 6);
        System.out.println(shortNames.size());
        for (int i = 0; i &lt; shortNames.size(); i++) {
            String s = (String) shortNames.get(i);
            System.out.println(s);
        }
    }
}
</pre>
<h4>Ejemplo en Groovy</h4>
<pre name="code" class="java">
names = ["Enrique", "Adrián", "Javier", "Marisa"]
println names
shortNames = names.findAll{ it.size() &lt;= 3 }
println shortNames.size()
shortNames.each{ println it }
</pre>
<p>Como supongo ya habréis adivinado, ambos códigos producen exactamente el mismo resultado, sólo que si tuviérais que elegir uno, ¿con cuál os quedaríais? No me lo digáis, yo también.</p>
<h3>Grails: la búsqueda del grial&#8230; ¿ha concluido?</h3>
<p>Sin ser, ni pretender ser un buen estratega militar, el objetivo que perseguía con las dos primeras secciones de este artículo, era el de despertar la curiosidad del lector ante un escenario tan sumamente heterogéneo de tecnologías en torno a Java, pero a la vez tan aprovechable utilizando la perla dinámica de Groovy. Espero haberlo conseguido, y como ya no puedo ocultarlo más, pues aquí os presento a Grails, la plataforma de desarrollo (web) que ha cambiado mi aura programadora.</p>
<p><center><img src="http://web.ontuts.com/wp-content/uploads/2010/11/grails_logo.png" alt="grails logo" /></center></p>
<p>Y es que <a href="http://grails.org" target="_blank">Grails</a> es uno de esos proyectos que si no existiera habría que inventarlo, porque ha conseguido mediante unas de las técnicas más antiguas del desarrollo, el &#8220;no te repitas a ti mismo y no reinventes la rueda&#8221; (<a href="http://es.wikipedia.org/wiki/No_te_repitas" target="_blank">DRY</a>, en inglés), un framework &#8220;completo&#8221; (aunque a mi me gusta llamarlo plataforma) compuesto de la unión de otros frameworks &#8220;pegamento&#8221;. Veamos qué se esconde detrás de este ejercicio de verbilocuencia.</p>
<h4>Framework &#8220;completo&#8221; contra framework &#8220;pegamento&#8221; (en inglés, &#8216;full-stack&#8217; vs &#8216;glue&#8217; frameworks)</h4>
<ul>
<li>Un <strong>framework &#8220;completo&#8221;</strong> es aquel cuyos objetivo principal es proporcionar un conjunto simple de componentes que permitan cubrir el espectro completo de las necesidades requeridas para construir aplicaciones (web), y asegurar que dichos componentes trabajan y se integran de forma óptima unos con otros.
<li>Un <strong>framework &#8220;pegamento&#8221;</strong>, por el contrario, persigue proporcionar un conjunto de adaptadores y código de interfaz que permita gestionar los diferentes componentes en cada capa del desarrollo, y asegurar que dichos adaptadores funcionan correctamente con tantas combinaciones de los componentes como sea posible. Como ejemplo, un framework especializado o focalizado bien en una capa específica, como la capa de presentación (web), o la capa de acceso a datos.</li>
</ul>
<p>En Grails, no sólo se superan los objetivos marcados por un framework &#8220;completo&#8221; con matrícula de honor cum-laude, sino que se elevan a la máxima potencia otorgando al desarrollador una plataforma integrada de ejecución de los propios desarrollos, que además es intercambiable, y que permite el &#8220;cambio en caliente&#8221; del código (algo que muchos desarrolladores no-Java darán por sentado, pero que no estaba tan claro en el mundo Java, salvo con complicadas maniobras de <a href="http://www.fundacionlengua.com/es/arte-birlibirloque/art/149/" target="_blank">birlibirloque</a>). </p>
<blockquote><p>Otro punto a favor de Grails es la gran cantidad de plugins que permiten extender la funcionalidad base, son ya más de 500 y no dejan de crecer día a día.</p></blockquote>
<p>Y si esto no calmara nuestra avivada sed de curiosidad por si sólo, destacar que la arquitectura de Grails ha sido diseñada con orientación abierta y &#8220;enchufable&#8221;, de forma que existe un ecosistema de más de 500 plugins que permiten extender la funcionalidad de nuestra aplicación con el único techo de nuestra capacidad como desarrolladores. </p>
<h4>Diseccionando a Grails de arriba a abajo</h4>
<p>Quedaría este artículo huérfano, y similar a una zanahoria flotando eternamente a unos centímetros de la boca del asno (siempre en sentido figurado, que nadie se me ofenda), si no presentáramos las piezas que forman el puzzle mágico del que hablamos. Así, Grails es:</p>
<ul>
<li>Una <strong>capa de abstración</strong> denominada GORM para acceso a datos construida sobre el ORM (Object Relational Mapping) más utilizado por la comunidad Java (y otras muchas más): <a href="http://www.hibernate.org/" target="_blank">Hibernate</a>.</li>
<li>Una tecnología expresiva de <strong>presentación</strong> / vista, basada en <strong>plantillas</strong>, denominada <a href="http://groovy.codehaus.org/GSP" target="_blank">GSP</a> (Groovy Server Pages).</li>
<li>Una <strong>capa de control</strong> basada en <a href="http://www.springframework.org/" target="_blank"><strong>Spring MVC</strong></a>, reconocida como la mejor tecnología MVC del mercado.</li>
<li>Un entorno de <strong>scripting</strong> de línea de comando construido sobre <a href="http://groovy.codehaus.org/Gant" target="_blank">Gant</a>, una extensión <a href="http://ant.apache.org/" target="_blank">Ant</a> basada en <strong>Groovy</strong>.</li>
<li>Un contenedor <a href="http://tomcat.apache.org/" target="_blank"><strong>Tomcat</strong></a> embebido, configurado para la recarga &#8220;en caliente&#8221; (fly reloading).</li>
<li>Gestión de <strong>inyección por dependencia</strong> (<a href="http://es.wikipedia.org/wiki/Inyecci%C3%B3n_de_dependencias" target="_blank">DI</a>) mediante el contenedor de Spring.</li>
<li>Soporte para <strong>internacionalización</strong> / localización (<a href="http://es.wikipedia.org/wiki/Internacionalizaci%C3%B3n_y_localizaci%C3%B3n" target="_blank">i18n</a>) a partir del concepto <em><a href="http://static.springsource.org/spring/docs/3.0.5.RELEASE/javadoc-api/org/springframework/context/MessageSource.html" target="_blank">MessageSource</a></em> de Spring.</li>
<li><strong>Gestión transaccional</strong> &#8220;gratuita&#8221; basada en la abstracción transaccional de <a href="http://static.springsource.org/spring/docs/3.0.5.RELEASE/javadoc-api/org/springframework/transaction/package-frame.html" target="_blank">Spring</a>.</li>
</ul>
<p>Y recordemos, todas estas piezas sólo como núcleo principal o plataforma, sin olvidar la posibilidad ya comentada de inyectar todo tipo de plugins con todo tipo de funcionalidades: búsqueda &#8220;full-text&#8221; con Lucene/Solr, integración social con Facebook/Twitter/Tuenti, almacenes NoSQL como MongoDB, GemFire, Redis, CouchDB, seguridad integrada de autenticación/autorización con Spring Security, librerías de widgets gráficos RIA, y un largo etcétera sólo por nombrar unos pocos. Encuentra <a href="http://www.grails.org/plugin/home" target="_blank">aquí</a> la lista completa.</p>
<h3>Conclusión</h3>
<p>Existen múltiples y variados frameworks Java de desarrollo que proporcionan algunas de las piezas del puzzle web, pero se echaba en falta un pegamento que permitiera aglutinarlas en una plataforma &#8220;completa&#8221; y &#8220;extensible&#8221; de desarrollo.</p>
<p>Grails ha conseguido este objetivo combinando el lenguaje dinámico Groovy con aquellas tecnologías abiertamente aceptadas como estándares de-facto en la comunidad Java. El &#8220;grial&#8221; Java ya está aquí, y ha venido para quedarse.</p>
<p>Si quieres ver una aplicación real en acción, <strong>deja tu comentario</strong> y anímame a ponerme a escribir un tutorial de desarrollo en Grails.</p>
<p>¡Nos vemos en el próximo artículo!</p>


<p>Related posts:<ol><li><a href='http://web.ontuts.com/tutoriales/introduccion-a-object-relational-mapping-orm/' rel='bookmark' title='Permanent Link: Introducción a Object-Relational Mapping (ORM)'>Introducción a Object-Relational Mapping (ORM)</a></li>
<li><a href='http://web.ontuts.com/tutoriales/introduccion-a-cookies-en-la-web/' rel='bookmark' title='Permanent Link: Introducción a Cookies en la Web'>Introducción a Cookies en la Web</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://web.ontuts.com/tutoriales/grails-introduccion-a-desarrollo-web-java-para-dummies/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

