runtime-sessions-cookies.md 13.5 KB
Newer Older
1 2 3 4 5 6 7 8
Sesiones (Sessions) y Cookies
=============================

Las sesiones y las cookies permiten la persistencia de datos a través de múltiples peticiones de usuario. En PHP plano, debes acceder a ellos a través de las variables globales `$_SESSION` y `$_COOKIE`, respectivamente. Yii encapsula las sesiones y las cookies como objetos y por lo tanto te permite acceder a ellos de manera orientada a objetos con estupendas mejoras adicionales.


## Sesiones <a name="sessions"></a>

pana1990 committed
9
Como las [peticiones](runtime-requests.md) y las [respuestas](runtime-responses.md), puedes acceder a las sesiones vía el [componente de la aplicación](structure-application-components.md) `session`  el cual es una instancia de [[yii\web\Session]], por defecto.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66


### Abriendo y cerrando sesiones <a name="opening-closing-sessions"></a>

Para abrir y cerrar una sesión, puedes hacer lo siguiente:

```php
$session = Yii::$app->session;

// comprueba si una sesión está ya abierta
if ($session->isActive) ...

// abre una sesión
$session->open();

// cierra una sesión
$session->close();

// destruye todos los datos registrados por la sesión.
$session->destroy();
```

Puedes llamar a [[yii\web\Session::open()|open()]] y [[yii\web\Session::close()|close()]] múltiples veces sin causar errores. Esto ocurre porque internamente los métodos verificarán primero si la sesión está ya abierta.


### Accediendo a los datos de sesión <a name="access-session-data"></a>

Para acceder a los datos almacenados en sesión, puedes hacer lo siguiente:

```php
$session = Yii::$app->session;

// devuelve una variable de sesión. Los siguientes usos son equivalentes:
$language = $session->get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] : null;

// inicializa una variable de sesión. Los siguientes usos son equivalentes:
$session->set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';

// remueve la variable de sesión. Los siguientes usos son equivalentes:
$session->remove('language');
unset($session['language']);
unset($_SESSION['language']);

// comprueba si una variable de sesión existe. Los siguientes usos son equivalentes:
if ($session->has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...

// recorre todas las variables de sesión. Los siguientes usos son equivalentes:
foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...
```

pana1990 committed
67
> Información: Cuando accedas a los datos de sesión a través del componente `session`, una sesión será automáticamente abierta si no lo estaba antes. Esto es diferente accediendo a los datos de sesión a través de `$_SESSION`, el cual requiere llamar explícitamente a `session_start()`.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

Cuando trabajas con datos de sesiones que son arrays, el componte `session` tiene una limitación que te previene directamente de modificar un elemento del array. Por ejemplo,

```php
$session = Yii::$app->session;

// el siguiente código no funciona
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;

// el siguiente código funciona:
$session['captcha'] = [
    'number' => 5,
    'lifetime' => 3600,
];

// el siguiente código también funciona:
echo $session['captcha']['lifetime'];
```

Puedes usar las siguientes soluciones para arreglar este problema:

```php
$session = Yii::$app->session;

// directamente usando $_SESSION (asegura te de que Yii::$app->session->open() ha sido llamado)
$_SESSION['captcha']['number'] = 5;
$_SESSION['captcha']['lifetime'] = 3600;

// devuelve el valor del array, lo modifica y a continuación lo guarda
$captcha = $session['captcha'];
$captcha['number'] = 5;
$captcha['lifetime'] = 3600;
$session['captcha'] = $captcha;

// usa un ArrayObject en vez de un array
$session['captcha'] = new \ArrayObject;
...
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;

// almacena los datos en un array con un prefijo común para las claves
$session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
```

Para un mejor rendimiento y legibilidad del código, recomendamos la última solución. Es decir, en vez de almacenar un array como una única variable de sesión, almacena cada elemento del array como una variable de sesión que comparta el mismo prefijo clave con otros elementos del array.


### Personalizar el almacenamiento de sesión <a name="custom-session-storage"></a>

pana1990 committed
119
Por defecto la clase [[yii\web\Session]] almacena los datos de sesión como ficheros en el servidor. Yii también provee de las siguientes clases de sesión que implementan diferentes almacenamientos de sesión:
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

