Sigueme por RSS! RSS

CodeIgniter: sesiones, hook y base de datos


Hace un tiempito hablamos de una manera rápida y básica de armar la autenticación de usuarios en CodeIgniter(CI), esto se puede mejorar mucho, la idea es almacenar las sesiones en la base de datos para las validaciones constantes de la sesión, que realizaría un proceso vigilante.

- La base de datos:
En el post inicial ya tenemos una estructura de base de datos, una tabla usuarios y una de tipo de usuarios. CI nos permite salvar las sesiones automáticamente en tablas (si se lo indicamos), para ello debemos crearla previamente:
CREATE TABLE IF NOT EXISTS ci_sesion (
 session_id varchar(40) DEFAULT '0' NOT NULL,
 ip_address varchar(16) DEFAULT '0' NOT NULL,
 user_agent varchar(120) NOT NULL,
 last_activity int(10) unsigned DEFAULT 0 NOT NULL,
 user_data text NOT NULL,
 PRIMARY KEY (session_id)
);

Configuramos la sesión, nos vamos a codeigniter --> application --> config --> config.php
Clic aquí para mostrar/ocultar el código
// El nombre que quiere que la cookie de sesión sea guardada.
$config['sess_cookie_name'] = 'ci_session';

// El número de segundos que quiere que dure la sesión.
$config['sess_expiration'] = 7200;

// Si la sesión expira al cerrar el navegador
$config['sess_expire_on_close'] = TRUE;

// Si encriptar o no los datos de sesión.
$config['sess_encrypt_cookie'] = FALSE;

// Si guardar los datos de sesión a una base de datos.
// Debe crear la tabla antes de habilitar esta opción.
$config['sess_use_database'] = TRUE;

// El nombre de la tabla de sesión en la base de datos
// Debe ser un nombre de tabla válido en SQL
$config['sess_table_name'] = 'ci_sesion';

// Se indica que valide si coincide la dirección de IP 
// del usuario cuando se lean los datos de sesión.
// Si la IP es dinámica y se requiere una sesión ilimitada
// deberá establecerlo a FALSE.
$config['sess_match_ip'] = FALSE;

// Si coincide el Agente del Usuario cuando se leen 
// los datos de sesión.
$config['sess_match_useragent'] = TRUE;

// Indica cuan a menudo la clase de sesión se regenerará 
// y creará un nuevo identificador de sesión.
$config['sess_time_to_update'] = 300;

// indicamos si queremos controlar el 
// tiempo limite de expiracion al iniciar sesion
$config['sess_use_time_expire'] = TRUE;


Fíjate en el ultimo elemento: $config['sess_use_time_expire'], ahí indicamos si deseamos o no que el usuario inserte el tiempo limite de la sesión (al loguearse), por defecto cargara el tiempo establecido en $config['sess_expiration'], si sess_use_time_expire se setea a FALSE, entonces no se le pedira al usuario un tiempo de expiración y se dejara a CI encargarse de eso (tomando en consideración el tiempo establecido en el elemento sess_expiration).

- Aplicando los hooks a nuestras sesiones:
En CI podemos trabajar con hooks, lo que nos permite disparar rutinas en momentos específicos del sistema:
pre_system: se dispara al principio de la ejecución del sistema.
pre_controller: se dispara antes de cargar el controlador.
post_controller_constructor: se dispara luego de cargar el constructor del controlador (recordemos que el constructor de una clase es lo primero que se ejecuta en ella).
post_controller: se dispara luego de que el controlador se haya cargado.
post_system: se dispara al final de la ejecución del sistema.

A nosotros nos interesa ejecutar nuestro proceso de validación de sesión, luego de que se cargue el constructor del controlador donde estemos en ese momento, así que usaremos post_controller_constructor, editamos el archivo hook.php, nos vamos a codeigniter --> application --> config --> hook.php y agregamos lo siguiente:

hook.php:
$hook['post_controller_constructor'] = array(
    'class'    => 'gestion_sesion', // clase que controla la sesion
    'function' => 'index', // metodo encargado de todo, dentro de la clase
    'filename' => 'gestion_sesion.php', // archivo a cargar
    'filepath' => 'hooks' // carpeta donde se encuentra la clase
);

Ahora debemos crear la clase, nos vamos a codeigniter --> application --> hooks y creamos un archivo con el nombre gestion_sesion.php que es el que asignamos:

gestion_sesion.php:
Clic aquí para mostrar/ocultar el código
<?php
class Gestion_sesion{
   function index(){

      //instanciamos al objeto codeigniter
      $CI =& get_instance(); 
      
      // obtenemos el nombre del controlador en el que estamos
      $controlador = $CI->router->class;
      
      // indicamos los controladores que pueden ver por defecto los visitantes
      $controladores_guest = array('index_c','login_c');
                
      // si la sesion se inicio y el usuario intenta entrar a login_c, 
      // lo enviamos al index    
      if(user_is_logged() && $controlador=='login_c'){
         redirect('index_c');
  
      // si el usuario es un visitante, 
      // solo puede entrar a los controladores permitidos para él..
      }elseif(!user_is_logged() && 
             (!in_array($controlador,$controladores_guest))){
         redirect('login_c');
      
      // cerramos la sesion si el tiempo establecido expiro
      // solo si se cambio el tiempo de expiracion
      }elseif($CI->config->item('sess_use_time_expire')){
          
          // cargamos la libreria de sesion
          $CI->load->library('session');
          $arrSesion = $CI->session->userdata('ses_usuario');
          if (is_array($arrSesion) and $arrSesion['seslimite']<=time()){
            cerrar_sesion();
          }
      }
      unset($CI);
   }
}
?>

