สร้างสตริงอักขระ 5 ตัวแบบสุ่ม


102

ฉันต้องการสร้างสตริงอักขระแบบสุ่ม 5 ตัวที่มีโอกาสซ้ำกันน้อยที่สุด วิธีที่ดีที่สุดจะทำอย่างไร? ขอบคุณ.


2
คุณมีชุดอักขระเฉพาะหรือเฉพาะ0-9a-zA-Z?
Yanick Rochon

ความท้าทายในการเล่นกอล์ฟรหัสนี้สามารถพบได้: codegolf.stackexchange.com/questions/119226/…
Titus

การใช้Random::alphanumericString($length)คุณสามารถรับสตริงที่มี 0-9a-zA-Z ที่มาจากข้อมูลสุ่มที่ปลอดภัยด้วยการเข้ารหัส
caw

คำตอบ:


164
$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)
Arc

3
array_rand($seed, 5)จะส่งคืนคีย์อาร์เรย์ไม่ใช่ค่าดังนั้นรหัสของคุณจะไม่ทำงาน
alumi

1
ฉันคิดว่าการใช้ฟังก์ชันแฮชการเข้ารหัสเพื่อสร้างอักขระแบบสุ่มนั้นไม่เหมาะสมอย่างน้อยที่สุด
gronostaj

มันเป็นไปได้ยังรวม", 'และทับขวาใน$charset? ฉันจำเป็นต้องใช้ลำดับการหลีกเพื่อรวมอักขระเหล่านั้นหรือไม่
เชียงใหม่

1
ตัวอย่างที่สองไม่ได้ใช้$lenพารามิเตอร์อินพุตด้วยซ้ำ... คุณลืมมันไปหรือเปล่า?
TechNyquist

79

หากforลูปขาดตลาดนี่คือสิ่งที่ฉันชอบใช้:

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

วิธีแก้ปัญหาที่น่าสนใจ ... กระชับมากแม้ว่าฉันจะสงสัยว่าจะเร็วหรือช้ากว่าการใช้สำหรับ ไม่ต้องกังวลกับเกณฑ์มาตรฐานแม้ว่า :-)
Arc

@matthew str_shuffle จะผลิตรายการซ้ำอย่างต่อเนื่อง
SCC

@ user2826057: str_shuffle('ab')จะให้abหรือแต่ไม่เคยba aaการเพิ่มการstr_repeatอนุญาตสำหรับสิ่งนั้น แต่ที่กล่าวว่าวิธีแก้ปัญหาที่ฉันให้นั้นไม่ได้ร้ายแรงจริงๆ ... แม้ว่ามันจะได้ผล
Matthew

2
มีโอกาส 1/60466176 ที่จะเกิดขึ้นโดยสมมติว่า RNG มีการกระจายอย่างสม่ำเสมอ
Matthew

1
เหมาะสำหรับกรณีการใช้งานของเราในการสร้างรหัสบัตรกำนัล เราได้นำความสับสนตัวอักษรเช่นl, i, 1, 0, Oฯลฯ และจาก 500 คูปองได้ไม่ซ้ำกัน
Luke Cousins



15

