PHP กำเนิดสตริงแบบสุ่ม


814

ฉันกำลังพยายามสร้างสตริงแบบสุ่มใน PHP และฉันก็ไม่ได้รับผลลัพธ์ใด ๆ จากสิ่งนี้:

<?php
    function RandomString()
    {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $randstring = '';
        for ($i = 0; $i < 10; $i++) {
            $randstring = $characters[rand(0, strlen($characters))];
        }
        return $randstring;
    }

    RandomString();
    echo $randstring;

ผมทำอะไรผิดหรือเปล่า?


241
โซลูชันบรรทัดเดียวของฉันสำหรับสร้างสตริงสั้นคือ substr (md5 (rand ()), 0, 7); ขอให้โชคดี ...
tasmaniski

5
@tasmaniski .. วิธีการแก้ปัญหาของคุณเป็นไร .. แต่มันสุ่มน้อยกว่า! ในตัวอย่างของคุณจำนวนสตริงแบบสุ่มที่สามารถสร้างได้ถูก จำกัด ด้วยขนาดของจำนวนเต็ม (2 ^ 32) ที่สูงสุด .. ในกรณีของการแก้ปัญหาอื่น ๆ คุณสามารถสร้าง (62 ^ 8) .. ในกรณีที่ฉันต้องการสตริงที่มีขนาดใหญ่กว่าจำนวนสตริงที่แตกต่างกันอยู่ที่สูงสุด 2 ^ 32 แต่ใน โซลูชันอื่นจะเพิ่มเป็น (62 ^ n) ..
Manu

9
คุณลืมที่จะเพิ่มตัวละครใหม่ที่สร้างขึ้นในสตริง คุณแค่เขียนทับมันตามที่เป็นอยู่ ควรเป็น $ randstring. = $ ตัวอักษร ..
สป็อค

3
@CaptainLightning คุณช่วยสลับคำตอบที่ยอมรับให้กับคำตอบที่ปลอดภัยกว่านี้ได้ไหม? :)
Scott Arciszewski

2
strlen($characters)=> strlen($characters) - 1- ความยาวสตริงเริ่มต้นด้วย 1
Zippp

คำตอบ:


1393

ในการตอบคำถามนี้โดยเฉพาะมีสองปัญหา:

  1. $randstring ไม่ได้อยู่ในขอบเขตเมื่อคุณสะท้อน
  2. อักขระไม่ได้ถูกต่อกันเข้าด้วยกันในลูป

นี่คือข้อมูลโค้ดที่มีการแก้ไข:

function generateRandomString($length = 10) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    return $randomString;
}

ส่งออกสตริงสุ่มด้วยการโทรด้านล่าง:

// Echo the random string.
// Optionally, you can give it a desired string length.
echo generateRandomString();

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


34
@ FranciscoPresencia มันจะดีกว่า "การสูญเสีย" ตัวแปรพิเศษที่เรียกวิธีการในเงื่อนไขการเปรียบเทียบของวง
Rico Sonntag

200
ทุกอย่างทำงานทำไมไม่เพียงแค่มีอะไรบางอย่างsubstr(str_shuffle(MD5(microtime())), 0, 10);?
SpYk3HH

4
ขอบคุณสำหรับรหัส แต่การเปลี่ยนแปลงโปรดไปrand() mt_rand()ผมใช้วิธีการของคุณและประสบการณ์ตันของการชนที่มีชื่อ
เนท

5
@FranciscoPresencia คุณมีความคิดใด ๆ วิธีที่ไม่มีประสิทธิภาพที่น่ากลัวนั่นคืออะไร? คุณกำลังตรวจสอบความยาวของสตริงสองครั้งต่อการวนซ้ำ! strlen ภายในลูปควรถูกแคชในตัวแปรก่อนเข้าสู่ลูป
developerbmw

4
นี่ไม่ใช่ทางออกที่ดี สตริงที่สร้างนี้จะสามารถคาดเดาได้ :(
Scott Arciszewski

370

หมายเหตุ: str_shuffle()ใช้ภายในrand()ซึ่งไม่เหมาะสมสำหรับวัตถุประสงค์การเข้ารหัส (เช่นการสร้างรหัสผ่านแบบสุ่ม) คุณต้องการตัวสร้างตัวเลขสุ่มที่ปลอดภัยแทน นอกจากนี้ยังไม่อนุญาตให้ใช้อักขระซ้ำ

อีกวิธีหนึ่ง

อัพเดท (ตอนนี้สิ่งนี้จะสร้างความยาวของสตริง):

function generateRandomString($length = 10) {
    return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}

echo  generateRandomString();  // OR: generateRandomString(24)

แค่นั้นแหละ. :)


