views:

2723

answers:

7

I'm looking to create a reusable function that will generate a random key with printable ACSII characters of choosen length (anywhere from 2 to 1000+). I'm thinking printable ASCII characters would be 33-126. They key does not need to completely unique, just unique if generated at the exact same millisecond (so uniqid() won't work).

I'm thinking a combination of chr() and mt_rand() might work...

Is this or is something else the best method?

Edit: uniqid() will also not work because it doesn't have a length parameter, it's just whatever PHP gives you.

My Idea: This is what I came up with:

function GenerateKey($length = 16) {
    $key = '';

    for($i = 0; $i < $length; $i ++) {
        $key .= chr(mt_rand(33, 126));
    }

    return $key;
}

Are there any problems with this?

Another Edit: Most of the other questions deal with password generation. I want a wider variety of characters and I don't care about 1 vs l. I want the maximum number of possible keys to be possible.

A: 

Does that question would be of interest to you?

I'm not sure why uniqid() doesn't work for you and in what case you need a unique number in the same millisecond but not necessarily otherwise; what are you generating so fast that in the same millisecond you could have a collision? I'm wondering how much time does uniqid() takes just to generate its number. If you want, use the prefix parameter of the uniqid() function with a few random letters and you should be safe.

If it's for generating file, you might want to look at tmpfile() or tempname().

In any case, depending on what you are trying to achieve, you can just loop and verify if the unique id is already taken (in an array, with file_exists, etc.) and just generate another one if it's the case.


Also, as I'm not sure I understand your question exactly, I would point you to those other questions that sound pretty similar while I get the difference of yours:

The first one will be of interest if you are looking to do a unique id that's human readable. The second one could be useful if you want to play with random numbers and md5/sha1. Although, again, I think uniqid() might already be what you are looking for.

lpfavreau
A: 

I suspect you haven't looked at uniqid() since they added the $more_entropy option to it. That addresses the same-millisecond thing.

chaos
See the edit on the question
Darryl Hein
+3  A: 

Personally, I like to use sha1(microtime(true).mt_rand(10000,90000)) but you are looking for more of a customizable approach, so try this function (which is a modification to your request of this answer):

function rand_char($length) {
  $random = '';
  for ($i = 0; $i < $length; $i++) {
    $random .= chr(mt_rand(33, 126));
  }
  return $random;
}

Still, this will probably be significantly slower than uniqid(), md5(), or sha1().

Edit: Looks like you got to it first, sorry. :D

Edit 2: I decided to do a nice little test on my Debian machine with PHP 5 and eAccelerator (excuse the long code):

function rand_char($length) {
  $random = '';
  for ($i = 0; $i < $length; $i++) {
    $random .= chr(mt_rand(33, 126));
  }
  return $random;
}

function rand_sha1($length) {
  $max = ceil($length / 40);
  $random = '';
  for ($i = 0; $i < $max; $i ++) {
    $random .= sha1(microtime(true).mt_rand(10000,90000));
  }
  return substr($random, 0, $length);
}

function rand_md5($length) {
  $max = ceil($length / 32);
  $random = '';
  for ($i = 0; $i < $max; $i ++) {
    $random .= md5(microtime(true).mt_rand(10000,90000));
  }
  return substr($random, 0, $length);
}

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_char(1000);

echo "Rand:\t".(microtime(true) - $a)."\n";

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_sha1(1000);

echo "SHA-1:\t".(microtime(true) - $a)."\n";

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_md5(1000);

echo "MD5:\t".(microtime(true) - $a)."\n";

Results:

Rand:   2.09621596336
SHA-1:  0.611464977264
MD5:    0.618473052979

So my suggestion, if you want speed (but not full charset), is to stick to MD5, SHA-1, or Uniqid (which I didn't test.. yet)

St. John Johnson
Beat ya just by a few seconds.
Darryl Hein
Beat ya just by a few months ;)
lpfavreau
+1 for the clean answer and modification to the original code, this one is better using mt_rand()
lpfavreau
@lpfavreau Ha, thanks!
St. John Johnson
Not to clutter the answer anymore, I added a simple Uniqid test and after many runs, it averaged about 0.165093898773, which is significantly faster than the other three. Remember though it returns 13 digits of hex + random numbers, which is a horrible charset!
St. John Johnson
Nice tests, I'd +1 again if I could. What would it give by combining sha1(uniqid()) or something like that? Unique + fixed characters and length.
lpfavreau
+2  A: 

You can still use uniqid(), just do some additional processing to expand its value to the number of characters you need.

For example, to expand it to 32 characters, you could do

$id = md5(uniqid());

To expand it to 64 characters, just append the md5 of the md5, like so

$first = md5(uniqid());
$id = $first . md5($first);

Then, trucate as necessary, if you need less than some multiple of 32.

It's possible you could run into collisions, but it's pretty unlikely. If you're paranoid about that, just use the same idea, but chug uniqid() through a symmetric cipher like AES instead of hashing it.

Bob Somers
A: 

I like to do something like,

$randkey = hash('sha-256', 
  uniqid(serialize($_SERVER), true));

The inclusion of uniqid() tries to ensure it is unique to this server. Serializing $_SERVER tries to ensure you won't generate the same hash on another server. I say 'tries to' because of the ridiculously small chance of stumbling upon a collision in SHA-256.

Note that this is 64 characters. If that is too much to swallow, you could base64 instead of the default hex. Brings it down to about 43 characters.

$randkey = base64_encode(hash('sha-256', 
  uniqid(serialize($_SERVER), true), true));
thomasrutter
A: 
md5(uniqid(mt_rand(), true));

This generates HEX (0-9A-F) characters which encode tightly when stored as HEX or BINARY in your column, you can use CHAR(32) but it's not as efficient. Obviously these print nicely and are easy to say outloud, no funny characters.

This is what is known as a UUID and you'll never generate the same one twice, not ever if every computer in the world was generating them.

PS: Technically you should use SHA-256 and substr() the thing to 32 characters long to generate even better quality UUIDs.

TravisO
A: 

See if the php code on this post helps: Generate Random Strings Using PHP

Basically it returns a random set of characters of fixed length, chosen from fixed set(s) of characters. You can edit the input parameters to generate a random string with a mix of upper/lower case characters, digits and symbols or specify your custom character set e.g. only hexa-decimal digits.

Example output for simple random strings (copied from the post):

EVH46H33
7248YPJP
F02W4M5E
0X550PII

Example output for complex random strings (for use in passwords):

mczt0:Rm
2dwvJp!v
wo9iVk@b
c5xmx:xR
Salman A