viernes, 11 de noviembre de 2011

MySQL: Devolver los resultados según un orden establecido

Básicamente, la mayoría de consultas que hacemos a la base de datos constan de tres aspectos: de dónde queremos obtener los datos, con qué criterios queremos seleccionar los datos y en qué orden los necesitamos. Nos vamos a centrar en este último aspecto.

Normalmente nos basta con ordenar los resultados por orden numérico, antigüedad o alfabéticamente. Pero, a veces, necesitaremos que se devuelvan en un orden predeterminado.

Para ello, podemos echar mano de la función de MySQL FIND_IN_SET(). Dicha función devuelve la posición de una cadena dentro de una lista de elementos separados por comas. Por ejemplo:

FIND_IN_SET('jueves', 'lunes,martes,miércoles,jueves,viernes,sábado,domingo') => 4

Si la cadena no se encuentra, la función devuelve 0.

Es importante, si no os queréis romper la cabeza preguntándoos por qué no funciona, que no haya espacios en blanco entre las comas.

Fuente: FIND_IN_SET() :: MySQL Function of the Day

jueves, 14 de julio de 2011

Parsear ficheros XML grandes

Cuando tenemos que integrarnos con servicios de terceros, lo más normal es que intercambiemos la información en formato XML o JSON (esto se está poniendo de moda últimamente). Con PHP4, parsear XML es poco menos que un suplicio, pero con PHP5 la cosa cambia.
Disponemos de la extensión SimpleXML que, de forma muy sencilla, nos permite indicar un XML de entrada y lo tendremos cargado en un bonito y accesible objeto.
Sin embargo, esta solución no es viable cuando vamos a procesar XML de gran tamaño, ya que estaríamos cargando toda la información en memoria. Normalmente no será necesario, ya que lo que se suele hacer es recorrer el XML buscando alguna información concreta, o bien convertirlo a otro formato o cargarlo en nuestra base de datos.
Para este tipo de operaciones es mejor usar la extensión XMLReader. Su funcionamiento es parecido al de un cursor que va recorriendo el XML. Por tanto, al no parsearlo entero, el consumo de memoria es mucho menor.
Vistas estas dos alternativas (hay algunas más), a la hora de procesar un XML entero una buena solución puede ser combinar ambos métodos. Es decir, usar XMLReader para ir recorriendo los nodos e ir cargando cada uno de ellos con SimpleXML, para que el manejo de la información contenida sea trivial.
Sería algo así:
Fuente: http://stackoverflow.com/questions/1835177/how-to-use-xmlreader-in-php

viernes, 8 de julio de 2011

Códigos de países, provincias y ciudades

Buscando información sobre listados de localidades me he encontrado este post de Carme Pla en el que parece estar trabajando en algo parecido y comparte su experiencia.
Los ficheros que encuentro más interesantes son:
Pero, sin duda, el gran descubrimento ha sido la web GeoNames, en la que podemos encontrar listados de prácticamente todas las localidades del mundo, y con licencia Creative Commons. Desde luego un gran trabajo que se merece una donación.
Sobre todo, es importante usar códigos más o menos estandarizados, porque siempre nos será más fácil integrarnos con servicios que empleen la misma estandarización y nos ahorraremos pasos de traducción de identificadores. Si no fuera así, mi recomendación es usar siempre un sistema de identificadores interno, que se ajuste a nuestro modelo de datos y que no dependa de ningún proveedor (porque luego lo cambias por otro y te quedas con el "culo al aire" y mucho código que cambiar).

jueves, 16 de junio de 2011

Cómo integrar reCAPTCHA en Wordpress

Últimamente estamos recibiendo mucho spam en los blogs de la plataforma. Y eso que tenemos instalado un plugin, WP-SpamFree, que parece que no está realizando del todo bien su trabajo.

Así que como primera medida preventiva, vamos a introducir un captcha en el formulario de envío de comentarios. La más popular de estas herramientas, adquirida y auspiciada hace tiempo por Google, es reCAPTCHA.

Supuestamente hay disponible un plugin para Wordpress. Y digo supuestamente porque el plugin parece haberse roto en las versiones 3.x de WP. Así que nuestro gozo en un pozo.

Tenemos, pues, tres opciones:

  • Buscar otro plugin que permita añadir captchas a los formularios. La verdad es que no nos ha convencido ninguno.
  • Arreglar el plugin de reCAPTCHA. Como contribución a la comunidad estaría genial, pero no tenemos los conocimientos ni la experiencia suficientes como para afrontar la tarea en un corto periodo de tiempo.
  • Modificar nosotros el código de nuestro tema de Wordpress para añadir reCAPTCHA.

