web-dev-qa-db-ja.com

PHPを使用してランダムな文字列を作成する方法は?

PHPのRand関数はランダムな整数を生成しますが、次のようなランダムな文字列を生成する最良の方法は何ですか?

元の文字列、9文字

$string = 'abcdefghi';

6文字に制限されたランダム文字列の例

$string = 'ibfeca';

更新:これらのタイプの関数を大量に見つけました。基本的に、各ステップの背後にあるロジックを理解しようとしています。

更新:関数は必要に応じて任意の量の文字を生成する必要があります。

返信する場合は、パーツをコメントしてください。

56
Keith Donegan

さて、あなたは私のコメントで私が尋ねたすべての質問を明確にしませんでしたが、「可能性のある」文字の文字列と文字列の長さを返す関数が必要だと仮定します。明確にするために、通常よりも多くの変数を使用して、要求どおりに徹底的にコメントしました:

function get_random_string($valid_chars, $length)
{
    // start with an empty random string
    $random_string = "";

    // count the number of chars in the valid chars string so we know how many choices we have
    $num_valid_chars = strlen($valid_chars);

    // repeat the steps until we've created a string of the right length
    for ($i = 0; $i < $length; $i++)
    {
        // pick a random number from 1 up to the number of valid chars
        $random_pick = mt_Rand(1, $num_valid_chars);

        // take the random character out of the string of valid chars
        // subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
        $random_char = $valid_chars[$random_pick-1];

        // add the randomly-chosen char onto the end of our string so far
        $random_string .= $random_char;
    }

    // return our finished random string
    return $random_string;
}

サンプル関数でこの関数を呼び出すには、次のように呼び出します。

$original_string = 'abcdefghi';
$random_string = get_random_string($original_string, 6);

この関数は、渡された有効な文字の一意性をチェックしないことに注意してください。たとえば、'AAAB'の有効な文字列で呼び出した場合、各文字にAをBとして選択する可能性は3倍になります。ニーズ。

91
Chad Birch

文字の繰り返し発生を許可する場合は、この関数を使用できます。

function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
{
    $str = '';
    $count = strlen($charset);
    while ($length--) {
        $str .= $charset[mt_Rand(0, $count-1)];
    }
    return $str;
}

基本的なアルゴリズムは、0から<文字数> − 1までの乱数の<長さ>倍を生成し、セットから文字を選択して連結するためのインデックスとして使用しますそれらのキャラクター。 0および<文字数> − 1の境界は、最初の文字が$charsetで、最後の文字が$charset[count($charset) - 1]でアドレス指定されるため、$charset[0]文字列の境界を表します。

98
Gumbo

お気に入り:

 echo substr(md5(Rand()), 0, 7);
52
tasmaniski

それでは、ライブラリを使用すると言って始めましょう。多くが存在します:

問題の核心は、このページのほぼすべての回答が攻撃を受けやすいことです。 mt_Rand()Rand()lcg_value()、およびuniqid()はすべて 攻撃を受けやすい です。

優れたシステムは、ファイルシステムの_/dev/urandom_、またはmcrypt_create_iv()(_MCRYPT_DEV_URANDOM_を使用)またはopenssl_pseudo_random_bytes()を使用します。上記のすべてが行います。 PHP 7 2つの新しい関数が付属しますrandom_bytes($len)およびrandom_int($min, $max)も安全です。

これらの関数のほとんど(random_int()を除く)は「生の文字列」を返すことに注意してください。これは、_0 - 255_の任意のASCII文字を含むことができることを意味します。文字列、base64_encode()を介して結果を実行することをお勧めします。

24
ircmaxell
function generate_random_string($name_length = 8) {
    $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length);
}

以下のコメントで mzhang の素晴らしい提案に従ってコードを更新しました。

17
nameht

@ taskamiskiの優れた答えのより良い更新されたバージョン:

mt_Rand()の代わりにRand()を使用するより良いバージョン:

_echo md5(mt_Rand()); // 32 char string = 128bit
_

さらに良いことに、長い文字列の場合、ハッシュアルゴリズムを選択できるhash()関数を使用します:

_echo hash('sha256', mt_Rand()); // 64 char string
echo hash('sha512', mt_Rand()); // 128 char string
_

結果を50文字にまで削減したい場合は、次のようにします。

_echo substr(hash('sha256', mt_Rand()), 0, 50); // 50 char string
_
9
Sliq

文字列の連結を繰り返すよりも、最後に文字を結合する方が効率的です。

編集#1:文字の繰り返しを避けるオプションを追加しました。

編集#2:$ norepeatが選択され、$ lenが選択する文字セットよりも大きい場合、無限ループに入るのを避けるために例外をスローします。

編集#3:連想配列キーのルックアップは、配列を線形検索するよりも高速であるため、$ norepeatが選択されている場合、配列キーを使用して、選択したランダムな文字を格納します。

function Rand_str($len, $norepeat = true)
{
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $max = strlen($chars) - 1;

    if ($norepeat && len > $max + 1) {
        throw new Exception("Non repetitive random string can't be longer than charset");
    }

    $Rand_chars = array();

    while ($len) {
        $picked = $chars[mt_Rand(0, $max)];

        if ($norepeat) {
            if (!array_key_exists($picked, $Rand_chars)) {
                $Rand_chars[$picked] = true;
                $len--;
            }
        }
        else {
            $Rand_chars[] = $picked;
            $len--;
        }
    }

    return implode('', $norepeat ? array_keys($Rand_chars) : $Rand_chars);   
}
6
Imran

これはランダムな文字列を生成します

function generateRandomString($length=10) {
    $original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z'));
    $original_string = implode("", $original_string);
    return substr(str_shuffle($original_string), 0, $length);
}
echo generateRandomString(6);
4
Akhilraj N S

