6

我想在 PHP 中生成随机的字母数字字符串。它们将用于随机数强度很重要的地方(URL 中公开可见的 ID 等)。

据我了解,在 PHP 中,加密强随机性的主要来源是openssl_random_pseudo_bytes(). 然而,这会返回一个字节数组,而不是字母数字字符。

要将它们转换为字母数字,我可以对它们进行散列(这将产生一个长度超过必要的一组有限十六进制字符的字符串),或者base64_encode()它们(这将产生一个带有+,/和其中的字符串=- 而不是字母数字)。

所以我认为我可以使用随机字节作为熵的来源,并生成我自己的仅由 characters 组成的字符串0-9a-zA-Z

那么问题就变成了——如何将 256 个不同的值(输入的一个字节)转换为 62 个不同的值(输出的一个字符)。在某种程度上,所有 62 个字符的可能性都相同。(否则会有 8 个字符出现的频率高于其他字符)。

或者也许我应该完全使用另一种方法?我希望我的字符串尽可能短(例如,20 个字符左右 - 较短的 URL 更好)并且只包含字母数字字符(因此它不需要在任何地方特别转义)。

4

3 回答 3

2

您可以实现自己的 base64 编码。如果您可以允许两个特定符号 - 这些可以是任何符号,例如.and -,这并不重要。它甚至可以是其中一个的空间。无论如何,你会做的是:

$alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-";
// using . and - for the two symbols here
$input = [123,193,21,13]; // whatever your input it, I'm assuming an array of bytes
$output = "";
foreach($input as $byte) {
    $output .= $alphabet[$byte%64];
}

假设随机输入,所有字符出现的概率相等。

话虽如此,如果您不能允许除纯字母数字之外的任何内容,请从 the 中删除符号$alphabet并使用%62而不是%64. 0虽然这确实意味着您对角色的偏见很小7,但我认为这不足以担心。

于 2013-11-01T17:32:58.247 回答
0

注意:这是错误的!我留下这个尝试的答案仅供参考。

(31 * 256) % 62 = 0

对于每个输出的字母数字字符,生成 31 个随机值。将这 31 个值相加并取模 62。

有点残酷,但这是我能想到的唯一“数学上正确”的选项:)

于 2013-11-01T18:11:45.607 回答
0

我在用户评论中在 php.net 上找到了这个函数。

     function crypto_rand($min,$max) {
         $range = $max - $min;
         if ($range == 0) return $min; // not so random...
         $length = (int) (log($range,2) / 8) + 1;
         return $min + (hexdec(bin2hex(openssl_random_pseudo_bytes($length,$s))) % $range);
     }

然后做类似的事情

 for($i=0; $i<20; $i++)
  {
    $string.= chr(crypto_rand(1,26)+96); //or +64 for upper case
  }

或类似的。

于 2013-11-01T17:46:41.530 回答