Al final hemos optado por la última opción. Una vez efectuadas las investigaciones pertinentes, no ha resultado demasiado complicado.

La implementación en el formulario es muy sencilla, siguiendo las instrucciones que podemos encontrar en su web: http://code.google.com/apis/recaptcha/docs/display.html.

Ahora sólo queda comprobar, a la hora de procesar el alta de comentarios, que el captcha introducido es correcto. Para ello, nuevamente tenemos dos opciones: escribir un plugin al uso o añadir código en la librería personalizada functions.php. Optamos una vez más por la segunda opción.

Lo que hemos hecho ha sido escribir una función que comprueba el captcha, a partir de las instrucciones que encontramos en la documentación: http://code.google.com/apis/recaptcha/docs/php.html. Y, haciendo uso de los filtros de Wordpress (tremendamente útiles para poder personalizar su comportamiento sin tocar el "core"), asignamos la función recién creada al filtro "pre_comment_approved", que se ejecuta antes de verificar si el comentario debe o no aprobarse.


// Custom reCAPTCHA "plugin"
add_filter('pre_comment_approved', 'recaptcha_solved_comment');
function recaptcha_solved_comment($approved)
{
require_once(dirname(__FILE__) . '/lib/recaptcha/recaptchalib.php');

$privatekey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX';

$resp = recaptcha_check_answer($privatekey, $_SERVER['REMOTE_ADDR'], $_POST['recaptcha_challenge_field'], $_POST['recaptcha_response_field']);

if (!$resp->is_valid)
{
$approved = 'spam';
wp_die( __('Debes introducir el código de verificación correcto.') );
}
return $approved;
}

lunes, 25 de abril de 2011

Almacenamiento Local HTML5

Una de las (pocas) cosas que se echa de menos al desarrollar aplicaciones para la web es la persistencia. En esencia, el protocolo HTML es unidireccional (es decir, el servidor, a partir de una petición del navegador, genera una respuesta/página) y no guarda información de estado (es decir, no hay un "recuerdo" entre una página y la siguiente).

Esa es la teoría. En la práctica, con los años se han ido desarrollando mecanismos que permiten almacenar cierta información de manera persistente. En el lado del navegador (las cookies) y en el lado del servidor (las sesiones). Pero no son la solución real al problema de la persistencia. Las cookies tienen un límite de tamaño de 4KB y, además, se envían con cada petición que se hace al servidor, así que no es muy recomendable usarlas para almacenar demasiados datos. Por otro lado, el manejo de sesiones puede complicarse cuando tenemos múltiples frontales, ya que hay que habilitar algún mecanismo para que compartan dicha información.

Con las nuevas características de almacenamiento local de los navegadores modernos, eliminamos todos estos problemas de un plumazo.

En resumen:
  • Disponemos de 5MB de almacenamiento local por dominio, en el que podremos guardar pares clave-valor. Tanto la clave como el valor son cadenas de texto (así que cuidado a la hora de almacenar otros tipos de datos, ya que tendremos que realizar las conversiones adecuadas).
  • El almacenamiento es persistente, incluso al cerrar el navegador o cuando el navegador se cuelga o se cierra debido a un error.
  • Los datos no se envían al servidor bajo ningún concepto (salvo que el usuario los envíe).
  • Disponemos de getters y setters para cada clave, así como métodos para borrar el valor de una clave, consultar cuántos elementos tenemos almacenados o borrar todo el almacenamiento.
  • Cada vez que se hace una operación sobre el almacenamiento local y dicha operación suponga un cambio (entendiendo como que una operación que escribe en una clave el mismo valor que ya tenía, no lo produce) dispara un evento, que podemos escuchar y actuar en consecuencia.
  • Podemos utilizar el almacenamiento local para comunicar varias ventanas del navegador (en las que se ha abierto la misma aplicación web).
Hay una versión de almacenamiento local, llamada Almacenamiento de Sessión (session storage) que funciona exactamente igual salvo por el hecho de que, al terminar la sesión (por ejemplo, cerrando el navegador), todos los datos se pierden.

Como siempre, deberíamos detectar si el navegador usado dispone de estas características antes de usarlas.

Enlaces interesantes:

Web. Detección de características avanzadas

