PHP функция быстрой случайной строки
Мне нужен быстрый способ для генерации случайных строк 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 для каждого символа, но меня беспокоит "качество" моей реализации. Я мало что знаю о криптографии, поэтому я хотел бы спросить, создает ли этот вид функции "хорошие" случайные значения или нет.
-
mcrypt_create_iv
кажется, да. возвращает некоторые случайные двоичные значения, фактически используемые для шифрования / дешифрования данных с помощью библиотеки mcrypt. Что такое base64_encode эффект на этот вид двоичных данных, действительно ли я уменьшаю энтропию, когда я base64_encode его? -
Как второй параметр для
mcrypt_create_iv
влияет на мои результаты? php.net руководство утверждает, чтоMCRYPT_RAND
является "системным генератором случайных чисел". Является ли это специфичным для ОС и если да, то насколько хорошие значения создаются?
5 ответов:
Base64_encoding не уменьшает энтропию, это просто другое представление одних и тех же данных.
Это специфично для ОС, но я думаю, что случайные значения, созданные достаточно хороши с этой функцией. В PHP 5.3 вы должны предварительно запустить генератор, это может быть проблемой, если вы используете этот код на разных серверах.
Это должно быть безопасно на большинстве систем и быстро:
bin2hex(openssl_random_pseudo_bytes($length / 2));
Бенчмарки (1000000 записей, длина строки 100 символов)
rstr1: 198.93383002281 rstr2: 35.5827729702 rstr3: 6.8811790943146 rstr4: 5.4545040130615 this:: 3.9310231208801
Из моих тестов, ваша функция уже очень быстрая, но мне удалось добраться до более быстрой, даже если она уменьшает энтропию
fcn time rstr1: 1.074s (slowest) rstr2: 0.917s rstr3: 0.028s (yours) rstr4: 0.022s (mine)
В моем сценарии мне нужно было 1K строк, как можно быстрее.
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; }
Для тех, кто ищет обновленную версию" лучшего " алгоритма:
Я использую термин "лучший", потому что он быстрее, чем случайные строковые манипуляции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
и по сравнению с другими решениями предлагает полный спектр букв (нижний и верхний регистры).
Вот как я это делаю, хотя это и не совсем криптография; Твистер Мерсенна быстр и надежен, но не самый безопасный.
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);