64
+1 สำหรับคำตอบที่สั้นที่สุด :) แต่ไม่ใช่คำตอบที่ดีที่สุดสำหรับการใช้งานทุกกรณี รหัสนี้จะเอาท์พุทสตริงที่ตัวละครแต่ละตัวจะไม่ปรากฏมากกว่าหนึ่งครั้ง (ทำให้อ่อนแอลงสำหรับการโจมตีแบบเดรัจฉานบังคับ) และจะไม่ส่งออกใด ๆ นานกว่า 62 ตัวอักษร
David

17
อย่าทำเช่นนี้มันอ่อนแออย่างยิ่ง ยิ่งคุณสร้างสตริงสุ่มของคุณนานเท่าไหร่ก็ยิ่งอ่อนแอลงเท่านั้น
Abhi Beckert

23
อาจจะอ่อนแอ แต่ก็ง่ายและรวดเร็ว ขึ้นอยู่กับการใช้งานกรณีนี้ใช้ได้ - ฉันใช้เพราะฉันไม่ต้องการความปลอดภัยหรือความแข็งแกร่ง เพียงแค่สับเปลี่ยนอย่างรวดเร็ว ฉันกำลังเขียนการทดสอบหน่วยและสิ่งนี้ให้การป้อนข้อมูลแบบสุ่มที่เหมาะสมในการทดสอบด้วย
SDC

23
@FranciscoPresencia เหตุผลที่ไม่ปลอดภัยคือเพราะไม่เคยใช้ตัวอักษรเดียวกันสองครั้ง มันทำให้เครื่องกำเนิดรหัสผ่านแย่มาก ได้โปรดให้ทุกคนหยุดการลงคะแนนในเรื่องนี้ซึ่งจะไม่ปลอดภัยอย่างเด็ดขาด เมื่อรหัสผ่านยาวขึ้นจำนวนตัวอักษรที่คุณต้องทดสอบด้วยแรงเดรัจฉานจะสั้นลงเนื่องจากคุณไม่ต้องทดสอบตัวอักษรที่เคยใช้ก่อนหน้านี้
Abhi Beckert

8
@FranciscoPresencia: ฉันสนับสนุนความคิดเห็นของคุณเกี่ยวกับการหลีกเลี่ยงการใช้รหัสผ่านแบบสุ่ม อย่างไรก็ตามฉันไม่เห็นด้วยว่าคำตอบนี้ไม่ควรเป็นแบบบวก ฉันมีหนึ่งในตัวเลือกนี้เพราะมันเป็นโซลูชั่นบรรทัดเดียวที่มีประสิทธิภาพสำหรับการสร้างสตริงแบบสุ่ม (หัวข้อเดิมของคำถามนี้)
bwright

331

มีคำตอบมากมายสำหรับคำถามนี้ แต่ไม่มีคำตอบใดที่สร้างCryptographically Secure Pseudo-Random Number Generator (CSPRNG)

คำตอบที่ง่ายปลอดภัยและถูกต้องคือใช้RandomLibและไม่ต้องพลิกโฉมพวงมาลัย

สำหรับบรรดาของคุณที่ยืนยันในการคิดค้นวิธีการแก้ปัญหาของคุณเอง PHP 7.0.0 จะจัดให้มีrandom_int()เพื่อวัตถุประสงค์นี้ หากคุณยังใช้ PHP 5.x อยู่เราเขียนPHP 5 polyfill ไว้random_int()ให้คุณสามารถใช้ API ใหม่ก่อนที่คุณจะอัปเกรดเป็น PHP 7

การสร้างจำนวนเต็มแบบสุ่มอย่างปลอดภัยใน PHPไม่ใช่เรื่องง่าย คุณควรตรวจสอบกับผู้เชี่ยวชาญด้านการเข้ารหัส StackExchange ถิ่นที่อยู่ของคุณก่อนที่จะปรับใช้อัลกอริทึมที่ปลูกเองในการผลิต

ด้วยเครื่องกำเนิดจำนวนเต็มที่ปลอดภัยในสถานที่สร้างสตริงแบบสุ่มด้วย CSPRNG คือการเดินเล่นในสวนสาธารณะ

การสร้างสตริงที่ปลอดภัยและสุ่ม

/**
 * Generate a random string, using a cryptographically secure 
 * pseudorandom number generator (random_int)
 *
 * This function uses type hints now (PHP 7+ only), but it was originally
 * written for PHP 5 as well.
 * 
 * For PHP 7, random_int is a PHP core function
 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
 * 
 * @param int $length      How many characters do we want?
 * @param string $keyspace A string of all possible characters
 *                         to select from
 * @return string
 */
function random_str(
    int $length = 64,
    string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
): string {
    if ($length < 1) {
        throw new \RangeException("Length must be a positive integer");
    }
    $pieces = [];
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pieces []= $keyspace[random_int(0, $max)];
    }
    return implode('', $pieces);
}

การใช้งาน :

$a = random_str(32);
$b = random_str(8, 'abcdefghijklmnopqrstuvwxyz');
$c = random_str();

การสาธิต : https://3v4l.org/IMJGF (ละเว้นความล้มเหลวของ PHP 5 จำเป็นต้องใช้ random_compat)


