Normalerweise hat man keine Möglichkeit, über JavaScript-Code auf die Festplatte des Client-Rechners1 zuzugreifen. Dies muss so sein, denn nur so kann die Sicherheit des Client-Rechner gewährleistet werden. Es ist aber auch ein wenig schade, denn ansonsten könnte man bei Bedarf Daten auf der Festplatte der Websurfer abspeichern - beispielsweise Formulareingaben oder das Datum des Tages, an dem der Besucher die Seite das letzte Mal heruntergeladen hat. Aus diesem Grunde wurde das Konzept der Cookies entwickelt, das einen eingeschränkten, vom Browser kontrollierten Zugriff auf die Festplatte des Client-Rechners erlaubt.
Cookies würde man im Deutschen als »Kekse« bezeichnen, nur sagt dieser Begriff überhaupt nichts über die Funktion dieser häufig eingesetzten Hilfsgeister, so dass wir auch im Deutschen üblicherweise von »Cookies« sprechen.
Nachdem wir nun geklärt hätten, dass Cookies außer dem Namen nichts mit Keksen gemein haben, sollten wir auch klären, was Cookies eigentlich sind.
»Cookies stellen eine Möglichkeit dar, wie der Autor einer Website Daten auf den Rechnern der Clients abspeichern kann.«
Nehmen wir an, Sie möchten alle Erstbesucher mit einer speziellen Eintrittsseite begrüßen (beispielsweise mit einer kleinen Animation oder einem Anmeldeformular). Wenn ein Besucher die Website zum zweiten Male ansteuert, soll die Eintrittsseite nicht mehr angezeigt werden. Um dies zu realisieren, wäre es am einfachsten, wenn beim Erstbesuch auf dem Rechner des Clients die Information abgespeichert würde, dass die Website bereits einmal betreten wurde. Beim nächsten Eintritt in die Website würde diese Information dann mit der URL an den Server geschickt und der Aufruf der Eintrittsseite unterbunden.
Das eigentliche Problem stellt hierbei das Speichern von Informationen auf der Client- Seite dar, das grundsätzlich eine empfindliche Verletzung der Sicherheit des Client- Rechners darstellt. Um dieses Risiko einzuschränken, wurde das Konzept der Cookies entwickelt.
Das ursprüngliche Konzept der Cookies beruht auf CGI:
Die Kontrolle über das Speichern und Abfragen von Cookies unterliegt dabei dem Browser, wodurch die Sicherheit des Client-Rechners gewährleistet bleibt.
JavaScript setzt auf diesem Konzept auf: über document.cookie können JavaScripte Cookies setzen und abfragen. Dies eröffnet dem Webdesigner die Möglichkeit, Daten zwischen den Seiten eines Webs direkt auszutauschen (ohne den Umweg über ein CGI-Skript).
Cookies werden in JavaScript durch das Dokument-Objekt document.cookie repräsentiert. Über dieses Objekt können Sie Cookies lesen wie auch abfragen. Bevor Sie jedoch ein Cookie erstellen oder lesen können, müssen Sie wissen, wie ein Cookie aufgebaut ist.
Cookies sind Zeichenketten aus Name/Wert-Paaren. Das erste Name/Wert-Paar gibt dabei den Namen und den Inhalt des Cookies an. Die nachfolgenden, optionalen Paare beeinflussen die Gültigkeit des Cookies.
Set-Cookie:
name=WERT; expires=DATUM; path=PFAD; domain=DOMAIN; secure
Tabelle 13.1: Cookie-Attribute
Zum Schluss noch eine Warnung zum Inhalt des Cookies. Was Sie in dem Cookie speichern, bleibt grundsätzlich Ihnen überlassen - das Abspeichern von Passwörtern oder ähnlich sensiblen Inhalten wäre allerdings eine grobe Fahrlässigkeit.
Worauf wir Sie auch noch aufmerksam machen möchten, ist, dass Sie in Cookies keine Leerzeichen oder Sonderzeichen verwenden dürfen. (Denken Sie daran, dass Cookies traditionell ja angehängt an den URL an CGI-Programme geschickt werden.) Wenn Sie also Daten in dem WERT-Teil speichern, codieren Sie diese mit der JavaScript-Funktion escape() und decodieren Sie die Daten beim Lesen mit unescape(), siehe nachfolgende Beispiele.
Zum Setzen und Abfragen von Cookies schreibt man sich am besten eigene JavaScript- Funktionen (oder besorgt sich aus dem Internet Funktionen, die man anpasst, siehe http://home.ecore.net/pigasus/frame1.htm oder http://www.hidaho.com/cookies/cookie.txt.
Die folgende Funktion übernimmt den Namen, den Inhalt und die Gültigkeit des Cookies (in Tagen) als Argumente und erzeugt daraus einen Cookie:
<script type="text/javascript">
function CookieSetzen(name, inhalt, tage)
{
var cookieDate = new Date();
cookieDate.setTime(cookieDate.getTime()
+ (1000 * 60 * 60 * 24 * tage));
document.cookie = name + "=" + escape (inhalt)
+ "; expires=" + cookieDate.toGMTString();
}
</script>
Beachten Sie die Umwandlung der Gültigkeitsangabe. Die Funktion erwartet, dass die Gültigkeit nicht als Datum, sondern als Gültigkeitsdauer in Tagen angegeben wird und rechnet diese in eine für den Cookie verwertbare Datumsangabe um.
Beachten Sie, dass auf einem Client-Rechner maximal 300 Cookies gespeichert werden können, dass ein Cookie nicht mehr als 4 KByte groß sein darf und dass pro Server und Domain nur 20 Cookies erlaubt sind.
Beim Abfragen des Cookies besteht die Hauptschwierigkeit darin, aus der Zeichenkette der Cookies den Teil herauszubrechen, der den eigentlichen Inhalt des gesuchten Cookies ausmacht.
Beachten Sie, dass es gut möglich ist, dass mehr als ein Cookie für eine Webseite definiert sind. Der Browser liest für jeden Cookie den Namen und Wert ein (beispielsweise meinCookie=Inhalt des Cookies). Mehrere Cookies werden durch Semikolon und Leerzeichen voneinander getrennt. Wenn zum Beispiel drei Cookies für die Webseite abgespeichert, liest der Browser beim Aufruf der Seite folgenden String in document.cookie ein:
cookie1=Inhalt%20Cookie1; cookie2=Inhalt%20Cookie2; cookie3=Inhalt%20Cookie3
Da die Sonderzeichen in den Cookies noch codiert sind, findet man im Inhalt der Cookies statt Leerzeichen die Zeichenfolge %20. Das ist wichtig, denn dadurch kann man am Leerzeichen erkennen, wo ein Cookie aufhört und der nächste anfängt.
Will man den Inhalt eines bestimmten Cookies auslesen, muss man also zuerst den Cookie finden und dann den Inhalt des Cookies extrahieren.
<script type="text/javascript">
function CookieAbfragen(name)
{
var ergebnis="";
var tmp = name + "=";
if (document.cookie.length > 0)
{
beginn = document.cookie.indexOf(tmp)
if (beginn != -1)
{
beginn += tmp.length;
ende = document.cookie.indexOf(";", beginn);
if (ende == -1)
ende = document.cookie.length;
ergebnis=
unescape(document.cookie.substring(beginn, ende));
}
}
// Cookie-Daten verarbeiten
}
</script>
Die obige Funktion sucht zuerst den Cookie mit dem angegebenen Namen (gespeichert in tmp). Hat sie ihn gefunden (if (beginn != -1) liefert true), extrahiert sie den Inhalt des Cookies. Dazu ermittelt die Funktion die Positionen des ersten und letzten Zeichens des Cookie-Inhalts. Die Position des ersten Zeichens ist die Position hinter dem Namen des Cookies, die Position des letzten Zeichens findet man, wenn man mit indexOf() nach dem abschließenden Semikolon sucht. Der String zwischen beiden Positionen wird dann als Teilstring zurückgeliefert, decodiert (Aufruf von unescape()) und in der Variablen ergebnis gespeichert.
Zum Austesten ihrer Cookie-Funktionen sollten Sie sich eine kleine Testwebseite mit einem Formular zum Setzen und Abfragen der Cookies erstellen.
Abbildung 13.1: Cookie-Testseite
Um einen Cookie zu setzen, füllen Sie das Formular zuerst vollständig aus (siehe Abbildung 13.1) und drücken dann die Schaltfläche Cookie setzen. Setzen Sie zur Probe ruhig mehrere Cookies!
Um danach den Inhalt eines Cookies abzufragen, geben Sie nur den Namen des Cookies ein und klicken Sie dann auf die Schaltfläche Cookie abfragen. Danach sollte im Inhalt-Feld der Inhalttext des Cookies angezeigt werden.
Hier noch einmal der vollständige Code dieser Seite.
Listing 13.1: cookies.html - Cookies-Mechanismus testen
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Cookies testen</title>
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<script type="text/javascript">
function CookieSetzen(name, inhalt, tage)
{
var cookieDate = new Date();
cookieDate.setTime(cookieDate.getTime()
+ (1000 * 60 * 60 * 24 * tage));
document.cookie = name + "=" + escape (inhalt) +
"; expires=" + cookieDate.toGMTString();
// Formular zurücksetzen
document.forms[0].elements[0].value = "";
document.forms[0].elements[1].value = "";
document.forms[0].elements[2].value = "";
}
function CookieAbfragen(name)
{
var ergebnis="";
var tmp = name + "=";
if (document.cookie.length > 0)
{
beginn = document.cookie.indexOf(tmp)
if (beginn != -1)
{
beginn += tmp.length;
ende = document.cookie.indexOf(";", beginn);
if (ende == -1)
ende = document.cookie.length;
ergebnis=
unescape(document.cookie.substring(beginn, ende));
}
}
document.forms[0].elements[1].value = ergebnis;
}
</script>
</head>
<body>
<h1>Cookie setzen und abfragen</h1>
<form>
<table border="0" width="400" cellspacing="5" cellpadding="5">
<tr>
<td width="67" align="right">Name</td>
<td width="291"><input type="text" name="T1"
size="20"></td>
</tr>
<tr>
<td width="67" align="right">Inhalt</td>
<td width="291"><input type="text" name="T2"
size="40"></td>
</tr>
<tr>
<td width="67" align="right">Tage</td>
<td width="291"><input type="text" name="T3"
size="20"></td>
</tr>
<tr>
<td width="67" align="right"></td>
<td width="291">
<input type="button" value="Cookie setzen" name="B1"
onClick=
"CookieSetzen(document.forms[0].elements[0].value,
document.forms[0].elements[1].value,
document.forms[0].elements[2].value)">
<input type="button" value="Cookie abfragen" name="B2"
onClick=
"CookieAbfragen(document.forms[0].elements[0].value)"></td>
</tr>
</table>
</form>
</body>
</html>
Wie Sie bereits wissen, verfallen Cookies automatisch nach Ablauf ihres Gültigkeitsdatums. Es gibt allerdings auch einmal Situationen, in denen man einen Cookie direkt löschen möchte.
Wenn Sie einen Cookie gleichen Namens mehrmals erzeugen, werden nicht mehrere Instanzen des gleichen Cookies angelegt. Vielmehr gibt es auf dem Client-Rechner stets nur einen Cookie dieses Namens, der bei jeder Erstellung eines neuen Cookies gleichen Namens überschrieben wird.
Dies nutzt man zum Löschen von Cookies. Erzeugen Sie einfach unter dem Namen des zu löschenden Cookies einen neuen Cookie, dessen Zerfalldatum Sie in die Vergangenheit zurücklegen. Der Cookie wird dann überschrieben - und sofort vom Client gelöscht, da er ja bereits abgelaufen ist.
function CookieLoeschen(name)
{
var cookieDate = new Date();
cookieDate.setTime(cookieDate.getTime() - 1);
document.cookie = name + "=Nur zum Loeschen" +
"; expires=" + cookieDate.toGMTString();
}
Versuchen Sie nicht mit einem Cookie zu überschreiben, der kein Zerfallsdatum hat. Diese Cookies, die nur für die aktuelle Sitzung mit dem Browser gültig sind, werden überhaupt nicht abgespeichert, können also auch nicht bereits gesetzte Cookies überschreiben oder gar löschen.
Ein häufiges Problem bei der Erstellung von dynamischen Webseiten ist, dass es keine Möglichkeit gibt, den Zustand einer Webseite bis zum nächsten Aufruf der Webseite festzuhalten.2
Stellen Sie sich vor, Sie präsentieren auf einer Seite Ihrer Website eine Bildergalerie - allerdings nicht als scrollbare Bilderflut, sondern als Diashow, die über Vor- und Zurück- Schalter gesteuert wird. Wenn nun der Besucher Ihrer Website die Seite mit der Diashow mitten in der Bilderfolge verlässt, um nach kurzer Zeit wiederzukehren, wird er enttäuscht sein, wenn er alle Bilder bis zu der Position, an der er angekommen war, noch einmal durchblättern muss.
Gleiches gilt für das Ausfüllen von Formularen. Wenn der Besucher die Seite mit einem halb ausgefüllten Formular kurzzeitig verlässt, ist beim Zurückkehren von seinen bisher gemachten Eintragungen nichts mehr zu sehen (außer er verwendet nur die Vor- und Zurück-Schalter seines Browser).
Abbildung 13.2: Rekonstruktion von Formulareingaben
Mit JavaScript und Cookies kann man hier Abhilfe schaffen. Die folgenden beiden Funktionen speichern und rekonstruieren den Zustand eines einfachen Formulars mit drei Texteingabefeldern.
function CookieFormularSpeichern(name)
{
var feld0 = document.forms[0].elements[0].value;
var feld1 = document.forms[0].elements[1].value;
var feld2 = document.forms[0].elements[2].value;
document.cookie = name + "=" + escape(feld0) + "|"
+ escape(feld1) + "|" + escape(feld2)
}
Die Funktion CookieFormularSpeichern() liest die Werte aus den Formularfeldern aus und speichert sie als |-getrennte Liste in einem Cookie. (Setzt natürlich voraus, dass in den Formulareingaben keine senkrechte Strichzeichen | verwendet werden.)
function CookieFormularLesen(name)
{
name += "=";
var laenge = name.length;
var cookie_laenge = document.cookie.length;
var i = 0;
while (i < cookie_laenge)
{
var j = i + laenge;
if(document.cookie.substring(i,j) == name)
{
return WerteAuslesen(j);
}
i = document.cookie.indexOf(" ", i) + 1;
if (i == 0)
{
break;
}
}
return null;
}
Die Funktion zum Auslesen ist hier etwas umfangreicher, da man berücksichtigen muss, dass unter Umständen mehrere Cookies für die Webseite gültig sind.
In so einem Fall liefert der Browser alle Cookies durch Leerzeichen getrennt zurück und es ist Aufgabe des JavaScripts, den Cookie herauszufiltern, der die Eingaben des Formulars enthält. Dies leistet die Funktion CookieFormularLesen(). Wenn Sie den Cookie für das Formular gefunden hat, übergibt sie diesen an die Hilfsfunktion WerteAuslesen(), deren Aufgabe es ist, die einzelnen Feldinhalte auszuwerten und auf die Formularfelder zu verteilen.
function WerteAuslesen(beginn)
{
var naechster = document.cookie.indexOf(";", beginn);
if (naechster == -1)
naechster = document.cookie.length;
var i = 0;
while (beginn < naechster)
{
ende = document.cookie.indexOf("|", beginn);
if (ende == -1)
ende = naechster;
document.forms[0].elements[i].value =
unescape(document.cookie.substring(beginn, ende));
beginn = ende + 1;
i += 1;
}
return 1;
}
Aufgerufen werden die beiden Funktionen zum Rekonstruieren und Speichern der Formulareingaben als Antwort auf die onload- und onunload-Ereignisse der Webseite.
Listing 13.2: Auszug aus formular.html
...
<body onload="CookieFormularLesen('Formulardaten')"
onunload="CookieFormularSpeichern('Formulardaten')">
<h1>Sind Sie für den internetfreien Sonntag?</h1>
<form>
<table border="0" width="450" cellspacing="5" cellpadding="5">
<tr>
<td width="150" align="right">Ihr Name</td>
<td width="300"><input type="text" name="T1"
size="20"></td>
</tr>
<tr>
<td width="150" align="right">Ihr Vorname</td>
<td width="300"><input type="text" name="T2"
size="40"></td>
</tr>
<tr>
<td width="150" align="right">Ihre Meinung</td>
<td width="300"><input type="text" name="T3"
size="40"></td>
</tr>
</table>
</form>
<div style="padding-top: 5em">
<a href="umfrage.html">Stand der Umfrage</a>
</div>
</body>
</html>
Die Seite umfrage.html, die sich ebenfalls auf der Buch-CD befindet, liefert keine echte Auswertung der Formulareingaben. Sie dient nur zum bequemen Verlassen und Wiederansteuern der Webseite formular.html. Wie man Gästebücher anlegt oder Umfragen auswertet, erfahren Sie in Woche 3.
Die im vorangehenden Abschnitt vorgestellte Technik eignet sich natürlich nicht nur dazu, dynamische Webseiten gemäß den letzten Einstellungen wiederherzustellen.
Genauso gut können Sie mit Cookies und JavaScript auch Daten zwischen verschiedenen Webseiten eines Webs austauschen - eine Technik, für die es wiederum eine Vielzahl von Anwendungsmöglichkeiten gibt, beispielsweise die Erstellung virtueller Warenkörbe.
Wenn man vermittels Cookies Daten zwischen verschiedenen Seiten eines Webs austauschen will, muss man darauf achten, dass die Cookies auch für alle betroffenen Webseiten gültig sind.
Wenn Sie über keine eigene Domain verfügen, sollten Sie als Pfad zumindest den Pfad zu Ihren Verzeichnissen eingeben und nicht etwa Angaben wie "/." verwenden, die den Cookie für alle Unterverzeichnisse der Domain verfügbar machen.
Virtuelle Warenkörbe lassen sich zwar vollständig mit JavaScript realisieren, doch üblich ist es eigentlich nicht, jedenfalls nicht für umfangreichere Warenangebote, die datenbankgestützt sind. Da hierbei für den Aufbau der Webseiten ehedem serverseitige Techniken eingesetzt werden (CGI, ASP, etc.) wird üblicherweise auch der Warenkorb serverseitig per CGI realisiert.
Cookies stellen einen vom Browser kontrollierten Mechanismus zum clientseitigen Abspeichern von Daten dar. In JavaScript kann man das vom Browser zur Verfügung gestellte Objekt document.cookie und dessen Eigenschaften und Methoden zum Setzen und Abfragen von Cookies verwenden.
Frage:
In der Einleitung zu diesem Kapitel wurde erwähnt, dass man mit Hilfe eines Cookies
feststellen kann, ob ein Websurfer eine Website schon einmal betreten hat und
dementsprechend auf die Anzeige einer Eingangseite verzichten kann. Muss oder sollte
man einen solchen Cookie implementieren, wenn man vor die zentrale Homepage des
Webs eine Eingangsseite schaltet?
Antwort:
Nein, nur weil Sie eine Eingangsseite für Ihr Web vorsehen, müssen Sie keinen
Cookie setzen, der dafür sorgt, dass die Eingangsseite bei neuerlichem Besuch des
Webs übersprungen wird. Wenn ein Besucher von Ihrer Webseite so begeistert ist,
dass er sie in der Zukunft noch des öfteren aufsuchen wird, sollte er die zentrale
Homepage in die Liste seiner Favoriten aufnehmen. Dann kann er die Homepage
direkt ansteuern und die Eingangsseite wird ehedem nicht angezeigt. Insofern
kann eine Eingangsseite - oder gar ein Eingangstunnel - auch ein zusätzlicher
Anreiz sein, die Homepage in die Favoritenliste einzutragen. ;-)
Frage:
Ist es sinnvoll, eine Webseite so aufzusetzen, dass sie nur dann funktioniert, wenn ein
Cookie angelegt und ausgewertet wird?
Antwort:
Cookies sind eine Art kleine, dienstbare Geister, mit deren Hilfe man Webseiten
interaktiver und benutzerfreundlicher machen kann. Keinesfalls aber sollte man
eine Webseite so konstruieren, dass sie auf die Unterstützung von Cookies
angewiesen ist. Denn erstens verwenden die einzelnen Browser unterschiedliche
Mechanismen zum Abspeichern von Cookies (das heißt, Cookies, die von einem
Browser gesetzt werden, bleiben den anderen Browsern verborgen), und zweitens
gibt es viele Websurfer (und Firmen), die das Anlegen von Cookies aus
Sicherheitserwägungen heraus abgeschaltet haben.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
Hier begnügen wir uns mit der clientseitigen Unterstützung. Erweitern Sie das Formular um zwei passende Optionsfelder und passen Sie den JavaScript-Code für die Abspeicherung und Rekonstruktion der Formulareingaben an.
Mit Client-Rechner meinen wir den Rechner des Websurfers, der unsere Webseiten besucht und in seinem Browser anschaut.
Dies hat damit zu tun, dass Webseiten vermittels des HTTP-Protokolls über das Netz übertragen werden. Das HTTP-Protokoll ist ein statusloses Protokoll, dass keine Zwischenspeicherung von Daten zulässt.