PHP:ランダムで一意の英数字の文字列を生成する方法は?


380

検証リンクで使用する数字と文字を使用して、ランダムで一意の文字列を生成するにはどうすればよいでしょうか?あなたがウェブサイトでアカウントを作成するときのように、それはあなたにリンク付きのメールを送ります、そしてあなたはあなたのアカウントを確認するためにそのリンクをクリックしなければなりません...ええ...それらの1つ。

PHPを使用してそれらの1つを生成するにはどうすればよいですか?

更新:について覚えてuniqid()いるだけです。これは、マイクロ秒単位の現在時刻に基づいて一意の識別子を生成するPHP関数です。私はそれを使うと思います。


必要なのは、文字列と一様に分布した乱数だけです。
Artelius 09

10
アンドリューさん、Scott正解として選択してください。スコットはOpenSSLの暗号的に安全な擬似乱数ジェネレーター(CSPRNG)を使用しています。これは、プラットフォームに基づいて、最も安全なエントロピーのソースを選択します。
2013

3
2015年以降にこれを読んでいる人は、paragonie.com
blog / 2015/07

OpenSSL uniqidは安全ではありません。Random::alphanumericString($length)またはのようなものを使用しますRandom::alphanumericHumanString($length)
CAW

回答:


305

セキュリティに関する通知:このソリューションは、ランダム性の品質がアプリケーションのセキュリティに影響を与える可能性がある状況では使用しないでください。特に、rand()およびuniqid()、暗号の乱数発生器を固定されていません。安全な代替案については、スコットの回答を参照してください。

時間の経過とともに完全に一意である必要がない場合:

md5(uniqid(rand(), true))

それ以外の場合(ユーザーの一意のログインが既に決定されている場合):

md5(uniqid($your_user_login, true))

90
どちらの方法でも一意性は保証されません。md5関数の入力の長さは出力の長さよりも長く、en.wikipedia.org / wiki / Pigeonhole_principleによると、衝突が保証されています。一方、「一意の」IDを達成するためにハッシュに依存する人口が多いほど、少なくとも1つの衝突が発生する可能性が高くなります(en.wikipedia.org/wiki/Birthday_problemを参照)。ほとんどのソリューションで確率は小さいかもしれませんが、まだ存在しています。
Dariusz Walczak 2011

12
これは、ランダムな値を生成する安全な方法ではありません。スコットの答えを見てください。
ルーク

4
メールの確認が比較的すぐに期限切れになる場合、誰かが誰かのメールをいつか確認する可能性はごくわずかですが、リスクはごくわずかです。ただし、トークンを作成した後、DBにトークンが既に存在するかどうかを常に確認し、その場合は新しいトークンを選択することができます。ただし、そのコードスニペットの記述に費やす時間は、実行される可能性がほとんどないため、無駄になります。
Andrew

md5は16進値を返すことに注意してください。つまり、文字セットは[0-9]と[af]に制限されます。
Thijs Riezebeek

1
md5は衝突する可能性があり、uniqidのアドバンテージを台無しにしました
user151496

507

この同じ問題を解決する方法を調べたところですが、パスワードの取得にも使用できるトークンを作成する関数も必要です。これは、推測されるトークンの能力を制限する必要があることを意味します。のでuniqid、時間に基づいて、php.netによるとされ、「戻り値は()のmicrotimeから少し異なるがある」uniqidの基準を満たしていません。PHPでは、openssl_random_pseudo_bytes()代わりにを使用して暗号的に安全なトークンを生成することをお勧めします。

簡単、短く、要点は次のとおりです。

bin2hex(openssl_random_pseudo_bytes($bytes))

これにより、長さ= $ bytes * 2のランダムな英数字の文字列が生成されます。残念ながら、これにはのアルファベットしかありませんが、[a-f][0-9]機能します。


以下は、条件を満たす最も強力な関数です(これは、Erikの回答の実装バージョンです)。

