Tạo chuỗi 5 ký tự ngẫu nhiên


101

Tôi muốn tạo chuỗi 5 ký tự ngẫu nhiên chính xác với ít khả năng bị trùng lặp nhất. Cách tốt nhất để làm điều đó là gì? Cảm ơn.


2
bạn có một bộ một ký tự cụ thể hay chỉ 0-9a-zA-Z?
Yanick Rochon

Thử thách chơi gôn mã này có thể là một cuộc tìm kiếm: codegolf.stackexchange.com/questions/119226/…
Tít

Sử dụng, Random::alphanumericString($length)bạn có thể nhận được các chuỗi có 0-9a-zA-Z được lấy từ dữ liệu ngẫu nhiên an toàn bằng mật mã.
caw

Câu trả lời:


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

Sẽ là dự đoán tốt nhất của tôi - Trừ khi bạn cũng đang tìm kiếm các ký tự đặc biệt:

$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];

Thí dụ

Và, đối với một cái dựa trên đồng hồ (ít va chạm hơn vì nó tăng dần):

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);
}

Lưu ý: tăng dần có nghĩa là dễ đoán hơn; Nếu bạn đang sử dụng nó như một muối hoặc một mã xác minh, thì không. Một muối (bây giờ) của "WCWyb" có nghĩa là 5 giây kể từ bây giờ là "WCWyg")


6
md5()Tuy nhiên, vấn đề với việc sử dụng là bạn nhận được một chuỗi gồm 16 ký tự (10 chữ số và ato f, tức là 4 bit cho mỗi ký tự chuỗi). Điều này có thể đủ cho một số mục đích nhưng có thể quá ít cho mục đích mật mã (năm ký tự trong số 16 ký hiệu = 16 ^ 5 = 20 bit = 1048576 khả năng).
Arc

3
array_rand($seed, 5)sẽ trả về khóa mảng chứ không phải giá trị, vì vậy mã của bạn sẽ không hoạt động
alumi

1
Tôi nghĩ rằng việc sử dụng hàm băm mật mã để tạo các ký tự ngẫu nhiên ít nhất là không phù hợp.
gronostaj,

Là nó có thể cũng bao gồm ", 'và dấu chéo ngược trong $charset? Tôi có cần sử dụng trình tự thoát để bao gồm các ký tự đó không?
Mai

1
Đoạn mã thứ hai thậm chí không sử dụng tham số $lenđầu vào ... bạn đã quên nó?
TechNyquist

76

Nếu forcác vòng lặp bị thiếu, đây là những gì tôi muốn sử dụng:

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

Giải pháp thú vị ... rất ngắn gọn, mặc dù tôi tự hỏi liệu điều này nhanh hơn hay chậm hơn so với sử dụng for. Mặc dù vậy, không thể bận tâm đến điểm chuẩn :-)
Arc

@matthew str_shuffle sẽ tạo ra các bản sao liên tục
SCC

@ user2826057: str_shuffle('ab')sẽ cho abhoặc banhưng không bao giờ aa. Thêm str_repeatphép cho điều đó. Nhưng điều đó nói lên rằng, giải pháp tôi đưa ra không thực sự là một giải pháp nghiêm túc ... mặc dù nó có hiệu quả.
Matthew

2
Có 1/60466176 khả năng điều đó xảy ra, giả sử RNG được phân phối đồng đều.
Matthew

1
Điều này là hoàn hảo cho trường hợp sử dụng của chúng tôi để tạo mã phiếu thưởng. Chúng tôi gỡ bỏ khó hiểu chars, như l, i, 1, 0, O, vv và trong số 500 phiếu đã không có bản sao.
họ Luke

25

Một cách nhanh chóng là sử dụng các ký tự dễ bay hơi nhất của uniqid hàm .

Ví dụ:

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


15

