PHP:如何生成一个随机的、唯一的、字母数字字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1846202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP: How to generate a random, unique, alphanumeric string?
提问by Andrew
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 函数,可根据当前时间(以微秒为单位)生成唯一标识符。我想我会用那个。
采纳答案by loletech
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()anduniqid()are not cryptographically secure random number generators. See Scott's answerfor a secure alternative.
安全注意事项:在随机性质量可能影响应用程序安全性的情况下,不应使用此解决方案。特别是,
rand()并且uniqid()不是加密安全的随机数生成器。有关安全的替代方案,请参阅Scott 的回答。
If you do not need it to be absolutely unique over time:
如果您不需要它随着时间的推移绝对独一无二:
md5(uniqid(rand(), true))
md5(uniqid(rand(), true))
Otherwise (given you have already determined a unique login for your user):
否则(假设您已经为您的用户确定了唯一的登录名):
md5(uniqid($your_user_login, true))
回答by Scott
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 uniqidis based on the time, and according to php.net "the return value is little different from microtime()", uniqiddoes 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.
这将生成一个随机字符串的字母数字字符的长度 = $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)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-pseudo-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($length)和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);
for ($i=0; $i < $length; $i++) {
$token .= $codeAlphabet[random_int(0, $max-1)];
}
return $token;
}
回答by Slava Fomin II
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://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);
}
}
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!
我希望它会帮助某人。干杯!
回答by Rehmat
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.
我迟到了,但我在这里提供了一些基于Scott's answer提供的功能的良好研究数据。所以我为这个为期 5 天的自动化测试设置了一个 Digital Ocean Droplet,并将生成的唯一字符串存储在 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 的长度在 50 万个中产生了 +/-3K 的重复,其余的长度没有产生任何重复。所以我们可以说,如果我们在 Scott 的函数中使用 15 或以上的长度,那么我们可以生成高度可靠的唯一字符串。这是显示我的研究数据的表格:
Update: I created a simple Heroku app using these functions that returns the token as a JSON response. The app can be accessed at https://uniquestrings.herokuapp.com/api/token?length=15
更新:我使用这些函数创建了一个简单的 Heroku 应用程序,该应用程序将令牌作为 JSON 响应返回。该应用程序可以在https://uniquestrings.herokuapp.com/api/token?length=15访问
I hope this helps.
我希望这有帮助。
回答by Developer
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 个十六进制数字表示,显示在由连字符分隔的五组中,格式为 8-4-4-4-12,总共 36 个字符(32 个字母数字字符和四个连字符)。
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 :)
希望它可以帮助未来的人:)
回答by Rathienth Baskaran
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
回答by DudeOnRock
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)
其中 length 是所需字符串的长度(可被 4 整除,否则将向下舍入为最接近的可被 4 整除的数字)
回答by Ramesh Kotkar
Use the code below 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);
回答by Erik A. Brandstadmoen
- Generate a random number using your favourite random-number generator
- Multiply and divide it to get a number matching the number of characters in your code alphabet
- Get the item at that index in your code alphabet.
- Repeat from 1) until you have the length you want
- 使用您最喜欢的随机数生成器生成一个随机数
- 乘以除以得到一个与您的代码字母表中的字符数相匹配的数字
- 获取代码字母表中该索引处的项目。
- 从 1) 开始重复,直到你得到你想要的长度
e.g (in pseudo code)
例如(在伪代码中)
int myInt = random(0, numcharacters)
char[] codealphabet = 'ABCDEF12345'
char random = codealphabet[i]
repeat until long enough
回答by Krishna Torque
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.
您可以根据需要为您的 id 回显任何“var”。但是 $mdun 更好,您可以将 md5 替换为 sha1 以获得更好的代码,但这会很长,您可能不需要。
Thank you.
谢谢你。