3
ที่จุดเริ่มต้นของฟังก์ชั่นเพิ่ม$keyspace = str_shuffle($keyspace );ความปลอดภัยมากขึ้น
Jevgenij Dmitrijev

13
"เพื่อความปลอดภัยมากขึ้น" คุณหมายถึงอะไร เรากำลังใช้ตัวสร้างตัวเลขสุ่มที่ปลอดภัยแล้ว
Scott Arciszewski

5
@JGEstiot การสร้างสตริงแบบสุ่มที่ปลอดภัยต้องใช้การสุ่มแบบปลอดภัยแบบเข้ารหัส ใครบางคนกำลังค้นหา "วิธีสร้างสตริงแบบสุ่มใน PHP" จะได้รับบริการที่ดีกว่าโดยคำตอบที่ปลอดภัยกว่าคำตอบที่ไม่ปลอดภัย
Scott Arciszewski

1
@ Scott Arciszewski คุณไม่จำเป็นต้องสร้างสตริงแบบสุ่มเข้ารหัสทุกครั้งที่คุณสร้างสตริงแบบสุ่ม คำถามคือเกี่ยวกับการสร้างสตริงแบบสุ่มและสิ่งนี้ไม่เกี่ยวข้องกับความปลอดภัย คุณคิดว่าสตริงนั้นจะถูกใช้ในบริบทที่ไวต่อความปลอดภัยและคุณเพิ่มเลเยอร์ของความซับซ้อนที่แยกออกจากแกนหลักของคำถาม
JG Estiot

45
ใช้random_int()แทนrand()หรือmt_rand()เพิ่มความซับซ้อนให้กับนักพัฒนา ในขณะเดียวกันก็ให้ความปลอดภัยมากขึ้น ผู้ที่มาที่ StackOverflow กำลังมองหาวิธีแก้ไขปัญหาอย่างรวดเร็วอาจไม่ทราบว่าสิ่งที่พวกเขากำลังสร้างนั้นต้องปลอดภัยหรือไม่ หากเราให้คำตอบที่ปลอดภัยโดยค่าเริ่มต้นพวกเขาจะสร้างอินเทอร์เน็ตที่ปลอดภัยยิ่งขึ้นแม้ว่าจากมุมมองของพวกเขาแล้วมันเป็นอุบัติเหตุโดยสิ้นเชิง ทำไมคุณถึงต่อต้านเป้าหมายนี้เป็นปริศนาสำหรับฉัน
Scott Arciszewski

156

สิ่งนี้จะสร้างสตริงเลขฐานสิบหกแบบยาว 20 ตัว:

$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars

ใน PHP 7 ( random_bytes () ):

$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f

โปรดทราบopenssl_random_pseudo_bytes()ว่าไม่ได้ใช้อัลกอริทึมที่แข็งแกร่งของการเข้ารหัสจนถึง php 5.6 ข้อผิดพลาดที่เกี่ยวข้อง: bugs.php.net/bug.php?id=70014
acidtv

โปรดทราบด้วยว่าสตริงที่เล็กที่สุดที่สามารถทำได้คือความยาว 2 หากคุณผ่านความยาวไบต์ที่ 1 หรือน้อยกว่าไปopenssl_random_pseudo_bytes()คุณจะไม่ได้อะไรเลย นอกจากนี้โปรดทราบว่าเมื่อใช้bin2hex(openssl_random_pseudo_bytes($length / 2))ตั้งแต่คุณทำงานกับจำนวนเต็มมันจะลบโมดูโลออกโดยอัตโนมัติและจะใช้พหุคูณที่ต่ำที่สุดถัดไปของ 2 ดังนั้น$length = 19จะสร้างสตริงที่มีความยาว 18
นาธาน F.

ข้อเสนอที่จะใช้เป็นเนื้อหาไฟล์ที่สามารถเปิดได้fgets($fp, 1024)และตัวแก้ไขไฟล์ทุกไฟล์ที่มีปัญหากับบรรทัดที่ยาวมาก: function string_rand($len, $split="\n") { return substr(chunk_split(bin2hex(openssl_random_pseudo_bytes(ceil($len / 2))), 1023, $split), 0, $len); }ตั้ง$splitเป็นnullหากควรส่งคืนหนึ่งบรรทัด โดยที่คุณสามารถใช้มันสำหรับทั้งสองกรณี
mgutt

ฉันชอบโซลูชัน random_bytes สำหรับ PHP 7 แต่ถ้าคุณต้องการสตริงที่จะเป็นจำนวนอักขระบางตัวสิ่งนี้จะเป็นอย่างไร $string = substr(base64_encode(random_bytes($size)), 0, $size);
โปรแกรม

นี่เป็นทางออกที่ดีที่สุดอย่างไม่ต้องสงสัย ใช้พื้นที่น้อยมากและเข้าใจง่ายสุด ๆ
Matthew Campbell

