2011/05/28

Bonito efecto CSS3

Algo ligero para hoy después de dos días "rompiendo" las normas. Un bonito efecto CSS3 que he encontrado por ahí útil para un título de web por ejemplo. Una capturita de cómo deberíais verlo.



Por descontado, os hará falta un navegador "de verdad" para verlo en su máximo esplendor.

Más detalles en el fiddle...

2011/05/27

Sesiones PHP a lo campestre II. Seamos civilizados

En contra de lo que el título puede indicar, a priori vamos a ver el método "correcto" de almacenar la información de nuestra aplicación en el pseudo-array $_SESSION de PHP.

A la hora de almacenar los datos, siempre podemos usar el método que aparece en todos los sitios, incluida la documentación de http://php.net/ donde de forma simplista dice
"Para almacenar una variable en la sesión, haz $_SESSION['variable'] = $valor;"
Muy bonito y sencillo, pero las cosas no se pueden reducir tanto. Imagináos el escenario de que en un mismo servidor hay varias aplicaciones web con PHP funcionando. Inicialmente creamos una sesión en una aplicación que alegremente nos mete en nuestra sesión un valor 'id' con valor 3 mediante $_SESSION['id'] = 3;

Hasta aquí, bien, todo funciona. Ahora abrimos una segunda aplicación dentro del mismo servidor que usa esa misma variable de sesión, pero ahora con valor 'nulo' mediante $_SESSION['id'] = 'nulo';

Volvemos a la primera aplicación y cuando ésta pregunta por el valor de 'id' en la sesión NO RECIBE el valor 3 que es lo que espera, si no 'nulo'. Ea!, ahora vuélvete loco depurando o directamente vete a por una pistola para pegarte un tiro, porque no lo vas a encontrar...

Esto se arregla usando la misma técnica que se usa en javascript para optimizar el ámbito de las variables. Lo que hay que hacer es crear un ámbito de cada aplicación dentro de la sesión. Para ello, en vez de asignar un valor directamente a $_SESSION, vamos a crear una nueva varible dentro PERO DE TIPO ARRAY con nombre, siendo originales, el de nuestra aplicación. Así, todo quedaría así:
// Inicia la sesión
session_start();
// Crea el contexto
if(!isset($_SESSION['aplicacion1'])) $_SESSION['aplicacion1'] = array(); 

$_SESSION['aplicacion1']['id'] = 3;
// Ahora sí que cuando se lea la segunda vez valdrá 3
Con ésto, nos aseguramos que todo va a funcionar como debe sin tener dolores de cabeza.

Visto lo visto, si queremos realizar la misma barbaridad que vimos ayer accediendo a los valores de la sesión usando el contexto que hemos creado, habría que cambiarlo por
// Coge los valores de la sesión para nuestro contexto
$aplicacion = 'aplicacion1';
$res   = preg_match('/' . $aplicacion . '\|a\:\d+\:\{(.*)\};?/i', $txt, $data);
if($res) $txt    = $data[1];
else die("No hay sesión iniciada");

// Lee el valor de la variable id del contexto aplicacion1
$var   = 'id';
$res   = preg_match('/"' . $var . '"\;s\:\d*\:\"(\d+)\";/i', $txt, $data);
if($res) $idt    = $data[1];
Los cambios son pocos pero sutiles. Ahora, nuestra variable estará encerrada entre comas (antes no lo estaba) y el separador entre el nombre de la variable y el valor pasa de ser dos puntos a ser punto y coma.

Cuidadín con lo que haceís ya que en ese fichero de sesión se almacenan todas las sesiones iniciadas por ese cliente, tanto para la "aplicacion1" como para la "aplicacion2" siguiendo el ejemplo del principio.

2011/05/26

Sesiones en PHP a lo campestre

Hola a todos, hoy toca ser un poco "bruto". En uno de mis desarrollos, me he encontrado con un bug de PHP de modo que al trabajar con ficheros en tiempo real, cada vez que abría la sesion son session_start() para leer los datos del usuario actual, se me bloqueaban los ficheros por lo que se el tempo real se me iba al garete y el tiempo re sespuesta al timeout.

