<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
	<channel>
	<title>Open Populi</title> 
	<link><![CDATA[http://www.openpopuli.com]]></link> 
	<description><![CDATA[Open Populi, S.L]]></description>
	<language>es-es</language> 
	<copyright><![CDATA[Copyright Open Populi, S.L]]></copyright>
			<image>
				<url>http://www.openpopuli.com/images/logotipo_openpopuli.gif</url>
				<title>Noticias Open Populi</title>
				<link>http://www.openpopuli.com</link>
			</image>
		<item>
<title><![CDATA[Introducción a Comet y aplicaciones RIA]]></title><link><![CDATA[http://www.openpopuli.com/noticia/introduccion-a-comet-y-aplicaciones-ria]]></link><description><![CDATA[En la introducción de este artículo, quiero citar un poco de historia contemporánea acerca de tecnologías web. Hasta no hace mucho mas de 5 años, las aplicaciones web based, tenían un gran dilema: cada vez que se necesitaba mostrar los datos que han resultado de peticiones al server, se debía recargar la pagina en su totalidad. Lo que producía que  las aplicaciones fueran bastante limitadas en cuanto a interactividad, velocidad,  usabilidad y tiempos de respuesta. Cuando aparece AJAX (Asynchronous JavaScript And XML) allá por 2005,  acerca a la gran mayoría de la comunidad de desarrollo el concepto de comunicacion asincrona con el servidor en segundo plano y abre todo un mundo de posibilidades, comenzando y produciendo un gran cambio que ha revolucionado la web. Aparecen aplicaciones web based que empiezan a asemejarse bastante a aplicaciones de escritorio. Permitiendo construir aplicaciones con UI's más potentes, amigables e intuitivas.<br /><br />Viendo toda esta revolución pasar por nuestras narices, el desarrollo de aplicaciones RIA (Rich Internet Applications) nos exige ir un poco mas allá. Por ejemplo, supongamos que debemos desarrollar una aplicación de mail, con su correspondiente bandeja de entrada. Esta aplicación necesitaría que cada cliente (browser) este actualizado al instante, en cuanto a las novedades que ocurren en el server que tienen que ver con él. Es decir, cada usuario de nuestra aplicación de mail tiene que enterarse de que ha llegado un nuevo correo que lo tiene como destinatario.<br /><br />De este ejemplo se desprende la necesidad de tener un canal bidireccional de comunicación  entre servidor y cliente. Digamos, que en ciertas oportunidades, cuando el servidor tiene novedades en relación a un cliente, sea este quien envie los datos sin necesidad que el cliente este constantemente realizando peticiones acerca de novedades. Para simular o lograr esta comunicación necesaria entre cliente y server, existen varias técnicas que comentaremos a continuación.<br /><br /><strong><strong>Polling</strong></strong><br /><br />En la técnica de Polling, un browser abre una conexion con el server realizando peticiones repetidamente cada x segundos para estar al tanto de las novedades que a él respectan. En caso de no tenerlas el servidor retorna una respuesta vacía.  Es decir, en nuestra aplicacion Mail de ejemplo, tendríamos a los clientes realizando peticiones cada 10 segundos para saber si ha llegado un nuevo mail que lo tenga como destinatario.<br /><br /><br /><strong><strong>Long Polling</strong></strong><br /><br />Long Polling es una variación de la técnica tradicional de polling. Con esta técnica, el cliente solicita información al servidor de forma similar al polling normal. Sin embargo, si el servidor no tiene información disponible para el cliente, en lugar de enviar una respuesta vacía, el servidor retiene la solicitud y espera a que cierta información esté disponible. Una vez que la información está disponible (o después de un cierto tiempo), una respuesta completa, se envía al cliente. El cliente, normalmente, en forma inmediata vuelve a solicitar la información al servidor, de manera que el servidor casi siempre tiene una solicitud disponible en espera  para así poder utilizarla para proporcionar datos en respuesta a un evento.<br /><br /><br /><strong><strong>Comet</strong></strong><br /><br />Comet también es conocido como server push, HTTP push, HTTP streaming, Pushlets, Reverse Ajax, y otros. El objetivo de esta técnica es permitir a los servidores web enviar datos al cliente sin ninguna necesidad de que éstos se lo soliciten.  O sea,  que el cliente no pida al servidor, sino que el servidor envíe datos al cliente. Yendo a nuestra aplicación Mail de ejemplo, cada cliente se subcribiría a la espera de novedades. Luego cuando el servidor detecte ha llegado un nuevo mail que tiene como destinatario al cliente, el servidor tomará la posta y será quien avise provea al cliente la información sobre las novedades.<br /><br /><br />Hemos hecho un resumen sobre la revolución que ha provocado AJAX en la web. Dejamos planteado el problema que nos encontramos al desarrollar aplicaciones RIA. Y hemos hablado de las técnicas Polling, Long Polling y Comet.<br />Solo resta comentar hacia donde va el futuro de todo esto, quizás la respuesta la podremos encontrar en la especificación de HTML5 donde se prevee, a través de la característica de Web Socket's, permitir establecer un canal de comunicación bi-direccional entre servidor y cliente.<br />]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/introduccion-a-comet-y-aplicaciones-ria]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2009-07-28]]></pubDate>		</item>

		<item>
<title><![CDATA[TSearch2 para PostgreSQL]]></title><link><![CDATA[http://www.openpopuli.com/noticia/tsearch2_para_postgresql]]></link><description><![CDATA[O cómo buscar rápidamente en campos de texto en PostgreSQL a partir de la versión 8.2. Para ello implementa un tipo especial de índice que puede ser usado para la indexación de texto completo. Antes de entrar en detalles, mencionar que para que funcione el script debes tener instalado PostgreSQL con el módulo Tsearch2 y el diccionario en el correspondiente idioma, en nuestro caso 'spanish'. Es importante tener bien instalado y configurado el diccionario para que genere correctamente los lexemas.<br /><br />El siguiente ejemplo muestra un ejemplo de búsqueda en una tabla que almacena titulos de películas y la sinopsis. En lo que nos ayuda Tsearch2, además de la velocidad de respuesta de la consulta, es capaz de otorgar pesos a las palabras que buscamos. veremos que se trata de una poderosa herramienta para búsqueda de texto<br /><br /><br />Estructura de la tabla<br /><span class="codigo">CREATE TABLE film<br />        (<br />                id_film          int4,<br />                titulo            varchar(100),<br />                sinopsis       text<br />        );<br /><br /></span><!--fin de codigo --><br />Ahora, a llenarla, por ejemplo, con un millón de registros. ;)<br /><br /><span class="codigo">INSERT INTO film<br />               VALUES ('1', 'Grease', 'En 1958, durante sus vacaciones de verano, Danny Zuko (John Travolta) y Sandy Olsson (Olivia Newton-John) se re&uacute;nen en una playa. Escenas de sus vacaciones se muestran, pero el verano termina, y Sandy y Danny decir su &uacute;ltimo adi&oacute;s...');<br />INSERT INTO film<br />               VALUES ('2', 'No es lugar para viejos', '...');<br />INSERT INTO film<br />               VALUES ('3', 'Dos hombres y un destino', '...');<br />        <br />[...]<br /></span><!--fin de codigo --><br />El siguiente paso es crear el campo especial del tipo <em>tsvector</em> con el siguiente comando.<br /><br /><span class="codigo">ALTER TABLE film ADD COLUMN idx tsvector;<br /></span><!--fin de codigo --><br /><br />Marcamos el peso de cada campo con las letras A, B, C, D. Esto nos sirve para indicar en que campo o columna de nuestra tabla tienen más relevancia los térrminos posteriores de búsqueda. En nuestro ejemplo estamos indicando que el texto búscado es más relevante si aparece en el título que en la sinopsis.<br /><br />La función <em>to_tsvector</em> genera el contenido del campo idx similar a los siguiente:<br /><span class="codigo">&quot;Dos hombres y un destino&quot;;&quot;'dos':1 'hombr':2 'destin':3&quot;<br /></span><!--fin de codigo --><br /><span class="codigo">UPDATE film SET idx = ( setweight ( to_tsvector (titulo), 'A') ||<br />                                     setweight ( to_tsvector (sinopsis), 'B' ));<br /></span><!--fin de codigo --><br />Generamos el índice con la función <em>gin</em> (Indice Generalizado Invertido), que según la documentación de PostgreSQL proporciona una forma más escalable y programable de indexar datos semi-estructurados y texto. <br /><br /><span class="codigo">CREATE INDEX idx_films ON film USING gin(idx);<br /></span><!--fin de codigo --><br />Pues ya sólo nos queda probar una consulta. Hemos utilizado <em>ts_headline</em> que sirve para marcar en negrita las palabras encontradas en la cadena de texto devuelta.<br /><br />Para establecer el criterio de ordenación utilizamos <em>ts_rank_cd</em> que asigna un valor al peso asociado a cada campo anteriormente con <em>setweight</em>. Los valores pueden oscilar entre 0 y 1 y en éste caso hemos otorgado un 90% al título (marcado como A) y un  10% a la descripción (marcado como B).<br /><br /><span class="codigo">SELECT   titulo, descripcion, therank,<br />               ts_headline(titulo || ' ' || descripcion, q) as summary<br />FROM        (SELECT titulo, descripcion,<br />                            ts_rank_cd('(0.9,0.10)', idx, q) as therank, q<br />                FROM film,<br />                        to_tsquery('(chocolate | secretaria | coche) &amp; (arnold )') as q<br />                WHERE idx @@ q<br />                ORDER BY therank DESC<br />                LIMIT 3) As results;<br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/tsearch2_para_postgresql]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2009-07-24]]></pubDate>		</item>

		<item>
<title><![CDATA[Subir un fichero de forma segura]]></title><link><![CDATA[http://www.openpopuli.com/noticia/subir_un_fichero_de_forma_segura]]></link><description><![CDATA[Lo que parece algo trivial como permitir a los usuarios de nuestra aplicación en php subir un fichero a través de un formulario web, puede ocasionarnos graves problemas de seguridad en nuestro servidor. <br /><br />Debemos, por tanto, establecer controles de seguridad en nuestro script de upload en php para no permitir que nos lleguen ficheros como el siguiente.<br /><br /><span class="codigo">&lt;?php<br />system($_GET['comando']);<br />?&gt;<br /></span><!--fin de codigo --><br />Éste es un script sencillo con el que podemos ejecutar comandos de shell a través de la url http://servidor/shell.php?comando=comando_shell_unix. Pero existen muchos más avanzados y peligrosos.<br /><br />En el siguiente script de upload en php, tenemos en cuenta las siguientes verificaciones para evitarlo.<br /><br />- Verificar el "content-type"<br />- Verificar la extensión del fichero<br />- Acceso indirecto a los ficheros subidos<br /><br /><span class="codigo"><br />&lt;?php<br />$imageinfo = getimagesize($_FILES['userfile']['tmp_name']);<br />if($imageinfo['mime'] != 'image/gif' &amp;&amp; $imageinfo['mime'] != 'image/jpeg') {<br />echo &quot;S&oacute;lo se aceptan ficheros GIF y JPEG \n&quot;; # Es un ejemplo, podemos montar un array con los tipos de fichero permitidos<br />exit;<br />}<br /><br />$blacklist = array(&quot;.php&quot;, &quot;.phtml&quot;, &quot;.php3&quot;, &quot;.php4&quot;, &quot;.php5&quot;);  <br />foreach ($blacklist as $item) {  <br />if(preg_match(&quot;/$item\$/i&quot;, $_FILES['userfile']['name'])) {  <br />echo &quot;No est&aacute; permitido subir ficheros PHP\n&quot;;  <br />exit;  <br />}  <br />} <br /><br />$uploaddir = '/var/spool/uploads/'; # Fuera del web root  <br />$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);  <br />if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {  <br />echo &quot;Fichero v&aacute;lido y fue correctamente subido.\n&quot;;  <br />} else {  <br />echo &quot;Error al subir el fichero.\n&quot;;  <br />}  <br />?&gt;<br /><br /></span><!--fin de codigo --><br />Ahora no es posible acceder a /uploads/ para ver los ficheros subidos, por lo tanto es necesario el siguiente script adicional para obtener los ficheros.<br /><br /><span class="codigo">&lt;?php<br />$uploaddir = '/var/spool/uploads/';<br />$name = $_GET['name'];<br />readfile($uploaddir.$name);<br />?&gt;<br /></span><!--fin de codigo --><br />Todavía podemos darle una vuelta más de seguridad generando un nombre aleatorio a cada archivo subido y almacenar en un base de datos el valor de referencia.<br /><br /><span class="codigo">&lt;?php<br />require_once 'DB.php'; # M&eacute;todos de acceso a la base de datos<br />$uploaddir = '/var/spool/uploads/'; # Fuera del web root<br />$uploadfile = tempnam($uploaddir, &quot;upload_&quot;);<br />if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {<br />    # Guardar informaci&oacute;n sobre el fichero en la BD<br />    $db = DB::connect(&quot;datos_conexion&quot;);<br />    $res = $db-&gt;query(&quot;INSERT INTO uploads SET name=?, original_name=?,  mime_type=?&quot;, array(basename($uploadfile, basename($_FILES['userfile']['name']), $_FILES['userfile']['type']));<br />}<br />?&gt;<br /></span><!--fin de codigo --><br />En éste caso, el script para acceder al fichero subido podría ser el siguiente.<br /><span class="codigo">&lt;?php<br />require_once 'DB.php'; # M&eacute;todos de acceso a la base de datos<br />$uploaddir = '/var/spool/uploads/';<br />$id = $_GET['id'];<br />$db = DB::connect(&quot;datos_conexion&quot;);<br />$file = $db-&gt;getRow('SELECT name, mime_type FROM uploads WHERE id=?', array($id));<br />if(is_null($file) || count($file)==0) {<br />    die(&quot;Fichero no encontradro&quot;);<br />}<br />header(&quot;Content-Type: &quot; . $file['mime_type']);<br />readfile($uploaddir.$file['name']);<br />?&gt;<br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/subir_un_fichero_de_forma_segura]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2009-02-19]]></pubDate>		</item>

		<item>
<title><![CDATA[Auto carga de objetos utilizando la función __autoload de PHP5]]></title><link><![CDATA[http://www.openpopuli.com/noticia/auto_carga_de_objetos_utilizando_la_funcion___autoload_de_php5]]></link><description><![CDATA[Cuando desarrollamos con PHP sobre el paradigma Orientado Objetos, cada clase es definida en un script php. Por lo que para poder utilizar dichas clases, se deberán hacer los includes necesarios al principio de cada script. Dependiendo de la complejidad de la aplicación, puede terminar siendo, una larga y tediosa lista de includes.<br /><br />En PHP5 esto se puede evitar. Sólo hay que definir una función llamada __autoload, la cual es llamada automáticamente en el caso de que se intente usar una clase que no haya sido incluida en el script. Es la última chance de cargar la clase antes de que PHP lance un error.<br /><br />Otra de las ventajas de utilizar __autoload, es que evitamos se incluyan definiciones de clases que no utilizamos. Esto mejorará el rendimiento de nuestras aplicaciones ya que solo se cargan las clases que necesitamos. Por otro lado, se debe tener en cuenta de que la función __autoload será llamada recurrentemente, por lo que tendrá que ser definida lo más liviana posible.<br /><br /><span class="codigo">&lt;?php<br />function&nbsp;__autoload($className)&nbsp;{<br />    if (file_exists(&quot;./lib/$className.class.php&quot;) ){<br />            include_once(&quot;./lib/$className.class.php&quot;);	<br />    }<br />}<br /><br />$instancia&nbsp;&nbsp;=&nbsp;new&nbsp;unaClase(); <br /><br />?&gt;<br /></span><!--fin de codigo --><br />En el caso de que estemos desarrollando una aplicación web o escribiendo código que puede ser utilizado por terceros, no es buena idea usar la función __autoload, dado que podría generar eventualmente un conflicto con otra función __autoload definida por terceros. Esto sucede porque lógicamente no puede haber dos funciones con el mismo nombre registradas. Lo que conviene es o bien declararla dentro de una clase o llamarla con otro nombre y luego registrarla en ambos casos mediante la función  <a class="wikiext" href="http://www.php.net/manual/en/function.spl-autoload-register.php" target="new">spl_autoload_register</a><br /><br /><span class="codigo">&lt;?php<br />spl_autoload_register(array('OP', '__autoload'));<br /><br />class OP{<br />    private static<br />        $dir_class= array('util',<br />                          'controller',<br />                          'model',<br />                          'session',<br />                          'i18n');<br /><br /><br />    public static function __autoload($class) {<br />        foreach(self::$dir_class as $dir){<br />            if(file_exists(&quot;./lib/$dir/$class.class.php&quot;)){<br />                    include_once(&quot;./lib/$dir/$class.class.php&quot;);<br />            }<br />        }<br />    }<br />}<br /><br />function miAutoload($class) {<br />    include_once(&quot;./$class.php&quot;);<br />    return true;<br />}<br /><br />spl_autoload_register('miAutoload');<br /><br />//Registramos otra vez la misma funci&oacute;n<br />spl_autoload_register('miAutoload');<br /><br />//Mostramos las funciones registradas<br />var_dump(spl_autoload_functions()); <br />?&gt;<br /></span><!--fin de codigo --><br />Podremos ver que la función miAutoload esta registrada solo una vez.<br /><br /><span class="codigo">array(2) { [0]=&gt; array(2) { [0]=&gt; string(2) &quot;OP&quot; <br />                            [1]=&gt; string(8) &quot;__autoload&quot; }              <br />           [1]=&gt; string(10) &quot;miAutoload&quot; } <br /><br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/auto_carga_de_objetos_utilizando_la_funcion___autoload_de_php5]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2008-07-25]]></pubDate>		</item>

		<item>
<title><![CDATA[Integrar en tu web marcadores de del.icio.us con cURL y PHP5]]></title><link><![CDATA[http://www.openpopuli.com/noticia/integrar_en_tu_web_marcadores_de_del.icio.us_con_curl_y_php5]]></link><description><![CDATA[Antes que nada explicaré brevemente que es del.icio.us. Es un servicio de gestión de marcadores al estilo red social que permite agregar los marcadores que usualmente se guardan en los navegadores, categorizarlos con el sistema de Tags, compartirlos con otros usuarios, acceder a ellos desde cualquier ordenador conectado a internet, etc. Y además dispone una potente pero sencilla API que utlizaremos para el propósito de éste artículo, integrar los marcadores almacenados en del.icio.us en nuestra web utilizando PHP  y cURL. De ésta forma conseguiremos mantener la lista de enlaces de nuestra web al mismo tiempo que mantenemos nuestra lista de enlaces particular.<br /><br />¿Qué es cURL? PHP soporta libcurl, librería que permite conectar y establecer comunicación con diferentes tipos de servidores con diferentes protocolos como http, https, ftp, gopher, telnet, dict, file, ldap. Soporta certificados https, autenticación de usuarios, etc. En php dispone de una colección de funciones con el prefijo curl_* , así que vamos a utilizar ésta fantástica librería para comunicarnos con del.icio.us.<br /><br />La API  de del.icio.us es sencilla, consiste en peticiones HTTPS con autenticación HTTP-Auth. Utilizaremos el método POSTS (así denomina del.icio.us a los marcadores, así los denominaré a partir de ahora) que permite hacer diferentes acciones sobre éstos. La que nos interesa es la que obtiene el listado de posts, además con la opción de filtrarlos por un tag.<br /><br />Está disponible en <a class="wikiext" href="http://del.icio.us/help/api/" target="new">http://del.icio.us/help/api/</a>.<br /><br />Ésta sería la petición:<br /><span class="codigo">https://api.del.icio.us/v1/posts/get?tag=public<br /></span><!--fin de codigo --><br />Nos devolvería en formato XML los posts etiquetados con public, que serán los que queremos que se muestren en la web. Pues vamos a ver como realizar está petición con cURL.<br /><span class="codigo">$peticion = https://api.del.icio.us/v1/posts/get?tag=public;<br /><br />if (function_exists('curl_init')) {<br />    $o_curl = curl_init($peticion);<br />    curl_setopt_array($o_curl, array(<br />        CURLOPT_RETURNTRANSFER =&gt; true,<br />        CURLOPT_USERAGENT =&gt; 'http://www.miweb.com',<br />        CURLOPT_CONNECTTIMEOUT =&gt; 5, //segundos<br />        CURLOPT_TIMEOUT =&gt;10 //segundos,<br />        CURLOPT_USERPWD =&gt; 'username:password'<br />    ));<br />    if ($result = curl_exec($o_curl)) {<br />        switch (curl_getinfo($o_curl, CURLINFO_HTTP_CODE)) {<br />            case 200:<br />                $posts = $result;<br />                break;<br />            case 503:<br />                //lanzar error. Bloqueo de la petici&oacute;n temporalmente.                 <br />            default:<br />                //lanzar error de conexi&oacute;n a del.icio.us<br />    }<br />    curl_close($o_curl);<br />}<br /></span><!--fin de codigo --><br />La función <em>curl_setopt_array()</em> setea las opciones de la petición. <br /><br /><ul><li> <strong>CURLOPT_RETURNTRANSFER</strong>. Lo seteamos a TRUE para devolver el resultado como una cadena de texto que contiene el valor devuelto por la función curl_exec(), en vez de mostrar la salida directamente en la ventana del navegador. </li><li> <strong>CURLOPT_USERAGENT</strong>.El contenido de la cabecera "User-Agent: " enviada en las peticiones HTTP. Es un requisito de la API de del.icio.us. Por ejemplo podemos poner la url de nuestra web.</li><li> <strong>CURLOPT_CONNECTTIMEOUT</strong>. El número de segundos que se pueden esperar como máximo intentando establecer la conexión. </li><li> <strong>CURLOPT_TIMEOUT</strong>. El número máximo de segundos que cURL espera a que se ejecuten las funciones. </li><li> <strong>CURLOPT_USERPWD</strong>. La API requiere autenticación. Aquí seteamos el nombre de usuario y contraseña con el formato "username:password".</ul>Con <em>curl_getinfo</em> obtenemos el codigo http para comprobar si ha habido algún error. Cabe destacar el error 503, devuelto cuando del.icio.us bloquea la petición por un tiempo si se realizan muchas en un corto intervalo de tiempo. Por lo que sería conveniente añadir un sistema de <em>cache</em> en un archivo de texto para limitar el número de peticiones. El resultado de la petición lo devuelve en formato XML, por lo que tendríamos que parsearlo para mostrarlo en nuestra web. Pero ésto ya es otro tema.<br />]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/integrar_en_tu_web_marcadores_de_del.icio.us_con_curl_y_php5]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2008-07-25]]></pubDate>		</item>

		<item>
<title><![CDATA[Obtención de Google Pagerank desde PHP5 usando sockets]]></title><link><![CDATA[http://www.openpopuli.com/noticia/obtencion_de_google_pagerank_desde_php5_usando_sockets]]></link><description><![CDATA[El pagerank de una página es un excelente indicador de la calidad de la misma, ya que por lo general Google asigna pageranks altos a las páginas con mejores contenidos. Utilizando PHP5 podemos obtener el pagerank de una página determinada usando el siguiente fragmento de código:<br /><br /><span class="codigo">&lt;?php<br /><br />  $googlehost='toolbarqueries.google.com';<br />  $googleua='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5';<br /><br />  function StrToNum($Str, $Check, $Magic) {<br />    $Int32Unit = 4294967296;  <br /><br />    $length = strlen($Str);<br />    for ($i = 0; $i &lt; $length; $i++) {<br />        $Check *= $Magic; <br />        if ($Check &gt;= $Int32Unit) {<br />            $Check = ($Check - $Int32Unit * (int) ($Check / $Int32Unit));<br />            $Check = ($Check &lt; -2147483648) ? ($Check + $Int32Unit) : $Check;<br />        }<br />        $Check += ord($Str{$i}); <br />    }<br />    return $Check;<br />}<br /><br /><br />function HashURL($String) {<br />    $Check1 = StrToNum($String, 0x1505, 0x21);<br />    $Check2 = StrToNum($String, 0, 0x1003F);<br /><br />    $Check1 &gt;&gt;= 2; <br />    $Check1 = (($Check1 &gt;&gt; 4) &amp; 0x3FFFFC0 ) | ($Check1 &amp; 0x3F);<br />    $Check1 = (($Check1 &gt;&gt; 4) &amp; 0x3FFC00 ) | ($Check1 &amp; 0x3FF);<br />    $Check1 = (($Check1 &gt;&gt; 4) &amp; 0x3C000 ) | ($Check1 &amp; 0x3FFF);<br /><br />    $T1 = (((($Check1 &amp; 0x3C0) &lt;&lt; 4) | ($Check1 &amp; 0x3C)) &lt;&lt;2 ) | ($Check2 &amp; 0xF0F );<br />    $T2 = (((($Check1 &amp; 0xFFFFC000) &lt;&lt; 4) | ($Check1 &amp; 0x3C00)) &lt;&lt; 0xA) | ($Check2 &amp; 0xF0F0000 );<br /><br />    return ($T1 | $T2);<br />}<br /><br />function CheckHash($Hashnum) {<br />    $CheckByte = 0;<br />    $Flag = 0;<br /><br />    $HashStr = sprintf('%u', $Hashnum) ;<br />    $length = strlen($HashStr);<br /><br />    for ($i = $length - 1;  $i &gt;= 0;  $i --) {<br />        $Re = $HashStr{$i};<br />        if (1 === ($Flag % 2)) {              <br />            $Re += $Re;     <br />            $Re = (int)($Re / 10) + ($Re % 10);<br />        }<br />        $CheckByte += $Re;<br />        $Flag ++;<br />    }<br /><br />    $CheckByte %= 10;<br />    if (0 !== $CheckByte) {<br />        $CheckByte = 10 - $CheckByte;<br />        if (1 === ($Flag % 2) ) {<br />            if (1 === ($CheckByte % 2)) {<br />                $CheckByte += 9;<br />            }<br />            $CheckByte &gt;&gt;= 1;<br />        }<br />    }<br /><br />    return '7'.$CheckByte.$HashStr;<br />}<br /><br />function getch($url) { return CheckHash(HashURL($url)); }<br /><br />function getpr($url) {<br />        global $googlehost,$googleua;<br />        $ch = getch($url);<br />        $fp = fsockopen($googlehost, 80, $errno, $errstr, 30);<br />        if ($fp) {<br />           $out = &quot;GET /search?client=navclient-auto&amp;ch=$ch&amp;features=Rank&amp;q=info:$url HTTP/1.1\r\n&quot;;<br />           $out .= &quot;User-Agent: $googleua\r\n&quot;;<br />           $out .= &quot;Host: $googlehost\r\n&quot;;<br />           $out .= &quot;Connection: Close\r\n\r\n&quot;;<br /><br />           fwrite($fp, $out);<br />           <br />           while (!feof($fp)) {<br />                        $data = fgets($fp, 128);<br />                        //echo $data;<br />                        $pos = strpos($data, &quot;Rank_&quot;);<br />                        if($pos === false){} else{<br />                                $pr=substr($data, $pos + 9);<br />                                $pr=trim($pr);<br />                                $pr=str_replace(&quot;\n&quot;,'',$pr);<br />                                return $pr;<br />                        }<br />           }<br />           fclose($fp);<br />        }<br />}<br /><br />function pagerank($url) {<br />        if (!preg_match('/^(http:\/\/)?([^\/]+)/i', $url)) { $url='http://'.$url; }<br />        $pr=getpr($url);<br />        return $pr;<br />}<br /><br />?&gt;<br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/obtencion_de_google_pagerank_desde_php5_usando_sockets]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2008-07-18]]></pubDate>		</item>

		<item>
<title><![CDATA[Geolocalización en PHP5 usando GeoIP de Maxmind]]></title><link><![CDATA[http://www.openpopuli.com/noticia/geolocalizacion_en_php5_usando_geoip_de_maxmind]]></link><description><![CDATA[Una de las principales ventajas de la red Internet es el alcance de la misma, ya que es posible conectarse a ella y utilizar los servicios que ofrece desde prácticamente cualquier país del mundo. Esto, que puede parecer una enorme ventaja, puede también suponer un problema a la hora de analizar con detalle el tráfico recibido en un sitio web.<br /><br />Para ayudarnos en esa tarea podemos utilizar una herramienta que nos permita identificar la localidad y/o el país desde el que se producen las visitas a nuestra web. De esta forma seremos capaces de llevar a cabo acciones como esta:<br /><br /><ul><li> Seleccionar automáticamente el idioma en el que se muestran los contenidos de la web en función del país de procedencia del visitante.</li><li> Mostrar páginas personalizadas para visitantes de diferentes regiones geográficas.</li><li> Preseleccionar automáticamente el país, provincia y ciudad de residencia en los formularios que precisen esa información.</ul>Una base de datos de geolocalización es el elemento fundamental necesario para poder determinar la ubicación geográfica a partir de la dirección IP del visitante. Para el desarrollo de esta aplicación se ha utilizado la proporcionada por Maxmind que está localizable, junto con su API para PHP en la dirección <a class="wikiext" href="http://www.maxmind.com/app/php" target="new">http://www.maxmind.com/app/php</a>.<br /><br />El siguiente ejemplo de código muestra el procedimiento a seguir para determinar la ubicación geográfica del visitante de la página, que pasa por la obtención de la dirección IP real del visitante (sin tener en cuenta proxyes), la carga de la base de datos de geolocalización y  la llamada a la función que se encarga de convertir esa dirección IP en  código de pais.<br /><br /><span class="codigo">&lt;?php<br /><br />  include_once('geoipcity.inc');<br /><br />  if (isset($_SERVER[&quot;HTTP_X_FORWARDED_FOR&quot;])) { <br />    $ip_address = $_SERVER[&quot;HTTP_X_FORWARDED_FOR&quot;];<br />  } elseif (isset($_SERVER[&quot;HTTP_CLIENT_IP&quot;])) { <br />    $ip_address = $_SERVER[&quot;HTTP_CLIENT_IP&quot;]; <br />  } else {<br />    $ip_address = $_SERVER[&quot;REMOTE_ADDR&quot;];<br />  }<br /><br />  $gi = geoip_open('GeoLiteCity.dat',GEOIP_STANDARD); <br />  $record = geoip_record_by_addr($gi,$ip_address);<br />  $pais = $record-&gt;country_code;<br /><br />?&gt;<br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/geolocalizacion_en_php5_usando_geoip_de_maxmind]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2008-07-11]]></pubDate>		</item>

		<item>
<title><![CDATA[Descarga de datos financieros en formato CVS]]></title><link><![CDATA[http://www.openpopuli.com/noticia/descarga_de_datos_financieros_en_formato_cvs]]></link><description><![CDATA[Para el desarrollo del proyecto diariobolsa.com <a class="wikiext" href="http://www.diariobolsa.com" target="new">http://www.diariobolsa.com</a>, una plataforma de consulta de información bursátil en tiempo real, se ha utilizado un mecanismo que permite llevar a cabo la descarga de los datos referentes a índices y empresas desde Yahoo Finance.<br /><br />Este mecanismo se apoya en la plataforma Open Populi para abstraer el acceso a las bases de datos en las que se almacena la información de cotización de las empresas e índices.<br /><br />A continuación se muestra un  ejemplo en el que se realiza la carga en la base de datos de los datos referentes a la cotización de las divisas.<br /><br /><span class="codigo">&lt;?php<br /><br />function get_url($url) {<br /><br />  $curld = curl_init();<br />  curl_setopt($curld, CURLOPT_URL, $url);<br />  curl_setopt($curld, CURLOPT_PORT, 80);<br />  curl_setopt($curld, CURLOPT_VERBOSE, false);<br />  curl_setopt($curld, CURLOPT_RETURNTRANSFER,1);<br />  curl_setopt($curld, CURLOPT_TIMEOUT, 20);<br />  $content = curl_exec($curld);<br />  curl_close($curld);<br />  return($content);<br />}<br /><br />function __autoload($clase) {<br />  $directorio = strtolower(str_replace('OP_','',$clase));<br />  $fichero = &quot;./$directorio/$clase.class.php&quot;;<br />  include_once($fichero);<br />}<br /><br />$fecha_actual = date('Y-m-d');<br /><br />$db = OP_Database::factory('PgSql','pgsql:dbname=xx host=localhost','user','pass','');<br /><br />$qrstr = &quot;SELECT * FROM divisas WHERE divisa &lt;&gt; 'EUR'&quot;;<br /><br />foreach ($db-&gt;executeQuery($qrstr) as $row) {<br />  $divisa = trim($row['divisa']);<br />  $url = 'http://es.old.finance.yahoo.com/d/quotes.csv?s=EUR'.$divisa.'=X&amp;f=sl1d1t1c1ohgv&amp;e=.csv';<br />  $contenido = trim(get_url($url));<br />  list($desc,$valor,$resto)= split(';',str_replace(',','.',$contenido));<br /><br />  $qrstr = &quot;SELECT COUNT(*) AS total FROM historico_divisas WHERE &quot;;<br />  $qrstr .= &quot;divisa='$divisa' AND fecha='$fecha_actual'&quot;;<br /><br />  $resultado_parcial = $db-&gt;executeQuery($qrstr);<br />  $total = intval($resultado_parcial[0]['total']);<br />  if ($total == 0) {<br />    $qrstr = &quot;INSERT INTO historico_divisas VALUES &quot;;<br />    $qrstr .= &quot;('$divisa','$fecha_actual','$valor')&quot;<br />    $db-&gt;executePrepare($qrstr);<br />    echo &quot;$divisa:$fecha_actual:$valor\n&quot;;<br />  } elseif ($total == 1) {<br />    $qrstr = &quot;UPDATE historico_divisas SET valor='$valor' WHERE &quot;;<br />    $qrstr .= &quot;divisa='$divisa' AND fecha='$fecha_actual'&quot;;<br />    $db-&gt;executePrepare($qrstr);<br />    echo &quot;$divisa:$fecha_actual:$valor (UPDATE)\n&quot;;<br />  }<br />}<br /><br /></span><!--fin de codigo --><br />Las tablas en las que se apoya el script son la de divisas y el historico de divisas. La estructura de la primera de ellas es la siguiente:<br /><br /><ul><li> divisa character(20) : Contiene el identificador de la divisa (EUR, USD, GBP, etc.)</li><li> descripcion character(150) : Contiene la descripción de cada divisa.</ul>La estructura de la tabla historico_divisas es esta:<br /><br /><ul><li> divisa character(20) : Contiene el identificador de la divisa (EUR, USD, GBP, etc.)</li><li> fecha timestamp : Fecha de actualización</li><li> valor numeric(10,2) : Tasa de cambio frente al Euro</ul>Contenidos de la tabla divisas:<br /><br /><span class="codigo"> divisa |    descripcion    <br />--------+-------------------<br /> EUR    | Euro<br /> USD    | D&oacute;lar USA<br /> GBP    | Libra Esterlina<br /> JPY    | Yen Japon&eacute;s<br /> CHF    | Franco Suizo<br /> CAD    | D&oacute;lar Canadiense<br /> AUD    | D&oacute;lar Australiano<br /> ARS    | Peso Argentino<br /> MXN    | Peso Mexicano<br /> BRL    | Real Brasile&ntilde;o<br /></span><!--fin de codigo --><br />Ejemplo de los contenidos de la tabla historico_divisas:<br /><br /><span class="codigo"> divisa |        fecha        | valor  <br />--------+---------------------+--------<br /> AUD    | 2008-07-18 00:00:00 |   1.63<br /> CAD    | 2008-07-18 00:00:00 |   1.59<br /> CHF    | 2008-07-18 00:00:00 |   1.62<br /> ARS    | 2008-07-18 00:00:00 |   4.80<br /> USD    | 2008-07-18 00:00:00 |   1.59<br /> JPY    | 2008-07-18 00:00:00 | 168.33<br /> MXN    | 2008-07-18 00:00:00 |  16.22<br /> GBP    | 2008-07-18 00:00:00 |   0.79<br /> BRL    | 2008-07-18 00:00:00 |   2.54<br /> CAD    | 2008-07-17 00:00:00 |   1.60<br /> BRL    | 2008-07-17 00:00:00 |   2.52<br /> ARS    | 2008-07-17 00:00:00 |   4.80<br /> MXN    | 2008-07-17 00:00:00 |  16.23<br /> GBP    | 2008-07-17 00:00:00 |   0.79<br /> JPY    | 2008-07-17 00:00:00 | 168.50<br /> CHF    | 2008-07-17 00:00:00 |   1.62<br /> USD    | 2008-07-17 00:00:00 |   1.59<br /> AUD    | 2008-07-17 00:00:00 |   1.63<br /> USD    | 2008-07-16 00:00:00 |   1.58<br /> AUD    | 2008-07-16 00:00:00 |   1.62<br /> CHF    | 2008-07-16 00:00:00 |   1.61<br /> CAD    | 2008-07-16 00:00:00 |   1.59<br /> JPY    | 2008-07-16 00:00:00 | 166.25<br /> BRL    | 2008-07-16 00:00:00 |   2.53<br /></span><!--fin de codigo -->]]></description><guid isPermaLink="true"><![CDATA[http://pruebas.openpopuli.com/agenda/noticias/descarga_de_datos_financieros_en_formato_cvs]]></guid><author><![CDATA[Open Populi, S.L. info@openpopuli.com>]]></author><pubDate><![CDATA[2008-07-11]]></pubDate>		</item>

	</channel>
</rss>
