PHP:如何生成一个随机的、唯一的、字母数字的字符串?

时间:2022-11-24 21:36:01

How would it be possible to generate a random, unique string using numbers and letters for use in a verify link? Like when you create an account on a website, and it sends you an email with a link, and you have to click that link in order to verify your account...yeah...one of those.

如何使用数字和字母在验证链接中生成一个随机的、唯一的字符串?比如当你在一个网站上创建一个帐户,它给你发送一个链接的电子邮件,你必须点击那个链接来验证你的帐户…其中之一。

How can I generate one of those using PHP?

如何使用PHP生成其中一个?

Update: Just remembered about uniqid(). It's a PHP function that generates a unique identifier based on the current time in microseconds. I think I'll use that.

更新:只记得uniqid()。它是一个PHP函数,它根据当前时间在微秒内生成唯一标识符。我想我会用这个。

21 个解决方案

#1


227  

Security Notice: This solution should not be used in situations where the quality of your randomness can affect the security of an application. In particular, rand() and uniqid() are not cryptographically secure random number generators. See Scott's answer for a secure alternative.

安全通知:此解决方案不应在您的随机性质量影响应用程序安全性的情况下使用。特别是,rand()和uniqid()不是加密安全的随机数生成器。看看斯科特对安全替代方案的回答。

If you do not need it to be absolutely unique over time:

如果你不需要它是绝对独特的时间:

md5(uniqid(rand(), true))

函数md5(rand(),是真的))

Otherwise (given you have already determined a unique login for your user):

否则(因为您已经为您的用户确定了一个唯一的登录):

md5(uniqid($your_user_login, true))

#2


375  

I was just looking into how to solve this same problem, but I also want my function to create a token that can be used for password retrieval as well. This means that I need to limit the ability of the token to be guessed. Because uniqid is based on the time, and according to php.net "the return value is little different from microtime()", uniqid does not meet the criteria. PHP recommends using openssl_random_pseudo_bytes() instead to generate cryptographically secure tokens.

我正在研究如何解决这个问题,但我也希望我的函数能够创建一个令牌,也可以用于密码检索。这意味着我需要限制令牌的猜测能力。因为uniqid是基于时间的,根据php.net,“返回值与microtime()略有不同”,uniqid不符合标准。PHP建议使用openssl_random_pseudo_bytes()来生成密码安全令牌。

A quick, short and to the point answer is:

一个简短的,简短的回答是:

bin2hex(openssl_random_pseudo_bytes($bytes))

which will generate a random string of alphanumeric characters of length = $bytes * 2. Unfortunately this only has an alphabet of [a-f][0-9], but it works.

它将生成一个字符串长度= $字节* 2的随机字符串。不幸的是,这只有一个字母表[a-f][0-9],但它起作用了。


Below is the strongest function I could make that satisfies the criteria (This is an implemented version of Erik's answer).

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) works as a drop in replacement for rand() or mt_rand. It uses openssl_random_pseudo_bytes to help create a random number between $min and $max.

crypto_rand_secure($min, $max)作为替换rand()或mt_rand的替代。它使用openssl_random_pseudo_bytes来帮助在$min和$max之间创建一个随机数。

getToken($length) creates an alphabet to use within the token and then creates a string of length $length.

getToken($length)创建一个在令牌中使用的字母表,然后创建一个长度为$length的字符串。

EDIT: I neglected to cite source - http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

编辑:我忽略了引用源- http://us1.php.net/manual/en/function.openssl-random-伪bytes.php#104322。

EDIT (PHP7): With the release of PHP7, the standard library now has two new functions that can replace/improve/simplify the crypto_rand_secure function above. random_bytes($length) and random_int($min, $max)

编辑(PHP7):随着PHP7的发布,标准库现在有两个新的函数可以替代/改进/简化上面的crypto_rand_secure函数。random_bytes(长度)和random_int(min,max)美元

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

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

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

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

Example:

例子:

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

#3


79  

Object-oriented version of the most up-voted solution

I've created an object-oriented solution based on Scott's answer:

基于Scott的回答,我创建了一个面向对象的解决方案:

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://*.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);
    }
}

Usage

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

Custom alphabet

You can use custom alphabet if required. Just pass a string with supported chars to the constructor or setter:

如果需要,您可以使用自定义字母。只需将一个字符串传递给构造函数或setter:

<?php

