Створити випадковий рядок з 5 символів


102

Я хочу створити точно 5 рядків випадкових символів з найменшою можливістю їх дублювання. Який був би найкращий спосіб зробити це? Дякую.


2
у вас є набір конкретних символів або тільки 0-9a-zA-Z?
Янік Рошон

Цей виклик коду для гольфу може бути знахідкою: codegolf.stackexchange.com/questions/119226/…
Тіт

Використовуючи Random::alphanumericString($length)ви можете отримати рядки з 0-9a-zA-Z, які походять з криптографічно захищених випадкових даних.
каркати

Відповіді:


162
$rand = substr(md5(microtime()),rand(0,26),5);

Я б найкраще здогадався - якщо ви також не шукаєте спеціальних персонажів:

$seed = str_split('abcdefghijklmnopqrstuvwxyz'
                 .'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                 .'0123456789!@#$%^&*()'); // and any other characters
shuffle($seed); // probably optional since array_is randomized; this may be redundant
$rand = '';
foreach (array_rand($seed, 5) as $k) $rand .= $seed[$k];

Приклад

І, наприклад, на основі годинника (менша кількість зіткнень, оскільки він наростає):

function incrementalHash($len = 5){
  $charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  $base = strlen($charset);
  $result = '';

  $now = explode(' ', microtime())[1];
  while ($now >= $base){
    $i = $now % $base;
    $result = $charset[$i] . $result;
    $now /= $base;
  }
  return substr($result, -5);
}

Примітка: додаткові засоби легше здогадатися; Якщо ви використовуєте це в якості солі або ознаки підтвердження, не робіть цього. Сіль (зараз) "WCWyb" означає 5 секунд, а тепер "WCWyg")


6
Проблема з використанням, md5()однак, полягає в тому, що ви отримуєте рядок з 16-символьного набору (10 цифр і aдо f, тобто 4 біта на символ рядка). Це може бути достатньо для деяких цілей, але може бути занадто мало для криптографічних цілей (п'ять символів із 16 символів = 16 ^ 5 = 20 біт = 1048576 можливостей).
Арк

3
array_rand($seed, 5)поверне ключ масиву, а не значення, тому ваш код не буде працювати
alumi

1
Я думаю, що використовувати криптографічну хеш-функцію для генерації випадкових символів, принаймні, недоцільно.
gronostaj

Можна також включити ", 'і зворотний слеш в $charset? Чи потрібно використовувати послідовності евакуації для включення цих символів?
травня

1
Другий фрагмент навіть не використовує параметр $lenвведення ... ти це забув?
TechNyquist

76

Якщо forциклів не вистачає, ось що я люблю використовувати:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);

Цікаве рішення ... дуже стисле, хоча мені цікаво, чи це швидше чи повільніше, ніж використання. Не можна заважати тестувати :-)
Арк,

@matthew str_shuffle буде створювати дублікати безперервно
SCC

@ User2826057: str_shuffle('ab')дасть abабо baале ніколи aa. Додавання str_repeatдозволяє для цього. Але це сказав, що рішення, яке я дав, насправді не є серйозним ... хоча воно і працює.
Метью

2
Є 1/60466176 ймовірність того, що це станеться, якщо припустити, що RNG розподілено рівномірно.
Метью

1
Це ідеально підходить для нашого випадку створення кодів ваучерів. Ми видалили заплутані символи, якl , i, 1, 0, O, і т.д. , і з 500 ваучерів не отримали дублікатів.
Люк Кузен

25

Швидкий спосіб - використовувати найбільш мінливі символи uniqid функції .

Наприклад:

$rand = substr(uniqid('', true), -5);


15