function crypto_rand_secure($min, $max)
{
    $range = $max - $min;
    if ($range < 1) return $min; // not so random...
    $log = ceil(log($range, 2));
    $bytes = (int) ($log / 8) + 1; // length in bytes
    $bits = (int) $log + 1; // length in bits
    $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
    do {
        $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
        $rnd = $rnd & $filter; // discard irrelevant bits
    } while ($rnd > $range);
    return $min + $rnd;
}

function getToken($length)
{
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet); // edited

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[crypto_rand_secure(0, $max-1)];
    }

    return $token;
}

crypto_rand_secure($min, $max)rand()またはの代わりのドロップとして機能しmt_randます。openssl_random_pseudo_bytesを使用して、$ minと$ maxの間の乱数を作成します。

getToken($length)トークン内で使用するアルファベットを作成してから、長さの文字列を作成します$length

編集:私はソースを引用するのを怠った-http: //us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

編集(PHP7):PHP7のリリースに伴い、標準ライブラリに2つの新しい関数が追加され、上記のcrypto_rand_secure関数を置換/改善/簡略化できるようになりました。random_bytes($length)そしてrandom_int($min, $max)

http://php.net/manual/en/function.random-bytes.php

http://php.net/manual/en/function.random-int.php

例:

function getToken($length){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    $max = strlen($codeAlphabet);

    for ($i=0; $i < $length; $i++) {
        $token .= $codeAlphabet[random_int(0, $max-1)];
    }

    return $token;
}

2
同意した。平文のパスワード保存はひどいです!(私はblowfishを使用します。)トークンが生成された後は、トークンの所有者がパスワードをリセットできるため、トークンは有効な間はパスワードと同等です(そのように扱われます)。
スコット

23
ちょっと、私はあなたの優れたコードを便利なKohana Text :: random()メソッド機能と組み合わせて、この要旨を作成しました:gist.github.com/raveren/5555297
raveren

9
パーフェクト!長さ10文字でテストしました。100000トークン、それでも重複なし!
Sharpless512 2014

5
私はこのプロセスを使用したところ、非常に遅いことがわかりました。長さが36の場合、開発サーバーでタイムアウトしました。24の長さでも、約30秒かかりました。何を間違えたかわかりませんが、私には遅すぎたので、別の解決策を選びました。
シェーン

5
base64_encode代わりにbin2hexを使用して、大きなアルファベットの短い文字列を取得することもできます。
erjiang 2014年

91

最も投票されたソリューションのオブジェクト指向バージョン

スコットの答えに基づいてオブジェクト指向のソリューションを作成しました:

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://stackoverflow.com/a/13733588/1056679
 */
class RandomStringGenerator
{
    /** @var string */
    protected $alphabet;

    /** @var int */
    protected $alphabetLength;


    /**
     * @param string $alphabet
     */
    public function __construct($alphabet = '')
    {
        if ('' !== $alphabet) {
            $this->setAlphabet($alphabet);
        } else {
            $this->setAlphabet(
                  implode(range('a', 'z'))
                . implode(range('A', 'Z'))
                . implode(range(0, 9))
            );
        }
    }

    /**
     * @param string $alphabet
     */
    public function setAlphabet($alphabet)
    {
        $this->alphabet = $alphabet;
        $this->alphabetLength = strlen($alphabet);
    }

    /**
     * @param int $length
     * @return string
     */
    public function generate($length)
    {
        $token = '';

        for ($i = 0; $i < $length; $i++) {
            $randomKey = $this->getRandomInteger(0, $this->alphabetLength);
            $token .= $this->alphabet[$randomKey];
        }

        return $token;
    }

    /**
     * @param int $min
     * @param int $max
     * @return int
     */
    protected function getRandomInteger($min, $max)
    {
        $range = ($max - $min);

        if ($range < 0) {
            // Not so random...
            return $min;
        }

        $log = log($range, 2);

        // Length in bytes.
        $bytes = (int) ($log / 8) + 1;

        // Length in bits.
        $bits = (int) $log + 1;

        // Set all lower bits to 1.
        $filter = (int) (1 << $bits) - 1;

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));

            // Discard irrelevant bits.
            $rnd = $rnd & $filter;

        } while ($rnd >= $range);

        return ($min + $rnd);
    }
}

