domingo, 7 de julio de 2013

Sesiones en PHP

PHP en cada petición ejecuta el script correspondiente de principio a final. Y hay ocasiones en que sin necesitar la persistencia de datos que ofrece una base de datos, necesitamos almacenar de alguna forma ciertos datos mientras el usuario este utilizando la aplicación/web.
Y al igual que los arrays superglobales asociativos $_GET  y  $_POST existe otro  de especial importancia para dicho almacenamiento de datos: $_SESSION.  Cada vez que un usuario entre en el sitio web, podremos iniciar una sesión con un identificador exclusivo para dicho usuario y se podrán almacenar datos por medio del array $_SESSION hasta que decidamos finalizar una sesión. Dicho ciclo de inicio y fin suele coincidir con login y desconexión del sistema por parte de un usuario.
Internamente, el servidor, almacena los datos del array superglobal de la sesión en un archivo temporal cuyo nombre está formado por 'sess' + dicho ID de sesión (depende de la configuración de php.ini).

Uso de sesiones

1. Inicializando

 session_start();  

Con esta función no solo iniciaremos una nueva sesión particular en el servidor, sino que reanudaremos una posible sesión existente. Ya que al haber iniciado una sesión nueva, el identificador único que se crea es pasado por medio de una cookie al cliente. De esta manera el servidor sabrá si existe una sesión que tiene que recuperar o no. Dicha cookie por defecto se llamará PHPSESSID aunque podremos modificar el nombre en el el archivo php.ini (etc/php5/apach2/php.ini).

Como para la creación y reanudación de sesiones se utilizan cookies internamente, la llamada de esta función debe ser lo primero que haya en cada uno de los scripts en que vayamos a usar sesiones. Realmente no es necesario si se utiliza con cuidado. Pero es aconsejable para asegurarnos de que no haya ninguna salida anterior al envío de la cookie de sesión. Ya que estas se envían con las cabeceras. Y una salida anterior puede provocar el error "headers already sent".
Este problema se explicó en el tutorial http://programandolo.blogspot.com.es/2013/07/redireccionamiento-php.html

2. Almacenamiento datos simples

Para almacenar datos simplemente crearemos un clave dentro del array $_SESSION  y especificaremos el dato que queremos almacenar.

 $_SESSION["username"] = "jose";  

3. Acceso datos simples (enteros, cadenas, arrays)

Y para acceder a un dato simple almacenado en la sesión simplemente accederemos a la clave con la que lo hemos almacenado. Igual que en cualquier array.

 echo $_SESSION["username"]  

4. Almacenamiento y acceso de objetos

Podemos almacenar objetos en la sesión como si de datos simples  se tratarán. Ya que PHP se encarga automáticamente de su serialización. Vamos a ver un ejemplo:

 class sessionUserInfo {  //userInfo.php
   public $username;  
   public $time;  
   public $name;  
   public $email;  
   public function setUsername($x) {  
     $this->username = $x;  
   }  
   public function setTime($x) {  
     $this->time = $x;  
   }  
   public function setName($x) {  
     $this->name = $x;  
   }  
   public function setEmail($x) {  
     $this->email = $x;  
   }  
 }  

 require './userInfo.php';  //ej1.php
 session_start();  
 $user = new sessionUserInfo();  
 $user->setEmail("prueba@ejemplo.com");  
 $user->setName("Santi");  
 $user->setUsername("prueba");  
 $user->setTime(900);  
 $_SESSION['user'] = $user;  
 $_SESSION['autenticado']=1;  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 $b = $_SESSION['user'];  
 $b->setTime(500);  
 $_SESSION['user'] = $b;  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  

y la salida es la siguiente:

 Array  
 (  
   [user] => sessionUserInfo Object  
     (  
       [username] => prueba  
       [time] => 900  
       [name] => Santi  
       [email] => prueba@ejemplo.com  
     )  
   [autenticado] => 1  
 )  
 Array  
 (  
   [user] => sessionUserInfo Object  
     (  
       [username] => prueba  
       [time] => 500  
       [name] => Santi  
       [email] => prueba@ejemplo.com  
     )  
   [autenticado] => 1  
 )  

Por lo que parece que funciona correctamente. Vamos a ver otro ejemplo de como funciona del mismo modo si accedemos desde otro script. Evidentemente estando la sesión aún viva:

 require './userInfo.php';  //ej2.php
 session_start();  
 print_r($_SESSION);  
 echo "<br/>";  
 $user = $_SESSION['user'];  
 $user->setTime(200);  
 print_r($_SESSION);  

Esta es la salida:

 Array ( [user] => sessionUserInfo Object ( [username] => prueba [time] => 500 [name] => Santi [email] => prueba@ejemplo.com ) [autenticado] => 1 )   
 Array ( [user] => sessionUserInfo Object ( [username] => prueba [time] => 200 [name] => Santi [email] => prueba@ejemplo.com ) [autenticado] => 1 )  


5. Destrucción de variables

Para la destrucción de variables tenemos dos funciones. La primera destruirá los datos asociados y la clave especificada del array $_SESSION:

 unset($_SESSION["username"]);  

La segunda de ellas destruirá todas las variables de la sesión, aunque la sesión aún permanecerá activa:

 session_unset();  

6. Destrucción de la sesión actual

Con la siguiente función destruiremos la sesión actual en el servidor. Pero solo destruiremos el fichero almacenado en el servidor para mantener una sesión en particular.

 session_destroy();  

