gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

tokenizerともう一つのトークンの考察

MagicWeaponには「tokenizer」という「一意のトークンを発行する」クラスがあります。ちょっとしたDBのPKに死ぬるほど便利なのでよく使います。
一方で、以前に書いたのですが( http://d.hatena.ne.jp/gallu/20120402/p2 )、違うトークンの作り方もあります。


で。おいちゃんは「使い分けてる」ので、その辺の話をもやもやと。
「ぢぢぃの世間話を聞いてる」くらいの生ぬるいスタンスで読んでくださいw


大まかに結論先に書いちゃうと。
tokenizerは「一意であることを保証したい」ケースで使って、もう一個のトークンは「推測困難性がほしい」時に使います。


ん…まず、うちのtokenizerの仕様から。
前提として「62進数」ってのを使ってます。
62進数表記にすると、0-9とa-zとA-Zで表現できるので、ま〜ま〜便利です。素直にbase64でもよかったのですが、できたら英数だけで表現したかったので作りました。


んで。
tokenizerは、デフォルトで
・現在のエポックタイム(実際には、数値がでかいんで、固定の数値を減算してます)
・現在のマイクロ秒
・プロセスID
・乱数
の4つの数字を、デフォルトだと「−(ハイフン)」でつなげてます。
オプションで「自分のIPアドレス」をここに足せるのと、CとJavaで組んでた時には「スレッドID」も足してました。
PHPにはスレッドないんで、いったん省いてます。


これをやると。乱数以外の部分でかぶるのが「同じマシンの同じプロセスID上で、同じ秒+同じマイクロ秒で、処理が2回以上走る」場合で、これほぼほぼありえないので。
ゆえに「一意である」ことを大変簡単かつ確実に取得できるんで、好んで使ってます。
で…実装当初、とはいえ数字を普通に連結すると「すげぇ長い文字列」になったので、62進数作りましたw
現在、だいたい20〜30文字以内くらいで収まります。


んで。
このtokenが「推測困難か?」って問われると、個人的には「可能ぢゃね?」って思ってます。
乱数もさほど気にした関数使ってませんし(PHPの場合mt_randつかってまふ)、エポック秒は容易。マイクロ秒もある程度あたりはつくでしょうし、プロセスIDだって、案外と。
なので、tokenizerは「一意であることを保証したいとき」に使います。


一方で。
セッションIDとか、今度書くけどCSRFの割符なんかに使いたいのは「推測困難な文字列」なので。
そうすると、以前も書いたのですが

$token = hash('sha512', file_get_contents('/dev/urandom', false, NULL, 0, 128), false);

とすると…
・urandなので、たぶんきっと、ある程度質の良い乱数であると期待できる(はずw)
・sha-512なので、結構空間広いので、そう簡単に「偶然当たる」ってのもあるまいて
というあたりの発想から「推測困難なIDがほしい」時に重宝します。


一方で。いやまぁ「ねぇだろ」とは思うのですが、一応、可能性としては「いつかどこかで、以前発行したIDと重複する」可能性が0ではないので。
基本的には「一意のIDがほしい」用途では、あんまり使わないです。


時々聞かれるので、説明を省略する意味合いを込めて、めもw


PS
そういえば…「推測困難」なほう、MagicWeaponに組み込みたいのですが…名前どしよ?
UUIDっぽい使い方をするのですが…一応「UUIDは16バイトの数値」って決まりがあるしなぁ…「似非UUID」とかって名前にしようかしらん?w