使用法

<?php

use Utils\RandomStringGenerator;

// Create new instance of generator class.
$generator = new RandomStringGenerator;

// Set token length.
$tokenLength = 32;

// Call method to generate random string.
$token = $generator->generate($tokenLength);

カスタムアルファベット

必要に応じて、カスタムアルファベットを使用できます。サポートされている文字列をコンストラクタまたはセッターに渡すだけです。

<?php

$customAlphabet = '0123456789ABCDEF';

// Set initial alphabet.
$generator = new RandomStringGenerator($customAlphabet);

// Change alphabet whenever needed.
$generator->setAlphabet($customAlphabet);

これが出力サンプルです

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

誰かのお役に立てば幸いです。乾杯!


申し訳ありませんが、どうすれば実行できますか?実行しました$obj = new RandomStringGenerator;が、どのメソッドを呼び出す必要がありますか?ありがとうございました。
sg552 2014年

@ sg552、generate上記の例のようにメソッドを呼び出す必要があります。整数をそれに渡して、結果の文字列の長さを指定します。
Slava Fomin II 14

おかげで私にとってCustom Alphabetはうまくいきましたが、うまくいきませんでした。エコーすると、出力が空になります。とにかく、2番目の例の用途が何かわからないCustom Alphabetので、最初の例をそのまま使用すると思います。ありがとう。
sg552 14

1
ニース、しかしかなり行き過ぎほとんどのシナリオでは、プロジェクトが頻繁にランダムに生成されたコードに依存していない限り
dspacejs

1
はい、いいですがやりすぎです。特に、php 5.7の場合はかなり非推奨になりました
Andrew

39

遅くなりましたが、スコットの回答が提供する機能に基づいたいくつかの優れた調査データを用意しています。そこで、この5日間の長い自動テストのためにDigital Oceanドロップレットをセットアップし、生成された一意の文字列をMySQLデータベースに保存しました。

このテスト期間中、5つの異なる長さ(5、10、15、20、50)を使用し、各長さに+/- 0.5百万のレコードが挿入されました。私のテスト中、長さ5のみが50万個から+/- 3Kの複製を生成し、残りの長さは複製を生成しませんでした。したがって、スコットの関数で15以上の長さを使用すると、信頼性の高い一意の文字列を生成できると言えます。これが私の研究データを示す表です:

ここに画像の説明を入力してください

更新:これらの関数を使用して、トークンをJSON応答として返す単純なHerokuアプリを作成しました。アプリはhttps://uniquestrings.herokuapp.com/api/token?length=15でアクセスできます

これがお役に立てば幸いです。


33

UUID(Universally Unique Identifier)を使用できます。ユーザー認証文字列から支払いトランザクションIDまで、あらゆる目的に使用できます。

UUIDは16オクテット(128ビット)の数値です。正規の形式では、UUIDは32個の16進数字で表され、ハイフンで区切られた5つのグループに8-4-4-4-12の形式で合計36文字(32文字の英数字と4つのハイフン)で表示されます。

function generate_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
        mt_rand( 0, 0xffff ),
        mt_rand( 0, 0x0C2f ) | 0x4000,
        mt_rand( 0, 0x3fff ) | 0x8000,
        mt_rand( 0, 0x2Aff ), mt_rand( 0, 0xffD3 ), mt_rand( 0, 0xff4B )
    );

}

//関数を呼び出す

$transationID = generate_uuid();

いくつかの出力例は次のようになります:

E302D66D-87E3-4450-8CB6-17531895BF14
22D288BC-7289-442B-BEEA-286777D559F2
51B4DE29-3B71-4FD2-9E6C-071703E1FF31
3777C8C6-9FF5-4C78-AAA2-08A47F555E81
54B91C72-2CF4-4501-A6E9-02A60DCBAE4C
60F75C7C-1AE3-417B-82C8-14D456542CD7
8DE0168D-01D3-4502-9E59-10D665CEBCB2

