Introducción
Trabajando en un pequeño proyecto de PHP me topé con la siguiente advertencia: Warning: session_set_save_handler(): Cannot change save handler when session is active. Este mensaje me tuvo dando vueltas por todo internet sin encontrar una solución, pero probando algunas cosas di con ella y vengo a exponerla.
PHP permite implementar nuestro propio manejador de sesiones. En este blog ya hemos hecho alguno anteriormente, justo aquí: implementar session handler en PHP.
Pues bien, vamos a la solución y explicación.
Explicación de Cannot change save handler when session is active
El mensaje lo dice todo. No se puede cambiar el manejador de sesiones mientras la sesión está activa. Esto tiene bastante sentido.
Es decir, no podemos hacer esto:
<?php session_start(); session_set_save_handler(/*El handler aquí*/); $_SESSION["foo"] = "bar"; echo $_SESSION["foo"]; ?>
Ya que como vemos, estamos llamando a session_start y después estamos llamando a session_set_save_handler. Por lo que primero debemos llamar a session_set_save_handler y luego utilizar la sesión.
Pero el problema no es así de simple, ya que, ¿Qué pasa cuando leemos dos veces la sesión? por ejemplo, puede que tengamos dos métodos que leen la sesión, y que se ejecuten uno después del otro. La llamada de las sesiones sería así:
<?php /* Esto genera un error de que la sesión ya ha sido iniciada pero este no es el problema ahora, eso se soluciona con session_status y bla bla */ #--Esto lo hace el primer método session_set_save_handler(/*El handler*/); session_start(); $_SESSION["foo"] = "bar"; #Hasta aquí todo bien #--Esto lo hace el segundo método /* Justo aquí abajo está el error... la sesión está siendo leída o escrita, porque la iniciamos allá arriba pero estamos intentando registrar un handler, y por eso se genera la advertencia, pues no se puede registrar un handler mientras leemos o escribimos */ session_set_save_handler(/*El handler*/); session_start(); $_SESSION["foo"] = "bar"; #Hasta aquí todo bien ?>
El huevo o la gallina
Y aquí entramos en un dilema. La solución más fácil sería ver si no hay datos de sesión, y si no los hay, entoncesregistramos el handler. Algo así:
<?php if(!isset($_SESSION["bla"])) session_set_save_handler(/*Handler*/); ?>
¿Pero cómo leemos datos de sesión de nuestro handler, si no lo hemos registrado? y recordemos que si lo registramos, generará un error. Pero si no lo registramos, no podremos comprobar si ya ha sido registrado.
Se parece al problema del huevo y la gallina. Ya que si no registramos el handler, estaremos leyendo datos de sesión del manejador propio de PHP, no del nuestro. Pero no podemos registrar el handler porque genera un error. Error que evitamos leyendo datos de la sesión con el handler registrado.
Solución a Cannot change save handler when session is active
La solución es sencilla. Ya que no podemos registrar nuestro handler porque eso genera un error, pero para omitir el error debemos leer datos de la sesión de nuestro handler, podemos mejor comprobar si está definido el arreglo superglobal $_SESSION.
Dicho arreglo superglobal estará indefinido si no hay datos de sesion (independientemente del handler), así que podemos comprobarlo para ver si deberíamos o no registrar el manejador. Así:
<?php if (!isset($_SESSION)){ session_set_save_handler(/*El handler aquí*/); }
De esta manera, no importa cuántas veces se llame a la sesión, pues el handler será registrado sólo una vez.