Saya ingin membuat 5 string karakter acak yang tepat dengan kemungkinan paling kecil untuk diduplikasi. Apa cara terbaik untuk melakukannya? Terima kasih.
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];
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")
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:
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 .
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):
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.
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.
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:
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.
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)
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;}
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:
Kiat pro - Sertakan beberapa penjelasan tentang bagaimana jawaban Anda memecahkan masalah OP, dan mengapa itu mungkin berbeda dengan jawaban lain yang sudah disediakan.
0-9a-zA-Z
?Random::alphanumericString($length)
Anda bisa mendapatkan string dengan 0-9a-zA-Z yang bersumber dari data acak yang aman secara kriptografis.Jawaban:
Akan menjadi tebakan terbaik saya - Kecuali Anda mencari karakter khusus juga:
Contoh
Dan, untuk satu berdasarkan jam (tabrakan lebih sedikit karena bertahap):
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")
sumber
md5()
bagaimanapun adalah bahwa Anda mendapatkan string yang terbuat dari set 16 karakter (10 digit dana
kef
, 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).array_rand($seed, 5)
akan mengembalikan kunci array, bukan nilai, jadi kode Anda tidak akan berfungsi"
,'
dan membuat garis miring terbalik$charset
? Apakah saya perlu menggunakan urutan escape untuk memasukkan karakter tersebut?$len
parameter masukan ... apakah Anda lupa?Jika
for
loop kekurangan pasokan, inilah yang ingin saya gunakan:sumber
str_shuffle('ab')
akan memberiab
atauba
tetapi tidak pernahaa
. Menambahkanstr_repeat
izin untuk itu. Namun demikian, solusi yang saya berikan tidak terlalu serius ... meskipun berhasil.l
,i
,1
,0
,O
, dll dan dari 500 voucher tidak punya duplikat.Cara cepat adalah dengan menggunakan karakter yang paling mudah menguap dari fungsi uniqid .
Sebagai contoh:
sumber
Anda bisa mencobanya seperti ini:
detail lebih lanjut: http://forum.arnlweb.com/viewtopic.php?f=7&t=25
sumber
Berikut ini adalah peluang duplikasi terkecil (Anda mungkin ingin mengganti
mt_rand()
dengan sumber nomor acak yang lebih baik misalnya dari/dev/*random
atau dari GUID):EDIT:
Jika Anda khawatir tentang keamanan, benar-benar, jangan tidak menggunakan
rand()
ataumt_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()
:sumber
strlen()
dalam loop tidak diperlukan, terutama jika Anda sudah mengetahui bahwa set karakter tidak akan berubah untuk sementara.Saya selalu menggunakan fungsi yang sama untuk ini, biasanya untuk menghasilkan kata sandi. Mudah digunakan dan berguna.
sumber
Sepertinya str_shuffle akan berguna untuk ini. Seed shuffle dengan karakter mana pun yang Anda inginkan.
sumber
sumber
Jika tidak apa-apa bahwa Anda hanya akan mendapatkan huruf AF, inilah solusi saya:
Saya percaya bahwa menggunakan fungsi hash adalah berlebihan untuk tugas sederhana seperti menghasilkan urutan digit heksadesimal acak.
dechex
+mt_rand
akan melakukan pekerjaan yang sama, tetapi tanpa pekerjaan kriptografi yang tidak perlu.str_pad
menjamin panjang 5 karakter dari string keluaran (jika nomor acak kurang dari 0x10000).Probabilitas duplikat tergantung pada
mt_rand
keandalannya. Mersenne Twister dikenal dengan keacakan berkualitas tinggi, jadi harus sesuai dengan tugas dengan baik.sumber
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:Anda dapat menggunakan fungsi ini seperti ini
sumber
Mirip dengan jawaban Brad Christie , tetapi menggunakan
sha1
alrorithm untuk karakter0-9a-zA-Z
dan diawali dengan nilai acak:Tetapi jika Anda telah menetapkan karakter yang ditentukan (diperbolehkan):
** 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.
sumber
time()
hingga 1 juta kali lebih mudah diprediksi daripadamicrotime()
.$str
.˫§»⁋⅓
" kepada mereka hanya karena lebih aman ... Anda menambah kunci referensi menjadi 7 karakter atau lebih . (BTW: koreksi dalam komentar saya sebelumnya, itu 5x36 karakter)berfungsi dengan baik di PHP (php 5.4.4)
Demo Langsung
sumber
Sumber: Fungsi PHP yang Menghasilkan Karakter Acak
Fungsi PHP sederhana ini bekerja untuk saya:
Pemakaian:
sumber
Ini saya
random 5 cents
...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_hash
dalam fungsi $ random cocok untuk diubah.Parameter untuk
$random()
* ($ a, $ b) sebenarnya adalahsubstr()
parameter. :)CATATAN: ini tidak perlu menjadi sebuah fungsi, ini bisa menjadi variabel normal juga .. sebagai satu singleliner yang buruk, seperti ini:
sumber
sumber
Saya sudah sering menggunakan ini:
Saat Anda menyebutnya, setel panjang string.
Anda juga dapat mengubah karakter yang mungkin dalam string
$a
.sumber