$customAlphabet = '0123456789ABCDEF';

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

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

Here's the output samples

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

I hope it will help someone. Cheers!

我希望它能帮助别人。干杯!

#4


28  

This function will generate a random key using numbers and letters:

该函数将使用数字和字母生成一个随机密钥:

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

Example output:

示例输出:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

#5


17  

You can use UUID(Universally Unique Identifier), it can be used for any purpose, from user authentication string to payment transaction id.

您可以使用UUID(通用惟一标识符),它可以用于任何目的,从用户身份验证字符串到支付事务id。

A UUID is a 16-octet (128-bit) number. In its canonical form, a UUID is represented by 32 hexadecimal digits, displayed in five groups separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters (32 alphanumeric characters and four hyphens).

UUID是一个16字节(128位)的数字。在它的规范形式中,UUID以32个十六进制数字表示,由连字符分隔的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 )
    );

}

//calling funtion

/ /调用函数

$transationID = generate_uuid();

some example outputs will be like:

一些示例输出如下:

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

hope it helps someone in future :)

希望它能帮助未来的某人

#6


13  

I'm late but I'm here with some good research data based on the functions provided by Scott's answer. So I set up a Digital Ocean droplet just for this 5-day long automated test and stored the generated unique strings in a MySQL database.

我很晚了,但我在这里有一些很好的研究数据,基于斯科特的回答所提供的功能。因此,我设置了一个数字海洋小液滴,只为了这个为期5天的自动化测试,并将生成的唯一字符串存储在MySQL数据库中。

During this test period, I used 5 different lengths (5, 10, 15, 20, 50) and +/-0.5 million records were inserted for each length. During my test, only the length 5 generated +/-3K duplicates out of 0.5 million and the remaining lengths didn't generate any duplicates. So we can say that if we use a length of 15 or above with Scott's functions, then we can generate highly reliable unique strings. Here is the table showing my research data:

在这个测试期间,我使用了5个不同的长度(5、10、15、20、50)和+/- 50万条记录。在我的测试中,只有5个生成的+/-3K复制出了50万,其余的长度没有产生任何重复。所以我们可以说,如果我们用一个15或以上的长度和Scott的函数,我们就可以生成高度可靠的唯一字符串。这是我的研究数据表:

PHP:如何生成一个随机的、唯一的、字母数字的字符串?

I hope this helps.

我希望这可以帮助。

#7


11  

I use this one-liner:

我用这个小笑话:

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

where length is the length of the desired string (divisible by 4, otherwise it gets rounded down to the nearest number divisible by 4)

其中长度为所需字符串的长度(可被4整除,否则它会被四舍五入到最接近的数字4)

#8


7  

  1. Generate a random number using your favourite random-number generator
  2. 使用你最喜欢的随机数生成器生成一个随机数。
  3. Multiply and divide it to get a number matching the number of characters in your code alphabet
  4. 用乘法和除法运算得到一个数字,与你的代码字母表中的字符数相匹配。
  5. Get the item at that index in your code alphabet.
  6. 在代码字母表中获取该索引项。
  7. Repeat from 1) until you have the length you want
  8. 重复一遍,直到你有你想要的长度。

e.g (in pseudo code)

e。g(伪代码)

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

#9


4  

Here is ultimate unique id generator for you. made by me.

这是你的终极唯一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;
?>

you can echo any 'var' for your id as you like. but $mdun is better, you can replace md5 to sha1 for better code but that will be very long which may you dont need.

您可以根据您的需要对任何“var”进行echo。但是$mdun更好,您可以将md5替换为sha1,以获得更好的代码,但是这将是非常长的,这可能您不需要。

Thank you.

谢谢你!

#10


3  

Use below code to generate the random number of 11 characters or change the number as per your requirement.

使用下面的代码生成随机数11个字符或根据您的需求更改数字。

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

or we can use custom function to generate the random number

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

#11


1  

Here is what I use:

以下是我所使用的:

md5(time() . rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b

#12


1  

I like to use hash keys when dealing verification links. I would recommend using the microtime and hashing that using MD5 since there should be no reason why the keys should be the same since it hashes based off of the microtime.

在处理验证链接时,我喜欢使用散列键。我将建议使用microtime并使用MD5进行哈希,因为应该没有理由为什么键应该是相同的,因为它是基于microtime的。

  1. $key = md5(rand());
  2. $关键= md5(rand());
  3. $key = md5(microtime());
  4. $关键= md5(());

#13


1  

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

 }