92

@tasmaniski: คำตอบของคุณใช้ได้กับฉัน ฉันมีปัญหาเดียวกันและฉันอยากจะแนะนำสำหรับผู้ที่กำลังมองหาคำตอบเดียวกัน นี่คือจาก @tasmaniski:

<?php 
    $random = substr(md5(mt_rand()), 0, 7);
    echo $random;
?>

นี่คือวิดีโอ youtube แสดงวิธีสร้างหมายเลขสุ่ม


6
ถ้าสตริงของคุณอิงเฉพาะจำนวนเต็มแบบสุ่มทำไมไม่ใช้แค่จำนวนเต็มแบบสุ่ม? พวกเขาฟางไม่ได้ลึกมากขึ้นโดยการสับมัน ... และโดยการตัดแฮชของคุณจริง ๆ แล้วทำลายเอนโทรปีเล็กน้อยที่คุณต้องเริ่มต้นด้วย
Surrican

4
โปรดทราบว่าmd5จะส่งผลให้มีจำนวนอักขระสูงสุด 30 ตัวและจะเป็นตัวพิมพ์เล็กเสมอ
fyrye

3
นอกจากนี้ไม่ควรใช้ rand () สำหรับการเข้ารหัส หากคุณกำลังมองหาที่จะสร้างเสียงสตริง crypographically ใช้openssl_random_pseudo_bytes
mattkgross

md5(rand())เสนอค่าที่เป็นไปได้ 2 ^ 32 เท่านั้น ซึ่งหมายความว่าโดยเฉลี่ยแล้ว 2 ^ 16 สตริงสุ่มคุณจะคาดหวังว่าจะทำซ้ำ
Scott Arciszewski

2
อืม.. ฉันจะพนันได้ว่า OP ไม่ได้พูดถึง "สตริงสุ่มที่ปลอดภัย" โซลูชันนี้มีขนาดกะทัดรัดง่ายและน่าจดจำสำหรับกรณีการใช้งานที่ถูกต้อง และถ้าคุณต้องการดูแลการชนที่อาจเกิดขึ้นทำไมไม่เติม / ต่อท้ายเวลาลงในสตริงแบบสุ่ม? :)
Erenor Paz

46

ขึ้นอยู่กับแอปพลิเคชันของคุณ (ฉันต้องการสร้างรหัสผ่าน) คุณสามารถใช้

$string = base64_encode(openssl_random_pseudo_bytes(30));

เป็น base64 พวกมันอาจมี=หรือ-รวมถึงตัวละครที่ขอ คุณสามารถสร้างสตริงที่ยาวกว่าได้จากนั้นกรองและตัดแต่งเพื่อลบสตริงเหล่านั้น

openssl_random_pseudo_bytesน่าจะเป็นวิธีที่แนะนำในการสร้างตัวเลขสุ่มที่เหมาะสมใน php ทำไมrandไม่ใช้/dev/randomฉันไม่รู้


2
แรนด์ไม่ได้ใช้ / dev / urandom เพราะมีเฉพาะใน posix เช่นสภาพแวดล้อมและไม่สามารถพกพาได้
MacroMan

3
@MacroMan แต่openssl_random_pseudo_bytes() เป็นแบบพกพา
Ja͢ck

หากคุณต้องการตัด base64 อักขระเพิ่มเติมลองทำดังนี้: gist.github.com/zyphlar/7217f566fc83a9633959
willbradley

3
ไม่ผิด แต่ฉันจะแนะนำอย่างระมัดระวังในวิธีที่คุณทิ้งตัวละครที่ไม่ต้องการ ดูคำขอดึงนี้บน PHP ลีก OAuth2 เซิร์ฟเวอร์ตัวอย่างเช่น
Scott Arciszewski

นี่คือหนึ่งในคำตอบที่ดีที่สุด น่าเสียดายที่มันไม่มีการสนับสนุนเพิ่มเติม ฉันขอแนะนำให้แก้ไขคำตอบของคุณเพื่อให้จัดการกับตัวละครที่ไม่พึงประสงค์ได้ดีขึ้น
jcuenod

28

นี่คือหนึ่งซับง่ายๆที่สร้างสตริงแบบสุ่มที่แท้จริงโดยไม่มีการวนลูประดับสคริปต์หรือใช้ไลบรารี OpenSSL

echo substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', mt_rand(1,10))), 1, 10);

ที่จะทำลายมันลงเพื่อให้พารามิเตอร์มีความชัดเจน

// Character List to Pick from
$chrList = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

// Minimum/Maximum times to repeat character List to seed from
$chrRepeatMin = 1; // Minimum times to repeat the seed string
$chrRepeatMax = 10; // Maximum times to repeat the seed string

// Length of Random String returned
$chrRandomLength = 10;

// The ONE LINE random command with the above variables.
echo substr(str_shuffle(str_repeat($chrList, mt_rand($chrRepeatMin,$chrRepeatMax))), 1, $chrRandomLength);

