Sesiones
HTTP es un protocolo sin estado, sin embargo, casi todas las aplicaciones necesitan mantener el estado entre peticiones, por ejemplo, el contenido de un carrito de compras. Precisamente para eso sirven las sesiones. Mostraremos:
- cómo usar las sesiones
- cómo evitar conflictos de nombres
- cómo configurar la expiración
Al usar sesiones, cada usuario recibe un identificador único llamado ID de sesión, que se pasa en una cookie. Este sirve como clave para los datos de la sesión. A diferencia de las cookies, que se almacenan en el lado del navegador, los datos de la sesión se almacenan en el lado del servidor.
Configuramos la sesión en la configuración, la opción de tiempo de expiración es especialmente importante.
La gestión de la sesión está a cargo del objeto Nette\Http\Session, al que puede acceder solicitando que se
le pase mediante inyección de dependencias. En
los presenters, basta con llamar a $session = $this->getSession()
.
Iniciar sesión
Nette, en su configuración predeterminada, inicia automáticamente la sesión en el momento en que comenzamos a leer
o escribir datos en ella. La sesión se inicia manualmente usando $session->start()
.
PHP envía al iniciar la sesión cabeceras HTTP que afectan al almacenamiento en caché, consulte session_cache_limiter, y posiblemente también una cookie con el ID de sesión. Por lo tanto, es necesario iniciar siempre la sesión antes de enviar cualquier salida al navegador, de lo contrario se lanzará una excepción. Si sabe que se utilizará la sesión durante la renderización de la página, iníciela manualmente antes, por ejemplo, en el presenter.
En modo de desarrollo, Tracy inicia la sesión porque la utiliza para mostrar barras con redirecciones y peticiones AJAX en la Tracy Bar.
Secciones
En PHP puro, el almacenamiento de datos de la sesión se realiza como un array accesible a través de la variable global
$_SESSION
. El problema es que las aplicaciones suelen constar de varias partes independientes entre sí y si todas
tienen acceso a un solo array, tarde o temprano se producirá 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 ya no puede producirse ninguna colisión.
Obtenemos la sección de la sesión:
$section = $session->getSection('nombreUnico');
En el presenter, basta con usar getSession()
con un parámetro:
// $this es Presenter
$section = $this->getSession('nombreUnico');
La existencia de la sección se puede verificar con el método $session->hasSection('nombreUnico')
.
Trabajar con la sección en sí es muy fácil usando los métodos set()
, get()
y
remove()
:
// escribir variable
$section->set('userName', 'juan');
// leer variable, devuelve null si no existe
echo $section->get('userName');
// eliminar variable
$section->remove('userName');
Para obtener todas las variables de la sección, se puede usar el bucle foreach
:
foreach ($section as $key => $val) {
echo "$key = $val";
}
Configuración de la expiración
Es posible configurar la expiración para secciones individuales o incluso variables individuales. Podemos así dejar que el inicio de sesión del usuario expire en 20 minutos, pero seguir recordando el contenido del carrito.
// la sección expirará después de 20 minutos
$section->setExpiration('20 minutes');
Para configurar la expiración de variables individuales, se utiliza el tercer parámetro del método set()
:
// la variable 'flash' expirará después de 30 segundos
$section->set('flash', $message, '30 seconds');
No olvide que el tiempo de expiración de toda la sesión (consulte configuración de la sesión) debe ser igual o mayor que el tiempo establecido para secciones o variables individuales.
La cancelación de una expiración previamente establecida se logra con el método removeExpiration()
. La
cancelación inmediata de toda la sección la asegura el método remove()
.
Eventos $onStart, $onBeforeWrite
El objeto Nette\Http\Session
tiene eventos
$onStart
y $onBeforeWrite
, por lo que puede añadir callbacks que se invocarán después de iniciar la
sesión o antes de escribirla en el disco y su posterior finalización.
$session->onBeforeWrite[] = function () {
// escribimos datos en la sesión
$this->section->set('basket', $this->basket);
};
Gestión de sesiones
Resumen de los métodos de la clase Nette\Http\Session
para la gestión de sesiones:
start(): void
Inicia la sesión.
isStarted(): bool
¿Está iniciada la sesión?
close(): void
Termina la sesión. La sesión termina automáticamente al final de la ejecución del script.
destroy(): void
Termina y elimina la sesión.
exists(): bool
¿Contiene la petición HTTP una cookie con el ID de sesión?
regenerateId(): void
Genera un nuevo ID de sesión aleatorio. Los datos se conservan.
getId(): string
Devuelve el ID de sesión.
Configuración
Configuramos la sesión en la configuración. Si escribe una aplicación que no utiliza un contenedor DI, estos métodos sirven para la configuración. Deben llamarse antes de iniciar la sesión.
setName (string $name): static
Establece el nombre de la cookie en la que se transmite el ID de sesión. El nombre estándar es PHPSESSID
. Es
útil si ejecuta varias aplicaciones diferentes en el mismo sitio web.
getName(): string
Devuelve el nombre de la cookie en la que se transmite el ID de sesión.
setOptions (array $options): static
Configura la sesión. Se pueden establecer todas las directivas de sesión de PHP (en formato camelCase, p. ej., en
lugar de session.save_path
escribimos savePath
) y también readAndClose.
setExpiration (?string $time): static
Establece el período de inactividad después del cual la sesión expira.
setCookieParameters (string $path, ?string $domain=null, ?bool $secure=null, ?string $samesite=null): static
Configuración de los parámetros de la cookie. Puede cambiar los valores predeterminados de los parámetros en la configuración.
setSavePath (string $path): static
Establece el directorio donde se guardan los archivos de sesión.
setHandler (\SessionHandlerInterface $handler): static
Configuración de un manejador personalizado, consulte la documentación de PHP.
La seguridad es lo primero
El servidor asume que se comunica siempre con el mismo usuario mientras las peticiones vayan acompañadas del mismo ID de sesión. La tarea de los mecanismos de seguridad es asegurar que esto sea realmente así y que no sea posible robar o suplantar el identificador.
Por lo tanto, Nette Framework configura correctamente las directivas PHP para que el ID de sesión se transmita únicamente en la cookie, lo haga inaccesible para JavaScript e ignore los posibles identificadores en la URL. Además, en momentos críticos, como el inicio de sesión del usuario, genera un nuevo ID de sesión.
Para la configuración de PHP se utiliza la función ini_set
, que lamentablemente algunos hostings
prohíben. Si es el caso de su proveedor de hosting, intente negociar con él para que le permita la función o al menos
configure el servidor.