PHP быстрая функция случайных строк - PullRequest
7 голосов
/ 21 января 2011

Мне нужен быстрый способ генерации случайных строк a-Z0-9 в PHP. Я немного подумал и протестировал, вот что у меня так далеко:

function randStr($length) {
    $result = null;
    $replace = array('/', '+', '=');
        while(!isset($result[$length-1])) {
        $result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
        }
    return substr($result, 0, $length);
}

Функция, кажется, работает быстро по сравнению с функциями, которые выполняют итерацию и выбирают случайное значение ASCII для каждого символа, но меня беспокоит «качество» моей реализации. Я не очень разбираюсь в криптографии, поэтому я хотел бы спросить, создает ли этот тип функции «хорошие» случайные значения или нет.

  1. mcrypt_create_iv, кажется, возвращает какие-то случайные двоичные значения, фактически используемые для шифрования / дешифрования данных с помощью библиотеки mcrypt. Каков эффект base64_encode для этого вида двоичных данных, действительно ли я уменьшаю энтропию, когда я base64_encode это?

  2. Как второй параметр для mcrypt_create_iv влияет на мои результаты? Руководство php.net утверждает, что MCRYPT_RAND - это «системный генератор случайных чисел». Это зависит от конкретной ОС и, если да, то как создаются хорошие значения?

Ответы [ 5 ]

5 голосов
/ 09 декабря 2014

Это должно быть безопасно в большинстве систем и быстро:

bin2hex(openssl_random_pseudo_bytes($length / 2));

тесты (1000000 записей, длина строки 100 символов)

rstr1: 198.93383002281
rstr2: 35.5827729702
rstr3: 6.8811790943146
rstr4: 5.4545040130615
this:: 3.9310231208801
3 голосов
/ 31 марта 2018

Для тех, кто ищет обновленную версию «лучшего» алгоритма:

function randomString($length) {
   $result = null;
   $replace = array('/', '+', '=');
   while(!isset($result[$length-1])) {
      $result.= str_replace($replace, NULL, base64_encode(random_bytes($length)));
   }
   return substr($result, 0, $length);
}

Я использую термин «лучший», потому что он быстрее, чем случайные манипуляции со строками rstr1 и rstr2, и по сравнению с другими решениями предлагает полный спектр букв (строчные и прописные).

3 голосов
/ 21 января 2011
  1. base64_encoding не уменьшит энтропию, это просто другое представление тех же данных.

  2. Это зависит от ОС, но я думаю, что случайные значениясозданы достаточно хороши с этой функцией.В PHP 5.3 вы должны заполнить генератор заранее, это может быть проблемой, если вы используете этот код на разных серверах.

2 голосов
/ 09 сентября 2013

Из моих тестов ваша функция уже очень быстрая, но мне удалось добраться до более быстрой, даже если она уменьшает энтропию

fcn     time  
rstr1:  1.074s (slowest)
rstr2:  0.917s
rstr3:  0.028s (yours)
rstr4:  0.022s (mine)

В моем сценарии мне потребовалось 1 тыс. Строк как можно быстрее.

function rstr1($length)
{
    // @see http://stackoverflow.com/a/853846/11301
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alphabet, $length)), 0, $length);
}

function rstr2($length)
{
    // @see http://stackoverflow.com/a/853870/11301
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $str = '';
    $count = strlen($alphabet);
    while ($length--) {
        $str .= $alphabet[mt_rand(0, $count-1)];
    }
    return $str;
}

function rstr3($length) {
    // @see http://stackoverflow.com/q/4757392/11301
    $result = null;
    $replace = array('/', '+', '=');
    while(!isset($result[$length-1])) {
        $result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
    }
    return substr($result, 0, $length);
}

function rstr4($length)
{
    // uses md5 & mt_rand. Not as "random" as it could be, but it works, and its fastest from my tests
    return str_shuffle(substr(str_repeat(md5(mt_rand()), 2+$length/32), 0, $length));
}


// test the functions
for($i=0; $i<1000; $i++){
    #$x = rstr1(1024); # 
    #$x = rstr2(1024);  # 0.917s
    #$x = rstr3(1024);  # 0.028s
    #$x = rstr4(1024);  # 0.022s

    #dlog($x); return;
}
0 голосов
/ 21 января 2011

Вот как я это делаю, хотя это не совсем криптографически;Mersenne Twister быстрый и надежный, но не самый безопасный.

function str_rand($chars, $len)
  {
  $str = '';
  for ($max = strlen($chars) - 1, $i = 0; $i < $len; ++$i)
       {
       $str .= $chars[mt_rand(0, $max)];
       }
  return $str;
  }

$strRand = str_rand('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 40);
...