Skip to content

Instantly share code, notes, and snippets.

@roukmoute
Created June 2, 2020 11:09
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 roukmoute/b8cd3416bf4ab1950ed197d9be387e0d to your computer and use it in GitHub Desktop.
Save roukmoute/b8cd3416bf4ab1950ed197d9be387e0d to your computer and use it in GitHub Desktop.
Generate a random token using /dev/random
<?php
declare(strict_types=1);
namespace App;
class TokenProvider
{
const RANDOM_COMPAT_READ_BUFFER = 8;
/**
* Generates a string of pseudo-random bytes.
*
* @param int $size the desired token length, in terms of bytes
* @param bool $strong setting to TRUE means /dev/random will be used for
* entropy, as otherwise the non-blocking
* /dev/urandom is used
*/
public static function generateToken(int $size, bool $strong = false): string
{
if ($size < 1) {
throw new \InvalidArgumentException('Cannot generate token with a size of less than 1');
}
return self::fallBack(self::randomBytes($strong, $size), $size);
}
private static function randomBytes(bool $strong, int $size): string
{
$vector = '';
$fd = fopen($strong ? '/dev/random' : '/dev/urandom', 'r');
if (!\is_resource($fd)) {
return $vector;
}
/*
* If we don't set the stream's read buffer to 0, PHP will
* internally buffer 8192 bytes, which can waste entropy.
*/
if (\is_callable('stream_set_read_buffer')) {
stream_set_read_buffer($fd, self::RANDOM_COMPAT_READ_BUFFER);
}
while (mb_strlen($vector) < $size) {
$randomString = fread($fd, $size - mb_strlen($vector));
if (!\is_string($randomString) || mb_strlen($randomString) < 0) {
break;
}
$vector .= $randomString;
}
fclose($fd);
return $vector;
}
/**
* Could not gather enough random data, falling back on rand().
*/
private static function fallBack(string $vector, int $size): string
{
$reaped = mb_strlen($vector);
if ($reaped >= $size) {
return $vector;
}
while ($reaped < $size) {
$randomString = \chr((int) (255 * rand() / mt_getrandmax()));
$vector .= $randomString;
$reaped += mb_strlen($randomString);
}
return $vector;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment