PHP:如何生成一个随机的,唯一的,字母数字string?
如何使用数字和字母在validation链接中生成随机唯一的string? 就像当你在一个网站上创build一个帐户一样,它会给你一个带有链接的电子邮件,你必须点击那个链接才能validation你的帐户…是的…其中之一。
我怎样才能生成使用PHP的人之一?
更新:刚刚记得关于uniqid()
。 这是一个基于当前时间生成唯一标识符的PHP函数,以微秒为单位。 我想我会用这个。
安全注意事项 :此解决scheme不应用于随机性的质量会影响应用程序的安全性的情况。 特别地,
rand()
和uniqid()
不是密码安全的随机数生成器 。 看到斯科特的答案是一个安全的select。
如果你不需要它随着时间的推移是绝对唯一的:
md5(uniqid(rand(), true))
否则(因为您已经为您的用户确定了唯一的login名):
md5(uniqid($your_user_login, true))
我只是在研究如何解决这个相同的问题,但我也希望我的函数创build一个可用于密码检索的令牌。 这意味着我需要限制令牌被猜测的能力。 因为uniqid
是基于时间的,根据php.net的“返回值与microtime()有点不同”, uniqid
不符合标准。 PHPbuild议使用openssl_random_pseudo_bytes()
来生成encryption安全令牌。
快速,简短和重点回答是:
bin2hex(openssl_random_pseudo_bytes($bytes))
这将产生一个随机的string长度= $字节* 2的string。不幸的是,这只有一个字母表[af][0-9]
,但它的工作原理。
下面是我能做的最强大的function,满足条件(这是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之间创build一个随机数。
getToken($length)
在标记中创build一个字母表,然后创build一个长度$length
的string。
编辑:我忽略引用来源 – http://us1.php.net/manual/en/function.openssl-random-pseudo-bytes.php#104322
编辑(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-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; }
面向对象的最新解决scheme
我已经根据Scott的回答创build了一个面向对象的解决scheme:
<?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);
自定义字母
如果需要,您可以使用自定义字母。 只需将支持字符的string传递给构造函数或setter:
<?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
我希望这会帮助别人。 干杯!
此function将使用数字和字母生成随机密钥:
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
您可以使用UUID(通用唯一标识符),它可以用于任何目的,从用户身份validationstring到付款交易ID。
UUID是一个16字节(128位)的数字。 在它的规范forms中,UUID由32个hex数字表示,以连字符分隔的五组显示,forms为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 ) ); }
/ /调用function
$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
希望它可以帮助未来的人:)
我用这一行:
base64_encode(openssl_random_pseudo_bytes(3 * ($length >> 2)));
其中长度是所需string的长度(可被4除尽,否则将舍入到可被4整除的最接近的数字)
我迟到了,但是我在这里根据Scott的答案提供了一些很好的研究数据。 因此,我为这个为期5天的自动化testingbuild立了一个数字海洋液滴,并将生成的唯一string存储在MySQL数据库中。
在此testing期间,我使用了5种不同的长度(5,10,15,20,50),每个长度都插入了+/- 0.5百万条logging。 在我的testing过程中,只有+/- 5K产生的长度5重复了50万,其余长度没有产生任何重复。 所以我们可以说,如果我们用Scott的函数长度为15或更长,那么我们可以生成高度可靠的独特string。 以下是显示我的研究数据的表格:
我希望这有帮助。
- 用你最喜欢的随机数发生器生成一个随机数
- 将其乘以除以得到与您的代码字母表中的字符数相匹配的数字
- 在您的代码字母表中获取该索引的项目。
- 从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; ?>
你可以随心所欲地回显任何'var'作为你的id。 但是$ mdun更好,你可以用md5replacesha1以获得更好的代码,但是这会很长,可能你不需要。
谢谢。
使用下面的代码来生成11个字符的随机数或根据您的要求更改数字。
$randomNum=substr(str_shuffle("0123456789abcdefghijklmnopqrstvwxyz"), 0, 11);
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-z]/', $password) && preg_match('/[0-9]/', $password)) { return $password; }else{ return random_string(); } }
这是我使用的:
md5(time() . rand()); // Creates something like 0c947c3b1047334f5bb8a3b7adc1d97b
我喜欢在处理validation链接时使用散列键。 我build议使用使用MD5的microtime和hashing,因为应该没有理由为什么键应该是相同的,因为它基于microtime的哈希值。
-
$key = md5(rand());
-
$key = md5(microtime());
斯科特,是的,你是非常好的解决scheme! 谢谢。
我也需要为我的每个用户生成唯一的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; }
请看看,让我知道,如果我能做的任何改善。 谢谢
在阅读了前面的例子之后,我想出了这个:
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); }
我重复10次数组[0-9,AZ]和洗牌的元素,我得到一个substr()的随机起点更'创造性':)你可以添加[az]和其他元素数组,复制或多或less,比我更有创意
我认为这是最好的使用方法。
str_shuffle(md5(rand(0,100000)))
<?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个字符的随机string。
我相信所有现存观点的问题是,它们可能是独一无二的,但并不是绝对独特的(正如Dariusz Walczak对loletech的回答所指出的那样)。 我有一个实际上是独一无二的解决scheme。 它要求您的脚本具有某种内存。 对我来说这是一个SQL数据库。 你也可以直接写一个文件到某个地方。 有两个实现:
第一种方法:有两个字段,而不是1提供唯一性。 第一个字段是一个不是随机的但是唯一的ID号(第一个ID是1,第二个是…)。 如果您正在使用SQL,只需使用AUTO_INCREMENT属性定义ID字段。 第二个领域不是唯一的,而是随机的。 这可以用人们已经提到的任何其他技术来生成。 斯科特的想法是好的,但MD5很方便,可能对于大多数目的来说足够好:
$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());
第二种方法:基本上是相同的想法,但最初select将会生成的最大数量的string。 这可能只是一个很大的数字,就像万亿。 然后做同样的事情,生成一个ID,但零填充,以便所有的ID都是相同的数字位数。 然后将ID与随机string连接起来。 它对于大多数目的来说足够随机,但ID部分将确保它也是唯一的。
这是我在我的一个项目中使用的,它工作的很好,它产生了一个唯一的随机标记 :
$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;
请注意,我将时间戳乘以三,以便为用户可能想知道如何生成此令牌的问题产生混淆;)
我希望它有助于:)
你可以使用这个代码,我希望这会对你有所帮助。
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中随机代码生成器的细节
简化上面的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) }