第21話:クッキーの利用

第3部 Webページのプログラミング

目次

マンガ

マンガ

マンガ

マンガ

マンガ

マンガ

マンガ

マンガ台詞

【1Page】
アイコン先生:よーし 今日は 『クッキー』の話を するぞ
アイコン遊:お菓子の話なら 任せて!
アイコン先生:お菓子のクッキーではなく ブラウザの『クッキー』の話だ
アイコン遊:はっ??
アイコン先生:ここ数回 Webページを 操作してきた
    例えば 背景色を変更する プログラムを 書いたとする
    Webページを 開くたびに 設定するのは 面倒だろう?
アイコン遊:そうね
    面倒すぎて 眠くなるわ!
【2Page】
アイコン先生:これは 『クッキー』を使えば 解決できる
アイコン遊:だから クッキーって 何?
アイコン先生:ブラウザの『クッキー』は 情報を書いた メモ用紙みたいなものだ
アイコン遊:食べられないの?
アイコン先生:食べられない
アイコン遊:ガーン!
アイコン先生:ブラウザの『クッキー』は
    情報を書き込んで ブラウザに保存する ためのものだ
    保存した情報は 次にそのページを 開いた時などに 取り出せる
アイコン守:なるほど その『クッキー』を使って 設定を保存するわけですね
アイコン先生:そういうことだ
    よし サンプルを書くぞ
【3Page】
        <!DOCTYPE html>
        <html lang="ja">
            <head>
                <meta charset="UTF-8">
                <script>
                function save() {
                    // 『input0』『input1』要素の値を取得して、クッキーに書き込み
                    writeCookie("input0", document.getElementById("input0").value, 1);
                    writeCookie("input1", document.getElementById("input1").value, 1);
                }
                function load() {
                    // クッキーから読み込んだ値を、『input0』『input1』要素に設定
                    document.getElementById("input0").value = readCookie("input0");
                    document.getElementById("input1").value = readCookie("input1");
                }
                function writeCookie(key, value, hours) {
                    if (key == "") return;

                    // 現在時刻に、引数『hours』を加えた時間を作成
                    var d = new Date();
                    d.setHours(d.getHours() + hours * 1);

                    // 作成した時間を、設定として配列に格納
                    var options = new Array();
                    options.push("expires=" + d.toGMTString());

                    // 引数『key』『value』を元にした設定と、時刻の設定を、
                    // 文字列結合してクッキーに書き込み
                    document.cookie = escape(key) + "=" + escape(value) + "; "
                        + options.join("; ");   // 『key=value; expires=時間』を書き込み
                }
                function readCookie(key) {
                    if (key == "") return;

                    // クッキーの文字列『key1=value; key2=value; …』から、
                    // 引数の『key』を元に、正規表現で値を検索
                    var re = new RegExp(escape(key) + "=(.*?)(?:;|$)");
                    if (document.cookie.match(re)) return unescape(RegExp.);
                    return "";
                }
                </script>
            </head>
            <body>
                <input type="text" id="input0" value=""><br>
                <input type="text" id="input1" value=""><br>
                <input type="button" onClick="save();" value="保存">
                <input type="button" onClick="load();" value="読み込み"><br>
            </body>
        </html>
        『document.cookie』を利用してクッキーを読み書きする
        『escape』はURLに使えない文字を特殊な符合に変換する関数
        『unescape』は元の文字列に戻す関数
【4Page】
アイコン遊:長いわね
アイコン先生:そうだな だいぶ長くなったな
アイコン先生:簡単に使い方を 説明しよう
    入力欄に書き込んで 『保存』ボタンを押せば
    文字列がブラウザに 保存される
        [aaa]
        [bbb]
        保存 読み込み
    次に ブラウザを再起動して
    『読み込み』ボタンを押せば
        []
        []
        保存 読み込み
    先ほど記入した文字列が 入力欄に読み込まれる
        [aaa]
        [bbb]
        保存 読み込み
【5Page】
アイコン先生:それじゃあ プログラムの 説明をするぞ
    『クッキー』は 『document.cookie』 を使って読み書きする
    代入する時と 取り出す時では 値が違うので 注意が必要だ
        document.cookie = strIn;
        strOut = document.cookie;
        // 『strIn』は『値名=値; オプション』で構成される1つの値
        // 『strOut』は『値名1=値; 値名2=値; …』と続く複数の値
アイコン先生:また 『クッキー』に 保存するデータは エスケープという 処理を行う必要がある
    読み込む時は アンエスケープを 行わないといけない
        URLに使えない文字列を『%~』形式に変換・逆変換
        escape("あいう") → %u3042%u3044%u3046
        あいう      ← unescape("%u3042%u3044%u3046")