Últimamente parece que las cosas se mueven a buen ritmo en el mundo del HTML. Sin embargo, los avances en las recomendaciones para HTML5 (y CSS3) hacen que algunas características interesantes estén disponibles en unas versiones de los navegadores y no en otras. Lamentablemente, no todo el mundo puede tener su navegador (o navegadores) actualizados a la última. O bien, que usan versiones obsoletas del navegador (me refiero a la gente que anda todavía con IE6, cuando incluso Microsoft se está poniendo las pilas con las últimas versiones de su navegador.

Para todos estos casos, viene bien tener algún método rápido y más o menos estándar de saber qué características etnemos disponibles.

Una librería muy interesante que nos permite conseguir este propósito es Modernizr.

Tenemos que tener en cuenta que Modernizr únicamente detecta qué características están disponibles; no ofrece una implementación alternativa a las mismas para aquellos navegadores que no las soporten. Para eso ya nos tenemos que buscar las mañas por otro lado.

Geolocalización (W3C API)

Uno de los temas que están "de moda" desde la explosión de uso de Internet en los móviles ha sido la geolocalización.

La distribución de direcciones IP no es como la de los números de teléfono, en los que mirando el antiguo prefijo (las 2 ó 3 primeras cifras) o incluso las siguientes, nos podemos hacer una idea de dónde está instalada la línea. La asignación de direcciones IP es bastante más arbitraria. No obstante, existen bases de datos que pretenden localizar un dispositivo a partir de su dirección IP (dependiendo de los países la localización será más o menos exacta).

Con los móviles la cosa cambia. Se puede conocer su posición a partir de tres elementos:

  • La red WiFi a la que esté conectado.
  • La celda móvil a la que esté conectado.
  • Su GPS interno.

Dependiendo de los métodos usados la precisión será mayor o menor.

En cualquier caso, la API de geolocalización enmascara todos estos procesos y nos da acceso asíncrono a la información de geolocalización del dispositivo a través del navegador. Esta característica no sólo está en los navegadores móviles, sino también en los de "sobremesa" (al menos en Chrome, Firefox y Opera).

La API para obtener la información consiste básicamente en un objeto, navigator.geolocation, que provee de un método, navigator.geolocation.getCurrentPosition(), que recibe como parámetros dos funciones callback: la primera de ellas para manejar el éxito de la geolocalización, y la segunda para manejo de errores.

La función de éxito recibirá un objeto position que tiene una propiedad coords con valores interesantes (creo que los nombres son autoexplicativos):

  • latitude
  • longitude
  • altitude
  • accuracy
  • altitudeAccuracy
  • heading
  • speed

A partir de dichos valores, es sencillo representar nuestra posición en un mapa, usando la API Javascript de Google Maps. Se pueden ver un par de ejemplos en Labs:


En el ejemplo, se pretende usar un timeout para actualizar la posición, pero leyendo más a fondo la documentación hay un método watchPosition() que permite hacer lo propio. También existe el método clearWatch() que se emplea para concluir el seguimiento.

Enlaces relacionados:

martes, 19 de abril de 2011

Cómo instalar Nginx y PHP-FPM en Ubuntu 10.10

Voy a hacer una breve anotación a este respecto, ya que es un tema que he tenido que buscar un par de veces.

En realidad, se trata de una tarea que, a día de hoy, es sencilla. Hace meses, no había repositorios oficiales para PHP-FPM, y había que andar compilándolo o bien usar repositorios alternativos. No obstante, desde la versión 10.10 de Ubuntu, PHP-FPM se encuentra en los repositorios oficiales. Sólo hay que hace algún pequeño ajuste en la configuración, que veremos a continuación.

En nuestros proyectos ya llevamos tiempo confiando en la dupla Nginx + PHP-FPM, con buenos resultados. Apache(2) pronto será cosa del pasado.

1. Instalamos Nginx:

apt-get install nginx


No será la última versión, pero nos valdrá. Si queremos la última (Nginx acaba de lanzar su versión 1.0) debemos instalarla desde la web oficial.

2. Instalamos PHP-FPM:

apt-get install php-fpm


PHP-FPM se ejecuta como servicio (demonio) escuchando por defecto el puerto 9000.

3. Configuramos Nginx para que envíe las peticiones a PHP-FPM. Ésta es la parte más "complicada" del invento. En el fichero /etc/nginx/nginx.conf descomentamos las líneas correspondientes:

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www$fastcgi_script_name;
    include fastcgi_params;
}