สิ่งต่อไปนี้ควรให้โอกาสในการทำซ้ำน้อยที่สุด (คุณอาจต้องการแทนที่mt_rand()ด้วยแหล่งที่มาของตัวเลขสุ่มที่ดีกว่าเช่นจาก/dev/*randomหรือจาก GUID):

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

แก้ไข:
หากคุณมีความกังวลเกี่ยวกับความปลอดภัยจริงๆไม่ได้ใช้rand()หรือmt_rand()และตรวจสอบว่าอุปกรณ์ข้อมูลแบบสุ่มของคุณเป็นจริงอุปกรณ์สร้างแบบสุ่ม/dev/zeroข้อมูลที่ไม่ได้เป็นแฟ้มปกติหรือสิ่งที่คาดเดาได้เช่น mt_rand()ถือว่าเป็นอันตราย:
https://spideroak.com/blog/20121205114003-exploit-information-leaks-in-random-numbers-from-python-ruby-and-php

แก้ไข: หากคุณรองรับ 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];
?>

ตัวอย่างแรกฉลาดกว่าด้วย $ result. = $ characters [mt_rand (0, strlen ($ characters) -1)]
hamboy75

ในกรณีนี้คุณควรกำหนดความยาวไว้ล่วงหน้าและเก็บไว้ในตัวแปรเป็นอย่างน้อย การใช้strlen()แบบวนซ้ำเป็นค่าใช้จ่ายที่ไม่จำเป็นโดยเฉพาะอย่างยิ่งถ้าคุณรู้อยู่แล้วว่าชุดอักขระจะไม่เปลี่ยนแปลงในระหว่างนี้
Arc

ฉันสงสัยว่า php ได้รับการปรับให้เหมาะสมอย่างไรก็ตามมันเป็นตัวเลือก :)
hamboy75

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 แทนจะดีกว่าไหม
Nico Andrade

6

ดูเหมือนว่าstr_shuffleจะเป็นประโยชน์สำหรับสิ่งนี้ เริ่มต้นการสุ่มด้วยอักขระใดก็ได้ที่คุณต้องการ

$my_rand_strng = substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), -5);



2

หากเป็นไปได้ว่าคุณจะได้รับเฉพาะ AF ตัวอักษรนี่คือวิธีแก้ปัญหาของฉัน:

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

ฉันเชื่อว่าการใช้ฟังก์ชันแฮชเป็นการใช้งานมากเกินไปสำหรับงานง่ายๆเช่นการสร้างลำดับเลขฐานสิบหกแบบสุ่ม dechex+ mt_randจะทำงานเดียวกัน แต่ไม่มีงานเข้ารหัสที่ไม่จำเป็น str_padรับประกันความยาว 5 อักขระของสตริงเอาต์พุต (หากตัวเลขสุ่มน้อยกว่า 0x10000)

ความน่าจะเป็นที่ซ้ำกันขึ้นอยู่กับmt_randความน่าเชื่อถือของ Mersenne Twister ขึ้นชื่อเรื่องการสุ่มคุณภาพสูงดังนั้นจึงควรเข้ากับงานได้ดี


2

ฉันยังไม่ทราบวิธีการทำเช่นนี้จนผมคิดว่าการใช้ PHP array's และฉันค่อนข้างมั่นใจว่านี่เป็นวิธีที่ง่ายที่สุดในการสร้างสตริงหรือตัวเลขสุ่มด้วยอาร์เรย์ รหัส:

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

คล้ายกับBrad Christieคำตอบของแต่ใช้sha1alrorithm สำหรับอักขระ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)];
}

** อัพเดท **

ตามที่Archimedixชี้ให้เห็นสิ่งนี้จะไม่รับประกันว่าจะส่งคืน "ความเป็นไปได้น้อยที่สุดในการทำซ้ำ" เนื่องจากจำนวนชุดค่าผสมต่ำสำหรับช่วงอักขระที่กำหนด คุณจะต้องเพิ่มจำนวนอักขระหรืออนุญาตให้มีอักขระพิเศษ (พิเศษ) ในสตริง ทางออกแรกน่าจะดีกว่าในกรณีของคุณ


ใช้time()เป็นถึง 1 microtime()ล้านครั้งคาดการณ์มากขึ้นกว่า
Arc

นอกจากนี้ยังทราบความคิดเห็นของฉันที่จะตอบของแบรดปัญหาที่ใหญ่กว่าคือว่ากัญชาสร้างเป็นตัวแทนเลขฐานสิบหกประกอบด้วย 16 ตัวอักษรที่ถูกต้องจึงเหลือเพียง 1,024 $strรูปแบบสำหรับ
Arc

@Archimedix บางที แต่ OP ไม่ได้ขอความปลอดภัยคำถามถูกกำหนดให้มีอัลกอริทึมการสร้างสตริงซึ่งประกอบด้วยอักขระที่แตกต่างกัน 5x26 รวมกันและหลีกเลี่ยงการซ้ำกัน นี่อาจเป็นหมายเลขอ้างอิงยืนยันในกระบวนการลงทะเบียน (หรือขั้นตอนการเรียกเก็บเงิน) หรืออะไรบางอย่าง
Yanick Rochon

มันเป็นความเข้าใจของฉันว่าเขาไม่ขอความเป็นไปได้น้อยที่สุดของการทำซ้ำและมีความน่าจะเป็น 0.1% (1 ใน 1024) ซึ่งจะได้รับเกือบ 1 ใน 1 พันล้าน
Arc

อย่างไรก็ตามหากคุณต้องการสร้างคีย์อ้างอิง 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));

ใหม่ของ PHP password_hash()ฟังก์ชัน (*> = PHP 5.5) ของ PHP กำลังทำงานในการสร้างชุดอักขระตัวพิมพ์ใหญ่และตัวพิมพ์เล็กและตัวเลขที่ยาวพอสมควร

สองข้อต่อ สตริงก่อนและหลังpassword_hashภายในฟังก์ชันสุ่ม $ เหมาะสำหรับการเปลี่ยนแปลง

พารามิเตอร์สำหรับ$random()* ($ a, $ b) เป็นsubstr()พารามิเตอร์จริงๆ :)

หมายเหตุ:สิ่งนี้ไม่จำเป็นต้องเป็นฟังก์ชัน แต่ก็สามารถเป็นตัวแปรปกติได้เช่นกัน .. เป็น singleliner ที่น่ารังเกียจเช่นนี้:

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

เคล็ดลับสำหรับมืออาชีพ - รวมคำอธิบายบางส่วนเกี่ยวกับวิธีที่คำตอบของคุณแก้ปัญหาของ OP และสาเหตุที่อาจแตกต่างจากคำตอบอื่น ๆ ที่ให้ไว้แล้ว
ทอม

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นอกจากนี้คุณยังสามารถเปลี่ยนตัวละครที่เป็นไปได้ในสตริง


ฉันเห็นว่าเวลาที่เสียไปนั้นไม่ได้ตั้งใจพัฒนาฟังก์ชันนี้ ฉัน googled น้อย! @Andrew
LipESprY
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.