それが将来誰かを助けることを願っています:)


私のリストに追加された素晴らしいですね!
Mustafa Erdogan

32

この関数は、数字と文字を使用してランダムなキーを生成します:

function random_string($length) {
    $key = '';
    $keys = array_merge(range(0, 9), range('a', 'z'));

    for ($i = 0; $i < $length; $i++) {
        $key .= $keys[array_rand($keys)];
    }

    return $key;
}

echo random_string(50);

出力例:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

6
しばらくすると、同じ数字になります
Sharpless512

1
同じchacaterが2回以上存在しないため、これは完全にランダムではありません。
EricP

16

私はこのワンライナーを使用します:

base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));

ここで、lengthは目的の文字列の長さです(4で割り切れない場合、4で割り切れる最も近い数値に切り捨てられます)。


6
常に英数字のみを返すわけではありません。次のような文字を含めることができます==
user3459110 2014年

1
URLで使用する場合は、base64url_encode代わりに使用できます。php.net
Paul

9

以下のコードを使用して、11文字の乱数を生成するか、必要に応じて数値を変更します。

$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 11);

または、カスタム関数を使用して乱数を生成できます

 function randomNumber($length){
     $numbers = range(0,9);
     shuffle($numbers);
     for($i = 0;$i < $length;$i++)
        $digits .= $numbers[$i];
     return $digits;
 }

 //generate random number
 $randomNum=randomNumber(11);

3
これは、文字列 "aaaaaaaaaaa"または "aaaaabbbbbb"を生成することはできません。アルファベットのランダムな順列の部分文字列を選択するだけです。11文字の長い文字列には、V(11,35)= 288の可能な値のみがあります。文字列が一意であると予想される場合は、これを使用しないでください。
kdojeteri 2017

@Peping then dosubstr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstvwxyz', 36)), 0, 11);
Tim Hallman

7
  1. お気に入りの乱数ジェネレータを使用して乱数を生成します
  2. 乗算および除算して、コードアルファベットの文字数と一致する数を取得します
  3. コードアルファベットのインデックスにあるアイテムを取得します。
  4. 必要な長さになるまで1)から繰り返します

例(疑似コード)

int myInt = random(0, numcharacters)
char[] codealphabet = 'ABCDEF12345'
char random = codealphabet[i]
repeat until long enough

理論的には、これにより同じ文字列が2回以上生成される可能性はありませんか?
-frezq

4

ここにあなたのための究極のユニークなIDジェネレータがあります。私が作った。

<?php
$d=date ("d");
$m=date ("m");
$y=date ("Y");
$t=time();
$dmt=$d+$m+$y+$t;    
$ran= rand(0,10000000);
$dmtran= $dmt+$ran;
$un=  uniqid();
$dmtun = $dmt.$un;
$mdun = md5($dmtran.$un);
$sort=substr($mdun, 16); // if you want sort length code.

echo $mdun;
?>

あなたは好きなようにあなたのIDにどんな 'var'をエコーすることができます。しかし$ mdunの方が優れています。より良いコードのためにmd5をsha1に置き換えることができますが、それは非常に長くなるため、必要ない場合があります。

ありがとうございました。


7
この場合、ランダム性はランダムに書かれたコードによって保証されますよね?
Daniel Kucal

3
ええ、これは非標準で曖昧なコードであるため、一種の「ランダム」です。これにより、予測が難しくなりますが、実際には、安全でない部分を使用して乱数を生成します。したがって、結果は技術的にランダムでも安全でもありません。
フィリップ

4

本当にランダムな文字列の場合、使用できます

<?php

echo md5(microtime(true).mt_Rand());

出力:

40a29479ec808ad4bcff288a48a25d5c

したがって、文字列を同時に複数回生成しようとしても、異なる出力が得られます。


4