Donde /var/www es el directorio raíz del servidor web, y tenemos que tener cuidado en separar las palabras include fastcgi_params, que en el fichero de configuración por defecto vienen juntas por error.

Otro cambio que puede ser útil, si queremos que el servidor web responda a varios dominios sin redirigir al primero de ellos (que es el comportamiento por defecto), consiste en añadir a la configuración el parámetro server_name_in_redirect off.

4. Reiniciamos NGinx:

/etc/init.d/nginx restart



5. Añadimos extensiones a PHP. Aquí, a gusto del cosumidor. Por ejemplo:

apt-get install php5-mysql php5-curl php5-gd php5-idn php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming php5-ps php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl php5-json



Si añadimos extensiones, debemos reiniciar PHP-FPM:

/etc/init.d/php-fpm restart



Y ya está. Si creamos un fichero info.php con el código:

<?php
phpinfo();
?>



Y accedemos desde nuestro navegador, deberíamos ver las opciones de PHP que hemos instalado.

Fuente principal: http://www.howtoforge.com/installing-nginx-with-php5-and-php-fpm-and-mysql-support-on-ubuntu-10.10.

jueves, 14 de abril de 2011

@font-face

Cuando hicimos el último rediseño de la web, en noviembre de 2010, una de sus señas de identidad estética fue el uso de la fuente American Typewriter en algunas zonas, principalmente títulos de secciones y de módulos.


Dicha fuente no es una fuente estándar. Por tanto, para implementarla, la empresa encargada de ayudarnos con el rediseño nos aconsejó el uso de la librería Cufon. Cufon es una librería Javascript que se encarga de, una vez cargado el HTML, sustituir las fuentes por las elegidas, empleando componentes canvas y VML.


Así lo hicimos, porque andábamos liados con mil cosas. El resultado quedó aparente, pero no estábamos del todo satisfechos.


Lo que ha encendido la mecha ha sido ver que Cufon no funcionaba con IE9. Bastaba con actualizarlo para solucionar el problema, pero empezamos a buscar alternativas, y fue cuando rescatamos del olvido @font-face.


Siguiendo un tutorial de los muchos que podemos encontrar, hemos implementado @font-face en nuestra web. Se trata de una característica de CSS, propuesta en la versión 2, y que soportan la gran mayoría de los navegadores. Básicamente, definimos cada familia de fuentes que queramos usar, indicando dónde están los ficheros para obtenerlas. Cada navegador utiliza un formato diferente. Una vez definidas las familias, pueden emplearse en la hoja de estilos como si fueran fuentes estándar.


El único inconveniente que hemos encontrado es que las fuentes deben estar alojadas en el mismo subdominio que la web, salvo que empleemos una cabecera especial para servirla desde nuestros servidores de estáticos. De momento hemos optado por que sean los frontales quienes las sirvan.


Ahora las fuentes especiales se muestran más rápidamente y sin necesidad de Javascript, por lo que conseguimos una librería menos que descargar al acceder a la página.

martes, 12 de abril de 2011

Implementando un hotfolder en Linux

Una de las ventajas de la consola de UNIX, en general, y de Linux, en particular, es la facilidad de procesar por lotes multitud de ficheros. Eso está bien cuando tenemos todos los ficheros disponibles para ser procesados. Pero, ¿qué pasa cuando queremos montar un "hotfolder", es decir, un directorio donde los usuarios irán dejando sus ficheros para que vayan siendo procesados.


El reto principal consiste en saber cuándo el fichero se ha terminado de enviar, para pasar a procesarlo. Si lo enviáramos mediante un sistema construido a medida, se podría monitorizar el envío y generar un mensaje al finalizar, o implementar cualquier otro mecanismo.


En nuestro caso, queremos que los usuarios suban los ficheros por FTP, con lo cual no podemos añadir ningún mecanismo extra de control a la subida, teniendo que monitorizar el directorio por nuestros propios medios.


Buscando en Internet, hemos encontrados dos métodos que pueden ser útiles para lo que queremos conseguir:


Chequear el tamaño del fichero o si está abierto por algún proceso [1]. Podemos usar el comando fuser. Si el fichero no está en uso, no devolverá salida alguna, mientras que si lo está, nos dirá qué proceso lo está usando. En nuestro caso, el fichero estaría abierto por el servidor de FTP hasta que se complete la transferencia.


