Skip to content

Instantly share code, notes, and snippets.

@CodesInChaos
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CodesInChaos/03f9ea0b58e8b2b8d435 to your computer and use it in GitHub Desktop.
Save CodesInChaos/03f9ea0b58e8b2b8d435 to your computer and use it in GitHub Desktop.
<?php
if (!function_exists('random_bytes')) {
function random_bytes($size)
{
if(!is_int($size))
throw new Exception('random_bytes: $size must be an int');
if($size <= 0)
throw new Exception('random_bytes: $size must be positive');
if(function_exists('mcrypt_create_iv'))
{
$result = mcrypt_create_iv($size, MCRYPT_DEV_URANDOM);
}
else if(function_exists('openssl_random_pseudo_bytes'))
{
$result = openssl_random_pseudo_bytes($size, $isSecure);
if($isSecure !== true)
{
throw new Exception("random_bytes: openssl_random_pseudo_bytes returned insecure data");
}
}
else
{
throw new Exception("random_bytes: No RNG found");
}
if(!is_string($result) || (strlen($result) !== $size))
{
throw new Exception("random_bytes: RNG is unavailable or broken");
}
return $result;
}
}
if (!function_exists('random_int')) {
function random_int($min, $max)
{
if(version_compare(PHP_VERSION, '5.1.0') < 0)
trigger_error("random_int: This version of PHP is not supported", E_USER_ERROR);
if(!is_int($min))
throw new Exception('random_int: $min must be an int');
if(!is_int($max))
throw new Exception('random_int: $max must be an int');
if($min > $max)
throw new Exception('random_int: $min must be less or equal to $max');
$range = $max - $min + 1;
// the rejection probability is at most 0.5, so this corresponds to a failure probability of 2^-128 for a working RNG
for($attempts = 0; $attempts < 128; $attempts++)
{
// generate a random integer
$bytes = random_bytes(PHP_INT_SIZE);
$value = 0;
for($i = 0; $i < PHP_INT_SIZE; $i++)
{
$value = ($value << 8) | ord($bytes[$i]);
}
if(!is_int($range))
{
if(($value >= $min) && ($value <= $max))
{
return $value;
}
} else {
$value &= PHP_INT_MAX;
// equivalent to (PHP_INT_MAX + 1) % range, but avoids int overflows
// I'm assuming PHP_INT_MAX + 1 is a power-of-two and that integer's are represented as two's complement.
$reject = (-$range & PHP_INT_MAX) % $range;
if($value >= $reject)
{
return ($value % $range) + $min;
}
}
}
throw new Exception("random_int: RNG is broken - too many rejections");
}
}
<?php
if (!function_exists('random_string')) {
function random_string($length, $charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
{
if(!is_int($length))
throw new Exception('random_string: $length must be an integer');
if($length < 1)
throw new Exception('random_string: $length must be positive');
if(!is_string($charset))
throw new Exception('random_string: $charset must be a string');
if(strlen($charset) < 1)
throw new Exception('random_string: $charset must contain at least one element');
$randomString = "";
for ($i = 0; $i < $length; $i++)
$randomString .= $charset[random_int(0, strlen($charset) - 1)];
return $randomString;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment