3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
15 * Pseudorandom number generator (PRNG)
21 * Alternative random byte generator using RandomLib
23 * @var RandomLib\Generator
25 protected static $generator = null;
28 * Generate random bytes using OpenSSL or Mcrypt and mt_rand() as fallback
31 * @param bool $strong true if you need a strong random generator (cryptography)
33 * @throws Exception\RuntimeException
35 public static function getBytes($length, $strong = false)
41 if (function_exists('openssl_random_pseudo_bytes')
42 && (version_compare(PHP_VERSION
, '5.3.4') >= 0
43 ||
strtoupper(substr(PHP_OS
, 0, 3)) !== 'WIN')
45 $bytes = openssl_random_pseudo_bytes($length, $usable);
46 if (true === $usable) {
50 if (function_exists('mcrypt_create_iv')
51 && (version_compare(PHP_VERSION
, '5.3.7') >= 0
52 ||
strtoupper(substr(PHP_OS
, 0, 3)) !== 'WIN')
54 $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM
);
55 if ($bytes !== false && strlen($bytes) === $length) {
59 $checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom'))
60 ||
class_exists('\\COM', false);
61 if (true === $strong && false === $checkAlternatives) {
62 throw new Exception\
RuntimeException (
63 'This PHP environment doesn\'t support secure random number generation. ' .
64 'Please consider installing the OpenSSL and/or Mcrypt extensions'
67 $generator = self
::getAlternativeGenerator();
68 return $generator->generate($length);
72 * Retrieve a fallback/alternative RNG generator
74 * @return RandomLib\Generator
76 public static function getAlternativeGenerator()
78 if (!is_null(static::$generator)) {
79 return static::$generator;
81 if (!class_exists('RandomLib\\Factory')) {
82 throw new Exception\
RuntimeException(
83 'The RandomLib fallback pseudorandom number generator (PRNG) '
84 . ' must be installed in the absence of the OpenSSL and '
88 $factory = new RandomLib\Factory
;
89 $factory->registerSource(
91 'Zend\Math\Source\HashTiming'
93 static::$generator = $factory->getMediumStrengthGenerator();
94 return static::$generator;
98 * Generate random boolean
100 * @param bool $strong true if you need a strong random generator (cryptography)
103 public static function getBoolean($strong = false)
105 $byte = static::getBytes(1, $strong);
106 return (bool) (ord($byte) %
2);
110 * Generate a random integer between $min and $max
114 * @param bool $strong true if you need a strong random generator (cryptography)
116 * @throws Exception\DomainException
118 public static function getInteger($min, $max, $strong = false)
121 throw new Exception\
DomainException(
122 'The min parameter must be lower than max parameter'
125 $range = $max - $min;
128 } elseif ($range > PHP_INT_MAX ||
is_float($range)) {
129 throw new Exception\
DomainException(
130 'The supplied range is too great to generate'
133 $log = log($range, 2);
134 $bytes = (int) ($log / 8) +
1;
135 $bits = (int) $log +
1;
136 $filter = (int) (1 << $bits) - 1;
138 $rnd = hexdec(bin2hex(self
::getBytes($bytes, $strong)));
139 $rnd = $rnd & $filter;
140 } while ($rnd > $range);
142 return ($min +
$rnd);
146 * Generate random float (0..1)
147 * This function generates floats with platform-dependent precision
149 * PHP uses double precision floating-point format (64-bit) which has
150 * 52-bits of significand precision. We gather 7 bytes of random data,
151 * and we fix the exponent to the bias (1023). In this way we generate
152 * a float of 1.mantissa.
154 * @param bool $strong true if you need a strong random generator (cryptography)
157 public static function getFloat($strong = false)
159 $bytes = static::getBytes(7, $strong);
160 $bytes[6] = $bytes[6] |
chr(0xF0);
161 $bytes .= chr(63); // exponent bias (1023)
162 list(, $float) = unpack('d', $bytes);
168 * Generate a random string of specified length.
170 * Uses supplied character list for generating the new string.
171 * If no character list provided - uses Base 64 character set.
174 * @param string|null $charlist
175 * @param bool $strong true if you need a strong random generator (cryptography)
177 * @throws Exception\DomainException
179 public static function getString($length, $charlist = null, $strong = false)
182 throw new Exception\
DomainException('Length should be >= 1');
185 // charlist is empty or not provided
186 if (empty($charlist)) {
187 $numBytes = ceil($length * 0.75);
188 $bytes = static::getBytes($numBytes, $strong);
189 return substr(rtrim(base64_encode($bytes), '='), 0, $length);
192 $listLen = strlen($charlist);
195 return str_repeat($charlist, $length);
198 $bytes = static::getBytes($length, $strong);
201 for ($i = 0; $i < $length; $i++
) {
202 $pos = ($pos +
ord($bytes[$i])) %
$listLen;
203 $result .= $charlist[$pos];