アイコン先生:そういえば今日は 麗くんがいないな
【6Page】
アイコン麗:おほほほ 遅くなってすみません
    前の授業で クッキーを 焼いていましたの
アイコン遊:ぱくっ
    むしゃむしゃ
アイコン麗:(驚く)
    きー 返しなさいよ!
アイコン遊:ブラウザの 『クッキー』ではないので 取り出すことはできません
アイコン麗:何よ!
    意味分かんないわよ!

説明

この章では、『クッキーの利用』について学びます。

WebページのJavaScriptでは、ローカル(パソコンのハードディスクなどの保存領域)への、データの読み書きはできません。これは、セキュリティ上の理由からです。ファイルを自由に読み書きできると、OSのシステムファイルや、ユーザーのプライベートなデータを、自由に削除したり、ネット上に送ったりできるからです。

では、WebページのJavaScriptでは、ローカルにデータの読み書きを一切できないのでしょうか? 実はその方法が用意されています。Webブラウザには、安全にデータを読み書きする方法として、『クッキー』という仕組みがあります。

この『クッキー』は、利用できるデータのサイズが小さく、文字列のみしか保存できないという制限がありますが、データの保存と読み込みを行うことができます。また、保存したデータの有効期限を設定したり、同じサイト上で、同一のデータを参照したりする仕組みを持っています。

それでは以下、『クッキー』の利用方法について説明していきます。

『クッキー』の保存と読み込み

『クッキー』の保存と読み込み

『クッキー』の保存と読み込みは、『document.cookie』プロパティを使います。

『クッキー』に値を保存する際は、キーと値のセットを1つずつ『document.cookie』に代入します。

(「Google Chrome」では、ローカル環境では『クッキー』は利用できません。Webページをサーバーに上げて、Webブラウザで読み込む必要があります)

document.cookie = "key1=value1;";
document.cookie = "key2=value2;";

こうやって書き込んだデータを取り出すと、以下のようになります。

alert(document.cookie);

【結果】

key1=value1; key2=value2;

『クッキー』の保存と読み込みの違い

『document.cookie』を利用した、『クッキー』の保存と読み込みには注意が必要です。保存(値を代入した)時の値と、読み込み(値を参照した)時の値が異なるからです。

以下、その例を示します。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script>
        function save() {
            // 対象要素を空に
            var ele = document.getElementById("view");
            ele.innerHTML = "";

            // 書き込み1つ目
            document.cookie = "key1=value1;";
            ele.innerHTML += document.cookie + "<br>";

            // 書き込み2つ目
            document.cookie = "key2=value2;";
            ele.innerHTML += document.cookie + "<br>";
        }
        </script>
    </head>
    <body>
        <input type="button" onClick="save();" value="保存">
        <br>
        <div id="view"></div>
    </body>
</html>

『保存』ボタンをクリックすると、以下の内容が出力されます。

【結果】

key1=value1
key1=value1; key2=value2

上記プログラムは、『クッキー』に値を2回書き込み、そのたびに、id『view』に『クッキー』の現在の値を出力するものです。

この結果の、2行目に注目してください。『書き込み2つ目』で、『key2=value2;』という値を『document.cookie』に代入しているにも関わらず、『document.cookie』の中身は『key1=value1; key2=value2』になっています。

このことから、保存時の値と、読み込み時の値が違うことが分かります。

クッキーの保存時と、読み込み時の処理は、内部的には、以下のような動作になっています。

【保存時】

1. 『document.cookie』に新しい値を代入する。
2.  内部的に『値を書き換える関数』が呼び出される。
3. 『値を書き換える関数』の中で、与えられた値を解釈する。
4. 『値を書き換える関数』の中で、解釈した値をブラウザに保存する。
【読み込み時】

1. 『document.cookie』から値を取り出そうとする。
2.  内部的に『値を読み込む関数』が呼び出される。
3. 『値を読み込む関数』の中で、ブラウザから全ての値を読み出して、文字列にして返す。

この『document.cookie』のように、変数に値を代入した際に特殊な動作が行われるプロパティは他にもあります。

例えば『location.href』は、そういったプロパティです。『location.href = "https://crocro.com/";』とすると、ブラウザで表示されるWebページが変わります。

他にも、『DOM』で操作する様々な要素のプロパティも、書き換えと同時に内部処理が発生します。

『クッキー』の保存条件

『クッキー』に値を保存する際は、キーと値のセットとともに、いくつかの保存条件を設定できます。

document.cookie = "key1=value1; expires=Thu, 22 Apr 2010 09:00:26 UTC";

『expires』は、有効期限を表すキーです。この値を設定しなかった場合は、ブラウザを閉じた時点で『クッキー』の値は失われます。

『expires』の値は、『Wdy, DD-Mon-YYYY HH:MM:SS GMT』という形式か、日付オブジェクトの『toGMTString』メソッドの値を記入します。

