PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/yousafsyed/easternglamor
PHP | 212 lines | 122 code | 21 blank | 69 comment | 23 complexity | f1b17ffd3a7e83e060bc6620e3118266 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 OpenSSL or Mcrypt and mt_rand() as fallback
  24. *
  25. * @param int $length
  26. * @param bool $strong true if you need a strong random generator (cryptography)
  27. * @return string
  28. * @throws Exception\RuntimeException
  29. */
  30. public static function getBytes($length, $strong = false)
  31. {
  32. $length = (int) $length;
  33. if ($length <= 0) {
  34. return false;
  35. }
  36. if (function_exists('openssl_random_pseudo_bytes')) {
  37. $bytes = openssl_random_pseudo_bytes($length, $usable);
  38. if (true === $usable) {
  39. return $bytes;
  40. }
  41. }
  42. if (function_exists('mcrypt_create_iv')) {
  43. $bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
  44. if ($bytes !== false && strlen($bytes) === $length) {
  45. return $bytes;
  46. }
  47. }
  48. $checkAlternatives = (file_exists('/dev/urandom') && is_readable('/dev/urandom'))
  49. || class_exists('\\COM', false);
  50. if (true === $strong && false === $checkAlternatives) {
  51. throw new Exception\RuntimeException(
  52. 'This PHP environment doesn\'t support secure random number generation. ' .
  53. 'Please consider installing the OpenSSL and/or Mcrypt extensions'
  54. );
  55. }
  56. $generator = self::getAlternativeGenerator();
  57. return $generator->generate($length);
  58. }
  59. /**
  60. * Retrieve a fallback/alternative RNG generator
  61. *
  62. * @return RandomLib\Generator
  63. */
  64. public static function getAlternativeGenerator()
  65. {
  66. if (null !== static::$generator) {
  67. return static::$generator;
  68. }
  69. if (!class_exists('RandomLib\\Factory')) {
  70. throw new Exception\RuntimeException(
  71. 'The RandomLib fallback pseudorandom number generator (PRNG) '
  72. . ' must be installed in the absence of the OpenSSL and '
  73. . 'Mcrypt extensions'
  74. );
  75. }
  76. $factory = new RandomLib\Factory;
  77. $factory->registerSource(
  78. 'HashTiming',
  79. 'Zend\Math\Source\HashTiming'
  80. );
  81. static::$generator = $factory->getMediumStrengthGenerator();
  82. return static::$generator;
  83. }
  84. /**
  85. * Generate random boolean
  86. *
  87. * @param bool $strong true if you need a strong random generator (cryptography)
  88. * @return bool
  89. */
  90. public static function getBoolean($strong = false)
  91. {
  92. $byte = static::getBytes(1, $strong);
  93. return (bool) (ord($byte) % 2);
  94. }
  95. /**
  96. * Generate a random integer between $min and $max
  97. *
  98. * @param int $min
  99. * @param int $max
  100. * @param bool $strong true if you need a strong random generator (cryptography)
  101. * @return int
  102. * @throws Exception\DomainException
  103. */
  104. public static function getInteger($min, $max, $strong = false)
  105. {
  106. if ($min > $max) {
  107. throw new Exception\DomainException(
  108. 'The min parameter must be lower than max parameter'
  109. );
  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. }