odd_duck
odd_duck

Reputation: 4111

Generate a different random string in my for loop

I have the following function to generate a random string:

public function generateString(){
    function generateCharacter () {
        $possible = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
        return $char;
    }
    function generateNumber () {
        $GUID = generateCharacter().generateCharacter().generateCharacter().generateCharacter().generateCharacter().generateCharacter().generateCharacter().generateCharacter().generateCharacter();
        return $GUID;
    }
    $string = generateNumber();
    return $string;
}

I then need to be able to generate these random strings x amount of times using a for loop and insert them into my MySQL table:

$how_many is where i would select how many times i want to loop.

for ($i = 1; $i <= $how_many; $i++) {

        $random = $this->generateString();

        $query_params = array( 
            ':code' => $random,
        );
        $query = " 
            INSERT INTO table
            ( 
                code
            ) 
            VALUES 
            ( 
                :code
            )
        ";
        try { 
            $stmt = DB::get()->prepare($query); 
            $stmt->execute($query_params); 
        }  
        catch(PDOException $ex) {} 

    }

The above gives me an error though of:

Fatal error: Cannot redeclare generateCharacter() (previously declared in....

I know i cannot have the function in the for loop otherwise i get this error but if i have it outside the loop it just generates the string once and inserts the same string everytime.

How can i get it so each insert in my loop is a new random string?

Upvotes: 2

Views: 2289

Answers (3)

Alex Shesterov
Alex Shesterov

Reputation: 27525

I'll try to explain what happens briefly, so I'll use terms which may be not fully correct from the technical point of view.

In your code, two inner functions generateCharacter and generateNumber are defined in the body of the outer function generateString.

Initially, only the outer function (generateString) is "available" for the rest of your code.

When the outer function gets called, it "defines" the two inner functions, and these become available in the global scope. I.e. the inner functions are not really private - they are exported into the global, not even class scope!

When you call the outer function generateString more than once, the inner functions are getting "defined" more than once - as if you would define them more than once manually in the global scope. This is not allowed in PHP, since the error.


Possible fixes:

  • Move inner functions into the global scope (they are exported there on the first call anyway). This it the worst way to go.

  • Make generateCharacter and generateNumber simple private methods.

  • Use PHP's uniqid as suggested in the other answer.


Here a simplified scenario, to see what happens:

class Test {
  public function aaa() {
    function bbb() {
      echo("bbb");
    }
    echo "aaa";
    bbb();
  }
}

// bbb(); // would produce fatal error: undefined function bbb()
$test = new Test();
$test->aaa(); // outputs "aaabbb"
bbb(); // ok here, outputs "bbb"

Upvotes: 0

Rajeev Ranjan
Rajeev Ranjan

Reputation: 4142

you can try it better :-

function generateString()
 {
  $number = base64_encode(openssl_random_pseudo_bytes(20, $strong));
  $newstr = preg_replace('/[^a-zA-Z0-9\']/', '', $number);
  return substr($newstr,0,10); return string of 10 random character 
 }
 ///same code after this
  for ($i = 1; $i <= $how_many; $i++) 
   {
    $random = $this->generateString();
    $query_params = array( 
        ':code' => $random,
    );
    $query = " 
        INSERT INTO table
        ( 
            code
        ) 
        VALUES 
        ( 
            :code
        )
    ";
    try { 
        $stmt = DB::get()->prepare($query); 
        $stmt->execute($query_params); 
    }  
    catch(PDOException $ex) {} 

}

Upvotes: 1

Robert
Robert

Reputation: 20286

Don't write functions that are already written.

PHP has function for it called uniqid()

From manual

uniqid() Gets a prefixed unique identifier based on the current time in microseconds.

The value returned by uniqid() will be 13 characters long. If more_entropy is TRUE, it will be 23 characters.

To get random number you can use rand() function.

In your code you prepare same statement multiple times in loop. This is very bad habbit. Prepare statement before loop then only execute and bind parameters in loop. It is more effecive.

Upvotes: 3

Related Questions