<?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>Cerebro en la Sombra &#187; Proyectos</title>
	<atom:link href="http://blog.osusnet.com/category/proyectos/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.osusnet.com</link>
	<description></description>
	<lastBuildDate>Fri, 30 Jul 2010 11:50:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso</title>
		<link>http://blog.osusnet.com/2010/04/21/nuevo-proyecto-en-5-horas-usaytira-me-direcciones-de-correo-de-usar-y-tirar-explicado-paso-a-paso/</link>
		<comments>http://blog.osusnet.com/2010/04/21/nuevo-proyecto-en-5-horas-usaytira-me-direcciones-de-correo-de-usar-y-tirar-explicado-paso-a-paso/#comments</comments>
		<pubDate>Wed, 21 Apr 2010 19:46:35 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[qmail]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=4140</guid>
		<description><![CDATA[Parece que últimamente me aburro mucho . Hace unos días, leyendo un artículo, se me ocurrió de nuevo explicar cómo se hacen esos sistemas de correo instantáneos que se suelen utilizar para registrarse en webs y que después no te envíen spam . La idea me pareció muy adecuada para poner un ejemplo práctico de [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Parece que últimamente me aburro mucho <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" /> . Hace unos días, leyendo un artículo, se me ocurrió de nuevo explicar cómo se hacen esos sistemas de correo instantáneos que se suelen utilizar para registrarse en webs y que después no te envíen spam <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" /> . La idea me pareció muy adecuada para poner un ejemplo práctico de algo que vimos hace tiempo sobre <a href="http://blog.osusnet.com/2008/12/31/otras-utilidades-para-un-servidor-de-correo/">otras utilidades para un servidor de correo</a> y, tal y como me ocurrió hace unos meses, lo que <a href="http://blog.osusnet.com/2009/11/24/de-articulo-a-proyecto-explicado-paso-a-paso-acorta-urls-con-iraurl-me/">era un artículo se convierte en proyecto</a>.</p>
<p><a href="http://blog.osusnet.com/wp-content/uploads/2010/04/usaytirame1.gif"><img class="aligncenter size-full wp-image-4143" title="usaytirame1" src="http://blog.osusnet.com/wp-content/uploads/2010/04/usaytirame1.gif" alt="usaytirame1 Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" width="470" height="300" /></a></p>
<p>La idea, por tanto, es crear un sistema que, <strong>sin necesidad de ningún registro</strong>, te permita crear una cuenta de correo y recibir y leer <em>emails </em>en ella por espacio de <strong>una hora</strong>, al cabo de este tiempo la cuenta se <em><strong>auto</strong></em><em><strong>destruye</strong> </em>y todos los <em>emails </em>serán devueltos. En nuestra aplicación tendremos dos opciones para crear la cuenta, aleatoria o personalizada, creo que no hacen falta más explicaciones. Una vez usas una cuenta puedes volver a ella más tarde cuando la necesites volviendo a crear una cuenta personalizada con el mismo usuario. Esto es útil, por ejemplo, para que te recuerden la contraseña que utilizaste para registrar en aquella web de descarga de películas y de la que ya no te acuerdas <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" /> .</p>
<h3>Qué necesitamos</h3>
<ul>
<li>Servidor Linux con <a href="http://qmail.org">Qmail</a> como MTA.</li>
<li>Apache, PHP y MySQL.</li>
<li><a href="http://pear.php.net/package/Mail_mimeDecode">Pear MimeDecode</a>: para procesar los correos entrantes con PHP.</li>
<li>Una plantilla superchula de <a href="http://www.freecsstemplates.org/">FreeCssTemplates</a></li>
<li><a href="http://jquery.com/">Jquery</a>: para todo lo que es <em>ajax </em>y <em>Javascript</em></li>
<li><a href="http://code.google.com/p/zeroclipboard/">ZeroClipboard</a>:  para copiar y pegar automáticamente</li>
<li><a href="http://plugins.jquery.com/project/ScrollTo">Jquery ScrollTo</a>: pluggin para desplazar el <em>scroll </em>automáticamente.</li>
<li>Una imagen de &#8220;Cargando&#8221; para las acciones <em>ajax </em>que personalizas <a href="http://www.ajaxload.info/">aquí</a>.</li>
<li>Diccionarios de palabras &#8220;aleatorias&#8221;. <a href="http://www.elhacker.org/index.php?Ver=Seccion&amp;Id=15">Aquí</a> hay unos cuantos.</li>
<li><a href="http://adodb.sourceforge.net/">Adodb</a> (opcional) para el acceso a base de datos.</li>
</ul>
<p>Eso es todo, sólo hay que juntar las piezas adecuadamente.</p>
<h3>Preparando Qmail</h3>
<p>Nuestro primer paso, antes de ponernos con los temas puramente web, será configurar adecuadamente el servidor de correo para nuestro propósito. Para ello necesitamos crear un usuario del sistema que reciba todo el correo dirigido a un dominio. Esto lo podemos hacer del siguiente modo:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">adduser -g <span class="kw2">users</span> -s /dev/null usaytirame</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">passwd</span> usaytirame UNACLAVESUPERCOMPLICADA</div>
</li>
</ol>
</div>
<p>Añadimos nuestro nombre de host en:</p>
<p><strong>/var/qmail/control/rcpthosts</strong></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">usaytira.me</div>
</li>
</ol>
</div>
<p>Y el usuario al que dirigiremos los correos en:</p>
<p><strong>/var/qmail/control/virtualdomains</strong></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">usaytira.me:usaytirame</div>
</li>
</ol>
</div>
<p>Reiniciando <strong>Qmail </strong>conseguiremos que los correos enviados a cualquier cuenta del dominio vayan al buzón del usuario indicado, es decir <em>cualquiercosa<strong>[arroba]</strong>usaytira.me</em>.</p>
<p>Pero no queremos que los correos vayan al buzón del usuario sino simplemente procesarlos. Para eso editamos el archivo:</p>
<p><strong>/home/usaytirame/.qmail-default</strong></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">|preline /usr/bin/php /home/usaytirame/procesa.php</div>
</li>
</ol>
</div>
<p>Sólo con esa línea. Con este comando conseguimos redirigir los correos entrantes a un <em>script </em>en el que podremos recuperarlos y reutilizarlos a nuestro antojo como veremos a continuación.</p>
<h3>Procesando los emails entrantes</h3>
<p>Vamos a comenzar por crear una base de datos donde guardaremos los emails recibidos. Como queremos poder acceder a los emails dirigidos a cada cuenta independientemente, haremos dos tablas, una (<em>emails</em>) la utilizaremos como tabla maestra para las cuentas de correo que se creen y en la otra (<em>correos</em>) iremos almacenando los emails recibidos para cada una de esas cuentas.  La estructura sería poco más o menos la siguiente:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">CREATE TABLE IF NOT EXISTS `emails` <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; `idEmail` int<span class="br0">&#40;</span><span class="nu0">11</span><span class="br0">&#41;</span> NOT NULL auto_increment,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `fecha` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `email` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; `ip` varchar<span class="br0">&#40;</span><span class="nu0">15</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; PRIMARY KEY &nbsp;<span class="br0">&#40;</span>`idEmail`<span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; KEY `email` <span class="br0">&#40;</span>`email`<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#41;</span> <span class="re2">ENGINE=</span>MyISAM &nbsp;DEFAULT <span class="re2">CHARSET=</span>utf8 <span class="re2">AUTO_INCREMENT=</span><span class="nu0">1</span> ;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">CREATE TABLE IF NOT EXISTS `correos` <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; `<span class="kw2">id</span>` int<span class="br0">&#40;</span><span class="nu0">11</span><span class="br0">&#41;</span> NOT NULL auto_increment,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `idEmail` int<span class="br0">&#40;</span><span class="nu0">11</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `de` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `para` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; `subject` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `fecha` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `body` text NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `fullmail` text NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; PRIMARY KEY &nbsp;<span class="br0">&#40;</span>`<span class="kw2">id</span>`<span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; KEY `idEmail` <span class="br0">&#40;</span>`idEmail`<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#41;</span> <span class="re2">ENGINE=</span>MyISAM &nbsp;DEFAULT <span class="re2">CHARSET=</span>utf8 <span class="re2">AUTO_INCREMENT=</span><span class="nu0">1</span> ;</div>
</li>
</ol>
</div>
<p>Creo que es suficientemente descriptiva. El campo <em>fecha</em> de <em>emails</em> nos servirá para controlar los 60 minutos de duración máxima.</p>
<p>Pues ya tenemos todo preparado. Veamos cómo procesamos los emails.</p>
<p><strong>/home/usaytirame/procesa.php</strong></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">include</span> <span class="br0">&#40;</span><span class="st0">&quot;mimeDecode.php&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$email</span>=<a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span><span class="st0">&quot;php://stdin&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$email</span>=<a href="http://www.php.net/implode"><span class="kw3">implode</span></a><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span>, <span class="re0">$email</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$params</span><span class="br0">&#91;</span><span class="st0">&#8216;include_bodies&#8217;</span><span class="br0">&#93;</span> = <span class="kw2">true</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$params</span><span class="br0">&#91;</span><span class="st0">&#8216;decode_bodies&#8217;</span><span class="br0">&#93;</span> = <span class="kw2">true</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$params</span><span class="br0">&#91;</span><span class="st0">&#8216;decode_headers&#8217;</span><span class="br0">&#93;</span> = <span class="kw2">true</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$params</span><span class="br0">&#91;</span><span class="st0">&#8216;input&#8217;</span><span class="br0">&#93;</span> = <span class="re0">$email</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$structure</span> = Mail_mimeDecode::<span class="me2">decode</span><span class="br0">&#40;</span><span class="re0">$params</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$subject</span> = <a href="http://www.php.net/quoted_printable_decode"><span class="kw3">quoted_printable_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$structure</span>-&gt;<span class="me1">headers</span><span class="br0">&#91;</span><span class="st0">&#8216;subject&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$ddate</span> = <a href="http://www.php.net/quoted_printable_decode"><span class="kw3">quoted_printable_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$structure</span>-&gt;<span class="me1">headers</span><span class="br0">&#91;</span><span class="st0">&#8216;date&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$from</span> = <a href="http://www.php.net/quoted_printable_decode"><span class="kw3">quoted_printable_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$structure</span>-&gt;<span class="me1">headers</span><span class="br0">&#91;</span><span class="st0">&#8216;from&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$to</span> = <a href="http://www.php.net/quoted_printable_decode"><span class="kw3">quoted_printable_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$structure</span>-&gt;<span class="me1">headers</span><span class="br0">&#91;</span><span class="st0">&#8216;to&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/ereg"><span class="kw3">ereg</span></a><span class="br0">&#40;</span><span class="st0">&quot;&lt;(.*)&gt;&quot;</span>, <span class="re0">$to</span>, <span class="re0">$p</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$to</span>=<span class="re0">$p</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$to</span>=<a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">&#40;</span><span class="re0">$to</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Tenemos la primera parte del procesado preparada. De aquí debemos destacar:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$email</span>=<a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span><span class="st0">&quot;php://stdin&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Con esto leemos desde la entrada estandar el contenido del email. Recordad que no estamos en una <em>aplicación web</em> sino en un <em>script</em> ejecutado en la <strong>consola del sistema</strong>.</p>
<p>La otra línea importante es:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$structure</span> = Mail_mimeDecode::<span class="me2">decode</span><span class="br0">&#40;</span><span class="re0">$params</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Con ella conseguimos procesar el email y separar su estructura en un <em>array asociativo</em> con los distintos parámetros. Os ayudará mucho ver el contenido de ese <em>array</em>:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><a href="http://www.php.net/print_r"><span class="kw3">print_r</span></a><span class="br0">&#40;</span><span class="re0">$structure</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Llegados a este punto podemos hacer una prueba. Necesitamos el contenido completo de un email, podemos sacarlo de nuestro cliente de correo o del propio servidor.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">cat</span> prueba.eml | /home/usaytirame/procesa.php</div>
</li>
</ol>
</div>
<p>Si todo ha ido bien veremos en pantalla un array con la estructura del correo.</p>
<p>No voy a detallar todo el proceso ya que alargaría mucho el artículo. Vamos con el siguiente paso:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$query</span>=<span class="st0">&quot;select idEmail from emails where email=&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">quote</span><span class="br0">&#40;</span><span class="re0">$to</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$rs</span>-&gt;<span class="me1">recordcount</span><span class="br0">&#40;</span><span class="br0">&#41;</span>==<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a><span class="br0">&#40;</span><span class="nu0">100</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$idEmail</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">&#8216;idEmail&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$content</span> = get_content<span class="br0">&#40;</span><span class="re0">$structure</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;insert into correos</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(idEmail, de, para, subject, fecha, body, fullmail)</span></div>
</li>
<li class="li2">
<div class="de2"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  VALUES</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ($idEmail,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$from</span><span class="br0">&#41;</span>.<span class="st0">&quot;,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$to</span><span class="br0">&#41;</span>.<span class="st0">&quot;,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$subject</span><span class="br0">&#41;</span>.<span class="st0">&quot;,</span></div>
</li>
<li class="li2">
<div class="de2"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$ddate</span><span class="br0">&#41;</span>.<span class="st0">&quot;,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$content</span><span class="br0">&#41;</span>.<span class="st0">&quot;,</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span>.<span class="re0">$conn</span>-&gt;<span class="me1">Quote</span><span class="br0">&#40;</span><span class="re0">$email</span><span class="br0">&#41;</span>.<span class="st0">&quot;)&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>En la primera parte del <em>script </em>comprobamos si la cuenta a la que va destinado el email existe en nuestra base de datos, si no, muy importante, <strong>devolvemos un código 100</strong> que indica a <strong>qmail </strong>que debe devolver el correo ya que no existe el usuario.</p>
<p>Si la cuenta existe recogemos el cuerpo del mensaje. Yo lo hago con la función <strong>get_content</strong>, que analiza la estructura del correo y devuelve el contenido. Esta parte os la dejo a vosotros. Básicamente consiste en comprobar las distintas partes que puede tener un correo y devolver lo que estimemos oportuno. Un detalle muy importante a tener en cuenta es la <strong>codificación</strong> tanto del email como de nuestra base de datos y la aplicación web. En mi caso las dos últimas están en <strong>UTF-8</strong>, con lo que debo convertir todos los textos del email a esta misma codificación. La estructura que teníamos inicialmente en un array tendrá parámetros que nos indican el <em><strong>charset</strong></em> en el que viene el email. Las funciones de conversión de PHP te pueden ser útiles: <strong>iconv</strong>, <strong>utf8_encode</strong>, etc.Finalmente introducimos todos los campos del email en la base de datos.</p>
<p>Puedes volver a probar a procesar el email de prueba tal y como hicimos antes. Recuerda que debes añadir el registro de la tabla emails para que  guarde el correo, si no la cuenta no existirá. Una vez te funcione desde la línea de comandos ya puedes probar a enviarte un correo real <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" /> .</p>
<h3>La aplicación web</h3>
<p>No creo que hacer la parte <em>web</em> propiamente dicha necesite muchas explicaciones. Tenemos ya todos los elementos preparados, sólo debemos añadir los formularios para crear la cuenta de correo (aleatoria o personalizada) y, con un poco de <em>ajax</em>, ir cargando los correos a medida que van llegando. No  hay más truco.</p>
<p>Añadiré, eso sí, algunas aclaraciones interesantes.</p>
<p>Para crear las cuentas aleatorias, en vez de utilizar una secuencia aleatoria de números y letras, que daría como resultado algo ininteligible, usamos los <strong>diccionarios</strong> que comentaba más arriba. Los importamos en una tabla de la base de datos y simplemente tenemos que buscar aleatoriamente una palabra que no esté utilizada todavía como cuenta de correo, sencillo y muy impactante visualmente ya que estás ofreciendo cuentas legibles y con sentido.</p>
<p>Como en cualquier otra aplicación accesible públicamente, hay que añadir algún tipo de mecanismo de seguridad. En mi caso lo he hecho implementando una <strong>blacklist</strong> de direcciones IP. Cada vez que se crea una cuenta actualizo en una base de datos el número de cuentas que se han creado desde esa IP, si pasa del límite que estimemos oportuno, esa IP se pasa a la tabla de lista negra y cuando intente crear una nueva cuenta no se le dejará.</p>
<p>Nos falta una cosa: <strong>Eliminar las cuentas que tienen más de una hora</strong>. Muy sencillo, una tarea en el <a href="http://es.wikipedia.org/wiki/Cron_%28Unix%29">CRON</a> que ejecuta un <em>script </em>que lanza una consulta a la base de datos que elimina las cuentas (y sus correos asociados) que se crearon hace más de 60 minutos.</p>
<p>Finalmente he añadido la opción de reiniciar esos 60 minutos de tiempo, simplemente actualizando el <em>timestamp </em>de la base de datos y algunos efectos visuales para plegar y desplegar los mensajes usando <strong>Jquery</strong>.</p>
<p>No hay mucho más, en unas <strong>cinco horas</strong> tenemos la aplicación hecha y funcionando.</p>
<h3>Conclusiones</h3>
<p>Como conclusión, <a href="http://blog.osusnet.com/2009/11/24/de-articulo-a-proyecto-explicado-paso-a-paso-acorta-urls-con-iraurl-me/">la misma que hice hace unos meses con el primer proyecto</a>. La copio tal cual porque es igual de válida.</p>
<p>Bueno, y todo este rollo ¿<strong>para qué</strong>?. Pues muy sencillo, para que veais que hoy en día la tecnología está al alcance de todos, es sencillo y rápido crear un proyecto en <strong>Internet</strong>, hay de todo por todas las esquinas, la tecnología no es lo importante, lo que verdaderamente cuenta es cómo mueves ese producto tecnológico para rentabilizarlo y obtener un beneficio de él.</p>
<p>Ya tengo mi proyecto superchulo funcionando, sólo me ha costado unas 5 horas de trabajo. Le he puesto un poco de <strong>Adsense </strong>por aquí y por allí. ¿Y ahora qué? ¿A esperar a que la gente entre y me haga millonario? <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" />  Es mucho más complicado que eso como todos sabéis, primero tienes que tener una masa de usuarios elevada que le dé movimiento al proyecto y después tienes que conseguir que la mayoría de ellos sean gente normal, no gente técnica, usuarios avanzados que no pagamos por nada ni pinchamos en publicidad <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" />  .</p>
<p>Hoy en día, en Internet, como en cualquier negocio, <strong>las técnicas de marketing y venta son mucho más importantes que la tecnología en sí misma</strong>, es duro reconocerlo, pero es así. De nada sirve que tengas el mejor producto del mundo mundial si no consigues que la gente lo utilice y se deje dinero, así de claro. Si tienes los conocimientos adecuados para mover el negocio, no te preocupes, la tecnología te la aporta cualquier partner por un módico precio, pero poner en manos de otro toda la estrategia de ventas de tu negocio no está tan claro ¿no?.</p>
<p>Espero que os sirva de algo el artículo. He querido mostrar, fundamentalmente, cómo utilizando algunas librerías que puedes obtener sin coste puedes hacer algo realmente útil y funcional con muy poco esfuerzo. Seguro que sacáis alguna idea.</p>
<p>Perdón por el rollo <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso" />  , al final me ha costado mucho más escribir el artículo que implementarlo.</p>
<p>Podíamos haber añadido una opción que he visto por ahí que consiste en crear una cuenta automáticamente cada vez que entra un email para una cuenta que no existe, pero estaríamos creando cuentas para todo el spam que recibamos, así que prefiero no hacerlo. Si quisierais hacerlo creo que ya sabéis cómo.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2010/04/21/nuevo-proyecto-en-5-horas-usaytira-me-direcciones-de-correo-de-usar-y-tirar-explicado-paso-a-paso/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Usando Amazon S3 como sistema de backup</title>
		<link>http://blog.osusnet.com/2010/04/13/usando-amazon-s3-como-sistema-de-backup/</link>
		<comments>http://blog.osusnet.com/2010/04/13/usando-amazon-s3-como-sistema-de-backup/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 15:44:15 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Sistemas]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[backups]]></category>
		<category><![CDATA[rsync]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=4084</guid>
		<description><![CDATA[Estoy tratando de mejorar el sistema de backups que utilizo habitualmente usando Amazon S3 como plataforma de almacenamiento. S3 (así como otros servicios Cloud de Amazon) tienen dos ventajas importantes, por un lado la disponibilidad, del orden del 99,99% y por otro el precio, altamente competitivo, cobran por espacio utilizado y por peticiones realizadas pero [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Estoy tratando de mejorar el sistema de <strong>backups</strong> que utilizo habitualmente usando <a href="http://aws.amazon.com/s3/">Amazon S3</a> como plataforma de almacenamiento. <strong>S3</strong> (así como otros servicios <em>Cloud </em>de Amazon) tienen dos ventajas importantes, por un lado la disponibilidad, del orden del 99,99% y por otro el precio, altamente competitivo, cobran por espacio utilizado y por peticiones realizadas pero aún así sale por un precio espectacular.</p>
<p>Nuestro backup es del orden de 40gb, y, si el sistema va bien, planeo utilizarlo también para <strong>backups </strong>personales (fotos sobre todo <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Usando Amazon S3 como sistema de backup" /> ).</p>
<p>El requerimiento básico es que la sincronización se realizará de manera automatizada desde un servidor Linux con lo que el sistema debe permitir el envío desatentido.</p>
<p>Buscando por ahí como hacerlo encontré <a href="http://code.google.com/p/s3fs/wiki/FuseOverAmazon">FuseOverAmazon</a>, un sistema basado en <a href="http://fuse.sourceforge.net/">Fuse</a> que permite montar un &#8220;<em>bucket</em>&#8221; de <strong>S3</strong> como si fuese una unidad local y sobre la que posteriormente podríamos utilizar <a href="http://samba.anu.edu.au/rsync/">rsync</a>. ¿Qué más se puede pedir? Dicho y hecho, vamos a probarlo. En mi caso utilizo <a href="http://centos.org/">CentOS</a>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">yum <span class="kw2">install</span> fuse fuse-devel curl-devel libxml2-devel</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">wget</span> http://s3fs.googlecode.com/files/s3fs-r191-<span class="kw3">source</span>.<span class="kw2">tar</span>.gz</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">tar</span> xvfz s3fs-r191-<span class="kw3">source</span>.<span class="kw2">tar</span>.gz</div>
</li>
<li class="li1">
<div class="de1"><span class="kw3">cd</span> s3fs</div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">make</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">make</span> <span class="kw2">install</span></div>
</li>
</ol>
</div>
<p>Vamos a probarlo.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">/usr/bin/s3fs nombrebucket -o <span class="re2">accessKeyId=</span>TUACCESSKEYID -o <span class="re2">secretAccessKey=</span>TUSECRETKEY /mnt/s3</div>
</li>
</ol>
</div>
<p>Si todo ha ido bien tendrás montado en <em>/mnt/s3</em> tu &#8220;<em>nombrebucket</em>&#8221; y podrás listar los archivos, copiar, eliminar, etc., como si fuese una unidad del equipo. Hasta aquí todo ha ido bien.  Sólo nos queda sincronizar nuestro <em>backup</em>:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">/usr/bin/rsync -avz &#8211;delete /usr1 /mnt/s3</div>
</li>
</ol>
</div>
<p>Y aquí es donde viene el problema. En mi caso han pasado 4 días y aún no ha pasado del 10% de la sincronización, funciona todo bien pero la sincronización es extremadamente lenta, no sé si estoy haciendo algo mal, si es normal, o no, pero es imposible de utilizar así.</p>
<p>Como la idea no ha sido del todo buena, tenemos un <em>plan B</em>. Se trata de utilizar <a href="http://s3sync.net/wiki">s3sync</a>, un script en Ruby que hace el proceso muy sencillo, sólamente hay que configurarlo indicando tus datos de acceso y a funcionar:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">s3sync -r /mnt/backup nombrebucket:prefijo</div>
</li>
</ol>
</div>
<p>Donde &#8220;<em>prefijo</em>&#8221; puede ser nulo.</p>
<p>Esto enviará a <em>nombrebucket/prefijo/</em> tu backup.  De momento las pruebas son mucho más satisfactorias que con <strong>s3fs</strong>, la velocidad se puede considerar más que adecuada, sobre todo comparada con el anterior.</p>
<p>Como decía, de momento estoy probando el rendimiento y la velocidad, pero no estoy del todo convencido, así que estoy pensando en utilizar <a href="http://aws.amazon.com/ec2/">Amazon EC2</a> en vez de <a href="http://aws.amazon.com/s3/">S3</a>, de manera que lanzando una instancia de una máquina virtual pueda hacer un <strong>rsync </strong>clásico contra un sistema de ficheros <em>de verdad</em>. La ventaja es que la máquina virtual puedo lanzarla sólo cuando la necesite y pararla después, con lo que con una hora diaria podría ser suficiente, recordemos que <em>Amazon EC2</em> cuesta, entre otras cosas, por cada hora que utilizas la instancia. Adicionalmente se podría hacer después un volcado del <strong>backup </strong>desde<strong> EC2</strong> a <strong>S3</strong>, pero en nuestro caso los 40gb sería una limitación que encarecería el precio considerablemente aún en el caso de utilizar rotaciones semanales.</p>
<p>Ya os contaré <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Usando Amazon S3 como sistema de backup" /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2010/04/13/usando-amazon-s3-como-sistema-de-backup/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me</title>
		<link>http://blog.osusnet.com/2009/11/24/de-articulo-a-proyecto-explicado-paso-a-paso-acorta-urls-con-iraurl-me/</link>
		<comments>http://blog.osusnet.com/2009/11/24/de-articulo-a-proyecto-explicado-paso-a-paso-acorta-urls-con-iraurl-me/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 15:54:00 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[acortar]]></category>
		<category><![CDATA[proyecto]]></category>
		<category><![CDATA[urls]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=3015</guid>
		<description><![CDATA[Hace un par de semanas me encontré con la necesidad de utilizar uno de esos sistemas que hay por ahí para acortar URL&#8216;s. Necesitaba enviar una dirección por SMS y tenía que ocupar la menor cantidad de caracteres posible por aquello de optimizar el texto del mensaje. Mientras lo utilizaba pensaba en lo ingenioso de [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Hace un par de semanas me encontré con la necesidad de utilizar uno de esos sistemas que hay por ahí para acortar <em>URL</em>&#8216;s. Necesitaba enviar una dirección por <strong>SMS </strong>y tenía que ocupar la menor cantidad de caracteres posible por aquello de optimizar el texto del mensaje. Mientras lo utilizaba pensaba en lo ingenioso de utilizar un sistema de numeración base36 para reducir exponencialmente el número de caracteres de la redirección. Esto iba a ser, pues, un artículo sobre las ventajas de los sistemas de numeración distintos al decimal para determinados proyectos, pero se acabó convirtiendo en un proyecto completo. Cuando estaba comenzando la explicación teórica pensé, ¿por qué no hacerlo? ¿por qué no demostrar lo rápido y fácil que se puede montar algo en Internet hoy en día?</p>
<p>Así, tras unas 15 horas de trabajo os presento <a href="http://iraurl.me">IraUrl.me</a>, un acortador de URL&#8217;s al estilo de <a href="http://tinyurl.com/">TinyUrl</a> o <a href="http://bit.ly/">Bit.ly</a>. Me ha costado más escribir el artículo que hacerlo realidad, curioso ¿eh?. En realidad a medida que iba preparando la aplicación se me iban ocurriendo más cosas que sería interesante montar, por lo que las 8 horas iniciales, más o menos, se convirtieron en 15.</p>
<p><a href="http://iraurl.me"><img class="aligncenter size-full wp-image-3075" title="iraurl" src="http://blog.osusnet.com/wp-content/uploads/2009/11/iraurl1.gif" alt="iraurl1 De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" width="470" height="335" /></a></p>
<h3>La teoría</h3>
<p>Para el que no lo sepa, un acortador de <em>URL</em> se basa en encontrar un dominio lo más corto posible y crear redirecciones <a href="http://en.wikipedia.org/wiki/HTTP_301">HTTP 301</a> a otras <em>URL</em>&#8216;s. El truco está en optimizar los parámetros que añadiremos a la <em>URL </em>para que sean lo más cortos posible, no queremos que éstos nos penalicen lo corto del dominio.</p>
<p>¿Cómo funcionan entonces estos acortadores de <em>URL</em>&#8216;s? Mucho más fácil de lo que parece y seguramente como a ti se te habría ocurrido. Simplemente tenemos una base de datos donde vamos añadiendo registros a una tabla a medida que se van creando nuevas URL&#8217;s cortas.  Esta tabla tiene un campo autonumérico, la clave de la tabla, que para cada nueva <em>URL </em>nos devuelve un identificador único, con lo que cada dirección podría ser accesible de la manera habitual:</p>
<p><strong>http://dominio.com/1</strong></p>
<p><strong>http://dominio.com/1000000</strong></p>
<p>Esa es exactamente la idea, lo único que hacemos es cambiar el identificador en cuestión de <a href="http://es.wikipedia.org/wiki/Sistema_decimal">base10</a> (la de nuestro sistema métrico decimal) a <a href="http://en.wikipedia.org/wiki/Base36">base36</a> o <a href="http://en.wikipedia.org/wiki/Base62">base62</a> en mi caso. Otros sistemas de numeración conocidos son el <a href="http://en.wikipedia.org/wiki/Base16">hexadecimal (base16)</a> y <a href="http://es.wikipedia.org/wiki/Base64">base64</a>.</p>
<p>Vale, ya has hablado en chino. ¿De qué va esto? Veamos.</p>
<h3>Sobre bases de numeración</h3>
<p>El sistema<strong> decimal</strong> utiliza diez dígitos (de ahí lo de decimal <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> ) para formar todas las combinaciones de números posibles. Lo que ya conocemos, vamos. El <strong>binario</strong> utiliza dos dígitos (0 y 1), el <strong>hexadecimal</strong> 16 (0..9ABCDE), <strong>base36</strong>, como su nombre indica, treinta y seis (0..9a..z) y <strong>base62</strong> utiliza los 62 dígitos que comprenden los números del 0 al 9 y las letras de la A a la Z en mayúsculas y minúsculas (0..9a..zA..Z). Veamos unos ejemplos:</p>
<table style="border: 1px none; height: 202px;" border="0" width="470">
<thead>
<tr>
<td><span style="color: #808080;"><strong>Binario</strong></span></td>
<td><span style="color: #808080;"><strong>Decimal</strong></span></td>
<td><span style="color: #808080;"><strong>Hexadecimal</strong></span></td>
<td><span style="color: #808080;"><strong>Base36</strong></span></td>
<td><span style="color: #808080;"><strong>Base62</strong></span></td>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>10</td>
<td>2</td>
<td>2</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>1010</td>
<td>10</td>
<td>A</td>
<td>a</td>
<td>a</td>
</tr>
<tr>
<td>1100100</td>
<td>100</td>
<td>64</td>
<td>2s</td>
<td>1c</td>
</tr>
<tr>
<td></td>
<td>1000000</td>
<td>F4240</td>
<td>lfls</td>
<td>4c92</td>
</tr>
<tr>
<td></td>
<td>10000000</td>
<td>989680</td>
<td>5yc1s</td>
<td>FXsk</td>
</tr>
</tbody>
</table>
<p>Se puede observar de un vistazo cómo a medida que aumenta el número, cuanto mayor sea la base que manejamos menos dígitos tendrá . Los números, a fin de cuentas, son combinaciones continuas entre todos los dígitos posibles.Así, en función de la base y del número de dígitos, el mayor número representable representable sería:</p>
<table style="border: 1px none; height: 202px;" border="0" width="470">
<thead>
<tr>
<td><span style="color: #808080;"><strong>Num. dígitos<br />
</strong></span></td>
<td><span style="color: #808080;"><strong>Decimal</strong></span></td>
<td><span style="color: #808080;"><strong>Base62</strong></span></td>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>10</td>
<td>62</td>
</tr>
<tr>
<td>2</td>
<td>100</td>
<td>3844</td>
</tr>
<tr>
<td>3</td>
<td>1000</td>
<td>238328</td>
</tr>
<tr>
<td>4</td>
<td>10000</td>
<td>14776336</td>
</tr>
<tr>
<td>5</td>
<td>100000</td>
<td>916132832</td>
</tr>
<tr>
<td>6</td>
<td>1000000</td>
<td>56800235584</td>
</tr>
<tr>
<td>7</td>
<td>10000000</td>
<td>3521614606208</td>
</tr>
<tr>
<td>8</td>
<td>100000000</td>
<td>218340105584896</td>
</tr>
<tr>
<td>9</td>
<td>1000000000</td>
<td>13537086546263552</td>
</tr>
</tbody>
</table>
<p>O lo que es lo mismo, <strong><em>base</em><sup>(número de dígitos)</sup></strong>, <strong>62<sup>9</sup></strong> contra <strong>10<sup>9</sup></strong>.Espero que se entienda la teoría. Como curiosidad:</p>
<p><strong>Decimal</strong>: 10000000000000000000000</p>
<p><strong>Base62</strong>: 36aHo5IWaicak</p>
<p>La pregunta ahora sería, <em>¿Por qué <strong>Base62</strong> y no <strong>Base64</strong>, por ejemplo, mucho más conocida?</em> Sencillo, porque además de los 62 caracteres de <strong>Base62</strong>, <strong>Base64</strong> utiliza dos adicionales, generalmente + y / además del =, lo que convierten la cadena en <strong><em>no web safe</em></strong>, es decir, los caracteres especiales debieran traducirse para que su transporte no diese problemas, con lo que estaríamos perdiendo las ventajas de nuestro <strong><em>cifrado corto</em></strong>. Los 62 caracteres utilizados en <strong>Base62</strong> son totalmente seguros, sólo letras (mayúsculas y minúsculas) y números.</p>
<p>Sabiendo ya cómo funciona el sistema, veremos cómo crear nuestra aplicación. Obviamente no contaré todo paso a paso ya que sino tardaría mucho más en escribir el artículo que en hacer la aplicación, me meteré sólo en las cosas que considere más importantes.</p>
<p>Para codificar/decodificar de <strong>base10</strong> a <strong>base62</strong> utilizaré estas librerías:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> dec2base<span class="br0">&#40;</span><span class="re0">$dec</span>, <span class="re0">$base</span>, <span class="re0">$digits</span> = <span class="kw2">FALSE</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$base</span> &lt; <span class="nu0">2</span> or <span class="re0">$base</span> &gt; <span class="nu0">256</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Invalid Base: .$base<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.php.net/bcscale"><span class="kw3">bcscale</span></a><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="re0">$value</span> = <span class="st0">&#8221;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>!<span class="re0">$digits</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$digits</span> = digits<span class="br0">&#40;</span><span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$dec</span> &gt; <span class="re0">$base</span> &#8211; <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rest</span> = <a href="http://www.php.net/bcmod"><span class="kw3">bcmod</span></a><span class="br0">&#40;</span><span class="re0">$dec</span>,<span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dec</span> = <a href="http://www.php.net/bcdiv"><span class="kw3">bcdiv</span></a><span class="br0">&#40;</span><span class="re0">$dec</span>,<span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$value</span> = <span class="re0">$digits</span><span class="br0">&#91;</span><span class="re0">$rest</span><span class="br0">&#93;</span>.<span class="re0">$value</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="re0">$value</span>=<span class="re0">$digits</span><span class="br0">&#91;</span><a href="http://www.php.net/intval"><span class="kw3">intval</span></a><span class="br0">&#40;</span><span class="re0">$dec</span><span class="br0">&#41;</span><span class="br0">&#93;</span>.<span class="re0">$value</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>string<span class="br0">&#41;</span> <span class="re0">$value</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">function</span> base2dec<span class="br0">&#40;</span><span class="re0">$value</span>, <span class="re0">$base</span>, <span class="re0">$digits</span> = <span class="kw2">FALSE</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$base</span> &lt; <span class="nu0">2</span> or <span class="re0">$base</span> &gt; <span class="nu0">256</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Invalid Base: .$base<span class="es0">\n</span>&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <a href="http://www.php.net/bcscale"><span class="kw3">bcscale</span></a><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$base</span> &lt; <span class="nu0">37</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$value</span> = <a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">&#40;</span><span class="re0">$value</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>!<span class="re0">$digits</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$digits</span> = digits<span class="br0">&#40;</span><span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="re0">$size</span> = <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">&#40;</span><span class="re0">$value</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="re0">$dec</span> = <span class="st0">&#8217;0&#8242;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">for</span><span class="br0">&#40;</span><span class="re0">$loop</span>=<span class="nu0">0</span>; <span class="re0">$loop</span> &lt; <span class="re0">$size</span>; <span class="re0">$loop</span>++<span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$element</span> = <a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$digits</span>, <span class="re0">$value</span><span class="br0">&#91;</span><span class="re0">$loop</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$power</span> = <a href="http://www.php.net/bcpow"><span class="kw3">bcpow</span></a><span class="br0">&#40;</span><span class="re0">$base</span>, <span class="re0">$size</span>-<span class="re0">$loop</span><span class="nu0">-1</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dec</span> = <a href="http://www.php.net/bcadd"><span class="kw3">bcadd</span></a><span class="br0">&#40;</span><span class="re0">$dec</span>, <a href="http://www.php.net/bcmul"><span class="kw3">bcmul</span></a><span class="br0">&#40;</span><span class="re0">$element</span>, <span class="re0">$power</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>string<span class="br0">&#41;</span><span class="re0">$dec</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">function</span> digits<span class="br0">&#40;</span><span class="re0">$base</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$base</span> &lt; <span class="nu0">64</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="st0">&#8217;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_&#8217;</span>, <span class="nu0">0</span>, <span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="st0">&quot;<span class="es0">\x</span>0<span class="es0">\x</span>1<span class="es0">\x</span>2<span class="es0">\x</span>3<span class="es0">\x</span>4<span class="es0">\x</span>5<span class="es0">\x</span>6<span class="es0">\x</span>7<span class="es0">\x</span>8<span class="es0">\x</span>9<span class="es0">\x</span>a<span class="es0">\x</span>b<span class="es0">\x</span>c<span class="es0">\x</span>d<span class="es0">\x</span>e<span class="es0">\x</span>f<span class="es0">\x</span>10<span class="es0">\x</span>11<span class="es0">\x</span>12<span class="es0">\x</span>13<span class="es0">\x</span>14<span class="es0">\x</span>15<span class="es0">\x</span>16<span class="es0">\x</span>17<span class="es0">\x</span>18<span class="es0">\x</span>19<span class="es0">\x</span>1a<span class="es0">\x</span>1b<span class="es0">\x</span>1c<span class="es0">\x</span>1d<span class="es0">\x</span>1e<span class="es0">\x</span>1f !<span class="es0">\x</span>22#<span class="es0">\x</span>24%&amp;amp;&#8217;()*+,-./0123456789:;&lt;=&gt;<span class="es0">\x</span>3f@ABCDEFGHIJKLMNOPQRSTUVWXYZ[<span class="es0">\]</span>^_`abcdefghijklmnopqrstuvwxyz{|}~<span class="es0">\x</span>7f<span class="es0">\x</span>80<span class="es0">\x</span>81<span class="es0">\x</span>82<span class="es0">\x</span>83<span class="es0">\x</span>84<span class="es0">\x</span>85<span class="es0">\x</span>86<span class="es0">\x</span>87<span class="es0">\x</span>88<span class="es0">\x</span>89<span class="es0">\x</span>8a<span class="es0">\x</span>8b<span class="es0">\x</span>8c<span class="es0">\x</span>8d<span class="es0">\x</span>8e<span class="es0">\x</span>8f<span class="es0">\x</span>90<span class="es0">\x</span>91<span class="es0">\x</span>92<span class="es0">\x</span>93<span class="es0">\x</span>94<span class="es0">\x</span>95<span class="es0">\x</span>96<span class="es0">\x</span>97<span class="es0">\x</span>98<span class="es0">\x</span>99<span class="es0">\x</span>9a<span class="es0">\x</span>9b<span class="es0">\x</span>9c<span class="es0">\x</span>9d<span class="es0">\x</span>9e<span class="es0">\x</span>9f<span class="es0">\x</span>a0<span class="es0">\x</span>a1<span class="es0">\x</span>a2<span class="es0">\x</span>a3<span class="es0">\x</span>a4<span class="es0">\x</span>a5<span class="es0">\x</span>a6<span class="es0">\x</span>a7<span class="es0">\x</span>a8<span class="es0">\x</span>a9<span class="es0">\x</span>aa<span class="es0">\x</span>ab<span class="es0">\x</span>ac<span class="es0">\x</span>ad<span class="es0">\x</span>ae<span class="es0">\x</span>af<span class="es0">\x</span>b0<span class="es0">\x</span>b1<span class="es0">\x</span>b2<span class="es0">\x</span>b3<span class="es0">\x</span>b4<span class="es0">\x</span>b5<span class="es0">\x</span>b6<span class="es0">\x</span>b7<span class="es0">\x</span>b8<span class="es0">\x</span>b9<span class="es0">\x</span>ba<span class="es0">\x</span>bb<span class="es0">\x</span>bc<span class="es0">\x</span>bd<span class="es0">\x</span>be<span class="es0">\x</span>bf<span class="es0">\x</span>c0<span class="es0">\x</span>c1<span class="es0">\x</span>c2<span class="es0">\x</span>c3<span class="es0">\x</span>c4<span class="es0">\x</span>c5<span class="es0">\x</span>c6<span class="es0">\x</span>c7<span class="es0">\x</span>c8<span class="es0">\x</span>c9<span class="es0">\x</span>ca<span class="es0">\x</span>cb<span class="es0">\x</span>cc<span class="es0">\x</span>cd<span class="es0">\x</span>ce<span class="es0">\x</span>cf<span class="es0">\x</span>d0<span class="es0">\x</span>d1<span class="es0">\x</span>d2<span class="es0">\x</span>d3<span class="es0">\x</span>d4<span class="es0">\x</span>d5<span class="es0">\x</span>d6<span class="es0">\x</span>d7<span class="es0">\x</span>d8<span class="es0">\x</span>d9<span class="es0">\x</span>da<span class="es0">\x</span>db<span class="es0">\x</span>dc<span class="es0">\x</span>dd<span class="es0">\x</span>de<span class="es0">\x</span>df<span class="es0">\x</span>e0<span class="es0">\x</span>e1<span class="es0">\x</span>e2<span class="es0">\x</span>e3<span class="es0">\x</span>e4<span class="es0">\x</span>e5<span class="es0">\x</span>e6<span class="es0">\x</span>e7<span class="es0">\x</span>e8<span class="es0">\x</span>e9<span class="es0">\x</span>ea<span class="es0">\x</span>eb<span class="es0">\x</span>ec<span class="es0">\x</span>ed<span class="es0">\x</span>ee<span class="es0">\x</span>ef<span class="es0">\x</span>f0<span class="es0">\x</span>f1<span class="es0">\x</span>f2<span class="es0">\x</span>f3<span class="es0">\x</span>f4<span class="es0">\x</span>f5<span class="es0">\x</span>f6<span class="es0">\x</span>f7<span class="es0">\x</span>f8<span class="es0">\x</span>f9<span class="es0">\x</span>fa<span class="es0">\x</span>fb<span class="es0">\x</span>fc<span class="es0">\x</span>fd<span class="es0">\x</span>fe<span class="es0">\x</span>ff&quot;</span>, <span class="nu0">0</span>, <span class="re0">$base</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">function</span> base_encode<span class="br0">&#40;</span><span class="re0">$value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> dec2base<span class="br0">&#40;</span>base2dec<span class="br0">&#40;</span><span class="re0">$value</span>, <span class="nu0">256</span><span class="br0">&#41;</span>, <span class="nu0">62</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">function</span> base_decode<span class="br0">&#40;</span><span class="re0">$value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">return</span> dec2base<span class="br0">&#40;</span>base2dec<span class="br0">&#40;</span><span class="re0">$value</span>, <span class="nu0">62</span><span class="br0">&#41;</span>, <span class="nu0">256</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Las dos últimas funciones son las que utilizaremos para las conversiones.</p>
<h3>Paquetes y librerías utilizadas:</h3>
<ul>
<li><a href="http://www.freecsstemplates.org/">Free CSS Templates</a>: Para tener una bonita plantilla <a href="http://es.wikipedia.org/wiki/XHTML">xhtml</a> para nuestro proyecto <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" />  .</li>
<li><a href="http://www.maxmind.com/app/geoip_country">Maxmind GeoLite Country</a>: Para la <a href="http://es.wikipedia.org/wiki/Georreferenciaci%C3%B3n">geolocalización</a> de un usuario a través de su IP.</li>
<li><a href="http://wurfl.sourceforge.net/">Wurfl</a>: Para identificar el navegador/terminal de un visitante por su <a href="http://es.wikipedia.org/wiki/Agente_de_usuario">User Agent</a>. Yo lo complemento con <a href="http://www.tera-wurfl.com/">Tera-Wurfl</a> para mantener la información en una base de datos.</li>
<li><a href="http://www.fusioncharts.com/free/">Fusion Charts Free</a>: Para los gráficos de estadísticas.</li>
<li><a href="http://code.google.com/p/zeroclipboard/">Zero Clipboard</a>: Para copiar al portapapeles la <em>url </em>corta generada sin que el usuario deba seleccionarla, solo con un click.</li>
<li><a href="http://jqueryui.com/">JqueryUI</a>: Para el componente de navegación con pestañas.</li>
<li><a href="http://code.google.com/intl/es-ES/apis/safebrowsing/">Google Safebrowsing API</a>: Para comprobar si una <em>url </em>es potencialmente peligrosa.</li>
<li><a href="http://adodb.sourceforge.net/">Adodb</a> (opcional): Para abstraer el acceso a la base de datos. Yo suelo utilizarla en todos mis proyectos pero se pueden utilizar las funciones nativas de PHP.</li>
<li><a href="http://phpexcel.codeplex.com/">PHPExcel</a>: Para generar Excel y PDF.</li>
</ul>
<p>Adicionalmente:</p>
<ul>
<li>Un dominio y hosting donde alojarlo (6€).</li>
<li>PHP y MySQL (tampoco son obligatorios, puedes hacerlo con cualquier tecnología).</li>
<li>15 horas de tu tiempo <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</li>
</ul>
<h3>Estructura de la web</h3>
<p>Cualquier proyecto web que se precie debe comenzarse describiendo qué queremos mostrar a nuestros visitantes, hay que recopilar todas las ideas, decidir las que interesan de verdad, estudiar cómo se van a disponer en el <em>frontend </em>y terminar con un mapa web que nos indique el flujo a seguir en el trabajo. Este será el nuestro:</p>
<p><a href="http://blog.osusnet.com/wp-content/uploads/2009/11/mapaWebIraUrl1.gif"><img class="aligncenter size-full wp-image-3321" title="mapaWebIraUrl" src="http://blog.osusnet.com/wp-content/uploads/2009/11/mapaWebIraUrl1.gif" alt="mapaWebIraUrl1 De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" width="470" height="351" /></a>Cuando un usuario vaya a una de nuestras url&#8217;s cortas en realidad estaremos reenviando la petición <em>http </em>internamente a un script encargado de hacer todo el proceso, <em>link.php</em> en mi caso.</p>
<p>Para ver las estadísticas de una <em>URL </em>me ha gustado el sistema de <a href="http://bit.ly">bit.ly</a>, así que se lo copiamos <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> . Añadiendo un &#8220;<strong>+</strong>&#8221; al final de la <em>URL </em>corta, en vez de saltar a la dirección larga mostraremos las estadísticas. Esto lo haremos, como en el caso anterior, dirigiendo internamente a otro script, <em>stats.php</em>.</p>
<p>Si el identificador que pretendemos usar para saltar a la <em>url </em>larga o ver estadísticas no existe, reenviaremos a <em>index.php</em> para que muestre un mensaje de error tipo &#8220;<em>La url no existe</em>&#8220;.</p>
<h3>El dominio</h3>
<p>Obviamente tendremos que buscar un dominio lo más corto posible, la mayoría estarán ya ocupados, pero buscando y buscando en <a href="http://es.wikipedia.org/wiki/Dominio_de_nivel_superior">TLD</a>&#8216;s extraños puedes encontrar algo. Yo he escogido un <em><strong>.me </strong></em>porque tiene un carácter menos que un <em><strong>.com</strong></em> <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" />  y no cuesta lo que un <em><strong>.es</strong></em> <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</p>
<h3>La base de datos</h3>
<p>Muy sencilla, dos tablas solamente, en una mantendremos las urls generadas y en otra las estadísticas de acceso a las mismas.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">CREATE TABLE IF NOT EXISTS `urls` <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; `<span class="kw2">id</span>` bigint<span class="br0">&#40;</span><span class="nu0">20</span><span class="br0">&#41;</span> NOT NULL auto_increment,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `url` varchar<span class="br0">&#40;</span><span class="nu0">500</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; `titulo` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; PRIMARY KEY &nbsp;<span class="br0">&#40;</span>`<span class="kw2">id</span>`<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#41;</span> <span class="re2">ENGINE=</span>MyISAM &nbsp;DEFAULT <span class="re2">CHARSET=</span>latin1;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">CREATE TABLE IF NOT EXISTS `stats` <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">`<span class="kw2">id</span>` bigint<span class="br0">&#40;</span><span class="nu0">20</span><span class="br0">&#41;</span> NOT NULL auto_increment,</div>
</li>
<li class="li2">
<div class="de2">`idurl` bigint<span class="br0">&#40;</span><span class="nu0">20</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`codpais` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`referer` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`hostreferer` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`ua` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li2">
<div class="de2">`hora` datetime NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`pais` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`marca` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">`modelo` varchar<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">PRIMARY KEY &nbsp;<span class="br0">&#40;</span>`<span class="kw2">id</span>`<span class="br0">&#41;</span>,</div>
</li>
<li class="li2">
<div class="de2">KEY `idurl` <span class="br0">&#40;</span>`idurl`,`hora`<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#41;</span> <span class="re2">ENGINE=</span>MyISAM &nbsp;DEFAULT <span class="re2">CHARSET=</span>latin1;</div>
</li>
</ol>
</div>
<h3>La configuración de Apache</h3>
<p>Como hemos comentado queremos que cuando alguien vaya a cualquier <em>url </em>de nuestro <em>site </em>del tipo</p>
<p><strong>http://tudominio.com/prueba3</strong></p>
<p>Se redirija internamente al <em>script link.php</em> que será el encargado de procesar la petición. De igual modo si alguien visita</p>
<p><strong>http://tudominio.com/prueba3+</strong></p>
<p>le mostraremos las estadísticas de esa <em>URL </em>(si existen). Configuramos <a href="http://httpd.apache.org/">Apache</a> para que tenga en cuenta todas estas particularidades, <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a> será nuestro amigo para conseguirlo. En mi caso he hecho que si la llamada no es un <em>script php</em>, ni una imagen ni un archivo <em>javascript </em>ni un <em>css </em>ni tiene el signo &#8220;<strong>+</strong>&#8220;, se vaya a <em>link.php</em>. Si tiene el signo &#8220;<strong>+</strong>&#8221; se irá a <em>stats.php</em>.</p>
<pre>RewriteEngine on
RewriteCond %{REQUEST_URI} !^/(.*).php$
RewriteCond %{REQUEST_URI} !^/css\/(.*)$
RewriteCond %{REQUEST_URI} !^/js\/(.*)$
RewriteCond %{REQUEST_URI} !^/(.*)\+$
RewriteCond %{REQUEST_URI} !^/images\/(.*)$
RewriteRule ^(.+) /link.php?id=$1
RewriteCond %{REQUEST_URI} ^/(.*)\+$
RewriteRule ^(.+) /stats.php?id=$1</pre>
<h3>Imagen y diseño</h3>
<p>Para el diseño, o te lo haces tú mismo o si eres un negado creativo como yo te descargas una plantilla <em>superchula </em>de <a href="http://freecsstamplates.org">freecsstamplates.org</a> y la adaptas a tus necesidades, no voy a entrar en más detalles.</p>
<h3>Crear urls cortas</h3>
<p>El primer <em>script </em>de nuestra aplicación. Un sencillo formulario donde el usuario introduce la <em>URL</em> que quiere acortar y al hacer <em>submit</em>&#8230; la acortamos integrando el sistema con la <a href="http://blog.osusnet.com/2009/11/13/google-safe-browsing-api-con-php-filtra-las-urls-potencialmente-peligrosas/">comprobación de malware</a> que explicaba hace unos días <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$urlbase</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">&#8216;url&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$url</span>=<span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">&#8216;url&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; try<span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="re0">$url</span>, <span class="nu0">0</span>, <span class="nu0">4</span><span class="br0">&#41;</span>!=<span class="st0">&quot;http&quot;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$url</span>=<span class="st0">&quot;http://&quot;</span>.<span class="re0">$url</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$class</span> = <span class="kw2">new</span> GoogleSafeBrowsing<span class="br0">&#40;</span><span class="st0">&#8216;ABQIAAAAQYvf-54bCBMuGY20SeONVxQ236Mc_IjryQBl-W_Repaw3fCykA&#8217;</span>, <span class="kw2">true</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$nomalware</span>=<span class="re0">$class</span>-&gt;<span class="me1">lookupsFor</span><span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$nomalware</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$htmltitle</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$html</span>=<a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$html</span>!=<span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/preg_match"><span class="kw3">preg_match</span></a><span class="br0">&#40;</span><span class="st0">&#8216;/(.*)&lt;<span class="es0">\/</span>title&gt;/is&#8217;</span>, <span class="re0">$html</span>, <span class="re0">$matches</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#41;</span> &amp;amp;&amp;amp; <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$matches</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$htmltitle</span>=<a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;select * from urls where url=&#8217;$url&#8217;&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$rs</span>-&gt;<span class="me1">recordcount</span><span class="br0">&#40;</span><span class="br0">&#41;</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$id</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;insert into urls (url, titulo) VALUES (&#8216;$url&#8217;, &#8216;$htmltitle&#8217;)&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$id</span>=<span class="re0">$conn</span>-&gt;<span class="me1">insert_id</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$base</span>=base_encode<span class="br0">&#40;</span><span class="re0">$id</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$urlbase</span>=<span class="st0">&quot;http://iraurl.me/&quot;</span>.<span class="re0">$base</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$err</span>=<span class="nu0">4</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>catch<span class="br0">&#40;</span>exception <span class="re0">$e</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$err</span>=<span class="nu0">3</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Hemos añadido una pequeña comprobación. Si la <em>URL </em>que se quiere añadir ya existe, devolvemos la misma <em>URL</em> corta, yo he tomado esa decisión, tú puedes hacer lo que quieras. Además obtenemos el título de la <em>URL </em>final para tener una referencia hacia la misma, cuestión de sencillez visual <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</p>
<h3>Reenvío a urls largas</h3>
<p>Ya tenemos nuestra <em>URL </em>corta, vamos ahora a reenviar las solicitudes a ella a la larga. Recordemos que nuestro <strong>Apache</strong> nos va a redirigir esa petición a <em>link.php?id=XXXX</em>. Nuestro script actualiza, además, las estadísticas de visitas de la url.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&lt;pre lang=<span class="st0">&quot;php&quot;</span>&gt;if<span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$idb</span>=<span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$id</span>=base_decode<span class="br0">&#40;</span><span class="re0">$idb</span><span class="br0">&#41;</span><span class="nu0">+0</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; try<span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;select * from urls where id=$id&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$rs</span>-&gt;<span class="me1">recordcount</span><span class="br0">&#40;</span><span class="br0">&#41;</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$url</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">&#8216;url&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$referer</span>=@<span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&#8216;HTTP_REFERER&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$ua</span>=@<span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&#8216;HTTP_USER_AGENT&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$ip</span>=@<span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&#8216;REMOTE_ADDR&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$hostreferer</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/preg_match"><span class="kw3">preg_match</span></a><span class="br0">&#40;</span><span class="st0">&#8216;@^(?:http://)?([^/]+)@i&#8217;</span>, <span class="re0">$referer</span>, <span class="re0">$matches</span><span class="br0">&#41;</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$hostreferer</span> = <span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$terminal</span>=getMarcaModelo<span class="br0">&#40;</span><span class="re0">$_SERVER</span><span class="br0">&#91;</span><span class="st0">&#8216;HTTP_USER_AGENT&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$marca</span>=<span class="re0">$terminal</span><span class="br0">&#91;</span><span class="st0">&#8216;marca&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$modelo</span>=<span class="re0">$terminal</span><span class="br0">&#91;</span><span class="st0">&#8216;modelo&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp</span>=getGeoCodeAndPais<span class="br0">&#40;</span><span class="re0">$ip</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$codpais</span>=<span class="re0">$temp</span><span class="br0">&#91;</span><span class="st0">&#8216;code&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pais</span>=<span class="re0">$temp</span><span class="br0">&#91;</span><span class="st0">&#8216;pais&#8217;</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;insert into stats (idurl, codpais, referer, ua, hora, pais, marca, modelo, hostreferer) VALUES</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ($id, &#8216;$codpais&#8217;, &#8216;$referer&#8217;, &#8216;$ua&#8217;, now(), &#8216;$pais&#8217;, &#8216;$marca&#8217;, &#8216;$modelo&#8217;, &#8216;$hostreferer&#8217;)&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$rs2</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;HTTP/1.x 301 Moved&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location: $url&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location: http://iraurl.me/index.php?err=1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span>catch<span class="br0">&#40;</span>exception <span class="re0">$e</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location: http://iraurl.me/index.php?err=2&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location: http://iraurl.me/index.php?err=1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
</pre>
<p>Como veis, si la <em>URL </em>no existe redirigimos al usuario a <em>index.php</em> con un mensaje de error. Necesitaremos dos funciones adicionales, las que nos devuelven información del país de origen de una IP y los datos del terminal del usuario (móvi o web). No entraré en detalles sobre la instalación de <a href="http://www.maxmind.com/app/geoip_country">Maxmind GeoLite Country</a> o de <a href="http://wurfl.sourceforge.net/">Wurfl</a>/<a href="http://www.tera-wurfl.com/">Tera-Wurfl</a>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> getGeoCodeAndPais<span class="br0">&#40;</span><span class="re0">$ip</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">require_once</span><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><span class="kw2">__FILE__</span><span class="br0">&#41;</span>.<span class="st0">&quot;/geoip/geoip.inc&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$gi</span> = geoip_open<span class="br0">&#40;</span><span class="st0">&quot;/usr/share/GeoIP/GeoIP.dat&quot;</span>,GEOIP_STANDARD<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$codpais</span>=geoip_country_code_by_addr<span class="br0">&#40;</span><span class="re0">$gi</span>, <span class="re0">$ip</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$pais</span>=geoip_country_name_by_addr<span class="br0">&#40;</span><span class="re0">$gi</span>, <span class="re0">$ip</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; geoip_close<span class="br0">&#40;</span><span class="re0">$gi</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">&quot;pais&quot;</span>=&gt;<span class="re0">$pais</span>, <span class="st0">&quot;code&quot;</span>=&gt;<span class="re0">$codpais</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">function</span> getCapabilities<span class="br0">&#40;</span><span class="re0">$ua</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">require_once</span><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><span class="kw2">__FILE__</span><span class="br0">&#41;</span>.<span class="st0">&quot;/Tera-WURFL/TeraWurfl.php&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$wurflObj</span> = <span class="kw2">new</span> TeraWurfl<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$matched</span> = <span class="re0">$wurflObj</span>-&gt;<span class="me1">GetDeviceCapabilitiesFromAgent</span><span class="br0">&#40;</span><span class="re0">$ua</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$movil</span> = <span class="re0">$wurflObj</span>-&gt;<span class="me1">capabilities</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$movil</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<h3>Estadísticas</h3>
<p>La teoría es la misma. Si existe la <em>URL </em>cargamos los datos, si no redirigimos a la <em>home</em>. En nuestra caso utilizamos el componente de pestañas de <a href="http://jqueryui.com/">JqueryUI</a> para organizar los distintos tipos de datos que permitiremos ver y añadiremos los botones para exportar a Excel y PDF.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$idb</span>=<a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span>, <span class="nu0">0</span>, <a href="http://www.php.net/strlen"><span class="kw3">strlen</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="nu0">-1</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$id</span>=base_decode<span class="br0">&#40;</span><span class="re0">$idb</span><span class="br0">&#41;</span><span class="nu0">+0</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$query</span>=<span class="st0">&quot;select * from urls where id=$id&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$rs</span>-&gt;<span class="me1">recordcount</span><span class="br0">&#40;</span><span class="br0">&#41;</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$urlbase</span>=<span class="st0">&quot;http://iraurl.me/&quot;</span>.<span class="re0">$idb</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$url</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">'url'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$id</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$htmltitulo</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">'titulo'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$htmltitulo</span>==<span class="st0">&quot;&quot;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$htmltitulo</span>=<span class="re0">$url</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$query</span>=<span class="st0">&quot;select count(*) as nregs from stats where idurl=$id&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$clicks</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fields</span><span class="br0">&#91;</span><span class="st0">'nregs'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Location: http://iraurl.me/index.php?err=1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/exit"><span class="kw3">exit</span></a>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Muy sencillo.</p>
<p><a href="http://iraurl.me/3pn+"><img class="aligncenter size-full wp-image-3078" title="stats" src="http://blog.osusnet.com/wp-content/uploads/2009/11/stats1.gif" alt="stats1 De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" width="470" height="560" /></a></p>
<p>Lo complicado en este caso es mostrar las gráficas con <strong>FusionCharts</strong>. Para cada una debemos añadir algo de código <em>html</em>:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">&lt;div id=&quot;chartClicks&quot;&gt;&lt;/div&gt;
</div>
</li>
<li class="li1">
<div class="de1">&lt;script type=&quot;text/javascript&quot;&gt;
</div>
</li>
<li class="li1">
<div class="de1">&nbsp;var myChart = new FusionCharts(&quot;images/Charts/FCF_Column3D.swf&quot;, &quot;idChartClicks&quot;, &quot;430&quot;, &quot;400&quot;, &quot;0&quot;, &quot;1&quot;);
</div>
</li>
<li class="li1">
<div class="de1">&nbsp;myChart.setDataURL(escape(&quot;xml.php?t=cli&amp;amp;id='.$idb.'&quot;));
</div>
</li>
<li class="li2">
<div class="de2">&nbsp;myChart.setTransparent(true);
</div>
</li>
<li class="li1">
<div class="de1">&nbsp;myChart.render(&quot;chartClicks&quot;);
</div>
</li>
<li class="li1">
<div class="de1">&lt;/script&gt;</div>
</li>
</ol>
</div>
<p>El script <em>xml.php</em> será el que devuelva los datos en el formato adecuado para FusionCharts. Por ejemplo:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$query</span>=<span class="st0">&quot;select DAY(hora) as dia, MONTH(hora) as mes, YEAR(hora) as ano, count(*) as nclicks</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> from stats</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> where idurl=$id</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> group by ano, mes, dia</span></div>
</li>
<li class="li2">
<div class="de2"><span class="st0"> order by hora&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$rs</span>=<span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$xml</span>=<span class="st0">'&lt;graph caption=&quot;Clicks&quot; rotateNames=&quot;1&quot; xAxisName=&quot;Día&quot; yAxisName=&quot;Clicks&quot; showNames=&quot;1&quot; decimalPrecision=&quot;0&quot; formatNumberScale=&quot;0&quot; chartLeftMargin=&quot;5&quot; chartRightMargin=&quot;5&quot; chartTopMargin=&quot;0&quot;&gt;'</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$r</span>=<span class="re0">$rs</span>-&gt;<span class="me1">fetchrow</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;<span class="re0">$xml</span>.=<span class="st0">'&lt;set name=&quot;'</span>.<span class="re0">$r</span><span class="br0">&#91;</span><span class="st0">'dia'</span><span class="br0">&#93;</span>.<span class="st0">&quot;/&quot;</span>.<span class="re0">$r</span><span class="br0">&#91;</span><span class="st0">'mes'</span><span class="br0">&#93;</span>.<span class="st0">&quot;/&quot;</span>.<span class="re0">$r</span><span class="br0">&#91;</span><span class="st0">'ano'</span><span class="br0">&#93;</span>.<span class="st0">'&quot; value=&quot;'</span>.<span class="re0">$r</span><span class="br0">&#91;</span><span class="st0">'nclicks'</span><span class="br0">&#93;</span>.<span class="st0">'&quot; color=&quot;#A1A1A1&quot; /&gt;'</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$xml</span>.=<span class="st0">'&lt;/graph&gt;'</span>;</div>
</li>
</ol>
</div>
<p>Os doy sólo un ejemplo, el resto lo montáis por vuestra cuenta <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</p>
<h3>Descifrar urls cortas</h3>
<p>Todos los sistemas de acortar <em>URL's </em>funcionan tal y como cuento en este artículo, haciendo un <a href="http://en.wikipedia.org/wiki/URL_redirection">HTTP/301 redirect</a> hacia la url original.</p>
<p>A partir de la <em>URL</em> corta podemos saber cual es la <em>URL</em> original simplemente siguiendo las redirecciones <em></em>que hace. Muy sencillo con PHP y que, además nos sirve para, integrándola en <a href="http://blog.osusnet.com/2009/11/13/google-safe-browsing-api-con-php-filtra-las-urls-potencialmente-peligrosas/">nuestra API de malware</a>, prevenir posibles problemas con la <em>URL</em> final.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> get_web_page<span class="br0">&#40;</span> <span class="re0">$url</span> <span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$options</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span> <span class="st0">'http'</span> =&gt; <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'user_agent'</span> &nbsp; &nbsp;=&gt; <span class="st0">'spider'</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'max_redirects'</span> =&gt; <span class="nu0">10</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'timeout'</span> &nbsp; &nbsp; &nbsp; =&gt; <span class="nu0">120</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#41;</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$context</span> = <a href="http://www.php.net/stream_context_create"><span class="kw3">stream_context_create</span></a><span class="br0">&#40;</span> <span class="re0">$options</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$page</span> &nbsp; &nbsp;= @<a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span> <span class="re0">$url</span>, <span class="kw2">false</span>, <span class="re0">$context</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$result</span> &nbsp;= <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$page</span> != <span class="kw2">false</span> <span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="st0">'content'</span><span class="br0">&#93;</span> = <span class="re0">$page</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span> !<a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span> <span class="re0">$http_response_header</span> <span class="br0">&#41;</span> <span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">null</span>; &nbsp; &nbsp;<span class="co1">// Bad url, timeout</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// Save the header</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="st0">'header'</span><span class="br0">&#93;</span> = <span class="re0">$http_response_header</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="co1">// Get the *last* HTTP status code</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$nLines</span> = <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span> <span class="re0">$http_response_header</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span> <span class="re0">$i</span> = <span class="re0">$nLines</span><span class="nu0">-1</span>; <span class="re0">$i</span> &gt;= <span class="nu0">0</span>; <span class="re0">$i</span>-- <span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$line</span> = <span class="re0">$http_response_header</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/strncasecmp"><span class="kw3">strncasecmp</span></a><span class="br0">&#40;</span> <span class="st0">&quot;HTTP&quot;</span>, <span class="re0">$line</span>, <span class="nu0">4</span> <span class="br0">&#41;</span> == <span class="nu0">0</span> <span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$response</span> = <a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">&#40;</span> <span class="st0">' '</span>, <span class="re0">$line</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$result</span><span class="br0">&#91;</span><span class="st0">'http_code'</span><span class="br0">&#93;</span> = <span class="re0">$response</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$result</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$url</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">'url'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$url</span>=<span class="re0">$_POST</span><span class="br0">&#91;</span><span class="st0">'url'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$datos</span>=get_web_page<span class="br0">&#40;</span> <span class="re0">$url</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$datos</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$headers</span>=<span class="re0">$datos</span><span class="br0">&#91;</span><span class="st0">'header'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$urls</span>=<a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span><span class="br0">&#40;</span><span class="re0">$headers</span> <span class="kw1">as</span> <span class="re0">$head</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp</span>=<a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span>, <span class="re0">$head</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/strtolower"><span class="kw3">strtolower</span></a><span class="br0">&#40;</span><span class="re0">$temp</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span>==<span class="st0">&quot;location:&quot;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$urls</span><span class="br0">&#91;</span><span class="br0">&#93;</span>=<span class="re0">$temp</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$htmltitle</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/preg_match"><span class="kw3">preg_match</span></a><span class="br0">&#40;</span><span class="st0">'/(.*)&lt;<span class="es0">\/</span>title&gt;/is'</span>, <span class="re0">$datos</span><span class="br0">&#91;</span><span class="st0">'content'</span><span class="br0">&#93;</span>, <span class="re0">$matches</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/is_array"><span class="kw3">is_array</span></a><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#41;</span> &amp;amp;&amp;amp; <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$matches</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$htmltitle</span>=<a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Ya está, en <em>$urls</em> tendremos la lista de urls que van saltando hasta llegar a la final.</p>
<p><a href="http://iraurl.me/descifrar.php"><img class="aligncenter size-full wp-image-3084" title="descifrar" src="http://blog.osusnet.com/wp-content/uploads/2009/11/descifrar2.gif" alt="descifrar2 De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" width="470" height="401" /></a></p>
<h3>Api</h3>
<p>Hoy en día todo tiene que tener <a href="http://es.wikipedia.org/wiki/Interfaz_de_programaci%C3%B3n_de_aplicaciones">Api</a>. Para las estadísticas es muy sencillo, el propio <a href="http://es.wikipedia.org/wiki/Extensible_Markup_Language">XML</a> que generamos para consumir con <a href="http://www.fusioncharts.com/free/">FusionCharts</a> nos permite que clientes externos se alimenten del mismo. Para crear <em>URL</em>'s cortas remotamente, simplemente creamos un archivo <em>api.php</em>:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span>isset<span class="br0">&#40;</span><span class="re1">$_GET</span><span class="br0">&#91;</span><span class="st0">'url'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re1">$url</span>=urldecode<span class="br0">&#40;</span><span class="re1">$_GET</span><span class="br0">&#91;</span><span class="st0">'url'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; try<span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$htmltitle</span>=<span class="st0">&quot;&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>substr<span class="br0">&#40;</span><span class="re1">$url</span>, <span class="nu0">0</span>, <span class="nu0">4</span><span class="br0">&#41;</span>!=<span class="st0">&quot;http&quot;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$url</span>=<span class="st0">&quot;http://&quot;</span>.<span class="re1">$url</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$html</span>=file_get_contents<span class="br0">&#40;</span><span class="re1">$url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re1">$html</span>!=<span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; preg_match<span class="br0">&#40;</span><span class="st0">'/(.*)&lt;<span class="es0">\/</span>title&gt;/is'</span>, <span class="re1">$html</span>, <span class="re1">$matches</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>is_array<span class="br0">&#40;</span><span class="re1">$matches</span><span class="br0">&#41;</span> &amp;amp;&amp;amp; count<span class="br0">&#40;</span><span class="re1">$matches</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$htmltitle</span>=trim<span class="br0">&#40;</span><span class="re1">$matches</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$query</span>=<span class="st0">&quot;select * from urls where url='$url'&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$rs</span>=<span class="re1">$conn</span>-&gt;Execute<span class="br0">&#40;</span><span class="re1">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="re1">$rs</span>-&gt;recordcount<span class="br0">&#40;</span><span class="br0">&#41;</span>&gt;<span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$id</span>=<span class="re1">$rs</span>-&gt;fields<span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$query</span>=<span class="st0">&quot;insert into urls (url, titulo) VALUES ('$url', '$htmltitle')&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$rs</span>=<span class="re1">$conn</span>-&gt;Execute<span class="br0">&#40;</span><span class="re1">$query</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$id</span>=<span class="re1">$conn</span>-&gt;insert_id<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$base</span>=base_encode<span class="br0">&#40;</span><span class="re1">$id</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re1">$urlbase</span>=<span class="st0">&quot;http://iraurl.me/&quot;</span>.<span class="re1">$base</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">echo</span> <span class="re1">$urlbase</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span>catch<span class="br0">&#40;</span>exception <span class="re1">$e</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;ERROR&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Eso es todo. No olvides integrarlo también con el sistema de <em>malware</em>.</p>
<h3>Conclusiones</h3>
<p>Bueno, y todo este rollo ¿para qué?. Pues muy sencillo, para que veais que hoy en día la tecnología está al alcance de todos, es sencillo y rápido crear un proyecto en Internet, hay de todo por todas las esquinas, la tecnología no es lo importante, lo que verdaderamente cuenta es cómo mueves ese producto tecnológico para rentabilizarlo y obtener un beneficio de él.</p>
<p>Ya tengo mi proyecto <em>superchulo </em>funcionando, sólo me ha costado unas 15 horas de trabajo. Le he puesto un poco de <em>Adsense</em> por aquí y por allí. ¿Y ahora qué? ¿A esperar a que la gente entre y me haga millonario? <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" />  Es mucho más complicado que eso como todos sabéis, primero tienes que tener una masa de usuarios elevada que le dé movimiento al proyecto y después tienes que conseguir que la mayoría de ellos sean gente normal, no gente técnica, usuarios avanzados que no pagamos por nada ni pinchamos en publicidad <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> .</p>
<p>Hoy en día, en Internet, como en cualquier negocio, las técnicas de marketing y venta son mucho más importantes que la tecnología en sí misma, es duro reconocerlo, pero es así. De nada sirve que tengas el mejor producto del <em>mundo mundial </em>si no consigues que la gente lo utilice y se deje dinero, así de claro. Si tienes los conocimientos adecuados para mover el negocio, no te preocupes, la tecnología te la aporta cualquier <em>partner </em>por un módico precio, pero poner en manos de otro toda la estrategia de ventas de tu negocio no está tan claro ¿no?.</p>
<p>Espero que os sirva de algo el artículo. He querido mostrar, fundamentalmente, cómo utilizando algunas librerías que puedes obtener sin coste puedes hacer algo realmente útil y funcional con muy poco esfuerzo. Seguro que sacáis alguna idea.</p>
<p>Perdón por el rollo <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="De artículo a proyecto explicado paso a paso: acorta URLs con IraUrl.me" /> , al final me ha costado mucho más escribir el artículo que implementarlo.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/11/24/de-articulo-a-proyecto-explicado-paso-a-paso-acorta-urls-con-iraurl-me/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Google Safe Browsing API con PHP, filtra las urls potencialmente peligrosas</title>
		<link>http://blog.osusnet.com/2009/11/13/google-safe-browsing-api-con-php-filtra-las-urls-potencialmente-peligrosas/</link>
		<comments>http://blog.osusnet.com/2009/11/13/google-safe-browsing-api-con-php-filtra-las-urls-potencialmente-peligrosas/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 09:18:38 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[safe browsing]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=3096</guid>
		<description><![CDATA[Preparando un pequeño nuevo proyecto del que os hablaré en mi siguiente artículo, tuve un problema que me llevó a escribir este otro. En un momento de la aplicación el usuario debe escribir una url (el resto es secreto aún ). Pues bien, ya durante las pruebas aparecieron los típicos graciosos que utilizan url&#8217;s potencialmente [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Preparando un pequeño nuevo proyecto del que os hablaré en mi siguiente artículo, tuve un problema que me llevó a escribir este otro. En un momento de la aplicación el usuario debe escribir una <em>url </em>(el resto es secreto aún <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Google Safe Browsing API con PHP, filtra las urls potencialmente peligrosas" /> ). Pues bien, ya durante las pruebas aparecieron los típicos <em>graciosos</em> que utilizan <em>url&#8217;s </em>potencialmente peligros, de esas que no hacen cosas nada buenas. Buscando un poco dí con <a href="http://code.google.com/intl/es-ES/apis/safebrowsing/">Google Safe Browsing API</a>, el sistema que Google pone a nuestra disposición para comprobar contra sus sistemas si tienen una determinada <em>url</em> recogida dentro de su base de datos de <em>urls</em> peligrosas, la misma que utilizan ellos para lanzar a veces esos avisos de &#8220;¿seguro que quieres ver esto?&#8221;.</p>
<p>Esta <strong>API</strong> funciona de modo diferente a la mayoría de aplicaciones de Google que residen directamente en<em> la nube</em> y lanzamos consultas contra su <strong>API</strong>. En este caso nos provee de su base de datos de <em>urls </em>potencialmente peligrosas para que las guardemos localmente y hagamos las consultas directamente en nuestros sistemas, lo único que debemos hacer es actualizar periódicamente esos datos, eso sí, con algunas limitaciones que nos impone Google, como que no se pueden renovar en intervalos inferiores a 30 minutos. Actualmente esta base de datos tiene más de trescientos mil registros.</p>
<p>Vamos a explicar como utilizarla. Lo primero que debemos hacer es, como en todo lo que hace Google, <a href="http://code.google.com/intl/es-ES/apis/safebrowsing/key_signup.html">crear una &#8220;API KEY&#8221;</a> y una sencilla tabla en nuestro servidor <strong>MySQL </strong>donde alojaremos la información que nos envíe Google.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">CREATE TABLE IF NOT EXISTS `malware` <span class="br0">&#40;</span></div>
</li>
<li class="li1">
<div class="de1">`malware_hash` varchar<span class="br0">&#40;</span><span class="nu0">32</span><span class="br0">&#41;</span> NOT NULL,</div>
</li>
<li class="li1">
<div class="de1">PRIMARY KEY &nbsp;<span class="br0">&#40;</span>`malware_hash`<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#41;</span> <span class="re2">ENGINE=</span>MyISAM DEFAULT <span class="re2">CHARSET=</span>latin1;</div>
</li>
</ol>
</div>
<p>Creamos ahora una tarea que se ejecutará periódicamente y que leerá, siguiendo las especificaciones adecuadas, los datos que devuelve Google y los insertará/eliminará de nuestra base de datos. Yo, como ya he comentado en otras ocasiones, utilizo <a href="http://adodb.sourceforge.net/">Adodb</a> para el acceso a datos.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">include</span><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><a href="http://www.php.net/dirname"><span class="kw3">dirname</span></a><span class="br0">&#40;</span><span class="kw2">__FILE__</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="st0">&quot;/includes/funciones.inc.php&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$api_key</span> = <span class="st0">&quot;TU KEY&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$google_url</span> = <span class="st0">&quot;http://sb.google.com/safebrowsing/update&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">//open the remote URL</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$target</span> = <span class="st0">&quot;$google_url?client=api&amp;amp;apikey=$api_key&amp;amp;version=goog-malware-hash:1:-1,goog-black-hash:1:-1&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$handle</span> = <a href="http://www.php.net/fopen"><span class="kw3">fopen</span></a><span class="br0">&#40;</span><span class="st0">&quot;$target&quot;</span>, <span class="st0">&#8216;r&#8217;</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; or <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Couldn&#8217;t open file handle &quot;</span> . <span class="re0">$target</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$handle</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>!<a href="http://www.php.net/feof"><span class="kw3">feof</span></a><span class="br0">&#40;</span><span class="re0">$handle</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$line</span> = <a href="http://www.php.net/fgets"><span class="kw3">fgets</span></a><span class="br0">&#40;</span><span class="re0">$handle</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="re0">$line</span>,<span class="nu0">0</span>,<span class="nu0">1</span><span class="br0">&#41;</span> != <span class="st0">&#8216;[&#8216;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$operation</span> = <span class="br0">&#40;</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="re0">$line</span>,<span class="nu0">0</span>,<span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//get the &#8216;+&#8217; or &#8216;-&#8217;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$hash</span> = <a href="http://www.php.net/trim"><span class="kw3">trim</span></a><span class="br0">&#40;</span><a href="http://www.php.net/substr"><span class="kw3">substr</span></a><span class="br0">&#40;</span><span class="re0">$line</span>,<span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//get the md5 hash</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$hash</span> = qstr<span class="br0">&#40;</span><span class="re0">$hash</span><span class="br0">&#41;</span>; <span class="co1">//escape</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$operation</span> == <span class="st0">&#8216;+&#8217;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$sql</span> = <span class="st0">&quot;insert ignore into malware (malware_hash) VALUES (&#8216;&quot;</span>.<span class="re0">$hash</span>.<span class="st0">&quot;&#8217;)&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$sql</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$sql</span> = <span class="st0">&quot;delete from malware where malware_hash = &#8216;&quot;</span>.<span class="re0">$hash</span>.<span class="st0">&quot;&#8217;&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$conn</span>-&gt;<span class="me1">Execute</span><span class="br0">&#40;</span><span class="re0">$sql</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">&#40;</span><span class="re0">$handle</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Lo que hacemos simplemente es eliminar los hash que nos indica que debemos quitar y añadir los nuevos. Vamos a probar el sistema. Utilicé varias clases y sistemas que había por ahí para utilizar con PHP pero ninguno me parecía lo suficientemente completo hasta que encontré <a href="http://blog.osusnet.com/wp-content/uploads/2009/11/safebrowsing.class.rar">este</a>.  Su funcionamiento es muy sencillo. De nuevo está hecho usando <a href="http://adodb.sourceforge.net/">Adodb</a>, cámbialo según tus requerimientos.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$class</span> = <span class="kw2">new</span> GoogleSafeBrowsing<span class="br0">&#40;</span><span class="st0">&#8216;tu_key&#8217;</span>, <span class="kw2">true</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$safe</span>=<span class="re0">$class</span>-&gt;<span class="me1">lookupsFor</span><span class="br0">&#40;</span><span class="st0">&quot;http://blog.osusnet.com&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Nos devolverá un <em>booleano </em>que indica si la <em>url </em>es segura o no. Si probamos con alguna de <a href="http://blog.programmableweb.com/2009/06/24/the-top-10-malware-sites-how-to-avoid-them-using-a-google-api/">éstas</a> obtendremos un bonito <em>false </em> <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="Google Safe Browsing API con PHP, filtra las urls potencialmente peligrosas" /> . Espero que os sirva.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/11/13/google-safe-browsing-api-con-php-filtra-las-urls-potencialmente-peligrosas/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Monitorizando aplicaciones web con rrdtool</title>
		<link>http://blog.osusnet.com/2009/11/10/monitorizando-aplicaciones-web-con-rrdtool/</link>
		<comments>http://blog.osusnet.com/2009/11/10/monitorizando-aplicaciones-web-con-rrdtool/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 20:35:40 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Sistemas]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[rendimiento]]></category>
		<category><![CDATA[rrd]]></category>
		<category><![CDATA[webservice]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=3018</guid>
		<description><![CDATA[Vamos con uno de esos artículos que le gustan a Álvaro basados en experiencias del trabajo. En uno de los proyectos en los que estamos trabajando actualmente y del que ya os he hablado, teníamos un problema de rendimiento en una aplicación web, pero no teníamos localizado el punto donde se nos iba el tiempo. [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Vamos con uno de esos artículos que le gustan a Álvaro basados en experiencias del trabajo.</p>
<p>En uno de los proyectos en los que estamos trabajando actualmente y del que <a href="http://blog.osusnet.com/2009/11/02/scrum-de-dos-equipos-en-distintas-ciudades/">ya os he hablado</a>, teníamos un problema de rendimiento en una aplicación web, pero no teníamos localizado el punto donde se nos iba el tiempo. Incluso había momentos que la aplicación iba bien pero en otros era lamentable. Se nos ocurrió, entonces, hacer un sencillo sistema de monitorización de los distintos puntos sensibles que manejábamos y crear con ellos una serie de gráficas que nos permitiese hacer un seguimiento visual de los potenciales problemas.</p>
<p>Nuestra aplicación se basa en llamadas a distintos <a href="http://es.wikipedia.org/wiki/Servicio_web">webservices</a> a partir de las cuales se genera un <em>XML </em>al que se le aplican <a href="http://www.w3.org/TR/xslt">transformaciones XSL</a> para obtener el código <em>html </em>que se muestra al usuario. Algunas de esas llamadas se guardan en la sesión del usuario, con lo que en sucesivos accesos a la aplicación el rendimiento es infinitamente mejor, así que necesitábamos que el control se hiciese con sesiones limpias para que no se nos desvirtuasen las gráficas.</p>
<p>Nuestro sistema consiste en generar por un lado, en la aplicación web, una serie de datos estadísticos que nos ayuden a buscar los puntos conflictivos. Estos datos se insertarán periódicamente en una <a href="http://oss.oetiker.ch/rrdtool/">base de datos rrd</a> (<em>round robin database</em>) que finalmente utilizaremos para generar las gráficas.</p>
<h3>Preparando la aplicación web</h3>
<p>El primer paso es, entonces, modificar el código de la aplicación para que vaya generando los tiempos de respuesta en los distintos puntos que queremos controlar. Para facilitar las cosas decidimos que cada vez que se pase un parámetro predefinido en la <em>url</em>, en vez de mostrar la página <em>html </em>correspondiente mostraremos las estadísticas que después controlaremos. En nuestro caso decidimos que la url de estadísticas fuese:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">http:<span class="co1">//tudominio.com/index.php?stats</span></div>
</li>
</ol>
</div>
<p>Es decir, añadiendo el parámetro <strong><em>stats </em></strong>a cualquiera de las urls del site obtendremos los tiempos de respuesta que necesitamos.</p>
<p>Tenemos una función que genera el tiempo exacto del servidor cada vez que se llama, así que la utilizaremos después de ejecutar cada uno de los <strong>webservices</strong> y guardaremos esos datos. En mi caso tengo que obtener ocho puntos de control además del tiempo de inicio y el tiempo final, algo así:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw2">function</span> getTime<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;<span class="re0">$mtime2</span> = <a href="http://www.php.net/explode"><span class="kw3">explode</span></a><span class="br0">&#40;</span><span class="st0">&quot; &quot;</span>, <a href="http://www.php.net/microtime"><span class="kw3">microtime</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;<span class="re0">$endtime</span> = <span class="re0">$mtime2</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> + <span class="re0">$mtime2</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;<span class="kw1">return</span> <span class="re0">$endtime</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$isStats</span>=<a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&#8216;stats&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_inicio</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws1</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;..</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws2</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws3</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$time_ws4</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws5</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws6</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws7</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$time_ws8</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;.</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$isStats</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$time_final</span>=getTime<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&#8230;&#8230;</div>
</li>
</ol>
</div>
<p>Finalmente devolvemos una línea con todos los valores intermedios, es decir, para cada indicador sería el valor del tiempo de ese indicador menos el del anterior, esto nos dará el valor real del tiempo que ha pasado entre el indicador anterior y el actual. Para facilitar la posterior integración de estos valores con <strong>rrdtool</strong> lo que haremos será generarlos ya en el formato adecuado, separando cada valor con &#8220;:&#8221;.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&#8216;stats&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws1</span>-<span class="re0">$time_inicio</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws2</span>-<span class="re0">$time_ws1</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws3</span>-<span class="re0">$time_ws2</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws4</span>-<span class="re0">$time_ws3</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws5</span>-<span class="re0">$time_ws4</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws6</span>-<span class="re0">$time_ws5</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws7</span>-<span class="re0">$time_ws6</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_ws8</span>-<span class="re0">$time_ws7</span>, <span class="nu0">7</span><span class="br0">&#41;</span>.<span class="st0">&quot;:&quot;</span>.</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/number_format"><span class="kw3">number_format</span></a><span class="br0">&#40;</span><span class="re0">$time_final</span>-<span class="re0">$time_inicio</span>, <span class="nu0">7</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<p>Si ahora llamamos a nuestra url obtendremos los valores de nuestros indicadores. El último valor nos devolverá el tiempo completo de ejecución del <em>script </em>entre los valores <em>$time_inicio</em> y <em>$time final</em>.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="nu0">0.0281749</span>:<span class="nu0">0.5443010</span>:<span class="nu0">0.3132501</span>:<span class="nu0">2.9015441</span>:<span class="nu0">0.0000241</span>:<span class="nu0">0.6517198</span>:<span class="nu0">5.5171580</span>:<span class="nu0">0.0000379</span>:<span class="nu0">10.0677590</span></div>
</li>
</ol>
</div>
<p>Vemos cómo esta llamada ha tardado diez segundos, de los cuales 5,5 corresponden al indicador <em>ws7</em>.</p>
<p>Tenemos el primer paso preparado, vamos ahora a crear la base de datos donde almacenaremos toda la información estadística de la <em>url</em>. Tendremos una tarea que se ejecutará cada minuto y que recuperará los valores en ese momento de los identificadores que se han definido.</p>
<h3>Creando la base de datos</h3>
<p>Para guardar la información he escogido <a href="http://oss.oetiker.ch/rrdtool/">rrd</a>, el mismo que utilizan aplicaciones como <a href="http://oss.oetiker.ch/mrtg/">mrtg</a> o <a href="http://blog.osusnet.com/2008/04/23/monitorizando-servidores-con-cacti/">Cacti</a> y el utilizado en la mayoría de sistemas de monitorización. Según reza en su propia web, es el sistema estándar para gráficas y logs de series de datos temporales.</p>
<p>Para que todo vaya bien nuestra base de datos <a href="http://oss.oetiker.ch/rrdtool/">rrd</a> debe tener la misma cantidad de fuentes de datos que el sistema de estadísticas, nueve en este caso, los ocho puntos de control más el total. Además tenemos que pensar qué graficas vamos a crear. Yo quiero cuatro: última hora, últimas seis horas, últimas 24 horas y última semana. No necesito hacer un sistema con histórico avanzado, lo que quiero en este caso es controlar el rendimiento, así que no necesitaré gráficas mensuales ni anuales, pero se podrían generar de igual modo.</p>
<p>Para crear nuestro archivo rrd ejecutamos el comando siguiente:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">rrdtool create estadisticas.rrd &#8211;step <span class="nu0">60</span></div>
</li>
<li class="li1">
<div class="de1">DS:ws1:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws2:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws3:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li2">
<div class="de2">DS:ws4:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws5:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws6:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws7:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li1">
<div class="de1">DS:ws8:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U</div>
</li>
<li class="li2">
<div class="de2">DS:total:GAUGE:<span class="nu0">120</span>:<span class="nu0">0</span>:U </div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">RRA:AVERAGE:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">60</span></div>
</li>
<li class="li1">
<div class="de1">RRA:AVERAGE:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">360</span></div>
</li>
<li class="li1">
<div class="de1">RRA:AVERAGE:<span class="nu0">0.5</span>:<span class="nu0">5</span>:<span class="nu0">144</span></div>
</li>
<li class="li2">
<div class="de2">RRA:AVERAGE:<span class="nu0">0.5</span>:<span class="nu0">10</span>:<span class="nu0">202</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MAX:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">60</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MAX:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">360</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MAX:<span class="nu0">0.5</span>:<span class="nu0">5</span>:<span class="nu0">144</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MAX:<span class="nu0">0.5</span>:<span class="nu0">10</span>:<span class="nu0">202</span></div>
</li>
<li class="li2">
<div class="de2">RRA:MIN:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">60</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MIN:<span class="nu0">0.5</span>:<span class="nu0">1</span>:<span class="nu0">360</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MIN:<span class="nu0">0.5</span>:<span class="nu0">5</span>:<span class="nu0">144</span></div>
</li>
<li class="li1">
<div class="de1">RRA:MIN:<span class="nu0">0.5</span>:<span class="nu0">10</span>:<span class="nu0">202</span></div>
</li>
</ol>
</div>
<p>Vamos a explicarlo un poco.</p>
<ul>
<li><strong>&#8211;step=60</strong>: indica que los datos los actualizaremos cada 60 segundos. Nuestro sistema guardará estadísticas cada minuto.</li>
<li><strong>DS:ws1:GAUGE:120:0:U</strong>: Fuentes de datos, hay una línea de este tipo para cada valor que vamos a mantener.
<ol>
<li><em>wsX </em>es el nombre que tendrá esa fuente.</li>
<li><em>GAUGE</em> es el tipo de fuente de datos, puedes consultar la <a href="http://oss.oetiker.ch/rrdtool/doc/rrdcreate.en.html">documentación</a> completa para tener más idea.</li>
<li>120 es el parámetro <em>heartbeat</em>, tiempo máximo entre dos actualizaciones antes de que se asuma que es desconocido. He puesto el doble de <em>step</em>, si pasado ese tiempo no hay una actualización es que se ha perdido por cualquier razón.</li>
<li>Los últimos datos son los valores mínimo y máximo que habrá en la fuente de datos. En nuestro caso el mínimo será cero y el máximo no lo sabemos, le ponemos <em>U</em> de <em>unknown</em>.</li>
</ol>
</li>
<li><strong>RRA:AVERAGE:0.5:1:60</strong>: <em>Round robin archives</em>. El objetivo de una <strong>rrd</strong> es guardar datos en los <strong>rra</strong> que mantienen valores y estadísticas para cada una de las fuentes de datos definidas.
<ol>
<li>AVERAGE/MAX/MIN/LAST: la función utilizada para consolidar los datos. Como su propio nombre indica son la media, máximo, mínimo y el último valor.</li>
<li><strong>0.5</strong>; el <em>xff</em> (<em>xfiles factor</em>). De 0 a 1, indica el número de datos <em>UNKNOWN</em> que se permiten por intervalo de consolidación.</li>
<li><strong>1</strong>: define el número de datos utilizados para crear un intervalo de consolidación.</li>
<li><strong>60</strong>: Cuantos datos se mantienen en cada RRA. Esto depende de la gráfica que vamos a generar y se relaciona con el dato anterior.</li>
</ol>
</li>
</ul>
<p>La última parte es la más complicada de comprender. Intentaré explicarlo lo mejor que pueda para que se entienda. En nuestro caso tomamos un dato cada 60 segundos y queremos tener la gráfica de la última hora (60 segundos x 60 minutos, 3600 segundos). Necesitamos, por tanto, 60 puntos de control (3600/60 segundos de intervalo), utilizaremos cada uno de los datos que se toman. Esto es lo que indica la creación<strong> RRA:AVERAGE:0.5:1:60</strong>, queremos utilizar 60 puntos de control tomados cada 60 segundos. Este es bastante fácil, veamos el siguiente.</p>
<p><strong>RRA:MIN:0.5:1:360</strong></p>
<p>Ahora estamos guardando 360 puntos generados cada 60 segundos, es decir, cubrimos 60&#215;360=21600 segundos=6 horas. Era sencillo.</p>
<p><strong>RRA:AVERAGE:0.5:5:144</strong></p>
<p>En la siguiente gráfica queremos obtener datos de las últimas doce horas (12 horas x 60 minutos x 60 segundos, 43200 segundos). Ahora ya no necesitamos saber el comportamiento exacto en cada momento sino que necesitamos una visión global de lo que ha ocurrido durante esas doce horas, tomamos, por tanto, un punto de control cada cinco datos de registro, es decir, estamos manteniendo un dato cada 5&#215;60 segundos, 300 segundos. Necesitaremos por tanto 43200/300=144 valores para obtener nuestra gráfica de las últimas 12 horas</p>
<p><strong>RRA:MIN:0.5:10:202</strong></p>
<p>La última gráfica es semanal, 7x24x60x60=604800 segundos. Acepto que con tener un valor cada 10 minutos será suficiente, tendré entonces un valor cada 10&#215;300=3000 segundos. 604800/3000=~202.</p>
<p>Es algo difícil de entender al principio, pero una vez lo piensas, todo tiene sentido.</p>
<h3>Guardando las estadísticas</h3>
<p>Tenemos ya nuestra base de datos preparada, creemos ahora la tarea que guardará en este archivo <strong>rrd</strong> los datos estadísticos. En mi caso es una tarea <strong>PHP</strong> que lo hace todo muy sencillo.</p>
<p><span style="text-decoration: underline;"><strong>tarea.php</strong></span></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$url</span>=<span class="st0">&quot;http://dominio.com/?stats&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$cont</span>=<a href="http://www.php.net/file_get_contents"><span class="kw3">file_get_contents</span></a><span class="br0">&#40;</span><span class="re0">$url</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><a href="http://www.php.net/system"><span class="kw3">system</span></a><span class="br0">&#40;</span><span class="st0">&quot;rrdtool update estadisticas.rrd N:&quot;</span>.<span class="re0">$cont</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Añadimos la tarea al <a href="http://es.wikipedia.org/wiki/Cron_%28Unix%29">cron</a> para que se ejecute cada 60 seguntos.</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1">*/<span class="nu0">1</span> * * * * /usr/bin/php /path/to/tarea.php &gt; /dev/null <span class="nu0">2</span>&gt;&amp;amp;<span class="nu0">1</span></div>
</li>
</ol>
</div>
<p>¡Y ya está! Nuestra base de datos de estadísticas se está alimentando automáticamente.</p>
<h3>Creando las gráficas</h3>
<p>Lo más importante a fin de cuentas, lo que realmente vamos a utilizar. Rrdtool viene con un script de ejemplo que debes colocar en el directorio cgi-bin de tu servidor web y realizar los ajustes adecuados. Yo he puesto como ejemplo la gráfica de la última hora, las demás se harían igual variando el parámetro &#8220;<em>&#8211;start</em>&#8221; a los segundos anteriores que queremos mostrar.</p>
<p><span style="text-decoration: underline;"><strong>/cgi-bin/stats.cgi</strong></span></p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re3">#!/usr/bin/rrdcgi</span></div>
</li>
<li class="li1">
<div class="de1">&lt;h1&gt;Tu Dominio &#8211; Home Stats&lt;/h1&gt;</div>
</li>
<li class="li1">
<div class="de1">&lt;RRD::GRAPH /usr1/www/www.genteirc.com/htdocs/imagenes/daily-visitas.png</div>
</li>
<li class="li1">
<div class="de1">&#8211;imginfo <span class="st0">&#8216;&lt;img src=&quot;http://tudominio.com/%s&quot; alt=&quot;&quot; width=&quot;%lu&quot; height=&quot;%lu&quot; /&gt;&#8217;</span></div>
</li>
<li class="li2">
<div class="de2">&#8211;start <span class="nu0">-3600</span></div>
</li>
<li class="li1">
<div class="de1">&#8211;end <span class="nu0">-0</span></div>
</li>
<li class="li1">
<div class="de1">-h <span class="nu0">400</span> -<span class="kw2">w</span> <span class="nu0">600</span></div>
</li>
<li class="li1">
<div class="de1">&#8211;vertical-<span class="re2">label=</span><span class="st0">&quot;Tiempo&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&#8211;<span class="re2">title=</span><span class="st0">&quot;Last Hour&quot;</span></div>
</li>
<li class="li2">
<div class="de2">-a PNG</div>
</li>
<li class="li1">
<div class="de1">-l <span class="nu0">0</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws1=</span>/path/to/estadisticas.rrd:ws1:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws1<span class="re3">#00FF00:WebSer1\t</span></div>
</li>
<li class="li2">
<div class="de2">GPRINT:ws1:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws1:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws1:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws2=</span>/path/to/estadisticas.rrd:ws2:AVERAGE</div>
</li>
<li class="li2">
<div class="de2">LINE1:ws2<span class="re3">#<span class="nu0">800000</span>:WebSer2\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws2:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws2:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws2:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">DEF:<span class="re2">ws3=</span>/path/to/estadisticas.rrd:ws3:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws3<span class="re3">#FF8000:WebSer3\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws3:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws3:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws3:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws4=</span>/path/to/estadisticas.rrd:ws4:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws4<span class="re3">#<span class="nu0">400080</span>:WebSer4\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws4:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws4:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2">GPRINT:ws4:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws5=</span>/path/to/estadisticas.rrd:ws5:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws5<span class="re3">#0000FF:WebSer5\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws5:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2">GPRINT:ws5:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws5:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws6=</span>/path/to/estadisticas.rrd:ws6:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws6a<span class="re3">#00FFF0:WebSer6\t</span></div>
</li>
<li class="li2">
<div class="de2">GPRINT:ws6a:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws6:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws6:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">ws7=</span>/path/to/estadisticas.rrd:ws7:AVERAGE</div>
</li>
<li class="li2">
<div class="de2">LINE1:ws7<span class="re3">#FF00FF:WebSer7\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws7:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws7:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws7:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">DEF:<span class="re2">ws8=</span>/path/to/estadisticas.rrd:ws8:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE1:ws8<span class="re3">#FFFF00:WebSer8\t</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws8:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws8:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:ws8:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">DEF:<span class="re2">total=</span>/path/to/estadisticas.rrd:total:AVERAGE</div>
</li>
<li class="li1">
<div class="de1">LINE2:total<span class="re3">#FF0000:</span><span class="st0">&#8216;Total &nbsp; <span class="es0">\t</span>&#8216;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:total:AVERAGE:<span class="st0">&quot;Media <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">GPRINT:total:MAX:<span class="st0">&quot;Max <span class="es0">\:</span> %.4lf<span class="es0">\t</span>&quot;</span></div>
</li>
<li class="li2">
<div class="de2">GPRINT:total:MIN:<span class="st0">&quot;Min <span class="es0">\:</span> %.4lf<span class="es0">\l</span>&quot;</span></div>
</li>
<li class="li1">
<div class="de1">&gt;</div>
</li>
</ol>
</div>
<p>Para cada línea que queremos mostrar en la gráfica le indicamos de qué archivo rrd saldrán los datos y la fuente (DS) que vamos a utilizar. Añadimos además como leyenda los datos de media, máximo y mínimo de cada fuente, de manera que en una sola gráfica tenemos toda la información necesaria. Si ahora vas a la url donde has dejado el cgi tendrás:</p>
<p><strong>http://tudominio.com/cgi-bin/stats.cgi</strong></p>
<p><a href="http://blog.osusnet.com/wp-content/uploads/2009/11/stats.gif"><img class="aligncenter size-full wp-image-3038" title="stats" src="http://blog.osusnet.com/wp-content/uploads/2009/11/stats.gif" alt="stats Monitorizando aplicaciones web con rrdtool" width="470" height="421" /></a></p>
<p>Y tu te preguntarás, con lo pesado que te pones con <a href="http://www.cacti.net">Cacti</a>, ¿por qué no meterla ahí también? Buena pregunta <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Monitorizando aplicaciones web con rrdtool" /> . Si tengo un ratito os enseño cómo integrarlo también con <a href="http://www.cacti.net">Cacti</a> <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="Monitorizando aplicaciones web con rrdtool" /> .</p>
<p>Me he pasado con este artículo, no se lo va a leer nadie <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="Monitorizando aplicaciones web con rrdtool" /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/11/10/monitorizando-aplicaciones-web-con-rrdtool/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SCRUM de dos equipos en distintas ciudades</title>
		<link>http://blog.osusnet.com/2009/11/02/scrum-de-dos-equipos-en-distintas-ciudades/</link>
		<comments>http://blog.osusnet.com/2009/11/02/scrum-de-dos-equipos-en-distintas-ciudades/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 11:31:17 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Management]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[scrum]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=2735</guid>
		<description><![CDATA[El pasado mes de mayo comenzamos el desarrollo de un nuevo proyecto que ha terminado recientemente, al menos la primera fase del mismo. Partimos casi de cero, los requerimientos eran muy básicos y poco documentados, pero parte del equipo teníamos en la cabeza exactamente lo que teníamos que hacer, de hecho era plasmar en una [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>El pasado mes de mayo comenzamos el desarrollo de un nuevo proyecto que ha terminado recientemente, al menos la primera fase del mismo. Partimos casi de cero, los requerimientos eran muy básicos y poco documentados, pero parte del equipo teníamos en la cabeza exactamente lo que teníamos que hacer, de hecho era plasmar en una única aplicación todo nuestro trabajo de los últimos cuatro años.</p>
<p>Desde el principio nadie tuvo dudas, <a href="http://www.proyectosagiles.org/como-funciona-scrum">SCRUM</a> era la mejor metodología posible para cumplir los plazos que nos habían impuesto. Planteamos <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a> de dos semanas y <a href="http://www.proyectosagiles.org/reunion-diaria-de-sincronizacion-scrum-daily-meeting">dailys</a> diarios (obviamente) a las 10 de la mañana de alrededor de 10 minutos. Como <a href="http://www.proyectosagiles.org/facilitador-scrum-master">scrum master</a> se quedó uno de nuestros <em>project managers</em> y como <a href="http://www.proyectosagiles.org/cliente-product-owner">product owner</a> otro del departamento de operaciones. La mayoría nos habíamos leído ya el <a href="http://www.proyectalis.com/2008/02/26/scrum-y-xp-desde-las-trincheras/">Scrum desde las trincheras</a>, pero una cosa es la teoría y otra muy diferente la práctica, y ahí casi nadie teníamos experiencia.</p>
<p>No trataré en este artículo de enseñaros <strong>SCRUM</strong>, no soy un experto, como mucho un poco &#8220;<em>evangelizador</em>&#8221; <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="SCRUM de dos equipos en distintas ciudades" /> , simplemente trataré de explicar mis sensaciones tras cinco meses de <strong>SCRUM</strong> intensivo.</p>
<h3>El Equipo</h3>
<p>En el proyecto participaron dos <a href="http://www.proyectosagiles.org/equipo-team">equipos</a> de desarrollo, uno en Valencia de 6 personas y otro en Madrid en el que llegaron a trabajar más de 30. Ninguna de estas casi 40 personas tenía disponibilidad completa para este proyecto sino que hubo que redistribuir toda la carga de trabajo para, con el mismo equipo, asumir un nuevo proyecto de cinco meses de duración. Salió bastante bien. Los <a href="http://www.proyectosagiles.org/reunion-diaria-de-sincronizacion-scrum-daily-meeting">dailys</a> se hacían vía conferencia entre una sala de reuniones en Madrid y otra en Valencia. Se hicieron, además, infinidad de reuniones a dos bandas entre los dos equipos para decidir funcionalidades, discutir los puntos donde no había acuerdo y resolver dudas.  No sólo participaban desarrolladores sino también jefes de equipo, <em>project managers</em>, diseñadores, &#8220;expertos&#8221; en usabilidad, gente de <em>testing </em>y calidad, documentalistas, gente de sistemas, de <em>datawarehouse</em>&#8230;</p>
<p>En la parte tecnológica tuvimos otro grave problema. Desde Madrid desarrollaban en <strong>.NET</strong> y desde Valencia en <strong>PHP</strong>. ¿Cual es el problema? <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="SCRUM de dos equipos en distintas ciudades" /> . Se diseñó la arquitectura de manera que la aplicación trabajase indistintamente en uno u otro lenguaje. Dentro de un mismo entorno web, unos módulos se cargan de un lado y los otros del otro de forma completamente transparente al usuario. Se diseñó un sistema de <a href="http://es.wikipedia.org/wiki/Single_Sign-On">single sign on</a> que pudiesen compartir y consultar ambas tecnologías y, asociado a éste, todo un mecanismo de seguridad de acceso a distintos menús y opciones de la aplicación. El resultado fue formidable, todo funciona perfectamente de una manera integrada, robusta, eficiente y segura.</p>
<h3>La Pila de Producto (<em>product backlog</em>)</h3>
<p>Con la poca documentación que se tenía al principio se elaboró una pequeña <a href="http://www.proyectosagiles.org/lista-requisitos-priorizada-product-backlog">pila de producto</a> que fue creciendo a medida que las tareas de análisis evolucionaban. A esto debemos sumar requerimientos que iban llegando por parte de los departamentos comerciales y de operaciones. Al final el <a href="http://www.proyectosagiles.org/lista-requisitos-priorizada-product-backlog">backlog</a> era considerable. En agosto hubo que decidir quitar algunas <a href="http://www.proyectosagiles.org/introduccion-estimacion-planificacion-agil#historias-usuario">historias de usuario</a> ya que era imposible acometer todo lo que se quería, de hecho los requerimientos a estas alturas eran infinitamente superiores a los que se habían supuesto en mayo. Aún así, eliminando cosas, se hizo un producto mucho más ambicioso de lo esperado. Las historias de usuario eliminadas no se olvidaron, simplemente se trasladaron a una segunda versión.</p>
<p>Para el seguimiento del <strong>SCRUM</strong>, en vez de la clásica pizarra y dada la dispersión de los equipos, decidimos utilizar una herramienta de software. Comenzamos con un sencillo <em>Excel</em> y a mitad del proyecto incorporamos <a href="http://www.danube.com/scrumworks">ScrumWorks</a>, no creo que sea el programa ideal pero cumple su función.</p>
<h3>Los Sprints</h3>
<p>Los tres primeros <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a> fueron prácticamente de análisis. Se hicieron documentos funcionales y orgánicos de todos los módulos requeridos y se perdió bastante tiempo definiendo la arquitectura de la aplicación, en realidad de las dos aplicaciones (.NET y PHP). Todo esto nos llevó a plantarnos a mediados de junio, tras 3 <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a>, con muy poco que mostrar en la <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a>, y nos condujo a la consabida reprimenda de los que mandan, nos estábamos desviando (teóricamente) de la planificación estipulada. Sin embargo el tiempo nos daría la razón, el tiempo perdido en el diseño de la arquitectura se recuperó con creces en <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a> siguientes y llegamos a la fecha con el proyecto terminado. Bueno, en realidad dejamos para el final un pequeño detalle, el rendimiento, que se solucionó en un <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprint</a> adicional.</p>
<p>A todo esto hemos de añadir, como ya he dicho, que el equipo no estaba dedicado al proyecto, cada día variaba la gente que entraba al <a href="http://www.proyectosagiles.org/reunion-diaria-de-sincronizacion-scrum-daily-meeting">daily</a> ya que no todos estaban trabajando en el proyecto en ese momento. A eso hay que sumarle lo que llamo &#8220;<em>contingencias del trabajo diario</em>&#8220;, es decir, nuevos proyectos que van surgiendo durante todo ese tiempo y que implican dedicarle tiempo que tienes que quitarle a lo verdaderamente importante. Por si eso no fuera poco, a finales de junio se nos informa que una parte de la aplicación, un módulo de <em>reporting</em>, tiene que estar operativa a finales de julio puesto que se necesita para dar servicio en otros proyectos. Esto, que de palabra suena sencillo, nos obligó a modificar la planificación, el <a href="http://www.proyectosagiles.org/lista-requisitos-priorizada-product-backlog">product backlog</a> y la <a href="http://www.proyectosagiles.org/lista-tareas-iteracion-sprint-backlog">pila de sprint</a> ya que el funcionamiento de este módulo implicaba a otros (<em>login</em>, seguridad, diseño&#8230;). Y aún así cumplimos todos los plazos, increíble. Eso sí, otros proyectos tuvo que decidirse entre descartarlos o aprobar una desviación de una o dos semanas en el proyecto del que hablamos, con lo que de igual manera fueron descartados <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="SCRUM de dos equipos en distintas ciudades" /> .</p>
<h3>Las Estimaciones</h3>
<p>Uno de los mayores problemas es, sin duda, <a href="http://www.proyectosagiles.org/introduccion-estimacion-planificacion-agil">estimar las horas de las tareas</a>. Comenzamos quedándonos cortísimos y terminamos quedándonos cortos también, creo que rara vez se hizo una estimación cercana a la realidad. Es muy complicado, sin duda. Las tareas de análisis se sobrestimaron en su mayoría y las de desarrollo (la mayoría) se quedaron cortas. Para planificar los primeros <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a> utilizamos <a href="http://www.proyectosagiles.org/introduccion-estimacion-planificacion-agil">Poker-Scrum</a>, pero acabamos haciéndolo directamente de viva voz ya que decidimos que no aportaba nada. En los primeros <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a> hubo que arrastrar bastantes tareas de uno a otro porque se habían estimado muy a la baja, sin embargo hacia el final se recuperó el tiempo perdido y las estimaciones no eran tan malas.</p>
<h3>Las Demos</h3>
<p>Las <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demos</a> al cliente (interno en nuestro caso) son el peor momento del <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprint</a>, no pocos días nos tocó quedarnos hasta altas horas de la noche para llegar a la <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a> del día siguiente con el trabajo terminado o, al menos, visible. Si esto lo hacíamos cada dos semanas, imaginaos que hubiese pasado si utilizásemos metodologías tradicionales, hubiésemos llegado al final del tiempo de desarrollo sin hacer ninguna <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a>, sin haber probado las cosas de una manera real. Habría sido imposible, de hecho es lo que ocurre habitualmente <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="SCRUM de dos equipos en distintas ciudades" /> .</p>
<p>En nuestro caso nos sirvió no sólo para ver la reacción del cliente ante el avance del producto sino también para ver las fortalezas y debilidades del trabajo que estábamos desarrollando y reorientar los siguientes <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprints</a>.</p>
<p>Las demos están para que el <a href="http://www.proyectosagiles.org/cliente-product-owner">cliente</a> vea el avance del producto que se le está desarrollando. El cliente en nuestro caso era una persona en representación de uno o varios departamentos internos de la organización. ¿Qué utilidad tienen las demos si sólo asiste el <a href="http://www.proyectosagiles.org/cliente-product-owner">product owner</a>? Digo esto porque de vez en cuando aparecía por allí algún despistado que se dedicaba a criticar el producto, en concreto partes del mismo que llevaban dos o tres meses terminadas y validadas por el <a href="http://www.proyectosagiles.org/cliente-product-owner">product owner</a>. ¿Por qué esa actitud <em>revienta-demos</em>? O mejor aún, ¿por qué no le prestas el debido interés a un producto en el que se basará todo tu trabajo los próximos años? Ah, ya, es más fácil dejar la responsabilidad al <a href="http://www.proyectosagiles.org/cliente-product-owner">product owner</a> y después quejarse. Sin la implicación de toda la organización da igual qué metodología se utilice, ninguna conseguirá triunfar. Estamos hablando de media hora cada quince días, sólo eso.  Otro punto importante a tener en cuenta es la opinión. La gente que asiste a la <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a> debería estar obligada a decir algo y no quedarse callados como si no fuera con ellos porque al final ocurre lo mismo, cuando tienen que opinar no opinan y después, cuando ya no se puede hacer nada, es cuando hablan.</p>
<h3>Retrospectiva y planificación</h3>
<p>Las reuniones de <a href="http://www.proyectosagiles.org/retrospectiva-sprint-retrospective">retrospectiva</a> fueron bastante interesantes. Por un lado comentábamos la indiferencia de los asistentes a las demos y por otro discutíamos sobre los problemas que se habían presentado durante el <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprint</a>, unas veces con más energía y otras con menos. En realidad casi podríamos decir que servían como válvula de escape al <em>pasotismo</em> de los asistentes a la <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a>.  Son necesarias las <a href="http://www.proyectosagiles.org/retrospectiva-sprint-retrospective">retrospectivas</a>, sirven precisamente para evaluar no sólo lo que ha ocurrido sino también los ánimos del equipo.</p>
<p>Tras la retrospectiva llega la reunión de <a href="http://www.proyectosagiles.org/planificacion-iteracion-sprint-planning">planificación de sprint</a>. Tal como indicaba más arriba, las <a href="http://www.proyectosagiles.org/introduccion-estimacion-planificacion-agil">estimaciones</a> se hicieron muy complicadas, muchísimas tareas por historia de usuario, muchísimas dependencias entre ellas y no siempre tenemos todos en la cabeza las implicaciones que pueden tener unas con otras, lo que termina en estimaciones muy poco aproximadas por no decir aleatorias. Aún así poco a poco se fueron afinando bastante. En las reuniones de planificación se ponían sobre la mesa también nuevos requerimientos que habían ido surgiendo y modificaciones sobre los ya terminados que obligaban a modificar las prioridades de la <a href="http://www.proyectosagiles.org/lista-requisitos-priorizada-product-backlog">pila de producto</a> ajustando el calendario a las nuevas necesidades y objetivos hasta llegar a la <a href="http://www.proyectosagiles.org/lista-tareas-iteracion-sprint-backlog">pila del sprint</a> siguiente.</p>
<h3>Conclusiones</h3>
<p>Sin duda la experiencia ha sido <strong>muy positiva</strong>. En otras ocasiones habíamos hecho intentos de aplicar <strong>SCRUM </strong>a determinados proyectos  que resultaron en utilizar solamente algunos conceptos de <strong>SCRUM,</strong> pero la falta de implicación del cliente (casi siempre interno) restaba utilidad a la metodología. En esta ocasión se hizo una aplicación completa, real y efectiva, implicando a todos los elementos de la organización que tuviesen algo que decir dentro del proyecto y, aunque siempre se pueden hacer críticas a la implicación de algunos, podemos afirmar que, en general, todos cumplieron con su parte.</p>
<p>Una de las cosas de <strong>SCRUM</strong> que todos alabamos cinco meses después son, sin duda, los <a href="http://www.proyectosagiles.org/reunion-diaria-de-sincronizacion-scrum-daily-meeting">dailys</a>. Nos sirvieron a todos los partícipes del proyecto para conocer de buena mano qué estaban haciendo los demás, qué problemas había,  cuándo se iban a resolver, etc. Creo que cualquier equipo de desarrollo, independientemente de la metodología que utilice, debería realizar reuniones diarias para compartir ideas y problemas.</p>
<p>La idea de tener <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demos</a> del producto cada dos semanas obliga a todo el equipo a pensar más en hacer cosas que funcionen que en ir avanzando en tareas, es más importante terminar dos historias de usuario para presentar al final del <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprint</a> que comenzar 20 tareas que no se terminen.</p>
<p>Uno de los puntos que nos desviaron del objetivo en cada <a href="http://www.proyectosagiles.org/ejecucion-iteracion-sprint">sprint</a> fue el proceso de integración y preparación para la <a href="http://www.proyectosagiles.org/demostracion-requisitos-sprint-demonstration">demo</a>. Nunca tuvimos en cuenta estas horas que al final implicaban bastante tiempo de todo el equipo ya que al realizar la integración siempre había cosas que no funcionaban bien. El último día estaba dedicado casi íntegramente a estas labores que nunca estaban planificadas en la <a href="http://www.proyectosagiles.org/lista-tareas-iteracion-sprint-backlog">pila del sprint</a>.</p>
<p>Los que me conocen saben que llevo ya unos años defendiendo <strong>SCRUM</strong> como metodología adecuada para el desarrollo de software. Esta experiencia no ha hecho más que confirmar esta opinión, la adaptación del producto al cliente que se consigue no se podría lograr con metodologías clásicas en las que la más mínima modificación de las tareas a realizar puede provocar una desviación enorme.</p>
<p>Supongo que pagamos algo cara la falta de experiencia, sobre todo al principio, pero aún así logramos el objetivo, seguramente con un poco más de experiencia el resultado habría sido aún mejor.</p>
<p>Por cierto, no hemos dejado <strong>SCRUM</strong>, el proyecto sigue y ya trabajamos en la siguiente release, así que seguimos liados con dailys, sprints, estimaciones&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/11/02/scrum-de-dos-equipos-en-distintas-ciudades/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Regala lotería de Navidad 2009</title>
		<link>http://blog.osusnet.com/2009/08/27/regala-loteria-de-navidad-2009/</link>
		<comments>http://blog.osusnet.com/2009/08/27/regala-loteria-de-navidad-2009/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 16:30:05 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Negocios]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[loteria]]></category>
		<category><![CDATA[tusdecimos]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=2062</guid>
		<description><![CDATA[Como en años anteriores, ya está disponible la creación de participaciones de lotería a medida con el décimo de este año. Si vas a regalar lotería no dudes en utilizar TusDecimos.com, además de ser una manera original de hacerlo también  podrás enviar las participaciones por email o directamente al móvil de tus amigos y familiares. [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Como en <a href="http://blog.osusnet.com/2008/07/30/regala-loteria-y-personaliza-tus-participaciones-y-decimos/">años anteriores</a>, ya está disponible la creación de participaciones de lotería a medida con el décimo de este año.</p>
<p>Si vas a <a href="http://tusdecimos.com">regalar lotería</a> no dudes en utilizar <strong>TusDecimos.com</strong>, además de ser una manera original de hacerlo también  podrás enviar las participaciones por email o directamente al móvil de tus amigos y familiares.</p>
<p><a href="http://blog.osusnet.com/wp-content/uploads/2009/08/tusdecimos2009.gif"><img class="aligncenter size-full wp-image-2063" title="tusdecimos2009" src="http://blog.osusnet.com/wp-content/uploads/2009/08/tusdecimos2009.gif" alt="tusdecimos2009 Regala lotería de Navidad 2009" width="470" height="283" /></a></p>
<p>En unas semanas os daré alguna sorpresa al respecto <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' title="Regala lotería de Navidad 2009" />  .<br />
¡Mucha suerte a todos!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/08/27/regala-loteria-de-navidad-2009/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Cucharete.com finalista de los Premios de Internet 2009</title>
		<link>http://blog.osusnet.com/2009/05/11/cucharetecom-finalista-de-los-premios-de-internet-2009/</link>
		<comments>http://blog.osusnet.com/2009/05/11/cucharetecom-finalista-de-los-premios-de-internet-2009/#comments</comments>
		<pubDate>Mon, 11 May 2009 10:38:45 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[aui]]></category>
		<category><![CDATA[cucharete]]></category>
		<category><![CDATA[marcos]]></category>
		<category><![CDATA[premio]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=1906</guid>
		<description><![CDATA[La Asociación de Usuarios de Internet organiza la XI edición de sus Premios de Internet y menuda sorpresa nos hemos llevado al ver entre los diez finalisdas de la caterogía C1-Mejor Web a Cucharete, la mejor web de restaurantes de Madrid. Sin duda alguna esta candidatura es premio al trabajo y al esfuerzo que están [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>La <a href="http://aui.es/">Asociación de Usuarios de Internet</a> organiza la XI edición de sus <a href="http://www.premiosdeinternet.org/">Premios de Internet</a> y menuda sorpresa nos hemos llevado al ver entre los diez finalisdas de la caterogía <a href="http://www.premiosdeinternet.org/index.php?body=categoria&amp;id_rubrique=4">C1-Mejor Web</a> a Cucharete, la mejor web de <a href="http://www.cucharete.com">restaurantes de Madrid</a>.</p>
<p style="text-align: center;"><a href="http://blog.osusnet.com/wp-content/uploads/2009/05/cucharete.jpg"><img class="aligncenter size-full wp-image-1907" title="cucharete" src="http://blog.osusnet.com/wp-content/uploads/2009/05/cucharete.jpg" alt="cucharete Cucharete.com finalista de los Premios de Internet 2009" width="282" height="259" /></a></p>
<p>Sin duda alguna esta candidatura es premio al trabajo y al esfuerzo que están realizando tanto <a href="http://www.marcosgarcia.es">Marcos</a> como su equipo para sacar adelante este bonito y <em>suculento</em> proyecto.</p>
<p>Mi más sincera enhorabuena.</p>
<p><span style="text-decoration: underline;"><strong>Actualizado a las 16:00 </strong></span></p>
<p>Ahora mismo quedan sólo tres finalistas, <strong>Cucharete</strong> entre ellos. Increíble.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/05/11/cucharetecom-finalista-de-los-premios-de-internet-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Mobile Pack, plugin para movilizar tu WordPress</title>
		<link>http://blog.osusnet.com/2009/05/06/wordpress-mobile-pack-plugin-para-movilizar-tu-wordpress/</link>
		<comments>http://blog.osusnet.com/2009/05/06/wordpress-mobile-pack-plugin-para-movilizar-tu-wordpress/#comments</comments>
		<pubDate>Wed, 06 May 2009 14:47:41 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Móvil]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[dotmobi]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=1886</guid>
		<description><![CDATA[Menuda sorpresa me he llevado hoy al leer esta noticia. Ha habido otros intentos de hacer algo similar pero ninguno llegaba a la perfección que roza este nuevo plugin ya que lo ajusta todo al terminal del cliente, desde las imágenes hasta la paginación de artículos. En el link de presentación tenéis toda la información. [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Menuda sorpresa me he llevado hoy al leer esta noticia.</p>
<p>Ha habido otros intentos de hacer algo similar pero ninguno llegaba a la perfección que roza este nuevo plugin ya que lo ajusta todo al terminal del cliente, desde las imágenes hasta la paginación de artículos. En el <a href="http://mobiforge.com/running/story/the-dotmobi-wordpress-mobile-pack">link de presentación</a> tenéis toda la información. No podía ser menos viniendo del organismo &#8220;oficial&#8221; de la web móbil, <a href="http://mtld.mobi/">dotMobi</a>.</p>
<p>Entre las características que me parecen importantes y fundamentales en un producto de este tipo y que hasta ahora otros habían obviado limitándose a presentar un blog menos recargado:</p>
<ul>
<li>Detecta el móvil del cliente y consulta la base de datos de <a href="http://deviceatlas.com/">DeviceAtlas</a> para obtener sus características (tamaño de pantalla, colores&#8230;).</li>
<li>Puedes hacer que cualquier petición a un dominio sea automáticamente móvil independientemente del dispositivo que acceda (m.tudominio.com).</li>
<li>Selección de temas concretos para la versión móvil independiente del web. No tienes que empezar de cero.</li>
<li>Versión móvil del panel de administración para publicar directamente desde tu dispositivo.</li>
<li>Paginación de artículos. En otros productos se mostraban en una sóla página y no todo el mundo escribe artículos pequeños <img src='http://blog.osusnet.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' title="WordPress Mobile Pack, plugin para movilizar tu Wordpress" />  .</li>
</ul>
<p>Ahora me toca personalizar el tema, pero aquí tenéis mi blog en un Nokia N95.</p>
<p><a href="http://blog.osusnet.com/wp-content/uploads/2009/05/screenshot0097.jpg"><img class="aligncenter size-medium wp-image-1887" title="Cerebro en la Sombra para móviles" src="http://blog.osusnet.com/wp-content/uploads/2009/05/screenshot0097-150x300.jpg" alt="Cerebro en la Sombra para móviles" width="150" height="300" /></a></p>
<p>Os recomiendo que le echéis un ojo ya que es muy interesante y hace todo el proceso de <strong>movilización</strong> de tu blog extremadamente sencillo.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/05/06/wordpress-mobile-pack-plugin-para-movilizar-tu-wordpress/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Adobe AIR VIII &#8211; Información encriptada y persistente</title>
		<link>http://blog.osusnet.com/2009/03/29/adobe-air-viii-informacion-encriptada-y-persistente/</link>
		<comments>http://blog.osusnet.com/2009/03/29/adobe-air-viii-informacion-encriptada-y-persistente/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 17:15:56 +0000</pubDate>
		<dc:creator>Osus</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[R.I.A.]]></category>
		<category><![CDATA[Técnico]]></category>
		<category><![CDATA[adobe]]></category>
		<category><![CDATA[air]]></category>
		<category><![CDATA[flex]]></category>

		<guid isPermaLink="false">http://blog.osusnet.com/?p=1520</guid>
		<description><![CDATA[Ya hemos visto como trabajar con bases de datos con AIR, sin embargo he deubierto un nuevo método para conservar datos que puede resultar especialmente útil para mantener información sensible, como claves de acceso a servicios, ya que se guarda encriptada. Hablamos de la clase EncryptedLocalStore. Una de las peculiaridades de esta clase es que [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:right;"></div><p>Ya hemos visto como trabajar con bases de datos con <strong>AIR</strong>, sin embargo he deubierto un nuevo método para conservar datos que puede resultar especialmente útil para mantener información sensible, como claves de acceso a servicios, ya que se guarda encriptada. Hablamos de la clase <strong>EncryptedLocalStore</strong>.</p>
<p>Una de las peculiaridades de esta clase es que es persistente mientras la aplicación no borre sus contenidos, ya que aunque se desinstale los datos siguen ahí, lo que resulta especialmente útil si tus aplicaciones son de pago (guardar licencias) o tienen periodos de prueba (así no se podrá utilizar de nuevo al desinstalar y volver a instalarla).</p>
<p>Cada aplicación dispone de su propia <strong>EncryptedLocalStore</strong> con lo que los datos que se guarden en una no interferirán con los de otra.<strong><br />
</strong></p>
<p><strong>EncryptedLocalStore</strong> tiene sólamente tres métodos estáticos (no es necesario instanciar la clase) que permiten guardar, leer y eliminar datos.</p>
<ul>
<li><strong>setItem(&#8220;nombre&#8221;, valor)</strong>:  guarda un dato.</li>
<li><strong>getItem(&#8220;nombre&#8221;)</strong>:  lee el dato.</li>
<li><strong>removeItem(&#8220;nombre&#8221;)</strong>:  elimina los datos.</li>
</ul>
<p>Para dar mayor versatilidad al sistema, los datos a guardar deben ser del tipo <strong>ByteArray</strong>, así que se podrá guardar cualquier dato que se pueda convertir a este tipo y no sólo cadenas de texto.</p>
<p>Veamos un ejemplo:</p>
<div class="dean_ch" style="white-space: nowrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">//guardar datos</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">var</span> clave:<span class="kw3">String</span> = <span class="st0">&quot;password&quot;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">var</span> bytes:ByteArray = <span class="kw2">new</span> ByteArray<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">bytes.<span class="me1">writeUTFBytes</span><span class="br0">&#40;</span>str<span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">EncryptedLocalStore.<span class="me1">setItem</span><span class="br0">&#40;</span><span class="st0">&quot;clave&quot;</span>, bytes<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">//leer datos</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">var</span> datos:ByteArray = EncryptedLocalStore.<span class="me1">getItem</span><span class="br0">&#40;</span><span class="st0">&quot;clave&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">var</span> miclave:<span class="kw3">String</span>=datos.<span class="me1">readUTFBytes</span><span class="br0">&#40;</span>datos.<span class="kw3">length</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">//eliminar datos</span></div>
</li>
<li class="li1">
<div class="de1">EncryptedLocalStore.<span class="me1">removeItem</span><span class="br0">&#40;</span><span class="st0">&quot;clave&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>Extremadamente sencillo y útil, no se como no lo había visto antes, creo que pasa bastante desapercibida esta manera de guardar datos en la documentación.</p>
<p>De esta manera podemos guardar datos sin necesidad de bases de datos. Eso sí, al parecer no deben exceder los 10mb o comenzaremos a tener problemas de rendimiento. Recuerda lo que decía al principio, aunque el usuario desinstale la aplicación los datos de <strong>EncryptedLocalStore </strong>siguen en su sistema operativo.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.osusnet.com/2009/03/29/adobe-air-viii-informacion-encriptada-y-persistente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
