You are here

function drupal_random_bytes in Drupal 6

Same name and namespace in other branches
  1. 7 includes/bootstrap.inc \drupal_random_bytes()

Returns a string of highly randomized bytes (over the full 8-bit range).

This function is better than simply calling mt_rand() or any other built-in PHP function because it can return a long string of bytes (compared to < 4 bytes normally from mt_rand()) and uses the best available pseudo-random source.

Parameters

$count: The number of characters (bytes) to return in the string.

5 calls to drupal_random_bytes()
drupal_random_key in includes/bootstrap.inc
Returns a URL-safe, base64 encoded string of highly randomized bytes (over the full 8-bit range).
user_password in modules/user/user.module
Generate a random alphanumeric password.
_drupal_bootstrap_full in includes/common.inc
_openid_dh_rand in modules/openid/openid.inc
_openid_get_bytes in modules/openid/openid.inc

File

includes/bootstrap.inc, line 1420
Functions that need to be loaded on every Drupal request.

Code

function drupal_random_bytes($count) {

  // $random_state does not use drupal_static as it stores random bytes.
  static $random_state, $bytes, $has_openssl, $has_hash;
  $missing_bytes = $count - strlen($bytes);
  if ($missing_bytes > 0) {

    // PHP versions prior 5.3.4 experienced openssl_random_pseudo_bytes()
    // locking on Windows and rendered it unusable.
    if (!isset($has_openssl)) {
      $has_openssl = version_compare(PHP_VERSION, '5.3.4', '>=') && function_exists('openssl_random_pseudo_bytes');
    }

    // openssl_random_pseudo_bytes() will find entropy in a system-dependent
    // way.
    if ($has_openssl) {
      $bytes .= openssl_random_pseudo_bytes($missing_bytes);
    }
    elseif ($fh = @fopen('/dev/urandom', 'rb')) {

      // PHP only performs buffered reads, so in reality it will always read
      // at least 4096 bytes. Thus, it costs nothing extra to read and store
      // that much so as to speed any additional invocations.
      $bytes .= fread($fh, max(4096, $missing_bytes));
      fclose($fh);
    }

    // If we couldn't get enough entropy, this simple hash-based PRNG will
    // generate a good set of pseudo-random bytes on any system.
    // Note that it may be important that our $random_state is passed
    // through hash() prior to being rolled into $output, that the two hash()
    // invocations are different, and that the extra input into the first one -
    // the microtime() - is prepended rather than appended. This is to avoid
    // directly leaking $random_state via the $output stream, which could
    // allow for trivial prediction of further "random" numbers.
    if (strlen($bytes) < $count) {

      // Initialize on the first call. The contents of $_SERVER includes a mix of
      // user-specific and system information that varies a little with each page.
      if (!isset($random_state)) {
        $random_state = print_r($_SERVER, TRUE);
        if (function_exists('getmypid')) {

          // Further initialize with the somewhat random PHP process ID.
          $random_state .= getmypid();
        }

        // hash() is only available in PHP 5.1.2+ or via PECL.
        $has_hash = function_exists('hash') && in_array('sha256', hash_algos());
        $bytes = '';
      }
      if ($has_hash) {
        do {
          $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
          $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
        } while (strlen($bytes) < $count);
      }
      else {
        do {
          $random_state = md5(microtime() . mt_rand() . $random_state);
          $bytes .= pack("H*", md5(mt_rand() . $random_state));
        } while (strlen($bytes) < $count);
      }
    }
  }
  $output = substr($bytes, 0, $count);
  $bytes = substr($bytes, $count);
  return $output;
}