ランダムなパスワードを生成しようとすると、次のことを試みます:

  • まず、暗号で保護されたランダムバイトのセットを生成します。

  • 2つ目は、ランダムなバイトを印刷可能な文字列に変換することです

今、PHPでランダムなバイトを生成する方法は複数あります:

$length = 32;

//PHP 7+
$bytes= random_bytes($length);

//PHP < 7
$bytes= openssl_random_pseudo_bytes($length);

次に、これらのランダムなバイトを印刷可能な文字列に変換します。

あなたはbin2hexを使うことができます:

$string = bin2hex($bytes);

またはbase64_encode

$string = base64_encode($bytes);

ただし、base64を使用する場合は、文字列の長さを制御しないことに注意してください。これを行うにはbin2hexを使用できます。32 バイトを使用すると、64文字の文字列になります。しかし、それはEVEN文字列でのみそのように機能します。

だから基本的にあなたはただ行うことができます

$length = 32;

if(PHP_VERSION>=7){
    $bytes= random_bytes($length);
}else{
    $bytes= openssl_random_pseudo_bytes($length);
} 

$string = bin2hex($bytes);


2
function random_string($length = 8) {
    $alphabets = range('A','Z');
    $numbers = range('0','9');
    $additional_characters = array('_','=');
    $final_array = array_merge($alphabets,$numbers,$additional_characters);
       while($length--) {
      $key = array_rand($final_array);

      $password .= $final_array[$key];
                        }
  if (preg_match('/[A-Za-z0-9]/', $password))
    {
     return $password;
    }else{
    return  random_string();
    }

 }

2

これは、文字と数字(英数字)を含むランダムな文字列を生成できる単純な関数です。文字列の長さを制限することもできます。これらのランダムな文字列は、紹介コード、プロモーションコード、クーポンコードなど、さまざまな目的に使用できます。関数は次のPHP関数に依存しています: base_convert、sha1、uniqid、mt_rand

function random_code($length)
{
  return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, $length);
}

echo random_code(6);

/*sample output
* a7d9e8
* 3klo93
*/

1

以前の例を読んだ後、私はこれを思いつきました:

protected static $nonce_length = 32;

public static function getNonce()
{
    $chars = array();
    for ($i = 0; $i < 10; $i++)
        $chars = array_merge($chars, range(0, 9), range('A', 'Z'));
    shuffle($chars);
    $start = mt_rand(0, count($chars) - self::$nonce_length);
    return substr(join('', $chars), $start, self::$nonce_length);
}

array [0-9、AZ]を10回複製し、要素をシャッフルします。substr()のランダムな開始点を取得してより「創造的」にした後、[az]と他の要素を配列に追加して複製します。多かれ少なかれ、私より創造的です


1

検証リンクを処理するときにハッシュキーを使用するのが好きです。マイクロタイムに基づいてハッシュするため、キーが同じである必要はないため、マイクロタイムとMD5を使用したハッシュを使用することをお勧めします。

  1. $key = md5(rand());
  2. $key = md5(microtime());

1
<?php
function generateRandomString($length = 11) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;

}

?>

上記の関数は、11文字の長さのランダムな文字列を生成します。


1

PHPで一意の文字列を生成する場合は、以下を試してください。

md5(uniqid().mt_rand());

これで、

uniqid()-それはユニークな文字列を生成します。この関数は、タイムスタンプベースの一意の識別子を文字列として返します。

mt_rand() -乱数を生成します。

md5() -ハッシュ文字列を生成します。


0

スコット、そうですね、あなたはとても書いていて良い解決策です!ありがとう。

また、ユーザーごとに一意のAPIトークンを生成する必要があります。以下は私のアプローチですが、ユーザー情報(ユーザーIDとユーザー名)を使用しました。

public function generateUniqueToken($userid, $username){

        $rand = mt_rand(100,999);
    $md5 = md5($userid.'!(&^ 532567_465 ///'.$username);

    $md53 = substr($md5,0,3);
    $md5_remaining = substr($md5,3);

    $md5 = $md53. $rand. $userid. $md5_remaining;

    return $md5;
}

