En este artículo voy a explicar como trabajar con las cookies en CakePHP.
El uso de cookies en aplicaciones web, en todo lo que llevo trabajando, es algo fundamental. Claro está que sean aplicaciones web grandes o portales web donde se necesite registrar algún tipo de dato en cookie y que permanezca un tipo almacenada en el ordenador del usuario.
Con CakePHP el uso de las cookies es relativamente sencillo, igual que si usamos php puro. No hay mucho misterio.
Cakephp crea un componente en su core para trabajar con cookies. Se puede incluir añadiéndolo en el array $components
[code lang=»PHP»]$components = array(‘Cookie’);[/code]
Hay varias funciones básicas para trabajar con el componente de Cookie de CakePHP
La funcion write() que se encarga de guardar una cookie.
write(mixed $identificador_cookie, mixed $valor, boolean $encriptacion, mixed $expiracion)
[code lang=»PHP»]
$this->Cookie->write(‘nombre_cookie’,’Pedro Ventura’);
[/code]
También añadir grupos de cookies especificando un punto en la notificación en el campo $nombre
[code lang=»PHP»]
$this->Cookie->write(‘User.name’, ‘Pedro Ventura’);
$this->Cookie->write(‘User.role’,’Admin’);
[/code]
El tercer parámetro indica si la cookie va encriptada o en claro. Obviamente si encriptamos la cookie ofrecerá mas seguridad. Claro está si se trata de alo irrelevante o no implica información crítica tampoco hará falta encriptar la cookie. Google en algunos casos no encripta sus cookies.
Para más información este es el link de la documentación oficial http://book.cakephp.org/view/180/Using-the-Component
La función read() que se encarga de recuperar el contenido de una cookie especificando su nombre
read(mixed $identificador_cookie)
[code lang=»PHP»]
echo $this->Cookie->read(‘nombre_cookie’);
[/code]
Devolverá: Pedro Ventura
La funcion del(). Elimina una cookie indicando el identificador de cookie.
del(mixed $key)
[code lang=»PHP»]
$this->Cookie->del(‘nombre_cookie’)
[/code]
Después de esta breve introducción en el uso y manejo de las cookies en CakePHP, añado el componente que he desarrollado como sistema de autologin.
Esto es el típico sistema de login directo en caso de que haya marcado en el formulario de login la opción de «manterme logeado» o «No cerrar sesión» (como pone facebook)
Para mas informacion leer todos los comentarios que he dejado en el código del component.
Irá guardado en /app/controllers/components/auto_login.php
[code lang=»PHP»]
<?php
/**
* Clase para generar la cookie y procesar la lógica de la cookie de recuerdo.
* Es la típica acción de "manterme logeado" o "no cerrar sessión".
*
* El componente va a constar de dos partes fundamentales, la creación de la cookie y la comprobación de la misma.
*
* Cuando un usuario se logea, habrá un checkbox que se pueda marcar, activando el desencadenante ("trigger") que llamará a este componente.
* Desde el controlador que comprueba las credenciales del usuario, se llamará a la función guardar_cookie_user() enviando los parámetros necesarios.
*
* No hay que decir, que este componente es para programadores experimentados en cakephp, por lo que los parámetros que se le pueda enviar a esta función
* serán totalmente personalizables a las necesidades de cada código, creando así una cookie específica.
* En el código que he desarrollado, presenta una función standard con unos datos normalmente utilizados a la hora de representar información de un usuario.
*
* La segunda parte del componente, será la de comprobar el status y los datos de la cookie.
* Uno de los campos de la cookie es una cadena de texto hasheada con todos los datos del usuario y una clave "salt"
* (una clave única que creamos para añadir más seguridad a la cadena).
* Tendremos que hacer una comprobacion de la cadena hash con el resto de datos de la cookie.
*
* A la hora de registrar la sesión del usuario o crear la cookie, lo estoy haciendo desde el objeto heredado.
* De manera que lo que hago es esto $this->controller->Session->write y no esto
* $this->Session->write. Hacer esto implica que hay que añadir la clase Sessión en este componente, y puede crear conflicto con la sessión activa sobrescribiendola.
* Por lo normal, lo más aconsejable es no incluir en el array $components el componente de Sessión, e indicar en el archivo core.php que inicialize la session siempre.
*
* @version 1.0
* @uses CakePHP 1.2
* @author Pedro Ventura www.pedroventura.com
*
*/
# en el código añado la siguiente constante en la cookie. Representa el dominio del site.
# utilizada par añadir mas complejidad a la cookie.
# para este ejemplo he indicado en este mismo componente la definición de la constante, pero lo ideal es añadirlo en el bootstrap.php
# también podéis eliminar esta define() y en todos los lugares donde se añade.
define(‘HTTP_DOMINIO’,’www.mi_dominio.com’);
class AutoLoginComponent extends Object
{
var $expires = 15552000; # 6 Meses
var $clave_seguridad = ‘3487t90japAS%242’; # clave usada para crear el hash de la cookie. Añadiendo complejidad adicional a la cadena codificada
var $cookie_name = ‘autoLogin_’;
/**
* seteamos el componente heredando los datos del controller
*
* @param mixed $controller
*/
function startup (&$controller)
{
$this->controller =& $controller;
return true;
}
/**
* Función que guarda la cookie con los datos del usuario.
* Los datos de la cookie van cifrados.
* Al mismo tiempo, se crea un campo hash que esta cifrado con varios parámetros.
* Este campo tendrá que coincidir para crear la sesión automáticamente
*
* @param mixed $id_user
* @param mixed $nombre_user
* @param mixed $email_user
* @param mixed $nick_user
*
* @version 1.0
* @author Pedro Ventura www.pedroventura.com
*/
function guardar_cookie_user($id_user, $nombre_user, $email_user,$nick_user)
{
$cookie = array();
$cookie[‘id’] = $id_user;
$cookie[‘nombre’] = $nombre_user;
$cookie[‘email’] = $email_user;
$cookie[‘nick’] = $nick_user;
$cookie[‘time’] = time();
$cookie[‘hash’] = md5($this->clave_seguridad.$cookie[‘id’].$cookie[‘nombre’].$cookie[‘email’].$cookie[‘nick’].$cookie[‘time’].HTTP_DOMINIO);
# creamos la cookie con el contenido
# el primer parámetro es el nombre de la cookie.
# el segundo parámetros son todos los datos que la cookie va a contener, puede ser un string, un numero entero o un array. En este caso es un array
# el tercer parámetro puede ser true o false. Especifica si se cifra la cookie o irá en claro. Si se pone a true irá cifrada.
# el cuarto parámetro indica el tiempo de expiración, por defecto si no se especifica nada en CakePHP , la cookie espirará con la sesión del usuario
$this->controller->Cookie->write($this->cookie_name, $cookie, true, $this->expires);
# Para realizar pruebas de testeo y debugin no estaría mal guardar un log con las cookies que se van creando.
$this->log(‘guardando cookie para: ‘.$nombre_user. ‘ nick: ‘. $nick_user .’ email: ‘. $email_user . ‘ id: ‘.$id_user. ‘ time :’.$cookie[‘time’],’cookies_log’);
# esto guardará el siguiente log: /app/tmp/logs/cookies_log.log
}
/**
*
* Función para comprobar la existencia de la cookie de recuerdo.
*
* Nueva mejora, si la cookie ha sido leida y se genera la session a partir de ésta, voy a crear una nueva variable de session que
* que marca como se ha leido la cookie y ya no se vuelve a consultar todo el tiempo la cookie.
*
* @param mixed $controller
*
* @version 1.0
* @author Pedro Ventura. www.pedroventura.com
*/
function comprobar_cookie_user()
{
$cookie = $this->controller->Cookie->read($this->cookie_name);
if ($cookie[‘hash’] != md5($this->clave_seguridad.$cookie[‘id’].$cookie[‘nombre’].$cookie[‘email’].$cookie[‘nick’].$cookie[‘time’].HTTP_DOMINIO))
{
$this->delete($this->cookie_name);
return false;
}
else
{
# si los hash coinciden inicio el proceso de login registrando los datos de session.
$this->controller->Session->write(‘User.id’, $cookie[‘id’]);
$this->controller->Session->write(‘User.nombre’, $cookie[‘nombre’]);
$this->controller->Session->write(‘User.email’, $cookie[‘email’]);
$this->controller->Session->write(‘User.nick’, $cookie[‘nick’]);
# guardo una session para que no se vuelva a comprobar la cookie en lo que dure la session del usuario en la aplicacion.
# esta sessión no se leerá en el componenten, sino en el controlador que llama al componente.
$this->controller->Session->write(‘UserCookie.lectura’, 1);
return true;
}
}
/**
* Funcion para borra la cooke de autoLogin.
* Se utiliza desde el mismo componente o se pueda invocar desde un controlador.
*
* @param mixed $nombre_cookie
*/
function delete($nombre_cookie)
{
if(isset($nombre_cookie) && (!empty($nombre_cookie)))
{
$this->controller->Cookie->del($nombre_cookie);
}
}
}
?>
[/code]
A continuació un ejemplo de como se usaría en un controlador.
[code lang=»PHP»]
<?php
/**
* Ejemplo de integracion del componente de AutoLogin en un controlador.
* Un controlador de ejemplo como puede ser usuarios, users, etc…
*
* Se incluye el componente AutoLogin en el array de $components
*
*/
class UsuariosController extends AppController
{
var $components = array(‘AutoLogin’);
/**
* Antes de que se ejecute cada funcion de la clase se ejecuta la funcion beforeFilter
* De esta manera simpre comprobamos la existencia de la cookie.
* En este ejemplo vemos para que sirve la session que hemos seteado en la funcion comprobar_cookie_user()
* La session UserCookie.lectura evita que siempre se esté comprobando la cookie. De manera que tan sólo se realiza una vez que el usuario entra
* en la aplicacion y que se haya comprobado la cookie con exito.
*/
function beforeFilter()
{
parent::beforeFilter();
if($this->Session->read(‘UserCookie.lectura’) != 1)
{
$this->AutoLogin->startup($this);
$this->AutoLogin->comprobar_cookie_user();
}
}
/**
* Funcion que realiza toda la comprobacion de las credenciales del usuario y efectua el login.
*
* Esta función queda abierta al desarrollo de cada programador.
*
* Lo único que yo mostraré es el proceso de generar la cookie.
* Como se puede ver en el código si en el formulario de login han activado el checkbox el valor de éste será 1
* Es nuestro trigger o desencadenante para registrar la cookie en el sistema.
* La variable $user, contiene la informacion de nuestro usuario logeado.
*
*/
function login()
{
// toda la logica para comprobar las credenciales del usuario
# genero la cookie que guarda los datos del usuario
if($this->data[‘Usuario’][‘auto_login_checkbox’] == 1) # esto es el checkbox del formulario de login.
{
$this->AutoLogin->guardar_cookie_user($user[‘id’],$user[‘nombre’],$user[‘email’],$user[‘nick’]);
}
}
}
?>
[/code]
Buenas Pedro, antes de nada, decirte que entré en tu blog hace un par de días y lo veo bastante completo, con información interesante y de la cual se puede aprender mucho, además en los temas que me interesan como son Cakephp, SEO y SEM.
Después de esto, en cuanto al código publicado y viendo otros ‘tutoriales’ sobre el manejo de cookies para la identificación, me gustaría comentarte que aún bien sabiendo que el ejemplo no está completo, ¿no debería de haber una función logout que termine con la cookie en cuestión?
Independientemente de ello, tengo una pregunta y perdona si es algo sencilla quizás (estoy empezando con tecn. web ) pero, ¿qué diferencia encuentras entre comprobar la existencia de una sesión o hacerlo con cookies? Es decir, introduces un elemento que son las Sesiones, pero de igual forma podías no haberlo introducido y consultar si la cookie ya existía. ¿Es tan ventajoso el empleo de Sessiones frente al de Cookies?
Buenas Alberto,
Referente al código publicado, suelo poner código o hablar de ciertos temas que se necesita tener experiencia con Cakephp o en general. Hay ciertas obviedades que no las cuento.
Sobre la funcion de logout, hay una funcion en el componente para eliminar la cookie function delete($nombre_cookie). En tu controlador de usaurios, users, o como lo quieras llamar, es obvio que tendras que tener un logout dentro de tu funcion de logout debes llamar a la funcion function delete($nombre_cookie) del componente para eliminar la cookie.
Sobre la pregunta. Vamos por partes, por un lado necesitas la Session para logearte si o si. O al menos yo lo hago así. Las cookies se suelen usar para dejar cierta informacion relevante pero que no sea critica a nivel de seguridad. Luego esta el usaro de la cookie para generar un autologin que esto ya es otra historia.
Lo normal cuando se hace login es comprobar las credenciales por BBDD y luego generas la session del usuario. Sin cookies. Pero que pasa cuando pones el típico checkbox de mantenerme logeado o no cerrar session? que eso lo tienes que hacer con cookies. Las tienes que codificar y encriptar todo lo que puedes para que sean lo más seguras posibles. Para que a la hora de que el usuario entre en la página se comprueben las cookies automaticamente y si existen y se comprueba la identidad del usuario se generan la session y el usuario se logea automaticamente.
Sobre si es ventajoso el empleo de sessiones frente al de cookies. Todo depende para que las quieras usar. Para hacer un login básico y tener datos de usuario es mejor y más cómodo las sessiones (siempre y cuando tengas una plataforma de servidores bien montada).
como puedo garantizar tiempos rápidos de respuesta en en el procesamiento de datos con CakePHP?
hola te hago una consulta, sirve para paginas web? o solo son para app????
un saludo, y muy buen tuto 😀 ^^