-3
\$\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\$
  • \$\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 '14 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\$ – Ismael Miguel Feb 8 '14 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 '14 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\$ – Ismael Miguel Feb 8 '14 at 9:00
3
\$\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\$
  • \$\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\$ – Ismael Miguel Feb 8 '14 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\$ – Ismael Miguel Feb 9 '14 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\$ – Ismael Miguel Feb 9 '14 at 2:29
  • \$\begingroup\$ @IsmaelMiguel fixed. \$\endgroup\$ – primo Feb 9 '14 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\$ – Ismael Miguel Feb 9 '14 at 4:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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