-4
\$\begingroup\$

I have this function to generate UUID's:

function uuid($v=4,$d=null,$s=false)//$v-> version|$data-> data for version 3 and 5|$s-> add salt and pepper
{
    switch($v.($x=''))
    {
        case 3:
            $x=md5($d.($s?md5(microtime(true).uniqid($d,true)):''));break;
        case 4:default:
            $v=4;for($i=0;$i<=30;++$i)$x.=substr('1234567890abcdef',mt_rand(0,15),1);break;
        case 5:
            $x=sha1($d.($s?sha1(microtime(true).uniqid($d,true)):''));break;
    }
    return preg_replace('@^(.{8})(.{4})(.{3})(.{3})(.{12}).*@','$1-$2-'.$v.'$3-'.substr('89ab',rand(0,3),1).'$4-$5',$x);
}

This is far from being short!

The idea is to reduce this at maximum!

Criteria to meet:

  • It MUST have the format xxxxxxxx-xxxx-vxxx-yxxx-xxxxxxxxxxxx, being x a hexadecimal number, y MUST be 89AB and v has to be the version! (required)

  • Only vcan be generated randomly for all versions (non-standard, optional)

  • Version 3 and 5 have to generate ALWAYS the same UUID (except for the rule above, required)

  • You must provide a method of making the UUID somewhat random (required, except for version 4)

  • Version 3 uses md5 to "pack" the data, while version 5 uses sha1 (leaving a few chars behind, required)

  • Function name MUST be uuid (required)

Scoring:

  • Lower number of chars wins
  • The score is calculated using (number chars)*0.75
  • Readable code is calculated using (number chars)*0.50
  • If one of the required criteria from above isn't met, the multiplier is increased by 0.5 for each criteria, except for the last which is 1.25 (maximum will be (number chars)*4.00, which means that 1 char is counting as 4)
  • Comments don't count but anything else between function uuid(...){ and } counts!

For example:

My function would have a crappy result:

It has 451 chars on linux.

Since it is somewhat hard to read, it is *0.75.

Since I fulfilled all the criteria, it stays *0.75.

Result: 451*0.75 = 338,25!

\$\endgroup\$
4
  • \$\begingroup\$ Your code doesn't seem to meet your own specification; for $v of 3 and 5, the y half-byte is chosen at random. Also, the criteria are somewhat hard to understand as written. For example, do you mean that versions 3 and 5 must always return the same UUID, given the same data, or do you mean that they actually always return the same value (fairly useless)? \$\endgroup\$
    – primo
    Feb 8, 2014 at 8:49
  • \$\begingroup\$ If I run uuid(3,'this') 4 times, depending on the implementation you choose, you must have the same UUID, except the only char that can be random. \$\endgroup\$ Feb 8, 2014 at 8:51
  • 1
    \$\begingroup\$ So this is a specification that you've invented? According the OSF UUID specification, a version 3 UUID must always return the same value for any given data. \$\endgroup\$
    – primo
    Feb 8, 2014 at 8:57
  • \$\begingroup\$ I know, but I'm letting that one be a little "loose". And it is well identified as being optional and NOT standard. All i want is a UUID generator for all those 3 versions. That one was my example. It works, but it's quite a chunk of frankencode. The idea is to keep it standard. All non-standard "features" are optional, except the "random" part, that can be a simple salt given by the function. \$\endgroup\$ Feb 8, 2014 at 9:00

1 Answer 1

4
\$\begingroup\$

PHP - 189 × 0.75 = 141.75

function uuid($v,$d,$s=''){
  $u=hash($v^3?sha1:md5,$v^4?$d.$s:gmp_strval(gmp_random(4)));
  $u[12]=$v;$u[16]=dechex(+"0x$u[16]"&3|8);
  return substr(preg_replace('/^.{8}|.{4}/','\0-',$u,4),0,36);
}

This implementation should be fully compliant with RFC 4122. If $s is provided, it is expected to be the byte string represention of the UUID for the applicable namespace. Otherwise, the default ("NULL") namespace is used.

gmp_random(4) is used to generate the 128 bits of entropy, which is just about the best PHP has. If the gmp module isn't available, you could also use this:

openssl_random_pseudo_bytes(16)) (requires openssl module to be enabled)

or, as a last resort:

for(;$i++<4)$r.=mt_rand();

Sample usage:

echo uuid(3,'MyCoolNewApp');

Sample output:

c478211b-224d-30b1-9116-c06048999ce2
\$\endgroup\$
14
  • \$\begingroup\$ I only see one problem with your function: The version 4 MUST be random. Other than that, it's a really nice implementation. I'm actually pleased with the result. Let's just wait a little longer to see more answers. \$\endgroup\$ Feb 8, 2014 at 22:45
  • \$\begingroup\$ But that is not a completely random string. microtime() and getmypid() aren't good ways of making random values. There is a risk that running that function twice at the exact time with the same pid will generate the same UUID, and that is not so random. But still, it's a good one. I wouldn't do better. \$\endgroup\$ Feb 9, 2014 at 2:24
  • \$\begingroup\$ I don't want true entropy (and i didn't even mention that anywhere). I'm just saying it is not a good way. That is just my opinion. \$\endgroup\$ Feb 9, 2014 at 2:29
  • \$\begingroup\$ @IsmaelMiguel fixed. \$\endgroup\$
    – primo
    Feb 9, 2014 at 3:28
  • \$\begingroup\$ Your code won't work everywhere. It relies on the GMP extension. And using openssl_random_pseudo_bytes(16) on windows is a bad idea... It simply times-out your script. a small idea would be use md5(mt_rand(0,1e9)). It's always random, between 0 and 1,000,000,000. \$\endgroup\$ Feb 9, 2014 at 4:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.