add reconnect example/test file
[GitHub/Stricted/speedport-hybrid-php-api.git] / CryptLib / Random / Generator.php
CommitLineData
14d4f286
S
1<?php
2/**
3 * The Random Number Generator Class
4 *
5 * Use this factory to generate cryptographic quality random numbers (strings)
6 *
7 * PHP version 5.3
8 *
9 * @category PHPCryptLib
10 * @package Random
11 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
12 * @author Timo Hamina
13 * @copyright 2011 The Authors
14 * @license http://www.opensource.org/licenses/mit-license.html MIT License
15 * @version Build @@version@@
16 */
17
18namespace CryptLib\Random;
19
20use CryptLib\Core\BaseConverter;
21
22/**
23 * The Random Number Generator Class
24 *
25 * Use this factory to generate cryptographic quality random numbers (strings)
26 *
27 * @category PHPCryptLib
28 * @package Random
29 * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
30 * @author Timo Hamina
31 */
32class Generator {
33
34 /**
35 * @var Mixer The mixing strategy to use for this generator instance
36 */
37 protected $mixer = null;
38
39 /**
40 * @var array An array of random number sources to use for this generator
41 */
42 protected $sources = array();
43
44 /**
45 * Build a new instance of the generator
46 *
47 * @param array $sources An array of random data sources to use
48 * @param Mixer $mixer The mixing strategy to use for this generator
49 */
50 public function __construct(array $sources, Mixer $mixer) {
51 foreach ($sources as $source) {
52 $this->addSource($source);
53 }
54 $this->mixer = $mixer;
55 }
56
57 /**
58 * Add a random number source to the generator
59 *
60 * @param Source $source The random number source to add
61 *
62 * @return Generator $this The current generator instance
63 */
64 public function addSource(Source $source) {
65 $this->sources[] = $source;
66 return $this;
67 }
68
69 /**
70 * Generate a random number (string) of the requested size
71 *
72 * @param int $size The size of the requested random number
73 *
74 * @return string The generated random number (string)
75 */
76 public function generate($size) {
77 $seeds = array();
78 foreach ($this->sources as $source) {
79 $seeds[] = $source->generate($size);
80 }
81 return $this->mixer->mix($seeds);
82 }
83
84 /**
85 * Generate a random integer with the given range
86 *
87 * @param int $min The lower bound of the range to generate
88 * @param int $max The upper bound of the range to generate
89 *
90 * @return int The generated random number within the range
91 */
92 public function generateInt($min = 0, $max = PHP_INT_MAX) {
93 $tmp = (int) max($max, $min);
94 $min = (int) min($max, $min);
95 $max = $tmp;
96 $range = $max - $min;
97 if ($range == 0) {
98 return $max;
99 } elseif ($range > PHP_INT_MAX || is_float($range)) {
100 /**
101 * This works, because PHP will auto-convert it to a float at this point,
102 * But on 64 bit systems, the float won't have enough precision to
103 * actually store the difference, so we need to check if it's a float
104 * and hence auto-converted...
105 */
106 throw new \RangeException(
107 'The supplied range is too great to generate'
108 );
109 }
110
111 $bits = (int) floor(log($range, 2) + 1);
112 $bytes = (int) max(ceil($bits / 8), 1);
113 $mask = (int) (pow(2, $bits) - 1);
114 /**
115 * The mask is a better way of dropping unused bits. Basically what it does
116 * is to set all the bits in the mask to 1 that we may need. Since the max
117 * range is PHP_INT_MAX, we will never need negative numbers (which would
118 * have the MSB set on the max int possible to generate). Therefore we
119 * can just mask that away. Since pow returns a float, we need to cast
120 * it back to an int so the mask will work.
121 *
122 * On a 64 bit platform, that means that PHP_INT_MAX is 2^63 - 1. Which
123 * is also the mask if 63 bits are needed (by the log(range, 2) call).
124 * So if the computed result is negative (meaning the 64th bit is set), the
125 * mask will correct that.
126 *
127 * This turns out to be slightly better than the shift as we don't need to
128 * worry about "fixing" negative values.
129 */
130 do {
131 $test = $this->generate($bytes);
132 $result = hexdec(bin2hex($test)) & $mask;
133 } while ($result > $range);
134 return $result + $min;
135 }
136
137 /**
138 * Generate a random string of specified length.
139 *
140 * This uses the supplied character list for generating the new result
141 * string.
142 *
143 * @param int $length The length of the generated string
144 * @param string $characters An optional list of characters to use
145 *
146 * @return string The generated random string
147 */
148 public function generateString($length, $characters = '') {
149 if ($length == 0 || strlen($characters) == 1) {
150 return '';
151 } elseif (empty($characters)) {
152 // Default to base 64
153 $characters = '0123456789abcdefghijklmnopqrstuvwxyz' .
154 'ABCDEFGHIJKLMNOPQRSTUVWXYZ./';
155 }
156 //determine how many bytes to generate
157 $bytes = ceil($length * floor(log(strlen($characters), 2) + 1.01) / 8);
158 $rand = $this->generate($bytes);
159 $result = BaseConverter::convertFromBinary($rand, $characters);
160 if (strlen($result) < $length) {
161 $result = str_pad($result, $length, $characters[0], STR_PAD_LEFT);
162 } else {
163 $result = substr($result, 0, $length);
164 }
165 return $result;
166 }
167
168 /**
169 * Get the Mixer used for this instance
170 *
171 * @return Mixer the current mixer
172 */
173 public function getMixer() {
174 return $this->mixer;
175 }
176
177 /**
178 * Get the Sources used for this instance
179 *
180 * @return Source[] the current mixer
181 */
182 public function getSources() {
183 return $this->sources;
184 }
185
186}