generate number

Links for php scripts

Moderators: macek, egami, gesf

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

generate number

Postby icu90ucme » Fri Jul 25, 2003 6:02 pm

I want to generate a random string of numbers and letters query it against my database to ensure it doesn't already exist and then input it in my table.... can this be done

Joel
New php-forum User
New php-forum User
Posts: 193
Joined: Sat Mar 29, 2003 11:57 pm
Location: Auckland, New Zealand
Contact:

Postby Joel » Fri Jul 25, 2003 9:29 pm

Oh yes it can.

This is a function I wrote to generate a random string.

Code: Select all

function RandomString($length=8)
{
   //Generate alphabet array
   $alphabet = "";
   for ($i = 0; $i < 26; $i++) {
      @$alphabet .= chr(97+$i).",";
   }
   
   $alphabet = explode(",", $alphabet);
   $RandomString = "";
   
   //Check that length is between 1 and 40
   if ($length > 40 || $length < 1) {
      $length = 8;
   }
   
   //Generate Random string
   for ($i = 1; $i <= $length; $i++) {
      $rand = rand(0, 25);
      $RandomString .= $alphabet[$rand];
   }
   
   return $RandomString;
}


Then to check that it doesn't already exist in the database.

Code: Select all

//Connect to database
//Select database

$sql = mysql_query("SELECT * FROM table WHERE field = '".RandomString()."'");
if (mysql_num_rows($sql) > 0) {
      echo "RandomString is already taken";
}
else {
      echo "Not taken";
}

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Fri Jul 25, 2003 11:08 pm

Joel wrote:

Code: Select all

function RandomString($length=8)
{
   //Generate alphabet array
   $alphabet = "";
   for ($i = 0; $i < 26; $i++) {
      @$alphabet .= chr(97+$i).",";
   }
   
   $alphabet = explode(",", $alphabet);
   $RandomString = "";
   
   //Check that length is between 1 and 40
   if ($length > 40 || $length < 1) {
      $length = 8;
   }
   
   //Generate Random string
   for ($i = 1; $i <= $length; $i++) {
      $rand = rand(0, 25);
      $RandomString .= $alphabet[$rand];
   }
   
   return $RandomString;
}


It seems to me you're doing quite a lot of extra work here, or at the very least, using two or three times as much memory as you need to. Also, the poster asked for a random string of letters and numbers, which I usually take as being [A-Z][a-z][0-9], though I'm sure this is up for interpretation. I came up with two ways to do this. The first works, but isn't very streamlined. The second is very streamlined, skipping all of the conditionals nonsense and using only one loop and the very useful (but rarely used, for some reason) curly braces string-access-by-character syntax.

Method 1:

Code: Select all

<?
function rand_string($length = 16) {
   $rand_string = '';
   $choice = 0;
   for($i = 0, $i < $length; $i++) {
      // pick lowercase, uppercase, or number
      $choice = rand(0,2);
      switch($choice) {
         case 0: // lowercase
            $num = rand(0, 25);
            $rand_string .= chr(97 + $num);
            break;
         case 1: // uppercase
            $num = rand(0, 25);
            $rand_string .= chr(65 + $num);
            break;
         case 2: // number
            $rand_string .= rand(0, 9);
            break;
      }
   }
   
   return $rand_string;
}
?>


Here's the second method, far simpler and likely faster:

Method 2:

Code: Select all

<?
   function rand_string($length = 16) {
      // list all valid characters (faster than generating them on-the-fly)
      $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' .
               'abcdefghijklmnopqrstuvwxyz' .
               '0123456789';
               
      $chars_len = strlen($chars);
     
      $rand_string = '';
     
      for($i = 0, $i < $length, $i++) {
         $rand_string .= $chars{rand(0, $chars_len - 1)};
      }
     
      return $rand_string;
   }
?>


This can very easily be pared down to just 8 lines, but why bother?

Both of the functions are used by calling rand_string() and optionally specifying a string length (which could be determined randomly, of course).

Joel
New php-forum User
New php-forum User
Posts: 193
Joined: Sat Mar 29, 2003 11:57 pm
Location: Auckland, New Zealand
Contact:

Postby Joel » Sat Jul 26, 2003 12:03 am

I have taken a liking to the second function there, the only painful part is the typing of all the letters, but hey, you've only got to do it once right.

