2012-09-04 12 views
7

Aquí está la cosa. Un colega mío está intentando sobrescribir el manejo de la sesión de un marco que usamos. Este marco utiliza el manejo de la sesión nativa de PHP de manera predeterminada, pero ahora está tratando de implementar una capa de base de datos entre las solicitudes.Aquí hay un verdadero desafío: ¿por qué PHP llama a la función de apagado antes de escribir las sesiones?

El problema es que el objeto de la base de datos no está disponible cuando las sesiones ya están escritas, pero está disponible para otras funciones, como cuando se leen datos de las sesiones. Este es un comportamiento salvaje. Esto es lo que hicimos:

register_shutdown_function('exithandler'); 

session_set_save_handler(
    'sess_open', 
    'sess_close', 
    'sess_read', 
    'sess_write', 
    'sess_destroy', 
    'sess_gc' 
); 

Cada una de estas funciones también se escribe una sola línea en nuestro archivo de registro que podamos hacer un seguimiento con el nombre de la función. Esto se hace cada vez que se llama a la función. Ahora, aquí hay dos URL que se solicitan, la primera es donde se escriben realmente las sesiones (datos nuevos para las sesiones) y la segunda donde simplemente se verifican los datos de la sesión (y no se escribe ninguno). Aquí está el acertijo:

/login/ 
sess_open 
sess_read 
exithandler 
sess_write 
sess_close 

/account/ 
sess_open 
sess_read 
sess_write 
sess_close 
exithandler 

¿Por qué es este comportamiento diferente? ¿Por qué se llama al manejador de salida antes de que se almacenen los datos en las sesiones y por qué no ocurre lo mismo con una página normal, a pesar de que efectivamente se invocan los mismos métodos?

El problema es que ninguna de nuestras clases ya está disponible después de llamar al manejador de salida, supongo que el recolector de basura de PHP ha llamado a los métodos __destruct() en todas nuestras clases y se han ido. Esto es simplemente malo.

¿Alguien sabe por qué PHP se comporta de esta manera?

+1

¿Qué versión de PHP está utilizando? –

+0

He probado esto usando PHP 5.4, y solo puedo reproducir el primer orden de operaciones para ambos tipos de solicitudes: Leer y escribir datos de sesión. – nickb

+1

Existe un problema común con alguna versión de PHP que requiere que agregue una línea antes de llamar 'session_set_save_handler()'. Use esto primero: 'register_shutdown_function ('session_write_close')' y vea si eso soluciona su comportamiento inestable. –

Respuesta

2

Como sus comentarios dicen PHP5.4, es posible que desee echar un vistazo a SessionHandlerInterface(). Puede pasar el register_shutdown_function en el método open() para semiautomatizar el proceso y realmente aprovechar las características de PHP5.4.

<?php 
class MySessionHandler implements SessionHandlerInterface 
{ 
    private $savePath; 

    public function open($savePath, $sessionName) 
    { 
     register_shutdown_function('session_write_close'); 
     $this->savePath = $savePath; 
     if (!is_dir($this->savePath)) { 
      mkdir($this->savePath, 0777); 
     } 

     return true; 
    } 

    public function close() 
    { 
     return true; 
    } 

    public function read($id) 
    { 
     return (string)@file_get_contents("$this->savePath/sess_$id"); 
    } 

    public function write($id, $data) 
    { 
     return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true; 
    } 

    public function destroy($id) 
    { 
     $file = "$this->savePath/sess_$id"; 
     if (file_exists($file)) { 
      unlink($file); 
     } 

     return true; 
    } 

    public function gc($maxlifetime) 
    { 
     foreach (glob("$this->savePath/sess_*") as $file) { 
      if (filemtime($file) + $maxlifetime < time() && file_exists($file)) { 
       unlink($file); 
      } 
     } 

     return true; 
    } 
} 

$handler = new MySessionHandler(); 
session_set_save_handler($handler, true); 
session_start(); 
+0

Lamentablemente, mi framework requiere PHP 5.3 y terminé haciendo un gestor de sesión personalizado que era más adecuado para mis necesidades. Pero su respuesta es técnicamente una 'respuesta correcta', a pesar de requerir que PHP 5.4 funcione. – kingmaple

+0

¿Funciona register_shutdown_handler() dentro de Classes? –

Cuestiones relacionadas