Hola, estoy haciendo unas pruebas con sesiones en Symfony (3.1.5) y los resulados me confunden un poco. Agradecería si alguien me aclara un poco las cosas.
El Controlador para las pruebas:
<?php // src/AppBundle/Controller/DefaultController.php namespace AppBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; class DefaultController extends Controller { /** * @Route("/") */ public function testSessionAction(Request $request) { $welcome = 'Bienvenido otra vez'; if(!$request->getSession()->has('first_time')){ $request->getSession()->set('first_time',true); $welcome = 'Bienvenido'; } return new Response($welcome); } }
Prueba 1:
# app/config/config_dev.yml framework: # ... session: cookie_lifetime: 0 gc_maxlifetime: 5 gc_probability: 1 gc_divisor: 1
- Navego hacia /app_dev.php/ -> Bienvenido
- Espero un poco mas de 5 segundos y recargo la página -> Bienvenido otra vez
- Regargo la página antes de 5 segundos -> Bienvenido
Yo esperaba que los puntos 2 y 3 produjeran resultados inversos. ¿A que se debe? ¿La recolección de basura se produce al final? En la documentación oficial de php pone "La recolección de basura puede suceder durante el inicio de sesiones" y como tengo session.gc_probability y session.gc_divisor configurados con 1 entiendo que se ejecuta siempre.
Prueba 2:
# app/config/config_dev.yml framework: # ... session: cookie_lifetime: 5 gc_maxlifetime: 5 gc_probability: 1 gc_divisor: 1
- Borro la coockie de la prueba anterior.
- Navego hacia /app_dev.php/ -> Bienvenido
- Recargo la página varias veces, y ,pasados los 5 segundos la salida vuelve a ser "Bienvenido"
Por lo que pude ver la cabecera Set-Cookie sólo se envió en la primera petición con lo cual al cabo de 5 segundos la coockie murió. ¿Hay alguna manera de modificar esto por configuración o tengo que implementar algo personalizado para que la cookie se actualice en cada petición?
Por si alguien sigue el tema y le gusta jugar y destripar las cosas igual que a mí, aquí está el mismo código en php de toda la vida:
<?php // web/welcome.php ini_set('session.cookie_lifetime', 0); // ini_set('session.cookie_lifetime', 5); ini_set('session.gc_maxlifetime', 5); ini_set('session.gc_probability', 1); ini_set('session.gc_divisor', 1); session_start(); $welcome = 'Bienvenido otra vez'; if (!isset($_SESSION['first_time'])) { $_SESSION['first_time'] = true; $welcome = 'Bienvenido'; } echo $welcome;
Prueba 1
El paso 1 y 2 son igual que la prueba en Symfony, pero el paso 3 sigue devolviendo "Bienvenido otra vez". Parece que php no quiere recoger la basura.
Prueba 2
El resultado es igual que en Symfony.
¿Soy el único que estos resultados le parecen curiosos?
Respuestas
Creo que lo que sucede es normal según el comportamiento de PHP. El borrado de las sesiones expiradas no ocurre automáticamente. En este artículo se explica mejor, pero básicamente PHP borra las sesiones expiradas solo si hay nuevas peticiones en la aplicación.
En otras palabras, cuando un usuario entra al sitio, PHP "lanza los dados" y si sale el resultado esperado, se mira qué sesiones están expiradas. Las opciones gc_probability
y gc_divisor
son las que controlan cómo de frecuente o infrecuente es la posibilidad de que salga el resultado esperado "al lanzar los dados".
Así que para probar tu ejemplo de manera más precisa, es mejor que utilices dos usuarios diferentes (por ejemplo con la ventana de la navegación privada del navegador) y así utilices un usuario para probar el comportamiento normal y otro usuario simplemente para visitar la aplicación y hacer que la sesión expirada se borre.
@javiereguiluz
El artículo del link explica bien lo de la recolección y mejor aún el link del artículo hacia StackOverflow, aunque esa parte la entendía, no había caido en cuenta de que en una aplicación en la vida real las peticiones de otros usuarios también podían recoger mi basura.
Muchas gracias
@nairdazeab