PHP でランダムな文字列を生成する方法のまとめ

はじめに

実務にて、ファイル名、パスワード、トークンなどに使用する為のランダムな文字列を生成する関数を実装する作業があり、それを解決したやり方を一覧に纏めた情報です。Web 開発の初心者、初学者の方にもわかりやすいように、ソースコードを編集してサンプルを公開しています、ご参考になれば幸いです。

検証環境

サンプル

解説

桁数が指定できるランダムな英数字の文字列を生成する方法を説明していきます。

random_bytes

random_bytes暗号論的擬似乱数生成器(cryptographically secure pseudo random number generator, CSPRNG)を用いてランダムなバイト列を生成、bin2hex で 16 進表現の ASCII 文字列に変換するやり方です。

random_bytes は PHP 7.0 で追加された関数です。

var_dump(genRandomStr(16)); // 0c5f55fd23b8ef3b883a6a140b53034a

function genRandomStr(int $length = 8): string {
  return bin2hex(random_bytes($length));
}

random_int

random_int 暗号論的擬似乱数生成器(cryptographically secure pseudo random number generator, CSPRNG)を用いてランダムな整数を生成、文字列のオフセットに設定して、桁数分の文字を連結するやり方です。

random_int は PHP 7.0 で追加された関数です。

var_dump(genRandomStr(32)); // KN8tAYIFVS4JmiZSh8mqHy9bdWGkIYkD

function genRandomStr(int $length = 16, string $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): string {
  $str = '';
  $chars_length = mb_strlen($chars, '8bit') - 1;
  for ($i = 0; $i < $length; ++$i) $str .= $chars[random_int(0, $chars_length)];
  return $str;
}

openssl_random_pseudo_bytes

openssl_random_pseudo_bytes で疑似ランダムなバイト文字列を生成して、bin2hex で 16 進表現の ASCII 文字列に変換するやり方です。

openssl_random_pseudo_bytes は PHP 5.3 で追加された関数です。random_bytes、random_int が利用できない PHP 7.0 未満に便利です。

var_dump(genRandomStr(16)); // 90c207a40d1a9457a978a43e649cff73

function genRandomStr(int $length = 8): string {
  return bin2hex(openssl_random_pseudo_bytes($length));
}

mcrypt_create_iv

mcrypt_create_iv でランダムなソースから初期化ベクトル(initialization vector, IV)を生成して、bin2hex で 16 進表現の ASCII 文字列に変換するやり方です。初期化ベクトル とは、ランダムに生成されるビット列のことです。

mcrypt_create_iv は、PHP 7.1.0 で非推奨PHP 7.2.0 で削除されている関数です。

var_dump(genRandomStr(16)); // 65e8607755e37771393b38a4361270c4

function genRandomStr(int $length = 8): string {
  return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM));
}

mt_rand

mt_rand で擬似乱数生成器(Pseudorandom number generator, PRNG)の1つである メルセンヌ・ツイスター(Mersenne twister, MT)を介して乱数値を生成、password_hash でハッシュ化するやり方です。

var_dump(genRandomStr()); // $2y$10$IGTRzjzBr7OhwEwBxRQxu.LC9zBTO9NF.iPripMMZDQQm0.DcBpIq

function genRandomStr(): string {
  return password_hash(mt_rand(), PASSWORD_DEFAULT);
}

mt_rand は、下記のマニュアルからの引用を見てわかる通り、暗号学的に安全な値ではありません。セキュリティ対策に用いるのはやめましょう。rand も同じです。

この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。

https://www.php.net/manual/ja/function.mt-rand.php

uniqid

uniqid でマイクロ秒単位の現在時刻に基づいた、接頭辞付きの ID を取得、password_hash でハッシュ化するやり方です。

var_dump(genRandomStr()); // $2y$10$k1zfy60OEEAyRB4FeyuwLuPUzejfNYKK88.Ueb2/7uopcBQu4EPS6

function genRandomStr(): string {
  return password_hash(uniqid('', true), PASSWORD_DEFAULT);
}

uniqid は、下記のマニュアルからの引用を見てわかる通り、暗号学的に安全な値ではありません。セキュリティ対策に用いるのはやめましょう。

この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。

https://www.php.net/manual/ja/function.uniqid.php

md5

md5 で文字列を RFC 1321(The MD5 Message-Digest Algorithm)を用いて MD5 ハッシュ化するやり方です。

var_dump(genRandomStr()); // b75dfb55337d72941e90ecc7d238e146

function genRandomStr(): string {
  return bin2hex(md5(uniqid('', true), true));
}

md5 は、下記のマニュアルからの引用を見てわかる通り、セキュリティ的に安全な値ではありません。パスワードのハッシュに使うのはやめましょう。sha1 も同じです。

パスワードを守るためにこの関数を使うことはおすすめしません。 ハッシュアルゴリズムの高速性がその理由です。 詳細とベストプラクティスについては、パスワードハッシュ FAQを参照ください。

https://www.php.net/manual/ja/function.md5.php

MD5 や SHA1 そして SHA256 といったハッシュアルゴリズムは、 高速かつ効率的なハッシュ処理のために設計されたものです。 最近のテクノロジーやハードウェア性能をもってすれば、 これらのアルゴリズムの出力をブルートフォースで(力ずくで)調べて元の入力を得るのはたやすいことです。

最近のコンピュータではハッシュアルゴリズムを高速に「逆算」できるので、 セキュリティ技術者の多くはこれらの関数をパスワードのハッシュに使わないよう強く推奨しています。

https://www.php.net/manual/ja/faq.passwords.php#faq.passwords.fasthash

str_shuffle

str_shuffle で文字列をランダムにシャッフルした後、substr で一部を切り出すやり方です。

var_dump(genRandomStr()); // 6NnclrMOP23K0q1Z

function genRandomStr(int $length = 16, string $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'): string {
  return substr(str_shuffle($chars), 0, $length);
}

str_shuffle は、下記のマニュアルからの引用を見てわかる通り、暗号学的に安全な値ではありません。セキュリティ対策に用いるのはやめましょう。

この関数が生成する値は、暗号学的に安全ではありません。そのため、これを暗号として使ってはいけません。暗号学的に安全な値が必要な場合は、random_int() か random_bytes() あるいは openssl_random_pseudo_bytes() を使いましょう。

https://www.php.net/manual/ja/function.str-shuffle.php

まとめ

PHP マニュアルに従って、下記の 2 点に気を付けましょう。

  1. PHP 5.3 以降、PHP 7.0 未満であれば openssl_random_pseudo_bytes を用いる。
  2. PHP 7.0 以降であれば、random_bytes、random_int を用いる。

大事なのは、関数の使い所を間違えないことです。

例えば、password_hash はパスワードを保存する為の関数なので、ファイル名やトークンを生成する為に使うのはバーベキューに白いワンピースを着て参加しているぐらい場違いです。

以上です。

おわりに

サンプルのソースコードを再利用する際は、要件定義やコーディング規約にお気を付けください。