UUID (Universally Unique Identifier) is standard (part of ISO/IEC 11578:1996) to create “universally unique” identifiers to identify objects within a system or across system boundaries. The identifiers are 128-bit in length (that’s 16 bytes) and while there really is no way to guarantee global uniqueness the probability of colissions are very small both thanks to the number of bits and the way the identifiers are created.

The UUID generation algorithms are specified in RFC4122 and I’ve created a static PHP class that implements version 1 which is time based UUID, version 4 which is truly psuedo random UUID and version 3 and 5 which are named based UUID, using either MD5 (version 3) or SHA-1 (version 5).

I know there is a PECL package around the original uuidlib but this class have no external dependencies. The full source is available at the bottom of the page.

The class has the following public functions, their return value depends on the format argument.

$mixed generate($type, $fmt = self::FMT_BYTE, $node = "", $ns = "")
$mixed convert($uuid, $from, $to)

UUID version constants where each constant represents a specific UUID version

UUID_TIME, UUID_NAME_MD5, UUID_RANDOM, UUID_NAME_SHA1

UUID format constants

  • FMT_BYTE is the default and returns a array of bytes that represents the 128-bit UUID.
  • FMT_FIELD returns a associative array with individual fields as the format specified in RFC4122.
  • FMT_STRING returns the familiar ASCII representation of a UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx).
  • FMT_BINARY returns a raw 128-bit binary representation of the UUID.

The convert method can be used to convert between these representations.

UUID version 1 example

xxxxxxxxx-xxxx-1xxx-xxxx-xxxxxxxxxxxx
Version 1 UUIDs are timed based with the node constant. The name space argument is ignored and is not used in the generation. The node identifier (”abcdef” in this case) should identify the node or object, only 6 bytes (or characters) are used from the node id.

require_once('class.uuid.php');
$str = UUID::generate(UUID::UUID_TIME, UUID::FMT_STRING, "abcdef");
print "$str\n";

Example output, the last part is the node id and will remain constant (as long as the node id is the same), the first part will change according to time while the middle part is pseudo random.

1b55e723-578b-4e34-d5cf-616263646566

The class does not fully implement version 1 as described in the RFC. The clock sequence is generated from a psuedo random generator each time a new UUID is generated and not written and read from a stable storage as described in the RFC.

UUID version 4 example

xxxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx
Version 4 is a fully pseudo random where all fields are randomly generated.

require_once('class.uuid.php');
$str = UUID::generate(UUID::UUID_RANDOM, UUID::FMT_STRING);
print "$str\n";

Kind of useless example output :)

d8988842-43d5-42b3-9049-af4bbc694dbe

UUID version 3/5 example

xxxxxxxxx-xxxx-3/5xxx-xxxx-xxxxxxxxxxxx
The main difference is that a node id is unique within a name space and a UUID generated from the same node id and name space is always the same. The generation algorithm is the same for both version 3 and 5 with the only difference being the hash method used (MD5 versus SHA1).
This is the example from the RFC.

require_once('class.uuid.php');
 
/*
 * 6ba7b810-9dad-11d1-80b4-00c04fd430c8 is the DNS name space
 */
$md5 = UUID::generate(UUID::UUID_NAME_MD5, UUID::FMT_STRING,
    "www.widgets.com", '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
$sha1  = UUID::generate(UUID::UUID_NAME_SHA1, UUID::FMT_STRING,
    "www.widgets.com", '6ba7b810-9dad-11d1-80b4-00c04fd430c8');
print "MD5: $md5\n";
print "SHA1: $sha1\n";

Example output

MD5: e902893a-9d22-3c7e-a7b8-d6e313b71d9f
SHA1: 13726f09-44a9-5eeb-8910-3525a23fb23b

Final notes

This class have been tested with PHP 5.2.x on both little and big endian machines. While there could be bugs in the algorithm implementation at least they are consistent across platforms :)

Get from github

Links

