它不一定是有意义的词 - 更像是随机密码生成,但问题是 - 它们应该是唯一的。我会将它用于某种包/产品代码。哪种方法最好? :)
答案 0 :(得分:6)
通常不可能生成具有唯一和随机元素的序列:显然,该算法必须考虑序列中先前生成的元素,因此下一个元素实际上不是随机的。
因此,您最好的选择是检测碰撞并重试(在您的特定情况下可能会非常昂贵)。
如果你只受到7个字符的限制,那么上面你可以做的并不多:
$allowed_chars = 'abcdefghijklmnopqrstuvwxz';
$allowed_count = strlen($allowed_chars);
$password = null;
$password_length = 7;
while($password === null || already_exists($password)) {
$password = '';
for($i = 0; $i < $password_length; ++$i) {
$password .= $allowed_chars{mt_rand(0, $allowed_count - 1)};
}
}
这最终会给你一个新密码。
然而,在我遇到的类似情况下,我通常会选择一个更大的密码大小,这也恰好是流行哈希函数(例如md5
)的十六进制表示的大小。然后,您可以使自己更容易,更不容易出错:
$password = time(); // even better if you have some other "random" input to use here
do {
$password = md5(time().$password);
}
while (already_exists($password));
这还具有序列空间更大的附加优点,因此碰撞将更少。您可以根据将来生成的密码的预期数量来选择哈希函数的大小,以“保证”低冲突概率,从而减少对可能昂贵的already_exists
函数的调用。
答案 1 :(得分:1)
这是一种没有哈希或循环的方法:
$password = sprintf(
"%04s%03s",
base_convert(mt_rand(0, pow(36, 4) - 1), 10, 36),
base_convert(mt_rand(0, pow(36, 3) - 1), 10, 36)
);
正如其他一些人所提到的,确保独特性更复杂,应该是不必要的。最简单的方法是在最后添加额外的字符,随着生成的每个密码递增。
答案 2 :(得分:1)
这是一个看似随机的东西,应该是唯一的,并且有7个字符可供使用时间:
echo base_convert(intval(microtime(true) * 10000), 10, 36);
或者更多随机性和更少唯一性( 1000 和 10000 每秒):< / p>
echo base_convert(mt_rand(1, 9) . intval(microtime(true) * 1000), 10, 36);
或(每秒 100 和 10000 之间的唯一性) - 这可能是最佳选择:
echo base_convert(mt_rand(10, 99) . intval(microtime(true) * 100), 10, 36);
或(每秒 10 和 10000 之间的唯一性):
echo base_convert(mt_rand(100, 999) . intval(microtime(true) * 10), 10, 36);
你明白了。
答案 3 :(得分:1)
具有7个字符的随机字母数字(基数36 = 0..9 + a..z
)值必须在2176782336
和78364164095
之间具有基数10表示,以下片段证明了这一点:
var_dump(base_convert('1000000', 36, 10)); // 2176782336
var_dump(base_convert('zzzzzzz', 36, 10)); // 78364164095
为了使它独一无二,我们必须依赖非重复因子,显而易见的选择是time()
:
var_dump(time()); // 1273508728
var_dump(microtime(true)); // 1273508728.2883
如果我们只想确保每秒1个唯一代码的最小唯一性因子,我们可以这样做:
var_dump(base_convert(time() * 2, 10, 36)); // 164ff8w
var_dump(base_convert(time() * 2 + 1, 10, 36)); // 164ff8x
var_dump(base_convert(time() * 2 + 2, 10, 36)); // 164ff8y
var_dump(base_convert(time() * 2 + 3, 10, 36)); // 164ff8z
您会注意到这些代码不是随机的,您还会注意到time()
(1273508728
)小于2176782336
(7的最小基数10代表) char code),这就是我做time() * 2
的原因。
现在让我们做一些日期数学运算,以便在遵守旧版本PHP(< 5.0
?)的整数限制的同时添加随机性并增加唯一性因子:
var_dump(1 * 60 * 60); // 3600
var_dump(1 * 60 * 60 * 24); // 86400
var_dump(1 * 60 * 60 * 24 * 366); // 31622400
var_dump(1 * 60 * 60 * 24 * 366 * 10); // 316224000
var_dump(1 * 60 * 60 * 24 * 366 * 20); // 632448000
var_dump(1 * 60 * 60 * 24 * 366 * 30); // 948672000
var_dump(1 * 60 * 60 * 24 * 366 * 31); // 980294400
var_dump(PHP_INT_MAX); // 2147483647
关于PHP_INT_MAX
我不确定最近版本的PHP中究竟发生了什么变化,因为以下内容在PHP 5.3.1中有明确的效果,也许有人可以对此有所了解:< / p>
var_dump(base_convert(PHP_INT_MAX, 10, 36)); // zik0zj
var_dump(base_convert(PHP_INT_MAX + 1, 10, 36)); // zik0zk
var_dump(base_convert(PHP_INT_MAX + 2, 10, 36)); // zik0zl
var_dump(base_convert(PHP_INT_MAX * 2, 10, 36)); // 1z141z2
var_dump(base_convert(PHP_INT_MAX * 2 + 1, 10, 36)); // 1z141z3
var_dump(base_convert(PHP_INT_MAX * 2 + 2, 10, 36)); // 1z141z4
我在这里理性化了,我很无聊,我很无聊,所以我会很快完成。我们几乎可以使用整个基本36个字符集并安全生成顺序代码,其最小保证唯一性因子为每秒1个唯一代码for 3.16887646 years ,使用此代码:< / p>
base_convert(mt_rand(22, 782) . substr(time(), 2), 10, 36);
我刚刚意识到由于mt_rand()
的第一个参数,上面的内容有时会返回重复值,为了产生独特的结果,我们需要稍微限制一下我们的36个charset:
base_convert(mt_rand(122, 782) . substr(time(), 2), 10, 36);
请注意,上述值仍然是连续的,为了使它们看起来随机,我们可以使用microtime()
,但我们只能确保每秒10个代码的唯一性因子for 3.8 months 强>:
base_convert(mt_rand(122, 782) . substr(number_format(microtime(true), 1, '', ''), 3), 10, 36);
事实证明这比我最初的解决困难,因为有很多限制:
如果我们可以忽略上述任何一项,那将会容易得多,我确信这可以进一步优化,但就像我说的那样:这让我很无聊。也许有人想在我离开的地方选择这个。 =)我很饿! = S 强>
答案 4 :(得分:0)
鉴于你在这里提到密码,我认为你需要一种安全的方法(即:某人不应该根据知道任何其他密码来猜测别人的密码)。您可以使用以下内容:
如果安全性不是问题,步骤1和2本身就足够了。如果安全是一个问题,那么除了你自己之外,没有人知道“MasterPassword”的价值是至关重要的。
答案 5 :(得分:0)
以下是我将如何解决这个问题:
考虑7个字符可以是26个字母(abc..z)中的一个,或10个数字(01 ... 9)。这使得36个可能的角色。
每次应用程序生成新代码时,都要增加一个全局变量。您可以使用“Hexatridecimal”转换器将此唯一编号转换为唯一字符串,并添加填充字符以构成字符串的其余部分。
看一下这个链接。我觉得这个家伙和你有同样的问题: http://www.codemaxima.com/2010/04/the-hexatridecimal-numbering-system/
答案 6 :(得分:0)
$random = substr(hash('md5',openssl_random_pseudo_bytes(32)),0,7);
答案 7 :(得分:0)
+1给@Michael Haren的评论。如果您网站上的密码不应具有唯一的约束。
如果我尝试使用给定的密码,并且我收到一个错误,我无法使用它,因为它已经在使用中,那么我知道系统上的某个用户有该密码。如果有1000个用户,我只需要尝试最多1000个其他帐户才能找到拥有该密码的用户。
没有真正回答你的问题,但不仅仅是评论。所以我正在标记这个CW。
答案 8 :(得分:0)
md5( microtime() );
答案 9 :(得分:0)
Galen的答案只允许在密码中使用每个字符。该字符串中的信息不多。一个简单的改变:
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$passwordlength = 7;
for ($x = 1; $x <= $passwordlength; $x++) {
$charlist .= $chars;
}
$temp_pw = substr( str_shuffle( $charlist ), 0, $passwordlength );
答案 10 :(得分:0)
这是我最喜欢的方式。
$pretrimmedrandom = md5(uniqid(mt_rand(),true));
$trimmed = substr($pretrimmedrandom ,0,7);
uniqid使用当前时间生成一个非常独特的随机字符串。结果看起来像“3f456yg”。
答案 11 :(得分:0)
substr(str_shuffle(md5(microtime())),rand(0,21),7);
答案 12 :(得分:0)
试试这个
echo $unique_key = substr(md5(rand(0, 1000000)), 0, 5);
它将给出长度为5的字符串。
答案 13 :(得分:-1)
使用Kohana文本,
http://docs.kohanaphp.com/helpers/text
例如,
$prod_id = text::random('alpha', 7);
如果您不想使用框架,只需复制代码即可。你会在那里找到很多好东西。
答案 14 :(得分:-1)
这是一个非常简单的方法
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$temp_pw = substr( str_shuffle( $chars ), 0, 7 );
if ( check_unique( $temp_pw ) ) {
$pw = $temp_pw;
}
您必须实现自己的check_unique函数。那部分应该很容易。