Monitorizar el uso de un fichero [2]. Mediante el uso de una utilidad como inotifywait, incluida en el paquete inotify-tools, podemos monitorizar, por ejemplo, cuándo se cierra un fichero en un directorio dado (también se puede hacer recursivamente) y, en el momento en que se produzca el evento, lanzar la ejecución de un proceso (en nuestro caso, el que procesa el fichero).


[1] http://www.unix.com/shell-programming-scripting/153036-check-if-file-finished-copy.html


[2] http://linux.die.net/man/1/inotifywait

jueves, 31 de marzo de 2011

Edición de iconos

Probablemente, la imagen más visualizada de un sitio web no es otra que el icono que la representa, el famoso "favicon".


Y no sé si alguna vez os habréis visto en la tesitura de crear un icono. Curiosamente, el formato .ico no suele estar soportado por muchos de los programas de edición gráfica más habituales.


De la mano de Microsoft, ya que hacen un uso algo más extensivo de los iconos en la última versión de su navegador Internet Explorer, llegamos a X-Icon Editor. Se trata de una herramienta web, creada en HTML5 (basada en el elemento canvas), que nos permite generar iconos, bien desde cero, bien a partir de una imagen que podemos cargar. Los iconos creados pueden ser de hasta 64x64 píxeles.

miércoles, 30 de marzo de 2011

jWYSIWYG - Editor HTML en Javascript

De toda la vida, no sé si por costumbre o por qué razón, hemos usado TinyMCE como editor HTML en Javascript para todos los campos de formulario en los que es necesario insertar código HTML.


El caso es que últimamente se nos hace pesado y complicado de mantener. Necesitamos algo más ligero y flexible. Seguro que es por torpeza nuestra.


Investigando en StackOverflow (una de nuestras páginas de cabecera), llegamos a jWYSIWYG.


Las premisas de la búsqueda fueron que el editor fuera fácilmente configurable y basado en jQuery. De esa forma, con la experiencia que estamos cogiendo últimamente con este framework, nos sería más fácil su integración y manejo.


Una de las cosas que pretendíamos conseguir, y que hemos conseguido con jWYSIWYG, era cargar sólo una instancia del editor en el momento en que hacemos clic en un textarea, y descargarlo cuando terminamos la edición. También queríamos tener un editor sencillito con los 3 ó 4 botones básicos (negrita, cursiva, etc.). Todo eso seguro que se puede hacer con TinyMCE, y con las decenas de soluciones semejantes que hay, tanto libres como de pago. Pero con jWYSIWYG lo hemos logrado en apenas un rato de investigación y cacharreo.

viernes, 25 de marzo de 2011

JSFiddle - Desarrollo sobre la marcha

A la hora de desarrollar, muchas veces tenemos la necesidad de probar cosas sobre la marcha, especialmente cuando hacemos desarrollos cliente (HTML, CSS, Javascript) sobre temas que no dominamos. En esos casos, tener un mecanismo de pruebas ágil nos puede ahorrar mucho tiempo.


Pero siempre tendremos que editar, publicar, y abrir en el navegador. También tendremos que bajar e instalar recursos externos (CSS, JS) cuando queramos probarlos, aun cuando no nos vayamos a quedar con ellos al final.


JSFiddle es una herramienta de prototipado que permite probar código HTML, CSS y JS en la misma ventana del navegador, sin necesidad de todo lo anterior.


Tenemos tres ventanas en las que podremos editar HTML, CSS y JS. Podremos cargar recursos externos, así como algunos de los frameworks JS más usados (Mootools, jQuery, Prototype...). Además, aporta extras como validar nuestro JS o limpiar el código que hayamos introducido.


Por último, si nos registramos, podremos almacenar nuestros "fiddles" para usarlos en otro momento.

jueves, 17 de marzo de 2011

Vídeos para Flash e iPhone

Andaba buscando la forma de que los vídeos de 20minutos.tv se puedan reproducir también en el iPhone, aunque sea a pantalla completa, y he encontrado esta página: http://code.google.com/p/swfobject/wiki/iphone_mp4. Ahí exponen una forma de codificar el tag de vídeo que funciona en todos los navegadores y también en el teléfono, sin llegar a usar los tags de HTML5 (ya que usamos un player Flash personalizado para servir el vídeo en streaming pudiendo ver capturas al hacer seeking y también para poder servir publicidad).


El código, adaptado a nuestras necesidades, sería algo así:




