Cada namespace es simplemente un elemento del array $_SESSION. En el siguiente ejemplo veremos claramente como crear y manipular namespaces:

$namespace = new Zend_Session_Namespace("ejemplo");
// $namespace hace referencia a $_SESSION["ejemplo"];

// seteamos algunas variables
$namespace->string = "valor";
$namespace->int = 7;
$namespace->array = array();

/*
el namespace ahora es asi

$_SESSION["ejemplo"] = array(
    "string" => "unString",
    "int" => 7,
    "array" => array()
);
*/


// verificamos si una variable fue previamente seteada
isset($namespace->string); // true
isset($namespace->inexistente); // false

// eliminamos una variable
unset($namespace->int);

Como vemos, crear el namespace, asignarle variables, eliminarlas, etc. es sumamente simple. Si en otra página queremos acceder a los datos del namespace simplemente creamos una nueva instancia y ya podremos trabajar directamente sobre él.

$elMismoNamespace = new Zend_Session_Namespace("ejemplo");
// tengo acceso a todas las variables creadas anteriormente
echo $elMismoNamespace->string; // "unString"

Una de las principales ventajas de trabajar con namespaces en $_SESSION es que evitamos el problema de la colisión de nombres. Teniendo cada cosa en su namespace correspondiente, nunca pisaremos una variable por error.

Los nombres de namespace no pueden ser una cadena vacía ni empezar con un número o un guión bajo. Tampoco pueden empezar con la palabra “Zend“, ya que dicho prefijo esta reservado para componentes de Zend.

Inicializando Session

Para inicializar session podemos poner en nuestro Bootstrap algo así:

protected function __initSession() {
    Zend_Session::start();
}

Sin embargo no es totalmente obligatorio, ya que si al crear un namespace no hicimos el start(), Zend lo hará automáticamente. El problema es que si ya enviamos los headers ocurrirá el famoso error de “Headers already sent”, así que por las dudas, para evitar este error, puedes hacer el start() manualmente.

Bloqueando un namespace

Zend_Session no solo nos brinda una linda forma de acceder a las variables de sesión sino que además nos da algunas funcionalidades interesantes, como por ejemplo bloquear un namespace para que sea de solo lectura y que no pueda ser alterado en otro lugar de nuestra aplicación, por lo menos hasta que lo volvamos a desbloquear para permitir que se escriba en él.

$namespace = new Zend_Session_Namespace("ejemplo");

// bloqueamos la escritura
$namespace->lock(); 

// esto lanzaría una excepción, ya que el namespace esta bloqueado
$namespace->bar = "baz";

// antes de escribir preguntamos si podemos hacerlo
if (!$namespace->isLocked()) {
    $namespace->bar = "baz";    
}

// lo volvemos a habilitar
$namespace->unLock();

Podemos consultar si un namespace existe con Zend_Session::namespaceIsset($namespace) y eliminarlo con Zend_Session::namespaceUnset($namespace);

Tiempo de vida de un namespace

Otra de las funcionalidades interesantes es la de poder setear la duración de un namespace. Hay dos posibilidades: la primera es setear un tiempo en segundos (“que el namespace expire en 60 segundos”); la segunda es setear una cantidad de hops (cada vez que se carga la pagina se considera un hop).

$namespace = new Zend_Session_Namespace("ejemplo");
$namespace->setExpirationSeconds(30, "string"); // $namespace->string expira en 30 segundos
$namespace->setExpirationSeconds(30); // todo el namespace expira en 30 segundos

$namespace->setExpirationHops(4, "string"); // $namespace->string expira en 4 hops
$namespace->setExpirationHops(4); // todo el namespace expira en 4 hops

Si seteamos a la vez un expirationSeconds y un expirationHops, el namespace expirará según el primer evento que se cumpla.

Introducción a Zend_Auth

Zend_Auth nos facilita la autenticación de usuarios, es decir el login / logout de usuarios, consultar por la identidad de la persona actualmente logueada, etc. Implementa el patrón singleton por lo que para obtener una instancia de la clase usaremos el método estático getInstance():

$auth = Zend_Auth::getInstance();

Database Adapter

