[PHP]クッキーについての考察、結論

Read More

以下クッキーについての考察。


formから送られてきた値を$_POSTや$_GETなどで利用するように、
クッキーの値を利用するにはスーパーグローバル変数である$_COOKIEを使う。


ただしこの$_COOKIEに値を代入したからといって$_SESSIONのように次画面でも値を保持するというようなことはできない。


もう少し丁寧に言うと、スーパーグローバル変数の$_COOKIEには値を代入すること自体はできるが、あくまでそれは通常の変数となんら変わりないということ。


ここでクッキーとセッションの仕組みについての違いを書いておく。


~クッキーとセッションの仕組みの違い~

セッションはその値をサーバに保存している。
ページの表示が完了してブラウザを閉じても一定期間その値は保持される。

これに対しクッキーはその値をローカルマシンに保持する。
セッションと同様に、ブラウザを閉じてもその値は保持される。


値を保持する、という点においては同様なのだが、仕組みは似て非なるものである。


この為であろうか、
PHPで値を保持する手順というのにかなり差異がある。


$_SESSIONはそれに直接値をぶち込むとそれが保持がされる。
※もちろんsession_start()を宣言している必要はある

しかし$_COOKIEは値を入れても保持されない。


プログラム側ではここは決定的に大きな違いなので必ず覚えておかなければならない。



つまり$_COOKIEに値を入れることは、$_POSTや$_GET、$_REQUESTなどと同じでまったくの無意味。
あくまでも$_SESSIONだけが"特別"だと思った方がよいだろう。


クッキーに値を代入するにはsetcookie()を使うしかない。



さてこのsetcookie()、
第1引数にキーとなるものを指定し、第2引数には値となるものを指定する。

■クッキーの送信
<?php
$iExp = time()+3600*24; // 1日保持
setcookie('key', 'value', $iExp);
?>



こうすることでローカルマシンにクッキーが送信される。


注意しなくてはならないのがクッキー送信とはあくまでhttpヘッダーなので、
すべての出力に先立って行わなければならない。
つまりprint()とか出力していた後には使えないということ。

$_SESSIONは値を代入する時にそんなことは気にしなくて良い。
※宣言時は別


あとsetcookie()をやっても$_COOKIEに値は即反映はされない。

ローカルマシンに値を送ることと$_COOKIEに値が反映されることは同じタイミングではないということだ。


スーパーグローバル変数の$_COOKIEはどのタイミングで初期化されるのか?
その流れをイメージするとこんな感じ。

ユーザがURLを叩く。

この時サーバにリクエストが送られる。

このリクエストの中でローカルに保持していたクッキーをサーバに送る。

サーバはクッキーを解析して$_COOKIEに格納する。

PHPプログラムがはじまる。


つまりPHPプログラム内でsetcookie()をやっても即反映されないのは当然だ。


この辺りも(値の確認の意味において)クッキーの使い辛い点である。



さて、クッキーの保持について書いたのならクッキーの削除についても書いておく。

■クッキーの削除
<?php
setcookie('key', null, -1);
?>


第3引数で保持する期間を指定できるのだがこの値を
-1、あるいは0を指定する。

この時注意しなければならないのは第2引数にはnull、もしくは""(空文字)を指定すること。


この2つの引数を正しくセットしなければクッキーは削除されない


この点もクッキーの使い辛い点と言える。




さて、クッキーでは配列も扱うことができる。
いや、できると言ってはかなりの語弊があるが。
個人的には"できない"と同義だと思っているので。

何を言っているのかわからないと思うが順を追って説明する。


まずは配列を扱う場合は第1引数を文字列で"hoge[pref]"とする。
※prefの部分にクォートは要らない。クォートを付けたらおかしな形で格納される。

■配列の例
<?php
$iExp = time()+3600*24;
setcookie('hoge[pref]', 'hiroshima', $iExp);
?>



これを出力して確認すると、
Array ( [hoge] => Array ( [pref] => hiroshima ))

となる。



これだけ見たら、
「おお!お?クッキーも普通に配列を扱えるのか!」
と思うだろう。


しかしここからが問題となる。


まずsetcookie()の第2引数で直接配列を渡そうとするとワーニングが出て怒られる。入らない。


以下、その例。

■失敗例 その1
<?php
$iExp = time()+3600*24;
$ary = array(
  '1'=>'yamada',
  '2'=>'suzuki',
);
setcookie('piyo', $ary, $iExp);
?>



■失敗例 その1の実行結果
Warning: setcookie() expects parameter 2 to be string, array given in {file path} on line {line number}

これだとうまく入らない


つまり、表現がむずかしいのだが、
キーの指定の仕方によって配列は使えるが値として直接配列を指定することはできない
ということだ。



また、クッキーのキーで"fuga[]"を複数使って代入してやっても最後の値しか入らない。

■失敗例 その2
<?php
$iExp = time()+3600*24;
setcookie('fuga[]', 1, $iExp);
setcookie('fuga[]', 2, $iExp);
setcookie('fuga[]', 3, $iExp);
?>



■失敗例 その2の結果を出力
Array ( [fuga] => Array ( [0] => 3 ))


自動的に整数indexが増えていない。
$_COOKIEには"fuga[0]"というキーが一つできるだけである。


さらにここから意味不明な挙動をする。
上記に続けて以下のもの(その3、その4、その5)を順に実行するともはやまったく理解できない。

■失敗例 その3
$iExp = time()+3600*24;
setcookie('fuga[0]', 4, $iExp);



■失敗例 その3の結果を出力
Array ( [fuga] => Array ( [0] => 4 ))


これは良い。上書きにあたるわけだから。
これに続いてその4を実行してみてほしい。


■失敗例 その4
<?php
setcookie('fuga[0]', null, -1);
?>



■失敗例 その4の結果を出力
Array ( [fuga] => Array ( [0] => 3 ))




ん???
あれ???

なんでさっき上書きしたのにまた3って数字がでてくるの?


こいつを消すにはこうするしかない。


■その5
<?php
setcookie('fuga[]', null, -1);
?>




わかるだろうか。


fuga[]で作成されたfuga[0]と、自分で指定して作ったfuga[0]の挙動がおかしい。

上書きはされてるのに削除が正しくできてない。


この辺り(その3、その4、その5)の順序を変えてやってみたらおかしな挙動がよくわかる。




結論としては、

クッキーに配列は使うな!

ということ。

配列を使い始めるとわけわからんことになる。

絶対に自分一人しか触らないプログラムならともかく、
将来的に誰がどのように管理するかなどを考えた場合配列を使うことはありえない。


というか、クッキーはあくまでもセッションのキーを保存するためだけに使いたい。