<object id="videoContent" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="544" height="330">
<param name="movie" value="http://estaticos.20minutos.es/player/player.swf" />
<param name="flashvars" value="status=200&dynconf=http://www.20minutos.tv/videoconfig/4340dsm330XX/d/&still=http://estaticos.20minutos.es/20minutostv/img/abcd7.jpg" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="http://estaticos.20minutos.es/player/player.swf" width="544" height="330">
<param name="flashvars" value="status=200&dynconf=http://www.20minutos.tv/videoconfig/4340dsm330XX/d/&still=http://estaticos.20minutos.es/20minutostv/img/abcd7.jpg" />
<object type="video/mp4" data="http://estaticos.20minutos.es/20minutostv/img/abcd7.jpg" width="544" height="330">
<param name="controller" value="false" />
<param name="src" value="http://estaticos.20minutos.es/20minutostv/img/abcd7.jpg" />
<param name="href" value="http://download.cdn.com/4340dsm330XX.mp4" />
<param name="target" value="myself" />
<!--<![endif]-->
<img src="http://estaticos.20minutos.es/20minutostv/img/abcd7.jpg" alt="" />
<!--[if !IE]>-->
</object>
</object>
<!--<![endif]-->
</object>


El object de tipo video/mp4 es el que hace el "milagro" de que el vídeo se pueda ver en el iPhone. Eso y que está codificado con un codec que es compatible con el terminal.

jueves, 3 de marzo de 2011

Procesando ficheros

Ayer me surgió la necesidad de procesar un montón de ficheros, distribuidos por diferentes directorios. En concreto, tenía que generar un fichero JPEG a partir de un PDF.


Dividimos la tarea en dos partes: por un lado, extraer la lista de ficheros que queremos procesar. Por el otro, el comando que los procesa en sí.


El resultado sería algo como esto:



find . -type f -name "*.pdf" | while read i ; do convert -geometry 100x135 -quality 80 $i `dirname $i`/`basename $i .pdf`.jpg; done

