Обходной путь для suhosin.mt_srand.ignore для последовательного перемешивания массива в PHP? - PullRequest
4 голосов
/ 28 февраля 2012

У меня есть PHP-скрипт, который должен рандомизировать массив с единообразными результатами, чтобы он мог представить первые несколько элементов пользователю, а затем он мог бы получить больше результатов из того же перемешанного набора, если они этого хотят.

В настоящее время я использую следующее (основываясь на алгоритме Фишера Йетса, как мне кажется):

function shuffle(&$array, $seed)
{
    mt_srand($seed);
    for ($a=count($array)-1; $a>0; $a--) {
        $b = mt_rand(0, $a);
        $temp = $array[$a];
        $array[$a] = $array[$b];
        $array[$b] = $temp;
    }
}

Что отлично работает на моей локальной установке, но на сервере, на котором он должен работать, установлен Suhosin, который переопределяет mt_srand, что означает, что начальное число игнорируется, массив просто случайным образом перемешивается, и пользователь получает дублированные результаты.

Все, что я нашел в Google, предполагает, что мне нужно отключить suhosin.mt_srand.ignore (и suhosin.srand.ignore, хотя и не уверен, что последний актуален), поэтому я добавил в .htaccess следующее:

php_flag suhosin.mt_srand.ignore Off
php_flag suhosin.srand.ignore Off

У меня нет доступа к php.ini на этом сервере, так что AFAIK - это единственный способ, которым я могу это сделать. Проблема в том, что ничего не дает - phpinfo () по-прежнему показывает обе настройки как On, тогда как я могу изменить другие настройки Suhosin с помощью .htaccess без проблем.

Итак, я полагаю, что я ищу способ либо фактически отключить suhosin.mt_srand.ignore (или причину, по которой он не работает), либо обходной путь для генерации генератора случайных чисел из PHP. Или мне просто придется самому внедрить еще один ГСЧ?

Любая помощь будет высоко ценится. Спасибо!

1 Ответ

2 голосов
/ 25 октября 2012

Используя некоторые базовые математические и некоторые трюки, вы можете довольно легко создать свою СОБСТВЕННУЮ случайную функцию, как я только что сделал:)

Извините, я не убрал это. Это было бы намного лучше в классе, поскольку вы могли бы предотвратить необходимость повторного посева с предыдущим семенем. Не используйте статическую переменную, так как она ограничивает вас использованием только 1 семени за раз (или вручную отслеживает семена). ООП решит это. Делайте то, что вам нравится, с помощью функции ниже, но дайте мне знать, если вы переписываете ее.

/**
* returns a decimal between 0 and max_number, requires seeding every time and will ALWAYS return the same decimal for the same seed
* @copyright scott thompson, all rights reserved
* @license MIT (do what you like with this)
* @param string $seed
* @param int $max_number=100 adjust the maximum number range
*/
function random_number($seed, $max_number = 100) {

    //make sure there won't be any deadspace where random numbers will never fill
    if ($max_number > 0xFFFFFF) {
        trigger_error("Max random number was to high. Maximum number of " . 0xFFFFFF . " allowed. Defaulting to maximum number.", E_USER_WARNING);
        $max_number = 0xFFFFFF;
    }

    //hash the seed to ensure enough random(ish) characters each time
    $hash = sha1($seed);

    //use the first x characters, and convert from hex to base 10 (this is where the random number is obtain)
    $rand = base_convert(substr($hash, 0, 6), 16, 10);

    //as a decimal percentage (ensures between 0 and max number)
    return $rand / 0xFFFFFF * $max_number ;

}

$seed = 'hello';
print ($seed = random_number($seed)) . '<br />'; //66.779748605475
print ($seed = random_number($seed)) . '<br />'; //3.5753311857779
print ($seed = random_number($seed)) . '<br />'; //13.994396567011
print ($seed = random_number($seed)) . '<br />'; //70.344917198713
print ($seed = random_number($seed)) . '<br />'; //4.5583250855401

Надеюсь, это поможет, Скотт

...