Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

187 lines (172 sloc) 6.022 kb
<?php
/**
* The Random Number Generator Class
*
* Use this factory to generate cryptographic quality random numbers (strings)
*
* PHP version 5.3
*
* @category PHPCryptLib
* @package Random
* @author Anthony Ferrara <ircmaxell@ircmaxell.com>
* @author Timo Hamina
* @copyright 2011 The Authors
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version Build @@version@@
*/
namespace CryptLib\Random;
use CryptLib\Core\BaseConverter;
/**
* The Random Number Generator Class
*
* Use this factory to generate cryptographic quality random numbers (strings)
*
* @category PHPCryptLib
* @package Random
* @author Anthony Ferrara <ircmaxell@ircmaxell.com>
* @author Timo Hamina
*/
class Generator {
/**
* @var Mixer The mixing strategy to use for this generator instance
*/
protected $mixer = null;
/**
* @var array An array of random number sources to use for this generator
*/
protected $sources = array();
/**
* Build a new instance of the generator
*
* @param array $sources An array of random data sources to use
* @param Mixer $mixer The mixing strategy to use for this generator
*/
public function __construct(array $sources, Mixer $mixer) {
foreach ($sources as $source) {
$this->addSource($source);
}
$this->mixer = $mixer;
}
/**
* Add a random number source to the generator
*
* @param Source $source The random number source to add
*
* @return Generator $this The current generator instance
*/
public function addSource(Source $source) {
$this->sources[] = $source;
return $this;
}
/**
* Generate a random number (string) of the requested size
*
* @param int $size The size of the requested random number
*
* @return string The generated random number (string)
*/
public function generate($size) {
$seeds = array();
foreach ($this->sources as $source) {
$seeds[] = $source->generate($size);
}
return $this->mixer->mix($seeds);
}
/**
* Generate a random integer with the given range
*
* @param int $min The lower bound of the range to generate
* @param int $max The upper bound of the range to generate
*
* @return int The generated random number within the range
*/
public function generateInt($min = 0, $max = PHP_INT_MAX) {
$tmp = (int) max($max, $min);
$min = (int) min($max, $min);
$max = $tmp;
$range = $max - $min;
if ($range == 0) {
return $max;
} elseif ($range > PHP_INT_MAX || is_float($range)) {
/**
* This works, because PHP will auto-convert it to a float at this point,
* But on 64 bit systems, the float won't have enough precision to
* actually store the difference, so we need to check if it's a float
* and hence auto-converted...
*/
throw new \RangeException(
'The supplied range is too great to generate'
);
}
$bits = (int) floor(log($range, 2) + 1);
$bytes = (int) max(ceil($bits / 8), 1);
$mask = (int) (pow(2, $bits) - 1);
/**
* The mask is a better way of dropping unused bits. Basically what it does
* is to set all the bits in the mask to 1 that we may need. Since the max
* range is PHP_INT_MAX, we will never need negative numbers (which would
* have the MSB set on the max int possible to generate). Therefore we
* can just mask that away. Since pow returns a float, we need to cast
* it back to an int so the mask will work.
*
* On a 64 bit platform, that means that PHP_INT_MAX is 2^63 - 1. Which
* is also the mask if 63 bits are needed (by the log(range, 2) call).
* So if the computed result is negative (meaning the 64th bit is set), the
* mask will correct that.
*
* This turns out to be slightly better than the shift as we don't need to
* worry about "fixing" negative values.
*/
do {
$test = $this->generate($bytes);
$result = hexdec(bin2hex($test)) & $mask;
} while ($result > $range);
return $result + $min;
}
/**
* Generate a random string of specified length.
*
* This uses the supplied character list for generating the new result
* string.
*
* @param int $length The length of the generated string
* @param string $characters An optional list of characters to use
*
* @return string The generated random string
*/
public function generateString($length, $characters = '') {
if ($length == 0 || strlen($characters) == 1) {
return '';
} elseif (empty($characters)) {
// Default to base 64
$characters = '0123456789abcdefghijklmnopqrstuvwxyz' .
'ABCDEFGHIJKLMNOPQRSTUVWXYZ./';
}
//determine how many bytes to generate
$bytes = ceil($length * floor(log(strlen($characters), 2) + 1.01) / 8);
$rand = $this->generate($bytes);
$result = BaseConverter::convertFromBinary($rand, $characters);
if (strlen($result) < $length) {
$result = str_pad($result, $length, $characters[0], STR_PAD_LEFT);
} else {
$result = substr($result, 0, $length);
}
return $result;
}
/**
* Get the Mixer used for this instance
*
* @return Mixer the current mixer
*/
public function getMixer() {
return $this->mixer;
}
/**
* Get the Sources used for this instance
*
* @return Source[] the current mixer
*/
public function getSources() {
return $this->sources;
}
}
Jump to Line
Something went wrong with that request. Please try again.