【问题标题】:How to generate random 64-bit value as decimal string in PHP如何在 PHP 中生成随机 64 位值作为十进制字符串
【发布时间】:2011-07-15 03:14:41
【问题描述】:

Oauth 需要一个随机的 64 位无符号数字,以十进制格式编码为 ASCII 字符串。你们能帮我用php实现这个吗? 谢谢

【问题讨论】:

    标签: php random oauth arbitrary-precision


    【解决方案1】:

    您可以使用两个 32 位数字、四个 16 位数字等。

    PHP 有 rand()mt_rand(),但标准没有指定它们提供多少随机位(尽管可以分别在 getrandmax()mt_getrandmax() 的帮助下查询它们。)

    因此,您的 最安全 最简单的选择是生成 64 个随机位并一一设置。

    至于使用 64 位整数,我建议使用 GMP 库,因为它有很多功能可以帮助您。

    您可以创建一个数字,在其上连续调用 64 gmp_setbit()s,然后使用 gmp_strval() 将其转换为字符串。

    【讨论】:

      【解决方案2】:

      这是一个非常有趣的问题(如何在 PHP 中创建任意长度随机数的十进制表示,不使用可选扩展)。这是解决方案:

      第一步:任意长度的随机数

      // Counts how many bits are needed to represent $value
      function count_bits($value) {
          for($count = 0; $value != 0; $value >>= 1) {
              ++$count;
          }
          return $count;
      }
      
      // Returns a base16 random string of at least $bits bits
      // Actual bits returned will be a multiple of 4 (1 hex digit)
      function random_bits($bits) {
          $result = '';
          $accumulated_bits = 0;
          $total_bits = count_bits(mt_getrandmax());
          $usable_bits = intval($total_bits / 8) * 8;
      
          while ($accumulated_bits < $bits) {
              $bits_to_add = min($total_bits - $usable_bits, $bits - $accumulated_bits);
              if ($bits_to_add % 4 != 0) {
                  // add bits in whole increments of 4
                  $bits_to_add += 4 - $bits_to_add % 4;
              }
      
              // isolate leftmost $bits_to_add from mt_rand() result
              $more_bits = mt_rand() & ((1 << $bits_to_add) - 1);
      
              // format as hex (this will be safe)
              $format_string = '%0'.($bits_to_add / 4).'x';
              $result .= sprintf($format_string, $more_bits);
              $accumulated_bits += $bits_to_add;
          }
      
          return $result;
      }
      

      此时,调用random_bits(2048)会给你2048个随机位作为十六进制编码的字符串,没问题。

      第 2 步:任意精度基数转换

      数学很难,代码如下:

      function base_convert_arbitrary($number, $fromBase, $toBase) {
          $digits = '0123456789abcdefghijklmnopqrstuvwxyz';
          $length = strlen($number);
          $result = '';
      
          $nibbles = array();
          for ($i = 0; $i < $length; ++$i) {
              $nibbles[$i] = strpos($digits, $number[$i]);
          }
      
          do {
              $value = 0;
              $newlen = 0;
              for ($i = 0; $i < $length; ++$i) {
                  $value = $value * $fromBase + $nibbles[$i];
                  if ($value >= $toBase) {
                      $nibbles[$newlen++] = (int)($value / $toBase);
                      $value %= $toBase;
                  }
                  else if ($newlen > 0) {
                      $nibbles[$newlen++] = 0;
                  }
              }
              $length = $newlen;
              $result = $digits[$value].$result;
          }
          while ($newlen != 0);
          return $result;
      }
      

      此功能将按照宣传的方式工作,例如尝试base_convert_arbitrary('ffffffffffffffff', 16, 10) == '18446744073709551615'base_convert_arbitrary('10000000000000000', 16, 10) == '18446744073709551616'

      把它放在一起

      echo base_convert_arbitrary(random_bits(64), 16, 10);
      

      【讨论】:

      • +1 甚至是 think 在 PHP 中这样做的令人兴奋的事情。请记住,count_bits 将无法处理大于 PHP_INT_MAX 的数字。
      • @Charles:感谢您的投票。 count_bits 确实是有限的,但是因为我们只打算用它来测量mt_getrandmax 的返回值,所以它足以胜任这项工作。
      • 考虑到mt_getrandmax 通常似乎是 2^31-1,即使在 64 位平台上也是如此。
      • 仅供参考:有时数字表示可能包含前导零(即 hash() 函数的结果),并且此函数显然无法在转换后恢复它们。所以如果nab = convert(n, a, b) 可以是n !== convert(nab, b, a)。小心。
      • 有趣的函数base_convert_arbitrary。但为什么所有的字母? $value = $value * $fromBase + $nibbles[$i];不是保证操作只能对base 2到​​16有效吗?
      【解决方案3】:

      您是否在自己构建 OAuth 适配器?如果是这样,您可能需要重新考虑。有很多优秀的 OAuth 库,包括 one from PECLone in PEARanother from the Zend Frameworkthis other one hosted on Google Code。前三个我都用过,都还不错。

      如果您真的想自己做这件事,您可能会遇到问题。 PHP 无法思考 64 位数字,除非它是在 64 位平台上编译的,或者您安装了高级数学扩展。这将使将 64 位数字表示为十进制 非常 变得困难。看起来我上面链接的许多库完全忽略了格式要求,只是使用原始 MD5 哈希。下面是 ZF 适配器的代码:

      /**
       * Generate nonce
       * 
       * @return string
       */
      public function generateNonce()
      {
          return md5(uniqid(rand(), true));
      }
      

      他们看起来好像可以摆脱这个互操作性问题。

      【讨论】:

        猜你喜欢
        • 2018-06-07
        • 1970-01-01
        • 2012-11-06
        • 2022-11-03
        • 1970-01-01
        • 2012-05-10
        • 2018-11-27
        • 1970-01-01
        • 2012-05-07
        相关资源
        最近更新 更多