PageRenderTime 26ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/zendframework/zend-math/src/Rand.php

https://gitlab.com/merial/WETE_Ryhma3
PHP | 212 lines | 121 code | 21 blank | 70 comment | 23 complexity | c85a08c6bc24d27d9a527d479d964020 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Math;
  10. use RandomLib;
  11. /**
  12. * Pseudorandom number generator (PRNG)
  13. */
  14. abstract class Rand
  15. {
  16. /**
  17. * Alternative random byte generator using RandomLib
  18. *
  19. * @var RandomLib\Generator
  20. */
  21. protected static $generator = null;
  22. /**
  23. * Generate random bytes using different approaches
  24. * If PHP 7 is running we use the random_bytes() function
  25. *
  26. * @param int $length
  27. * @param bool $strong true if you need a strong random generator (cryptography)
  28. * @return string
  29. * @throws Exception\RuntimeException
  30. */
  31. public static function getBytes($length, $strong = false)
  32. {
  33. $length = (int) $length;
  34. if ($length <= 0) {
  35. return false;
  36. }
  37. if (function_exists('random_bytes')) { // available in PHP 7
  38. return random_bytes($length);
  39. }
  40. if (function_exists('mcrypt_create_iv')) {
  41. $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
  42. if ($bytes !== false && strlen($bytes) === $length) {
  43. return $bytes;
  44. }
  45. }
  46. $checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom'))
  47. || class_exists('\\COM', false);
  48. if (true === $strong && false === $checkAlternatives) {
  49. throw new Exception\RuntimeException(
  50. 'This PHP environment doesn\'t support secure random number generation. ' .
  51. 'Please consider either installing ext/mcrypt or upgrading to PHP 7'
  52. );
  53. }
  54. $generator = self::getAlternativeGenerator();
  55. return $generator->generate($length);
  56. }
  57. /**
  58. * Retrieve a fallback/alternative RNG generator
  59. *
  60. * @return RandomLib\Generator
  61. */
  62. public static function getAlternativeGenerator()
  63. {
  64. if (null !== static::$generator) {
  65. return static::$generator;
  66. }
  67. if (!class_exists('RandomLib\\Factory')) {
  68. throw new Exception\RuntimeException(
  69. 'The RandomLib fallback pseudorandom generator is not installed. '.
  70. 'Please install it to support secure random numbers'
  71. );
  72. }
  73. $factory = new RandomLib\Factory;
  74. $factory->registerSource(
  75. 'HashTiming',
  76. 'Zend\Math\Source\HashTiming'
  77. );
  78. static::$generator = $factory->getMediumStrengthGenerator();
  79. return static::$generator;
  80. }
  81. /**
  82. * Generate random boolean
  83. *
  84. * @param bool $strong true if you need a strong random generator (cryptography)
  85. * @return bool
  86. */
  87. public static function getBoolean($strong = false)
  88. {
  89. $byte = static::getBytes(1, $strong);
  90. return (bool) (ord($byte) % 2);
  91. }
  92. /**
  93. * Generate a random integer between $min and $max
  94. *
  95. * @param int $min
  96. * @param int $max
  97. * @param bool $strong true if you need a strong random generator (cryptography)
  98. * @return int
  99. * @throws Exception\DomainException
  100. */
  101. public static function getInteger($min, $max, $strong = false)
  102. {
  103. if ($min > $max) {
  104. throw new Exception\DomainException(
  105. 'The min parameter must be lower than max parameter'
  106. );
  107. }
  108. if (function_exists('random_int')) { // available in PHP 7
  109. return random_int($min, $max);
  110. }
  111. $range = $max - $min;
  112. if ($range == 0) {
  113. return $max;
  114. } elseif ($range > PHP_INT_MAX || is_float($range)) {
  115. throw new Exception\DomainException(
  116. 'The supplied range is too great to generate'
  117. );
  118. }
  119. // calculate number of bits required to store range on this machine
  120. $r = $range;
  121. $bits = 0;
  122. while ($r) {
  123. $bits++;
  124. $r >>= 1;
  125. }
  126. $bits = (int) max($bits, 1);
  127. $bytes = (int) max(ceil($bits / 8), 1);
  128. $filter = (int) ((1 << $bits) - 1);
  129. do {
  130. $rnd = hexdec(bin2hex(static::getBytes($bytes, $strong)));
  131. $rnd &= $filter;
  132. } while ($rnd > $range);
  133. return ($min + $rnd);
  134. }
  135. /**
  136. * Generate random float (0..1)
  137. * This function generates floats with platform-dependent precision
  138. *
  139. * PHP uses double precision floating-point format (64-bit) which has
  140. * 52-bits of significand precision. We gather 7 bytes of random data,
  141. * and we fix the exponent to the bias (1023). In this way we generate
  142. * a float of 1.mantissa.
  143. *
  144. * @param bool $strong true if you need a strong random generator (cryptography)
  145. * @return float
  146. */
  147. public static function getFloat($strong = false)
  148. {
  149. $bytes = static::getBytes(7, $strong);
  150. $bytes[6] = $bytes[6] | chr(0xF0);
  151. $bytes .= chr(63); // exponent bias (1023)
  152. list(, $float) = unpack('d', $bytes);
  153. return ($float - 1);
  154. }
  155. /**
  156. * Generate a random string of specified length.
  157. *
  158. * Uses supplied character list for generating the new string.
  159. * If no character list provided - uses Base 64 character set.
  160. *
  161. * @param int $length
  162. * @param string|null $charlist
  163. * @param bool $strong true if you need a strong random generator (cryptography)
  164. * @return string
  165. * @throws Exception\DomainException
  166. */
  167. public static function getString($length, $charlist = null, $strong = false)
  168. {
  169. if ($length < 1) {
  170. throw new Exception\DomainException('Length should be >= 1');
  171. }
  172. // charlist is empty or not provided
  173. if (empty($charlist)) {
  174. $numBytes = ceil($length * 0.75);
  175. $bytes = static::getBytes($numBytes, $strong);
  176. return substr(rtrim(base64_encode($bytes), '='), 0, $length);
  177. }
  178. $listLen = strlen($charlist);
  179. if ($listLen == 1) {
  180. return str_repeat($charlist, $length);
  181. }
  182. $bytes = static::getBytes($length, $strong);
  183. $pos = 0;
  184. $result = '';
  185. for ($i = 0; $i < $length; $i++) {
  186. $pos = ($pos + ord($bytes[$i])) % $listLen;
  187. $result .= $charlist[$pos];
  188. }
  189. return $result;
  190. }
  191. }