#14


0  

Scott, yes you are very write and good solution! Thanks.

斯科特,你写得很好!谢谢。

I am also required to generate unique API token for my each user. Following is my approach, i used user information (Userid and Username):

我还需要为我的每个用户生成唯一的API令牌。下面是我的方法,我使用了用户信息(用户名和用户名):

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

Please have a look and let me know if any improvement i can do. Thanks

请您看一看,如果有什么改进的话,请告诉我。谢谢

#15


0  

after reading previous examples I came up with this:

在阅读了之前的例子之后,我想到了这个:

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

I duplicate 10 times the array[0-9,A-Z] and shuffle the elements, after I get a random start point for substr() to be more 'creative' :) you can add [a-z] and other elements to array, duplicate more or less, be more creative than me

我复制了10倍的数组[0-9,a-z],然后对元素进行洗牌,在我得到一个随机的起始点后,substr()会变得更“有创意”:)你可以添加[a-z]和其他元素来数组,复制或多或少,比我更有创造力。

#16


0  

I think this is the best method to use.

我认为这是最好的方法。

str_shuffle(md5(rand(0,100000)))

#17


0  

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

}

?>

above function will generate you a random string which is length of 11 characters.

上面的函数将生成一个长度为11个字符的随机字符串。

#18


-1  

I believe the problem with all the existing ideas is that they are probably unique, but not definitely unique (as pointed out in Dariusz Walczak's reply to loletech). I have a solution that actually is unique. It requires that your script have some sort of memory. For me this is a SQL database. You could also simply write to a file somewhere. There are two implementations:

我认为所有现存的想法的问题在于它们可能是独一无二的,但并不是绝对独一无二的(正如Dariusz Walczak对loletech的回复中所指出的那样)。我有一个独特的解决方案。它要求您的脚本具有某种内存。对我来说,这是一个SQL数据库。您也可以简单地在某个地方写一个文件。有两种实现:

First method: have TWO fields rather than 1 that provide uniqueness. The first field is an ID number that is not random but is unique (The first ID is 1, the second 2...). If you are using SQL, just define the ID field with the AUTO_INCREMENT property. The second field is not unique but is random. This can be generated with any of the other techniques people have already mentioned. Scott's idea was good, but md5 is convenient and probably good enough for most purposes:

第一种方法:有两个字段,而不是一个提供惟一性的字段。第一个字段是一个ID号,它不是随机的,而是唯一的(第一个ID是1,第二个是2…)。如果使用SQL,只需使用AUTO_INCREMENT属性定义ID字段。第二个领域不是唯一的,而是随机的。这可以用人们已经提到过的其他技术来生成。斯科特的想法很好,但是md5很方便,而且很可能足够好,可以达到大多数目的:

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

Second method: Basically the same idea, but initially pick a maximum number of strings that will ever be generated. This could just be a really big number like a trillion. Then do the same thing, generate an ID, but zero pad it so that all IDs are the same number of digits. Then just concatenate the ID with the random string. It will be random enough for most purposes, but the ID section will ensure that it is also unique.

第二种方法:基本相同的想法,但最初选择的字符串的最大数量将会生成。这可能是一个非常大的数字,像一万亿。然后做同样的事情,生成一个ID,但是0填充它,这样所有的ID都是相同的数字。然后将ID与随机字符串连接起来。它在大多数情况下都是随机的,但是ID部分将确保它也是唯一的。

#19


-1  

Here is what I'm using on one of my projects, it's working great and it generates a 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;

Please note that I multiplied the timestamp by three to create a confusion for whoever user might be wondering how this token is generated ;)

请注意,我将时间戳乘以了3,以创建一个混淆,因为用户可能想知道这个标记是如何生成的;

I hope it helps :)

我希望它有帮助:)

#20


-1  

You can use this code, I hope it will be helpful for you.

您可以使用这段代码,我希望它对您有帮助。

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

Details about Random code generator in PHP

有关PHP中随机代码生成器的详细信息。

#21


-1  

Simplifying Scotts code above by removing unnecessary loops which is slowing down badly and does not make it any more secure than calling openssl_random_pseudo_bytes just once

通过删除不需要的循环,从而简化了上面的Scotts代码,并没有使它更安全,而不是只调用openssl_random_pseudo_bytes一次。

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

#1


227  

