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:
bake: function(cookieName,cookieValue,days,path){fetch: function(cookieName){crumble: function(cookieName){- 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:
// set a cookie named 'admin' with a value of 'Harmen' to expire after 2 dayscookiejar.bake ('admin', 'Harmen', 2);// alert the value of the cookie named 'admin'alert (cookiejar.fetch('admin'));// remove the cookiecookiejar.crumble('admin');- 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:
admin_name=Harmenadmin_age=22admin_homepage=whatstyle.net- Download this code: /code/subcookies3.txt
If we use subcookies to store this data, our cookie could look like this:
admin=name:Harmen/age:22/homepage:whatstyle.net- 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:
admin_homepage=http://www.whatstyle.net- 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
fetchmethod fetches the value of the subcookie namedsubcookieNameinside cookiecookieName. 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 namedsubcookieName. 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 providedaysandpathparameters, which, naturally, function in the same way as they do in thebakemethod. Note that you can delete the entire cookie withcookiejar.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:
// create the 'cookie' objectvar c = {name : 'Harmen',age : 22,homepage : http://www.whatstyle.net};// create the cookiesubcookiejar.bake ('admin', c, 2);// alert the subcookie 'name'alert (subcookiejar.fetch('name'));// crumble only the subcookie 'age'subcookiejar.crumble ('admin','age',2);// crumble entire cookiecookiejar.crumble('admin');- 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.
Filed under Javascript
- ← previous article: Installing PHPEclipse on Ubuntu Feisty Fawn
- → next article: Subcookies, the PHP version
Comments:
This little script is made of awesome. Exactly the kind of thing I was looking for, and very elegantly accomplished. Thanks!
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
Jim, that's a good change, I didn't think of that.
Glad you like it :)
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.
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
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 :)
I sure will! :)
Thank you very much for your fast response!
Any news about this script?
I really would like to incorporate it in some of my personal projects.
This article is full of WIN! Thanks for taking the time to share with us!
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.
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.
@Roch; this is default behaviour. I would just boolean test it if I were you. Like this:
if (!value) {
}
Thanks man.
You have been a great help.
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.
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!
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!
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!!
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.
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.
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.
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!
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.