Điều sau sẽ cung cấp ít cơ hội trùng lặp nhất (bạn có thể muốn thay thế mt_rand()bằng một nguồn số ngẫu nhiên tốt hơn, ví dụ từ /dev/*randomhoặc từ các GUID):

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

CHỈNH SỬA:
Nếu bạn lo lắng về bảo mật, thực sự, không sử dụng rand()hoặc mt_rand()và xác minh rằng thiết bị dữ liệu ngẫu nhiên của bạn thực sự là một thiết bị tạo ra dữ liệu ngẫu nhiên , không phải là một tệp thông thường hoặc một cái gì đó có thể dự đoán được /dev/zero. mt_rand()bị coi là có hại:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

CHỈNH SỬA: Nếu bạn có hỗ trợ OpenSSL trong PHP, bạn có thể sử dụng 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];
?>

Ví dụ đầu tiên thông minh hơn với $ result. = $ Character [mt_rand (0, strlen ($ character) -1)]
hamboy75

Trong trường hợp đó, bạn nên xác định độ dài trước đó và lưu trữ nó trong một biến ít nhất. Sử dụng strlen()trong một vòng lặp là chi phí không cần thiết, đặc biệt nếu bạn đã biết rằng bộ ký tự sẽ không thay đổi trong thời gian chờ đợi.
Arc

Tôi nghi ngờ điều đó, php được tối ưu hóa, dù sao nó là một lựa chọn :)
hamboy75

7

Tôi luôn sử dụng cùng một chức năng cho việc này, thường là để tạo mật khẩu. Nó dễ sử dụng và hữu ích.

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;
}

Mã đẹp. Tuy nhiên, $ alt luôn thay đổi từ một đến 0. Sẽ tốt hơn nếu chọn ngẫu nhiên $ alt?
Nico Andrade,


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

Nếu bạn chỉ nhận được các chữ cái AF, thì đây là giải pháp của tôi:

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

Tôi tin rằng việc sử dụng các hàm băm là một việc quá mức cần thiết cho một nhiệm vụ đơn giản như tạo một chuỗi các chữ số thập lục phân ngẫu nhiên. dechex+ mt_randsẽ thực hiện công việc tương tự, nhưng không có công việc mật mã không cần thiết. str_padđảm bảo độ dài 5 ký tự của chuỗi đầu ra (nếu số ngẫu nhiên nhỏ hơn 0x10000).

Xác suất trùng lặp phụ thuộc vào mt_randđộ tin cậy của. Mersenne Twister được biết đến với tính ngẫu nhiên chất lượng cao, vì vậy nó sẽ phù hợp với nhiệm vụ.


2

Tôi cũng không biết làm thế nào để làm điều này cho đến khi tôi nghĩ đến việc sử dụng PHP array. Và tôi khá chắc rằng đây là cách đơn giản nhất để tạo một chuỗi hoặc số ngẫu nhiên với của mảng. Mật mã:

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;
};

Bạn có thể sử dụng chức năng này như thế này

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

Tương tự như câu trả lời của Brad Christie , nhưng sử dụng sha1alrorithm cho các ký tự 0-9a-zA-Zvà có tiền tố là một giá trị ngẫu nhiên:

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

Nhưng nếu bạn đã đặt một ký tự được xác định (được phép):

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

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

** CẬP NHẬT **

Như Archimedix đã chỉ ra, điều này sẽ không đảm bảo trả về "khả năng bị trùng lặp ít nhất" vì số lượng kết hợp thấp đối với phạm vi ký tự đã cho. Bạn sẽ cần phải tăng số lượng ký tự hoặc cho phép các ký tự phụ (đặc biệt) trong chuỗi. Tôi nghĩ rằng giải pháp đầu tiên sẽ phù hợp hơn trong trường hợp của bạn.


Việc sử dụng time()có khả năng dự đoán cao hơn tới 1 triệu lần microtime().
Arc

Cũng lưu ý nhận xét của tôi đối với câu trả lời của Brad, vấn đề lớn hơn là hàm băm được tạo là một biểu diễn thập lục phân bao gồm 16 ký tự hợp lệ, do đó chỉ để lại 1024 biến thể cho $str.
Arc

@Archimedix, có lẽ, nhưng OP không yêu cầu bảo mật, câu hỏi được xác định là có thuật toán tạo chuỗi bao gồm sự kết hợp của 5x26 ký tự khác nhau và tránh trùng lặp. Đây có lẽ là đối với một số tài liệu tham khảo xác nhận trong một quá trình đăng ký (hoặc quá trình thanh toán), hoặc một cái gì đó
Yanick Rochon

Tôi hiểu rằng anh ấy đã yêu cầu ít nhất khả năng bị trùng lặp , và xác suất này có 0,1% (1 trên 1024), có thể là gần 1 trên 1 tỷ.
Arc

tuy nhiên, nếu bạn cần tạo khóa tham chiếu gồm 5 ký tự và cung cấp cho bạn là khách hàng / khách hàng, bạn không muốn cung cấp cho họ " ˫§»⁋⅓" đơn giản vì nó an toàn hơn ... bạn tăng khóa tham chiếu của mình lên 7 ký tự trở lên . (BTW: sửa trong nhận xét trước đây của tôi, đó là 5x36 ký tự)
Yanick Rochon

1

hoạt động tốt trong PHP (php 5.4.4)

$seed = str_split('abcdefghijklmnopqrstuvwxyz');
$rand = array_rand($seed, 5);
$convert = array_map(function($n){
    global $seed;
    return $seed[$n];
},$rand);

$var = implode('',$convert);
echo $var;

Bản thử trực tiếp


1

Nguồn: Hàm PHP tạo ký tự ngẫu nhiên

Hàm PHP đơn giản này phù hợp với tôi:

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;

}

Sử dụng:

echo cvf_ps_generate_random_code(5);

1

Đây là 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()Hàm mới (*> = PHP 5.5) của PHP đang thực hiện công việc tạo ra một tập hợp dài các ký tự và số viết hoa và viết thường.

Hai cuộc giao tranh. các chuỗi trước và sau password_hashtrong hàm $ random thích hợp để thay đổi.

Các tham số cho $random()* ($ a, $ b) thực sự là substr()các tham số. :)

LƯU Ý: đây không cần phải là một hàm, nó cũng có thể là biến bình thường .. như một trình đơn khó chịu, như thế này:

$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;
}

Mẹo chuyên nghiệp - Bao gồm một số giải thích về cách câu trả lời của bạn giải quyết vấn đề của OP và tại sao nó có thể khác với các câu trả lời khác đã được cung cấp.
Tom

0

Tôi luôn luôn sử dụng cái này:

<?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;
} ?>

Khi bạn gọi nó, hãy đặt độ dài của chuỗi.

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

Bạn cũng có thể thay đổi các ký tự có thể có trong chuỗi $a.


Tôi thấy rằng đã mất thời gian để phát triển chức năng này. Tôi googled nhỏ! @ Andrew
LipESprY
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.