You know what is array_rand and you use it sometimes like rand() ( maybe mt_rand() if you want better random value). Anyway, i was reading this page when i saw the comment by Sebmil. This was pretty weird and i tried to figure it out why. This is in progress, because i did not found the reason.  I'm using php 5.3.6-p10-gentoo but i tested on ubuntu with 5.3.2 and i'm pretty sure it's all around.
$values = range(0, 49);
$prob = array_fill(0, 50, 0);
for ($i = 0; $i < 10000; $i++) {     $rand = array_rand($values, 10);     foreach($rand as $key => $value) {
        $prob[$values[$value]]++;
    }
}
asort($prob);
var_dump($prob);

/** Output something like this:
*  "30" will always be at the top
array
  <strong>30 => int 1842</strong>
  40 => int 1934
  3 => int 1935
  10 => int 1940
  45 => int 1942
  28 => int 1949
  14 => int 1962
  47 => int 1965
  22 => int 1965
  19 => int 1968
  ...
*/

What do i know ?!?

  • If the second params of for is lower ( like 50 ) , the output seem random.
  • If we use rand() in each loop the "lower" value (30) will change. One for each rand() used. When we reach 3 ( about 27 rand() calls ),  the output seem random.
  • If we use rand() or mt_rand() instead of array_rand, the output seem random.
  • php 5.4 trunk array_rand function doesn't seem to have changed.

array_rand() source php 5.3 trunk :

Can you figure out where the bug is ?
/* {{{ proto mixed array_rand(array input [, int num_req])
   Return key/keys for random entry/entries in the array */
PHP_FUNCTION(array_rand)
{
        zval *input;
        long randval, num_req = 1;
        int num_avail, key_type;
        char *string_key;
        uint string_key_len;
        ulong num_key;
        HashPosition pos;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &input, &num_req) == FAILURE) {
                return;
        }

        num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));

        if (ZEND_NUM_ARGS() > 1) {
                if (num_req  num_avail) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");
                        return;
                }
        }

        /* Make the return value an array only if we need to pass back more than one result. */
        if (num_req > 1) {
                array_init_size(return_value, num_req);
        }

        /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
        while (num_req && (key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &pos)) != HASH_KEY_NON_EXISTANT) {

                randval = php_rand(TSRMLS_C);

                if ((double) (randval / (PHP_RAND_MAX + 1.0)) < (double) num_req / (double) num_avail) {
                        /* If we are returning a single result, just do it. */
                        if (Z_TYPE_P(return_value) != IS_ARRAY) {
                                if (key_type == HASH_KEY_IS_STRING) {
                                        RETURN_STRINGL(string_key, string_key_len - 1, 1);
                                } else {
                                        RETURN_LONG(num_key);
                                }
                        } else {
                                /* Append the result to the return value. */
                                if (key_type == HASH_KEY_IS_STRING) {
                                        add_next_index_stringl(return_value, string_key, string_key_len - 1, 1);
                                } else {
                                        add_next_index_long(return_value, num_key);
                                }
                        }
                        num_req--;
                }
                num_avail--;
                zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);
        }
}

Possible solution :

  1. Shuffle() your array in each loop
  2. Use multiple time rand()
  3. Don't use array_rand too often.