如何使用数字和字母生成一个随机且唯一的字符串用于验证链接?就像在网站上创建账户并通过电子邮件发送带有链接的邮件,您需要点击该链接以验证您的账户一样。
我如何使用PHP生成此类字符串?
如何使用数字和字母生成一个随机且唯一的字符串用于验证链接?就像在网站上创建账户并通过电子邮件发送带有链接的邮件,您需要点击该链接以验证您的账户一样。
我如何使用PHP生成此类字符串?
function codeGenerate() {
$randCode = (string)mt_rand(1000,9999);
$randChar = rand(65,90);
$randInx = rand(0,3);
$randCode[$randInx] = chr($randChar);
return $randCode;
}
echo codeGenerate();
输出
38I7
33V7
E836
736U
可以使用这段代码。我测试了35,000,00个ID,没有重复。
<?php
$characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_';
$result = '';
for ($i = 0; $i < 11; $i++)
$result .= $characters[mt_rand(0, 63)];?>
您可以根据需要自由修改它。如果您有任何建议,请随时评论。建议在使用这些ID之前检查数据库中的每个ID,以确保您的数据库具有100%的唯一ID。
在阅读之前的例子后,我想到了这个:
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);
}
我复制了数组[0-9,A-Z]十次并打乱元素顺序,然后随机选择一个起始点来使用substr()函数,以使结果更加“有创意” :) 你可以将[a-z]和其他元素添加到数组中,增加或减少复制次数,比我更有创造力。
<?php
function random_alphanumeric($length) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
$my_string = '';
for ($i = 0; $i < $length; $i++) {
$pos = random_int(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;
它生成了两个独特的字符串:
qsBDs4JOoVRfFxyLAOGECYIsWvpcpMzAO9pypwxsqPKeAmYLOi
Ti3kE1WfGgTNxQVXtbNNbhhvvapnaUfGMVJecHkUjHbuCb85pF
希望这正是您所需要的...
一种简单的解决方案是通过丢弃非字母数字字符将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);
}
编辑:我重新访问了这个问题,因为我需要更灵活的解决方案。下面是一个比上面表现更好的解决方案,并提供了指定ASCII字符集任何子集的选项:
<?php
class RandomText
{
protected
$allowedChars,
//Maximum index to use
$allowedCount,
//Index values will be taken from a pool of this size
//It is a power of 2 to keep the distribution of values even
$distributionSize,
//This many characters will be generated for each output character
$ratio;
/**
* @param string $allowedChars characters to choose from
*/
public function __construct(string $allowedChars)
{
$this->allowedCount = strlen($allowedChars);
if($this->allowedCount < 1 || $this->allowedCount > 256) throw new \Exception('At least 1 and no more than 256 allowed character(s) must be specified.');
$this->allowedChars = $allowedChars;
//Find the power of 2 equal or greater than the number of allowed characters
$this->distributionSize = pow(2,ceil(log($this->allowedCount, 2)));
//Generating random bytes is the expensive part of this algorithm
//In most cases some will be wasted so it is helpful to produce some extras, but not too many
//On average, this is how many characters needed to produce 1 character in the allowed set
//50% of the time, more characters will be needed. My tests have shown this to perform well.
$this->ratio = $this->distributionSize / $this->allowedCount;
}
/**
* @param int $length string length of required result
* @return string random text
*/
public function get(int $length) : string
{
if($length < 1) throw new \Exception('$length must be >= 1.');
$result = '';
//Keep track of result length to prevent having to compute strlen()
$l = 0;
$indices = null;
$i = null;
do
{
//Bytes will be used to index the character set. Convert to integers.
$indices = unpack('C*', random_bytes(ceil(($length - $l) * $this->ratio)));
foreach($indices as $i)
{
//Reduce to the smallest range that gives an even distribution
$i %= $this->distributionSize;
//If the index is within the range of characters, add one char to the string
if($i < $this->allowedCount)
{
$l++;
$result .= $this->allowedChars[$i];
}
if($l >= $length) break;
}
}while($l < $length);
return $result;
}
}
Scott,是的,你说得很对,提供了一个好的解决方案!谢谢。
我还需要为每个用户生成唯一的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;
}
我认为这是使用的最佳方法。
str_shuffle(md5(rand(0,100000)))
这是一个有趣的例子
public function randomStr($length = 16) {
$string = '';
while (($len = strlen($string)) < $length) {
$size = $length - $len;
$bytes = random_bytes($size);
$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
}
return $string;
}
从 Laravel 偷来的 这里
这是我在一个项目中使用的代码,它运行良好并生成一个唯一随机令牌:
$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;
我认为所有现有想法的问题在于它们可能是独一无二的,但不是绝对独一无二的(正如Dariusz Walczak回复loletech所指出的)。我有一个独特的解决方案。它需要您的脚本具有某种记忆功能。对我而言,这就是SQL数据库。您也可以简单地将其写入某个文件中。这里有两个实现方法:
第一种方法:拥有两个字段而不是1个字段提供独一无二性。第一个字段是一个非随机但唯一的ID编号(第一个ID为1,第二个为2...)。如果您使用SQL,则只需使用AUTO_INCREMENT属性定义ID字段即可。第二个字段不是唯一的,但是是随机的。可以使用其他技术中已经提到的任何方法来生成它。Scott的想法很好,但是md5很方便,对于大多数目的来说可能已经足够:
$random_token = md5($_SERVER['HTTP_USER_AGENT'] . time());
第二种方法:基本上是相同的想法,但最初选择一个将被生成的字符串的最大数量。这可能只是一个非常大的数字,比如一万亿。然后做同样的事情,生成一个ID,但零填充它,使所有ID具有相同的数字位数。然后只需将ID与随机字符串连接起来即可。对于大多数目的来说,它已经足够随机了,但ID部分也将确保它是唯一的。
uniqid
是不安全的。使用类似于Random::alphanumericString($length)
或者Random::alphanumericHumanString($length)
这样的东西。 - caw