En vez de desesperar, me las he ingeniado para realizar las operaciones que jace el session_start() a lo basto, leyendo directamente las sesiones desde disco y extrayendo los datos que necesitaba.

Aquí tenéis un ejemplo. Sed buenos, que os estoy vigilando ;)

El primer paso es recibir el session_id() bueno de la sesión que tengamos iniciada (suponemos que en algún momento hemos hecho un session_start() con éxito. Si no, mal vamos).

El session_id se puede obtener llamando a la función session_id() después de un session_start() o mediante la lectura de la cookie PHPSESSID mediante $_COOKIE['PHPSESSID']. En el ejemplo se puede pasar el is mediante el parámetro "sid" de la página o mediante la cookie.
// Obtiene el session_id
$sid = $_REQUEST['sid'];
if(!$sid) $sid = $_COOKIE['PHPSESSID'];
if(!$sid) die "Necesito un identificador de sesión!!!";

Ahora calculamos el nombre del fichero donde se almacena la sesión
// Lee los IDs desde los ficheros de la sesión
$fname = session_save_path() . "/sess_" . $sid;
$txt   = file_get_contents($fname);

Los ficheros son ficheros de texto con cada variable expresada sefún el formato
variable|tipo:longitud:"valor";

variable es el nombre de la variable
tipo es un carácter que indica el tipo de datos. por ejemplo las cadenas son la letra 's'
longitud es el número de caracteres del valor
valor es el valor de la variable de sesión
Así, vamos a leer el valor de las variables usando expresiones regulares
$res = preg_match('/variable\|s\:\d*\:\"(\d+)\";/i', $txt, $data);
if($res) $valor = $data[1];

2011/05/25

BubbleUp un plugin con jQuery con inspiración en los macs

Hace tiempo, encontré este pequeño plugin que funciona bastante bien en éste sitio. Como tenía planteado usarlo en alguno de mis proyectos, nada mas abrirlo me encontré con unas cuantas cosas que no me gustaban así que después de limpiarlo y quitarle algunas telarañas, vi que con un mínimo esfuerzo se podía mejorar para simplificar el CSS usado, así como darle estilo a los tooltips y mejorar las animaciones. Así que me puse manos a la obra y aquí está la versión 0.0.2 y funciona en todo menos para IE6 (mecachis...).

Lo podéis ver en funcionamiento en mi jsfiddle:

2011/05/20

Detectando la rotación de pantalla en Android

Snippet para detectar cambios en la orientación de pantalla en dispositivos móviles. Está pensado para Android, pero supongo que serviría para cualquier plataforma móvil. Realmente no controla que se rote, si no que controla si existe el evento de "onorientationchange" y asigna una función a él. En el caso de que el evento no esté soportado, vincula el evento a resize.

// Detect whether device supports orientationchange event,
// otherwise fall back to the resize event.
var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    alert('HOLY ROTATING SCREENS BATMAN:' + window.orientation + " " + screen.width);
}, false);

Como guinda del pastel, en el caso de que se vincule al evento "resize", se podrían definir 2 variables globales (al contexto) llamadas por ejemplo "screenW" y "screenH" que se controlan en el evento de modo que si están intercambiadas, se ha cambiado la orientación. Con ello, nuestro código quedaría así.

var _screenW = screen.width;
var _screenH = screen.height;

// Detect whether device supports orientationchange event,
// otherwise fall back to the resize event.
var supportsOrientationChange = "onorientationchange" in window,
    orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";

window.addEventListener(orientationEvent, function() {
    if(supportsOrientationChange ||
      (!supportsOrientationChange && _screenW == screen.height && _screenH == screen.width))
   {
       alert('HOLY ROTATING SCREENS BATMAN:' + window.orientation + " " + screen.width);
   }
}, false);