web-dev-qa-db-ja.com

PHP:ランダムでユニークな英数字の文字列を生成するにはどうすればいいですか?

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

どうやってPHPを使ってそれらの一つを生成することができますか?

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

327
Andrew

セキュリティ上の注意 :この解決策は、あなたのランダム性の質がアプリケーションのセキュリティに影響を与える可能性がある状況では使用すべきではありません。特に Rand()uniqid()は暗号的に安全な乱数発生器ではありません 。安全な方法については、 Scottの回答 を参照してください。

あなたがそれが時間の経過とともに絶対的にユニークである必要がないならば:

md5(uniqid(Rand(), true))

そうでなければ(あなたがすでにあなたのユーザーのためのユニークなログインを決定していると仮定すると):

md5(uniqid($your_user_login, true))
271
loletech

私はちょうどこの同じ問題を解決する方法を調べていましたが、私は私の関数にもパスワード検索にも使えるトークンを作成して欲しいと思います。これは、トークンが推測される能力を制限する必要があることを意味します。 uniqid は時間に基づいており、php.netによれば "戻り値はmicrotime()とほとんど変わらない"ため、uniqidは基準を満たしていません。 PHPは、暗号的に安全なトークンを生成するために代わりにopenssl_random_pseudo_bytes()を使用することを推奨します。

手短に、そして要点をまとめると、次のとおりです。

bin2hex(openssl_random_pseudo_bytes($bytes))

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


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): PHP 7のリリースに伴い、標準ライブラリに上記のcrypto_Rand_secure関数を置き換え/改善/単純化できる2つの新しい関数が追加されました。 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); // edited

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

    return $token;
}
444
Scott

最も支持されているソリューションのオブジェクト指向バージョン

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

<?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

誰かに役立つことを願っています。乾杯!

86
Slava Fomin II

遅れていますが、 Scott's answer が提供する機能に基づいた良い研究データがあります。そこで、この5日間の自動テスト用にDigital Oceanのドロップレットを設定し、生成された一意の文字列をMySQLデータベースに格納しました。

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

enter image description here

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

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

31
Rehmat

この関数は数字と文字を使ってランダムな鍵を生成します。

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
30

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

}

// funtionを呼び出す

$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

それが将来誰かに役立つことを願っています:)

25
Developer

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

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

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

13
DudeOnRock

以下のコードを使用して、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);
7
Ramesh Kotkar
  1. お気に入りの乱数ジェネレータを使って乱数を生成する
  2. あなたのコードのアルファベットの文字数に一致する数を得るためにそれを乗算して除算
  3. あなたのコードのアルファベットでそのインデックスのアイテムを入手してください。
  4. 必要な長さになるまで1)から繰り返します

例(疑似コード)

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

これはあなたのための究極のユニークな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に置き換えることができますが、これは非常に長くなります。

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

4
Krishna Torque

本当にランダムな文字列のために、あなたは使うことができます

<?php

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

出力:

40a29479ec808ad4bcff288a48a25d5c

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

3
AMB

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

  • 最初に暗号的に安全な乱数バイトのセットを生成する

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

さて、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 _ の文字列の中でしかそのように動作しません。

2
Dylan Kas

これが私が使っているものです:

md5(time() . Rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b
2
Faraz Kelhini
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
Nidhin

検証リンクを扱うときはハッシュキーを使うのが好きです。マイクロタイムに基づいてハッシュするのでキーが同じでなければならない理由はないはずなので、マイクロタイムを使用し、MD5を使用することをハッシュすることをお勧めします。

  1. $key = md5(Rand());
  2. $key = md5(microtime());
1
codermjb

PHPでユニークな文字列を生成したい場合は、以下を試してください。

md5(uniqid().mt_Rand());

これでは、

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

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

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

1
akshaypjoshi

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

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);
}

Substr()がより '創造的'になるためのランダムな開始点を取得した後、配列[0-9、AZ]を10倍複製し、要素をシャッフルします:)多かれ少なかれ、私より創造的になる

1
Luiggi ZAMOL

これは、文字と数字(英数字)を含むランダムな文字列を生成することを可能にする単純な関数です。文字列の長さを制限することもできます。これらのランダムな文字列は、紹介コード、プロモーションコード、クーポンコードなど、さまざまな目的に使用できます。関数は以下の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
Arpit J.
<?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文字の長さのランダムな文字列を生成します。

0

これが私のプロジェクトで使っているもので、うまくいっていて、 UNIQUE RANDOM TOKEN が生成されます。

$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倍にしたことに注意してください。

それが役立つことを願っています:)

0
Kaszoni Ferencz

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

私はまた私の各ユーザーのためのユニークな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
Himanshu Sharma

これが一番いい方法だと思います。

str_shuffle(md5(Rand(0,100000)))
0
Davinder Kumar

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

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

私はいつもこの私の関数を使ってカスタムのランダムな英数字の文字列を生成しています。

<?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
Alessandro