Wie speicher und lade ich Strings in Cookies?

kkapsner

Super Moderator
Da das Thema immer wieder hier auftaucht will ich hier mal an exponierter Stelle meine Cookie-Verwaltung darstellen:
Code:
var cookie = {
	// return value if the name is not stored in document.cookie
	defaultReturnValue: null,
	// this should be true if you want to be sure, that all your special characters (like ä, ö, ü, ², µ, €, \n, \t, ...) are treated in a safe way - but with this option enabled the string stored in the cookie can get much longer
	secureEncoding: true,
	
	update: function(){
		var cString = document.cookie.toString();
		var werte = cString.split(";");
		for (var i = 0; i < werte.length; i++){
			var wert = werte[i].split("=");
			var name = this.decode(wert[0].replace(/^\s+/, ""));
			var value = this.decode(wert.slice(1).join("="));
			this[name] = value;
		}
		return this;
	},
	
	getValue: function(name){
		this.update();
		if (typeof(this[name]) == "string") return this[name];
		return this.defaultReturnValue;
	},
	
	setValue: function(name, value, att){
		//att can contain this attributes: expire, domain, path, secure
		if (!att) att = {};
		var insert = this.encode(name) + "=" + this.encode(value);
		if (att.expire && att.expire.constructor == Date){
			insert += ";expires=" + att.expire.toGMTString();
		}
		if (typeof(att.expire) == "string" && att.expire){
			insert += ";expires=" + att.expire;
		}
		if (typeof(att.domain) == "string" && att.domain){
			insert += ";domain=" + att.domain;
		}
		if (typeof(att.path) == "string" && att.path){
			insert += ";path=" + att.path;
		}
		if (att.secure){
			insert += ";secure";
		}
		document.cookie = insert + ";";
		return this;
	},
	
	deleteValue: function(wert, att){
		if (!att) att = {};
		att.expire = new Date(0);
		this.setValue(wert, "", att);
		if (typeof this[wert] == "string") this[wert] = false;
		return this;
	},
	encode: function encode(str){
		if (this.secureEncoding) return str.replace(/([^a-z0-9])/ig, function(m, f){return "+" + f.charCodeAt(0).toString(36) + "/"});
		return str.replace(/(%|=|;)/g, function(match, f){return "%" + {"%": "%%", "=": "%_", ";": "%."}[f];});
	},
	decode: function decode(str){
		if (this.secureEncoding) return str.replace(/\+([a-z0-9]+?)\//g, function(m, f){return String.fromCharCode(parseInt(f, 36));})
		return str.replace(/%(%|_|.)/g, function(match, f){return {"%": "%", "_": "=", ".": ";"}[f];});
	}
};

Die Anwendung ist recht einfach:
Code:
var name = "³²{};=,&%+/";
var value = ";=;()~ÄÜä\\}]/()";
cookie.setValue(name, value);
var newValue = cookie.getValue(name);
alert(value + " -> " + newValue + ":" + (newValue == value));
cookie.deleteValue(name);
alert(cookie.getValue(name));
- versucht das mal mit den üblichen Cookie-Skripts!

PS: Kommentare, Verbesserungen, Fragen dazu gerne gesehen.
 
Zuletzt bearbeitet:
kleine Verbesserung da att = null einen Fehler verursachen sollte.
Code:
	deleteValue: function(wert, att){
		[B]if (!(att instanceof Object)) att = {};[/B]
		att.expire = new Date(0);
		this.setValue(wert, "", att);
		if (typeof this[wert] == "string") this[wert] = false;
	},
 
Ein schönes Beispiel, wo so alles drin ist was man so für Cookies braucht. Habe selbst noch nicht allzu viel Cookies benutzt. Hab erstmal ein wenig den Code studieren müssen um zu wissen wie ein Ablaufdatum gesetzt wird: als Object!
PHP:
cookie.setValue(name, value, {expire: new Date("2010/2/27 8:26")});
ok ?
Dazu eine Frage:
Warum wird das att so ausgiebig getestet. Sollte nicht der Nutzer des Codes wissen was er will?

kleine Verbesserung da att = null einen Fehler verursachen sollte.

Wer ruft denn eine function mit den att==null auf ???
Wenn ich att weglasse, ist der Wert intern undefined und einen Fehler gibt es auch nicht.
 
ich hab grad gesehen, daß dieser Test auch in setValue() geändert werden muß.
PHP:
	setValue: function (name, value, att)
	{
		//att can contain this attributes: expire, domain, path, secure
		if (!(att instanceof Object)) {
			att = {};
		}
		var insert = this.encode(name) + "=" + this.encode(value);
		if (att.expire instanceof Date) {
			insert += ";expires=" + att.expire.toGMTString();
		}
 
es wäre sicher auch sinnvoll, am Ende von setValue() this.update() aufzurufen, damit die neuen Daten auch über Cookie.name abrufbar sind
 
woher soll ich das wissen, es ist eine öffentliche Methode und daher nicht auszuschließen (irgendeinen DAU gibt es immer). Andernfalls sollte der Test gleich weggelassen werden.

Wenn du schon einen DAU an solche Methoden lassen möchtest, dann ist instanceof Object auch nicht das Allheilmittel, denn:
(function() {}) instanceof Object == true

:D
 
Naja, das macht aber nichts, da eine Funktion durchaus auch ein Object sein kann. Du brauchst in der Funktion halt einfach ein Objekt, geal was für eins.
 
Wenn du schon einen DAU an solche Methoden lassen möchtest, dann ist instanceof Object auch nicht das Allheilmittel, denn:
(function() {}) instanceof Object == true

ja und? das verursacht jedenfalls keinen Fehler, wenn ich versuche: if (att.expire). eine Funktion ist ja schließlich, im Gegesatz zu null, ein Objekt.
 
Das ist doch wirklich Mist, dass null den Typ Object hat...
Hab's oben geändert - ein bisschen einfacher als Dormilich vorgeschlagen.
Das mit dem update ist Geschmackssache, aber wenn man auf der sicheren Seite sein will sollte man ja sowieso über getValue() gehen - dann hat man nämlich auch sicherlich den defaultWert, wenn das Cookie nicht existiert.

Edit: Normalerweise mach' ich das ja mit einer internen Funktion is.object die dann die !is['undefined'], die dann is['null'] aufruft.
 
Zuletzt bearbeitet:
Am besten gefällt mir in diesem Zusammenhang:
Code:
var f = null;
alert(f);
alert(f.toString());
Aber man muss sich hald für seine Überprüfungen seine eigenen Routinen schreiben, die dem Problem aus dem Weg gehen.
 
So müsste es auch gehen:
PHP:
   :
 var insert = this.encode(name) + "=" + this.encode(value);
 if (att) 
   {   
   if (att.expire && att.expire.constructor == Date){
      :

Anstatt ein leeres Object zu setzen den ganzen Zweig garnicht erst ausführen.
 
Vielleicht bringt es dem Thema ja was ein "Praxisbeispiel" zu haben.

Dieses Script benötigt Cookies, und hatte diese auch schonmal bekommen NUR ist das vorige etwas hakig, es funktioniert nur korrekt wenn die Cookies per "Body Onload" geladen werden und dann auch nur mit Verzögerung bis der Body geladen hat, dann wird von einem Skin auf den anderen gewechselt. Das alte Thema ist hier zu finden.

Code:
<script type="text/javascript">
function swapContent(num) {
for(i=0; obj = document.getElementById('content'+ i); ++i)
obj.style.display = 'none';
document.getElementById('content'+ num).style.display = 'inline';
return false;
}
</script>

<a href="#" onclick="return swapContent(0)">1</a>  <a href="#" onclick="return swapContent(1)">2</a>  <a href="#" onclick="return swapContent(2)">3</a>

Wie gesagt, wenn es als Praxisbeispiel taugt, wäre es cool wenn man das benutzen kann, denn mir ist mit JS und Cookies noch alles echt völlig unklar.
 
Bei Nutzung der Cookie-Verwaltung von kkapsner hab ich als value einen numerischen Wert anstelle eines strings übergeben, und promt dafür die Quittung in Form eines Fehlers erhalten. Eine kleine Erweiterung akzeptiert jetzt auch numerische Werte und Datumsobjecte. Datumsobjecte werden mit toLocaleString() umgesetzt, für sonstige unsinnige Werte wird ein leerer String genommen. Beispiele:
Code:
	cookie.setValue("Wert",4532);
        cookie.setValue("Datum",new Date());

Hier der komplette Code der erweiterten Cookie-Verwaltung:

Code:
var cookie = {
        // cookie verwaltung von kkapsner aus forum.jswelt.de
        // gering modifiziert
        // return value if the name is not stored in document.cookie defaultReturnValue: null,
        // this should be true if you want to be sure, that all your special characters (like ä, ö, ü, ², µ, €, \n, \t, ...) are treated in a safe way - but with this option enabled the string stored in the cookie can get much longer
        secureEncoding: true,

        update: function(){
                var cString = document.cookie.toString();
                var werte = cString.split(";");
                for (var i = 0; i < werte.length; i++){
                        var wert = werte[i].split("=");
                        var name = this.decode(wert[0].replace(/^\s+/, ""));
                        var value = this.decode(wert.slice(1).join("="));
                        this[name] = value;
                }
                return this;
        },

        getValue: function(name){
                this.update();
                if (typeof(this[name]) == "string") return this[name];
                return this.defaultReturnValue;
        },

        setValue: function(name, value, att){
                //att can contain this attributes: expire, domain, path, secure
                if(value){
                  if(typeof value == "number") value = value.toString(10);
                  if(typeof value == "object"){
                     if(value.toString(10).length > 20) value = value.toLocaleString();
                          }
                   if(typeof value != "string") value="";//alle sonst Objecte
                  }
                else value="";
                var insert = this.encode(name) + "=" + this.encode(value);
                if (att){
                if (att.expire && att.expire.constructor == Date){
                        insert += ";expires=" + att.expire.toGMTString();
                }
                if (typeof(att.expire) == "string" && att.expire){
                        insert += ";expires=" + att.expire;
                }
                if (typeof(att.domain) == "string" && att.domain){
                        insert += ";domain=" + att.domain;
                }
                if (typeof(att.path) == "string" && att.path){
                        insert += ";path=" + att.path;
                }
                if (att.secure){
                        insert += ";secure";
                }
                }
                document.cookie = insert + ";";
                return this;
        },

        deleteValue: function(wert, att){
                if (!att) att = {};
                att.expire = new Date(0);
                this.setValue(wert, "", att);
                if (typeof this[wert] == "string") this[wert] = false;
                return this;
        },
        encode: function encode(str){
                if (this.secureEncoding) return str.replace(/([^a-z0-9])/ig, function(m, f){return "+" + f.charCodeAt(0).toString(36) + "/"});
                return str.replace(/(%|=|;)/g, function(match, f){return "%" + {"%": "%%", "=": "%_", ";": "%."}[f];});
        },
        decode: function decode(str){
                if (this.secureEncoding) return str.replace(/\+([a-z0-9]+?)\//g, function(m, f){return String.fromCharCode(parseInt(f, 36));})
                return str.replace(/%(%|_|.)/g, function(match, f){return {"%": "%", "_": "=", ".": ";"}[f];});
        }
};

jspit
 
Stimmt - solwohl als Names als auch als Wert durften nur Strings übergeben werden... Aber ich würde das nicht in der setValue regeln, weil das Verwirrung stifften kann:
Code:
var f = 3;
cookie.setValue("name", f);
alert(cookie.getValue("name") + 1)
- ich würde einen TypeError werfen... wie ein Wert in einen String umgewandelt werden soll sollte sich der Nutzer dann selbst überlegen (denkbar wäre auch eine Wrapperfunktion, die dann noch eine JSON-Konvertierung dazwischenschaltet - dann hätte man immer den richtigen Datentyp)

EDIT: auch ein new String("ein ganz langer Text, der wirklich wirchtig ist...") wird bei dir falsch behandelt...
 
Zuletzt bearbeitet:
auch ein new String("ein ganz langer Text, der wirklich wirchtig ist...") wird bei dir falsch behandelt...
Danke, und der Test auf ein Datum ist auch mehr als unglücklich. Der Normalfall für die Übergabe von value ist ein String, auch bei einem Datum gefällt es nicht jedermann wie es per toLocaleString() gemacht wird.
Mit einem string hat man es selbst in der Hand. Ich bin jedoch kein Freund von "Fehler werfen" und versuche jetzt irgendwas Sinnvolles aus der Übergabe zu machen, wenn was anderes als ein String übergeben wird. Der geänderte Code ist sogar noch etwas kürzer und String-Objecte sollten auch wieder funktionieren (Hab ich selbst noch nie gebraucht).
Code:
var cookie = {
        // cookie verwaltung von kkapsner aus forum.jswelt.de
        // modifiziert 01.04.2010 jspit
        // return value if the name is not stored in document.cookie defaultReturnValue: null,
        // this should be true if you want to be sure, that all your special characters (like ä, ö, ü, ², µ, €, \n, \t, ...) are treated in a safe way - but with this option enabled the string stored in the cookie can get much longer
        secureEncoding: true,

        update: function(){
                var cString = document.cookie.toString();
                var werte = cString.split(";");
                for (var i = 0; i < werte.length; i++){
                        var wert = werte[i].split("=");
                        var name = this.decode(wert[0].replace(/^\s+/, ""));
                        var value = this.decode(wert.slice(1).join("="));
                        this[name] = value;
                }
                return this;
        },

        getValue: function(name){
                this.update();
                if (typeof(this[name]) == "string") return this[name];
                return this.defaultReturnValue;
        },

        setValue: function(name, value, att){
                //att can contain this attributes: expire, domain, path, secure
                if(value){
                  if(value instanceof Date) value = value.toLocaleString();
                  else value = value.toString(10);
                  }
                else value="";
                var insert = this.encode(name) + "=" + this.encode(value);
                if (att){
                if (att.expire && att.expire.constructor == Date){
                        insert += ";expires=" + att.expire.toGMTString();
                }
                if (typeof(att.expire) == "string" && att.expire){
                        insert += ";expires=" + att.expire;
                }
                if (typeof(att.domain) == "string" && att.domain){
                        insert += ";domain=" + att.domain;
                }
                if (typeof(att.path) == "string" && att.path){
                        insert += ";path=" + att.path;
                }
                if (att.secure){
                        insert += ";secure";
                }
                }
                document.cookie = insert + ";";
                return this;
        },

        deleteValue: function(wert, att){
                if (!att) att = {};
                att.expire = new Date(0);
                this.setValue(wert, "", att);
                if (typeof this[wert] == "string") this[wert] = false;
                return this;
        },
        encode: function encode(str){
                if (this.secureEncoding) return str.replace(/([^a-z0-9])/ig, function(m, f){return "+" + f.charCodeAt(0).toString(36) + "/"});
                return str.replace(/(%|=|;)/g, function(match, f){return "%" + {"%": "%%", "=": "%_", ";": "%."}[f];});
        },
        decode: function decode(str){
                if (this.secureEncoding) return str.replace(/\+([a-z0-9]+?)\//g, function(m, f){return String.fromCharCode(parseInt(f, 36));})
                return str.replace(/%(%|_|.)/g, function(match, f){return {"%": "%", "_": "=", ".": ";"}[f];});
        }
};
 
Zurück
Oben