You could even spice it up by the random length, and have the max length and min length adjustable. Or in other words, Swirlee, I love you.

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Sat Jul 26, 2003 12:32 pm

Joel wrote:Or in other words, Swirlee, I love you.


LOL. 8O

Actually, I found that just typing out all of the letters and numbers took less time than coding the for() loop. But I did discover one basic flaw: If you're anal about statistics and want a given character to have an equal probability of being a lowercase, uppercase, or numeral, my script won't work, simply because there are 16 more uppercase and lowercase letters than there are numerals (in other words, you have about a 42% chance of getting a lowercase, 42% chance of getting an uppercase, but only about a 16% chance of getting a numeral). The way to fix this, essentially, is to combine the two functions into a hybrid:

Code: Select all

<?
   function rand_string($length = 16) {
      // each set of characters is in a different array element
      $chars = array(
         'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // uppercase
         'abcdefghijklmnopqrstuvwxyz', // lowercase
         '0123456789' // numerals
      );
               
      $rand_string = '';

      for($i = 0, $i < $length, $i++) {
         // choose a set of characters at random
         $which_list = rand(0, count($chars));
         
         // choose a character (index) from that set
         $which_char = rand(0, strlen($chars[$which_list]));
         
         // append the character to $rand_string
         $rand_string .= $chars[$which_list]{$which_char};
      }
     
      return $rand_string;
   }
?>


Note that I'm not sure if the syntax on the append line -- $array[$string_index]{$char_index} -- will actually work, as I can't test it on this machine. You may have to copy the array element to a new string before using the access-by-character syntax.
Last edited by swirlee on Sat Jul 26, 2003 10:53 pm, edited 1 time in total.

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Sat Jul 26, 2003 4:54 pm

the functions both of you have written are great and i know the odds of getting a replica in the database are slim and none but if it does return back to me as already existing in the database, how do i make it keep regenerating until none is found so i may then insert that string.

thanks for all your help

Joel
New php-forum User
New php-forum User
Posts: 193
Joined: Sat Mar 29, 2003 11:57 pm
Location: Auckland, New Zealand
Contact:

Postby Joel » Sat Jul 26, 2003 5:04 pm

Code: Select all

