miércoles, 10 de julio de 2013

Cookies en PHP

Básicamente una cookie es un fichero de texto almacenado en el navegador de un cliente por orden de un sitio web. En estos ficheros, de tamaño máx. 4 KB se almacena información útil para el servidor como podría ser información del último acceso o información para la personalización de la web de un usuario concreto. Una cookie solo puede ser leída por el sitio web (dominio) que la creó.
Hay un limite de cookies que el navegador puede almacenar:
- 20 cookies para un servidor o dominio
- 300 cookies en total.
Ya que estas se almacenan en el disco duro del usuario, hay que tener cuidado con la posibilidad de que dicho usuario desactive su uso. En dicho caso no se almacenarán. Por lo que hay que tener previsto otro tipo de almacenamiento si la persistencia de información en cookies es indispensable para el sitio web.

Una cookie se envía junto a las demás cabeceras HTTP. Por lo tanto se exige lo mismo que exigíamos cuando queríamos enviar dichas cabeceras. Que no haya ninguna salida (elemento html, espacio en blanco o salida del script) anterior al envío. http://programandolo.blogspot.com.es/2013/07/redireccionamiento-php.html

Un ejemplo de cabeceras HTTP con envío de cookies:

 HTTP/1.0 200 OK  
 Content-type: text/html  
 Set-Cookie: MyCookieName=MyCookie; path=/; expires= Fri 08-Jan-1999 13:00:00 GMT  

Como se observa, cada cookie se enviará tras la cabecera "Set-Cookie" y cada atributo de la misma irá separado por ";".

Atributos 

Cada cookie contiene 6 pares de atributo-valor que la definen:
  • Name: nombre que identifica la cookie y su valor. Por ejemplo  PHPSESSID = e85d1da.... Es el único campo obligatorio a la hora de enviar una cookie.
  • Domain: define el dominio asociado con la cookie. Solo páginas de dicho dominio podrán acceder a la cookie. Por ejemplo Domain = www.blogger.com. Si queremos que la cookie sea visible en todos los subdominios añadiremos un "." delante del dominio. Por ejemplo Domain = .blogger.com
  • Path: especifica en que secciones del dominio anteriormente definido pueden acceder a la cookie. Si se utiliza "/" significa que todo el dominio especificado puede acceder a la cookie. Por ejemplo Path = /.
  • Expires: Define hasta que fecha será válida la cookie. Si se especifica una fecha ya pasada, el navegador eliminará la cookie. Por lo que un método de asegurarnos de borrar una cookieseria el siguiente: enviar una cookie con valor ya existente (para que sea sustituida) una fecha de expiración en pasado. Por ejemplo Expires = Friday, 25-Jan-08 23:59:50 IST. Si no se especifica, la cookie durará hasta que se cierre el navegador.
  • Secure: Especifica si una conexión segura debe ser necesaria para el envío de la cookie. Por ejemplo Secure =  True.
  • HttpOnly: Este último atributo especifica si la cookie solo puede ser enviada mediante el protocolo HTTP o puede ser enviada también, por ejemplo, mediante JavaScript. Por ejemplo HttpOnly = True.
Envío de cookies


Mediante la siguiente función PHP enviaremos una cookie en las cabeceas HTTP.

 bool setcookie ( string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )  

Como vemos los parámetros a enviar son los mencionados en el apartado anterior y la mayoría de ellos son opcionales (a excepción del nombre $name) ya que tienen unos valores por defecto.
Hay que tener en cuenta dos cosa importantes con la fecha de expiración $expire:
- La fecha se enviará en segundos Unix. Para ello es útil la función time() que nos devuelve dichos segundos hasta el momento presente. Por lo tanto mediante time() + X segundos formaremos la fecha de expiración.
- Una fecha en pasado hará que el navegador elimine una cookie. Así, si especificamos time()-3600, por ejemplo, indicaremos una fecha pasada en una hora.
- Si dejamos el valor por defecto quiere decir que la cookie se eliminará cuando cerremos el navegador.