Нижче наведено найменший шанс на дублювання (можливо, ви захочете замінити mt_rand()на краще джерело випадкових чисел, наприклад, /dev/*randomз GUID або від нього):

<?php
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $result = '';
    for ($i = 0; $i < 5; $i++)
        $result .= $characters[mt_rand(0, 61)];
?>

EDIT:
Якщо ви стурбовані безпекою, дійсно, не варто використовувати rand()або mt_rand(), і переконайтеся , що випадкове пристрій даних насправді пристрій , яке генерує випадкові дані, а не звичайний файл або що - то передбачуване , як /dev/zero. mt_rand()вважається шкідливим:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDIT: Якщо у вас є підтримка OpenSSL в PHP, ви можете використовуватиopenssl_random_pseudo_bytes() :

<?php
    $length = 5;
    $randomBytes = openssl_random_pseudo_bytes($length);
    $characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    $charactersLength = strlen($characters);
    $result = '';
    for ($i = 0; $i < $length; $i++)
        $result .= $characters[ord($randomBytes[$i]) % $charactersLength];
?>

Перший приклад розумніший з результатом $. = $ Символів [mt_rand (0, strlen ($ символів) -1)]
hamboy75

У такому випадку слід заздалегідь визначити довжину і принаймні зберігати її в змінній. Використовувати strlen()в циклі зайве накладні витрати, особливо якщо ви вже знаєте, що набір символів тим часом не змінюється.
Арк

Сумніваюсь, php оптимізований, все
одно

7

Я завжди використовую для цього одну і ту ж функцію, як правило, для створення паролів. Він простий у використанні та корисний.

function randPass($length, $strength=8) {
    $vowels = 'aeuy';
    $consonants = 'bdghjmnpqrstvz';
    if ($strength >= 1) {
        $consonants .= 'BDGHJLMNPQRSTVWXZ';
    }
    if ($strength >= 2) {
        $vowels .= "AEUY";
    }
    if ($strength >= 4) {
        $consonants .= '23456789';
    }
    if ($strength >= 8) {
        $consonants .= '@#$%';
    }

    $password = '';
    $alt = time() % 2;
    for ($i = 0; $i < $length; $i++) {
        if ($alt == 1) {
            $password .= $consonants[(rand() % strlen($consonants))];
            $alt = 0;
        } else {
            $password .= $vowels[(rand() % strlen($vowels))];
            $alt = 1;
        }
    }
    return $password;
}

Хороший код. Однак $ alt завжди переходить від одного до 0. Чи не було б краще рандомізувати $ alt замість цього?
Ніко Андраде


3
$str = '';
$str_len = 8;
for($i = 0, $i < $str_len; $i++){
    //97 is ascii code for 'a' and 122 is ascii code for z
    $str .= chr(rand(97, 122));
}
return $str

2

Якщо добре, що ви отримаєте лише листи AF, то ось моє рішення:

str_pad(dechex(mt_rand(0, 0xFFFFF)), 5, '0', STR_PAD_LEFT);

Я вважаю, що використання хеш-функцій є надмірним завданням для такого простого завдання, як генерація послідовності випадкових шістнадцяткових цифр. dechex+ mt_randзробить таку ж роботу, але без зайвих криптографічних робіт. str_padгарантує 5-символьну довжину вихідного рядка (якщо випадкове число менше 0x10000).

Дублювання ймовірності залежить від mt_randнадійності Росії. Мерсенн Твістер відома високою якістю випадковості, тому вона повинна добре відповідати завданням.


2

Я також не знав, як це зробити, поки не думав використовувати PHP array. І я впевнений, що це найпростіший спосіб генерації випадкового рядка чи числа за допомогою масиву. Код:

function randstr ($len=10, $abc="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789") {
    $letters = str_split($abc);
    $str = "";
    for ($i=0; $i<=$len; $i++) {
        $str .= $letters[rand(0, count($letters)-1)];
    };
    return $str;
};

Ви можете використовувати цю функцію так

randstr(20)     // returns a random 20 letter string
                // Or like this
randstr(5, abc) // returns a random 5 letter string using the letters "abc"

1

Схожий на відповідь Бреда Крісті , але використовуючи sha1алроритм для символів 0-9a-zA-Zі з префіксом випадковою величиною:

$str = substr(sha1(mt_rand() . microtime()), mt_rand(0,35), 5);

Але якщо ви встановили визначені (дозволені) символи:

$validChars = array('0','1','2' /*...*/,'?','-','_','a','b','c' /*...*/);
$validCharsCount = count($validChars);

$str = '';
for ($i=0; $i<5; $i++) {
    $str .= $validChars[rand(0,$validCharsCount - 1)];
}

** ОНОВЛЕННЯ **

Як зазначав Архімедікс , це не гарантує повернення "найменшої можливості отримання дублювання", оскільки кількість комбінацій є низьким для даного діапазону символів. Вам або потрібно буде збільшити кількість символів, або дозволити додаткові (спеціальні) символи в рядку. Перше рішення було б кращим, я думаю, у вашому випадку.