Si bien hay varios adapters disponibles (y podemos crear nuestros propios adapters de ser necesario), en la mayoría de nuestros proyectos trabajaremos contra una base de datos.

  • setTableName($table): el nombre de tabla contra la que se verificara que los datos del usuario sean correctos.
  • setIdentityColumn($column): el campo de la base de datos correspondiente al nombre de usuario.
  • setCredentialColumn($column): el campo de la base de datos correspondiente al password
  • setIdentity($user): el nombre de usuario que queremos autenticar
  • setCredential($pass): el password de dicho usuario

Supongamos que nuestra tabla se llama ‘mdw_usuarios‘, el campo usuario es ‘user‘, el del password es ‘pass‘ y recibimos los datos del login por $_POST, el ejemplo quedaría así:

$dbAdapter = Zend_Db_Table_Abstract::getDefaultAdapter();

$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

$authAdapter
    ->setTableName('mdw_usuarios')
    ->setIdentityColumn('user')
    ->setCredentialColumn('pass')
    ->setIdentity($this->getRequest()->getPost('user'))
    ->setCredential($this->getRequest()->getPost('pass'));

Agregando cláusulas al where

Supongamos que tengamos un campo extra en nuestra bdd que determina si un usuario esta activado o no, por lo que para loguearse además de tener el user y pass correcto debe verificar que activado=1. Este requerimiento lo podemos controlar de la siguiente manera:

// obtenemos el query sobre el que trabaja el adapter
$select = $adapter->getDbSelect();

// le agregamos nuestra condición al where
$select->where('activado = 1');

Cuando ejecute la consulta para verificar que el user y pass son correctos, también controlará que activado=1.

Ahora si, realizando la autenticación

Teniendo configurado el adapter ya tenemos todo listo para controlar que los datos sean correctos. El método authenticate() de Zend_Auth recibe el adapter y devuelve una instancia de Zend_Auth_Result a la que le podemos preguntar si el login fue exitoso o no:

$result = Zend_Auth::getInstance()->authenticate($authAdapter);

Zend_Auth_Result

Zend_Auth_Result contiene toda la información sobre el intento de login: si fue válido o no; mensajes de error en caso de que algo haya fallado; información sobre que fue lo que falló, etc. Como su única función es devolver información, solamente tiene cuatro métodos:

  • isValid(): para saber si el login fue correcto o no.
  • getCode(): devuelve el código del error
  • getIdentity(): el nombre de usuario usado en el intento de autenticación
  • getMessages(): los mensajes de error, si hubo alguno

Como dijimos $result contiene los resultados de la autenticación del usuario.

if ($result->isValid()) {
    // los datos del usuario son correctos

    $this->_redirect("/bienvenido");
} else {
    // datos incorrectos, podríamos mostrar un mensaje de error

    switch ($result->getCode()) {
        case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND:
            // usuario inexistente
            break;
        case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
            // password erroneo
            break; 
        default:
            /* otro error */
            break;
    }

}

Persistiendo datos en sesión

Por defecto, Zend_Auth persiste los datos en sesión por medio de Zend_Session. Podemos obtener el storage que representa al namespace de Zend_Auth con

Zend_Auth::getInstance()->getStorage()

En muchas ocasiones nos va a interesar almacenar los datos de la bdd correspondientes al usuario actual. Esto lo podemos lograr por medio del método getResultRowObject() de Zend_Auth_Adapter_DbTable.

Así que lo que vamos a hacer es pedir estos datos y guardarlos en sesión para poder acceder a ellos cuando los necesitemos:

$storage = Zend_Auth::getInstance()->getStorage();
$bddResultRow = $authAdapter->getResultRowObject(); 
$storage->write($bddResultRow);

Luego, en otro lugar de nuestra aplicación podemos acceder a estar información con getIdentity():

$infoUsuario = Zend_Auth::getInstance()->getIdentity();

Preguntar por el usuario actual y finalizar sesión.

Por último, dos cosas que con seguridad necesitaremos hacer: la primera es consultar si hay algún usuario logueado:

$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
    echo "Estas logueado";
} else {
    echo "No estas logueado";
}

Y la otra es realizar el logout:

public function logoutAction() {
    Zend_Auth::getInstance()->clearIdentity();
}

Continuando con la guía:

Este es el capítulo 9 de la Guía Zend y en el transcurso han surgido preguntas que hemos tratado de responder en cada capítulo publicado.

Ir al siguiente capítulo: Review de otros componentes que seguramente vayas a usar