Security Notice: This solution should not be used in situations where the quality of your randomness can affect the security of an application. In particular, rand() and uniqid() are not cryptographically secure random number generators. See Scott's answer for a secure alternative.

安全通知:此解决方案不应在您的随机性质量影响应用程序安全性的情况下使用。特别是,rand()和uniqid()不是加密安全的随机数生成器。看看斯科特对安全替代方案的回答。

If you do not need it to be absolutely unique over time:

如果你不需要它是绝对独特的时间:

md5(uniqid(rand(), true))

函数md5(rand(),是真的))

Otherwise (given you have already determined a unique login for your user):

否则(因为您已经为您的用户确定了一个唯一的登录):

md5(uniqid($your_user_login, true))

#2


375  

I was just looking into how to solve this same problem, but I also want my function to create a token that can be used for password retrieval as well. This means that I need to limit the ability of the token to be guessed. Because uniqid is based on the time, and according to php.net "the return value is little different from microtime()", uniqid does not meet the criteria. PHP recommends using openssl_random_pseudo_bytes() instead to generate cryptographically secure tokens.

我正在研究如何解决这个问题,但我也希望我的函数能够创建一个令牌,也可以用于密码检索。这意味着我需要限制令牌的猜测能力。因为uniqid是基于时间的,根据php.net,“返回值与microtime()略有不同”,uniqid不符合标准。PHP建议使用openssl_random_pseudo_bytes()来生成密码安全令牌。

A quick, short and to the point answer is:

一个简短的,简短的回答是:

bin2hex(openssl_random_pseudo_bytes($bytes))

which will generate a random string of alphanumeric characters of length = $bytes * 2. Unfortunately this only has an alphabet of [a-f][0-9], but it works.

它将生成一个字符串长度= $字节* 2的随机字符串。不幸的是,这只有一个字母表[a-f][0-9],但它起作用了。


Below is the strongest function I could make that satisfies the criteria (This is an implemented version of Erik's answer).

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) works as a drop in replacement for rand() or mt_rand. It uses openssl_random_pseudo_bytes to help create a random number between $min and $max.

crypto_rand_secure($min, $max)作为替换rand()或mt_rand的替代。它使用openssl_random_pseudo_bytes来帮助在$min和$max之间创建一个随机数。

getToken($length) creates an alphabet to use within the token and then creates a string of length $length.

getToken($length)创建一个在令牌中使用的字母表,然后创建一个长度为$length的字符串。

EDIT: I neglected to cite source - http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322

编辑:我忽略了引用源- http://us1.php.net/manual/en/function.openssl-random-伪bytes.php#104322。

EDIT (PHP7): With the release of PHP7, the standard library now has two new functions that can replace/improve/simplify the crypto_rand_secure function above. random_bytes($length) and random_int($min, $max)

编辑(PHP7):随着PHP7的发布,标准库现在有两个新的函数可以替代/改进/简化上面的crypto_rand_secure函数。random_bytes(长度)和random_int(min,max)美元

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

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

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

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

Example:

例子:

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

#3


79  

Object-oriented version of the most up-voted solution

I've created an object-oriented solution based on Scott's answer:

基于Scott的回答,我创建了一个面向对象的解决方案:

<?php

namespace Utils;

