Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ext/standard/php_random.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ typedef struct {
#define php_random_bytes_throw(b, s) php_random_bytes((b), (s), 1)
#define php_random_bytes_silent(b, s) php_random_bytes((b), (s), 0)

#define php_random_int_throw(min, max, result) \
php_random_int((min), (max), (result), 1)
#define php_random_int_silent(min, max, result) \
php_random_int((min), (max), (result), 0)

PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw);
PHPAPI int php_random_int(zend_long min, zend_long max, zend_long *result, zend_bool should_throw);

#ifdef ZTS
# define RANDOM_G(v) ZEND_TSRMG(random_globals_id, php_random_globals *, v)
Expand Down
63 changes: 39 additions & 24 deletions ext/standard/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ PHP_MSHUTDOWN_FUNCTION(random)
/* }}} */

/* {{{ */

PHPAPI int php_random_bytes(void *bytes, size_t size, zend_bool should_throw)
{
#if PHP_WIN32
Expand Down Expand Up @@ -214,37 +213,27 @@ PHP_FUNCTION(random_bytes)
}
/* }}} */

/* {{{ proto int random_int(int min, int max)
Return an arbitrary pseudo-random integer */
PHP_FUNCTION(random_int)
/* {{{ */
PHPAPI int php_random_int(zend_long min, zend_long max, zend_long *result, zend_bool should_throw)
{
zend_long min;
zend_long max;
zend_ulong umax;
zend_ulong result;

if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ll", &min, &max) == FAILURE) {
return;
}

if (min > max) {
zend_throw_exception(zend_ce_error, "Minimum value must be less than or equal to the maximum value", 0);
return;
}
zend_ulong trial;

if (min == max) {
RETURN_LONG(min);
*result = min;
return SUCCESS;
}

umax = max - min;

if (php_random_bytes_throw(&result, sizeof(result)) == FAILURE) {
return;
if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) {
return FAILURE;
}

/* Special case where no modulus is required */
if (umax == ZEND_ULONG_MAX) {
RETURN_LONG((zend_long)result);
*result = (zend_long)trial;
return SUCCESS;
}

/* Increment the max so the range is inclusive of max */
Expand All @@ -256,14 +245,40 @@ PHP_FUNCTION(random_int)
zend_ulong limit = ZEND_ULONG_MAX - (ZEND_ULONG_MAX % umax) - 1;

/* Discard numbers over the limit to avoid modulo bias */
while (result > limit) {
if (php_random_bytes_throw(&result, sizeof(result)) == FAILURE) {
return;
while (trial > limit) {
if (php_random_bytes(&trial, sizeof(trial), should_throw) == FAILURE) {
return FAILURE;
}
}
}

RETURN_LONG((zend_long)((result % umax) + min));
*result = (zend_long)((trial % umax) + min);
return SUCCESS;
}
/* }}} */

/* {{{ proto int random_int(int min, int max)
Return an arbitrary pseudo-random integer */
PHP_FUNCTION(random_int)
{
zend_long min;
zend_long max;
zend_long result;

if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "ll", &min, &max) == FAILURE) {
return;
}

if (min > max) {
zend_throw_exception(zend_ce_error, "Minimum value must be less than or equal to the maximum value", 0);
return;
}

if (php_random_int_throw(min, max, &result) == FAILURE) {
return;
}

RETURN_LONG(result);
}
/* }}} */

Expand Down