ぜひご覧になり、改善できる点があればお知らせください。ありがとう


0

ここに私が私のプロジェクトの1つで使用しているものがあり、それは素晴らしい働きをしていて、それはユニークなランダムトークンを生成します:

$timestampz=time();

function generateRandomString($length = 60) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}


$tokenparta = generateRandomString();


$token = $timestampz*3 . $tokenparta;

echo $token;

このトークンがどのように生成されるのか疑問に思うユーザーを混乱させるために、タイムスタンプを3倍したことに注意してください。

それが役に立てば幸いです:)


1
難読化によるセキュリティのように聞こえる「私は、ユーザーが、このトークンが生成される様子を不思議に思われるかもしれません誰のための混乱を作成するための3つでタイムスタンプを掛けたことをしてくださいノート」stackoverflow.com/questions/533965/...
ハリー

これは「難読化によるセキュリティ」ではなく、生成されたランダムな文字列にタイムスタンプが追加されます。これは、返される実際の最終文字列です;)
Kaszoni Ferencz


0

この2行のコードを使用して、一意の文字列を生成し、約10000000回の反復をテストできます。

  $sffledStr= str_shuffle('abscdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_-+');
    $uniqueString = md5(time().$sffledStr);

0

私は常にこの関数を使用してカスタムのランダムな英数字の文字列を生成します...このヘルプを願っています。

<?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;
  }
  echo random_alphanumeric(50); // 50 characters
?>

たとえば、Y1FypdjVbFCFK6Gh9FDJpe6dciwJEfV6MQGpJqAfuijaYSZ86gが生成されます。

別の文字列と比較して、それが一意のシーケンスであることを確認したい場合は、このトリックを使用できます...

$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;

2つの一意の文字列を生成します。

qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi

Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF

これがあなたが探しているものであることを願っています...


0

簡単な解決策は、英数字以外の文字を破棄して、base 64を英数字に変換することです。

これは、暗号的に安全な結果を得るために、random_bytes()を使用します。

function random_alphanumeric(int $length): string
{
    $result='';
    do
    {
        //Base 64 produces 4 characters for each 3 bytes, so most times this will give enough bytes in a single pass
        $bytes=random_bytes(($length+3-strlen($result))*2);
        //Discard non-alhpanumeric characters
        $result.=str_replace(['/','+','='],['','',''],base64_encode($bytes));
        //Keep adding characters until the string is long enough
        //Add a few extra because the last 2 or 3 characters of a base 64 string tend to be less diverse
    }while(strlen($result)<$length+3);
    return substr($result,0,$length);
}


-1

私は、既存のすべてのアイデアの問題は、それらはおそらく一意であるが、完全に一意ではないことだと思います(loletechに対するDariusz Walczakの応答で指摘されているように)。実際にユニークなソリューションがあります。スクリプトには何らかのメモリが必要です。私にとってこれはSQLデータベースです。また、単にどこかにファイルに書き込むこともできます。2つの実装があります。

最初の方法:一意性を提供する1つではなく2つのフィールドがあります。最初のフィールドはランダムではないが一意のID番号です(最初のIDは1、2番目は2 ...)。SQLを使用している場合は、AUTO_INCREMENTプロパティを使用してIDフィールドを定義するだけです。2番目のフィールドは一意ではありませんが、ランダムです。これは、人々がすでに述べた他の技術のいずれかで生成できます。スコットのアイデアは良かったのですが、md5は便利で、おそらくほとんどの目的には十分です。

$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());

2番目の方法:基本的には同じアイデアですが、最初は生成される文字列の最大数を選択します。これは、1兆のような非常に大きな数になる可能性があります。次に、同じことを行い、IDを生成しますが、すべてのIDが同じ桁数になるようにゼロパッドします。次に、IDをランダムな文字列と連結します。それはほとんどの目的のために十分ランダムですが、IDセクションはそれが一意であることも保証します。


-1

あなたはこのコードを使用することができます、それがあなたのために役立つことを願っています。