/**
 * Class RandomStringGenerator
 * @package Utils
 *
 * Solution taken from here:
 * http://*.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);
    }
}

Usage

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

Custom alphabet

You can use custom alphabet if required. Just pass a string with supported chars to the constructor or setter:

如果需要,您可以使用自定义字母。只需将一个字符串传递给构造函数或setter:

<?php

$customAlphabet = '0123456789ABCDEF';

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

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

Here's the output samples

SRniGU2sRQb2K1ylXKnWwZr4HrtdRgrM
q1sRUjNq1K9rG905aneFzyD5IcqD4dlC
I0euIWffrURLKCCJZ5PQFcNUCto6cQfD
AKwPJMEM5ytgJyJyGqoD5FQwxv82YvMr
duoRF6gAawNOEQRICnOUNYmStWmOpEgS
sdHUkEn4565AJoTtkc8EqJ6cC4MLEHUx
eVywMdYXczuZmHaJ50nIVQjOidEVkVna
baJGt7cdLDbIxMctLsEBWgAw5BByP5V0
iqT0B2obq3oerbeXkDVLjZrrLheW4d8f
OUQYCny6tj2TYDlTuu1KsnUyaLkeObwa

I hope it will help someone. Cheers!

我希望它能帮助别人。干杯!

#4


28  

This function will generate a random key using numbers and letters:

该函数将使用数字和字母生成一个随机密钥:

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

Example output:

示例输出:

zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8

#5


17  

You can use UUID(Universally Unique Identifier), it can be used for any purpose, from user authentication string to payment transaction id.

您可以使用UUID(通用惟一标识符),它可以用于任何目的,从用户身份验证字符串到支付事务id。

A UUID is a 16-octet (128-bit) number. In its canonical form, a UUID is represented by 32 hexadecimal digits, displayed in five groups separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters (32 alphanumeric characters and four hyphens).

UUID是一个16字节(128位)的数字。在它的规范形式中,UUID以32个十六进制数字表示,由连字符分隔的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 )
    );

}

//calling funtion

/ /调用函数

$transationID = generate_uuid();

some example outputs will be like:

一些示例输出如下:

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

hope it helps someone in future :)

希望它能帮助未来的某人

#6


13  

I'm late but I'm here with some good research data based on the functions provided by Scott's answer. So I set up a Digital Ocean droplet just for this 5-day long automated test and stored the generated unique strings in a MySQL database.

我很晚了,但我在这里有一些很好的研究数据,基于斯科特的回答所提供的功能。因此,我设置了一个数字海洋小液滴,只为了这个为期5天的自动化测试,并将生成的唯一字符串存储在MySQL数据库中。

During this test period, I used 5 different lengths (5, 10, 15, 20, 50) and +/-0.5 million records were inserted for each length. During my test, only the length 5 generated +/-3K duplicates out of 0.5 million and the remaining lengths didn't generate any duplicates. So we can say that if we use a length of 15 or above with Scott's functions, then we can generate highly reliable unique strings. Here is the table showing my research data:

在这个测试期间,我使用了5个不同的长度(5、10、15、20、50)和+/- 50万条记录。在我的测试中,只有5个生成的+/-3K复制出了50万,其余的长度没有产生任何重复。所以我们可以说,如果我们用一个15或以上的长度和Scott的函数,我们就可以生成高度可靠的唯一字符串。这是我的研究数据表:

PHP:如何生成一个随机的、唯一的、字母数字的字符串?

I hope this helps.

我希望这可以帮助。

#7


11  

I use this one-liner:

我用这个小笑话:

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

where length is the length of the desired string (divisible by 4, otherwise it gets rounded down to the nearest number divisible by 4)

其中长度为所需字符串的长度(可被4整除,否则它会被四舍五入到最接近的数字4)

#8


7  

  1. Generate a random number using your favourite random-number generator
  2. 使用你最喜欢的随机数生成器生成一个随机数。
  3. Multiply and divide it to get a number matching the number of characters in your code alphabet
  4. 用乘法和除法运算得到一个数字,与你的代码字母表中的字符数相匹配。
  5. Get the item at that index in your code alphabet.
  6. 在代码字母表中获取该索引项。
  7. Repeat from 1) until you have the length you want
  8. 重复一遍,直到你有你想要的长度。

e.g (in pseudo code)

e。g(伪代码)

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

#9


4  

Here is ultimate unique id generator for you. made by me.

这是你的终极唯一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;
?>

you can echo any 'var' for your id as you like. but $mdun is better, you can replace md5 to sha1 for better code but that will be very long which may you dont need.

您可以根据您的需要对任何“var”进行echo。但是$mdun更好,您可以将md5替换为sha1,以获得更好的代码,但是这将是非常长的,这可能您不需要。

Thank you.

谢谢你!

#10


3  

Use below code to generate the random number of 11 characters or change the number as per your requirement.

使用下面的代码生成随机数11个字符或根据您的需求更改数字。

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

or we can use custom function to generate the random number

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

#11


1  

Here is what I use:

以下是我所使用的:

md5(time() . rand());    
// Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b

#12


1  

I like to use hash keys when dealing verification links. I would recommend using the microtime and hashing that using MD5 since there should be no reason why the keys should be the same since it hashes based off of the microtime.

在处理验证链接时,我喜欢使用散列键。我将建议使用microtime并使用MD5进行哈希,因为应该没有理由为什么键应该是相同的,因为它是基于microtime的。

  1. $key = md5(rand());
  2. $关键= md5(rand());
  3. $key = md5(microtime());
  4. $关键= md5(());

#13


1  

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

 }

#14


0  

Scott, yes you are very write and good solution! Thanks.

斯科特,你写得很好!谢谢。

I am also required to generate unique API token for my each user. Following is my approach, i used user information (Userid and Username):

我还需要为我的每个用户生成唯一的API令牌。下面是我的方法,我使用了用户信息(用户名和用户名):

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

Please have a look and let me know if any improvement i can do. Thanks

请您看一看,如果有什么改进的话,请告诉我。谢谢

#15


0  

after reading previous examples I came up with this:

在阅读了之前的例子之后,我想到了这个:

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

I duplicate 10 times the array[0-9,A-Z] and shuffle the elements, after I get a random start point for substr() to be more 'creative' :) you can add [a-z] and other elements to array, duplicate more or less, be more creative than me

我复制了10倍的数组[0-9,a-z],然后对元素进行洗牌,在我得到一个随机的起始点后,substr()会变得更“有创意”:)你可以添加[a-z]和其他元素来数组,复制或多或少,比我更有创造力。

#16


0  

I think this is the best method to use.

我认为这是最好的方法。

str_shuffle(md5(rand(0,100000)))

#17


0  

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

}

?>

above function will generate you a random string which is length of 11 characters.

上面的函数将生成一个长度为11个字符的随机字符串。

#18


-1  

I believe the problem with all the existing ideas is that they are probably unique, but not definitely unique (as pointed out in Dariusz Walczak's reply to loletech). I have a solution that actually is unique. It requires that your script have some sort of memory. For me this is a SQL database. You could also simply write to a file somewhere. There are two implementations:

我认为所有现存的想法的问题在于它们可能是独一无二的,但并不是绝对独一无二的(正如Dariusz Walczak对loletech的回复中所指出的那样)。我有一个独特的解决方案。它要求您的脚本具有某种内存。对我来说,这是一个SQL数据库。您也可以简单地在某个地方写一个文件。有两种实现:

First method: have TWO fields rather than 1 that provide uniqueness. The first field is an ID number that is not random but is unique (The first ID is 1, the second 2...). If you are using SQL, just define the ID field with the AUTO_INCREMENT property. The second field is not unique but is random. This can be generated with any of the other techniques people have already mentioned. Scott's idea was good, but md5 is convenient and probably good enough for most purposes:

第一种方法:有两个字段,而不是一个提供惟一性的字段。第一个字段是一个ID号,它不是随机的,而是唯一的(第一个ID是1,第二个是2…)。如果使用SQL,只需使用AUTO_INCREMENT属性定义ID字段。第二个领域不是唯一的,而是随机的。这可以用人们已经提到过的其他技术来生成。斯科特的想法很好,但是md5很方便,而且很可能足够好,可以达到大多数目的:

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

Second method: Basically the same idea, but initially pick a maximum number of strings that will ever be generated. This could just be a really big number like a trillion. Then do the same thing, generate an ID, but zero pad it so that all IDs are the same number of digits. Then just concatenate the ID with the random string. It will be random enough for most purposes, but the ID section will ensure that it is also unique.

第二种方法:基本相同的想法,但最初选择的字符串的最大数量将会生成。这可能是一个非常大的数字,像一万亿。然后做同样的事情,生成一个ID,但是0填充它,这样所有的ID都是相同的数字。然后将ID与随机字符串连接起来。它在大多数情况下都是随机的,但是ID部分将确保它也是唯一的。

#19


-1  

Here is what I'm using on one of my projects, it's working great and it generates a 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;

Please note that I multiplied the timestamp by three to create a confusion for whoever user might be wondering how this token is generated ;)

请注意,我将时间戳乘以了3,以创建一个混淆,因为用户可能想知道这个标记是如何生成的;

I hope it helps :)

我希望它有帮助:)

#20


-1  

You can use this code, I hope it will be helpful for you.

您可以使用这段代码,我希望它对您有帮助。

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

Details about Random code generator in PHP

有关PHP中随机代码生成器的详细信息。

#21


-1  

Simplifying Scotts code above by removing unnecessary loops which is slowing down badly and does not make it any more secure than calling openssl_random_pseudo_bytes just once

通过删除不需要的循环,从而简化了上面的Scotts代码,并没有使它更安全,而不是只调用openssl_random_pseudo_bytes一次。

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