初めて Cookie を PHP や Javascript で送信したり削除してサイトをパワーアップ

Cookie を使うのは初めてなので、いろいろと勉強してみました。一応以下のページにすべてまとめてありますが、詳しく掘り下げて知ろうと思うとこのページだけではダメなので、それを以下にまとめました。
とほほのCookie入門

Cookie には制限がある

1つのクッキーに保存できるのは最大で4096バイト、1台のサーバが同じコンピュータに対して発行できるクッキーの数は20個という制限が設けられています。

PHPスクリプト講座:クッキーについて — そふぃのphp入門より抜粋。

ここで疑問が。以下のどれが正解かわからなくなりました。

  1. サーバーは20個発行したら、それ以上は発行できなくなる。
  2. サーバーは20個発行した後、21個目を1個目を削除し発行する。
  3. ブラウザは同一サーバーから20個 Cookie を受け取ったら、それ以上受け取れなくなる。
  4. ブラウザは同一サーバーから20個 Cookie を受け取ったら、21個目を1個目を削除して受け取る。

もし1と2のどちらかが正解の場合は、共有のレンタルサーバーを使っている人には、事実上 Cookie を使えないということになり、Cookie はちゃんとしたサイトじゃないと使えなくなってしまう。そしてもし3が正解だったら最初に20個発行したもの勝ちになってしまうので絶対違う。

消去法で行くと4つ目の解釈で正しいと思うんですが、今の私にははっきりとした正解はわかりません。
でもとりあえず同じサーバー内の人のサイトには、そう簡単にめぐり合うことはないと思うので大丈夫だと思います。このまま Cookie について勉強していきます。

Cookie を送信する

1
2
3
$name = '名前';
$value = '値';
setcookie($name,$value);

単純にこのような形で送信できます。でも先ほど書いたように同一サーバーから20個しかCookieを送信することはできないので、できるだけ最小限の個数で抑えるために配列を使ったりするのが一般的みたいです。
PHP: setcookie – Manual
PHPスクリプト講座:配列を利用したクッキー — そふぃのphp入門

Javascript を使ってクッキーを送信する

PHP では <html> より前の部分でクッキーの送信などをしなければいけないので、訪問者にページの表示が完了してから Cookie を送信させるには PHP では不可能です。ということで自ずとJavascript を使うことになるみたいです。Javascript はめちゃくちゃ扱いにくいから、ここ本気出して考えました。

まずはイヌでもわかるJavaScript講座で紹介されているスクリプトをそのまま使ってみるパターン。このサイトはかなり役に立ちました。感謝!

1
2
3
4
5
6
7
function mySetCookie(myCookie,myValue,myDay){
   myExp = new Date();
   myExp.setTime(myExp.getTime()+(myDay*24*60*60*1000));
   myItem = "@" + myCookie + "=" + escape(myValue) + ";";
   myExpires = "expires="+myExp.toGMTString();
   document.cookie =  myItem + myExpires;
}

スクリプトの解説はイヌでもわかるJavaScript講座にありますので省きますです。
一応私が一番重要(厄介)だと思うところは escape() の部分でして、これは PHP ではデコードすることはできません。でもそれを PHP でもデコードできるようにした人がいました。すごいです。

PHP: utf8_encode – Manual
unescape(PHP)関数 Javascript版escape日本語POST対応 PEAR::HTML_AJAX – PHP::PEAR – dozo PukiWiki

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
/**
 * Function converts an Javascript escaped string back into a string with specified charset (default is UTF-8).
 * Modified function from http://pure-essence.net/stuff/code/utf8RawUrlDecode.phps
 *
 * @param string $source escaped with Javascript's escape() function
 * @param string $iconv_to destination character set will be used as second paramether in the iconv function. Default is UTF-8.
 * @return string
 */