Використання time()в 1 мільйон разів більш передбачуване, ніж microtime().
Арк

Також зауважте мої коментарі до відповіді Бреда, більша проблема полягає в тому, що генерований хеш - це шістнадцятковий подання, що складається з 16 дійсних символів, тому залишається лише 1024 варіантів для $str.
Арк

@Archimedix, можливо, але ОП не запитував про безпеку, питання було визначено про алгоритм генерації рядків, що складається з комбінації 5x26 різних символів та уникнення дублікатів. Це, мабуть, номер підтвердження для підтвердження в процесі реєстрації (або процесу виставлення рахунків), або щось таке
Yanick Rochon

Це було моє розуміння того, що він зробив просити найменшому можливість отримання дублюється , і це має 0,1% ймовірність (1 в 1024 році ) , яке могло б бути майже 1 в 1 млрд.
Арк

однак, якщо вам потрібно генерувати довідковий ключ з 5 символів і давати, що ви - клієнт / клієнт, ви не хочете їх надавати " ˫§»⁋⅓" просто тому, що це більш безпечно ... ви збільшуєте свій посилальний ключ до 7 і більше символів . (BTW: виправлення в моєму попередньому коментарі, це 5x36 символів)
Yanick Rochon


1

Джерело: Функція PHP, яка генерує випадкові символи

Ця проста функція PHP працювала для мене:

function cvf_ps_generate_random_code($length=10) {

   $string = '';
   // You can define your own characters here.
   $characters = "23456789ABCDEFHJKLMNPRTVWXYZabcdefghijklmnopqrstuvwxyz";

   for ($p = 0; $p < $length; $p++) {
       $string .= $characters[mt_rand(0, strlen($characters)-1)];
   }

   return $string;

}

Використання:

echo cvf_ps_generate_random_code(5);

1

Ось мої random 5 cents...

$random=function($a, $b) {
    return(
        substr(str_shuffle(('\\`)/|@'.
        password_hash(mt_rand(0,999999),
        PASSWORD_DEFAULT).'!*^&~(')),
        $a, $b)
    );
};

echo($random(0,5));

Нова password_hash()функція PHP (*> = PHP 5.5) виконує завдання для створення пристойно довгого набору великих і малих символів та цифр.

Два конкати. рядки до і після password_hash$ випадкової функції підходять для зміни.

Параметри для $random()* ($ a, $ b) - це фактично substr()параметри. :)

ПРИМІТКА: це не повинно бути функцією, це може бути і нормальна змінна .. як один неприємний одиночний ліній, як це:

$random=(substr(str_shuffle(('\\`)/|@'.password_hash(mt_rand(0,999999), PASSWORD_DEFAULT).'!*^&~(')), 0, 5));

echo($random);

1
function CaracteresAleatorios( $Tamanno, $Opciones) {
    $Opciones = empty($Opciones) ? array(0, 1, 2) : $Opciones;
    $Tamanno = empty($Tamanno) ? 16 : $Tamanno;
    $Caracteres=array("0123456789","abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    $Caracteres= implode("",array_intersect_key($Caracteres, array_flip($Opciones)));
    $CantidadCaracteres=strlen($Caracteres)-1;
    $CaracteresAleatorios='';
    for ($k = 0; $k < $Tamanno; $k++) {
        $CaracteresAleatorios.=$Caracteres[rand(0, $CantidadCaracteres)];
    }
    return $CaracteresAleatorios;
}

Порада щодо професіоналів - включіть пояснення щодо того, як ваша відповідь вирішує проблему ОП, і чому вона може відрізнятися від інших, вже наданих відповідей.
Том

0

Я завжди використовую це:

<?php function fRand($len) {
    $str = '';
    $a = "abcdefghijklmnopqrstuvwxyz0123456789";
    $b = str_split($a);
    for ($i=1; $i <= $len ; $i++) { 
        $str .= $b[rand(0,strlen($a)-1)];
    }
    return $str;
} ?>

Коли ви називаєте це, встановлює довжину рядка.

<?php echo fRand([LENGHT]); ?>

Ви також можете змінити можливі символи в рядку $a.


Я бачу, що втрачений час неробливо розвиває цю функцію. Я гугла маленька! @Andrew
LipESprY
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.