为什么str_shuffle总是生成类似的模式?

I am trying to generate 1500 authentication code using the following code:

    <?php
include "../include/top.php";

set_time_limit(0);
ini_set("memory_limit", "-1");

$end=0;
while ($end<1500)
{
//generate an authentication code
$string="ABCDEFGHJKLMNPQRSTUVWXYZ123456789";
$string= substr(str_shuffle($string),5,8) ;

//check whether generated code already exist
$query = "select count(*) from auth where code = '$string' ";
$stmt = prepare ($query);
execute($stmt);
$bind = mysqli_stmt_bind_result($stmt, $count);
check_bind_result($bind);
mysqli_stmt_fetch($stmt);
mysqli_stmt_free_result($stmt);

//If generated code does not already exist, insert it to Database table
if ($count == 0)
    {
    echo $string."<br>";
    $query = "insert into auth (Code) values ('$string')";
    $stmt = prepare ($query);
    execute($stmt);
    $end++;
    }
}
?>

It generated and inserted 1024 codes in database and printed 667 codes in browser within 15 seconds and the browser continue loading without inserting/printing further codes, until I close the browser window after half an hour. After that when opening any web page in browser from the WAMP, It shows like the browser is loading and does not show the content. That is, I need to restart the WAMP after running this script before opening any web pages. I have tried this many times.

Why the script does not generate 1500 codes and always stop when it reach the count 667/1024?

UPDATE

As an experiment, I have added an ELSE clause to the IF condition and wrote the code to print "Code Already Exist" in ELSE clause. And ran the script with an empty(truncated) copy of the same table , then it print and inserted 1024 codes and after that, it print "Code Already Exist" continuously (Around 700 000+ entries within 5 minutes and continuing). And again when running the script with table having only 1024 rows, It doesn't print or insert even a single code. Instead it infinitely continuing print "Code Already Exist". Another thing I observed that the very first 1024 iteration of the WHILE loop passes the IF condition(if the table is empty). And all the subsequent iteration failed the IF condition.

You have to fine-tune some variables in your php.ini configuration file, find those:

; Maximum execution time of each script, in seconds
; http://php.net/max-execution-time
; Note: This directive is hardcoded to 0 for the CLI SAPI
max_execution_time = 600    

And, not mandatory, you can change those also:

suhosin.post.max_vars = 5000   
suhosin.request.max_vars = 5000

After modification, restart your web server.

I dont think that randomiser in str_shuffle is up to this.

If I run it once I get 1024 unique codes and then it just generates duplicates. If I then restart it, it will generate another 976 unique codes giving a total of 2000 codes on the database.

I therefore assume that the randomiser used by str_shuffle() needs a reset to accomplish the generation of the required 1500 unique codes.

Try this minor modification, it will at least stop the execution after 15000 failed attempts at generating a unique code.

Basically I think you have to come up with a much better randomisation mehanism.

<?php
include "../include/top.php";

set_time_limit(0);
ini_set("memory_limit", "-1");

$end=0;
$dups=0;
while ($end<1500 && $dups < 15000)
{
    //generate an authentication code
    $string="ABCDEFGHJKLMNPQRSTUVWXYZ123456789";
    $string= substr(str_shuffle($string),5,8) ;

    //check whether generated code already exist
    $query = "select count(*) from auth where code = '$string' ";
    $stmt = prepare ($query);
    execute($stmt);
    $bind = mysqli_stmt_bind_result($stmt, $count);
    check_bind_result($bind);
    mysqli_stmt_fetch($stmt);
    mysqli_stmt_free_result($stmt);

    //If generated code does not already exist, insert it to Database table
    if ($count == 0) {
        echo $string."<br>";
        $query = "insert into auth (Code) values ('$string')";
        $stmt = prepare ($query);
        execute($stmt);
        $end++;
    } else {
        $dups++
        echo "DUPLICATE for $string, Dup Count = $dups<br>";
    }
}
?>

Why you need to restart = you set php timeout so it never times out.

I don't see any specific coding errors. The use of the str_shuffle for creating a authentication code is peculiar because it will prevent duplicated letters, making a much smaller possible range of values. So it may just be repeating the patterns.

Try something like this instead, so that you are shuffling the shuffled string:

$origstring= str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ123456789");

while ($end<1500 && $dups < 15000)
{
   $origstring = str_shuffle( $origstring);
   $string = substr( $newstring, 5, 8);

Or, use something like this to generate the string so that you can have duplicates, creating a much larger range of possible values:

   $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
   for ($i = 0; $i < 8; $i++)
   {
      $code .= $characters[mt_rand(0, 35)];
   }