我有一个PHP脚本,可以制作随机令牌(A-Z,a-z,0-9):
function token($length) {
$characters = array(
"A","B","C","D","E","F","G","H","J","K","L","M",
"N","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","m",
"n","o","p","q","r","s","t","u","v","w","x","y","z",
"1","2","3","4","5","6","7","8","9");
//make an "empty container" or array for our keys
$keys = array();
//first count of $keys is empty so "1", remaining count is 1-6 = total 7 times
while(count($keys) < $length) {
//"0" because we use this to FIND ARRAY KEYS which has a 0 value
//"-1" because were only concerned of number of keys which is 32 not 33
//count($characters) = 33
$x = mt_rand(0, count($characters)-1);
if(!in_array($x, $keys)) {
$keys[] = $x;
}
}
foreach($keys as $key){
$random .= $characters[$key];
}
return $random;
}
工作完美,但我希望能够检查某个数据库,以确保以前从未使用过相同的令牌。如果有,它会在输出之前立即重新创建一个新令牌。
我知道我可以使用此脚本来检查重复:
$check = mysqli_query($mysqli, "SELECT ".$table.".token FROM ".$table." WHERE ".$table.".token = '".$random."'");
if(mysqli_num_rows($check) > 0){
//ERROR: DUPLICATE TOKEN, CREATE A NEW TOKEN NOW...
}
我只是需要帮助才能将它们全部添加到一起,这样如果在数据库中找到重复项,它将循环返回并重试。
答案 0 :(得分:6)
使用do while循环:
do {
$random = token(LENGTH);
} while (mysqli_num_rows(mysqli_query(YOUR_LOOKUP_QUERY)));
PS:您可以简化令牌代码:
function token($length) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789';
return substr(str_shuffle($characters), 0, $length);
}
答案 1 :(得分:4)
将令牌创建并检查到do … while
循环:
do {
$random = token(10);
$check = mysqli_query($mysqli, "SELECT ".$table.".token FROM ".$table." WHERE ".$table.".token = '".$random."'");
} while (mysqli_num_rows($check) > 0);
顺便说一下:您可以按如下方式简化token
功能:
function token($length) {
$characters = array(
"A","B","C","D","E","F","G","H","J","K","L","M",
"N","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","m",
"n","o","p","q","r","s","t","u","v","w","x","y","z",
"1","2","3","4","5","6","7","8","9");
if ($length < 0 || $length > count($characters)) return null;
shuffle($characters);
return implode("", array_slice($characters, 0, $length));
}
答案 2 :(得分:3)
使用令牌上的唯一键设置数据库表效率更高 - 然后尝试插入新值 - 如果查询成功,则获得新值,如果返回错误代码1022,则键已存在 - 如果它返回一个不同的错误 - 其他错误。
下进行。
答案 3 :(得分:1)
我不知道您的方案的上下文是什么,但是可能值得研究使用更加预先制作的方法来生成您的唯一令牌(桌面上的唯一ID用于实例?)
话虽如此,如果您希望对令牌的格式进行微调控制,那么可能值得研究将唯一性生成例程包装到SQL过程中,以便在一个事务中进行确定,而不是为每次迭代打开一个单独的通信请求。
这样的东西会生成1000个“独特”标记,但它可以很容易地调整为循环,直到代码真正唯一而不是固定数量的循环(并且它可能会被清理一下:)):
DECLARE @token as varchar(6),
@numberOfLoops int,
@currentLoop int,
@pool varchar(50)
-- Initialize
SET @token = ''
SET @numberOfLoops = 1000
SET @currentLoop = 0
SET @pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890';
WHILE (@currentLoop < @numberOfLoops)
BEGIN
SET @token =
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1) +
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1) +
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1) +
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1) +
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1) +
SUBSTRING(@pool, CAST((RAND() * LEN(@pool) + 1) as int), 1);
print @token;
SET @currentLoop = @currentLoop + 1;
END
但是,这里有一些重要的注意事项需要考虑。我能用你自己推出的令牌来考虑的最大问题是暂时的唯一性问题。根据您分配令牌的时间,它可能是唯一的w / r / t您的数据源片刻,但随后---可能 - 如果您不小心则声称下一个。
答案 4 :(得分:0)
您可以将所有代码包装在while循环中,该循环将重复代码,直到找到有效代码(不重复)。例如;
do {
$nextToken = token(32);
$check = mysqli_query($mysqli, "SELECT ".$table.".token FROM ".$table." WHERE ".$table.".token = '".$nextToken."'");
} while ( mysql_num_rows($check) > 0 );
这将重复加载随机令牌,直到找到一个不会从mysql_num_rows函数生成任何行的令牌(即之前没有重复过)。
答案 5 :(得分:0)
do-while循环对此非常合适,因为您希望在生成的令牌不唯一的情况下“生成新令牌”。
do {
$token = token(...);
} while (token_exists($token));
正如您对token
函数所做的那样,您应该将数据库查找代码放入一个新函数中,以便明确说明主算法(继续生成新令牌,直到它是唯一的)。我在上面的代码中假设该函数将被称为token_exists
,看起来像这样:
function token_exists($random) {
$check = mysqli_query($mysqli, "SELECT ".$table.".token FROM ".$table." WHERE ".$table.".token = '".$random."'");
return (mysqli_num_rows($check) > 0);
}
答案 6 :(得分:0)
mysql> CREATE TABLE tokens (id integer primary key auto_increment, token varchar(36), UNIQUE(token));
<?php
mysqli_query('INSERT INTO tokens (token) SELECT UUID();');
$r = mysqli_query('SELECT token FROM tokens WHERE id = '.mysqli_insert_id());
$result = mysqli_fetch_row($r);
echo $result[0];