Hasilkan string 5 karakter acak

102

Saya ingin membuat 5 string karakter acak yang tepat dengan kemungkinan paling kecil untuk diduplikasi. Apa cara terbaik untuk melakukannya? Terima kasih.

Peter
sumber
2
apakah Anda memiliki sekumpulan karakter tertentu atau hanya 0-9a-zA-Z?
Yanick Rochon
Tantangan kode golf ini dapat ditemukan: codegolf.stackexchange.com/questions/119226/…
Titus
Menggunakan, Random::alphanumericString($length)Anda bisa mendapatkan string dengan 0-9a-zA-Z yang bersumber dari data acak yang aman secara kriptografis.
gak

Jawaban:

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

Akan menjadi tebakan terbaik saya - Kecuali Anda mencari karakter khusus juga:

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

Contoh

Dan, untuk satu berdasarkan jam (tabrakan lebih sedikit karena bertahap):

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

Catatan: incremental berarti lebih mudah ditebak; Jika Anda menggunakan ini sebagai garam atau token verifikasi, jangan. Salt (sekarang) dari "WCWyb" berarti 5 detik dari sekarang menjadi "WCWyg")

Brad Christie
sumber
6
Masalah dengan menggunakan md5()bagaimanapun adalah bahwa Anda mendapatkan string yang terbuat dari set 16 karakter (10 digit dan ake f, yaitu 4 bit per karakter string). Ini mungkin cukup untuk beberapa tujuan tetapi mungkin terlalu sedikit untuk tujuan kriptografik (lima karakter dari 16 simbol = 16 ^ 5 = 20 bit = 1048576 kemungkinan).
Arc
3
array_rand($seed, 5)akan mengembalikan kunci array, bukan nilai, jadi kode Anda tidak akan berfungsi
alumi
1
Menurut saya, menggunakan fungsi hash kriptografi untuk menghasilkan karakter acak setidaknya tidak tepat.
gronostaj
Apakah mungkin juga untuk memasukkan ", 'dan membuat garis miring terbalik $charset? Apakah saya perlu menggunakan urutan escape untuk memasukkan karakter tersebut?
Mai
1
Potongan kedua bahkan tidak menggunakan $lenparameter masukan ... apakah Anda lupa?
TechNyquist
76

Jika forloop kekurangan pasokan, inilah yang ingin saya gunakan:

$s = substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", 5)), 0, 5);
Matthew
sumber
Solusi menarik ... sangat ringkas, meskipun saya bertanya-tanya apakah ini lebih cepat atau lebih lambat daripada menggunakan for. Tidak dapat diganggu untuk melakukan benchmark :-)
Arc
@matthew str_shuffle akan menghasilkan duplikat secara terus menerus
SCC
@ user2826057: str_shuffle('ab')akan memberi abatau batetapi tidak pernah aa. Menambahkan str_repeatizin untuk itu. Namun demikian, solusi yang saya berikan tidak terlalu serius ... meskipun berhasil.
Matius
2
Ada kemungkinan 1/60466176 hal itu terjadi, dengan asumsi RNG didistribusikan secara seragam.
Matius
1
Ini sempurna untuk kasus penggunaan kami dalam menghasilkan kode voucher. Kami dihapus membingungkan chars, seperti l, i, 1, 0, O, dll dan dari 500 voucher tidak punya duplikat.
Luke Cousins
25

Cara cepat adalah dengan menggunakan karakter yang paling mudah menguap dari fungsi uniqid .

Sebagai contoh:

$rand = substr(uniqid('', true), -5);
John Parker
sumber
22

Anda bisa mencobanya seperti ini:

$length = 5;

$randomletter = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, $length);

detail lebih lanjut: http://forum.arnlweb.com/viewtopic.php?f=7&t=25

Apurba Pathak
sumber
15

