Question

For testing and learning purpose, I wanted to modify the php rand and mt_rand functions which are in https://github.com/php/php-src:ext/standard/rand.c.

I wanted to give a fixed output each time rand function is called and for this purpose I modified the code

PHPAPI long php_rand(TSRMLS_D)
{
    long ret;

    if (!BG(rand_is_seeded)) {
        php_srand(GENERATE_SEED() TSRMLS_CC);
    }

#ifdef ZTS
    ret = php_rand_r(&BG(rand_seed));
#else
# if defined(HAVE_RANDOM)
    ret = random();
# elif defined(HAVE_LRAND48)
    ret = lrand48();
# else
    ret = rand();
# endif
#endif

    // ignoring the results coming from the calls above and 
    // returning a constant value 
    ret = 3264;

    return ret;
}

compiled

./configure
make
make install

and finally called the rand function as echo rand(3000,4000); and it always returns 3000.

What would be the way to modify this function? and why there is TSRMLS_D but not the range parameters?

Was it helpful?

Solution

The actual function that is called from PHP is the one declared PHP_FUNCTION(rand), which calls the php_rand() function that you modified. It does the following:

PHP_FUNCTION(rand)
{
    long min;
    long max;
    long number;
    int  argc = ZEND_NUM_ARGS();

    if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE)
        return;

    number = php_rand(TSRMLS_C);
    if (argc == 2) {
        RAND_RANGE(number, min, max, PHP_RAND_MAX);
    }

    RETURN_LONG(number);
}

As you can see, if you pass 2 parameters in, it calls the RAND_RANGE macro, which transforms the result of php_rand() into the range given.

#define RAND_RANGE(__n, __min, __max, __tmax) \
    (__n) = (__min) + (long) ((double) ( (double) (__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))

If you want it always to output a given value, I would recommend modifying PHP_FUNCTION(rand), instead of php_rand().

Though if all you're looking for is stable random number outputs, so that you get the same result every time, if you don't care about the exact result, you can just call srand(0) at the beginning of your program, to seed the random number generator with a constant value. This will mean that the random number generator will always give you the same sequence of random numbers, which is useful for testing purposes, and can be done without patching PHP itself.

OTHER TIPS

Look at the RAND_RANGE macro define in php_rand.h. It does some additional permutation/scrambling of the input value to make it fit between the range you've specified.

If you really want the rand() function to return 3264 even if that doesn't fit within the parameters passed to rand(), remove this block in rand.c:

    if (argc == 2) {
    RAND_RANGE(number, min, max, PHP_RAND_MAX);
}

If you still want to consider min/max, you're going to need to figure out what you want that to actually do if you specify a min/max that doesn't include your hardcoded number.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top