<?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>HiperGalaxia &#187; Web</title>
	<atom:link href="http://www.hipergalaxia.org/blog/tag/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hipergalaxia.org/blog</link>
	<description>El conocimiento, la frontera final.</description>
	<lastBuildDate>Thu, 09 Sep 2010 02:16:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Instalar Polipo, un proxy web/caché en ArchLinux 2010.05 x64</title>
		<link>http://blog.jorgeivanmeza.com/2010/07/instalar-polipo-un-proxy-webcache-en-archlinux-2010-05-x64/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=instalar-polipo-un-proxy-webcache-en-archlinux-2010-05-x64</link>
		<comments>http://blog.jorgeivanmeza.com/2010/07/instalar-polipo-un-proxy-webcache-en-archlinux-2010-05-x64/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=instalar-polipo-un-proxy-webcache-en-archlinux-2010-05-x64#comments</comments>
		<pubDate>Wed, 21 Jul 2010 19:46:42 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[ArchLinux]]></category>
		<category><![CDATA[caché]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Linux/Solaris/BSD]]></category>
		<category><![CDATA[Polipo]]></category>
		<category><![CDATA[proxy]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=6016</guid>
		<description><![CDATA[Introducción. Para hacer unas pruebas esta tarde necesito un proxy que haga caché sobre los datos descargados; inicialmente iba a instalar Squid sobre un Scientific Linux pero decidí hacerlo sobre ArchLinux, con el cual estoy jugando desde el día de ayer.  Leyendo la documentación del wiki de ArchLinux, que por cierto es muy buena, encontré [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>Para hacer unas pruebas esta tarde necesito un proxy que haga caché sobre los datos descargados; inicialmente iba a instalar Squid sobre un Scientific Linux pero decidí hacerlo sobre ArchLinux, con el cual estoy jugando desde el día de ayer.  Leyendo la documentación del wiki de ArchLinux, que por cierto es muy buena, encontré que hacen referencia a <a href="http://www.pps.jussieu.fr/~jch/software/polipo/" >Polipo</a>, un software similar en funciones a Squid pero con mayores limitaciones y destinado a servidores con muy pocos usuarios.  Ese es mi caso, así que procedí a instalarlo en una máquina virtual con VirtualBox y 512MB de RAM.  Espero que aguante.</p>
<h2>Instalación de los paquetes.</h2>
<p>Desafortunadamente lo paquetes de Polipo no están disponibles en los repositorios, sin embargo estos pueden ser creados utilizando una facilidad interesante del sistema operativo.</p>
<p>Los siguientes pasos deben realizarse como un <a href="http://blog.jorgeivanmeza.com/2010/07/crear-un-usuario-sin-privilegios-y-activar-sudo-en-archlinux-2010-05-x64/" >usuario sin privilegios</a>.</p>
<p>Descargar la versión mas reciente de los archivos (sección de <em>files</em>) de Polipo de la siguiente ubicación.</p>
<p style="padding-left: 30px;"><a href="http://aur.archlinux.org/packages.php?ID=14579" >http://aur.archlinux.org/packages.php?ID=14579</a></p>
<p><span style="font-family: courier new,courier;">$ wget http://aur.archlinux.org/packages/polipo/polipo/PKGBUILD</span></p>
<p><span style="font-family: courier new,courier;">$ wget http://aur.archlinux.org/packages/polipo/polipo/polipo.install</span></p>
<p><span style="font-family: courier new,courier;">$ wget http://aur.archlinux.org/packages/polipo/polipo/polipo</span></p>
<p>Generar el paquete.</p>
<p><span style="font-family: courier new,courier;">$ makepkg -s</span></p>
<p>Instalar el paquete recién generado.</p>
<p><span style="font-family: courier new,courier;">$ sudo pacman -u polipo-1.0.4.1-1-x86_64.pkg.tar.xz</span></p>
<h2>Configuración de Polipo.</h2>
<p>Crear un archivo básico de configuración a partir de la plantilla.</p>
<p><span style="font-family: courier new,courier;">$ sudo cp /etc/polipo/config-sample /etc/polipo/config</span></p>
<p>Permitir las conexiones externas, además de <span style="font-family: courier new,courier;">localhost</span>.</p>
<p><span style="font-family: courier new,courier;">$ sudo vi /etc/polipo/config</span></p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">proxyAddress = &#8220;0.0.0.0&#8243;</span></p>
<p>Si se desea permitir el uso del caché por equipos diferentes del mismo (<span style="font-family: courier new,courier;">localhost</span>)  es necesario especificar las redes autorizadas en la siguiente variable del mismo archivo <span style="font-family: courier new,courier;">config</span>.  Nótese que, a diferencia del ejemplo en el mismo archivo, fue necesario remover las comillas dobles que encerraban las direcciones de red.</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">allowedClients = 127.0.0.1, 10.0.0.0/16, 192.168.1.0/24</span></p>
<p>Actualizar el archivo de inicio de Polipo.  Nótese en el <em>script</em> que por razones de seguridad se utilizará al usuario <span style="font-family: courier new,courier;">nobody</span> para ejecutar el servicio.</p>
<p><span style="font-family: courier new,courier;">$ sudo cp /etc/rc.d/polipo /etc/rc.d/polipo.orig</span></p>
<p><span style="font-family: courier new,courier;">$ sudo vi /etc/rc.d/polipo</span></p>
<pre style="padding-left: 30px;">#!/bin/bash
. /etc/rc.conf
. /etc/rc.d/functions
DAEMON=polipo
ARGS="daemonise=true pidFile=/var/run/$DAEMON/$DAEMON.pid"
PID=`pidof -o %PPID /usr/bin/$DAEMON`
case $1 in
    start)
        stat_busy "Starting $DAEMON"
        rm /var/run/$DAEMON/$DAEMON.pid 2&gt; /dev/null
        install -d /var/run/$DAEMON
        ## /usr/bin/$DAEMON $ARGS &gt;/dev/null 2&gt;&amp;1
        <strong>sudo -u nobody</strong> /usr/bin/$DAEMON $ARGS &gt;/dev/null 2&gt;&amp;1
        if [[ $? != 0 ]]; then
            stat_fail
        else
            add_daemon $DAEMON
            stat_done
        fi
    ;;
    stop)
        stat_busy "Stopping $DAEMON"
        kill $PID &gt;/dev/null 2&gt;&amp;1
        if [[ $? != 0 ]]; then
            stat_fail
        else
            rm_daemon $DAEMON
            stat_done
        fi
    ;;
    purge)
        stat_busy "Purging polipo"
        [[ ! -d /var/run/polipo ]] &amp;&amp; mkdir /var/run/polipo
        if ! ck_daemon polipo; then
            kill -USR1 $DAEMON &gt;/dev/null 2&gt;&amp;1 || stat_die $?
            sleep 1
            /usr/bin/$DAEMON -x $ARGS &gt;/dev/null 2&gt;&amp;1 || stat_die $?
            kill -USR2 $PID &gt;/dev/null 2&gt;&amp;1 || stat_die $?
            stat_done
        else
            /usr/bin/$DAEMON -x $ARGS &gt;/dev/null 2&gt;&amp;1 || stat_die $?
            stat_done
        fi
    ;;
    restart)
        $0 stop
        sleep 1
        $0 start
    ;;
    *)
        echo "usage: $0 {start|stop|restart|purge}"
    ;;