วิธีนี้ใช้ได้โดยการสุ่มรายชื่อตัวละครซ้ำจากนั้นจะสับสตริงที่รวมกันแล้วส่งกลับจำนวนอักขระที่ระบุ

คุณสามารถสุ่มเพิ่มเติมโดยสุ่มความยาวของสตริงที่ส่งคืนแทนที่$chrRandomLengthด้วยmt_rand(8, 15)(สำหรับสตริงสุ่มระหว่าง 8 และ 15 ตัวอักษร)


ขออภัยที่จะพูด แต่เมื่อ gots ตัวหนึ่งเลือกความน่าจะเป็นที่จะเกิดขึ้นอีกครั้งจะไม่สูงเท่ากับตัวละครอื่นที่ยังคงอยู่ในกลุ่ม ไม่มีการสุ่มจริงที่นี่ ...
Surrican

@TheSurrican - คุณจะไม่ถูกต้องในคำสั่งนั้น ตัวละครทุกตัวมีความน่าจะเป็นที่เท่าเทียมกันในการใช้อัลกอริทึมนี้และจึงเป็นการสุ่มอย่างแท้จริง สิ่งนี้จะทำให้มั่นใจได้โดยการทำซ้ำสตริง chrList $ chrRepeatMax และเวทมนตร์จะเกิดขึ้นใน str_shuffle ซึ่งกำหนดแบบสุ่ม
Kraang Prime

ตัวอักษรทั้งหมดจะปรากฏเพียงครั้งเดียวและมีแนวโน้มที่จะคาดเดาได้
ยาก

@venimus นั่นไม่ถูกต้อง อักขระถ่านมีการทำซ้ำสำหรับอักขระมากเท่าที่คุณต้องการ (ดู$chrRepeatMaxและ$chrRepeatMin) - ดังนั้นอักขระถ่าน 10 ตัวสามารถ (ไม่น่าเป็นไปได้ แต่เป็นไปได้) เป็น "aaaaaaaaaa"
Kraang Prime

@SanuelJackson ขออภัยฉันพลาดการแสดงความคิดเห็น ฉันใส่ความคิดเห็นในคำตอบที่ผิด คุณพูดถูก! ฉันใช้ "เคล็ดลับ" ของคุณจริง ๆ แต่ไม่ได้ใช้ mt_rand เพราะมันไม่มีประโยชน์กับ IMHO มันไม่ได้เพิ่มเข้าไปในเอนโทรปี เพิ่งใช้ const กับความยาวสูงสุด
venimus

25
function generateRandomString($length = 15)
{
    return substr(sha1(rand()), 0, $length);
}

Tada!


โปรดทราบว่าsha1จะส่งผลให้มีความยาวไม่เกิน 40 อักขระและเป็นตัวพิมพ์เล็กเสมอ
fyrye

3
สตริง sha1 ไม่ได้สุ่มอักขระบางตัวจะเกิดขึ้นบ่อยครั้งกว่าตัวอื่น ๆ มันจะไม่ฉลาดที่จะใช้สิ่งนี้ในกรณีที่คุณต้องการสุ่มตัวอย่างเช่นสำหรับรหัสผ่าน
Kit Sunde

1
@KitSunde - ใช่ sha ไม่ใช่แบบสุ่ม rand () เป็นแบบสุ่ม และชาก็เป็นสิ่งที่ดีที่สุดสำหรับสิ่งที่ต้องการที่นี่ OP ไม่จำเป็นต้องมีระดับการเข้ารหัสแบบสุ่ม
Davor

@ รสrant()การสุ่มไม่สำคัญว่าเมื่อไหร่ที่ชาไม่ได้รับการกระจายอย่างเท่าเทียมกัน หากคุณสุ่มเลือกจากการแจกแจงที่ไม่สม่ำเสมอคุณจะได้รับการแจกแจงแบบไม่สม่ำเสมอที่แน่นอน มันไม่ได้เป็น "ระดับการเข้ารหัสลับ" สุ่มผมเน้นว่าเป็นกรณีที่คุณไม่ควรจะใช้rand()อย่างใดอย่างหนึ่ง ใช้ความพยายามน้อยที่สุดในการถอนออกจากการแจกแจงแบบสม่ำเสมอเช่นเดียวกับในคำตอบที่ยอมรับและเป็นแบบสุ่มเช่นเดียวกับแรนด์ () ซึ่งสมเหตุสมผลมาก
Kit Sunde

@KitSunde - มันทำให้ไม่แตกต่างกันอย่างแท้จริงในที่สุด นั่นคือคำจำกัดความของการครอบงำและการชุบทอง
Davor

24

วิธีที่ดีกว่าในการใช้ฟังก์ชั่นนี้คือ:

function RandomString($length) {
    $keys = array_merge(range(0,9), range('a', 'z'));

    $key = "";
    for($i=0; $i < $length; $i++) {
        $key .= $keys[mt_rand(0, count($keys) - 1)];
    }
    return $key;
}