これのほとんどの側面についてはすでに説明しましたが、少し更新することをお勧めします。これを小売用に使用している場合は、ドメインABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789を避けます

代わりに使用:ABCDEFGHJKMNPQRSTUVWXY3456789

確かに、文字数ははるかに少なくなりますが、顧客がOを0、lを1またはZを2と間違えないようにすることで、手間を大幅に節約できます。また、入力に対してUPPERを実行すると、顧客は大文字または小文字を入力します-似ているように見えるため、混乱を招くこともあります。

2
CoderOfTheNight

ここにも私の貢献を追加すると思います。

function random_string($length) {
    $bytes_1 = openssl_random_pseudo_bytes($length);
    $hex_1 = bin2hex($bytes_1);
    $random_numbers = substr(sha1(Rand()), 0, $length);
    $bytes_2 = openssl_random_pseudo_bytes($length);
    $hex_2 = bin2hex($bytes_2);
    $combined_chars = $hex_1 . $random_numbers . $hex_2;
    $chars_crypted = hash('sha512', $combined_chars);

    return $chars_crypted;
}

ありがとう

2
zeeks

ランダム文字列が必要なのは何ですか?

これは、パスワードにリモートで類似したものに使用されますか?

ランダム文字列にanyセキュリティプロパティが必要な場合は、このスレッドのすべての安全でないrandom_int()回答の代わりにPHP 7のmt_Rand()関数を使用する必要があります。

/**
 * Generate a random string
 * 
 * @link https://paragonie.com/b/JvICXzh_jhLyt4y3
 *
 * @param int $length - How long should our random string be?
 * @param string $charset - A string of all possible characters to choose from
 * @return string
 */
function random_str($length = 32, $charset = 'abcdefghijklmnopqrstuvwxyz')
{
    // Type checks:
    if (!is_numeric($length)) {
        throw new InvalidArgumentException(
            'random_str - Argument 1 - expected an integer'
        );
    }
    if (!is_string($charset)) {
        throw new InvalidArgumentException(
            'random_str - Argument 2 - expected a string'
        );
    }

    if ($length < 1) {
        // Just return an empty string. Any value < 1 is meaningless.
        return '';
    }
    // This is the maximum index for all of the characters in the string $charset
    $charset_max = strlen($charset) - 1;
    if ($charset_max < 1) {
        // Avoid letting users do: random_str($int, 'a'); -> 'aaaaa...'
        throw new LogicException(
            'random_str - Argument 2 - expected a string at least 2 characters long'
        );
    }
    // Now that we have good data, this is the meat of our function:
    $random_str = '';
    for ($i = 0; $i < $length; ++$i) {
        $r = random_int(0, $charset_max);
        $random_str .= $charset[$r];
    }
    return $random_str;
}

PHP 7をまだ使用していない場合(この記事の執筆時点ではリリースされていないため、おそらくそうです))、 paragonie/random_compat 、これはPHP 5プロジェクトのrandom_bytes()およびrandom_int()のユーザーランド実装です。

セキュリティコンテキストの場合、alwaysrandom_int()Rand()などではなく、mt_Rand()を使用します。参照 ircmaxellの答え も同様です。

2
// @author http://codeascraft.etsy.com/2012/07/19/better-random-numbers-in-php-using-devurandom/                                                
function devurandom_Rand($min = 0, $max = 0x7FFFFFFF)
{
    $diff = $max - $min;
    if ($diff < 0 || $diff > 0x7FFFFFFF) {
        throw new RuntimeException('Bad range');
    }
    $bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
    if ($bytes === false || strlen($bytes) != 4) {
        throw new RuntimeException('Unable to get 4 bytes');
    }
    $ary = unpack('Nint', $bytes);
    $val = $ary['int'] & 0x7FFFFFFF; // 32-bit safe                           
    $fp = (float) $val / 2147483647.0; // convert to [0,1]                          
    return round($fp * $diff) + $min;
}

function build_token($length = 60, $characters_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
    $map_length = mb_strlen($characters_map)-1;
    $token = '';
    while ($length--) {
        $token .= mb_substr($characters_map, devurandom_Rand(0,$map_length),1);
    }
    return $token;
}

これは、PHPがmcryptでコンパイルされているUNIX環境でのみ機能します。

1
Gajus

元の文字をランダムに並べ替えてパスワードを作成しますか?一意の文字のみを含める必要がありますか?

Randを使用して、インデックスごとにランダムな文字を選択します。

0
Dario
echo substr(bin2hex(random_bytes(14)), 0, $length);

このコードは、バイナリから16進数に変換されたランダムなバイトを取得し、$ length変数に入れる限り、この16進数の文字列のサブストリングを取得します

0
Oscar Garcia

これは古い質問ですが、解決策を投稿してみてください...私は常にこの関数を使用してカスタムのランダムな英数字文字列を生成します...

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = mt_Rand(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
  $test = random_alphanumeric(50); // 50 characters
  echo $test;
?>

テスト:UFOruSSTCPIqxTRIIMTRkqjOGidcVlhYaS9gtwttxglheVugFM

2つ以上の一意の文字列が必要な場合は、このトリックを使用できます...

$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  if ($string_1 != $string_2) {
     break;
  }
}
echo $string_1;
echo "<br>\n";
echo $string_2;

$ string_1:tMYicqLCHEvENwYbMUUVGTfkROxKIekEB2YXx5FHyVByp3mlJO

$ string_2:XdMNJYpMlFRKFDlF6GhVn6jsBVNQ1BCCevj8yK2niFOgpDI2MU

これが役立つことを願っています。

0
Alessandro