// 有効期限を1年後に
var d = new Date();
d.setFullYear(d.getFullYear() + 1);

// クッキーの保存
document.cookie = "key1=value1; expires=" + d.toGMTString();

マンガ中のプログラムの解説

それでは、マンガ中で出てきたプログラムの解説を行います。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script>
        function save() {
            // 『input0』『input1』要素の値を取得して、クッキーに書き込み
            writeCookie("input0", document.getElementById("input0").value, 1);
            writeCookie("input1", document.getElementById("input1").value, 1);
        }
        function load() {
            // クッキーから読み込んだ値を、『input0』『input1』要素に設定
            document.getElementById("input0").value = readCookie("input0");
            document.getElementById("input1").value = readCookie("input1");
        }
        function writeCookie(key, value, hours) {
            if (key == "") return;

            // 現在時刻に、引数『hours』を加えた時間を作成
            var d = new Date();
            d.setHours(d.getHours() + hours * 1);

            // 作成した時間を、設定として配列に格納
            var options = new Array();
            options.push("expires=" + d.toGMTString());

            // 引数『key』『value』を元にした設定と、時刻の設定を、
            // 文字列結合してクッキーに書き込み
            document.cookie = escape(key) + "=" + escape(value) + "; "
                + options.join("; ");   // 『key=value; expires=時間』を書き込み
        }
        function readCookie(key) {
            if (key == "") return;

            // クッキーの文字列『key1=value; key2=value; …』から、
            // 引数の『key』を元に、正規表現で値を検索
            var re = new RegExp(escape(key) + "=(.*?)(?:;|$)");
            if (document.cookie.match(re)) return unescape(RegExp.);
            return "";
        }
        </script>
    </head>
    <body>
        <input type="text" id="input0" value=""><br>
        <input type="text" id="input1" value=""><br>
        <input type="button" onClick="save();" value="保存">
        <input type="button" onClick="load();" value="読み込み"><br>
    </body>
</html>

『』タグ内の解説

だいぶ長いので、分割して解説します。まずは、『』タグの中から説明します。

    <body>
        <input type="text" id="input0" value=""><br>
        <input type="text" id="input1" value=""><br>
        <input type="button" onClick="save();" value="保存">
        <input type="button" onClick="load();" value="読み込み"><br>
    </body>

『保存』ボタンをクリックすると、『save』関数を呼び出します。『読み込み』ボタンをクリックすると、『load』関数を呼び出します。

『id』の値が『input0』と『input1』の入力欄には、文字列を書き込めます。『保存』ボタンをクリックすると、この値を保存して、『読み込み』ボタンをクリックすると、それぞれの入力欄に、この値を読み込みます。

        function save() {
            // 『input0』『input1』要素の値を取得して、クッキーに書き込み
            writeCookie("input0", document.getElementById("input0").value, 1);
            writeCookie("input1", document.getElementById("input1").value, 1);
        }
        function load() {
            // クッキーから読み込んだ値を、『input0』『input1』要素に設定
            document.getElementById("input0").value = readCookie("input0");
            document.getElementById("input1").value = readCookie("input1");
        }

『save』と『load』関数では、『writeCookie』『readCookie』という関数を使い、『input0』と『input1』の『value』の値を読み書きしています。『input0』『input1』の要素の取得は、これまでに出てきた『document.getElementById』メソッドを使っています。

『writeCookie』関数の解説

次は、『writeCookie』関数ですが、ここは少し詳しい解説が必要です。

        function writeCookie(key, value, hours) {
            if (key == "") return;

            // 現在時刻に、引数『hours』を加えた時間を作成
            var d = new Date();
            d.setHours(d.getHours() + hours * 1);

            // 作成した時間を、設定として配列に格納
            var options = new Array();
            options.push("expires=" + d.toGMTString());

            // 引数『key』『value』を元にした設定と、時刻の設定を、
            // 文字列結合してクッキーに書き込み
            document.cookie = escape(key) + "=" + escape(value) + "; "
                + options.join("; ");   // 『key=value; expires=時間』を書き込み
        }

『"expires=" + d.toGMTString()』と時間の文字列を設定しているところは、データの有効期限になります。先ほどの『save』関数では、『writeCookie(key, value, '''1''')』と、『hours』の値を『1』として呼び出しています。そのため有効期限は、現在の時間の1時間後となります。

最後に、『document.cookie』に値を設定しています。この時、『key』と『value』の値をエスケープしています。

『クッキー』に保存できる文字列は、URLに利用できる文字列です。そのため、URLに利用できない記号や日本語は、エスケープ(特殊な符合で書き換える)処理をしてやらなければなりません。

また、『クッキー』に保存する値の末尾に、先ほど作成した有効期限の値を加えています。

これで、『クッキー』への値の保存は終了です。

