Changes
Title
unchanged
Cookie management in Yii
Category
unchanged
How-tos
Yii version
unchanged
Tags
changed
cookies, cookie, chttpcookie, ccookiecollection, safe reading
Content
changed
[...]
```php
$cookie = Yii::app()->request->cookies['cookie_name']->value;
```
See also "Safe reading" in the next chapter.
### Writing a cookie
To write a cookie value, use following code:
```php
Yii::app()->request->cookies['cookie_name'] = new CHttpCookie('cookie_name', $value);
```
Notice, that cookie name must be given twice! See also "Reload required" in the next chapter.
### Deleting a cookie
To delete a cookie, use following code:
```php
unset(Yii::app()->request->cookies['cookie_name']);
```
or you can delete ALL cookies with:
```php
Yii::app()->request->cookies->clear();
```
Notice, that cookie will not be deleted until next page reload - see "Reload required" and "Cookie expiration problem" in the next chapter.
## What to remember about?
### Cookies are objects
Cookies in Yii are read from [CHttpCookie](http://www.yiiframework.com/doc/api/1.1/CHttpCookie/ "") which is **an object**, that's why you have add **->value** to your code (see examples in previous chapter). If you omit that, you'll get warning or error saying that object of class CHttpCookie cannot be converted to a string.
### Safe reading
On the same basis, as above, if a particular cookie does not exists, a corresponding object (CHttpCookie instance) for it will not be created! Trying to read such cookie will result in error "Trying to get property of non-object". It avoid that, it is always better to read a cookie using ternary operator, like that:
```php
$cookie = (isset(Yii::app()->request->cookies['cookie_name']->value)) ? Yii::app()->request->cookies['cookie_name']->value : '';
```
This way, you'll get either cookie value or an empty string.
This example also gives us idea how to check, if particular cookie exits:
```php
$is_cookie = !empty(Yii::app()->request->cookies['cookie_name']->value);
```
### Reload required
Please, remember that server has actually **nothing** to do with the cookies. It only inform browser (in request result) about changes to cookies. Browser is responsible to do the job.
Therefore, cookies changes **are NOT** visible until next reload of page (next request). If you set a cookie value in some place in your code and try to read if few lines below, you'll get empty value or warning (or error in strict PHP mode).
This, of course, goes also to modifying cookie value or deleting them, which also requires reload of a page to succeed. Common pitfall, when developing shopping-cart-like solutions is to delete a cookie and testing if it exists in the same page. This will not work - cookie will not be deleted until next reload.
### Cookie expiration problem
If you set cookie like in above examples, it will be deleted automatically upon closing a browser (or clearing all cookies with proper option). Again - this is browser, not server job. You must close all open windows (copies) of browsers, because only then all cookies will be deleted. In some rare situation (browser hang-up) you can have a hidden copy (window) of a browser still in memory (on processes list) of which you may not be aware. Starting up new copy of browser will then show you all cookies that were meant to be deleted, as existing and having value - that is because that hidden window prevented browser from fully closing itself, and only then deletion of cookies is a fact.
To set a cookie that will not be deleted upon browser closure (like the one in default Yii login screen, where cookie is available for thirty days after last login), you must set it's expiration date. Like that:
```php
$cookie = new CHttpCookie('cookie_name', $value);
$cookie->expire = time()+60*60*24*180;
Yii::app()->request->cookies['cookie_name'] = $cookie;
```
As, you can see - we're setting cookie expiration time **relative** to current time (first common pitfall) and as a timestamp, not date-time variable (second common pitfall). That is, why in above example we used **time()** PHP function.
We're counting expiration time **in seconds** (third common pitfall), so in above example we set cookie expiration date to be _180 days from this moment_, which equal to 15 552 000 seconds, but it is of course easier to write it as equation.
Common settings for cookie expiration time:
- an hour: 3600 seconds,
- an day: 86400 seconds,
- a week: 604800 seconds,
- a month (unified = 30 days): 2592000 seconds,
- a year (unified = 12 months of 30 days): 31104000 seconds.
## Further reading
- [CHttpCookie](http://www.yiiframework.com/doc/api/1.1/CHttpCookie/ "") class reference,
- [CCookieCollection](http://www.yiiframework.com/doc/api/1.1/CCookieCollection/ "") class reference,
- [Handling Cookies](http://www.yiiframework.com/forum/index.php?/topic/15820-handling-cookies "") forum thread,
Please, extend this article, if you find any mistakes or that something is missing here.ince Yii 1.1.11 you can also access the cookie value directly without accessing the value property first.
```php
$value = (string)Yii::app()->request->cookies['cookie_name'];
```
**Note**: You should only use this if you are sure the cookie exists.
Also this may not work on PHP prior to 5.2 (See [PHP.net -> __toString()](http://www.php.net/manual/en/language.oop5.magic.php#object.tostring "PHP.net -> __toString()")).
See also "Safe reading" in the next chapter.
### Writing a cookie
Notice, that you have to specify the name twice, if you want to use this:
```php
Yii::app()->request->cookies['cookie_name'] = new CHttpCookie('cookie_name', $value);
```
See also "Reload required" in the next chapter.
### Configure a cookie
Starting with Yii 1.1.11 you can configure an cookie upon creation.
```php
$cookieCollection['name'] = new CHttpCookie('name', 'value', $options);
```
The option parameter is internally passed to the public method [CHttpCookie::configure()](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#configure-detail "CHttpCookie::configure()") which accepts an array with the following keys:
- [domain](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#domain-detail "domain")
- [expire](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#expire-detail "expire")
- [secure](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#secure-detail "secure")
- [path](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#path-detail "path")
- [httpOnly](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#httpOnly-detail "httpOnly")
### Deleting a cookie
To delete a cookie, use following code:
```php
unset(Yii::app()->request->cookies['cookie_name']);
```
or you can delete ALL cookies with:
```php
Yii::app()->request->cookies->clear();
```
Notice, that cookie will not be deleted until next page reload - see "Reload required" and "Cookie expiration problem" in the next chapter.
## What to remember about?
### Cookies are objects
Cookies in Yii are read from [CHttpCookie](http://www.yiiframework.com/doc/api/1.1/CHttpCookie/ "") which is **an object**. Also it is important to know that
```php
Yii::app()->request->cookies;
```
is an instance of [CCookieCollection](http://http://www.yiiframework.com/doc/api/1.1/CCookieCollection "CCookieCollection") which extends [CMap](http://www.yiiframework.com/doc/api/1.1/CMap "CMap"), therefore it is possible to use simliar to an array.
### Safe reading
On the same basis, as above, if a particular cookie does not exists, a corresponding object (CHttpCookie instance) for it will not be created! Trying to read such cookie will result in error "Trying to get property of non-object". To avoid that, it is always better to read a cookie using ternary operator, like that:
```php
$value = isset(Yii::app()->request->cookies['cookie_name']) ? Yii::app()->request->cookies['cookie_name']->value : '';
// or
$value = Yii::app()->request->cookies->contains('cookie_name') ?
Yii::app()->request->cookies['cookie_name']->value : '';
```
This way, you'll get either cookie value or an empty string.
This example also gives us idea how to check, if particular cookie exits:
```php
$is_cookie = !isset(Yii::app()->request->cookies['cookie_name']);
```
### Reload required
Please, remember that server has actually **nothing** to do with the cookies. It only inform browser (in request result) about changes to cookies. Browser is responsible to do the job.
Therefore, cookies changes **are NOT** visible until next reload of page (next request). If you set a cookie value in some place in your code and try to read if few lines below, you'll get empty value or warning (or error in strict PHP mode).
This, of course, goes also to modifying cookie value or deleting them, which also requires reload of a page to succeed. Common pitfall, when developing shopping-cart-like solutions is to delete a cookie and testing if it exists in the same page. This will not work - cookie will not be deleted until next reload.
### Cookie expiration problem
If you set cookie like in above examples, it will be deleted automatically upon closing a browser (or clearing all cookies with proper option). Again - this is browser, not server job. You must close all open windows (copies) of browsers, because only then all cookies will be deleted. In some rare situation (browser hang-up) you can have a hidden copy (window) of a browser still in memory (on processes list) of which you may not be aware. Starting up new copy of browser will then show you all cookies that were meant to be deleted, as existing and having value - that is because that hidden window prevented browser from fully closing itself, and only then deletion of cookies is a fact.
To set a cookie that will not be deleted upon browser closure (like the one in default Yii login screen, where cookie is available for thirty days after last login), you must set it's expiration date. Like that:
```php
$cookie = new CHttpCookie('cookie_name', $value);
$cookie->expire = time()+60*60*24*180;
Yii::app()->request->cookies['cookie_name'] = $cookie;
```
As, you can see - we're setting cookie expiration time **relative** to current time (first common pitfall) and as a timestamp, not date-time variable (second common pitfall). That is, why in above example we used **time()** PHP function.
We're counting expiration time **in seconds** (third common pitfall), so in above example we set cookie expiration date to be _180 days from this moment_, which equal to 15 552 000 seconds, but it is of course easier to write it as equation.
Common settings for cookie expiration time:
- an hour: 3600 seconds,
- an day: 86400 seconds,
- a week: 604800 seconds,
- a month (unified = 30 days): 2592000 seconds,
- a year (unified = 12 months of 30 days): 31104000 seconds.
## Cookies in JavaScript
By default, you can access your cookies from both PHP code (examples above) and JS code incorporated into your pages. Since JS script handling is entirely done in browser, problems with need of reloading page are not related here.
### httpOnly
[CHttpCookie.httpOnly](http://www.yiiframework.com/doc/api/1.1/CHttpCookie#httpOnly-detail "") property decides, whether particular cookie is available to both PHP and scripting languages. This is default setting (false). By setting it to true, you will rise your application security (this reduces identity theft through XSS attacks), but your cookies will not be available to JS code.
### jQuery
If you're using any widget or other class that is forcing Yii to publish jQuery code, you can make use of jQuery Cookie Plugin (jquery.cookie.js file), that ships with jQuery on-board Yii. Managing cookies this way in JavaScript is extremely easy. For example, to set a cookie, you call:
```php
$.cookie('the_cookie', 'the_value');
```
To read it - use standard jQuery approach of:
```php
var cookie = $.cookie('the_cookie');
```
And to delete cookie, simple set its value to NULL
```php
$.cookie('the_cookie', null);
```
Look for _jquery.cookie.js_ file published in your assets folder and read its head comment for more examples of using cookies with this jQuery plugin.
### Non-jQuery approach
If you don't use jQuery in your application or for other reasons don't want to use jQuery Cookie Plugin, you can use these two functions for accessing cookies in JavaScript:
```php
function readCookie(cookieName)
{
var theCookie = '' + document.cookie;
var ind = theCookie.indexOf(cookieName);
var ind1 = theCookie.indexOf(';', ind);
if(ind1 == -1) ind1 = theCookie.length;
if(ind == -1 || cookieName == '') return '';
return unescape(theCookie.substring(ind + cookieName.length + 1, ind1));
}
function setCookie(cookieName, cookieValue, nDays)
{
var today = new Date();
var expire = new Date();
if(nDays == null || nDays == 0) nDays = 1;
expire.setTime(today.getTime() + 3600000 * 24 * nDays);
document.cookie = cookieName + '=' + escape(cookieValue) + ';expires=' + expire.toGMTString();
}
```
As you can see (second function) - time offset in JavaScript is counted in **miliseconds**, therefore you must recalculate above mentioned example time periods times 1000.
## Further reading
- [CHttpCookie](http://www.yiiframework.com/doc/api/1.1/CHttpCookie/ "") class reference,
- [CCookieCollection](http://www.yiiframework.com/doc/api/1.1/CCookieCollection/ "") class reference,
- [Handling Cookies](http://www.yiiframework.com/forum/index.php?/topic/15820-handling-cookies "") forum thread,
Please, extend this article, if you find any mistakes or that something is missing here.
## Links
[Russian version](http://resurtm.com/working-with-cookies-in-yii)