manekineko倉金家ホームページ

趣味の部屋/ホームページ余話

javascriptによるCookie取得関数のまちがい

2011年9月28日 2011年11月28日 更新
 その昔参考書にあるjavascriptのコードを使ってクッキーの値が正しく取得できなかったことがあり原因を調べてコードを修正したのですが、最近この間違ったコードがまだ使われる可能性に気がつきました。
javascriptでクッキーを取得する場合ご注意ください。


 その昔(10年も前の話)、ホームページの作成を始めた当時javascriptを使う必要があってその勉強のために参考書を買いました。技術評論社の「JavaScript XXXX辞典」。
素人の私にはわかりやすく、ずいぶん参考にさせていただきました。

 その中にクッキーの取得方法が書いてありクッキー名をcookienameとすると
cookiedata = document.cookie + ";";
cookienameorder = cookiename + "=";
startpos = cookiedata.indexOf(cookienameorder);
ここでstartposの値から該当する名前のものがあるかを判定し、あればさらに
endpos = cookiedata.indexOf(";", startpos);
readdata = cookiedata.substring(startpos + cookienameorder.length, endpos);
といった具合でクッキーの値が取得できるというもの。

 しばらくこれを使っていましたが、あるときページの動作がおかしいので調べたらクッキーがおかしな値になっているのに気がつきました。
必死に原因を探った結果、別に似たような名前のクッキーがあり、その値を取得しているのを発見。

 具体的には、もともとcountというクッキー名を使っていたところに、持続性を維持したかったのでcountはそのままでhogecountやfugacountとかいった名前のクッキーを追加したのが原因でした。
すなわち上記のjavascriptでは名前にcountを含む、たまたま最初にリストされた別のクッキーの値を拾ってしまっていたのでした。
(どうしてそうなるのかは考えてみてね。)

 この方式を使うならば、
cookiedata = " " + document.cookie + ";"; …" "の中は半角スペース。
cookienameorder = " " + cookiename + "=";
startpos = cookiedata.indexOf(cookienameorder);
とするのが正解で、そのように修正してからはちゃんと値が取得できるようになりました。

 上記を使って実際にcookieの書込、読出関数を書くならば一例として、
<script type="text/javascript"><!--
cookie_head = "SITE1_"; // 同一ドメインに複数サイトあるときのサイト識別用。
function setcookie(cookiename, cookievalue, timelimit) {
cookienameorder = cookie_head + cookiename + "=";
if(timelimit) {
lifetime = parseInt(timelimit.toString().match(/^[\+\-]?[0-9]*/));
if(lifetime != 0) {
cookielife = new Date();
lifeunit = timelimit.toString().match(/[A-Za-z]*$/).toString();
if(lifeunit.match(/^min/i)) { lifetime *= 60; } // minutes
else if(lifeunit.match(/^h/i)) { lifetime *= 60*60; } // hours
else if(lifeunit.match(/^d/i)) { lifetime *= 60*60*24; } // days
else if(lifeunit.match(/^w/i)) { lifetime *= 60*60*24*7; } // weeks
else if(lifeunit.match(/^m/i)) { lifetime *= 60*60*24*31; } // months
else if(lifeunit.match(/^y/i)) { lifetime *= 60*60*24*365; } // years
else { lifetime *= 60*60*24; } // default unit: days
cookielife.setTime(cookielife.getTime() + lifetime*1000);
expiredate = cookielife.toGMTString();
document.cookie = cookienameorder + cookievalue + ";expires=" + expiredate+";";
} else {
document.cookie = cookienameorder + cookievalue + ";";
}
} else {
document.cookie = cookienameorder + cookievalue + ";";
}
}
function getcookie(cookiename) {
cookiedata = " "+document.cookie+";";
cookienameorder = " "+cookie_head+cookiename+"=";
startpos = cookiedata.indexOf(cookienameorder);
if(startpos >= 0) {
endpos = cookiedata.indexOf(";", startpos);
readdata = cookiedata.substring(startpos + cookienameorder.length, endpos);
} else return false;
return(readdata);
}
//--></script>

 ...とまあ、すいぶん昔の話なのでこれはこれでいいとして、先日別のことで検索して調べていたら偶然このまちがった方法を掲載しているサイトを見つけたので、もしやほかにもと思い調べてみると他にもいくつかありました。(例の本の影響が大きいようで。)

思い当たる方は確認するようお薦めします。

 とはいうものの、自分のずっと昔のページにはまだこの間違ったコードがそのまま残っているかもしれない...。(全部見直す元気なし。たぶん名前がダブってはいないだろうから、ま、いいか。)

(追記 2011年11月28日)
 先日東京へ出て暇があったので本屋を覗いてjavascript関係の本もちょっと見てみたら、この間違った方法を記載している本が今だにありました。
ご注意を!