<?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>unreal4u&#039;s Personal Network &#187; Mundo Web</title>
	<atom:link href="http://blog.unreal4u.com/category/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.unreal4u.com</link>
	<description>Because my reality... is just your virtuality</description>
	<lastBuildDate>Tue, 07 Sep 2010 17:20:48 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>¿Problemas en los tildes o acentos?</title>
		<link>http://blog.unreal4u.com/2010/09/problemas-en-los-tildes-o-acentos/</link>
		<comments>http://blog.unreal4u.com/2010/09/problemas-en-los-tildes-o-acentos/#comments</comments>
		<pubDate>Thu, 02 Sep 2010 17:25:08 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Bases de Datos (MySQL)]]></category>
		<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=432</guid>
		<description><![CDATA[Desde que empecé en esto de la Web, siempre tuve un problema: las tildes. O me salía el típico signo de pregunta o bien me salían caracteres extraños, que intentando por aquí y por allá siempre lograba evitar, aunque a veces me superaba y optaba simplemente por terminar escribiendo su entidad.
Aunque no pretendo arreglarle la [...]]]></description>
			<content:encoded><![CDATA[<p>Desde que empecé en esto de la Web, siempre tuve un problema: las tildes. O me salía el típico signo de pregunta o bien me salían caracteres extraños, que intentando por aquí y por allá siempre lograba evitar, aunque a veces me superaba y optaba simplemente por terminar escribiendo <a href="http://www.w3schools.com/tags/ref_entities.asp">su entidad</a>.</p>
<p>Aunque no pretendo arreglarle la vida a todo el mundo, en este post sí les dejaré algunos tips para asegurarse de que todo funciona como debería: se verán algunas funciones de PHP que sirven harto y se verá superficialmente la interacción con bases de datos.<br />
Dato rosa antes de continuar: la diferencia entre acento y tilde, es que <strong>tilde</strong> <span style="text-decoration: underline;">representa el signo</span> " <code>´</code> " mientras que <strong>acento</strong> se refiere a la <span style="text-decoration: underline;">fuerza</span> que se le impregna a la sílaba específica. De esta manera, en la palabra "sílaba", el tilde está en la letra "i", mientras que el acento está en la sílaba "sí".<br />
<span id="more-432"></span></p>
<h2>Barniz teórico</h2>
<p>Los charset no son más que códigos mediante los cuales el computador guarda de forma binaria la representación de un caracter que nosotros podamos entender y comprender.<br />
De esta manera, el computador no <em>entiende</em> lo que significa la letra "A", pero sí conoce cómo trabajar con el número hexadecimal 65, representación de "A".<br />
Es en esta última etapa donde está el problema: las codificaciones disponibles por razones históricas no son las mismas, por lo que en un charset determinado, la letra "A" podría estar representada por el número 190 y en otro por el 65.</p>
<p>Volviendo un poco a la realidad actual, hoy en día tenemos 2 codificaciones que son las más populares: la ISO-8859-1 y UTF-8. Aunque en sus primeros 127 caracteres son iguales, a partir de ahí la cosa cambia, aunque no mucho.<br />
Sin embargo, para la desgracia de los hispano-hablantes, cada letra que nos hace distinto al inglés, tiene una codificación distinta. Esto quiere decir que justamente las letras con tildes son aquellas que confundiéndolos de codificación, no vamos a poder entender y nos aparecen todo tipo de caracteres extraños, un signo de pregunta en caso de querer imprimir la letra "á" de ISO-8859-1 en una codificación UTF-8 y dos símbolos extraños (dos debido a que UTF-8 guarda la letra "á" en dos bytes en vez de uno) en caso de querer ver "á" codificado en UTF-8 en una codificación ISO-8859-1. Suena un poco enredado, pero tiene su lógica.</p>
<h2>Empezando a solucionar el problema</h2>
<p>Desde que comprendí el esquema de trabajo, es que empecé a ser constante, y es lo más importante sin duda. Sucede que las codificaciones están en todos lados: desde el archivo mismo con el que uno trabaja hasta la consulta que la DB devuelve.<br />
Para esto, primero debemos aclarar con cuál charset nos quedamos. Por opción personal, prefiero UTF-8 debido a que es más nuevo y más compatible a nivel global, no importando el sistema operativo. Un Linux instalado en China con sólo lo mínimo, es probable que no entienda la codificación ISO-8859-1 que es la latinoamericana, pero sí va a tener UTF-8 instalada.</p>
<p>Partiendo por esto, es que debemos asegurarnos en primer lugar que los archivos que creemos estén codificadas bajo UTF-8. En Linux, el cambio es fácil de hacer gracias a iconv, basta hacer un<br />
<code>iconv -f ISO-8859-1 -t UTF-8 -o salida.txt entrada.txt</code><br />
para convertir uno (o más) archivos desde ISO-8859-1 a UTF-8. En Windows el asunto se pone un poco más complejo: el único método que sé que funciona es bajando <a href="http://www.pspad.com/es/">PSPad</a> y haciendo la conversión desde dentro del programa. Puede que exista una forma más fácil, pero no tengo ningún Windows a mano en este momento como para ponerme a averiguar.</p>
<p>Después de los archivos le toca a la base de datos. Ojo que en MySQL, la codificación UTF-8 no existe! Sólo existe utf8 (en minúsculas sin raya) y por supuesto latin1, que sería el equivalente a ISO-8859-1. Obviamente existen muchas codificaciones más, las que <a href="http://dev.mysql.com/doc/refman/5.1/en/charset-charsets.html">pueden ver aquí</a>.<br />
Por lo general a MySQL le importa poco y nada el charset con el cual guarda los datos, sólo le importa el charset con el que <strong>entrega</strong> los datos, así que con decirle que trate todos los datos salientes en esa conexión como UTF-8 debería ser suficiente. ¿No sabe cómo? <a href="http://www.phpclasses.org/package/5812-PHP-MySQL-database-access-wrapper-using-MySQLi.html">Ocupe mi class</a> <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Si estás ocupando otro motor, ya depende de cada uno. En PostGreSQL por ejemplo, se define el charset cuando se crea la base de datos (échenle un vistazo <a href="http://www.chw.net/foro/bases-de-datos-f222/567361-miniguia-pasar-una-base-psql-de-sql_ascii-a-utf8.html">a este thread en CHW</a> para saber cómo cambiar de uno a otro), mientras que en otros motores la cosa puede ser un poco más difícil. De todas maneras, siempre debería ser posible poder cambiar el charset.</p>
<p>Finalmente, está la salida hacia el navegador.<br />
Aunque por lo general el navegador podrá averiguar por si solo el charset del documento (Apache tomará el control), hay veces que tanto Apache o el navegador no sabrán qué codificación aplicar. Para evitar estos errores, se debe usar PHP para señalar qué charset se ocupará en el documento, lo cual es algo que veremos en el próximo capítulo.</p>
<h2>Funciones útiles de PHP</h2>
<p>Algunas funciones muy útiles de PHP son sin duda el poderoso <a href="http://www.php.net/manual/en/function.iconv.php">iconv()</a> y en menor medida <a href="http://www.php.net/manual/en/function.utf8-encode.php">utf8_encode()</a> y <a href="http://www.php.net/manual/en/function.utf8-decode.php">utf8_decode()</a>. También sirven de utilidad <a href="http://www.php.net/manual/en/function.htmlentities.php">htmlentities()</a> (que por supuesto tiene su inversa <a href="http://www.php.net/manual/en/function.html-entity-decode.php">html_entity_decode()</a>) y su casi simil <a href="http://www.php.net/manual/en/function.htmlspecialchars.php">htmlspecialchars()</a>. Por supuesto que también es importante la función <a href="http://www.php.net/manual/en/function.header.php">header()</a>, ya que sin ella Apache asumirá el control, lo cual obviamente no es la idea.<br />
Existen otras funciones que hacen cosas parecidas o que extienden las funcionalidades, pero jamás las he ocupado y para casi cualquier operación que se quiera hacer, con el uso de estas funciones uno está más que bien.</p>
<p>Pero qué se puede hacer con estas funciones? Básicamente, convertir de un formato a otro.<br />
Aunque claramente están explicadas en el manual, haré un pequeño resumen acerca de qué es lo que hacen estas funciones: </p>
<p><strong>iconv</strong>: Convierte de un charset a otro arbitrariamente. Ejemplo de uso: </p>
<pre class="brush: php;">$cadena = iconv('ISO-8859-1','UTF-8//TRANSLIT','cádéñá cón tíldés');</pre>
<p>El primer parámetro es origen, segundo destino y le agregué TRANSLIT para que de esta manera, se "traduzca" la letra que no se conoce lo mejor posible. Esto podría llegar a pasar con algunos caracteres extraños.</p>
<p><strong>utf8_encode</strong> y <strong>utf8_decode</strong>: Respectivamente, son sinónimos para:</p>
<pre class="brush: php;">
iconv('ISO-8859-1','UTF-8//TRANSLIT','cádéñá cón tíldés');
iconv('UTF-8','ISO-8859-1//TRANSLIT','cádéñá cón tíldés');
</pre>
<p><strong>htmlentities</strong>: Convierte todos los caracteres que tienen alguna equivalencia en entidad a su respectiva entidad. Sugiero leer la documentación oficial ya que es bien powa esta función.</p>
<p><strong>html_entity_decode</strong>: Lo mismo que la anterior, pero al revés.</p>
<p><strong>htmlspecialchars</strong>: Lo mismo que htmlentities pero sólo se aplica a los siguientes caracteres:<br />
&#038; => &amp;amp;<br />
" => &amp;quot; (Sólo cuando ENT_NOQUOTES no se encuentra presente)<br />
' => &amp;#039; (Sólo cuando ENT_QUOTES está presente)<br />
< => &amp;lt;<br />
> => &amp;gt;</p>
<p><strong>header</strong>: Permite mandar cabeceras al navegador. Lo más genial de esta función es que nos permite enviar el charset de la siguiente forma: </p>
<pre class="brush: php;">
define('CHARSET','UTF-8');
header('Content-type: text/html; charset='.CHARSET);
</pre>
<h2>Conclusiones</h2>
<p>Para trabajar de una buena manera, recomiendo en muy resumidas cuentas: </p>
<ul>
<ol>Crea todos tus archivos bajo la codificación UTF-8</ol>
<ol>Mantén la base de datos (y por supuesto las tablas en el caso de MySQL) bajo la codificación UTF-8</ol>
<ol>Siempre señala en tu cabecera la codificación que irá a ocupar la página.</ol>
</ul>
<p>Espero que les haya servido el post. Intenté hacerlo lo más corto posible sin caer en hacerlo demasiado complicado.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/09/problemas-en-los-tildes-o-acentos/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Abrir todos los links externos en nueva ventana</title>
		<link>http://blog.unreal4u.com/2010/08/abrir-todos-los-links-externos-en-nueva-ventana/</link>
		<comments>http://blog.unreal4u.com/2010/08/abrir-todos-los-links-externos-en-nueva-ventana/#comments</comments>
		<pubDate>Sun, 29 Aug 2010 05:05:04 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mundo Web]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=429</guid>
		<description><![CDATA[Hace un tiempo atrás, necesitaba que todos los links externos fueran abiertos en una nueva ventana. Primero hice una función en PHP que cuando construía el link, detectaba si el mismo era interno o externo y si era externo, lo dejaba con el famoso target="_BLANK". Sin embargo, al poco tiempo después me di cuenta que [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un tiempo atrás, necesitaba que todos los links externos fueran abiertos en una nueva ventana. Primero hice una función en PHP que cuando construía el link, detectaba si el mismo era interno o externo y si era externo, lo dejaba con el famoso target="_BLANK". Sin embargo, al poco tiempo después me di cuenta que ésta no era la solución ideal ya que fallaba en dos aspectos fundamentales: Si el link era construido mediante TinyMCE (o sea, por el usuario), no pasaba por el "constructor" de links. Por otro lado, el código generado no era compatible con la W3C en el modo estricto (En este modo, se elimina el atributo "target").<br />
Así que me puse a investigar qué necesitaba para que cumpliera con los dos propósitos... ¿La respuesta? JavaScript, y si podía utilizar el poder de selección de la librería jQuery, aún mejor. El resultado fue que todos los links externos de la página, independiente de quién las haya creado, se abren en otra ventana y lo mejor de todo es que el código de la página es compatible con la W3C.</p>
<pre class="brush: jscript;">
$(document).ready(function(){$('a:not([href^=&quot;http://blog.unreal4u.com/&quot;])').attr(&quot;target&quot;,&quot;_BLANK&quot;);});
</pre>
<p>Obviamente tiene que reemplazar <em>http://blog.unreal4u.com/</em> con la ruta de su aplicación.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/08/abrir-todos-los-links-externos-en-nueva-ventana/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Búsqueda de PHP.net en Firefox y trucos de vim</title>
		<link>http://blog.unreal4u.com/2010/08/busqueda-de-php-net-en-firefox-y-trucos-de-vim/</link>
		<comments>http://blog.unreal4u.com/2010/08/busqueda-de-php-net-en-firefox-y-trucos-de-vim/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 14:24:06 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=391</guid>
		<description><![CDATA[Hoy me di cuenta de algo que no me había dado cuenta. (duuuh)
Siempre, cuando necesitaba buscar alguna función en PHP.net, hacía la típica: iba a Google, tipeaba el nombre de la función, ubicaba PHP.net y hacía click.
Bueno, como casi todos los grandes descubrimientos de la humanidad, estaba en la portada de PHP.net y por accidente [...]]]></description>
			<content:encoded><![CDATA[<p>Hoy me di cuenta de algo que no me había dado cuenta. (duuuh)<br />
Siempre, cuando necesitaba buscar alguna función en PHP.net, hacía la típica: iba a Google, tipeaba el nombre de la función, ubicaba PHP.net y hacía click.<br />
Bueno, como casi todos los grandes descubrimientos de la humanidad, estaba en la portada de PHP.net y por accidente hice clic donde no debía. Descubrí esto:</p>
<p><img src="http://blog.unreal4u.com/wp-content/uploads/2010/08/php.png" alt="" /></p>
<p>Sin embargo, el verdadero potencial de este post está por verse, veamos algunos comandos semi-avanzados de vim que nos hará la vida mucho más fácil al trabajar con este editor.<span id="more-391"></span></p>
<p>Lo primero, (y más importante) a mi gusto, es instalar el manual de PHP en vim. Para esto, debemos tener instalado man y pear. De ahí, se procede a la instalación del manual.</p>
<p>En  CentOS, todo esto se haría como:</p>
<pre class="brush: bash;"># yum install php-pear man
# pear install doc.php.net/pman
</pre>
<p>Y estaríamos con el 80% de la pega adelantada ya. Lo más importante, sin embargo, viene ahora.</p>
<p>Debemos, primero que nada, abrir el archivo ~/.vimrc. Si no existe, lo creamos. En ella, podemos configurar a nuestro gusto total vim, incluyendo opciones tan avanzadas como agrupar código (en una sola línea), poner el número de línea del código o consultar el manual de PHP con una tecla mientras estamos en la función. (Muy al estilo man).</p>
<p>Esta es mi configuración actual de vim:</p>
<pre class="brush: plain;">
set tabstop=2
set autoindent
set incsearch
set number
set keywordprg=pman
autocmd FileType php let php_folding=1
au BufWinLeave * mkview
au BufWinEnter * silent loadview
</pre>
<p>Explicaré cada línea:<br />
<em>set tabstop=2</em>: Esto nos permite que, cuando apretemos tab, inserte espacios en vez de un tab. La cantidad de espacios es definida después del signo igual.<br />
<em>set autoindent</em>: Esta muy útil función permite que vim siga las reglas de indentación que tiene el archivo. Muy útil.<br />
<em>set incsearch</em>: permite que, muy al estilo búsqueda rápida de Firefox, se vaya ubicando automáticamente el cursor en cuanto estemos buscando alguna frase.<br />
<em>set number</em>: le pone número a las líneas.<br />
<em>set keywordprg=pman</em>: esta línea hace que integremos pman con vim, para que de esta manera, al apretar "K" (k mayúscula) sobre alguna función en específico aparezca el manual.<br />
El resto: Activa la agrupación de código. La primera línea inicia la característica en sí, mientras que las dos siguientes guardan y cargan automáticamente las agrupaciones respectivamente.<br />
Se debe utilizar en conjunto con algunos comandos:</p>
<ul>
<ol><strong>:20,40 fo</strong><br />
Para agrupar de la línea 20 a la 40.
</ol>
<ol><strong>zfa}</strong><br />
Para agrupar de aquí a la próxima llave, aunque ojo: se debe estar posicionado sobre la llave que abre!</ol>
<ol><strong>zd</strong><br />
Para eliminar el fold actual</ol>
<ol><strong>zm</strong><br />
Para refoldear todos los folds anteriores.</ol>
<ol>Para más comandos útiles, visitar la tercera fuente.</ol>
</ul>
<p>Hay bastantes más consejos para vim, pero no todos me funcionaron. Una de las más populares que he visto dando vueltas por internet es activar la vista de código HTML o queries dentro de los string, pero no me funcionaron. Tampoco me funcionó desactivar los tags cortos, así que ojo con eso.</p>
<p>Fuentes:<br />
<a href="http://phpslacker.com/2009/02/05/vim-tips-for-php-programmers/">PHPSLACKER</a><br />
<a href="http://bjori.blogspot.com/2010/01/unix-manual-pages-for-php-functions.html">bjori doesn't blog</a><br />
<a href="http://www.linux.com/archive/feature/114138">Linux.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/08/busqueda-de-php-net-en-firefox-y-trucos-de-vim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo ocupar ob_start(), ob_get_contents() y otros relacionados</title>
		<link>http://blog.unreal4u.com/2010/08/como-ocupar-ob_start-ob_get_contents-y-otros-relacionados/</link>
		<comments>http://blog.unreal4u.com/2010/08/como-ocupar-ob_start-ob_get_contents-y-otros-relacionados/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 15:01:04 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=384</guid>
		<description><![CDATA[Pensando en qué truco podría ser útil, me acordé de los famosos ob_* que en un principio me parecían bastante complicados e inútiles.
Sin embargo, hoy constituyen un pilar fundamental en mi ambiente de desarrollo, puesto que me permiten ejecutar código, y poder redirigir a alguna página en específico incluso después de haberse ejecutado la página [...]]]></description>
			<content:encoded><![CDATA[<p>Pensando en qué truco podría ser útil, me acordé de los <a href="http://cl.php.net/manual-lookup.php?pattern=ob_">famosos ob_*</a> que en un principio me parecían bastante complicados e inútiles.</p>
<p>Sin embargo, hoy constituyen un pilar fundamental en mi ambiente de desarrollo, puesto que me permiten ejecutar código, y poder redirigir a alguna página en específico incluso después de haberse ejecutado la página completa. Por supuesto, también me permite insertar contenido Javascript en los headers <strong>después</strong> de haber ejecutado la página.</p>
<p>¿Pero cómo se ocupa? Para esto es este post.<br />
<span id="more-384"></span><br />
Antes de poder imprimir código, debo explicar para qué sirve: ob_* controlan un <strong>buffer</strong>, el cual se puede controlar. La gracia es que la salida puede ser demorada por lo que podemos hacer cualquier acción, ya sea redirigir a otra página o -a mi gusto la más importante- poder controlar las cabeceras en cualquier momento, ideal para una carga por partes de la aplicación, sin caer en cargar partes que ni siquiera ocuparemos.</p>
<p>Existen específicamente 3 funciones que yo diría son las más importantes:</p>
<ul>
<li>ob_start(): que le da comienzo al buffer</li>
<li>ob_flush(): que permite limpiar el buffer imprimiendo toda la salida</li>
<li>ob_get_contents(): que permite obtener los contenidos del buffer <strong>sin imprimir en pantalla</strong></li>
<li>ob_end_clean(): que permite desechar todo el buffer, <strong>sin imprimir en pantalla</strong></li>
</ul>
<p>Dicho eso, podemos proceder a nuestro primer ejemplo:</p>
<pre class="brush: php;">
ob_start();
echo 'hola mundo';
if (!file_exists('chao.txt')) header('Location: http://www.google.com/');
$contenido = ob_get_contents();
ob_end_clean();

include('cabecera.php');
echo $contenido;
include('pie-pagina.php');
</pre>
<p>Este archivo hace lo siguiente: Imprime "hola mundo", revisa si existe el archivo chao.txt y si no existe, redirige a Google. Si existe el archivo entonces sigue la carga normal. ¿Se entendió? Veamos un último ejemplo un poco más completo entonces:</p>
<p><em><strong>index.php</strong></em> </p>
<pre class="brush: php;">
include('carga-previa.php');
ob_start();
echo '&lt;h1&gt;Hola mundo&lt;/h1&gt;';
if (!is_readable('chao.txt')) $msgStack-&gt;add('No se encontró el archivo!');
else $msgStack-&gt;add('Se encontró el archivo!');
$titulo = 'Hola mundo';
$contenido = ob_get_contents();
ob_end_clean();

include('cabecera.php');
echo $contenido;
include('pie-pagina.php');
</pre>
<p><em><strong>carga-previa.php</strong></em></p>
<pre class="brush: php;">
class messages() {
  private $aMsgs = array();

  public function add($msg) {
    if (!empty($msg)) $this-&gt;aMsgs[] = '&lt;h4 class=&quot;mensaje&quot;&gt;'.$msg.'&lt;/h4&gt;';
    return TRUE;
  }

  public function print() {
    if (count($this-&gt;aMsgs) &gt; 0) {
      foreach($this-&gt;aMsgs AS $a) {
        echo $a;
      }
    }
    return TRUE;
  }
}

$msgStack = new messages();
</pre>
<p><em><strong>cabecera.php</strong></em></p>
<pre class="brush: php;">
echo '&lt;html&gt;&lt;head&gt;&lt;title&gt;';
if (!empty($titulo)) echo $titulo;
else echo 'sin titulo';
echo '&lt;/title&gt;&lt;/head&gt;&lt;body&gt;';
$msgStack-&gt;print();
</pre>
<p>Ahora bien, no tiene ninguna gracia tener que escribir 20 líneas de código cuando nos podríamos ahorrar todo eso en un solo paso. Veamos nuevamente cómo podemos ahorrar bastante código y a la vez tener control absoluto sobre la aplicación:</p>
<p><em><strong>index.php</strong></em></p>
<pre class="brush: php;">
include('carga-previa.php');
include('cabecera.php');
echo $contenido;
include('pie-pagina.php');
</pre>
<p><em><strong>carga-previa.php</strong></em></p>
<pre class="brush: php;">
class messages() {
  // etc
}

if (empty($_GET['a'])) $_GET['a'] = 'index';
else $_GET['a'] = strtolower($_GET['a']);

$msgStack = new messages();
$myLink   = new DB_mysql();
// cargar otras classes

ob_start();
if (is_readable('includes/paginas/'.$_GET['a'].'.php')) include('includes/paginas/'.$_GET['a'].'.php');
else include('includes/paginas/not-found.php');
$contenido = ob_get_contents();
ob_end_clean();
</pre>
<p>Las demás páginas siguen tal cual como venían originalmente. Ahora lo único que debemos hacer para cargar por ejemplo las noticias es poner en nuestro navegador<br />
<strong>www.ejemplo.com/?a=noticias</strong> o bien<br />
<strong>www.ejemplo.com/?a=login</strong><br />
para cargar el login. Si a esto le sumamos un poco de htaccess, podemos cargar la página respectiva mediante<br />
<strong>www.ejemplo.com/noticias/</strong> o<br />
<strong>www.ejemplo.com/login/</strong>.</p>
<p>En resumen: ob_* permite crear páginas con mucho poder de administración, fáciles y super rápidas de hacer en cuanto a desarrollo, de una forma elegante y cómoda.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/08/como-ocupar-ob_start-ob_get_contents-y-otros-relacionados/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Verificar RUT con Javascript y PHP</title>
		<link>http://blog.unreal4u.com/2010/03/verificar-rut-con-javascript-y-php/</link>
		<comments>http://blog.unreal4u.com/2010/03/verificar-rut-con-javascript-y-php/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 04:08:59 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=359</guid>
		<description><![CDATA[Sí, estamos totalmente de acuerdo: hay por lo menos unos 50 validadores distintos si buscamos en Internet. Sin embargo, este validador es uno distinto: lo hice yo   
Fuera de bromas, es un script bastante cortito (menor transferencia == página más rápida para el usuario) que realiza la verificación simple del RUT, es decir, [...]]]></description>
			<content:encoded><![CDATA[<p>Sí, estamos totalmente de acuerdo: hay por lo menos unos 50 validadores distintos si buscamos en Internet. Sin embargo, este validador es uno distinto: lo hice yo <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  </p>
<p>Fuera de bromas, es un script bastante cortito (menor transferencia == página más rápida para el usuario) que realiza la verificación simple del RUT, es decir, un RUT tipo 11.111.111-1 seguirá siendo válido para este algoritmo. Lamentablemente el tiempo para hacer el completo no me sobra y creo que este blog es fiel reflejo de ello: hace muchísimo tiempo que no lo actualizo con alguna noticia.</p>
<p>También anda bastante lento el algoritmo en general, aunque eso puede ser problema de mi propio PC también. Sin embargo, se puede optimizar bastante más. La base fue tomada (la idea no más en realidad) del sitio del BancoEstado, <a href="https://www.bancoestado.cl/imagenes/comun2008/lg_prs.html">específicamente este iframe</a>. La versión de BancoEstado pesa 8309 bytes mientras que la versión realizada por mi pesa 1232 bytes (Un nada miserable 85% menos!). Manejando los mensajes de otra forma creo que se puede llegar al límite de un solo paquete de 1024 bytes.<br />
A continuación, el algoritmo del RUT chileno en Javascript y en PHP.<br />
<span id="more-359"></span></p>
<h2>Javascript</h2>
<pre class="brush: jscript;">
function ff(a){b=a;setTimeout(&quot;b.focus();&quot;,0);setTimeout(&quot;b.select();&quot;,0);return true;};
/* BORRAR COMENTARIO:: Lo de arriba es un arreglo para Firefox */
function revisa_RUT(c,e){
var t=&quot;&quot;;var b=0;var w=c.value;for(i=0;i&lt;w.length;i++){if(w.charAt(i)!=' '&amp;&amp;w.charAt(i)!='.'&amp;&amp;w.charAt(i)!='-'){t=t+w.charAt(i)};};if(t.length==8){t=0+t;};
if(t.length!=9){return 'Lo sentimos, pero el RUT no corresponde. Por favor intente nuevamente.';};
if(e=='e'){b=1;};a=t.substring(t.length-1,-1);d=t.charAt(t.length-1);if(d=='k'){d='K';};
if(isNaN(a)){return 'Lo sentimos, pero el RUT contiene caracteres invalidos. Por favor intente nuevamente.';};
if(b==1&amp;&amp;a&gt;50000000){return 'Lo sentimos, pero el RUT ingresado no corresponde a un RUT de persona natural.';};
//if(b==0&amp;&amp;a&lt;50000000){return 'Lo sentimos, pero el RUT ingresado no corresponde a un RUT de empresa.';};
if(!revisa_DV(a,d)){return 'Lo sentimos, pero el RUT es incorrecto. Por favor intente nuevamente.';};
c.value=a.substring(0,2)+'.'+t.substring(2,5)+'.'+t.substring(5,8)+'-'+d;
return true;};
function revisa_DV(a,b){if(a==null||b==null){return false;};
var s=0;var m=2;var d='0';var e=0;
for(i=a.length-1;i&gt;=0;i--){s=s+a.charAt(i)*m;if(m==7){m=2;}else{m++;};};
var r=s%11;if(r==1){d='K';}else{if(r==0){d='0'}else{e=11-r;d=e+'';};};
if(b!=d){return false;};return true;};
/*
Llamar:
onblur=&quot;javascript:g=revisa_RUT(this,'n');if(g!=true){alert(g);ff(this);};&quot;

donde:
this == el elemento input del RUT
'e' == tipo de persona: natural o jurídica. &quot;n&quot; para natural, &quot;e&quot; para jurídica.

TODO:::
llamar a una función separada que dé el formato indicado.
Optimizar.
*/
</pre>
<h2>PHP</h2>
<pre class="brush: php;">function verifica_RUT($rut='') {
  $tmpRUT = '';
  $sep = array();
  $multi = 2;
  $suma = 0;
  if (empty($rut)) return 1;
  for ($i = 0; $i &lt; strlen($rut); $i++) {
    if ($rut[$i] != ' ' AND $rut[$i] != ' ' AND $rut[$i] != '.' AND $rut[$i] != '-') $tmpRUT .= $rut[$i];
  }
  if ( strlen($tmpRUT) == 8 ) $tmpRUT = '0'.$tmpRUT;
  if (strlen($tmpRUT) != 9) return 2;
  $sep['rut'] = substr($tmpRUT,0,8);
  $sep['dv']  = substr($tmpRUT, -1);
  if ($sep['dv'] == 'k') $sep['dv'] = 'K';
  if (!is_numeric($sep['rut'])) return 3;
  if (empty($sep['rut']) OR $sep['dv'] == '') return 4;
  for ($i=strlen($sep['rut']) - 1; $i &gt;= 0; $i--) {
    $suma = $suma + $sep['rut'][$i] * $multi;
    if ($multi == 7) $multi = 2;
    else $multi++;
  }
  $resto = $suma % 11;
  if ($resto == 1) {
    $sep['dvt'] = 'K';
  }
  else {
    if ($resto == 0) {
      $sep['dvt'] = '0';
    }
    else {
      $sep['dvt'] = 11 - $resto;
    }
  }
  if ($sep['dvt'] != $sep['dv']) return 5;
  return 0;
}
// --------------------------------------------------------
// Hasta aquí llega, lo de abajo fue una prueba de concepto
// no más, que pueden copiar tal cual.

$rut = '';
if (isset($_POST['rut'])) {
  $error = verifica_RUT($_POST['rut']);
  switch($error) {
    case 0 : echo 'Todo bien!!'; break;
    case 1 : echo 'RUT viene vacío'; break;
    case 2 : echo 'El RUT no viene con el mínimo de caracteres necesarios para validarlo'; break;
    case 3 : echo 'El RUT no viene en un formato numérico'; break;
    case 4 : echo 'El RUT o el dígito viene vacío.'; break;
    case 5 : echo 'El RUT y el dígito verificador no coinciden'; break;
    default: echo 'Error de la décimanovena dimensión!!! Corran en círculos!!!'; break;
  }
  $rut = $_POST['rut'];
}
?&gt;&lt;html&gt;&lt;head&gt;&lt;title&gt;Probando...&lt;/title&gt;&lt;/head&gt;&lt;body onload=&quot;document.getElementById('rut').focus();&quot;&gt;
&lt;form  action=&quot;&lt;?php echo $_SERVER['SCRIPT_NAME']; ?&gt;&quot; method=&quot;post&quot;&gt;
&lt;input type=&quot;text&quot; id=&quot;rut&quot; name=&quot;rut&quot; value=&quot;&lt;?php echo $rut; ?&gt;&quot; /&gt;&lt;input type=&quot;submit&quot; value=&quot;aceptar&quot; /&gt;&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;
</pre>
<h2>Conclusiones</h2>
<p>Si sé, es un trabajo cochino que es muy muy muy probable que se pueda pulir mucho más que como está, pero este fue una volada que hice a la rapidita (especialmente la de PHP). A ver si algún día me animo a mejorarlo y optimizarlo. También le faltan muchas cosas todavía, pero por el momento es lo que hay.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/03/verificar-rut-con-javascript-y-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Script para reducir peso de los CSS</title>
		<link>http://blog.unreal4u.com/2010/02/script-para-reducir-peso-de-los-css/</link>
		<comments>http://blog.unreal4u.com/2010/02/script-para-reducir-peso-de-los-css/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 13:45:27 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Mundo Web]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=335</guid>
		<description><![CDATA[En la Web hay una cosa que yo diría es bastante fundamental y nadie le presta mucha atención: el peso de los archivos. Mantener un peso bajo puede ahorrar mucho ancho de banda, cosa necesaria en cualquier sitio de alto tráfico, ya que además de acelerar la descarga también hace que al cliente o usuario [...]]]></description>
			<content:encoded><![CDATA[<p>En la Web hay una cosa que yo diría es bastante fundamental y nadie le presta mucha atención: el peso de los archivos. Mantener un peso bajo puede ahorrar mucho ancho de banda, cosa necesaria en cualquier sitio de alto tráfico, ya que además de acelerar la descarga también hace que al cliente o usuario final la página le aparezca más rápido.</p>
<p>Aunque me gustaría ahondar mucho más en el tema, por el momento sólo presentaré una pequeña función que puede ser bastante útil a la hora de reducir el peso de CSS gigantes, sin embargo, la verdadera ganancia puede no estar aquí, sino que en la compresión que se debe activar en el servidor, o bien ocupando <code>ob_start()</code> de PHP, pero como ya dije: eso ya es harina de otro costal y al ser más amplio preferiría dejarlo para otro post.</p>
<p>Sin embargo, a continuación les presento el pequeño script. Vamos... haz click en leer más <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /><br />
<span id="more-335"></span></p>
<h2>Entendiendo CSS</h2>
<p>CSS es un invento genial. Mediante el mismo, y combinándolo inteligentemente con HTML, podemos controlar cualquier aspecto de nuestra página. Es, como casi todo en la Web, fácilmente interpretable y también pesa poco: aplicando sólo una hoja de estilos, podemos controlar todo el aspecto gráfico de la página. Sin embargo, y casi de forma tan variable como lo sea el gusto del programador, es también posible llenar un CSS demasiado con comentarios, espacios demás y hasta caracteres demás. De muestra, un botón:</p>
<pre class="brush: css;">html {
  background-color:#113355;
}
/* Algunos estilos */
p.hola, a:link {
  margin-left: 2px;
  margin-right: 2px;
  margin-top: 43px;
  margin-bottom: 43px;
}
/* El contenedor General de la página */
#wrapper {
  padding: 0px 0px 0px 0px;
  color: #5533AA;
}</pre>
<p>Esto puede reducirse bastante, para que no quede tan críptico, dejé cada estilo en una línea:</p>
<pre class="brush: css;">html{background:#135}
p.hola,a:link{margin:43px 2px}
#wrapper{padding:0;color:#53A}</pre>
<p>Explicaré algunas reglas básicas:</p>
<ol>
<li>Los comentarios no sirven: si quieren un peso chico, eliminen todo comentario.</li>
<li>margin, padding y algunos otros tienen un formato reducido. Sin embargo, es algo que se explicará en otro artículo</li>
<li>El punto y coma final de cada declaración no es necesario. Elimínenlo.</li>
<li>Los colores se pueden reducir, siempre y cuando los tres pares RGB sean iguales. Es útil.</li>
<li>A CSS no le gustan mucho los espacios. Se pueden eliminar muchos.</li>
</ol>
<p>Ahora bien, en el pequeño ejemplo de arriba, que son exactamente iguales, el peso del archivo se redujo de 263 bytes a 84 bytes. Ahora se pueden imaginar la misma situación, pero en la vida real donde el CSS no pesa algunos bytes, sino que bastantes kibibytes. (Eso serían bytes multiplicados por 1024). De todas formas, eliminando los saltos de línea, se puede dejar en 81 bytes, pero queda de difícil lectura.</p>
<p>Sin embargo, el tema que nos convoca hoy no hace algo tan avanzado, sino que simplemente elimina los puntos 1, 3 y la gran mayoría del punto 5. Aunque todavía está lejos de ser perfecto aunque hasta el momento he detectado que hace bien su pega.</p>
<pre class="brush: php;">&lt;?php
  function compress($buffer) {
    $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
    $buffer = str_replace(array(&quot;\r\n&quot;, &quot;\r&quot;, &quot;\n&quot;, &quot;\t&quot;, '  ', '    ', '    '), '', $buffer);
    $buffer = str_replace(array(';}','; }',': ',' {','; '),array(&quot;}\n&quot;,&quot;}\n&quot;,':','{',';'),$buffer);
    return $buffer;
  }

header('Content-type: text/css');
echo compress(file_get_contents('highslide.css'));
?&gt;
</pre>
<p>En el ejemplo de arriba tomé el CSS de highslide, un script hecho en JavaScript que realiza el típico efecto zoom de una foto. El CSS de este script pesa 21.274 bytes, un poco más de 21KiB. Aunque el CSS en sí está bastante bien hecho, no está optimizado para la transferencia Web, tiene muchos espacios vacíos inútiles y también algunos comentarios, todo separado por un enter que parece que se le hubiera quedado pegado al programador.<br />
Después de aplicar el script, quedó pesando 15.695 bytes, lo cual significa una reducción de 6KiB. Puede no sonar tanto, pero en cuanto a porcentaje estamos hablando de una <strong>reducción de peso de un poco más de un 26%</strong>, ¡sólo eliminando espacios innecesarios! Además, hay que tener en cuenta que se está agregando un enter después de cada declaración: al eliminar estos enter que en estricto rigor también están demás, obtenemos un archivo de 15.511 bytes, lo cual en porcentaje significa un poco más del 27%.</p>
<p>Ahora bien, la desventaja de este esquema es que cada vez que queramos modificar el CSS, tendremos que realizar el paso de conversión y luego escribir el archivo, algo bastante impráctico sobretodo si se está desarrollando continuamente. Para solucionar esto, se puede ampliar un poco la función de arriba, combinando CSS y PHP en un solo archivo.</p>
<pre class="brush: php;">
&lt;?php
  header('Content-type: text/css');
  ob_start(&quot;comprimir&quot;);
  function comprimir($buffer) {
    $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
    $buffer = str_replace(array(&quot;\r\n&quot;, &quot;\r&quot;, &quot;\n&quot;, &quot;\t&quot;, '  ', '    ', '    '), '', $buffer);
    $buffer = str_replace(array(';}','; }',': ',' {','; '),array(&quot;}&quot;,&quot;}&quot;,':','{',';'),$buffer);
    return $buffer;
  }
?&gt;
body{background:#1C762C none repeat scroll 0 0;color:#000;font-family:Arial;margin:0;padding:0}
img{border:none}
marquee{background:#FFF;height:168px;padding:0;text-align:center;width:130px}
a{color:#111;text-decoration:none}
ul{text-align:left}
&lt;?php
  ob_end_flush();
?&gt;
</pre>
<p>Pero, esto tiene un pequeño detalle: hay que guardarlo como un archivo .php, debido a que por lo general la configuración no permite establecer un .css como un script ejecutable de PHP. Lo que en el fondo se hace es generar un archivo PHP que genera CSS gracias a <code>ob_start()</code> que, con una explicación muy a la lijera, toma la salida y le aplica la función que definimos antes de enviarlo al explorador. Finalmente, debemos indicarle expresamente dónde termina el archivo.</p>
<p>De esta forma, se consigue comprimir todo el contenido. El único cambio que habría que hacer en HTML sería el siguiente:</p>
<pre class="brush: xml;">
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; lang=&quot;es&quot;&gt;
  &lt;head&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;/&gt;
    &lt;base href=&quot;http://looneyfactory.com/&quot;/&gt;
    &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;http://yui.yahooapis.com/3.0.0/build/cssreset/reset-min.css&quot;/&gt;
    &lt;link href=&quot;estilo_general.css.php?v=1.0&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;/&gt;
  &lt;/head&gt;
  &lt;body&gt;
&lt;!-- el contenido del cuerpo --&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Aquí pasan varias cosas interesantes. Primero llamamos a una aplicación de Yahoo, que es la encargada de resetear todos los valores predeterminados que puedan tener los navegadores. (¿Se acuerdan del artículo sobre <a href="http://blog.unreal4u.com/2010/01/resetear-css/">reseteo de CSS</a>?). Después de eso, llamamos a nuestro estilo, que en realidad es un script hecho en PHP. Además, le pasamos la cadena v=1.0 y esto tiene una razón bastante específica: Hoy en día, no es extraño encontrar que algunos sitios (como por ejemplo: Yahoo, Google y en general cualquier empresa grande que tenga empleados que algo cachan sobre la Web) tengan habilitada una caché que dura menos que 1 año. El CSS de Yahoo por ejemplo, expira en 10 años más. Sin embargo, no tiene ni una gracia que se tenga que cambiar el nombre del archivo cada vez que hay un pequeño cambio en el CSS. Es por eso, que se le agrega al más puro estilo $_GET de PHP un identificador único con lo cual el navegador sub-entiende que ese nombre de archivo (completo, incluido los parámetros) lo debe guardar en caché. </p>
<h2>Ahora entendí un poco más... Y todo junto cómo sería?</h2>
<p>Afortunadamente para ustedes, cuando empezé a escribir este post comencé también a trabajar en una class que me hiciera esto de forma automática. Sin embargo, y como siempre, aunque el requerimiento era bastante simple, terminé por meterle mucho más contenido que lo que originalmente iba a hacer.<br />
Mayor información, tal como link hacia la class y qué cosas hace, las pueden encontrar <a href="http://blog.unreal4u.com/2010/01/nueva-class-publicada-csstacker/">en este post</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/02/script-para-reducir-peso-de-los-css/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nueva class publicada: CSStacker</title>
		<link>http://blog.unreal4u.com/2010/01/nueva-class-publicada-csstacker/</link>
		<comments>http://blog.unreal4u.com/2010/01/nueva-class-publicada-csstacker/#comments</comments>
		<pubDate>Sun, 24 Jan 2010 05:05:53 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Classes]]></category>
		<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=351</guid>
		<description><![CDATA[A partir de hoy se lanza mi segunda class al público en general: es una class que es capaz de tomar varios CSS, comprimirlo, optimizarlo y enviarlo hacia el cliente (con gzip). 
De esta forma, el CSS principal de CHW por ejemplo, pasa de pesar 43876 bytes a 5802 bytes, una compresión de un 87%! [...]]]></description>
			<content:encoded><![CDATA[<p>A partir de hoy se lanza mi segunda class al público en general: es una class que es capaz de tomar varios CSS, comprimirlo, optimizarlo y enviarlo hacia el cliente (con gzip). </p>
<p>De esta forma, el <a href="http://www.chw.net/wp-content/themes/chw-5.0/s/base.css">CSS principal de CHW</a> por ejemplo, pasa de pesar 43876 bytes a 5802 bytes, una compresión de un 87%! </p>
<p>Cómo se hace esto? Muy simple: se toma el o los CSS a procesarse, se eliminan los comentarios, los retornos de carros, los espacios que sobran, los tabs que sobran, se cambian todos los 0px a 0, los colores se convierten a su respectivo código corto y por último los colores se tratan de acortar de #EEAA11 a #EA1.<br />
Por último, a ese archivo resultante se le aplica gzip y se manda al cliente. Por último, si el cliente ya tiene en su caché el CSS, simplemente se manda un código HTTP de que el archivo no ha sido modificado, reduciendo de esta manera ancho de banda.<br />
<span id="more-351"></span><br />
Mi class trabaja con dos formas de caché, ambos configurables:<br />
El primer caché se genera en el servidor. De esta manera, se pueden dar distintas combinaciones para distintos perfiles.<br />
Si en una página cargo hola.css y chao.css y en otra página cargo hola.css y mundo.css, ambos tendrán una caché distinta.<br />
Esta caché se puede activar o desactivar, aunque desactivado no tiene mucha gracia ya que cada vez que hay un request, se debe realizar todo el proceso de arriba nuevamente. </p>
<p>La segunda caché es la del cliente: si el CSS no ha cambiado entonces no descarga nada. Si en cambio, el archivo fuente ha cambiado o el cliente no tiene en caché el CSS se descarga nuevamente.<br />
Esta caché se puede desactivar como también regular el tiempo que dura. </p>
<p>¿Qué ventajas tiene esto? </p>
<ol>
<li>Los CSS quedan originales, no teniendo que renombrarse. Es tan fácil como llegar y editarlos en caso que sea necesario. Cuando se editan, se actualiza automáticamente la caché interna y se manda la nueva versión al cliente. </li>
<li>No más problemas extraños con distintos navegadores: la class se encarga de hablar con el navegador. </li>
<li>Menos HTTP requests por cliente. </li>
<li>Menos peso que transferir hacia el cliente. </li>
<li>De fácil integración: sólo son 2 líneas de código <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  </li>
</ol>
<p>Por último, también es posible enviar el CSS como un archivo (recomendado) o bien imprimirlo inline como parte del estilo. </p>
<p>Y de dónde se puede descargar esta maravilla? De acá: </p>
<h4><a href="http://unreal4u.users.phpclasses.org/browse/package/5950.html">http://unreal4u.users.phpclasses.org/browse/package/5950.html</a></h4>
<p>En ese link se encuentra la class, documentación completa (en inglés, sorry es requisito del sitio), el archivo de configuración necesaria y por último un par de ejemplos. </p>
<p>Cualquier duda, puede ser mediante phpclasses.org o bien <a href="http://www.chw.net/foro/webmasters-f91/300941-nueva-class-publicada-csstacker.html">mediante CHW</a> o por último, como comentario en este mismo blog <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>[UPDATE]: Saqué la versión 1.3 hace algunos días que incorpora algo nuevo: uno puede forzar la creación de un archivo caché (en el servidor) y ahora también existe la opción de sólo imprimir el nombre del archivo caché que genera. De esa forma, podemos incluirlo en nuestro código fuente sin tener otro archivo dando vueltas y que el Webserver se encargue de lidiar con la caché del navegador. (Aunque esto hay que configurarlo, mi class la hace solo <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  )</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/01/nueva-class-publicada-csstacker/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Remover (quitar) contenido desde Google</title>
		<link>http://blog.unreal4u.com/2010/01/remover-quitar-contenido-desde-google/</link>
		<comments>http://blog.unreal4u.com/2010/01/remover-quitar-contenido-desde-google/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 06:41:17 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Mundo Web]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=311</guid>
		<description><![CDATA[Existe una infinidad de información acerca de cómo mejorar el ranking en Google (u otros buscadores), acerca de cómo mejorar el SEO, miles de consejos -algunas bastante místicas por decir lo menos-, PERO casi no existe información sobre cómo darse de alta o quitar el contenido de los buscadores. 
Les cuento el pequeño problema: Hace [...]]]></description>
			<content:encoded><![CDATA[<p>Existe una infinidad de información acerca de cómo mejorar el ranking en Google (u otros buscadores), acerca de cómo mejorar el SEO, miles de consejos -algunas bastante místicas por decir lo menos-, PERO casi no existe información sobre cómo darse de alta o quitar el contenido de los buscadores. </p>
<p>Les cuento el pequeño problema: Hace ya bastante tiempo, tengo un servidor de desarrollo. Este servidor de desarrollo afortunadamente es bastante estable: funciona bien hace más de 1 año y sólo lo he reiniciado 2 veces a lo largo del año que recién pasó (Feliz año nuevo a todo esto): la primera fue debido a una costumbre windowsera y la segunda fue por una actualización importante del kernel. Sin embargo, lo realmente importante es que el downtime de este servidor es de menos de un 1% durante este año y eso fue sólo porque en el datacenter hubo una serie de malos entendidos que llevaron a que me desconectaron el servidor durante todo un fin de semana. Sino hubiese sido por este pequeño incidente, el downtime hubiese sido de menos de un 0.01% (Considerando ese 0.01% como el tiempo que se demora la máquina en reiniciar 2 veces durante el transcurso de un año).<br />
<span id="more-311"></span><br />
Lo único malo de esto, es que Google piensa que este servidor tan estable debería aparecer en su listado, mientras que yo pienso todo lo contrario: es un servidor <strong>de desarrollo</strong>, y por lo general el contenido que se genera en este servidor, finalmente termina copiándose al server final. </p>
<p>A continuación las típicas preguntas:<br />
<strong>¿Cómo es que llegaron a indexarme?</strong><br />
La verdad no tengo idea, lo más probable es que en alguna página tenía un link hacia el servidor de desarrollo lo cual llevó a Google a indexarla. Supongo que en el transcurso de 1 año eso es perfectamente factible: durante ese año lo más probable es que alguna vez haya puesto un link en alguna parte. </p>
<p><strong>¿Cuál es el problema?</strong><br />
Que Google termina castigando al usuario final por contenido duplicado en una máquina de desarrollo. (medio WTF pero es como Google funciona). Es así como me encontré con la desagradable sorpresa de que buscando por un término fácilmente relacionable con una empresa para la cual estaba desarrollando una página, el servidor oficial aparecía en primer lugar y el servidor de desarrollo aparecía en cuarto lugar. Incluso habían usuarios que se habían creado una cuenta en el servidor de desarrollo a pesar de los múltiples avisos ¬¬. </p>
<p><strong>¿Cómo quitarlo?</strong><br />
Me puse a investigar cómo dar de alta este servidor el cual nunca había querido indexar siquiera. Fue así como me inscribí en Google Webmasters donde, <a href="http://googlewebmastercentral.blogspot.com/2007/04/requesting-removal-of-content-from-our.html" target="_BLANK">según una guía "oficial" de Google</a> podría sacar la página de Google. Sin embargo, el link para sacarme que aparecía muy claro en el SS de la guía, ni siquiera me aparecía ¬¬.<br />
Quedándome claro que ese no era el método, seguí leyendo el mismo artículo, que finalmente explicaba otros métodos para que la gran G no me siguiera indexando, los cuales eran bastante más atinados y fáciles de seguir que hacer clicks en un mar de links. </p>
<h2>Primer método: retornar un 404</h2>
<p>Google, tal como otros buscadores, desindexa un sitio que aunque previamente funcionaba bien, ahora retorna un error 404. Lo único "malo" de esto es que se tiene que eliminar todo el sitio, lo cual obviamente no era la idea: mal que mal, se necesita seguir desarrollando en la página y eliminarlo definitivamente no es la mejor opción. </p>
<h2>Segundo método: Bloquear mediante robots.txt</h2>
<p>Si bien es cierto nunca he hablado del robots.txt supongo que los que visitan este blog algo sabrán del mismo, y si no saben, una muy breve explicación: robots.txt es uno de los primeros archivos a visitarse por los buscadores, y en ella se indican los directorios o archivos que están prohibidos o permitidos para la indexación.<br />
Sin embargo, no hay que olvidar que puede llegar a ser un arma de doble filo: este archivo es público, por lo tanto, es mejor no colocar rutas confidenciales, ya que como investigación previa a cómo hackear una página, este es sin duda uno de los primeros archivos que visitaré, justamente para ver si acaso existe alguna ruta confidencial. Facebook de hecho, tiene cosas bien interesantes en su robots.txt. Además, aunque la gran mayoría de los buscadores respetan este archivo, no todos lo hacen (Aunque son los menos).<br />
En primera instancia, elegí este método ya que es el más rápido para bloquear sólo una sección. Se hace de la siguiente manera: </p>
<p><code>User-agent: *<br />
Disallow: /</code><br />
Esto le dice a todos los buscadores (un asterisco en User-agent indica todos los buscadores) que no indexen nada que se encuentre desde el home en adelante. Es decir, si pusiera esto en mi blog, estaría denegando expresamente a Google, Bing, Yahoo y otros que me indexen el sitio completo, subcarpetas y archivos incluidos. </p>
<p>Sin embargo, por esas cosas de la vida, uno quizás no querría denegar el acceso a todo el sitio, sino que sólo a una subcarpeta en específico a sólo Google.<br />
<code>User-agent: GoogleBot<br />
Disallow: /carpeta/<br />
Disallow: /login.php<br />
Disallow: /otra-carpeta/archivo.jpg<br />
Disallow: /*.gif$</code></p>
<p>Con esa orden, estamos denegando el acceso al GoogleBot a la carpeta llamada "carpeta" y mediante la segunda línea, al archivo llamado login.php que se encuentra en la raíz. Con la tercera línea, estamos denegando el acceso a archivo.jpg dentro de la carpeta "otra-carpeta" y finalmente, mediante la cuarta línea, estamos denegando el acceso a todos los archivos cuyo nombre termina en .gif.<br />
Más información acerca de las expresiones regulares permitidos en robots.txt se puede encontrar <a href="http://www.google.com/support/webmasters/bin/answer.py?hl=es&#038;answer=156449" target="_BLANK">en este enlace</a>. (Hacer click en "Crear de forma manual un archivo robots.txt" para ver esa información). </p>
<h2>Tercer método: Prohibir mediante meta-tags</h2>
<p>Este método es bastante bueno, pero tiene algunas desventajas bastante grandes también. Básicamente, se trata de incluir un metatag en cada HTML que le indica a los buscadores que no se indexe tal página, las combinaciones útiles son: </p>
<pre class="brush: xml;">&lt;meta name=&quot;robots&quot; content=&quot;noindex, follow&quot;&gt;
&lt;meta name=&quot;robots&quot; content=&quot;index, nofollow&quot;&gt;
&lt;meta name=&quot;robots&quot; content=&quot;noindex, nofollow&quot;&gt;</pre>
<p>Esto es bastante fácil de entender: el name es siempre "robots" si se quiere tomar en cuenta todos los buscadores. ("googlebot" en minúsculas si se quiere especificar solamente Google).<br />
Content se refiere básicamente qué tipo de acciones son los que están prohibidos. Los posibles valores son siempre "index", "noindex", "follow" y "nofollow", pero obviamente no todas las combinaciones son posibles. </p>
<ul>
<li><em>index</em> o <em>noindex</em> se refieren a si acaso se desea indexar el sitio: index para sí indexar, noindex para no indexar.</li>
<li><em>follow</em> o <em>nofollow</em> se refieren a seguir los enlaces de esa página; de esa forma; si pongo un nofollow en hola.php y hola.php contiene links hacia otras páginas o secciones de mi página, mediante esa directiva no se seguirán.</li>
</ul>
<p><strong>¿Las desventajas?</strong></p>
<ol>
<li>Si una página ya se encuentra indexada, lo más probable es que las imágenes también lo estén. Por lo tanto, si nuestra imagen se puede linkear directamente, seguirá indexada.</li>
<li>¿Ya les dije que tenía un servidor de desarrollo cierto? Imagínense qué pasaría si se me olvida sacar esta regla de <code>/includes/header.php</code> y queden todas las páginas sin indexarse. Para los lentos: se borrarían todas las páginas desde los buscadores del dominio final lo cual obviamente <strong>no</strong> es la idea. </li>
</ol>
<h2>[Opcional] Google Hell</h2>
<p>Si desde hace tiempo conocen de manejo SEO y otros relacionados, seguramente conocerán el término Google Hell. Este término se inauguró hace ya bastante tiempo atrás cuando la página cae en una cierta categoría de sitio spam y Google decide (de un día a otro) no mostrar más tu página en el buscador, a no ser que busques por el dominio mismo de la página. Aunque es altamente recomendado para quitar contenido de Google, también puede haber el riesgo de que la misma decida también tirar al infierno la página que está en producción, con lo cual el cliente no estará muy contento.<br />
Sin embargo, el apellido "Hell" viene porque una vez que un sitio cae en esta categoría, es casi imposible salir. En la gran mayoría de los casos, se opta por simplemente comprar otro dominio y empezar de nuevo: las respuestas por parte de Google siempre son automatizados y son del tipo: "Lo sentimos, pero el proceso de indexación es automatizado y no podemos hacer nada". Sin duda alguna, el cliente cuya empresa se llama "Lavaseco S.A." y tiene el dominio lavaseco.cl no estará muy contento de tener que cambiar su super hiper genial dominio por alguno que sea mucho más difícil de recordar.<br />
Obviamente es una excelente forma para que Google nunca más nos indexe, pero por cierto es la que NO debería aplicarse. </p>
<h2>Conclusiones</h2>
<p>Quitar una página desde un buscador puede ser un poco más difícil que tratar de incluirlo en alguno de ellos. Tampoco existe un método 100% fiable, a no ser que se caiga en el Google Hell. Sin embargo, no todo es imposible y aquí se expresaron al menos 3 métodos bastante fiables explicando sus ventajas y desventajas.<br />
Sin duda, es que creo que el segundo método es el mejor de todos: nos permite tener un control bastante detallado de qué contenido está prohibido de indexar y además también bloquea la indexación de imágenes y otro tipo de documentos que no tengan un HTML de por medio, tales como documentos PDF, .doc y otros, los que no son posibles de bloquear con el tercer método. </p>
<p>Bueno, eso sería todo por hoy. Espero que haya sido claro en todo, y si no quedó muy claro, dejen su comentario más abajo <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2010/01/remover-quitar-contenido-desde-google/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Manejar errores en PHP</title>
		<link>http://blog.unreal4u.com/2009/12/manejar-errores-en-php/</link>
		<comments>http://blog.unreal4u.com/2009/12/manejar-errores-en-php/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 18:00:35 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=207</guid>
		<description><![CDATA[El otro día, mediante twitter, leí un título proveniente del DeveloperWorks de IBM que prometía mucho, pero que finalmente resultó en una farsa. El título decía algo así como: "Aprenda cómo manejar errores en PHP" pero al final no mostraba nada de código y además creo que promocionaban uno de estos software de IBM que [...]]]></description>
			<content:encoded><![CDATA[<p>El otro día, mediante twitter, leí un título proveniente del DeveloperWorks de IBM que prometía mucho, pero que finalmente resultó en una farsa. El título decía algo así como: "Aprenda cómo manejar errores en PHP" pero al final no mostraba nada de código y además creo que promocionaban uno de estos software de IBM que vale como USD $999,99 si lo compraba en ese mismo instante. (LLAME YA!)<br />
Sin embargo, el tema me pareció muy interesante, tanto, que me comprometí a algún día escribir al respecto. Y bueno... este es el resultado. Es un artículo largo, así que para variar se separará por páginas.</p>
<p><span id="more-207"></span></p>
<p>La primera regla de los errores es que es el usuario (final) <strong>jamás</strong> debe ver un error en pantalla. No es una buena idea que vea una pantalla en blanco que dice algo así como:</p>
<blockquote><p><strong>Fatal error N° 1002</strong>: Couldn't connect to MySQL, server responded: MySQL error 44: to busy</p>
<p>on line <strong>3412</strong> in file <strong>/home/asdf/public_html/includes/mysql.class.php</strong></p>
<hr />
Apache v2.0.54 / PHP v5.2.12 on unreal4u.com</p></blockquote>
<p>Principalmente por 3 razones:</p>
<ul>
<li>Puede no estar en el mismo idioma</li>
<li>El mensaje de error generalmente es críptico, y asusta al usuario. El resultado es que el usuario cerrará la ventana y nunca más visitará el sitio pensando que fue él el que ocasionó el error. (Si el mensaje fuera el de arriba, parcialmente es así de todas formas xD)</li>
<li>Por último, el más importante. Hay mucha información: sale la ruta del archivo que produjo el error, sale la línea y por último, si se encuentra habilitado, el servidor muestra qué está corriendo.</li>
</ul>
<p>Por lo tanto, si vamos a mostrar un error, mínimo que sea en la misma página donde se produjo, en el idioma del usuario, con un error en lenguaje más humano, algo así como esto:</p>
<p style="background: #af6d6d none repeat scroll 0pt 0pt; color: #ffffff; font-size: 1.3em; line-height: 30px; padding-bottom: 4px; text-align: center; width: 98%;"><img style="display:table-cell;padding:0 10px 0 0;vertical-align:middle;border:0" title="  " src="http://unreal4u.com/~tesis/i/warning.png" alt=" " width="25" height="22" />Lo sentimos, pero en este momento el servidor tiene demasiado tráfico</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2009/12/manejar-errores-en-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Evitar autocompletado en los formularios</title>
		<link>http://blog.unreal4u.com/2009/12/evitar-autocompletado-en-los-formularios/</link>
		<comments>http://blog.unreal4u.com/2009/12/evitar-autocompletado-en-los-formularios/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 18:42:53 +0000</pubDate>
		<dc:creator>unreal4u</dc:creator>
				<category><![CDATA[Mundo Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.unreal4u.com/?p=248</guid>
		<description><![CDATA[Hoy en el foro de CHW, preguntaron si acaso era posible que una aplicación (sea PHP, ASP, .NET, etc) pudiera ser forzado a NO recordar lo escrito en una caja de texto. 
Lo primero en que pensé fue en la propiedad autocomplete="off", pero tiene algunos problemas asociados y no funciona de la mejor manera que [...]]]></description>
			<content:encoded><![CDATA[<p>Hoy en el <a href="http://www.chw.net/foro/webmasters-f91/292343-que-el-navegador-no-guarde-la-informacion.html">foro de CHW</a>, preguntaron si acaso era posible que una aplicación (sea PHP, ASP, .NET, etc) pudiera ser forzado a NO recordar lo escrito en una caja de texto. </p>
<p>Lo primero en que pensé fue en la propiedad <code>autocomplete="off"</code>, pero tiene algunos problemas asociados y no funciona de la mejor manera que digamos. Por ende, tratando de juntar un par de ideas, pensé en lo siguiente. </p>
<p>Click en "leer más" o "ver artículo completo" o como sea que esté traducido para ver la solución propuesta <img src='http://blog.unreal4u.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<span id="more-248"></span></p>
<h2>Primera solución</h2>
<p>Dije que podríamos haberlo hecho con <code>autocomplete="off"</code>. Veamos cómo funciona: </p>
<pre class="brush: xml;">&lt;input type=&quot;text&quot; autocomplete=&quot;off&quot; id=&quot;asdf&quot; name=&quot;asdf&quot; value=&quot;&quot; /&gt;</pre>
<p>Con esa sola línea se supone que debería quedar desactivado el autocompletado, pero tiene un solo gran problema: no es compatible con la W3C.<br />
Sin embargo, no hay que olvidarse que la W3C no revisa JavaScript, por lo que poniendo en el evento onload del body lo siguiente, sí se retorna un documento válido que cumplirá el mismo propósito: </p>
<pre class="brush: jscript;">document.getElementById(&quot;asdf&quot;).setAttibute(&quot;autocomplete&quot;,&quot;off&quot;);</pre>
<p>Peeeero... aquí ocurre el otro problema: no todos los navegadores aceptan este tipo de instrucción, por lo que por ejemplo Firefox va a seguir llenando el input. Mal que mal, es una característica que tiene que funcionar a toda prueba para el navegador cierto? </p>
<h2>Segunda solución (Siempre funciona)</h2>
<p>El problema se genera justamente en el cliente: firefox o cualquier otro navegador simplemente toma en cuenta el nombre del elemento y lo llena de acuerdo a lo que tiene guardado. De esta forma, se hace posible que por ejemplo, mi nombre de usuario aparezca en todos los foros vBulletin, ya que muchos de ellos tienen el mismo nombre en el input. </p>
<p>Por lo tanto, una solución sería poder darle un nombre único a cada elemento que no queremos que se autocomplete. Sin embargo, hay que tener en cuenta que muchas veces un input de tipo texto que no haga nada es algo inútil: necesitamos hacer algo con ese elemento. El único problema es que... ¿cómo se llama dicho elemento si su nombre es totalmente al azar?<br />
Bueno, para eso lo que se puede hacer es lo siguiente: tenemos que ver de qué manera podemos generar un nombre único pero a la vez tenemos que ver cómo lo podemos rescatar referenciándolo por ese nombre. </p>
<p>El truco en sí es bastante fácil: basta poner un elemento de tipo hidden y darle de valor el nombre del elemento y punto. Así de corta. </p>
<pre class="brush: php;">&lt;?php
// Rescatando o revisando que el formulario enviado no sea vacío
  if (isset($_POST['qwerty']) AND !empty($_POST[$_POST['qwerty']])) {
// No es vacío, por lo que procedemos a imprimir o cualquier cosa
// que se haga dentro de un formulario enviado
    echo 'El valor es: &lt;strong&gt;'.$_POST[$_POST['qwerty']].'&lt;/strong&gt;&lt;br /&gt;';
  }
?&gt;&lt;form action=&quot;&lt;?php echo $_SERVER['SCRIPT_NAME']; ?&gt;&quot; method=&quot;post&quot;&gt;
&lt;?php
// Primero establecemos un nombre único. &quot;uniqid&quot; retorna
// una id única (con 14 decimales de precisión gracias al
// segundo argumento), precedida por el tiempo en segundos
// Finalmente, a todo eso se le aplica un md5.
  $nombre = 'asdf_'.md5(uniqid(time(),TRUE));
// Imprimo la caja que se verá públicamente con su nombre único
  echo '&lt;input type=&quot;text&quot; name=&quot;'.$nombre.'&quot; /&gt;';
// Imprimo un elemento de tipo hidden con valor == $nombre
  echo '&lt;input type=&quot;hidden&quot; name=&quot;qwerty&quot; value=&quot;'.$nombre.'&quot; /&gt;';
// Siempre es bueno desocupar la mayor cantidad de memoria posible
  unset($nombre);
?&gt;
&lt;br /&gt;&lt;input type=&quot;submit&quot; value=&quot;Aceptar&quot; /&gt;
&lt;/form&gt;</pre>
<p>Por si lo quieren probar, <a href="http://unreal4u.com/test/form-llenado/index.php" target="_BLANK">aquí está la prueba de concepto</a>. </p>
<p>Saludos !!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.unreal4u.com/2009/12/evitar-autocompletado-en-los-formularios/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
