Configurando sesiones y controladores de guardado

Esta sección se ocupa de cómo configurar la gestión de sesiones y ajustarla a tus necesidades específicas. Esta documentación incluye los controladores de guardado, que almacenan y recuperan datos de la sesión y configuración del comportamiento de la sesión.

Controladores de guardado

El flujo de trabajo en la sesión PHP tiene 6 posibles operaciones que pueden ocurrir. El flujo de sesión normal sigue el proceso de apertura, lectura, escritura y cierre, con la posibilidad de destrucción y gc (por garbage collection o recolección de basura, la cual cerrará todas las sesiones abiertas: la gc se invoca aleatoriamente de acuerdo a la configuración de PHP y si es llamada directamente, su invocación se difiere hasta después de una operación de apertura). Puedes leer más sobre esto en php.net/session.customhandler

Controladores de guardado nativos de PHP

Los llamados controladores ‘nativos’, son controladores de guardado que son o bien compilados en PHP o proporcionados por extensiones PHP, como PHP SQLite, PHP-Memcached, etc.

Todos los controladores de guardado nativos son internos a PHP y como tal, no tienen enfrente API pública. Ellos deben estar configurados en las directivas ini de PHP, por lo general session.save_path y potencialmente otros controladores específicos para la directiva. Puedes encontrar los detalles específicos en el bloque de documentación del método setOptions() de cada clase.

Mientras los controladores de guardado nativos se pueden activar utilizando directamente ini_set('session.save_handler', $nombre);, Symfony2 proporciona una manera conveniente de activar estos en la misma forma que los controladores personalizados.

Symfony2 proporciona controladores para el siguiente controlador de guardado nativo, por ejemplo:

  • Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;

Ejemplo de uso:

use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;

$storage = new NativeSessionStorage(array(), new NativeFileSessionHandler());
$session = new Session($storage);

Nota

Salvo el controlador files que está integrado en PHP y siempre disponible, la disponibilidad de los otros controladores depende de las extensiones de PHP activas en tiempo de ejecución.

Nota

Los controladores de guardado nativos proporcionan una rápida solución de almacenamiento de sesión, sin embargo, en sistemas complejos donde se necesita más control, los controladores de guardado personalizados pueden proporcionar más libertad y flexibilidad. Symfony2 proporciona varias implementaciones que se pueden personalizar aún más según sea necesario.

Controladores de guardado personalizados

Los controladores personalizados son aquellos que sustituyen por completo a los controladores de guardado de sesión integrados en PHP, proveyendo seis funciones retrollamadas que PHP invoca internamente en varios puntos en el flujo de trabajo de la sesión.

HttpFoundation de Symfony2, por omisión, ofrece algunos de estos y fácilmente te pueden servir como ejemplos, si quieres escribir uno propio.

  • Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
  • Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler
  • Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler
  • Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler
  • Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler

Ejemplo de uso:

use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorage;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

$storage = new NativeSessionStorage(array(), new PdoSessionHandler());
$session = new Session($storage);

Configurando sesiones PHP

La clase Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage puede ajustar la mayoría de las directivas de configuración de PHP, las cuales están documentadas en php.net/session.configuration.

Para configurar estas opciones, pasa las claves (omitiendo la primera parte session. de la clave) como un arreglo de clave/valor como el argumento $options del constructor. O ajústalas a través del método setOptions().

En aras de la claridad, algunas de las opciones principales se explican en esta documentación.

Configurando la recolección de basura

Cuando se abre una sesión, PHP llama aleatoriamente al controlador gc de acuerdo a la probabilidad establecida por session.gc_probability / session.gc_divisor. Por ejemplo, si éstos se establecieron en 5/100, respectivamente, significaría una probabilidad del 5%. Del mismo modo, 3/4 significaría invocarlo en 3 de cada 4 oportunidades, es decir, un 75%.

Si se invoca el controlador de recolección de basura, PHP pasará el valor almacenado en la directiva ini session.gc_maxlifetime de PHP. El significado en este contexto es que se debería suprimir cualquier sesión almacenada que se guardó por más de maxlifetime. Esto le permite a uno expirar los registros basándose en el tiempo de inactividad.

Puedes configurar estas opciones pasando gc_probability, gc_divisor y gc_maxlifetime en un arreglo al constructor de Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage o al método setOptions()().

Tiempo de vida de la sesión

Cuando se crea una nueva sesión, significa que Symfony2 emite una nueva cookie de sesión para el cliente, la cookie será sellada con un tiempo de caducidad. Este se calcula sumando el valor de configuración de session.cookie_lifetime en PHP con la hora actual del servidor.

Nota

