Sesiones
HTTP es un protocolo sin estado, pero casi todas las aplicaciones necesitan mantener un estado entre peticiones, por ejemplo, el contenido de un carrito de la compra. Para esto se utiliza una sesión. Veamos
- cómo usar las sesiones
- cómo evitar conflictos de nombres
- cómo fijar la caducidad
Cuando se utilizan sesiones, cada usuario recibe un identificador único llamado ID de sesión, que se pasa en una cookie. Esto sirve como clave para los datos de sesión. A diferencia de las cookies, que se almacenan en el navegador, los datos de sesión se almacenan en el servidor.
Configuramos la sesión en la configuración, la elección del tiempo de expiración es importante.
La sesión es gestionada por el objeto Nette\Http\Session,
que se obtiene pasándolo mediante inyección de dependencia. En
presentadores simplemente llame a $session = $this->getSession()
.
Inicio de la sesión
Por defecto, Nette iniciará una sesión automáticamente en el momento en que empecemos a leer de ella o a escribir datos en
ella. Para iniciar una sesión manualmente, utilice $session->start()
.
PHP envía cabeceras HTTP que afectan a la caché cuando se inicia la sesión, ver session_cache_limiter, y posiblemente una cookie con el ID de sesión. Por lo tanto, siempre es necesario iniciar la sesión antes de enviar cualquier salida al navegador, de lo contrario se lanzará una excepción. Por lo tanto, si sabe que se va a utilizar una sesión durante la representación de la página, iníciela manualmente antes, por ejemplo en el presentador.
En modo desarrollador, Tracy inicia la sesión porque la utiliza para mostrar barras de redirección y peticiones AJAX en la Tracy Bar.
Sección
En PHP puro, el almacén de datos de sesión se implementa como un array accesible a través de una variable global
$_SESSION
. El problema es que las aplicaciones normalmente consisten en un número de partes independientes, y si
todas tienen un mismo array disponible, tarde o temprano ocurrirá una colisión de nombres.
Nette Framework resuelve el problema dividiendo todo el espacio en secciones (objetos Nette\Http\SessionSection). Cada unidad utiliza entonces su propia sección con un nombre único y no pueden producirse colisiones.
Obtenemos la sección del gestor de sesiones:
$section = $session->getSection('unique name');
En el presentador basta con llamar a getSession()
con el parámetro:
// $this es Presentador
$section = $this->getSession('unique name');
La existencia de la sección puede comprobarse mediante el método $session->hasSection('unique name')
.
La sección en sí es muy fácil de trabajar con los métodos set()
, get()
y
remove()
:
// escritura de variables
$section->set('nombreusuario', 'franta');
// lectura de una variable, devuelve null si no existe
echo $section->get('nombredeusuario');
// eliminar variable
$section->remove('userName');
Es posible utilizar el ciclo foreach
para obtener todas las variables de la sección:
foreach ($section as $key => $val) {
echo "$key = $val";
}
Cómo fijar la caducidad
La caducidad puede establecerse para secciones individuales o incluso variables individuales. Podemos dejar que el login del usuario caduque en 20 minutos, pero seguir recordando el contenido de un carrito de la compra.
// la sección caducará a los 20 minutos
$section->setExpiration('20 minutes');
El tercer parámetro del método set()
se utiliza para establecer la caducidad de variables individuales:
// la variable 'flash' caduca a los 30 segundos
$section->set('flash', $message, '30 seconds');
Recuerda que el tiempo de expiración de toda la sesión (ver configuración de la sesión) debe ser igual o superior al tiempo establecido para secciones o variables individuales.
La anulación de la caducidad previamente fijada puede conseguirse mediante el método removeExpiration()
. La
eliminación inmediata de toda la sección se asegurará mediante el método remove()
.
Eventos $onStart, $onBeforeWrite
El objeto Nette\Http\Session
tiene los eventos
$onStart
y $onBeforeWrite
, por lo que puedes añadir callbacks que sean llamados después de que la
sesión se inicie o antes de que se escriba en disco y luego se termine.
$session->onBeforeWrite[] = function () {
// escribir datos en la sesión
$this->section->set('basket', $this->basket);
};
Gestión de sesiones
Visión general de los métodos de la clase Nette\Http\Session
para la gestión de sesiones:
start(): void
Inicia una sesión.
isStarted(): bool
¿Se ha iniciado la sesión?
close(): void
Finaliza la sesión. La sesión termina automáticamente al final del script.
destroy(): void
Finaliza y borra la sesión.
exists(): bool
¿Contiene la petición HTTP una cookie con un ID de sesión?
regenerateId(): void
Genera un nuevo ID de sesión aleatorio. Los datos permanecen inalterados.
getId(): string
Devuelve el ID de sesión.
Configuración
Configuramos la sesión en configuración. Si está escribiendo una aplicación que no utiliza un contenedor DI, utilice estos métodos para configurarla. Deben ser llamados antes de iniciar la sesión.
setName(string $name): static
Establece el nombre de la cookie que se utiliza para transmitir el ID de sesión. El nombre por defecto es
PHPSESSID
. Esto es útil si ejecuta varias aplicaciones diferentes en el mismo sitio.
getName(): string
Devuelve el nombre de la cookie de sesión.
setOptions(array $options): static
Configura la sesión. Es posible establecer todas las directivas de sesión de PHP (en formato camelCase, por
ejemplo, escribir savePath
en lugar de session.save_path
) y también readAndClose.
setExpiration(?string $time): static
Establece el tiempo de inactividad tras el cual expira la sesión.
setCookieParameters(string $path, ?string $domain=null, ?bool $secure=null, ?string $samesite=null): static
Establece los parámetros para las cookies. Puede cambiar los valores predeterminados de los parámetros en configuration.
setSavePath(string $path): static
Establece el directorio donde se almacenan los archivos de sesión.
setHandler(\SessionHandlerInterface $handler): static
Establece el manejador personalizado, vea la documentación de PHP.
Seguridad
El servidor asume que se comunica con el mismo usuario mientras las peticiones contengan el mismo identificador de sesión. La tarea de los mecanismos de seguridad es garantizar que este comportamiento funciona realmente y que no hay posibilidad de sustituir o robar un identificador.
Por eso Nette Framework configura adecuadamente las directivas PHP para transferir el identificador de sesión sólo en las cookies, evitar el acceso desde JavaScript e ignorar los identificadores en la URL. Además en momentos críticos, como el login del usuario, genera un nuevo identificador de sesión.
La función ini_set se utiliza para configurar PHP, pero desafortunadamente, su uso está prohibido en algunos servicios de alojamiento web. Si es tu caso, intenta pedir a tu proveedor de hosting que te permita esta función, o al menos que configure su servidor adecuadamente.