Skip to content

Instantly share code, notes, and snippets.

@mpratt
Created December 12, 2013 21:42
Show Gist options
  • Save mpratt/7936062 to your computer and use it in GitHub Desktop.
Save mpratt/7936062 to your computer and use it in GitHub Desktop.
A random number/range/string/bool generator
<?php
/**
* Random.php
*
* @author Michael Pratt <[email protected]>
* @link http://www.michael-pratt.com/
* @license MIT
*
*/
namespace Random;
/**
* This simple class is used to generate random values
*/
class Random
{
/**
* Generates Random Bytes for the given $length.
*
* @param int $length
* @return string
*
* @throws InvalidArgumentException when an invalid length is specified.
* @throws RuntimeException when no secure way of making bytes is posible
*/
public function bytes($length = 0)
{
if ($length < 1) {
throw new \InvalidArgumentException('The lenght parameter must be a number greater than 0!');
}
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes($length, $secure);
if ($secure === true) {
return $bytes;
}
}
/**
* There is a bug in mcrypt_create_iv in older versions/snaps of PHP in windows
* where an empty value is returned.
* https://bugs.php.net/bug.php?id=55169
*/
if (function_exists('mcrypt_create_iv') && (strtolower(substr(PHP_OS, 0, 3)) !== 'win' || version_compare(PHP_VERSION, '5.3.7') >= 0)) {
$bytes = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
if ($bytes !== false) {
return $bytes;
}
}
throw new \RuntimeException('There is no posible way of making secure bytes');
}
/**
* Generates a random integer between $min and $max
*
* @param int $min
* @param int $max
* @param int $seedLenght
* @return int
*
* @throws InvalidArgumentException when min/max numbers are invalid
* @throws RuntimeException when the range is too big.
*/
public function range($min, $max, $seedLenght = 5)
{
if ($min >= $max) {
throw new \InvalidArgumentException('The min parameter must be lower than max parameter');
}
$range = $max - $min;
if ($range > PHP_INT_MAX || is_float($range)) {
throw new \RuntimeException('The supplied range is too big');
}
$seed = hexdec(bin2hex($this->bytes($seedLenght)));
while ($seed > 1) {
$seed *= 0.1;
}
return (int) $min + ($seed * ($range + 1));
}
/**
* Generates a random string
*
* @param int $length
* @param string $chars If no chars are given, it uses Base64 character set.
* @return string
*
* @throws InvalidArgumentException when an invalid length is specified.
*/
public function string($length = 0, $chars = null)
{
if ($length < 1) {
throw new \InvalidArgumentException('The lenght parameter must be a number greater than 0!');
}
if (empty($chars)) {
$numBytes = ceil($length * 0.75);
$bytes = $this->bytes($numBytes);
return substr(rtrim(base64_encode($bytes), '='), 0, $length);
}
$listLen = strlen($chars);
if ($listLen == 1) {
return str_repeat($chars, $length);
}
$bytes = $this->bytes($length);
$pos = 0;
$result = '';
for ($i = 0; $i < $length; $i++) {
$pos = ($pos + ord($bytes[$i])) % $listLen;
$result .= $chars[$pos];
}
return $result;
}
/**
* Generates random boolean
*
* @return bool
*/
public function bool()
{
return (bool) (ord($this->bytes(1)) % 2);
}
}
?>
<?php
/**
* @author Michael Pratt <[email protected]>
* @link http://www.michael-pratt.com/
*/
use Random\Random;
require 'Random.php';
class TestRandom extends PHPUnit_Framework_TestCase
{
public function testBytes()
{
$random = new Random();
$bytes1 = $random->bytes(5);
$bytes2 = $random->bytes(5);
$bytes3 = $random->bytes(5);
$bytes4 = $random->bytes(5);
$bytes5 = $random->bytes(5);
$bytes6 = $random->bytes(5);
$this->assertTrue((strlen($bytes1) == 5));
$this->assertTrue((strlen($bytes2) == 5));
$this->assertTrue((strlen($bytes3) == 5));
$this->assertTrue((strlen($bytes4) == 5));
$this->assertTrue((strlen($bytes5) == 5));
$this->assertTrue((strlen($bytes6) == 5));
$this->assertTrue(($bytes1 != $bytes2 && $bytes2 != $bytes3 && $bytes3 != $bytes1));
$this->assertTrue(($bytes4 != $bytes5 && $bytes5 != $bytes6 && $bytes4 != $bytes6));
$this->assertTrue(($bytes1 != $bytes6 && $bytes1 != $bytes4 && $bytes5 != $bytes1));
$this->assertTrue(($bytes2 != $bytes6 && $bytes2 != $bytes4 && $bytes5 != $bytes2));
$this->assertTrue(($bytes3 != $bytes6 && $bytes3 != $bytes4 && $bytes5 != $bytes3));
}
public function testBytesInvalid()
{
$this->setExpectedException('InvalidArgumentException');
$random = new Random();
$bytes1 = $random->bytes();
}
public function testRange()
{
$random = new Random();
$r1 = $random->range(5, 25);
$r2 = $random->range(5, 25);
$r3 = $random->range(5, 25);
$this->assertTrue(($r1 != $r2 && $r2 != $r3 && $r3 != $r1));
$this->assertTrue(($r1 >= 5 && $r1 <= 25));
$this->assertTrue(($r2 >= 5 && $r2 <= 25));
$this->assertTrue(($r3 >= 5 && $r3 <= 25));
}
public function testRange2()
{
$random = new Random();
$r1 = $random->range(5, 200);
$r2 = $random->range(5, 200);
$r3 = $random->range(5, 200);
$this->assertTrue(($r1 != $r2 && $r2 != $r3 && $r3 != $r1));
$this->assertTrue(($r1 >= 5 && $r1 <= 200));
$this->assertTrue(($r2 >= 5 && $r2 <= 200));
$this->assertTrue(($r3 >= 5 && $r3 <= 200));
}
public function testRangeInvalid()
{
$this->setExpectedException('InvalidArgumentException');
$random = new Random();
$random->range(10, 5);
}
public function testBool()
{
$random = new Random();
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
$this->assertTrue(is_bool($random->bool()));
}
public function testString()
{
$random = new Random();
$s1 = $random->string(4);
$s2 = $random->string(4);
$s3 = $random->string(4);
$this->assertTrue(($s1 != $s2 && $s2 != $s3 && $s3 != $s1));
$this->assertEquals(strlen($s1), 4);
$this->assertEquals(strlen($s2), 4);
$this->assertEquals(strlen($s3), 4);
$this->assertTrue(is_string($s1));
$this->assertTrue(is_string($s2));
$this->assertTrue(is_string($s3));
}
public function testStringChars()
{
$random = new Random();
$chars = 'aGhretdPxZmlL046s1r';
$s1 = $random->string(4, $chars);
$s2 = $random->string(4, $chars);
$s3 = $random->string(4, $chars);
$this->assertTrue(($s1 != $s2 && $s2 != $s3 && $s3 != $s1));
$this->assertEquals(strlen($s1), 4);
$this->assertEquals(strlen($s2), 4);
$this->assertEquals(strlen($s3), 4);
$this->assertTrue(is_string($s1));
$this->assertTrue(is_string($s2));
$this->assertTrue(is_string($s3));
$this->assertTrue((strpos('u', $s1) === false));
$this->assertTrue((strpos('u', $s2) === false));
$this->assertTrue((strpos('u', $s3) === false));
}
public function testStringInvalid()
{
$this->setExpectedException('InvalidArgumentException');
$random = new Random();
$random->string();
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment