Take your cookies to the next level with Subcookies

Posted on 27 May 2007 (01:30 AM)

Cookies provide an easy way to save some user data. They can be a nice aid in usability, as they give you a way of remembering certain choices made by the user.

Browsers have placed some restrictions on the storage capacity of a cookie, though. They usually allow only 20 cookies to be stored per domain or server. To circumvent this problem, I'll explain a technique called "subcookies" to you and show you an easy Javascript way of accessing the so-called subcookies.

The article has been down for a day, unfortunately, due to a PHP error. I'm terribly sorry! The article is fixed now, do check it out :)

Access to regular cookies

First, let's take a quick look at the cookiejar object. An object I've written to provide easy access to cookies. First of all; the functionality of the object is written by Peter-Paul Koch (http://www.quirksmode.org/js/cookies.HTML). All I did was wrap it all in one object and add automatic escaping of cookie data. Credit where credit's due, eh? :)

The cookiejar object has three methods:

  1. bake: function(cookieName,cookieValue,days,path){
  2. fetch: function(cookieName){
  3. crumble: function(cookieName){
  4. Download this code: /code/subcookies1.txt

The bake method creates a new cookie. Parameters are the name of the cookie, the value of the cookie, the days (as an integer) after which the cookie will expire and the path in which the cookie is accessible.
The fetch method is used to get the value of a given cookie. It takes one parameter; the name of the cookie. Lastly, the crumble method destroys a cookie, which name is given in the only parameter.

Example:

  1. // set a cookie named 'admin' with a value of 'Harmen' to expire after 2 days
  2. cookiejar.bake ('admin', 'Harmen', 2);
  3.  
  4. // alert the value of the cookie named 'admin'
  5. alert (cookiejar.fetch('admin'));
  6.  
  7. // remove the cookie
  8. cookiejar.crumble('admin');
  9. Download this code: /code/subcookies2.txt

Access to subcookies

The principle behind subcookies is simple: store multiple values in one cookie. That way, you can store more data without exceeding the browser limit of 20 cookies per domain or server.

It's important to separate your name/value pairs with certain custom characters (characters that are unlikely to appear in a cookie's value). For instance, let's look at these cookies:

  1. admin_name=Harmen
  2. admin_age=22
  3. admin_homepage=whatstyle.net
  4. Download this code: /code/subcookies3.txt

If we use subcookies to store this data, our cookie could look like this:

  1. admin=name:Harmen/age:22/homepage:whatstyle.net
  2. Download this code: /code/subcookies4.txt

Notice I use a colon (":") as the name/value separator, and a slash as the subcookie separator ("/").

Now I can store as much data as I'd like, unrestricted by the browser's cookie limit!

Drawbacks

Before looking at the subcookiejar object, there are some things to keep in mind when using subcookies. First, domains (or servers) are only allowed to store 4KB of data (4096 characters). Yes, you could save all your data inside one cookie, but don't overdo it.

Second, some care must be taken in picking separating characters. In the cookies.js file you can download at the bottom of this page, I use $$:$$ as a name/value separator and $$/$$ as the subcookie separator. These character combinations are highly unlikely to be found inside actual cookie values. Always think about your separators. A separator which appears inside your cookie data will split up the value. Consider, for instance, this cookie:

  1. admin_homepage=http://www.whatstyle.net
  2. Download this code: /code/subcookies5.txt

If I were to use the slash and colon mentioned above, the value would break on the "http://" prefix.

The subcookiejar object

The subcookiejar object sports the same bake, fetch and crumble methods the cookiejar object does, but they take different parameters.

bake (cookieName,subcookieObj,days,path)
Sets a new cookie, subcookie-style.
cookieName
The name of the cookie
subcookieObj
An object which members represent the subcookie's name. The value of that member will be the value of the subcookie.
days
The days (as an integer) after which the cookie will expire.
path
The path that has access to this cookie.
fetch (cookieName,subcookieName)
The fetch method fetches the value of the subcookie named subcookieName inside cookie cookieName.
crumble (cookieName,subcookieName,days,path)
Unfortunately, crumbling a given subcookie works different from crumbling a regular cookie. It loops through all the values inside the given cookie (named cookieName), until it finds the subcookie named subcookieName. It removes this subcookie from the data and creates a new cookie containing all other name/value pairs present in the cookie. Therefore, you have also have to provide days and path parameters, which, naturally, function in the same way as they do in the bake method. Note that you can delete the entire cookie with cookiejar.crumble

That's all there is to it! You can access the separators through subcookiejar.subcookieSeparator and subcookiejar.nameValueSeparator if you'd like to change those.

Example:

  1. // create the 'cookie' object
  2.  
  3. var c = {
  4. name : 'Harmen',
  5. age : 22,
  6. homepage : http://www.whatstyle.net
  7. };
  8.  
  9. // create the cookie
  10.  
  11. subcookiejar.bake ('admin', c, 2);
  12.  
  13. // alert the subcookie 'name'
  14.  
  15. alert (subcookiejar.fetch('name'));
  16.  
  17. // crumble only the subcookie 'age'
  18.  
  19. subcookiejar.crumble ('admin','age',2);
  20.  
  21. // crumble entire cookie
  22.  
  23. cookiejar.crumble('admin');
  24.  
  25. Download this code: /code/subcookies6.txt

Download the file

You can download the entire cookies.js file and use it freely. Do leave a comment and tell me what you think of this technique, or tell me how I can improve it.

Note: I've written an updated version to this script. Click here to download Version 2, or click here to read the new article.

Back to top

Filed under Javascript

Comments:

  1. 19 July 2007 (07:16 AM) by Adam Messinger

    This little script is made of awesome. Exactly the kind of thing I was looking for, and very elegantly accomplished. Thanks!

  2. 20 September 2007 (03:18 PM) by Jim Thomson

    Great script. I did make one change in subcookie.fetch. After getting the cookie value, I check to make sure it was actually found before looking for the subcookie because I was getting an error if none was found:

    var cookieValue = cookiejar.fetch(cookieName);

    //make sure a cookie was found than proceed

    if(cookieValue)

    {

    var subcookies = cookieValue.split(subcookiejar.subcookieSeparator);

    for (var i=0; i<subcookies.length; i++)

    {

    var sc = subcookies[i].split(subcookiejar.nameValueSeparator);

    if (sc[0]==subcookieName) return sc[1];

    }

    }

    return null;

    this comment has been quoted by Harmen Janssen

  3. 20 September 2007 (04:28 PM) by Harmen Janssen

    Jim Thomson wrote:

    Great script. I did make one change in subcookie.fetch. After getting the cookie value, I check to make sure it was actually found before looking for the subcookie because I was getting an error if none was found:

    var cookieValue = cookiejar.fetch(cookieName);

    //make sure a cookie was found than proceed

    if(cookieValue)

    {

    var subcookies = cookieValue.split(subcookiejar.subcookieSeparator);

    for (var i=0; i

    {

    var sc = subcookies[i].split(subcookiejar.nameValueSeparator);

    if (sc[0]==subcookieName) return sc[1];

    }

    }

    return null;

    Jim, that's a good change, I didn't think of that.

    Glad you like it :)

  4. 16 December 2007 (03:34 PM) by just-thinking

    instead of "/" you can build the whole cookie value as pairs using just ":". this is how i did it and while you still have one char you hope nobody wants to use in their value, it's the fewest possible.

  5. 26 March 2008 (03:03 PM) by C

    I find very intersting this approach to manage cookies, but:

    when you create the subcookie its value will override the existent value stored in the main cookie... :(

    Is this normal? I mean, is this how it is supposed to happen?

    Shouldn't the subcookie value be added in the main cookie without overriding the original value?

    Thank you in advance. :)

    this comment has been quoted by Harmen Janssen

  6. 26 March 2008 (07:01 PM) by Harmen Janssen

    C wrote:

    I find very intersting this approach to manage cookies, but:

    when you create the subcookie its value will override the existent value stored in the main cookie... :(

    Is this normal? I mean, is this how it is supposed to happen?

    Shouldn't the subcookie value be added in the main cookie without overriding the original value?

    Thank you in advance. :)

    Hmm, I see what you mean.

    For now; try and fetch the existing subcookies, construct an object including the new subcookies you wish to append and overwrite the existing cookie.

    I will rewrite the code to fix the problem in the near future. Keep an eye on your RSS reader :)

  7. 26 March 2008 (09:16 PM) by C

    I sure will! :)

    Thank you very much for your fast response!

  8. 09 May 2008 (01:03 PM) by C

    Any news about this script?

    I really would like to incorporate it in some of my personal projects.

  9. 16 October 2008 (07:52 PM) by Chris

    This article is full of WIN! Thanks for taking the time to share with us!

  10. 11 November 2009 (12:31 AM) by Alan Pearson

    Why do this? Cookies are meant to hold small amounts of state information, if you have a lot of info you need it should be stored and retrieved server-side via the SID in the cookie. Cookies are not meant to be a database.

  11. 04 January 2010 (02:38 PM) by Roch

    Hi, Thanks a lot for this.It really helped me solve a great problem.Though I am stuck at one point -

    When I am deleting a cookie using cookiejar.crumble('admin')

    It gets deleted but if you fetch with that name it will give you a blank value.How can I skip these values and display only cookies with some values.

    Thanks.

  12. 04 January 2010 (02:41 PM) by Harmen Janssen

    @Roch; this is default behaviour. I would just boolean test it if I were you. Like this:

    if (!value) {

    }

  13. 05 January 2010 (05:05 AM) by Roch

    Thanks man.

    You have been a great help.

  14. 05 January 2010 (05:21 AM) by Roch

    One more thing , if you can help me with this it will be great.

    I am storing records in cookies so for that I am generating them at a button event.

    How can I keep tab on the count of cookies generated?

    Sorry if the question is lame since I am very new to this.

  15. 05 January 2010 (07:15 AM) by Roch

    Hey I got a workaround for th earlier problem.

    However I am stuck at another one now.

    As I said I am generating subcookies at runtime so

    c = {

    txt1: document.getElementById("txt1").value,

    txt2: document.getElementById("txt2").value,

    txt3: document.getElementById("txt3").value

    };

    In place of txt1 I want something like an array[0] or eval("txt"+i) where i=1.

    I have tried everything but it always comes in conflict with the seperator :

    Can you help me with this?

    Thanks in advance!

  16. 05 January 2010 (10:58 AM) by Harmen Janssen

    So you want to have dynamic keys?

    You could do this:

    var c = {};

    c["txt"+1] = "my value";

    c[array[0]] = "my other value";

    And just a quick tip; try never to use eval()! In Javascript you can just use "+" and the resulting value will be a concatenated string.

    Let me know if this helps!

  17. 06 January 2010 (09:53 AM) by Roch

    Thanks a million....

    You have really been a great help.

    I hope I am able to sail through without any difficulty now.

    Even if I get stuck somwhere I know whom to ask it.

    Thanks again!!

  18. 07 January 2010 (06:51 AM) by Roch

    Hi Harmen, Your code is working like a charm but it is giving me problems at one point.

    As I said I am generating dynamic cookies ,

    arr[1] = document.getElementById("gvHeader1").rows[0].cells[0].innerText;

    //I am taking value from a gridview and putting it into an array.

    Data[arr[1]] = document.getElementById("GridView11_ctl02_D" + 1).value;

    //A dropdown value is put into the Data var.

    If I check using alert statement I am getting all the values,however when I make a cookie and give a statement

    alert(admin.Activity);

    even if i give alert(Data["Activity"]);

    I am still getting undefined.

    Activity - getting it from the gridview

    Am i missing something here.

  19. 07 January 2010 (01:02 PM) by Harmen Janssen

    First of all, in Firebug, run

    console.dir(admin)

    That way, you can see exactly what is in that object. Use this to check where it went wrong, because it looks like somewhere in your code the wrong values get assigned in the wrong places.

  20. 11 January 2010 (06:23 AM) by Roch

    Hi Harmen,

    I was able to figure out the problem there.I don't know for what reason it wasn't detecting the gridview control.So I had to take the values from somewhere else.

    Just one more doubt, Can we acces these cookies server side - in ASP.

    I tried using request.cookies("Name")

    But i didn't work.

    Thanks for all the help.

  21. 11 January 2010 (10:56 AM) by Harmen Janssen

    Roch, I'm glad you were able to solve your problem.

    In regards to the server-side; yes, cookies set can be accessed either by the client-side or the server-side. I'm not sure how this works in ASP, since I'm a PHP guy myself, but again; the best debugging practice in any language is inspection.

    Thru the course of your program, print variables, extract and print arrays, et cetera. If you don't find the value in an array you expect to find there, print that entire array and check what IS contained in it. That might provide insight into how that array stores its values.

    Good luck!

  22. 01 February 2010 (06:48 AM) by Roch

    Hi Harmen,

    I have ran into trouble in your code lately.

    When you fetch your cookie

    var admin = subcookiejar.fetch('cookiename');

    if my subcookie has keys like Case Type

    So alert(admin.Case Type) is giving me an error.

    Can you tell me how to overcome that space in key values.

    Just to note : I am storig key values in array and those are dynamic so I have to can't remove spaces.

    Thanks again.

Leave a comment

RE: Take your cookies to the next level with Subcookies

Note to spammers: rel="nofollow" will be added to links. If I consider your comment spam, your IP-address might get blocked.

HTML not allowed. URLS will be auto-linked. Maximum length is 1250 characters.

I understand this is inconvenient, but the spam I'm receiving on this website is driving me nuts. Please forgive me and cope with it until I find a better solution.

Mandatory fields are marked by an asterisk (*).

Increase textarea-size Decrease textarea-size

Back to top

Preferences

These settings will be saved for your convenience.