function rand_code($len)
{
 $min_lenght= 0;
 $max_lenght = 100;
 $bigL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 $smallL = "abcdefghijklmnopqrstuvwxyz";
 $number = "0123456789";
 $bigB = str_shuffle($bigL);
 $smallS = str_shuffle($smallL);
 $numberS = str_shuffle($number);
 $subA = substr($bigB,0,5);
 $subB = substr($bigB,6,5);
 $subC = substr($bigB,10,5);
 $subD = substr($smallS,0,5);
 $subE = substr($smallS,6,5);
 $subF = substr($smallS,10,5);
 $subG = substr($numberS,0,5);
 $subH = substr($numberS,6,5);
 $subI = substr($numberS,10,5);
 $RandCode1 = str_shuffle($subA.$subD.$subB.$subF.$subC.$subE);
 $RandCode2 = str_shuffle($RandCode1);
 $RandCode = $RandCode1.$RandCode2;
 if ($len>$min_lenght && $len<$max_lenght)
 {
 $CodeEX = substr($RandCode,0,$len);
 }
 else
 {
 $CodeEX = $RandCode;
 }
 return $CodeEX;
}

PHPのランダムコードジェネレーターの詳細


-2

上記のScottsコードを簡素化し、低速になり、openssl_random_pseudo_bytesを1回だけ呼び出すよりも安全でない不要なループを削除します

function crypto_rand_secure($min, $max)
{
 $range = $max - $min;
 if ($range < 1) return $min; // not so random...
 $log = ceil(log($range, 2));
 $bytes = (int) ($log / 8) + 1; // length in bytes
 $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
 return $min + $rnd%$range;
}

function getToken($length)
{
 return bin2hex(openssl_random_pseudo_bytes($length)
}

残念ながら、これがcrypto_rand_secure関数の適切な簡略化であることには同意できません。このループは、ランダムに生成された数値の結果を取り、範囲を分割する数値でそれを変調するときに発生するモジュロバイアスを回避するために必要です。en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#Modulo_bias。ループを使用して範囲外の数値を破棄し、新しい数値を選択することにより、このバイアスを回避します。stackoverflow.com/questions/10984974/...
スコット・

@Scott、その投稿はrand()についてです。ただし、この場合、openssl_random_pseudo_bytesによってすでに処理されているため、ループは不要です。
mabel

1
gist.github.com/anonymous/87e3ae6fd3320447f46b973e75c2ea85-このスクリプトを実行してください。結果の分布はランダムではないことがわかります。0〜55の数値は、56〜100の数値よりも出現頻度が高くなります。opensslこれが原因ではありません。これは、returnステートメントのモジュロバイアスが原因です。100(範囲)は255(1バイト)を均等に分割せず、これらの結果を引き起こします。あなたの答えに関する私の最大の問題は、関数がループを使用するのと同じくらい安全であると述べていることです。これは誤りです。crypto_rand_secureの実装は暗号的に安全ではなく、誤解を招くおそれがあります。
Scott

@Scott、ここで細かく説明します。これは最後のreturnステートメントではなく、openssl_random_pseudo_bytesの戻り値からモジュロを使用せずに徐々に計算することもできます。私が指摘している点は、openssl_random_pseudo_bytesがランダムなバイトを返すとループが不要になるということです。ループを作ることで、それをより安全にするのではなく、ただ遅くするだけです。
mabel

2
この答えは悪い情報を伝えます。opensslこの答えは、ループが安全性を向上させないことは正しいですが、さらに重要なことには、安全性が低下することではありません。上記のコードは、完全に適切な乱数を取得し、それをより低い数にバイアスすることによってそれをマングルします。(ループを削除することにより)より高速であることを示す免責事項を回答に付けたが、それがCSPRNGではない場合、この問題は解決されます。暗号化が大好きなため、この関数の出力はバイアスされる可能性があり、同等のソリューションではないことをユーザーに知らせてください。ループはあなたを困らせるだけではありません。
Scott
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.