do {
     $randomstring = RandomString();
     $sql = mysql_query("SELECT * FROM table WHERE field = '".$randomstring."'");
} while (mysql_num_rows($sql) > 0;

Although, I didn't really think that through, but it should work.

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Sun Jul 27, 2003 3:34 pm

i was just wondering what yall thought about this function. i tried using the other functions and i want it to return a 16 character string everytime but sometimes it comes back as 8 or 9 or 4 or 10, or 15, and so on

function randomstring()
{
$char = "abchefghjkmnpqrstuvwxyz0123456789";
srand((double)microtime()*1000000);
$i = 0;
while ($i <= 16) {
$num = rand() % 33;
$tmp = substr($char, $num, 1);
$string = $string . $tmp;
$i++;
}

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Sun Jul 27, 2003 4:21 pm

Was it your intention to have only 23 letters in your alphabet, two of which are "h"? Just curious.

Anyway, your code will work, but unless your RAND_MAX happens to be a multiple of strlen($char), you won't get an even distribution. This may or may not matter to you. I don't know what the default for RAND_MAX happens to be. It's far easier just to specify a min and max for the rand() function and will yield the same result. And it should be noted that if you're running a PHP version 4.2 or later, it's no longer necessary to seed the random number generator.

And as far as general coding (which I'm always compelled to pick on people about, sorry, it's my vice), using a for() instead of a while() loop will save you two lines of code, and most programmers prefer to use the concatenation operator ($a .= $b) instead of the method you employ ($a = $a . b).

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Sun Jul 27, 2003 9:29 pm

thankx. if i were to use your code how could i make it return 16 characters everytime..

if i'm not mistaken wouldn't the loop keep repeating until $length is reached which just happens to be 16 which would give me a string 16 characters long.

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Sun Jul 27, 2003 10:11 pm

Heh. I just got the chance to actually test my code for the first time, and I find that you've discovered a tiny bug -- occasionally (at random), it would skip a character because I forgot to subtract 1 from my count() (count() returns the number of elements, not the maximum index, of an array). Also, I was using commas instead of semicolons in my for() loop. Oops. Anyway, here's the fixed code:

Code: Select all

<?
   function rand_string($length = 16) {
      // each set of characters is in a different array element
      $chars = array(
         'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // uppercase
         'abcdefghijklmnopqrstuvwxyz', // lowercase
         '0123456789' // numerals
      );

      $rand_string = '';

      for($i = 0; $i < $length; $i++) {
         // choose a set of characters at random
         $which_list = rand(0, count($chars) - 1);

         // choose a character (index) from that set
         $which_char = rand(0, strlen($chars[$which_list]));

         // append the character to $rand_string
         $rand_string .= $chars[$which_list]{$which_char};
      }

      return $rand_string;
   }
?>


By the way, if you want only lowercases and numerals, just delete the uppercase array element. Likewise for the other elements.

Some charming strings generated by the function:
y16w5UGIlxlAK3ac, FvHSTJE7HZIlrAO, OU106U072aTklf2t, u87M3sDDC15WH0KZ, and sSDGfRijnyO8g37.
Last edited by swirlee on Mon Jul 28, 2003 6:14 am, edited 1 time in total.

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Sun Jul 27, 2003 10:28 pm

:) sorry to break your heart but it's still not 100% -- the second output of your code generated 15 characters. and once i tried it out it came all the way down to 13 on an occasion. It definetly hits 16 more often though if that makes you feel better. I can't find anything wrong with it though.

Joel
New php-forum User
New php-forum User
Posts: 193
Joined: Sat Mar 29, 2003 11:57 pm
Location: Auckland, New Zealand
Contact:

Postby Joel » Sun Jul 27, 2003 11:42 pm

I made the one adjustment, which Swirlee mentioned and printed the random string 2000 times and checking if any were not 16 characters. This is the function I used. (Swirlees)

Code: Select all

function rand_string($length = 16) {
// each set of characters is in a different array element
   $chars = array(
   'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // uppercase
   'abcdefghijklmnopqrstuvwxyz', // lowercase
   '0123456789' // numerals
   );
   
   $rand_string = '';
   
   for($i = 0; $i < $length; $i++) {
      // choose a set of characters at random
      $which_list = rand(0, count($chars) - 1);
      
      // choose a character (index) from that set
      $which_char = rand(0, strlen($chars[$which_list]) - 1);
      
      // append the character to $rand_string
      $rand_string .= $chars[$which_list]{($which_char)};
   }
   
   return $rand_string;
}

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Mon Jul 28, 2003 6:17 am

There you go, cleaning up after me again. Thanks -- that would've driven me crazy. I wonder why the extra parentheses are required on the append line.

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Mon Jul 28, 2003 7:35 am

after testing it again it still came up with a random length. but i changed it a little bit and again all it was were a few parenthesis.

Code: Select all

function rand_string($length = 16) {
// each set of characters is in a different array element
   $chars = array(
   'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // uppercase
   'abcdefghijklmnopqrstuvwxyz', // lowercase
   '0123456789' // numerals
   );
   
   $rand_string = '';
   
   for($i = 0; $i < $length; $i++) {
      // choose a set of characters at random
      $which_list = rand(0, count($chars) - 1);
       
      // choose a character (index) from that set
      $which_char = rand(0, strlen(($chars[$which_list])) - 1);
       
      // append the character to $rand_string
      $rand_string .= $chars[$which_list]{($which_char)};
   }
   
   return $rand_string;



i placed the parenthesis on the $which_car statement around the ($chars[$which_list]) --- now it's perfect :)

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Mon Jul 28, 2003 8:32 am

FYI, that's the same thing Joel did above. But I'm glad you're happy with it.

icu90ucme
New php-forum User
New php-forum User
Posts: 23
Joined: Mon Jul 07, 2003 2:29 pm

Postby icu90ucme » Mon Jul 28, 2003 10:09 am

if you look closely you'll see i added an extra set :)

User avatar
swirlee
Moderator
Moderator
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back
Contact:

Postby swirlee » Mon Aug 04, 2003 10:43 am

How this one thread has gotten so much attention boggles the mind.

Anyway, I just stumbled across the uniqid() function which generates a unique ID based on the time. It's not random -- it appears to just convert the time to base 16 -- but it works if you don't need something random. If you want something that at least looks a little more random, do md5(uniqid(''));


Return to “PHP Scripts”

Who is online

Users browsing this forum: No registered users and 0 guests

cron