echo RandomString(20);

mt_randเป็นแบบสุ่มมากขึ้นตามนี้และนี้ใน PHP 7. ฟังก์ชั่นเป็นนามแฝงของrandmt_rand


1
ข้อควรระวัง: mt_randไม่สร้างค่าความปลอดภัยแบบเข้ารหัส สำหรับสิ่งที่คุณควรใช้ PHP7 เป็นหรือrandom_int random_bytes
jchook

18

$randstringในขอบเขตของฟังก์ชั่นไม่เหมือนกับขอบเขตที่คุณเรียกใช้ คุณต้องกำหนดค่าส่งคืนให้กับตัวแปร

$randstring = RandomString();
echo $randstring;

หรือเพียงแค่สะท้อนผลตอบแทนโดยตรง:

echo RandomString();

นอกจากนี้ในการทำงานของคุณคุณมีข้อผิดพลาดเล็กน้อย ภายใน for for loop คุณต้องใช้.=เพื่อให้ตัวละครแต่ละตัวต่อท้ายสตริง โดยการใช้งาน=คุณกำลังเขียนทับมันด้วยตัวละครใหม่แต่ละตัวแทนการต่อท้าย

$randstring .= $characters[rand(0, strlen($characters))];

14

ก่อนอื่นคุณต้องกำหนดตัวอักษรที่คุณต้องการใช้:

$alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$special  = '~!@#$%^&*(){}[],./?';
$alphabet = $alphanum . $special;

จากนั้นใช้openssl_random_pseudo_bytes()เพื่อสร้างข้อมูลสุ่มที่เหมาะสม:

$len = 12; // length of password
$random = openssl_random_pseudo_bytes($len);

สุดท้ายคุณใช้ข้อมูลสุ่มนี้เพื่อสร้างรหัสผ่าน เนื่องจากอักขระแต่ละตัว$randomสามารถอยู่ได้chr(0)จนถึงchr(255)รหัสจึงใช้ส่วนที่เหลือหลังจากการหารค่าตามลำดับด้วย$alphabet_lengthเพื่อให้แน่ใจว่ามีการเลือกเฉพาะอักขระจากตัวอักษร (โปรดทราบว่าการทำแบบอคติเป็นการสุ่ม):

$alphabet_length = strlen($alphabet);
$password = '';
for ($i = 0; $i < $len; ++$i) {
    $password .= $alphabet[ord($random[$i]) % $alphabet_length];
}

อีกวิธีหนึ่งและโดยทั่วไปดีกว่าคือใช้RandomLibและSecurityLib :

use SecurityLib\Strength;

$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new Strength(Strength::MEDIUM));

$password = $generator->generateString(12, $alphabet);

การใช้ตัวดำเนินการแบบโมดูโล%จะสร้างผลลัพธ์แบบเอนเอียง อย่างไรก็ตาม +1 ที่แข็งแกร่งสำหรับ RandomLib อย่าประดิษฐ์ล้อใหม่
Scott Arciszewski

1
ใช่ฟังก์ชั่น random_int () ใหม่นั้นดี: D
Ja͢ck

11

วิธีการสั้น ..

ต่อไปนี้เป็นวิธีที่สั้นที่สุดในการสร้างสตริงแบบสุ่ม

<?php
echo $my_rand_strng = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), -15); 

echo substr(md5(rand()), 0, 7);

echo str_shuffle(MD5(microtime()));
?>

10

ฉันได้ทดสอบประสิทธิภาพของฟังก์ชั่นยอดนิยมที่นั่นเวลาที่จำเป็นสำหรับการสร้าง 1'000'000 สายอักขระ 32 สัญลักษณ์ในกล่องของฉันคือ:

2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);

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

substr () รอบ MD5 ถูกเพิ่มเพื่อความถูกต้องถ้าคุณต้องการสายอักขระที่สั้นกว่า 32 สัญลักษณ์

เพื่อประโยชน์ในการตอบ: สตริงไม่ถูกต่อกัน แต่ถูกเขียนทับและผลลัพธ์ของฟังก์ชันไม่ถูกเก็บไว้


ฉันคิดว่าคำตอบที่ดีที่สุด ขอบคุณ!
NSukonny

10

PHP 7+สร้างไบต์สุ่มแบบเข้ารหัสที่ปลอดภัยโดยใช้ฟังก์ชันrandom_bytes

$bytes = random_bytes(16);
echo bin2hex($bytes);

ผลลัพธ์ที่เป็นไปได้

da821217e61e33ed4b2dd96f8439056c


PHP 5.3+สร้างไบต์สุ่มโดยใช้ฟังก์ชันopenssl_random_pseudo_bytes

$bytes = openssl_random_pseudo_bytes(16);
echo bin2hex($bytes);

ผลลัพธ์ที่เป็นไปได้

