29
29
# include "win32/winutil.h"
30
30
#endif
31
31
32
- // Big thanks to @ircmaxell for the help on this bit
33
- union rand_long_buffer {
34
- char buffer [8 ];
35
- long number ;
36
- };
37
-
38
- // Copy/pasted from mcrypt.c
39
32
static int php_random_bytes (void * bytes , size_t size )
40
33
{
41
34
int n = 0 ;
@@ -79,7 +72,7 @@ static int php_random_bytes(void *bytes, size_t size)
79
72
return SUCCESS ;
80
73
}
81
74
82
- /* {{{ proto string random_bytes(int bytes )
75
+ /* {{{ proto string random_bytes(int length )
83
76
Return an arbitrary length of pseudo-random bytes as binary string */
84
77
PHP_FUNCTION (random_bytes )
85
78
{
@@ -90,8 +83,8 @@ PHP_FUNCTION(random_bytes)
90
83
return ;
91
84
}
92
85
93
- if (size <= 0 || size >= INT_MAX ) {
94
- php_error_docref (NULL , E_WARNING , "Cannot genrate a random string with a size of less than 1 or greater than %d" , INT_MAX );
86
+ if (size < 1 ) {
87
+ php_error_docref (NULL , E_WARNING , "Length must be greater than 0" );
95
88
RETURN_FALSE ;
96
89
}
97
90
@@ -108,44 +101,46 @@ PHP_FUNCTION(random_bytes)
108
101
}
109
102
/* }}} */
110
103
111
- /* {{{ proto int random_int(int maximum )
104
+ /* {{{ proto int random_int(int max )
112
105
Return an arbitrary pseudo-random integer */
113
106
PHP_FUNCTION (random_int )
114
107
{
115
- zend_long maximum ;
116
- zend_long size ;
117
- size_t i ;
108
+ zend_long max = ZEND_LONG_MAX ;
109
+ zend_long limit ;
110
+ zend_long result ;
118
111
119
- if (zend_parse_parameters (ZEND_NUM_ARGS (), "|l" , & maximum ) == FAILURE ) {
112
+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "|l" , & max ) == FAILURE ) {
120
113
return ;
121
114
}
122
115
123
- if (ZEND_NUM_ARGS () == 0 ) {
124
- maximum = INT_MAX ;
116
+ if (max <= 0 || max > ZEND_LONG_MAX ) {
117
+ php_error_docref (NULL , E_WARNING , "Cannot use maximum less than 1 or greater than %d" , ZEND_LONG_MAX );
118
+ RETURN_FALSE ;
125
119
}
126
120
127
- if (maximum <= 0 || maximum > INT_MAX ) {
128
- php_error_docref (NULL , E_WARNING , "Cannot use maximum less than 1 or greater than %d" , INT_MAX );
129
- RETURN_FALSE ;
121
+ // Special case so we can return a range inclusive of the upper bound
122
+ if (max == ZEND_LONG_MAX ) {
123
+ if (php_random_bytes (& result , sizeof (result )) == FAILURE ) {
124
+ return ;
125
+ }
126
+ RETURN_LONG (result & ZEND_LONG_MAX );
130
127
}
131
128
132
- long range = (long ) maximum ; // @todo Support min?
129
+ // Increment the max so the range is inclusive of max
130
+ max ++ ;
133
131
134
- // Big thanks to @ircmaxell for the help on this bit
135
- union rand_long_buffer value ;
136
- long result ;
137
- int bits = (int ) (log ((double ) range ) / log (2.0 )) + 1 ;
138
- int bytes = MAX (ceil (bits / 8 ), 1 );
139
- long mask = (long ) pow (2.0 , (double ) bits ) - 1 ;
132
+ // Ceiling under which ZEND_LONG_MAX % max == 0
133
+ limit = ZEND_LONG_MAX - (ZEND_LONG_MAX % max ) - 1 ;
140
134
135
+ // Discard numbers over the limit to avoid modulo bias
141
136
do {
142
- if (php_random_bytes (& value . buffer , 8 ) == FAILURE ) {
137
+ if (php_random_bytes (& result , sizeof ( result ) ) == FAILURE ) {
143
138
return ;
144
139
}
145
- result = value . number & mask ;
146
- } while (result > maximum );
140
+ result &= ZEND_LONG_MAX ;
141
+ } while (result > limit );
147
142
148
- RETURN_LONG (result );
143
+ RETURN_LONG (result % max );
149
144
}
150
145
/* }}} */
151
146
0 commit comments