Sin embargo los datos seguirán en el array $_SESSION y lo más importante, la cookie de sesión seguirá existiendo. Por lo que con una llamada a session_start() reanudaríamos la sesión. Entonces session_destroy() es solo la primera parte para la eliminación completa de la sesión.
Para borrar completamente una sesión deberemos de utilizar algo parecido al siguiente código:

 //borramos la cookie de sesión en el servidor  
 if ( isset( $_COOKIE[session_name()] ) ) { 
 setcookie( session_name(), "", time()-3600, "/" );  
 //limpiamos completamente el array superglobal   
 session_unset();
 //Eliminamos la sesión (archivo) del servidor  
 session_destroy();  }

Un ejemplo de como un simple session_destroy() no sirve para eliminar la sesión, lo tenemos en el siguiente ejemplo

 <?php  
 session_start();  
 $_SESSION['prueba1'] = 'abc';  
 $_SESSION['prueba2'] = '123';  
 $_SESSION['prueba3'] = '456';  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba1] => xyz  
   [prueba2] => 123  
   [prueba3] => abc  
 )  
 */  
 unset($_SESSION['prueba1']);  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba2] => 123  
   [prueba3] => 456  
 )  
 */  
 session_destroy();  
 echo '<pre>';  
 print_r($_SESSION);   
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba2] => 123  
   [prueba3] => 456  
 )  
 */   
 ?>  

Vemos como tras el session_destroy() imprimimos la sesión y el array $_SESSION está completamente igual que estaba antes de la llamada a dicha función.

Una llamada  a session_unset() tras un session_destroy() no tiene ningún efecto. Solo es a modo de ejemplo, ya que no es lógico. Pero si llamásemos a $_SESSION = array() si que liberamos los datos del array de sesión en esta situación.


 session_start();  
 $_SESSION['prueba1'] = 'abc';  
 $_SESSION['prueba2'] = '123';  
 $_SESSION['prueba3'] = '456';  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba1] => xyz  
   [prueba2] => 123  
   [prueba3] => abc  
 )  
 */  
 unset($_SESSION['prueba1']);  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba2] => 123  
   [prueba3] => 456  
 )  
 */  
 session_destroy();  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba2] => 123  
   [prueba3] => 456  
 )  
 */  
 session_unset();  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array  
 (  
   [prueba2] => 123  
   [prueba3] => 456  
 )  
 */  
 $_SESSION = array();  
 echo '<pre>';  
 print_r($_SESSION);  
 echo '</pre>';  
 /*  
 Array(  
 )  
  */  

Cookies y sesiones

Con la siguiente función obtenemos los parámetros de la cookie de sesión. Y devolverá un array asociativo con 5 claves y sus valores:
  • "lifetime" - El tiempo de vida de la cookie en segundos.
  • "path" - La ruta en el dominio donde la cookie trabajará. Se puede usar una barra simple ('/') para indicar todas las rutas en el dominio.
  • "domain" - El dominio de la cookie. Para hacer las cookies visibles en todos los sub-dominios, el dominio debe ser prefijado con un punto, como '.ejemplo.com'. 
  • "secure" - La cookie debería ser enviada solamente sobre conexiones seguras si el valor es TRUE .
  • "httponly" - La cookie sólo puede ser accedida a través del protocolo HTTP si el valor es TRUE.

 array session_get_cookie_params ( void )  

 $params = session_get_cookie_params();  
 while (list($clave,$valor) = each($params)) {  
   echo "$clave => $valor <br/>";  
 }  
 /*  
 lifetime => 0   
 path => /   
 domain =>   
 secure =>   
 httponly =>   
 */  

Como se ha comentado en anteriores apartados, al crear una sesión nueva, automáticamente PHP envía una cookie de sesión con unos valores definidos. Que por supuesto que podemos modificar en el archivo de configuración php.ini. Pero existe una función con la que en tiempo de ejecución podemos modificar dicho valores. Y evidentemente se tendrá que ser llamada antes de inicializar una sesión con session_start().

 void session_set_cookie_params ( int $lifetime [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]] )  

 session_set_cookie_params(40 * 60, "/");  
 session_start();  
 print_r(session_get_cookie_params());  
 Array ( [lifetime] => 2400 [path] => / [domain] => [secure] => )  

Y por último tenemos la función para enviar una cookie. Y es importante acordarse que el envío se realice antes de que haya ninguna salida. En ella el único parámetro que no es opcional es $name y que contiene el nombre de la cookie. Importante mencionar el segundo y tercer parámetro ya que los demás ya los hemos mencionado en la funciones anteriores. $value es el valor de la cookie que se va a almacenar en el ordenador del cliente. Y dicho valor va a poder ser consultado en el array asociativo $_COOKIE[$name]. Y $expire indica la fecha de expiración la cookie expresados en segundos Unix. Por lo tanto se expresará en segundos desde la fecha Unix hasta la presente época (eso lo proporciona time()), más los segundos de duración de la cookie. Si se pone a 0 o se omite querrá decir que expira al cerrarse el navegador.

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

Por lo tanto al poder enviar una cookie también podremos modificar una existente. Para ello enviamos una cookie con el mismo nombre (primer parámetro) que una existente.Y si la modificamos con una fecha, en segundos, ya pasada, la eliminaremos. En el siguiente ejemplo pondremos la fecha en segundos de hace una hora. Eso es igual a los segundos actuales desde la fecha Unix - 3600 segundos.

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

Y de esta manera hemos podido eliminar una cookie de sesión. Ya que el navegador encontrará una fecha pasada y eliminará dicha cookie. Que recordemos que no es más que una cookie cuyo nombre es el PHPSESSID (por defecto) y como $value un identificador único.


Entradas relacionadas

Cookies en PHP

No hay comentarios:

Publicar un comentario