Además es posible enviar multiples cookies simplemente mediante una llamada a setCookie() por cada cookie que queramos enviar.

 setcookie("cookie", "valor", time() + 3600);   
 setcookie("cookie2", "valor2", time() + 3600, "/", ".midominio.com");  

Acceso a cookies

Cada vez que el cliente hace una petición HTTP al servidor, en las cabeceras también viajan las cookies accesibles al dominio del servidor. Y en PHP podemos acceder a sus valores mediante el array asociativo superglobal $_COOKIE. De esta forma podríamos acceder al valor de las cookies como haríamos en cualquier array; accediendo a la clave (nombre de la cookie) del array:

 if(isset($_COOKIE['cookie'],$_COOKIE['cookie2'])){  
   echo $_COOKIE['cookie'];  
   echo $_COOKIE['cookie2'];  
 }  

Cada cookie será un elemento del array identificada por su clave que será el nombre de dicha cookie. Los demás atributos que especificamos al crear la cookie solo son útiles para el navegador. Por lo que no podremos acceder a ellos desde el citado array.

Ejemplos de uso 

- Eliminación de cookie de sesión

Suponemos que se ha creado una sesión en el servidor, por lo que se habrá enviado una cookie de nombre PHPSESSID y como valor el identificador de la sesión creada. Tanto el nombre y demás parámetros (dominio, tiempo de vida..) podremos configurarlos en el archivo etc/php5/apach2/php.ini o mediante la función session_set_params() http://programandolo.blogspot.com.es/2013/07/sesiones-php.html.
Por lo tanto si enviamos una cookie con el mismo nombre y con un tiempo de expiración ya pasado (por ejemplo en una hora) el navegador eliminará la cookie.

  setcookie( session_name(), "", time()-3600, "/" );   

Nota: La función session_name() devuelve el nombre de la sesión actual. Como se ha mencionado, podemos modificarlo si queremos para que no sea PHPSESSID. El nombre de la sesión no puede consistir en solo valores númericos. Y solo admite valores alfanuméricos.

- Recordar usuario