La lista de ficheros la generamos a partir de un find: find . -type f -name "*.pdf" (suponiendo que estemos ubicados en el directorio a partir del que vamos a buscar los ficheros para procesar.


El bucle de procesado sería: while read i ; do COMANDO_PROCESADO; done.


En nuestro caso, el comando de procesado es la herramienta convert: convert -geometry 100x135 -quality 80 $i `dirname $i`/`basename $i .pdf`.jpg. Lo que hace es generar una miniatura en JPEG de 100x135px y 80 de calidad alojada en el mismo directorio que el PDF original.


Ahora imaginemos que lo que necesitamos es modificar la ruta, no el nombre del fichero. Lo podemos lograr usando sed:



find . -type f -name "*.jpeg" | while read i ; do echo convert -geometry 74x74 -quality 80 $i `echo $i | sed 's/RUTA1/RUTA2/g'`; done

En el ejemplo, sustituimos RUTA1 por RUTA2 en el nombre del fichero destino.

martes, 15 de febrero de 2011

New York Times y el Mundial 2010

Me gustaría compartir una entrada del blog de desarrolladores del NYT en la que hablan de cómo afrontaron las retransmisiones en directo de los partidos del Mundial:

http://open.blogs.nytimes.com/2010/07/13/behind-the-scenes-of-a-live-world-cup/

Se pueden leer algunas ideas interesantes.

KSES – Filtrado sencillo de etiquetas HTML

Finalizando el proyecto de migración de los blogs a WordPress, ya en la fase de prueba de funcionalidades, me di cuenta de que, al dar de alta una entrada, WordPress permite por defecto muy pocas etiquetas HTML. Así que tenía la necesidad de permitir al menos las que incrustan vídeo, ya que son muy usadas.


WordPress usa TinyMCE en la parte cliente como editor “Rich-text”. ¿Pero en servidor, cómo hace la validación?


Pues lo hace mediante la librería KSES.


KSES se configura de forma muy parecida a TinyMCE. En un array definimos cuáles son las etiquetas permitidas, los atributos de dichas etiquetas e, incluso, los valores permitidos para dichos atributos. De esta forma, permite un filtrado mucho más potente que la función strip_tags de PHP.


Al final he optado por usar el plugin Extend KSES, que implementa la librería KSES y proporciona toda la funcionalidad que necesitaba.

Subversion hooks

Leyendo información sobre algunos de los temas que salieron en la reunión de ayer (PHPDoc, guías de estilo, etc.), he estado leyendo sobre los hooks de Subversion.


Los hooks son scripts que se pueden lanzar automáticamente en la ocurrencia de ciertos eventos: start-commit, pre-commit, post-commit, etc.


Nosotros no los estamos usando, pero podríamos automatizar algunas tareas, como avisar por email cuando alguien sube cambios al repositorio, comprobar que el PHP que subimos es sintácticamente correcto, que cumple ciertas reglas de dependencia o lo que hablábamos de limpiar y chequear nuestro código antes de subirlo. Incluso pasar una batería de pruebas.


Podéis encontrar algo más de información en estas páginas:


Ejemplo de arquitectura compleja – Poppen.de

Nuestro SysAdmin nos envía un ejemplo de arquitectura compleja al que merece la pena echar un vistazo.


http://highscalability.com/blog/2010/4/12/poppende-architecture.html


Usan Nginx, PHP-FPM, Memcached, MySQL, RabbitMQ, Red5 y algún otro servicio interesante.


No perdáis de vista los comentarios. Hay alguna discusión interesante en ellos.

Rendera – Un editor online de HTML5 y CSS3

Rendera es una aplicación online mediante la cual, sin necesidad de instalar nada, podemos escribir código HTML5, CSS3 y Javascript (con soporte para jQuery) y ver cómo queda en tiempo real.


Es una buena opción para hacer pruebas rápidas. Además, la página incluye algunos ejemplos que nos pueden servir de inspiración.


Lógicamente, los resultados dependerán del navegador que estemos utilizando. No todos ellos dan soporte a todas las funcionalidades de estas nuevas versiones de los estándares.


Vía wwwhat’snew.

Parseando HTML

Lo ideal, cuando necesitamos obtener datos de un proveedor, es acceder a un servicio web que nos los proporcione en algún formato estructurado (XML, JSON o similar). Lamentablemente, no siempre disponemos de este servicio, pero sí que es posible que podamos obtener la información en alguna página web, en formato HTML.


Para ello, lo que tenemos que hacer es interpretar el HTML, extrayendo los datos que nos interesen. En nuestra ayuda viene una librería como PHP Simple HTML DOM, que nos permite realizar esta función de manera sencilla, empleando selectores como los de jQuery.


La pega (que no debería ser tal): sólo funciona con PHP 5 en adelante.


Por descontado, nuestro parser estará íntimamente ligado al código HTML de la página. Cualquier mínimo cambio puede dejar nuestro script inutilizable. Pero al construirlo con esta librería, como las reglas de selección son bastante claras, es fácil adaptarlo.

Generar la salida de error en un script PHP


La salida de un script PHP lo normal es que sea en la salida estándar, que es donde se vuelca la información para que sea recogida por el cliente de turno. Esto suele hacerse mediante las sentencias echo y print que siempre imprimen en la salida estándar, pero ¿y si quiero enviar un mensaje a la salida de error?.


Cuando programamos nuestros scripts de linea de comandos surge la cuestión de necesitar trabajar con el resto de canales de entrada y salida que define el sistema. De los canales definidos en el sistema como salida tenemos dos, la salida estándar (stdout) y la salida de errores (stderr). Son dos canales distintos por donde se puede volcar la salida de un script, y por lo tanto nos puede interesar poder especificar porque canal quiero mandar la información. Lógicamente la salida estándar será para los mensajes de proceso y la de error para mensajes que indiquen un comportamiento anómalo al proceso.


Para esto PHP define una serie de secuencias de entrada y salida para poder utilizar con las funciones de tratamiento de ficheros, y que nos permite tratar información sobre los canales del sistema. Sobre los canales de salida que nos interesan están php://stdout y php://stderr que son los que ofrecen acceso al canal de salida estándar y de error respectivamente. Estos canales están definidos en unas constantes (STDOUT y STDERR) que definen el descriptor de cada canal, y que permiten trabajar con ellos usando directamente las funciones de escritura…



fwrite(STDOUT, "Conectando a servidor");

fwrite(STDERR, "ERROR: No se pudo acceder al recurso");


Al utilizar la constante STDERR como descriptor de fichero en la función de escritura, todos los mensajes que se escriban saldrán por el canal de error.


Así en nuestro scripts podremos diferenciar este canal…



php -q script.php 2> /var/log/script/script_php.error.log


Diferencias entre entornos


Para ejecutar un script de PHP podemos tener el intérprete compilado de dos formas diferentes: CGI y CLI


CLI


PHP actúa como si fuera un script de linea de comando. Es la versión que se tiene en el entorno de desarrollo, y sería la opción más adecuada para lanzar los scripts que se programan como tareas en el sistema.


No tiene asociada ninguna excepción sobre lo que hemos visto.


CGI


Integrado en los entornos de test y producción.


Usado antiguamente (y puede que actualmente) como el interprete que se configuraba en los servidores web para poder integrar PHP. Esta versión esta más orientada a ejecutar scripts en un entorno web, y no desde linea de comando como suelen ser nuestro caso. Es por esto que existen diferencias con la versión CLI y en este caso con los descriptores de ficheros.


No existen las constantes que representan los canales de salida STDOUT y STDERR, y por lo tanto hay que realizar la escritura de otra manera…



$fd_err = fopen("php://stderr","w"):

fwrite($fd_err, "ERROR: No se pudo acceder al recurso");


… para poder trabajar con la secuencia de error.


Solución


Para no tener que escribir código diferente entre las versiones se puede definir las constantes para que el trabajo sea igual y quede como si no hubiera diferencia…



if(!defined('STDERR')) define('STDERR', fopen("php://stderr","w"));

fwrite(STDERR, "ERROR: No se pudo acceder al recurso");


… así, si la constante no está definida se creara, y nuestro código quedaría igual para los diferentes entornos.

jueves, 20 de enero de 2011

MacOSX en Virtual Box

Parece mentira, pero si queremos desarrollar algo para iPhone/iPad, la única opción es hacernos con un Mac. No contaba con tener disponible el SDK para Linux, pero es que para Windows tampoco lo hay.


No sé si habrá algún motivo técnico o es una decisión comercial. Pero es lo que hay.


En cualquier caso, también tenemos que pagar la licencia de desarrollo, que viene a costar unos 79€ al año.


Si queremos trastear un poco, antes de desembolsar el dinero que cuesta un Mac y las licencias correspondientes, podemos hacer alguna prueba con VirtualBox.


Primeramente tenemos que obtener una imagen de OSX compatible con la máquina virtual, como por ejemplo: http://thepiratebay.org/torrent/5203531/Snow_Leopard_10.6.1-10.6.2_Intel_AMD_made_by_Hazard


Una vez instalada, procederemos a instalar iOS SDK y XCode, la plataforma de desarrollo. Pero resulta que requiere OSX 10.6.4. Así que hay que actualizar nuestro sistema recién instalado.


El problema es que, si lo hacemos sin más, al reiniciar nos dará un error "kernel mismatch".


Para evitarlo, podemos obtener un kernel compatible en: http://3rr0rists.net/driver/legacy-kernel-10-6-6-10-6.html. Lo instalaremos antes de reiniciar la actualización a 10.6.x (10.6.6 en el momento de hacer las pruebas)

martes, 18 de enero de 2011

Túneles

Seguro que todos sabéis hacerlo, pero yo siempre me lío.


Muchas veces tendremos la necesidad de acceder a un servicio en un puerto remoto hacia el que no tenemos visibilidad desde el entorno local.


Para poder acceder sin necesidad de usar IPs públicas, abrir firewalls y demás, podemos hacer un túnel SSH.


La sintaxis sería la siguiente:



ssh -L puerto_local:host_destino:puerto_destino usuario@host

Por ejemplo, yo necesitaba conectar al MySQL de la plataforma, que está en servidorX. Sin embargo, sólo hay visibilidad de servidorY. Así que, abriendo el siguiente túnel, tengo visibilidad de la base de datos en el puerto P de mi máquina:



ssh -L P:servidorX:3306 usuario@servidorY

Cómo manejar directorios con muchos ficheros

Estaba configurando el script de PHPDoc y me he encontrado con la limitación de que no permite indicar ficheros con wildcards. Es decir, o le dices que escanee un directorio, y lo hará por completo (subdirectorios incluidos), o bien le indicas qué ficheros quieres que parsee, separados por comas (pero sin espacios).


Lo de sin espacios es importante, ya que ls -m no genera una salida válida para PHPDoc.


Así que tenemos que tirar de un poco de shell. La solución implementada, además, permite el manejo de directorios de cualquier número de ficheros (gracias al comando find):



find $DIR -maxdepth 1 -name "*.php" -exec echo -n "{}," \; | sed -e 's/,$//g'