17 Responses to “UUID generator for PHP”
  1. [...] recurrir a librerías externas. Una ejemplo de una de ellas podría ser esta, que podemos descargar desde [...]

  2. elmimmo says:

    Oops, just to note, I do not get the same UUID v5 with OSSP uuid removing the http:// with either, just like

    uuid -v5 6ba7b810-9dad-11d1-80b4-00c04fd430c8 http://www.widgets.com

  3. elmimmo says:

    I do not get the same UUID v5 with same name and namespace as given in the sample here in this post, if I use OSSP uuid http://www.ossp.org/pkg/lib/uuid/ like so

    uuid -v5 ns:DNS http://www.widgets.com

    nor

    uuid -v5 6ba7b810-9dad-11d1-80b4-00c04fd430c8 http://www.widgets.com

    Am I not supposed to get the same UUID no matter the implementation, given the same namespace and name?

  4. zapytaj says:

    zapytaj…

    [...]UUID generator for PHP « shapeshifter.se[...]…

  5. Lysender says:

    I have modified them so that it will convert binary back to string or byte etc

    static private function conv_bin2byte($src) {
    // array_merge – reindex since unpack starts at index 1
    return array_merge(unpack(’C16′, $src));
    }

    static private function conv_bin2field($src) {
    $byte = self::conv_bin2byte($src);
    return self::conv_byte2field($byte);
    }

    static private function conv_bin2string($src) {
    $byte = self::conv_bin2byte($src);
    return self::conv_byte2string($byte);
    }

  6. Lysender says:

    How do I convert a binary back to string or byte or field?

    Uuid::convert($id, Uuid::FMT_BINARY, Uuid::FMT_STRING)

    is not yet supported. It is just now that I notice the problem.

  7. [...] und als Klasse bereit gestellt. Bei der Suche im Netz habe ich zwei Varianten entdeckt: DrUUID und UUID Generator. Außerdem kann man auch das PECL Package uuid nutzen, welches jedoch die libuuid (des Projekts [...]

  8. Gavitron says:

    Actually, after several hours of testing, I have identified a significant bug in this implementation. If you generate a version 3 or 5 UUID, using a namespace UUID with the first byte > 8, your code overflows, and generates invalid UUIDs. further, this invalid UUID is the same for all namespace UUIDs >80000000-0000-0000-0000-00000000000

  9. David says:

    Thanks for the great class!

    One note is that many implementations claim that the example for version 3 as shown in RFC4122 is incorrect (OSSP uuid, python) where the value generated should actually be 3d813cbb-47fb-32ba-91df-831e1593ac29. If one needs compatibility with these (and other) libraries for version 3/5 one can remove lines 163-165 and 180-182 (byte swapping lines) and get matching results.

  10. fli says:

    The bugs mentioned in the posts above should have been fixed now.

  11. jonovic says:

    I’ve tried on Php 5.2.6 on Windows and fall into trouble with random generation. Time_low part is generated using mt_rand with interval set to 0,0xffffffff. The mt_rand function however uses signed integer for parameter and that’s why the resulting value is always negative. When passing to sprintf the result of time_low part is always 0.

  12. [...] besonders anspruchsvolle Situationen und Sicherheitsfanatiker hat ‘fli’ einen UUID-Generator geschrieben, der keine Wünsche offen [...]

  13. J. King says:

    I was very excited to see your implementation of RFC4122, because I was looking to use UUIDs for Atom and didn’t want something merely “UUID-like” as all these other PHP implementations are. However, I hate to break it to you, but your implementation of Version 1 UUIDs seems to be broken in a number of ways. Besides the clock sequence (which is understandable) your implementation seems to use a null MAC node (whereas it should generate a random one), but worst of all the encoding of the time is completely wrong! :( If you plug the output of your generator into the time extractor at http://www.famkruithof.net/uuid/uuidgen?typeReq=-1 (which I know to be correct: I checked with known timestamp values) you’re left with a time several centuries from now. If you use a date in the past the disparity is even greater (several -millennia- from now…). I just thought you should know.

    If you’re curious I also wrote my own implementation from scratch yesterday since I had no one to depend on but myself (and I didn’t like your API anyway—sorry). I’d very much like to know what you think of it. :)

    http://jkingweb.ca/code/php/lib.uuid/

  14. Konrad says:

    Thank you.

  15. Just what I was looking for. Thanks!

  16. Keith says:

    Finally! A decent implementation. It’s very hard to find one of these that wasn’t written by a muppet! I’m using this as a library class for our internal ORM framework – looks to be working very well so far. Thanks!

  17.