* [[yii\web\DbSession]]: almacena los datos de sesión en una tabla en la base de datos.
* [[yii\web\CacheSession]]: almacena los datos de sesión en una caché con la ayuda de la configuración del [componente caché](caching-data.md#cache-components).
* [[yii\redis\Session]]: almacena los datos de sesión usando [redis](http://redis.io/) como medio de almacenamiento.
* [[yii\mongodb\Session]]: almacena los datos de sesión en [MongoDB](http://www.mongodb.org/).

Todas estas clases de sesión soportan los mismos métodos de la API. Como consecuencia, puedes cambiar el uso de diferentes almacenamientos de sesión sin la necesidad de modificar el código de tu aplicación que usa sesiones.

> Nota: si quieres acceder a los datos de sesión vía `$_SESSION` mientras estás usando un almacenamiento de sesión personalizado, debes asegurar te que la sesión está ya empezada por [[yii\web\Session::open()]]. Esto ocurre porque los manipuladores de almacenamiento de sesión personalizado son registrados sin este método.

Para aprender como configurar y usar estas clases de componentes, por favor consulte la documentación de la API. Abajo está un ejemplo que muestra como configurar [[yii\web\DbSession]] en la configuración de la aplicación para usar una tabla en la base de datos como almacenamiento de sesión:

```php
return [
    'components' => [
        'session' => [
            'class' => 'yii\web\DbSession',
            // 'db' => 'mydb',  // el identificador del componente de aplicación DB connection. Por defecto'db'.
            // 'sessionTable' => 'my_session', // nombre de la tabla de sesión. Por defecto 'session'.
        ],
    ],
];
```

También es necesario crear la siguiente tabla de la base de datos para almacenar los datos de sesión:

```sql
CREATE TABLE session
(
    id CHAR(40) NOT NULL PRIMARY KEY,
    expire INTEGER,
    data BLOB
)
```

donde 'BLOB' se refiere al BLOB-type de tu DBMS preferida. Abajo está el tipo BLOB que puedes usar para algunos DBMS populares:

- MySQL: LONGBLOB
- PostgreSQL: BYTEA
- MSSQL: BLOB

> Nota: De acuerdo con la configuración de php.ini `session.hash_function`, puedes necesitar ajustar el tamaño de la columna `id`. Por ejemplo, si `session.hash_function=sha256`, deberías usar el tamaño 64 en vez de 40.


### Flash Data <a name="flash-data"></a>

pana1990 committed
166
Flash data es una clase especial de datos de sesión que, una vez se inicialice en la primera petición, estará sólo disponible durante la siguiente petición y automáticamente se borrará después. Flash data es comúnmente usado para implementar mensajes que deberían ser mostrados una vez a usuarios finales, tal como mostrar un mensaje de confirmación después de que un usuario envíe un formulario con éxito.
167

pana1990 committed
168
Puedes inicializar y acceder a flash data a través del componente de aplicación `session`. Por ejemplo,
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

```php
$session = Yii::$app->session;

// Petición #1
// inicializa el mensaje flash nombrado como "postDeleted"
$session->setFlash('postDeleted', 'You have successfully deleted your post.');

// Petición #2
// muestra el mensaje flash nombrado "postDeleted"
echo $session->getFlash('postDeleted');

// Petición #3
// $result será false ya que el mensaje flash ha sido borrado automáticamente
$result = $session->hasFlash('postDeleted');
```

pana1990 committed
186
Al igual que los datos de sesión regulares, puede almacenar datos arbitrarios como flash data.
187 188 189

Cuando llamas a [yii\web\Session::setFlash()]], sobrescribirá cualquier Flash data que tenga el mismo nombre.
Para añadir un nuevo flash data a el/los existes con el mismo nombre, puedes llamar a [[yii\web\Session::addFlash()]].
190
Por ejemplo:
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

```php
$session = Yii::$app->session;

// Petición #1
// añade un pequeño mensaje flash bajo el nombre de "alerts"
$session->addFlash('alerts', 'You have successfully deleted your post.');
$session->addFlash('alerts', 'You have successfully added a new friend.');
$session->addFlash('alerts', 'You are promoted.');

// Petición #2
// $alerts es un array de mensajes flash bajo el nombre de "alerts"
$alerts = $session->getFlash('alerts');
```

> Nota: Intenta no usar a la vez [[yii\web\Session::setFlash()]] con [[yii\web\Session::addFlash()]] para flash data
  del mismo nombre. Esto ocurre porque el último método elimina el flash data dentro del array así que puedes añadir un nuevo flash data con el mismo nombre. Como resultado, cuando llamas a [[yii\web\Session::getFlash()]], puedes encontrarte algunas veces que te está devolviendo un array mientras que otras veces te está devolviendo un string, esto depende del orden que invoques a estos dos métodos.


## Cookies <a name="cookies"></a>

Yii representa cada cookie como un objeto de [[yii\web\Cookie]]. Tanto [[yii\web\Request]] como [[yii\web\Response]]
pana1990 committed
213
mantienen una colección de cookies vía la propiedad de llamada `cookies`. La colección de cookie en la antigua representación son enviadas en una petición, mientras la colección de cookie en esta última representa las cookies que van a ser enviadas al usuario.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269


### Leyendo Cookies <a name="reading-cookies"></a>

Puedes recuperar las cookies en la petición actual usando el siguiente código:

```php
// devuelve la colección de cookie (yii\web\CookieCollection) del componente "request"
$cookies = Yii::$app->request->cookies;

// devuelve el valor "language" de la cookie. Si la cookie no existe, retorna "en" como valor por defecto.
$language = $cookies->getValue('language', 'en');

// una manera alternativa de devolver el valor "language" de la cookie
if (($cookie = $cookies->get('language')) !== null) {
    $language = $cookie->value;
}

// puedes también usar $cookies como un array
if (isset($cookies['language'])) {
    $language = $cookies['language']->value;
}

// comprueba si hay una cookie con el valor "language"
if ($cookies->has('language')) ...
if (isset($cookies['language'])) ...
```


### Enviando Cookies <a name="sending-cookies"></a>

Puedes enviar cookies a usuarios finales usando el siguiente código:

```php
// devuelve la colección de cookie (yii\web\CookieCollection) del componente "response"
$cookies = Yii::$app->response->cookies;

// añade una nueva cookie a la respuesta que se enviará
$cookies->add(new \yii\web\Cookie([
    'name' => 'language',
    'value' => 'zh-CN',
]));

// remueve una cookie
$cookies->remove('language');
// equivalente a lo siguiente
unset($cookies['language']);
```

Además de [[yii\web\Cookie::name|name]], [[yii\web\Cookie::value|value]] las propiedades que se muestran en los anteriores ejemplos, la clase [[yii\web\Cookie]] también define otras propiedades para representar toda la información posible de las cookies, tal como [[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]]. Puedes configurar estas propiedades según sea necesario para preparar una cookie y luego añadirlo a la colección de cookies de la respuesta.

> Nota: Para mayor seguridad, el valor por defecto de [[yii\web\Cookie::httpOnly]] es true. Esto ayuda a mitigar el riesgo del acceso a la cookie protegida por script desde el lado del cliente (si el navegador lo soporta). Puedes leer el [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) para más detalles.


### Validación de la Cookie <a name="cookie-validation"></a>

pana1990 committed
270
Cuando estás leyendo y enviando cookies a través de los componentes `request` y `response` como mostramos en las dos últimas subsecciones, cuentas con el añadido de seguridad de la validación de cookies el cual protege las cookies de ser modificadas en el lado del cliente. Esto se consigue con la firma de cada cookie con una cadena hash, el cual permite a la aplicación saber si una cookie ha sido modificada en el lado del cliente o no. Si es así, la cookie no será accesible a través de [[yii\web\Request::cookies|cookie collection]] del componente `request`.
271

pana1990 committed
272
> Información: Si falla la validación de una cookie, aún puedes acceder a la misma a través de `$_COOKIE`. Esto sucede porque librerías de terceros pueden manipular de forma propia las cookies, lo cual no implica la validación de las mismas.
273 274 275 276 277

La validación de cookies es habilitada por defecto. Puedes desactivar lo ajustando la propiedad [[yii\web\Request::enableCookieValidation]] a false, aunque se recomienda encarecidamente que no lo haga.

> Nota: Las cookies que son directamente leídas/enviadas vía `$_COOKIE` y `setcookie()` no serán validadas.

pana1990 committed
278
Cuando estás usando la validación de cookie, puedes especificar una [[yii\web\Request::cookieValidationKey]] el cual se usará para generar los strings hash mencionados anteriormente. Puedes hacerlo mediante la configuración del componente `request` en la configuración de la aplicación:
279 280 281 282 283 284 285 286 287 288 289 290 291

```php
return [
    'components' => [
        'request' => [
            'cookieValidationKey' => 'fill in a secret key here',
        ],
    ],
];
```

> Información: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] es crítico para la seguridad de tu aplicación.
  Sólo debería ser conocido por personas de confianza. No lo guardes en sistemas de control de versiones.