『readCookie』関数の解説

では次に、『クッキー』からの値の読み込みを見てみましょう。

        function readCookie(key) {
            if (key == "") return;

            // クッキーの文字列『key1=value; key2=value; …』から、
            // 引数の『key』を元に、正規表現で値を検索
            var re = new RegExp(escape(key) + "=(.*?)(?:;|$)");
            if (document.cookie.match(re)) return unescape(RegExp.);
            return "";
        }

『クッキー』の文字列は、先ほど説明したように、保存時と読み込み時は異なります。読み込み時は『key1=value; key2=value; …』と連なった文字列になっています。そこで、正規表現を使って、引数の『key』から、対応する値を取得しようとしています。

『RegExp(escape(key) + "=(.*?)(?:;|$)")』というのは、「エスケープ処理した引数『key』の値」+「最短一致の任意の文字列」+「『;』もしくは『末尾』(ただし、この文字は含まない)」という意味です。少し難しいですが、分からなければ、『正規表現』の章を復習してください。『正規表現』はパズルのようなものです。使いこなせると、複雑な検索条件を短いプログラムで実現できます。

次の行では、『document.cookie』の文字列を、『match』メソッドを使い、検索を行っています。その際、先ほど作成した正規表現の変数『re』を引数にしています。そして、検索に一致する値があった場合(戻り値が『true』の場合)に、『if』文の右側の処理を実行させています。

検索の『if』文の右側では、『RegExp.』という値をアンエスケープ(エスケープした文字を『元に戻す処理』)しています。『RegExp.』は、検索した文字列の中で、最初の『(~)』内の文字列です。ここでは、『key=~』の『~』部分になります。

こうして取得した値を、『return』を使い、『readCookie』関数の戻り値として戻しています。

『escape』と『unescape』

『escape』関数で行われるエスケープ処理は、URLに利用できない記号や日本語を、特殊な符合で書き換えるものです。また、『unescape』関数は、エスケープ処理された文字列を、元の文字列に復号するものです。

この2つの関数は、『クッキー』にデータを保存する時以外にも利用されます。たとえば、リンクのURLを利用して、サーバーにデータを送信する際などに使います。

以下、この2つの関数の動作を確認する例を示します。

var str = escape("あいう");
document.write(str + "<br>");

str = unescape(str);
document.write(str + "<br>");

【結果】

%u3042%u3044%u3046
あいう

『escape』関数を使うと、文字列が『%u3042%u3044%u3046』といった形式に変換されます。また、『unescape』関数を使うと、エスケープされた文字列が『あいう』と復号されます。

サーバー上のWebページの『クッキー』

以下、サーバー上でWebページを使用する際の話です。ローカルだけでWebページを使用する際には関係のない話なので、読み飛ばしてもらって構いません。

『クッキー』の保存条件は、『expires』だけでなく、以下のようなものもあります。

キー 説明
expires 有効期限
domain クッキーがサーバーに送られるURLのドメイン
省略時は、Webページが保存されているサイトのドメイン
例:『https://www.google.com/hoge/hoge/index.cgi』の場合は『'''www.google.com'''』
path クッキーがサーバーに送られるパス
省略時は現在のパス
例:『https://www.google.com/hoge/hoge/index.cgi』の場合は『'''/hoge/hoge/'''』
secure https://の安全なサイトのみにクッキーを送信するフラグ
キーのみで、値はなし

以下、例です。

document.cookie = "key1=value1; expires=Thu, 22 Apr 2010 09:00:26 UTC; domain=www.google.com; path=/hoge/hoge/; secure";

さて、『クッキー』をインターネット上で使う際に、もう1つ知っておいた方がよいことがあります。それは、『クッキー』は、JavaScriptのプログラム以外でも使用されるということです。

Webブラウザは、Webページを読み込んだ際に、サーバーの要求に従って『クッキー』をサーバーに送信します。そして、サーバーからの指示があれば、データを『クッキー』に書き込みます。たとえばサーバーでは、この値を見ることで、訪問者が誰かを判断して、処理を分岐させます。

『クッキー』は、WebブラウザのJavaScript内だけで使う仕組みではありません。これは、サーバーと連携したプログラムを作成する際などに、必要な知識となるので、覚えておくとよいでしょう。

以下、参考になるWebページです。

参考

サンプルの入手

以下は、今回出てきたサンプルです。

ZIPでまとめてダウンロード (右クリックから保存してください)

sample1.html』(『クッキー』の読み書き)を表示

sample2.html』(『document.cookie』のin/outの違い)を表示

sample3.html』(『escape』『unescape』の実験)を表示

プログラムの中身を見たい場合は、それぞれのHTMLファイルをブラウザで開いたあと、右クリックをして『ソースの表示』を選択してください。

メモ帳で、ファイルの中身を見ることができます。