esac</pre>
<h2>Ajustes al sistema operativo.</h2>
<p>Crear un proceso <span style="font-family: courier new,courier;">cron</span> para <em>purgar</em> el servicio.</p>
<p><span style="font-family: courier new,courier;">$ sudo vi /etc/cron.weekly/polipo</span></p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">#!/bin/sh<br />
/etc/rc.d/polipo purge &gt;/dev/null 2&gt;&amp;1</span></p>
<p><span style="font-family: courier new,courier;">$ sudo chmod +x /etc/cron.weekly/polipo</span></p>
<p>Crear las rutas necesarias para los archivos del proxy.</p>
<p><span style="font-family: courier new,courier;">$ sudo touch /var/log/polipo</span></p>
<p><span style="font-family: courier new,courier;">$ sudo chown nobody:nobody /var/log/polipo</span></p>
<p><span style="font-family: courier new,courier;">$ sudo mkdir /var/run/polipo</span></p>
<p><span style="font-family: courier new,courier;">$ sudo chown nobody:nobody /var/run/polipo</span></p>
<p><span style="font-family: courier new,courier;">$ sudo mkdir /var/cache/polipo</span></p>
<p><span style="font-family: courier new,courier;">$ sudo chown nobody:nobody /var/cache/polipo</span></p>
<p>Configurar el inicio automático de Polipo con el sistema operativo.</p>
<p><span style="font-family: courier new,courier;">$ sudo vi /etc/rc.conf</span></p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">DAEMONS=(syslog-ng network netfs <strong>polipo</strong> crond)</span></p>
<h2>Prueba del caché.</h2>
<p>Configure el proxy de Firefox o de cualquier otro cliente y acceda a los recursos que desee, estos deberán almacenarse en el caché por lo cual futuros accesos (recuerde limpiar el caché local de ser necesario para hacer mas confiable la prueba) deberían ser más rápidos.  Como ubicación del servidor de caché utilice la IP del servidor donde se instaló Polipo y el puerto -por defecto- <span style="font-family: courier new,courier;">8123</span>.</p>
<h2>Enlaces.</h2>
<ul>
<li>Polipo - a caching web proxy.<br />
<a href="http://www.pps.jussieu.fr/~jch/software/polipo/" >http://www.pps.jussieu.fr/~jch/software/polipo/</a></li>
<li>Polipo en ArchLinux.<br />
<a href="http://wiki.archlinux.org/index.php/Polipo" >http://wiki.archlinux.org/index.php/Polipo</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2010/07/instalar-polipo-un-proxy-webcache-en-archlinux-2010-05-x64/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Modo de mantenimiento de WordPress 3</title>
		<link>http://blog.jorgeivanmeza.com/2010/07/modo-de-mantenimiento-de-wordpress-3/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=modo-de-mantenimiento-de-wordpress-3</link>
		<comments>http://blog.jorgeivanmeza.com/2010/07/modo-de-mantenimiento-de-wordpress-3/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=modo-de-mantenimiento-de-wordpress-3#comments</comments>
		<pubDate>Fri, 16 Jul 2010 16:14:30 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=5219</guid>
		<description><![CDATA[Cuando se realizan actualizaciones WordPress 3 pasa automáticamente a un modo de mantenimiento, es decir, nadie puede acceder al sitio durante la actualización.  Si alguien consulta el blog obtendrá un mensaje como el siguiente. No disponible por mantenimiento programado. Vuelve a comprobarlo en unos minutos. Gracias O su versión en inglés. Briefly unavailable for scheduled [...]]]></description>
			<content:encoded><![CDATA[<p>Cuando se realizan actualizaciones WordPress 3 pasa automáticamente a un modo de mantenimiento, es decir, nadie puede acceder al sitio durante la actualización.  Si alguien consulta el blog obtendrá un mensaje como el siguiente.</p>
<h2 style="text-align: center;">No disponible por mantenimiento programado. Vuelve a comprobarlo en unos minutos. Gracias</h2>
<p>O su versión en inglés.</p>
<h2 style="text-align: center;"><em>Briefly unavailable for scheduled maintenance. Check back in a minute.</em></h2>
<p>Algunas veces algo falla en la actualización, frecuentemente me ha sucedido durante la actualización de <em>plugins</em>, y el modo mantenimiento no se restaura automáticamente queda el sitio aisaldo.</p>
<p>Para corregir este problema es necesario acceder al sistema de archivos del sitio y remover un archivo llamado <span style="font-family: courier new,courier;">.maintenance</span> en la raíz del blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2010/07/modo-de-mantenimiento-de-wordpress-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Integración de una autenticación externa con los foros de Simple Machines 1.1.11</title>
		<link>http://blog.jorgeivanmeza.com/2010/05/integracion-de-una-autenticacion-externa-con-los-foros-de-simple-machines-1-1-11/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=integracion-de-una-autenticacion-externa-con-los-foros-de-simple-machines-1-1-11</link>
		<comments>http://blog.jorgeivanmeza.com/2010/05/integracion-de-una-autenticacion-externa-con-los-foros-de-simple-machines-1-1-11/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=integracion-de-una-autenticacion-externa-con-los-foros-de-simple-machines-1-1-11#comments</comments>
		<pubDate>Mon, 10 May 2010 20:59:12 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[autenticacion]]></category>
		<category><![CDATA[CMS]]></category>
		<category><![CDATA[codeigniter]]></category>
		<category><![CDATA[Foros]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[Integración]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2429</guid>
		<description><![CDATA[Introducción. La situación es la siguiente, se cuenta con un CMS desarrollado en PHP bajo el framework de CodeIgniter con su propio sistema de autenticación en el que se almacenan los usuarios de la siguiente manera. CREATE TABLE IF NOT EXISTS `core_usuario` ( `id_usuario` int(11) unsigned NOT NULL auto_increment, `estado` enum(&#8216;activo&#8217;,'inactivo&#8217;) NOT NULL, `_username` varbinary(16) [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>La situación es la siguiente, se cuenta con un CMS desarrollado en <a href="http://php.net/" >PHP</a> bajo el <em>framework</em> de <a href="http://codeigniter.com/" >CodeIgniter</a> con su propio sistema de autenticación en el que se almacenan los usuarios de la siguiente manera.</p>
<p><span style="font-family: courier new,courier;">CREATE TABLE IF NOT EXISTS `<strong>core_usuario</strong>` (<br />
<strong> `id_usuario` int(11) unsigned NOT NULL auto_increment,</strong><br />
<strong>`estado` enum(&#8216;activo&#8217;,'inactivo&#8217;) NOT NULL,<br />
</strong><strong> `_username` varbinary(16) NOT NULL,<br />
`_password` varbinary(32) NOT NULL,<br />
`nombres` varchar(50) NOT NULL,<br />
`apellidos` varchar(50) NOT NULL,<br />
</strong>`fecha_nacimiento` date default NULL,<br />
`tipo_documento` enum(&#8216;cc&#8217;,'ce&#8217;,'ti&#8217;,'nit&#8217;) NOT NULL,<br />
`documento_identidad` varchar(12) NOT NULL,<br />
`genero` enum(&#8216;m&#8217;,'f&#8217;) NOT NULL,<br />
`correo` varchar(255) NOT NULL,<br />
`pagina` varchar(255) default NULL,<br />
`observaciones` varchar(255) default NULL,<br />
`fecha_creacion` datetime NOT NULL,<br />
`fecha_actualizacion` datetime NOT NULL,<br />
PRIMARY KEY  (`id_usuario`),<br />
);</span></p>
<p>En el sitio se ha instalado un foro basado en la versión 1.1.11 de <a href="http://www.simplemachines.org/" >Simple Machines</a> el cual comparte la base de datos con el CMS.  Se necesita encontrar la forma de unificar los nombres de los usuarios y las contraseñas para tener una única identificación para la autenticación en los dos sistemas.</p>
<p>Para hacer esto se utiliza el API de <a href="http://docs.simplemachines.org/index.php?topic=400.0" >SSI</a> de SMF de la siguiente manera.</p>
<h2>Hooks de integración.</h2>
<p>SMF provee una facilidad para alterar el ciclo de flujo del software mediante la manipulación de <em>hooks</em> que se agregan a etapas específicas del programa para modificar su comportamiento por defecto.  En este caso nos interesa crear un <em>hook</em> sobre el punto <a href="http://www.simplemachines.org/community/index.php?topic=173483.msg1106028#msg1106028" ><span style="font-family: courier new,courier;">integrate_validate_login</span></a> ya que ese es el punto exacto en que SMF va a realizar la validación de los usuarios durante su autenticación.</p>
<p>Para implementar esto se crea un archivo llamado <span style="font-family: courier new,courier;">jimhook.php</span> (el nombre es arbitrario) con el siguiente contenido inicial.</p>
<pre class="php">&lt;?php
define('SMF_INTEGRATION_SETTINGS', serialize(array(
    'integrate_validate_login' =&gt; 'user_validate',
)));

require_once('SSI.php');

function user_validate()
{
    // Implementación de la lógica de la nueva autenticación.
}
?&gt;</pre>
<p>Estos <em>hooks</em> deben asociarse al sistema de foros agregando la siguiente línea al inicio del archivo <span style="font-family: courier new,courier;">index.php</span>.</p>
<pre class="php">include_once("jimhook.php");</pre>
<h2>Conexión a la base de datos.</h2>
<p>Como se mencionó inicialmente el CMS fue desarrollado en CodeIngniter y en este caso, comparte la base de datos con los foros.  El primer paso es obtener la información de conexión a la base de datos desde los archivos de configuración del CMS.</p>
<pre class="php">define('BASEPATH', 1);
include('../pt/system/application/config/database.php');</pre>
<p>Teniendo esta información se realiza una conexión global a la base de datos utilizando las funciones de PDO.</p>
<pre class="php">$pdo = null;

try
{
    $pdo = new PDO("mysql:host={$db['default']['hostname']};dbname={$db['default']['database']}",
                   $db['default']['username'],
                   $db['default']['password'],
                   array(PDO::MYSQL_ATTR_INIT_COMMAND =&gt; "SET NAMES utf8")
    );
}
catch (PDOException $e)
{
    print "Error!: " . $e -&gt; getMessage() . "&lt;br/&gt;";
    die();
}</pre>
<h2>Funciones de apoyo del CMS.</h2>
<p>Se crean algunas funciones básicas que servirán de soporte para el nuevo procedimiento de autenticación.</p>
<pre class="php">function existeUsuarioEnPlataforma($usuario)
{
    global $pdo;

    $stmt = $pdo -&gt; prepare("SELECT id_usuario FROM `usuarios` WHERE user=?");

    $results = $stmt -&gt; execute(array($usuario));

    return ($stmt -&gt; rowCount() &gt; 0);
}</pre>
<p>Verifica si el usuario identificado por el nombre de usuario (<span style="font-family: courier new,courier;">$usuario</span>) existe o no registrado en el CMS.  Retorna <span style="font-family: courier new,courier;">true</span> o <span style="font-family: courier new,courier;">false</span> según se encuentren o no efectivamente registrados.</p>
<pre class="php">function autenticarUsuarioEnPlataforma($usuario, $contrasena)
{
    global $pdo;

    $stmt = $pdo -&gt; prepare("SELECT id_usuario FROM `usuarios` WHERE user=? AND pass=?");

    $results = $stmt -&gt; execute(array($usuario, MD5($contrasena)));

    return ($stmt -&gt; rowCount() &gt; 0);
}</pre>
<p>Verifica que el usuario identificado con el nombre de usuario (<span style="font-family: courier new,courier;">$usuario</span>) tenga efectivamente a <span style="font-family: courier new,courier;">$contraseña</span> como clave de usuario.  Retorna <span style="font-family: courier new,courier;">true</span> en caso de coincidir, <span style="font-family: courier new,courier;">false</span> de lo contrario.</p>
<p>Nótese como el CMS almacena sus contraseñas en <a href="http://co.php.net/md5" >MD5</a> motivo por el cual es necesario realizar esta conversión antes de realizar la comparación en la consulta SQL.</p>
<h2>Funciones de apoyo de los foros.</h2>
<p>De manera análoga, estas funciones facilitan la manipulación de la información en las tablas del sistema de foros, las cuales tienen configurado el prefijo <span style="font-family: courier new,courier;">foros_</span> en sus tablas.</p>
<pre class="php">function existeUsuarioEnForos($usuario)
{
    global $pdo;

    $stmt = $pdo -&gt; prepare("SELECT ID_MEMBER FROM foros_members WHERE memberName = ?");

    $results = $stmt -&gt; execute(array($usuario));

    if($stmt -&gt; rowCount() == 0)
        return false;

    $fuente = $stmt -&gt; fetch();

    return $fuente['ID_MEMBER'];
}</pre>
<p>Verifica si el usuario identificado por el nombre de usuario (<span style="font-family: courier new,courier;">$usuario</span>) existe o no registrado en el foro .  Retorna el identificador del usuario si existe o <span style="font-family: courier new,courier;">false</span> de lo contrario.</p>
<pre class="php">function traerUsuario($usuario, $contrasena)
{
    global $pdo, $sourcedir, $modSettings;

    if(!existeUsuarioEnPlataforma($usuario))
        return false;

    $stmt = $pdo -&gt; prepare("SELECT * FROM `usuarios` WHERE user=?");

    $results = $stmt -&gt; execute(array($usuario));

    $fuente = $stmt -&gt; fetch();

    require_once($sourcedir . '/Subs-Members.php');

    $regOptions = array('username' =&gt; $fuente['user'],
                        'password' =&gt; $contrasena,
                        'password_check' =&gt; $contrasena,
                        'email' =&gt; $fuente['email'],
                        'posts' =&gt; '0',
                        'ID_GROUP' =&gt; '0',
                        'ID_POST_GROUP' =&gt; '4');

    $memberID = registerMember($regOptions);

    return ($memberID &gt; 0);
}</pre>
<p>Obtiene la información del usuario de plataforma identificado por <span style="font-family: courier new,courier;">$usuario</span> y <span style="font-family: courier new,courier;">$contrasena</span>, y lo agrega en la base de datos del foro a través de su API interno.  A este nivel no se realiza ninguna verificación de autenticación.</p>
<pre class="php">function activarUsuarioForo($usuario, $estado='1')
{
    global $pdo;

    $stmt = $pdo -&gt; prepare("UPDATE foros_members SET is_activated = ? WHERE memberName = ?");

    $control = $stmt -&gt; execute(array($estado, $usuario));

    return $control;
}</pre>
<p>Activa al usuario del foro recién creado, el cual por defecto siempre queda en espera de confirmación (<span style="font-family: courier new,courier;">is_activated = 3</span>).</p>
<pre class="php">function actualizarContrasenaForo($usuario, $contrasena)
{
    global $pdo;

    $passwd       = sha1(strtolower($usuario) . $contrasena);
    $passwordSalt = substr(md5(mt_rand()), 0, 4);

    $stmt = $pdo -&gt; prepare("UPDATE foros_members SET passwd = ?, passwordSalt = ? WHERE memberName = ?");

    $control = $stmt -&gt; execute(array($passwd, $passwordSalt, $usuario));

    return $control;
}</pre>
<p>Actualiza la <span style="font-family: courier new,courier;">$contrasena</span> del <span style="font-family: courier new,courier;">$usuario</span> en el sistema de foros.  Nótese como la <span style="font-family: courier new,courier;">$contrasena</span> se recibe de manera plana y se almacena en la base de datos de SMF en <a href="http://co.php.net/sha1" >SHA1</a>.</p>
<h2>Acerca del comportamiento del <em>login</em> de SMF.</h2>
<p>Algo que se debe tener en cuenta acerca del comportamiento del <em>login </em>de SMF es que desde el cliente (navegador del usuario) se envía la contraseña ya en su propia representación SHA1 así que si la contraseña con que se va a comparar no está en la misma representación, como en este caso, el CMS la almacena en MD5, se tiene entonces un problema.</p>
<p>Para solventar esto, el sistema de foros permite solicitar nuevamente la contraseña al usuario (<em>retry</em>) y en este segundo intento la envía totalmente plana para su manipulación libre.  En este punto es donde la aprovechamos para verificar la autenticación del usuario contra la información del CMS, crear el usuario en el foro si no existe y actualizar la contraseña en el foro previniendo que haya sido actualizada antes en el CMS.</p>
<h2>Implementación del nuevo proceso de autenticación.</h2>
<pre class="php">function user_validate()
{
    $user = $_REQUEST['user'];
    $id   = 0;

    // Verificar un usuario proveniente de plataforma.

    if(existeUsuarioEnPlataforma($user))
    {
        $id = existeUsuarioEnForos($user);

        // Nueva lógica de autenticación.
    }

    // El usuario no existe en plataforma, verificar los nativos del foro.

    return false;
}</pre>
<p>La base de la nueva autenticación es entonces la definición de la función <span style="font-family: courier new,courier;">user_validate</span> que corresponde con la especificada inicialmente durante la configuración de los <em>hooks</em>.</p>
<p>En ella se verifica inicialmente si el usuario que intenta acceder al sistema (<em>login</em>) se encuentra presente o no en la base de datos de usuarios del CMS.  En caso de no estar presente el control de la autenticación se libera para que el sistema verifique sus usuarios propios, esto permite definir también usuarios internos del foro que no estén presentes en el CMS.</p>
<p>El paso siguiente consiste en determinar si el usuario existe previamente o no en el foro, es decir, no es su primer ingreso al mismo.  A partir de esta respuesta se toma uno de los siguientes caminos.</p>
<ul>
<li>Si no está disponible la contraseña plana (primer <em>login</em>) se solicita nuevamente (segundo <em>login</em>).</li>
<li>Si el usuario no existe en el foro entonces ...
<ul>
<li>Se verifica que el nombre de usuario y la contraseña coincidan.</li>
<li>Se crea el usuario en el foro.</li>
<li>Se activa al nuevo usuario.</li>
</ul>
</li>
<li>Si el usuario ya existía previamente en el foro entonces ...
<ul>
<li>Se verifica que el nombre de usuario y la contraseña coincidan.</li>
<li>Se actualiza la contraseña en el foro por si ha sido actualizada previamente en el CMS.</li>
</ul>
</li>
</ul>
<p>La implementación de estas acciones se detalla a continuación.  En el caso en que el usuario no exista previamente en el foro se ejecuta la siguiente lógica del negocio.</p>
<pre class="php">if($id === false)
{
    // Esta disponible la contrasena (2do. login).

    if(isset($_REQUEST['passwrd']) &amp;&amp; !empty($_REQUEST['passwrd']))
    {
        $auth = autenticarUsuarioEnPlataforma($user, $_REQUEST['passwrd']);

        if($auth)                           // La informacion del usuario es valida.
        {
            $id = traerUsuario($user, $_REQUEST['passwrd']);

            activarUsuarioForo($user);

            return false;                   // La autenticacion tiene EXITO.
        }
        else                                // La informacion del usuario NO es valida.
            return true;                    // La autenticacion FALLA.
    }
    else                                    // No esta disponible la contrasena (1er. login).
        return "retry";                     // Vuelva a solicitar el login para confirmar.
}</pre>
<p>En el caso en que el usuario si exista previamente en el foro, el procedimiento es mas simple y se ejecuta  la siguiente lógica del negocio.</p>
<pre class="php">// El usuario existe en el foro.

if($id !== false)
{
    // Esta disponible la contrasena (2do. login) -&gt; actualizar la contraseña en el foro.

    if(isset($_REQUEST['passwrd']) &amp;&amp; !empty($_REQUEST['passwrd']))
    {
        $auth = autenticarUsuarioEnPlataforma($user, $_REQUEST['passwrd']);

        if($auth)                           // La informacion del usuario es valida.
        {
            actualizarContrasenaForo($user, $_REQUEST['passwrd']);

            return false;                   // La autenticacion tiene EXITO.
        }
        else                                // La informacion del usuario NO es valida.
            return true;                    // La autenticacion FALLA.
    }
    else                                    // No esta disponible la contrasena (1er. login).
        return "retry";                     // Vuelva a solicitar el login para confirmar.
}</pre>
<h2>Conclusiones.</h2>
<p>Hasta ahora, con poca experiencia en su uso, SMF parece ser un sistema de foros útil y práctico.  El proceso de determinar esta unificación de la autenticación fue largo y doloroso debido a la poca documentación que pude encontrar acerca del API, la cual en su mayor parte se encuentra diseminada en los foros de su sitio web.</p>
<p>En términos de su código parece tener un nivel decente de flexibilidad, el concepto de <em>hooks</em> permite realizar modificaciones interesantes al flujo normal del software, sin embargo es difícil formalizarlo al no contar con información suficiente de su lógica de funcionamiento.  Algunas partes del software, en especial los temas, adolecen de separación MVC por lo que se hace necesario editar funciones, entre comillas, que retornan el código HTML que se desea modificar siendo esto molesto, difícil y propenso a errores, sobretodo si se compara con tener archivos PHP separados con la lógica y HTML con la presentación como sería una mejor opción.</p>
<p>Finalmente, después de varios días de luchas y de pruebas, la unificación de la autenticación está funcionando y se ve bien, de todas maneras es mi primer acercamiento a este software por lo que no puedo garantizar que sea la mejor aproximación.  Como siempre, estoy abierto a sugerencias constructivas.</p>
<h2>Enlaces.</h2>
<ul>
<li>Simple Machines.<br />
<a href="http://www.simplemachines.org/" >http://www.simplemachines.org/</a>
<ul>
<li>A guide to the SMF integration hooks.<br />
<a href="http://www.simplemachines.org/community/index.php?topic=173483.0" >http://www.simplemachines.org/community/index.php?topic=173483.0</a></li>
</ul>
</li>
<li>CodeIgniter.<br />
<a href="http://codeigniter.com/" >http://codeigniter.com/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2010/05/integracion-de-una-autenticacion-externa-con-los-foros-de-simple-machines-1-1-11/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Los controladores en Yii</title>
		<link>http://blog.jorgeivanmeza.com/2010/01/los-controladores-en-yii-2/</link>
		<comments>http://blog.jorgeivanmeza.com/2010/01/los-controladores-en-yii-2/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 05:45:56 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Desarrollo de software]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[yii]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2262</guid>
		<description><![CDATA[Introducción.
Estos se ubican entre el usuario y la aplicación.  Su función es la de controlar la comunicación entre los modelos y la vistas según la solicitud (requerimiento) que ha hecho usuario.
Su clase base es CController y en ellos se implementan Acciones (definen la lógica de la aplicación) y Filtros (establecen validaciones o controles antes y [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>Estos se ubican entre el usuario y la aplicación.  Su función es la de controlar la comunicación entre los modelos y la vistas según la solicitud (requerimiento) que ha hecho usuario.</p>
<p>Su clase base es <span style="font-family: courier new,courier;">CController</span> y en ellos se implementan <strong>Acciones</strong> (definen la lógica de la aplicación) y <strong>Filtros</strong> (establecen validaciones o controles antes y después de la ejecución de las acciones).</p>
<p>El usuario invoca indirectamente a los controladores especificando un <strong>ruta</strong> a través del controlador frontal o <span style="font-family: courier new,courier;">Application</span>.</p>
<h2>La ruta del requerimiento.</h2>
<p>El URL solicitado determina que controlador y que acción se van a ejecutar para resolver el requerimiento del usuario.</p>
<p>Los URL tienen el siguiente formato.</p>
<p style="padding-left: 30px;">Sin <em>URL limpias</em> (por defecto).</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">http://servidor/index.php?r=ControladorId/AcciónId</span></p>
<p style="padding-left: 30px;">Con <em>URL limpias</em>.</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">http://servidor/ControladorId/AcciónId</span></p>
<p style="padding-left: 30px;">Si se utilizan módulos (y <em>URL limpias</em> para este ejemplo).</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">http://servidor/MóduloId/ControladorId/AcciónId</span></p>
<ul>
<li>El archivo fuente del controlador se ubica en <span style="font-family: courier new,courier;">protected/controllers/<strong>ControladorId</strong>Controller.php</span>.</li>
<li>El nombre de la clase allí contenida deberá ser <span style="font-family: courier new,courier;"><strong>ControladorId</strong>Controller</span>.</li>
<li>Se invoca a la acción (ver mas adelante) <span style="font-family: courier new,courier;">AcciónId</span>.  En caso de no haberse especificado una se considera la acción por defecto del controlador, comúnmente <span style="font-family: courier new,courier;">index</span>.</li>
</ul>
<h2>Las acciones.</h2>
<p>Pueden implementarse de dos maneras.</p>
<ul>
<li>Como métodos del mismo controlador.</li>
<li>Como clases que heredan de <span style="font-family: courier new,courier;">CAction</span>.</li>
</ul>
<h3>Acciones implementadas como métodos del controlador.</h3>
<ul>
<li>El nombre del método deberá ser <span style="font-family: courier new,courier;">action<strong>AcciónId</strong></span>.</li>
</ul>
<p>En el siguiente ejemplo se muestra al controlador <span style="font-family: courier new,courier;">User</span> que implementa la acción <span style="font-family: courier new,courier;">add</span> como un método suyo.</p>
<pre class="php">class UserController extends CController
{
    public function actionAdd()
    {
        // Implementación ...
    }
}</pre>
<h3>Acciones implementadas como clases independientes.</h3>
<ul>
<li>Los objetos acción heredan de <span style="font-family: courier new,courier;">CAction</span>.</li>
<li>El nombre de la clase es <span style="font-family: courier new,courier;"><strong>AcciónId</strong>Action</span> (por convención, no es obligatorio).</li>
<li>Se almacena en un archivo bajo la ruta <span style="font-family: courier new,courier;">protected/controllers/<strong>controladorId</strong>/<strong>AcciónId</strong>Action.php.</span></li>
<li>Su ubicación puede referenciarse mediante alias de esta manera: <span style="font-family: courier new,courier;">application.controllers.<strong>controladorId</strong>.<strong>AcciónId</strong>Action</span>.</li>
<li>Es obligatorio sobreescribir el método <span style="font-family: courier new,courier;">run()</span> de la acción para definir allí su implementación.</li>
</ul>
<p>En el siguiente código se muestra la acción <span style="font-family: courier new,courier;">remove</span> del controlador <span style="font-family: courier new,courier;">User</span> implementada como una clase independiente.</p>
<pre class="php">class RemoveAction extends CAction
{
    public function run()
    {
        // Implementación ...
    }
}</pre>
<p>Esta clase se almacena entonces en el archivo <span style="font-family: courier new,courier;">protected/controllers/user/RemoveAction.php</span>.</p>
<p>Como paso final de su implementación, es necesario indicarle al controlador de la existencia de la acción.  Para hacer esto es necesario sobreescribir el método <span style="font-family: courier new,courier;">actions</span> del controlador de la siguiente manera.</p>
<pre class="php">class UserController extends CController
{
   public function actions()
   {
       return array(
           'remove' =&gt; 'application.controllers.user.RemoveAction'
       );
   }
}</pre>
<h2>Los filtros.</h2>
<ul>
<li>Permiten realizar verificaciones y validaciones antes y después de la ejecución de las acciones.</li>
<li>Una acción puede tener asociados múltiples filtros.</li>
<li>Los filtros se ejecutan en el orden en que fueron especificados.</li>
<li>Un filtro puede abortar la ejecución de los demás filtros y de la acción misma.</li>
<li>De manera análoga a las acciones, los filtros pueden implementarse de dos maneras también.
<ul>
<li>Como métodos del mismo controlador.</li>
<li>Como clases que heredan de <span style="font-family: courier new,courier;">CFilter</span>.</li>
</ul>
</li>
</ul>
<h3>Filtros implementados como métodos del controlador.</h3>
<ul>
<li>El nombre del método debe empezar por la palabra <span style="font-family: courier new,courier;">filter</span>.</li>
<li>Deberá recibir como parámetro a <span style="font-family: courier new,courier;">$filterChain</span>.</li>
</ul>
<p>En el siguiente ejemplo se muestra al controlador <span style="font-family: courier new,courier;">User</span> que implementa al filtro <span style="font-family: courier new,courier;">checkUser</span> como un método suyo.</p>
<pre class='php'>class UserController extends CController
{
    public function filterCheckUser($filterChain)
    {
        // Implementación ... invocar $filterChain -&gt; run()
        // para continuar con el próximo filtro
    }
}</pre>
<h3>Filtros implementados como clases independientes.</h3>
<ul>
<li>Los objetos acción heredan de <span style="font-family: courier new,courier;">CFilter</span>.</li>
<li>El nombre de la clase es <span style="font-family: courier new,courier;"><strong>FiltroId</strong>Filter</span> (por convención, no es obligatorio).</li>
<li>Se almacena en un archivo bajo la ruta <span style="font-family: courier new,courier;">protected/filters/<strong>FiltroId</strong>Filter.php</span>.</li>
<li>Su ubicación puede referenciarse mediante alias de esta manera: <span style="font-family: courier new,courier;">application.filters.<strong>FiltroId</strong>Filter</span>.</li>
<li>Es obligatorio sobreescribir los métodos <span style="font-family: courier new,courier;">preFilter($filterChain)</span> y <span style="font-family: courier new,courier;">postFilter($filterChain)</span> del filtro para definir que hacer antes y después de ejecutar la acción.</li>
</ul>
<p>En el siguiente código se muestra al filtro <span style="font-family: courier new,courier;">isValid</span> del controlador <span style="font-family: courier new,courier;">User</span> implementado como una clase independiente.</p>
<pre class='php'>class IsValidFilter extends CFilter
{
    public $admin;

    public function preFilter($filterChain)
    {
        // Se aplica antes de ejecutarse la acción.
        // Si retorna true continúa el proceso, false lo
        // aborta y no se ejecuta la acción solicitada.

        return $exito;
    }

    public function postFilter($filterChain)
    {
        // Se aplica después de ejecutarse la acción.
    }
}</pre>
<p>Esta clase se almacena entonces en el archivo <span style="font-family: courier new,courier;">protected/filters/IsValidFilter.php</span>.</p>
<p>Como paso final de su implementación, es necesario indicarle al controlador de la existencia del filtro y determinar su alcance sobre las acciones del mismo.  Para hacer esto es necesario sobreescribir el método <span style="font-family: courier new,courier;">filters</span> del controlador de la siguiente manera.</p>
<pre class='php'>class UserController extends CController
{
   public function filters()
   {
       return array(
           'checkUser + add, remove',

           array(
               'application.filters.IsValidFilter - add, remove',
               'admin' =&gt; false
           )
       );
   }
}</pre>
<ul>
<li><span style="font-family: courier new,courier;">checkUser</span> es un filtro basado en un método del controlador.</li>
<li><span style="font-family: courier new,courier;">isValid</span> es un filtro basado en una clase externa.</li>
<li>Es posible especificar los filtros con una notación de arreglo para determinar valores específicos para los atributos del filtro.</li>
</ul>
<p>Los operadores <span style="font-family: courier new,courier;">+</span> y <span style="font-family: courier new,courier;">-</span> actúan como determinadores del alcance de los filtros sobre las acciones especificadas de la siguiente manera.</p>
<ul>
<li><span style="font-family: courier new,courier;">+</span> determina exactamente a cuales acciones se les debe aplicar el filtro.  De esta manera, el filtro <span style="font-family: courier new,courier;">checkUser</span> se aplicará a las acciones <span style="font-family: courier new,courier;">add</span> y <span style="font-family: courier new,courier;">remove</span> únicamente.</li>
<li><span style="font-family: courier new,courier;">-</span> determina a cuales acciones NO se les debe aplicar el filtro.  Así, el filtro <span style="font-family: courier new,courier;">isValid</span> se aplicará a todas las acciones EXCEPTO a <span style="font-family: courier new,courier;">add</span> y <span style="font-family: courier new,courier;">remove</span>.</li>
<li>Si no se especifica ninguno de los dos modificadores, el filtro aplicará a todas las acciones del controlador.</li>
</ul>
<h2>Enlaces.</h2>
<ul>
<li>Yii Documentation: controllers.<br />
<a href="http://www.yiiframework.com/doc/guide/basics.controller" >http://www.yiiframework.com/doc/guide/basics.controller</a></li>
<li>Yii PHP Framwork.<br />
<a href="http://www.yiiframework.com/" >http://www.yiiframework.com/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2010/01/los-controladores-en-yii-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evitando el reemplazo de los guiones dobles en WordPress 2.9</title>
		<link>http://blog.jorgeivanmeza.com/2009/12/evitando-el-reemplazo-de-los-guiones-dobles-en-wordpress-2-9/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/12/evitando-el-reemplazo-de-los-guiones-dobles-en-wordpress-2-9/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 07:10:46 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2220</guid>
		<description><![CDATA[Introducción.
Algo que extrañamente no había notado hasta el día de hoy es que Wordpress reemplaza, a manera de característica y en total contra de mi voluntad, los guíones dobles (--) por simples (-) en el momento de generar la presentación de los artículos.  Esto es altamente incoveniente ya que ciertos comandos, especialmente de UNIX, requieren [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>Algo que extrañamente no había notado hasta el día de hoy es que Wordpress reemplaza, a manera de <em>característica</em> y en total contra de mi voluntad, los guíones dobles (<span style="font-family: courier new,courier;">--</span>) por simples (<span style="font-family: courier new,courier;">-</span>) en el momento de generar la presentación de los artículos.  Esto es altamente incoveniente ya que ciertos comandos, especialmente de UNIX, requieren de opciones que inician con doble guión, como por ejemplo <span style="font-family: courier new,courier;">--help</span>.</p>
<p>El método que encontré para evitar este problema no es probablemente el mas elegante de todos, sin embargo funciona muy bien.  Debe tenerse muy en cuenta en el momento de actualizar el núcleo de Wordpress ya que, al modificar un archivo de la distribución, probablmente deba aplicarse la modificación cada vez que se instale una nueva versión.</p>
<h2>Procedimiento.</h2>
<p>Edite el archivo responsable del formateo de los artículos.</p>
<p><span style="font-family: courier new,courier;">$ vi wp-includes/formatting.php</span></p>
<p>Ubique las variables <span style="font-family: courier new,courier;">$static_characters</span> y <span style="font-family: courier new,courier;">$static_replacements</span> que se encuentran en las líneas 56 y 57 de la versión 2.9 de Wordpress (pueden variar en otras versiones).</p>
<pre class="php">$static_characters = array_merge(array('---', ' -- ', '--', ' - ', 'xn&amp;#8211;', '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
$static_replacements = array_merge(array('&amp;#8212;', ' &amp;#8212; ', '&amp;#8211;', ' &amp;#8211; ', 'xn--', '&amp;#8230;', $opening_quote, '&amp;#8217;s', $closing_quote, ' &amp;#8482;'), $cockneyreplace);</pre>
<p>Remueva o comente (mucho mejor) los primeros cinco elementos de cada uno de los arreglos.</p>
<pre class="php">$static_characters = array_merge(array(/* '---', ' -- ', '--', ' - ', 'xn&amp;#8211;', */ '...', '``', '\'s', '\'\'', ' (tm)'), $cockney);
$static_replacements = array_merge(array(/* '&amp;#8212;', ' &amp;#8212; ', '&amp;#8211;', ' &amp;#8211; ', 'xn--', */ '&amp;#8230;', $opening_quote, '&amp;#8217;s', $closing_quote, ' &amp;#8482;'), $cockneyreplace);</pre>
<p>Grabe el archivo.</p>
<p>Listo!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/12/evitando-el-reemplazo-de-los-guiones-dobles-en-wordpress-2-9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redefinir una función en Javascript</title>
		<link>http://blog.jorgeivanmeza.com/2009/12/redefinir-una-funcion-en-javascript/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/12/redefinir-una-funcion-en-javascript/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 18:14:45 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Desarrollo de software]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2190</guid>
		<description><![CDATA[Introducción.
Estaba reutilizando un formulario complejo en un nuevo módulo de mi aplicación.  Todo iba bien hasta que descubrí que uno de los códigos Javascript que actualiza parte del formulario a través de AJAX no me era útil ya que debía mostrar una vista diferente a la estándar.   Como el código estaba escrito en funciones procedimentales [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>Estaba <em>reutilizando</em> un formulario complejo en un nuevo módulo de mi aplicación.  Todo iba bien hasta que descubrí que uno de los códigos Javascript que actualiza parte del formulario a través de AJAX no me era útil ya que debía mostrar una vista diferente a la <em>estándar</em>.   Como el código estaba escrito en funciones procedimentales no podía acceder a la sobreescritura de la orientación a objetos, sin embargo encontré un par de detalles interesantes de Javascript que me permitieron hacer algo similar.</p>
<h2>Determinar existencia de funciones.</h2>
<pre class="javascript">if(typeof miFuncion == 'function')
    // Si existe la función
else
    // No existe la función</pre>
<p>El código anterior determina si la función <span style="font-family: courier new,courier;">miFuncion</span> ha sido definida o no en el espacio de ejecución de la aplicación Javascript.</p>
<h2>Redefinir una función.</h2>
<pre class="javascript">window['miFuncion'] = function()
{
    // Nueva implementación de la función
};</pre>
<p>El código anterior permite redefinir la implementación de la función <span style="font-family: courier new,courier;">miFuncion</span> la cual obviamente fue especificada anteriormente.  Lo interesante de esta sintáxis de Javascript es que esta redefinición puede realizarse de manera dinámica, es decir, en un segundo archivo <span style="font-family: courier new,courier;">*.js</span> que se cargue después del original o inclusive dentro de un condicional.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/12/redefinir-una-funcion-en-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instalar Chromium Browser en Linux Ubuntu 9.10</title>
		<link>http://blog.jorgeivanmeza.com/2009/12/instalar-chromium-browser-en-linux-ubuntu-9-10/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/12/instalar-chromium-browser-en-linux-ubuntu-9-10/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 23:33:45 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Browser]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Chromium]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[Linux/Solaris/BSD]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2185</guid>
		<description><![CDATA[Introducción.
Chromium Browser (Chrome) es el navegador web de Google que desde hace un tiempo puede ser descargado y utilizado en la plataforma Windows.  Desafortunadamente aún no hay una versión (release) oficial para la plataforma Linux, sin embargo es posible instalarlo en Ubuntu mediante un PPA de frecuente actualización.
Instalación.
Agregar el repositorio.
$ sudo add-apt-repository ppa:chromium-daily/ppa
Instalar los paquetes.
$ [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p><em>Chromium Browser</em> (<em>Chrome</em>) es el navegador web de Google que desde hace un tiempo puede ser <a href="http://www.google.com/chrome/" >descargado</a> y utilizado en la plataforma Windows.  Desafortunadamente aún no hay una versión (<em>release</em>) oficial para la plataforma Linux, sin embargo es posible instalarlo en Ubuntu mediante un PPA de frecuente actualización.</p>
<h2>Instalación.</h2>
<h3>Agregar el repositorio.</h3>
<p><span style="font-family: courier new,courier;">$ sudo add-apt-repository ppa:chromium-daily/ppa</span></p>
<h3>Instalar los paquetes.</h3>
<p><span style="font-family: courier new,courier;">$ sudo aptitude update</span></p>
<p><span style="font-family: courier new,courier;">$ sudo aptitude install chromium-browser chromium-codecs-ffmpeg</span></p>
<h2>Ejecución.</h2>
<p><a href="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/12/screenshot_007.png"><img class="aligncenter size-full wp-image-2186" title="screenshot_007" src="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/12/screenshot_007.png" alt="screenshot_007" width="740" height="486" /></a></p>
<p>Ejecutar la aplicación desde el menú de programas a través de la siguiente ruta.</p>
<p style="padding-left: 30px;"><strong>Applications</strong> &gt; <strong>Internet</strong> &gt; <strong>Chromium Web Browser</strong>.</p>
<p>O desde la línea de comando como se muestra a continuación.</p>
<p><span style="font-family: courier new,courier;">$ /usr/bin/chromium-browser &amp;</span></p>
<h2>Enlaces.</h2>
<ul>
<li>Instalación y puesta a punto de Chromium en GNU/Linux.<br />
<a href="http://bitelia.com/2009/11/instalacion-y-puesta-a-punto-de-chromium-en-gnulinux" >http://bitelia.com/2009/11/instalacion-y-puesta-a-punto-de-chromium-en-gnulinux</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/12/instalar-chromium-browser-en-linux-ubuntu-9-10/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Probar la nueva interfaz de Google en Colombia</title>
		<link>http://blog.jorgeivanmeza.com/2009/11/probar-la-nueva-interfaz-de-google-en-colombia/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/11/probar-la-nueva-interfaz-de-google-en-colombia/#comments</comments>
		<pubDate>Fri, 27 Nov 2009 14:02:29 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2161</guid>
		<description><![CDATA[Introducción.
No había podido probar la nueva interfaz de Google en Colombia ya que el procedimiento que circulaba por Internet aplicaba al dominio google.com y cuando intentaba acceder a él soy redirigido a google.com.co por lo cual la prueba no tenía efecto.  Por suerte ya encontré como superar esta situación y es en realidad muy sencillo.
Procedimiento.
Abra [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>No había podido probar la nueva interfaz de Google en Colombia ya que el procedimiento que circulaba por Internet aplicaba al dominio <span style="font-family: courier new,courier;">google.com</span> y cuando intentaba acceder a él soy redirigido a <span style="font-family: courier new,courier;">google.com.co</span> por lo cual la prueba no tenía efecto.  Por suerte ya encontré como superar esta situación y es en realidad muy sencillo.</p>
<h2>Procedimiento.</h2>
<p>Abra un navegador web.</p>
<p>Escriba el siguiente código en la barra de direcciones y presione <strong>Enter</strong>.</p>
<p style="padding-left: 30px;"><span style="font-family: courier new,courier;">javascript:void(document.cookie=&#8221;PREF=ID=20b6e4c2f44943bb:U=4bf292d46faad806:TM=1249677602:LM=1257919388:S=odm0Ys-53ZueXfZG;path=/; domain=.google.com&#8221;);</span></p>
<p>Visite la página <a href="http://google.com/ncr" >http://google.com/ncr</a>.  Aparecerá la página de búsqueda con la nueva interfaz.</p>
<p><a href="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/11/screenshot_003.png"><img class="aligncenter size-full wp-image-2162" title="screenshot_003" src="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/11/screenshot_003.png" alt="screenshot_003" width="565" height="472" /></a></p>
<p>Realice cualquier búsqueda y podrá apreciar la nueva presentación de los resultados con una barra izquierda que facilita el acceso a los servicios de Google y algunos filtros para la información.</p>
<p><a href="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/11/screenshot_0042.png"><img class="aligncenter size-full wp-image-2163" title="screenshot_004" src="http://blog.jorgeivanmeza.com/wp-content/uploads/2009/11/screenshot_0042.png" alt="screenshot_004" width="558" height="442" /></a></p>
<p>Para volver a la interfaz convencional es necesario remover la <em>cookie</em> del sitio.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/11/probar-la-nueva-interfaz-de-google-en-colombia/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hacer algo cuando inicia o termina el evento AJAX con Prototype</title>
		<link>http://blog.jorgeivanmeza.com/2009/11/hacer-algo-cuando-inicia-o-termina-el-evento-ajax-con-prototype/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/11/hacer-algo-cuando-inicia-o-termina-el-evento-ajax-con-prototype/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 13:46:15 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Desarrollo de software]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2152</guid>
		<description><![CDATA[Introducción.
De manera análoga a como hace poco había mostrado como manejar el evento de inicio y terminación de AJAX con jQuery para realizar algún tipo de acción específica como el mostrar un indicador de carga, ahora experimentaremos como hacerlo con el framework de Prototype el cual nuevamente estaré utilizando en el proyecto de los próximos [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>De manera análoga a como hace poco había mostrado como <a href="http://blog.jorgeivanmeza.com/2009/10/hacer-algo-cuando-inicia-o-termina-el-evento-ajax-con-jquery/" >manejar el evento de inicio y terminación de AJAX con jQuery</a> para realizar algún tipo de acción específica como el mostrar un indicador de carga, ahora experimentaremos como hacerlo con el framework de Prototype el cual nuevamente estaré utilizando en el proyecto de los próximos meses.</p>
<h2>Procedimiento.</h2>
<pre class="javascript">Ajax.Responders.register({
    onCreate: function()
    {
        // An AJAX request has been initialized!
    }, 

    onComplete: function()
    {
        // An AJAX request has been completed!
    }
});</pre>
<p>Adicionalmente hay otros eventos que pueden manejarse de igual manera <span style="font-family: courier new,courier;">onUninitialized</span>, <span style="font-family: courier new,courier;">onLoading</span>, <span style="font-family: courier new,courier;">onLoaded</span>, <span style="font-family: courier new,courier;">onInteractive</span> y <span style="font-family: courier new,courier;">onException</span>, además de los ya mencionados <span style="font-family: courier new,courier;">onCreate</span> y <span style="font-family: courier new,courier;">onComplete</span>.</p>
<h2>Enlaces.</h2>
<ul>
<li>Prototype API - Ajax Responders.<br />
<a href="http://api.prototypejs.org/ajax/ajax/responders.html" >http://api.prototypejs.org/ajax/ajax/responders.html</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/11/hacer-algo-cuando-inicia-o-termina-el-evento-ajax-con-prototype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ejemplo rápido y simple de AJAX con PHP y PrototypeJS</title>
		<link>http://blog.jorgeivanmeza.com/2009/11/ejemplo-rapido-y-simple-de-ajax-con-php-y-prototypejs/</link>
		<comments>http://blog.jorgeivanmeza.com/2009/11/ejemplo-rapido-y-simple-de-ajax-con-php-y-prototypejs/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 17:33:24 +0000</pubDate>
		<dc:creator>jimezam</dc:creator>
				<category><![CDATA[Sindicados]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[Desarrollo de hardware]]></category>
		<category><![CDATA[Hipergalaxia]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.jorgeivanmeza.com/?p=2148</guid>
		<description><![CDATA[Introducción.
Intentando recuperar mis neuronas que saben de Prototype para continuar por fin con uno de los proyectos que se encontraba en pausa permanente, el día de hoy me día a la breve tarea de recordar un poco la invocación asíncrona y la manipulación del DOM utilizando esta librería.  Para hacer una pequeña práctica decidí modificar [...]]]></description>
			<content:encoded><![CDATA[<h2>Introducción.</h2>
<p>Intentando recuperar mis neuronas que saben de <a href="http://prototypejs.org/" >Prototype</a> para continuar por fin con uno de los proyectos que se encontraba en pausa permanente, el día de hoy me día a la breve tarea de recordar un poco la invocación asíncrona y la manipulación del DOM utilizando esta librería.  Para hacer una pequeña práctica decidí modificar el ejemplo de la <a href="http://blog.jorgeivanmeza.com/2009/10/ejemplo-de-ajax-rapido-y-simple-con-php-y-jquery/" >calculadora que se basaba en jQuery y PHP</a> para migrar su código de acuerdo con la especificación de Prototype.</p>
<p>Las modificaciones necesarias se centraron en la inclusión de la librería javascript en la página web (<em>frontend</em>) y en reescribir la invocación asíncrona de la aplicación web en PHP (<em>backend</em>).</p>
<h2>Procedimiento.</h2>
<p>Reemplazar la inclusión de la librería de jQuery por la de Prototype.  Para este caso se continúo utilizando el API de Google AJAX.</p>
<pre class="javascript">&lt;script src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
&lt;script&gt;google.load("prototype", "1.6");&lt;/script&gt;</pre>
<p>Posteriormente se asoció el manejo del evento de presión del botón <span style="font-family: courier new,courier;">igual</span> a la invocación de la función <span style="font-family: courier new,courier;">procesar</span>, esto se realiza tan pronto como la estructura de la página (código HTML) se encuentra cargada completamente por el navegador.</p>
<pre class="javascript">/* Código a ejecutarse tan pronto como la
   página ha sido cargada por el navegador */

document.observe('dom:loaded', function()
{
    /* Asociar el evento de clic del botón 'igual'
       con la lógica del negocio de la aplicación */

    Event.observe('igual', 'click', procesar);
});</pre>
<p>Finalmente se implementa la función <span style="font-family: courier new,courier;">procesar</span> que realizará la invocación asíncrona del cálculo matemático.  Esta función consta de las siguientes partes.</p>
<ol>
<li>Información básica del requerimiento.</li>
<li>Que hacer en caso de éxito.</li>
<li>Que hacer en caso de fracaso.</li>
</ol>
<p>El requerimiento incluye la siguiente información básica de conexión.</p>
<ul>
<li>El URL de la aplicación remota a invocar (<em>backend</em>).</li>
<li>El método HTTP a utilizar.</li>
<li>Los parámetros de la página web a enviarse.</li>
</ul>
<pre class="javascript">function procesar()
{
    new Ajax.Request('calcular.php',                                         /* URL a invocar asíncronamente */
    {
        method:       'post',                                                /* Método utilizado para el requerimiento */
        parameters:   $('formulario').serialize(true),                       /* Información local a enviarse con el requerimiento */</pre>
<p>En caso de que la invocación asíncrona tenga un resultado exitoso se deberán realizar los siguientes pasos.</p>
<ul>
<li>Mostrar un mensaje de éxito en color verde.</li>
<li>Desplegar el valor del resultado obtenido en el campo definido para tal fin.</li>
</ul>
<pre class="javascript">        /* Que hacer en caso de ser exitoso el requerimiento */

        onSuccess: function(transport)
        {
            /* Cambiar el color del texto a verde */

            $('mensaje').setStyle('color: #0ab53a');

            /* Mostrar un mensaje informando el éxito sucedido */

            $('mensaje').update("Operación realizada exitosamente");

            /* Mostrar el resultado obtenido del cálculo solicitado */

            $('resultado').update(transport.responseText);
        },</pre>
<p>En caso de que fracase el proceso de invocación asíncrona se deberán realizar los siguientes pasos análogos.</p>
<ul>
<li>Mostrar el mensaje de error proveniente del servidor, en color rojo.</li>
<li>Limpiar cualquier resultado previo para evitar confusiones con la operación.</li>
</ul>
<pre class="javascript">        /* Que hacer en caso de que sea fallido el requerimiento */

        onFailure: function(transport)
        {
            /* Cambiar el color del texto a rojo */

            $('mensaje').setStyle('color: #ff0e0e');

            /* Mostrar el mensaje de error */

            $('mensaje').update('Error: ' + transport.responseText);

            /* Limpiar cualquier resultado anterior */

            $('resultado').update('Error');
        }
    });
}</pre>
<h2>Enlaces.</h2>
<ul>
<li>Demostración &amp; descarga del código fuente.<br />
<a href="http://demo.jorgeivanmeza.com/Prototype/AjaxSimpleRapido-Calc/" >http://demo.jorgeivanmeza.com/Prototype/AjaxSimpleRapido-Calc/</a></li>
<li>Prototype Javascript Framework.<br />
<a href="http://prototypejs.org/" >http://prototypejs.org/</a></li>
<li>Prototype Introduction to Ajax.<br />
<a href="http://www.prototypejs.org/learn/introduction-to-ajax" >http://www.prototypejs.org/learn/introduction-to-ajax</a></li>
<li>Prototype's AJAX Request API.<br />
<a href="http://api.prototypejs.org/ajax/ajax/request.html" >http://api.prototypejs.org/ajax/ajax/request.html</a></li>
<li>Prototype's Element API.<br />
<a href="http://api.prototypejs.org/dom/element.html" >http://api.prototypejs.org/dom/element.html</a></li>
<li>Ejemplo de AJAX rápido y simple con PHP y jQuery.<br />
<a href="http://blog.jorgeivanmeza.com/2009/10/ejemplo-de-ajax-rapido-y-simple-con-php-y-jquery/" >http://blog.jorgeivanmeza.com/2009/10/ejemplo-de-ajax-rapido-y-simple-con-php-y-jquery/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.jorgeivanmeza.com/2009/11/ejemplo-rapido-y-simple-de-ajax-con-php-y-prototypejs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