function unescape($source, $iconv_to = 'UTF-8') {
  $decodedStr = '';
  $pos = 0;
  $len = strlen ($source);
  while ($pos &lt; $len) {
      $charAt = substr ($source, $pos, 1);
      if ($charAt == '%') {
          $pos++;
          $charAt = substr ($source, $pos, 1);
          if ($charAt == 'u') {
              // we got a unicode character
              $pos++;
              $unicodeHexVal = substr ($source, $pos, 4);
              $unicode = hexdec ($unicodeHexVal);
              $decodedStr .= code2utf($unicode);
              $pos += 4;
          }
          else {
              // we have an escaped ascii character
              $hexVal = substr ($source, $pos, 2);
              $decodedStr .= chr (hexdec ($hexVal));
              $pos += 2;
          }
      }
      else {
          $decodedStr .= $charAt;
          $pos++;
      }
  }
 
  if ($iconv_to != "UTF-8") {
      $decodedStr = iconv("UTF-8", $iconv_to, $decodedStr);
  }
 
  return $decodedStr;
}
 
/**
 * Function coverts number of utf char into that character.
 * Function taken from: http://sk2.php.net/manual/en/function.utf8-encode.php#49336
 *
 * @param int $num
 * @return utf8char
 */
function code2utf($num){
  if($num&lt;128)return chr($num);
  if($num&lt;2048)return chr(($num&gt;&gt;6)+192).chr(($num&amp;63)+128);
  if($num&lt;65536)return chr(($num&gt;&gt;12)+224).chr((($num&gt;&gt;6)&amp;63)+128).chr(($num&amp;63)+128);
  if($num&lt;2097152)return chr(($num&gt;&gt;18)+240).chr((($num&gt;&gt;12)&amp;63)+128).chr((($num&gt;&gt;6)&amp;63)+128) .chr(($num&amp;63)+128);
  return '';
}
?>

で、せっかくこういうのを見つけてからアレなんだけれども、PHP を使っているんだったら Cookie に送信する文字列を PHP で事前にエンコードしておけば、Javascript 側で escape する必要がなくなり、結果的に PHP でデコードすることができるようになるので、こっちの方が手早いんではないかと思うのですが実際はどうなんでしょうか……。

Javascript で後から追加する場合の注意点

Javascript で追加すると確かに Cookie は送信されるけどページの再読み込みを行わないと Cookie が送信されたのか訪問者にはわかりません。なので、ページを再読み込みさせる必要があります。Javascript とかいろいろ何が正しいのかわかりませんが、私は Cookie の送信をしたと同時に Javascript の location.reload() でページを再読み込みさせることにしました。
location.reload()?JavaScriptリファレンス

こちらは Web サーバのデータからリロードされ、最新の状態に更新されます。

1
<input type="button" value="計算" onclick="SetCookie('name','value');location.reload(true)" />

こちらはキャッシュからリロードされます。サーバー与える負荷を減らすためにはこちらがいいかもですね。

1
<input type="button" value="計算" onclick="SetCookie('name','value');location.reload(false)" />

Cookie を追加すると同時にページをリロードさせ、Cookie をコンテンツに反映させてます。ちなみに onclick に複数の何かを挿入する場合はセミコロンで区切るらしいです。

追記(2009/4/10): Ajax を使えばページを部分的にリロードして軽量化できる

Cookie を反映させるためにページ全体を読み込むのはスマートじゃありません。あれからいろいろと勉強をして Ajax が使えるようになったので、やる気のある人は Ajax もついでに勉強してみてはどうでしょうか。

Cookie を削除する

クッキーの削除は簡単です。以下のページが丁寧でした。
PHPスクリプト講座:クッキーの削除 — そふぃのphp入門

クッキーの削除の仕方は二通りあり、1つ目は setcookie() でクッキー名のみを指定する方法。

1
setcookie('クッキー名');

2つ目は、有効期限を過去にする。

1
setcookie('クッキー名', '', time() - 1);

Cookie には path がある

とても複雑で意味が分からないんですが、これを完璧に検証してくれた人がいるみたいです。感謝!
Cookie(クッキー)の届く範囲 (あいまいモード)

ただ Javascript での path の指定の仕方がわかりかせんでしたがとほほのCookie入門のテストページのソースにわかりやすくコメントアウトして記述してくれていましたのでなんとか解決。

コメント

コメントは受け付けていません。