Berikut ini adalah peluang duplikasi terkecil (Anda mungkin ingin mengganti mt_rand()dengan sumber nomor acak yang lebih baik misalnya dari /dev/*randomatau dari GUID):

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

EDIT:
Jika Anda khawatir tentang keamanan, benar-benar, jangan tidak menggunakan rand()atau mt_rand(), dan memverifikasi bahwa perangkat data acak Anda sebenarnya adalah sebuah perangkat menghasilkan acak data, bukan file biasa atau sesuatu yang diprediksi seperti /dev/zero. mt_rand()dianggap berbahaya:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

EDIT: Jika Anda memiliki dukungan OpenSSL di PHP, Anda dapat menggunakan 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];
?>
Busur
sumber
Contoh pertama lebih pintar dengan hasil $. = $ Karakter [mt_rand (0, strlen ($ karakter) -1)]
hamboy75
Dalam hal ini, Anda harus menentukan panjangnya terlebih dahulu dan setidaknya menyimpannya dalam variabel. Menggunakan strlen()dalam loop tidak diperlukan, terutama jika Anda sudah mengetahui bahwa set karakter tidak akan berubah untuk sementara.
Arc
Saya ragu, php dioptimalkan, bagaimanapun itu adalah pilihan :)
hamboy75
7

Saya selalu menggunakan fungsi yang sama untuk ini, biasanya untuk menghasilkan kata sandi. Mudah digunakan dan berguna.

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;
}
Kristoffer la Cour
sumber
Kode yang bagus. Namun $ alt selalu membalik dari satu ke 0. Bukankah lebih baik untuk mengacak $ 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
edrian
sumber
2

Jika tidak apa-apa bahwa Anda hanya akan mendapatkan huruf AF, inilah solusi saya:

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

Saya percaya bahwa menggunakan fungsi hash adalah berlebihan untuk tugas sederhana seperti menghasilkan urutan digit heksadesimal acak. dechex+ mt_randakan melakukan pekerjaan yang sama, tetapi tanpa pekerjaan kriptografi yang tidak perlu. str_padmenjamin panjang 5 karakter dari string keluaran (jika nomor acak kurang dari 0x10000).

Probabilitas duplikat tergantung pada mt_randkeandalannya. Mersenne Twister dikenal dengan keacakan berkualitas tinggi, jadi harus sesuai dengan tugas dengan baik.

gronostaj.dll
sumber
2

Saya juga tidak tahu bagaimana melakukan ini sampai saya berpikir untuk menggunakan PHP array. Dan saya cukup yakin ini adalah cara paling sederhana untuk menghasilkan string atau angka acak dengan array. Kode:

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

Anda dapat menggunakan fungsi ini seperti ini

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

sumber
1

Mirip dengan jawaban Brad Christie , tetapi menggunakan sha1alrorithm untuk karakter 0-9a-zA-Zdan diawali dengan nilai acak:

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

Tetapi jika Anda telah menetapkan karakter yang ditentukan (diperbolehkan):

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

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

** PERBARUI **

Seperti yang ditunjukkan Archimedix , ini tidak akan menjamin untuk mengembalikan "kemungkinan paling kecil untuk diduplikasi" karena jumlah kombinasi rendah untuk rentang karakter tertentu. Anda harus menambah jumlah karakter, atau mengizinkan karakter ekstra (khusus) dalam string. Solusi pertama akan lebih disukai, saya pikir, dalam kasus Anda.

Yanick Rochon
sumber
Penggunaan time()hingga 1 juta kali lebih mudah diprediksi daripada microtime().
Arc
Perhatikan juga komentar saya untuk jawaban Brad, masalah yang lebih besar adalah hash yang dihasilkan adalah representasi heksadesimal yang terdiri dari 16 karakter yang valid, oleh karena itu hanya menyisakan 1024 variasi $str.
Arc
@Archimedix, mungkin, tetapi OP tidak meminta keamanan, pertanyaannya didefinisikan memiliki algoritma penghasil string yang terdiri dari kombinasi 5x26 karakter berbeda, dan menghindari duplikat. Ini mungkin untuk nomor referensi konfirmasi dalam proses pendaftaran (atau proses penagihan), atau sesuatu
Yanick Rochon
Itu pemahaman saya bahwa ia memang meminta setidaknya kemungkinan mendapatkan diduplikasi , dan ini memiliki 0,1% probabilitas (1 di 1024) yang bisa saja hampir 1 dalam 1 miliar.
Arc
namun, jika Anda perlu membuat kunci referensi yang terdiri dari 5 karakter dan memberi Anda klien / pelanggan, Anda tidak ingin memberikan " ˫§»⁋⅓" kepada mereka hanya karena lebih aman ... Anda menambah kunci referensi menjadi 7 karakter atau lebih . (BTW: koreksi dalam komentar saya sebelumnya, itu 5x36 karakter)
Yanick Rochon
1

berfungsi dengan baik di 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;

Demo Langsung

Lyoniel Farase
sumber
1

Sumber: Fungsi PHP yang Menghasilkan Karakter Acak

Fungsi PHP sederhana ini bekerja untuk saya:

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;

}

Pemakaian:

echo cvf_ps_generate_random_code(5);
Carl
sumber
1

Ini saya 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()Fungsi PHP baru (*> = PHP 5.5) melakukan pekerjaan untuk menghasilkan kumpulan karakter huruf besar dan huruf kecil dan angka yang cukup panjang.

Dua concat. string sebelum dan sesudah password_hashdalam fungsi $ random cocok untuk diubah.

Parameter untuk $random()* ($ a, $ b) sebenarnya adalah substr()parameter. :)

CATATAN: ini tidak perlu menjadi sebuah fungsi, ini bisa menjadi variabel normal juga .. sebagai satu singleliner yang buruk, seperti ini:

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

echo($random);
Menyeramkan
sumber
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;
}
John F.
sumber
Kiat pro - Sertakan beberapa penjelasan tentang bagaimana jawaban Anda memecahkan masalah OP, dan mengapa itu mungkin berbeda dengan jawaban lain yang sudah disediakan.
Tom
0

Saya sudah sering menggunakan ini:

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

Saat Anda menyebutnya, setel panjang string.

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

Anda juga dapat mengubah karakter yang mungkin dalam string $a.

LipESprY
sumber
Saya melihat waktu yang hilang itu dengan malas mengembangkan fungsi ini. Saya mencari di Google sedikit! @ Andrew
LipESprY