PHPの標準関数のみでユニークなトークンを作りたかったので、メモとして残します。
目的
メールアドレス認証時に使用するアクティベーションキー用のトークンを発行したく、
実行する度に被らないランダムな文字列を取得するのが目的です。
TL;DR
uniqid(bin2hex(random_bytes(1)))
環境
PHP7系
乱数に使えそうな関数を探す
uniqid
uniqid ([ string $prefix = "" [, bool $more_entropy = FALSE ]] ) : string
マイクロ秒単位の現在時刻にもとづいた、接頭辞つきの一意な ID を取得します。
この関数は、戻り値の一意性を保証するものではありません。
uniqid() // 5ce3d9f085632
uniqid() // 5ce3d9f154c7a
uniqid() // 5ce3d9f25823a
13桁の16進数の文字列が返ってくるようです。
現在時刻に基づいてるので実行するたびにカウントアップされていくようです。
uniqid
には第一引数で接頭辞を付けられます。
uniqid('ucan-') // ucan-5ce3dabb38549
uniqid('ucan-') // ucan-5ce3dabbe1c38
uniqid('ucan-') // ucan-5ce3dabc5407c
接頭辞を付けられるのは便利だったのですが、
固定文字列を付けてしまうと結局一意性は保証されません。
dechex
10 進数を 16 進数に変換する
dechex ( int $number ) : string
$number
で指定した符号なし整数値を 16 進数表現した文字列を返します。
dechex(0) // 0
dechex(100) // 64
dechex(255) // ff
random_int
暗号学的に安全な疑似乱数整数を生成する。
random_int ( int $min , int $max ) : int
$min
〜 $max
の間で偏りのない結果が重要な場合に使用するのに適した暗号化された乱数整数を生成します。
random_int(0, 255) // 4
random_int(0, 255) // 158
random_int(0, 255) // 184
乱数を生成する
16進数2桁(0 〜 ff)の乱数を生成して接頭辞を付ける。
uniqid(dechex(random_int(0, 255))) // 865ce3dddb0e35b
uniqid(dechex(random_int(0, 255))) // 85ce3dddb13e1d
uniqid(dechex(random_int(0, 255))) // b25ce3dddb198dc
乱数を生成する(固定桁数)
もし桁数を固定したい場合は sprintf
を使って0埋めすると良さそうかな🤔
uniqid(sprintf('%02x', random_int(0, 255))) // 4e5ce3dd8d7e2de
uniqid(sprintf('%02x', random_int(0, 255))) // 0a5ce3dd8d83477
uniqid(sprintf('%02x', random_int(0, 255))) // 4f5ce3dd8d8925d
2019.05.23 追記
@suin さんから random_bytes
もオススメのコメントいただきました!
random-bytes
random_bytes - 暗号学的に安全な疑似乱数バイトを生成する
random_bytes ( int $length ) : string
salt、鍵、または初期化ベクトルを生成するときなど、暗号用途に適した任意の長さの暗号ランダムバイトの文字列を生成します。
random_bytes(1)
とすると1byteのバイナリ文字列が返ります。
バイナリ文字列から16進数に bin2hex
関数で変換すれば 00
〜 ff
を取得できます。
uniqid(bin2hex(random_bytes(1))) // 085ce642e0803c3
uniqid(bin2hex(random_bytes(1))) // 555ce642e2cb9fa
uniqid(bin2hex(random_bytes(1))) // eb5ce642e463215
2019.05.24 追記
@go12lim さんから uniqid
の第二引数使うとシンプルに書けるとアドバイスいただきました🙇♂️
uniqid('', true) // "5ce7b766c4b586.26307700"
uniqid('', true) // "5ce7b767d85ab4.09025400"
uniqid('', true) // "5ce7b7687dd943.84230183"
これが一番シンプルで良さそうです!
ドット付きが気にならなければこれで良さそう!
参考
- https://php.net/manual/ja/function.uniqid.php
- https://php.net/manual/ja/function.dechex.php
- https://php.net/manual/ja/function.random-int.php
- https://php.net/manual/ja/function.bin2hex.php
- https://php.net/manual/ja/function.random-bytes.php
- https://qiita.com/gakuri/items/27cca8f0fa28b78ddeca