e2d1254506fbb6cd842cd640333214ad


กรณีการใช้งานที่ดีที่สุดอาจจะเป็น

function getRandomBytes($length = 16)
{
    if (function_exists('random_bytes')) {
        $bytes = random_bytes($length / 2);
    } else {
        $bytes = openssl_random_pseudo_bytes($length / 2);
    }
    return bin2hex($bytes);
}
echo getRandomBytes();

ผลลัพธ์ที่เป็นไปได้

ba8cc342bdf91143


สิ่งนี้จะไม่สร้างสตริงที่มีความยาวที่กำหนด
Timberman

@ Timberman มันจะสร้างความยาวที่แน่นอนในขณะนี้
Madan Sapkota

9

วิธีหนึ่งที่รวดเร็วมากคือการทำสิ่งที่ชอบ:

substr(md5(rand()),0,10);

สิ่งนี้จะสร้างสตริงแบบสุ่มที่มีความยาว 10 ตัวอักษร แน่นอนว่าบางคนอาจบอกว่ามันหนักกว่านิดหน่อยในด้านการคำนวณ แต่ทุกวันนี้โปรเซสเซอร์ได้รับการปรับให้เหมาะกับการรันอัลกอริทึม md5 หรือ sha256 อย่างรวดเร็ว และแน่นอนถ้าrand()ฟังก์ชันส่งคืนค่าเดียวกันผลลัพธ์จะเหมือนกันโดยมีโอกาส 1/32767 ในการเป็นแบบเดียวกัน หากความปลอดภัยเป็นปัญหาคุณควรเปลี่ยนrand()เป็นmt_rand()


7
function rndStr($len = 64) {
     $randomData = file_get_contents('/dev/urandom', false, null, 0, $len) . uniqid(mt_rand(), true);
     $str = substr(str_replace(array('/','=','+'),'', base64_encode($randomData)),0,$len);
    return $str;
}

4
นี่ไม่ใช่พกพา; หากคุณพยายามเรียกใช้สิ่งนี้ในสภาพแวดล้อมที่ไม่ใช่ posix จะทำให้เกิดข้อผิดพลาดร้ายแรง
Bryan Agee


6

ฟังก์ชั่นตัวช่วยจากเฟรมเวิร์ก Laravel 5

/**
 * Generate a "random" alpha-numeric string.
 *
 * Should not be considered sufficient for cryptography, etc.
 *
 * @param  int  $length
 * @return string
 */
function str_random($length = 16)
{
    $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}

4
"ไม่ควรถือว่าเพียงพอสำหรับการเข้ารหัส ฯลฯ " ควรเน้นอย่างยิ่งนี้
Scott Arciszewski


4

รุ่นที่แก้ไขของฟังก์ชั่นทำงานได้ดี แต่มีเพียงปัญหาเดียวที่ฉันพบ: คุณใช้อักขระที่ไม่ถูกต้องเพื่อใส่ $ อักขระดังนั้นบางครั้งอักขระ 'จึงเป็นส่วนหนึ่งของสตริงสุ่มที่สร้างขึ้น

ในการแก้ไขปัญหานี้ให้เปลี่ยน:

$characters = 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;

ถึง:

$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

วิธีนี้ใช้เฉพาะอักขระที่ล้อมรอบและอักขระ 'จะไม่เป็นส่วนหนึ่งของสตริงแบบสุ่มที่สร้างขึ้น


4

อีกหนึ่งซับซึ่งสร้างสตริงสุ่ม 10 ตัวอักษรด้วยตัวอักษรและตัวเลข มันจะสร้างอาร์เรย์ด้วยrange(ปรับพารามิเตอร์ที่สองเพื่อกำหนดขนาด) วนรอบอาร์เรย์นี้และกำหนดอักขระ ASCII แบบสุ่ม (ช่วง 0-9 หรือ az) จากนั้นฝังอาร์เรย์เพื่อรับสตริง

$str = implode('', array_map(function () { return chr(rand(0, 1) ? rand(48, 57) : rand(97, 122)); }, range(0, 9)));

หมายเหตุ: ใช้งานได้ใน PHP 5.3 และใหม่กว่าเท่านั้น


ในที่สุดการแก้ปัญหาแบบสุ่มอย่างแท้จริงไม่แฮชป่องของจำนวนเต็ม 32 บิตสุ่มหรือสตริงสับ ...
The Surrican

มีเพียงปัญหาเดียว: ตัวเลขมีแนวโน้มที่จะเกิดขึ้นเป็นตัวละครซึ่งไม่สุ่มเท่าที่ฉันชอบที่จะมี anyaway +1 สำหรับทางออกที่ดีที่สุดในหน้านี้ ปรับแต่งที่สมบูรณ์แบบ
Surrican

บิด ... แบบนี้? rand(0, 57-48+122-97)<57-48?...:...? :)
vp_arth

4

หนึ่งในสายการบิน.