El uso de cookie en las identificaciones de sistemas es muy común cuando se quiere almacenar información para dar acceso a un usuario ya identificado. Sin necesitad de que introduzca nuevamente los datos de dicha identificación. Para ello podemos crear una cookie en el navegador del cliente que contenga un valor identificativo del mismo para que el servidor sepa que ya se ha identificado.
Siempre es conveniente minimizar el alcance de los fallos de seguridad. Por lo tanto es importante no enviar en la cookie el login y la contraseña de usuario en texto plano (utilizaremos un hash). Ya que de esta manera si alguien consiguiera interceptar la cookie podría entrar en la sesión pero no realizar operaciones que requieran introducir la contraseña. Ya que no dispone de ella. Así limitaremos que tenga acceso total.

 <?php  
 if(!isset($_SESSION['username'])) {  
      if(isset($_COOKIE['username'],$_COOKIE['password'])) {  
           //consultamos en la BBDD si existe el usuario o no  
           if(existeUsuario($_COOKIE['username'], $_COOKIE['password'])) {  
                $_SESSION['username'] = $_COOKIE['username'];  
                header("location: home.php");  
                exit();  
           }  
      }  
      else if(isset($_POST['username'],$_POST["password"],$_POST['autologin']){   
           //habría que validar los datos  
           $username = trim($_POST['username']);  
           $password = sha1(trim($_POST['password']));  
           $autologin = $_POST['autologin']; //checkbox "recordarme"  
           //consulamos en la BBDD si existe el usuario o no  
           if(existeUsuario($user,$password))   
           {  
                $_SESSION['username'] = $user;  
                if($autologin == 1)  
                {  
                     //duración de la cookie 1 día  
                     setcookie('username', $username, time() + 7*24*3600);  
                     setcookie('password', $password, time() + 7*24*3600);  
                } else {  
                      //destroy alguna cookie de indentificación anterior  
                      setcookie('username', '', time() - 7*24*3600);  
                      setcookie('password', '', time() - 7*24*3600);  
                }  
                header("location: home.php");  
                exit();  
           }  
      }  
 }else{  
      //si ya existe sesión es porque nos hemos identificado anteriormente  
      header("location: home.php");  
      exit();  
 }  
 //si no existe sesion o cookie correcta o no hay envío de post se mostrará la salida inferior del formulario  
 //vamos que si no ha entrao por ninguno de los header() se muestra el formulario  
 ?>  
 <html>  
 <head></head>  
 <body>  
      <form name="login" method="post" action="">  
           <fieldset><legend>Authentication</legend>  
           <p><label>Username</label><input id="name" type="text" name="username"></p>  
           <p><label>Password</label><input type="password" name="password"></p>  
           <p><input type="checkbox" name="autologin" value="1">Recordarme</p>  
           <p><input id="submit" type="submit" name="submit" value="Login"></p>  
      </form>  
 </body>  
 </html>  

La combinación de cookies y sesiones es necesaria, ya que en una aplicación real, la sesión caducará en relativamente poco tiempo o cuando pasen un periodo de inactividad. Por ejemplo guardando en sesión el tiempo Unix (time()) con el que se accede a un script y comprobar si ha pasado tiempo limite al acceder a otro de los scripts del servidor.
Y gracias a las cookies, en este ejemplo, durante 1 semana podremos entrar sin tener que volver a identificarnos.

- Opciones de configuración del usuario

El almacenamiento de preferencias de un usuario es uno de los principales usos de las cookies. Vamos a ver un ejemplo de como podríamos usar las cookies para almacenar el idioma en el que el usuario quiere la página web multidioma.

Ejemplo de script PHP encargado de guardar y leer una cookie para el idioma del cliente que accede a la web. Evidentemente será incluido al principio del script encargado de mostrar la página.

 if (isset($_GET['idioma'])) {   
   $idioma = $_GET['idioma'];  
   setcookie("idioma", $idioma, time()+604800);//duración de 1 semana  
   header('Location: ' . $_SERVER['PHP_SELF']);  
 }  
 function cargar_idioma() {  
   if (isset($_COOKIE['idioma'])) {  
     include('idiomas/' . $_COOKIE['idioma'] . '.php');  
   } else {  
     $idioma = $_SERVER["HTTP_ACCEPT_LANGUAGE"];  
     $pos_es = stripos($idioma, 'es');  
     $pos_va = stripos($idioma, 'ca');  
     if ($pos_es > $pos_va) {  
       include('idiomas/va.php');  
     } else {  
       include('idiomas/es.php');  
     }  
   }  
 }  
 cargar_idioma();  


- Carrito de compra

Usar cookies para webs en las que  se realizan compras (carrito/cesto de compra) es una opción. Sin embargo, necesita continuos intercambios de información entre cliente y usuario, por lo que hay que tener más cuidado con la seguridad. Además tiene un limite más pequeño de información a almacenar respecto a otras alternativa. Por lo tanto es más conveniente el uso de sesiones o si es posible de tablas de bases de datos temporales. Pero vamos a ver un pequeño ejemplo de como podría realizarse:

En este ejemplo por cada producto que queramos comprar se generará una cookie()

 if(isset($_POST['codProducto'],$_POST['cantidad']))  
 {  //falta comprobar que el tipo de los datos pasados y si existe o no el código de producto
   $nom="cart_".$_SESSION["usuario"];  
   setcookie($nom."_".$_POST["codProducto"],$_POST["cantidad"],time()+3600);   
 }  

 //verCarro.php  
 foreach($_COOKIE as $clave => $cantidad){  
   $cad = "cart_jose_1000";  
   $aux = explode("_",$cad);  
   $codProd = $aux[2];  
   //calcular coste  
 }  

Finalmente para eliminar un producto de la cesta, eliminaremos la cookie de ese producto

 if(isset($_GET["codProducto"]))  
 {  //falta la comprobación de si el código de producto existe y es un entero
   $nom="cart_".$_SESSION["usuario"];  
   setcookie($nom."_".$_GET["codProducto"],"",time()­-3600);  
 }  


No hay comentarios:

Publicar un comentario