Por ultimo en esto de los hooks, hay que indicarle a CI que deseamos que se apliquen estos cambios, así que nos vamos a codeigniter --> application --> config --> config.php y donde dice:
$config['enable_hooks'] = FALSE;

lo cambiamos por:
$config['enable_hooks'] = TRUE;

En la clase gestion_sesion.php hacemos uso de unas funciones que no son nativas de PHP, así que creamos nuestro propio helper(asistente) y ahí las incluimos, esto lo hacemos así porque al ser un asistente, podemos acceder a esas funciones cuando lo necesitemos. Nos vamos a codeigniter --> system -->helpers y ahí creamos un archivo de nombre mod_ppal_helper.php, puedes usar cualquier otro nombre, pero deja el sufijo _helper, dentro del archivo incluimos nuestras funciones:

mod_ppal_helper.php:
Clic aquí para mostrar/ocultar el código
<?php
# determina si el usuario esta logueado o no..
if ( ! function_exists('user_is_logged'))
{
   function user_is_logged(){   

        //instanciamos al objeto codeigniter
        $CI =& get_instance();
        
        // cargamos la base de datos
        $CI->load->database('default');
        
        // obtenemos el valor del item 'sess_use_database'
        $sess_use_database = $CI->config->item('sess_use_database');

        // cargamos la libreria de sesion
        $CI->load->library('session');

        // obtenemos los datos de la sesion
        $arrSesion = $CI->session->userdata('ses_usuario');
        
        // si no esta definida la sesion, no esta logueado
        if (!isset($arrSesion['usuario'])){
            return false;// indicamos no is_logged

        }else{

            // obtenemos el id del usuario
            $session_id = $CI->session->userdata('session_id');
            
            // si se usa la session database, debemos asegurarnos
            // de que la sesion en el cliente, coincida con
            // la sesion de la base de datos
            if (!empty($session_id) and $sess_use_database){
                 
                // consultamos por id
                $CI->db->from('ci_sesion');
                $CI->db->where('session_id',$session_id);
                $query = $CI->db->get();
                
                // si coincide el session_id en algun registro
                // es porque el usuario tiene sesion abierta
                return ($query->num_rows()>0) ? true : false;

            }else{

                // 
                return (!empty($session_id)) ? true : false;
            }
        }
        $CI->db->close();
        unset($CI);
    }
}

# permite cerrar la sesion activa ..
if (! function_exists('cerrar_sesion')){
    
    function cerrar_sesion(){
        
        //instanciamos al objeto codeigniter
        $CI =& get_instance();
        
        // cargamos la base de datos
        $CI->load->database('default');
                
        // obtenemos el valor del item 'sess_use_database'
        $sess_use_database = $CI->config->item('sess_use_database');
        
        // si el usuario esta logueado, cerramos la sesion..
        if (user_is_logged()){
        
            // cargamos la libreria sesion
            $CI->load->library('session');

            // si se esta usando la base de datos para las sesiones
            if($sess_use_database){
            
                //exit('entre, esta logueado y se usa db');
                
                // indicara si se elimino la seison de la db
                $delete = false;
                
                // obtenemos los datos de la sesion
                $arrSesion = $CI->session->userdata('ses_usuario');                
                
                // obtenemos los registros de sesion
                $CI->db->select('user_data,session_id');
                $CI->db->from('ci_sesion');
                $query    = $CI->db->get();
                $arrDatos = array();

                // recorremos la lista de usuarios con sesion en la db
                foreach($query->result() as $row){

                    // obtenemos el user_data de la fila 
                    $valor = $row->user_data;

                    // los datos estan serializados en la db
                    // asi que los deserializamos
                    $arrData = unserialize($valor);
                    
                    // verificamos si el usuario pasado por parametro 
                    // es el mismo q tiene la sesion abierta
                    if ($arrSesion['usuario']==$arrData['ses_usuario']['usuario']){
                                
                        // borramos la sesion de la db
                        $CI->db->delete('ci_sesion',array('session_id' => $row->session_id));
                        //echo $CI->db->last_query();exit;
                        $delete = true;
                        break;
                    }
                }
        
                if($delete){
                    // cerramos la sesion
                    $CI->session->sess_destroy();
                }
            }else{
                
                // cerramos la sesión
                $CI->session->sess_destroy();
            }
        }
        
        // adicionalmente verificamos las sesioens activas en la db 
        // y eliminamos las que tengan determinado tiempo de incactividad        
        $CI->db->where('last_activity <',(time() - 3600));//3600 - 1 hora
        $CI->db->delete('ci_sesion');
        $CI->db->close();
        #-----------------------------------------------------------------------
        
        unset($CI);
        
        // redireccionamos al controlador index
        redirect('index_c', 'location');
   }
}
?>

Ahora le indicamos a CI que cargue por defecto nuestro helper, ya que son funciones de uso común. En codeigniter --> application --> config --> autoload.php agregamos el helper al array:
$autoload['helper'] = array('url');

nos quedaría así:
$autoload['helper'] = array('url','mod_ppal');



3 comentarios: Suscribete a los comentarios por RSS

bonisoft

Muchas gracias Reinaldo por compartir el código, muy interesante y provechoso.


Saludos desde el otro lado del charcho,
http://www.bonisoft.com

iscris

Disculpa, quiero leer el articulo completo, como le hago?

Reinaldo

hola: http://cassianinet.blogspot.com.es/2012/06/codeigniter-sesiones-hook-y-base-de.html

Publicar un comentario

- Los comentarios están siendo moderados y serán publicados en la brevedad posible.