มันเร็วสำหรับสตริงขนาดใหญ่ที่มีเอกลักษณ์บางอย่าง

function random_string($length){
    return substr(str_repeat(md5(rand()), ceil($length/32)), 0, $length);
}

md5(rand())เป็นวิธีที่ไม่ปลอดภัยอย่างน่ากลัวในการสร้างตัวเลขสุ่ม
Scott Arciszewski

1
สตริงที่มีความยาว X และเอกลักษณ์บางอย่างเป็นเจตนา การสุ่มตัวอย่างที่แท้จริงไม่ใช่เจตนา
Jacob Smith


3

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

function rndStr($len = 20) {
    $rnd='';
    for($i=0;$i<$len;$i++) {
        do {
            $byte = openssl_random_pseudo_bytes(1);
            $asc = chr(base_convert(substr(bin2hex($byte),0,2),16,10));
        } while(!ctype_alnum($asc));
        $rnd .= $asc;
    }
    return $rnd;
}


3

นี่คือโซลูชันบรรทัดเดียวที่เรียบง่ายของฉันในการสร้างรหัสผ่านแบบสุ่มที่ใช้งานง่ายยกเว้นตัวละครที่มีลักษณะคล้ายกันเช่น "1" และ "l", "O" และ "0" ฯลฯ ... ที่นี่คือ 5 ตัวอักษร แต่คุณสามารถ เปลี่ยนแน่นอน:

$user_password = substr(str_shuffle('abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789'),0,5);

นี่คือที่สมบูรณ์แบบในการสร้างสตริง ID สุ่มที่จะโทรหา jquery ในภายหลัง IDK ถ้าเป็นการฝึกฝนที่ดี แต่สิ่งนี้ช่วยฉันได้มากโดยไม่ใช้คำตอบที่ยอมรับเช่นเดียวกับ ...
Rodrigo Zuluaga

3

นี่คือทางออกอื่น

function genRandomString($length = 10)
{
    if($length < 1)
        $length = 1;
    return substr(preg_replace("/[^A-Za-z0-9]/", '', base64_encode(openssl_random_pseudo_bytes($length * 2))), 0, $length);
}

PS ฉันใช้ PHP 7.2 บน Ubuntu


2

อีกวิธีในการสร้างสตริงแบบสุ่มในPHPคือ:

function RandomString($length) {
    $original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z'));
    $original_string = implode("", $original_string);
    return substr(str_shuffle($original_string), 0, $length);
}
echo RandomString(6);

2

นี่คือวิธีที่ฉันทำเพื่อรับคีย์สุ่มที่ไม่ซ้ำกันจริง:

$Length = 10;
$RandomString = substr(str_shuffle(md5(time())), 0, $Length);
echo $RandomString;

คุณสามารถใช้ time () เนื่องจากเป็นเวลา Unix และจะไม่ซ้ำกันเสมอเมื่อเทียบกับการสุ่มอื่น ๆ ที่กล่าวถึงข้างต้น จากนั้นคุณสามารถสร้าง md5sum จากนั้นและใช้ความยาวที่ต้องการที่คุณต้องการจากMD5 ที่สร้างขึ้นสตริงในกรณีนี้ฉันใช้อักขระ 10 ตัวและฉันสามารถใช้สตริงที่ยาวกว่านี้ได้ถ้าฉันต้องการทำให้มันมีความพิเศษมากขึ้น

ฉันหวังว่านี่จะช่วยได้.


2
แน่นอนtime()อยู่ไกลจากที่ไม่ซ้ำกัน: มันจะคืนค่าเดิมอีกครั้งและอีกครั้งจนกว่าจะสิ้นสุดที่สองในปัจจุบัน สิ่งที่ให้สุ่มตัวอย่างที่นี่คือstr_shuffle()- รหัสที่เหลือจะลดตัวอย่างเพื่อเลือกตัวอักษรเท่านั้น
ÁlvaroGonzález

1
ดังนั้นสิ่งที่คุณทำอยู่โดยทั่วไปคือสับรอบจำนวนเต็ม 32 บิต เอนโทรปีไม่มากที่นี่ ...
The Surrican

2
ผู้โจมตีสามารถเดาค่าที่ส่งคืนโดยtime()(เป็นเพียงการประทับเวลา) มันเป็นแหล่งที่มาของการสุ่ม
อัล

2

Parametrised หนึ่งซับใช้ฟังก์ชั่นพื้นเมือง PHPเท่านั้นทำงานตั้งแต่PHP 5.1.0

str_shuffle(implode('', (array_intersect_key(($map =  array_map('chr', array_merge(array_map('mt_rand', array_fill(0, $length = 25, 48), array_fill(0,$length,57)),array_map('mt_rand', array_fill(0, $length, 65), array_fill(0,$length,90)),array_map('mt_rand', array_fill(0, $length, 97), array_fill(0,$length,122))))), array_flip($keys = array_rand($map, $length))))))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.