PHP sólo emitirá una cookie una vez. Se espera que el cliente guarde esa cookie toda la vida. Sólo se otorgará una nueva cookie cuando la sesión sea destruida, se elimine la cookie en el navegador, o se vuelva a regenerar el identificador de sesión usando los métodos migrate() o invalidate() de la clase Session.

La duración inicial de la cookie se puede establecer configurando NativeSessionStorage utilizando el método setOptions(array('cookie_lifetime' => 1234)).

Nota

Una galeta con una vida útil de 0 significa que la galleta expira al cerrar el navegador.

Tiempo de inactividad/Mantener viva la sesión

A menudo hay circunstancias en las que posiblemente quieras proteger, o reducir al mínimo el uso no autorizado de una sesión cuando un usuario se aleja de su terminal mientras está conectado destruyendo la sesión después de cierto periodo de tiempo de inactividad. Por ejemplo, es común que las aplicaciones de banca cierren la sesión después de sólo 5 a 10 minutos de inactividad. Ajustar la duración de la cookie aquí no es apropiado debido a que el cliente la puede manipular, por lo que debemos hacer la expiración de lado del servidor. La forma más fácil es implementarla a través de la recolección de basura la cual se ejecuta con razonable frecuencia. El lifetime de la cookie se establece a un valor relativamente alto, y la recolección de basura maxlifetime se establecería para destruir sesiones en cualquiera que sea el periodo de inactividad deseado.

La otra opción es comprobar específicamente si una sesión ha caducado después de haber iniciado la sesión. La sesión se puede destruir si es necesario. Este método de procesamiento puede permitir la integración de la expiración de sesiones en la experiencia del usuario, por ejemplo, visualizando un mensaje.

Symfony2 registra algunos metadatos básicos acerca de cada sesión para darte completa libertad en este ámbito.

Metadatos de sesión

Las sesiones están decoradas con un poco de metadatos básicos para permitirte un control preciso sobre la configuración de seguridad. El objeto Sesión tiene un captador de metadatos, getMetadataBag() que expone una instancia de Symfony\Component\HttpFoundation\Session\Storage\MetadataBag:

$session->getMetadataBag()->getCreated();
$session->getMetadataBag()->getLastUsed();

Ambos métodos devuelven una marca de tiempo Unix (relativa al servidor).

Puedes utilizar estos metadatos para expirar la sesión explícitamente en el acceso, por ejemplo:

$session->start();
if (time() - $session->getMetadataBag()->getLastUsed() > $maxIdleTime) {
    $session->invalidate();
    throw new SessionExpired(); // redirige a la página de sesión expirada
}

También es posible decir cuál es el cookie_lifetime establecido en una cookie en particular leyendo el método getLifetime():

$session->getMetadataBag()->getLifetime();

Puedes determinar el tiempo de caducidad de la cookie sumando la fecha y hora de creación y el lifetime.

Compatibilidad con PHP 5.4

A partir de PHP 5.4.0, están disponibles SessionHandler y SessionHandlerInterface. Symfony 2.1 proporciona compatibilidad para SessionHandlerInterface por lo tanto la puedes utilizar en PHP 5.3. Esto, gratamente mejora la interoperabilidad con otras bibliotecas.

SessionHandler es una clase interna especial de PHP que expone los controladores de guardado nativos para el espacio de usuario de PHP.

Con el fin de proporcionar una solución para aquellos que utilizan PHP 5.4, Symfony2 tiene una clase especial llamada Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler que bajo PHP 5.4, se extiende desde SessionHandler y bajo PHP 5.3 es sólo una clase base vacía. Esto proporciona interesantes oportunidades para aprovechar la funcionalidad de PHP 5.4 si está disponible.

Controladores delegados de guardado

Hay dos tipos de controladores delegados de clases de guardado que heredan de Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractProxy: estas son Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeProxy y Symfony\Component\HttpFoundation\Session\Storage\Handler\SessionHandlerProxy.

La Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage automáticamente inyecta los controladores de guardado en un controlador de guardado delegado, a menos que ya lo envuelva uno.

La clase Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeProxy se utiliza automáticamente en PHP 5.3, cuando los controladores de guardado internos de PHP se especifican usando las clases Native*SessionHandler, mientras que la clase Symfony\Component\HttpFoundation\Session\Storage\Handler\SessionHandlerProxy se utiliza para envolver cualquier controlador de guardado personalizado, esta implementa la SessionHandlerInterface.

En PHP 5.4 y superior, todos los controladores de sesión implementan la SessionHandlerInterface incluyendo las clases Native*SessionHandler que heredan de SessionHandler.

El mecanismo delegado te permite involucrarte profundamente en las clases controladoras de guardado de sesión. Podrías utilizar un delegado, por ejemplo, para cifrar cualquier transacción de la sesión sin el conocimiento específico del controlador de guardado.

Bifúrcame en GitHub