# # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # UUID format (see RFC 4122): # time-low "-" time-mid "-" time-high-and-version "-' # clock-seq-high-and-reserved clock-seq-low "-" node # e.g. 00000000-0000-0000-0000-000000000000 (hex) # 0 1 2 3 4 5 6 7 8 9 A B C D E F if (!defined('UUID_TYPE_TIME')) { define('UUID_TYPE_TIME', 1); } if (!defined('UUID_TYPE_DCE')) { define('UUID_TYPE_DCE', 2); } if (!defined('UUID_TYPE_NAME_MD5')) { define('UUID_TYPE_NAME_MD5', 3); } if (!defined('UUID_TYPE_NAME')) { define('UUID_TYPE_NAME', 3); } if (!defined('UUID_TYPE_RANDOM')) { define('UUID_TYPE_RANDOM', 4); } if (!defined('UUID_TYPE_NAME_SHA1')) { define('UUID_TYPE_NAME_SHA1', 5); } if (!defined('UUID_TYPE_NULL')) { define('UUID_TYPE_NULL', -1); } if (!defined('UUID_VARIANT_NCS')) { define('UUID_VARIANT_NCS', 0); } if (!defined('UUID_VARIANT_DCE')) { define('UUID_VARIANT_DCE', 1); } if (!defined('UUID_VARIANT_MICROSOFT')) { define('UUID_VARIANT_MICROSOFT', 2); } if (!defined('UUID_VARIANT_OTHER')) { define('UUID_VARIANT_OTHER', 3); } if (!defined('UUID_NAMESPACE_DNS')) { define('UUID_NAMESPACE_DNS', '6ba7b810-9dad-11d1-80b4-00c04fd430c8'); } if (!defined('UUID_NAMESPACE_URL')) { define('UUID_NAMESPACE_URL', '6ba7b811-9dad-11d1-80b4-00c04fd430c8'); } if (!defined('UUID_NAMESPACE_OID')) { define('UUID_NAMESPACE_OID', '6ba7b812-9dad-11d1-80b4-00c04fd430c8'); } if (!defined('UUID_NAMESPACE_X500')) { define('UUID_NAMESPACE_X500', '6ba7b814-9dad-11d1-80b4-00c04fd430c8'); } if (!function_exists('uuid_create')) { function uuid_create($type=NULL, $namespace_uuid=NULL, $name=NULL) { switch($type) { # Valid types that are supported case NULL: case UUID_TYPE_NULL: case UUID_TYPE_DCE: case UUID_TYPE_RANDOM: break; # Valid types that require a valid $namespace_uuid parameger case UUID_TYPE_NAME_MD5: case UUID_TYPE_NAME_SHA1: if (!uuid_is_valid($namespace_uuid)) { trigger_error("UUID_TYPE_NAME_* require a valid namespace UUID", E_USER_WARNING); $type = NULL; } break; # Valid types that are unsupported case UUID_TYPE_TIME: trigger_error("UUID_TYPE_TIME not supported, using default type instead", E_USER_WARNING); $type = NULL; break; # Unrecognized types default: trigger_error("Unknown/invalid UUID type '".intval($type)."' requested, using default type instead", E_USER_WARNING); $type = NULL; } # Select the default type (in this case, random) if (is_null($type)) { $type = UUID_TYPE_RANDOM; } switch($type) { case UUID_TYPE_NULL: return uuid_frombinary("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); case UUID_TYPE_DCE: case UUID_TYPE_RANDOM: # Generate a random (version 4) UUID. See RFC 4122. # Get 128 random bits if (function_exists("mcrypt_create_iv")) { $data = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM); if (!$data) { srand(); $data = mcrypt_create_iv(16, MCRYPT_RAND); } } else { mt_srand(); $data = ""; for($i = 0; $i < 16; $i++) { $data .= chr(mt_rand(0, 255)); } } if (!isset($data) or !$data or strlen($data) != 16) { die("Internal error while generating random UUID"); } # Set the variant to UUID_VARIANT_DCE (1 0 x) $c8 = chr(ord(substr($data, 8, 1)) & ~0x40 | 0x80); # Set the version to 4 $c6 = chr(ord(substr($data, 6, 1)) & ~0xf0 | 0x40); $uuid = substr($data, 0, 6) . $c6 . substr($data, 7, 1) . $c8 . substr($data, 9); return uuid_frombinary($uuid); case UUID_TYPE_NAME_MD5: case UUID_TYPE_NAME_SHA1: # Generate a name-based (version 3 or 5) UUID. See RFC 4122. # Note that the sample output in Appendix B of RFC 4122 should # return 3d813cbb-47fb-32ba-91df-831e1593ac29 and not # e902893a-9d22-3c7e-a7b8-d6e313b71d9f (see also # http://home.famkruithof.net/guid-uuid-namebased.html) if (is_null($name)) { $name = ""; } $namespace = uuid_tobinary($namespace_uuid); $hashinput = $namespace . $name; if ($type == UUID_TYPE_NAME_SHA1) { $hashoutput = sha1($hashinput); $ver = 5; } elseif ($type == UUID_TYPE_NAME_MD5) { $hashoutput = md5($hashinput); $ver = 3; } else { die("BUG: Unknown type in name-based UUID handler '".$type."'"); } # Convert hex to binary, and truncate to 128 bits $data = pack('H*', $hashoutput); # Truncate to 128 bits $data = substr($data, 0, 16); # Set the variant to UUID_VARIANT_DCE (1 0 x) $c8 = chr(ord(substr($data, 8, 1)) & ~0x40 | 0x80); # Set the version $c6 = chr(ord(substr($data, 6, 1)) & ~0xf0 | (($ver & 0xf) << 4)); $uuid = substr($data, 0, 6) . $c6 . substr($data, 7, 1) . $c8 . substr($data, 9); return uuid_frombinary($uuid); default: die("BUG: Unknown type '".$type."'"); } die("BUG: Reached end of uuid_create"); } } if (!function_exists('uuid_is_valid')) { function uuid_is_valid($uuid) { if (!preg_match( '/^([0-9a-fA-F]{8})-([0-9a-fA-F]{4})-([0-9a-fA-F]{4})-([0-9a-fA-F]{4})-([0-9a-fA-F]{12})$/', $uuid)) { return FALSE; } else { return TRUE; } } } if (!function_exists('uuid_compare')) { function uuid_compare($uuid1, $uuid2) { if (!uuid_is_valid($uuid1)) { return FALSE; } if (!uuid_is_valid($uuid2)) { return FALSE; } return strcmp(uuid_tobinary($uuid1), uuid_tobinary($uuid2)); } } if (!function_exists('uuid_is_null')) { function uuid_is_null($uuid) { if (!uuid_is_valid($uuid)) { trigger_error("Invalid UUID passed to uuid_is_null", E_USER_WARNING); return FALSE; } return (0 === uuid_compare($uuid, "00000000-0000-0000-0000-000000000000")); } } if (!function_exists('uuid_variant')) { function uuid_variant($uuid) { if (!uuid_is_valid($uuid)) { trigger_error("Invalid UUID passed to uuid_variant", E_USER_WARNING); return FALSE; } $bin = uuid_tobinary($uuid); $v = ord(substr($bin, 8, 1)) >> 5; if ($v < 0x4) { return UUID_VARIANT_NCS; } elseif ($v < 0x6) { return UUID_VARIANT_DCE; } elseif ($v < 0x7) { return UUID_VARIANT_MICROSOFT; } else { return UUID_VARIANT_OTHER; } } } if (!function_exists('uuid_type')) { function uuid_type($uuid) { if (!uuid_is_valid($uuid)) { trigger_error("Invalid UUID passed to uuid_type", E_USER_WARNING); return FALSE; } if (uuid_is_null($uuid)) { return UUID_TYPE_NULL; } $bin = uuid_tobinary($uuid); return ord(substr($bin, 6, 1)) >> 4; } } if (!function_exists('uuid_time')) { function uuid_time($uuid) { if (!uuid_is_valid($uuid)) { trigger_error("Invalid UUID passed to uuid_time", E_USER_WARNING); return FALSE; } $bin = uuid_tobinary($uuid); # if (function_exists('gmp_init')) { # $n = gmp_init("0x".substr($hex, 16, 3).substr($hex, 9, 4).substr($hex, 0, 8)); # $n = gmp_sub($n, gmp_init("0x01B21DD213814000")); # $n = gmp_div_q($n, gmp_init("10000000")); # return gmp_intval($n); # } else { # Do a little big-number math. # Split into 16-bit words $a = unpack("n*", substr($bin, 2, 2).substr($bin, 0, 2).substr($bin,4,2).substr($bin,6,2)); $n = array($a[4] & 0xFFF, $a[3], $a[2], $a[1]); # Subtract 0x01B21DD213814000 (difference between the epochs) $s = array(0x01B2, 0x1DD2, 0x1381, 0x4000); $carry = 0; for($i = count($s)-1; $i >= 0; $i--) { $n[$i] += (~$s[$i]) + 1 + $carry; $carry = $n[$i] >> 16; $n[$i] &= 0xFFFF; } # Split into 4-bit words $tmp = array(); for($i = 0; $i < count($n); $i++) { $tmp[] = ($n[$i] >> 12) & 0xF; $tmp[] = ($n[$i] >> 8) & 0xF; $tmp[] = ($n[$i] >> 4) & 0xF; $tmp[] = $n[$i] & 0xF; } $n = $tmp; unset($tmp); # Divide by 10000000 $d = 10000000; $r = 0; $q = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); for($i = 0; $i < count($n); $i++) { $n[$i] |= $r << 4; $q[$i] = intval($n[$i] / $d); $r = $n[$i] % $d; } # Convert to 32-bit integer $retval = 0; for($i = 8; $i < 16; $i++) { $retval = ($retval << 4) | $q[$i]; } return $retval; # } } } if (!function_exists('uuid_mac')) { function uuid_mac($uuid) { if (!uuid_is_valid($uuid)) { trigger_error("Invalid UUID passed to uuid_mac", E_USER_WARNING); return FALSE; } $bin = uuid_tobinary($uuid); if (uuid_variant($uuid) != UUID_VARIANT_DCE) { return FALSE; } if (uuid_type($uuid) != UUID_TYPE_TIME) { return FALSE; } if ((ord(substr($bin, 10, 1)) & 0x80) != 0) { return FALSE; } return substr(uuid_frombinary($bin), 24); } } if (!function_exists('uuid_frombinary')) { function uuid_frombinary($uuid) { if (!isset($uuid) or !$uuid or strlen($uuid) != 16) { trigger_error("Invalid binary UUID passed to uuid_frombinary", E_USER_WARNING); return FALSE; } return bin2hex(substr($uuid, 0, 4))."-".bin2hex(substr($uuid, 4, 2))."-". bin2hex(substr($uuid, 6, 2))."-".bin2hex(substr($uuid, 8, 2))."-". bin2hex(substr($uuid, 10)); } } if (!function_exists('uuid_tobinary')) { function uuid_tobinary($uuid) { if (!isset($uuid) or !$uuid or strlen($uuid) != 36) { trigger_error("Invalid hex UUID passed to uuid_tobinary", E_USER_WARNING); return FALSE; } $m = array(); if (!preg_match( '/^([0-9a-fA-F]{8})-([0-9a-fA-F]{4})-([0-9a-fA-F]{4})-([0-9a-fA-F]{4})-([0-9a-fA-F]{12})$/', $uuid, $m)) { trigger_error("Invalid hex UUID passed to uuid_tobinary", E_USER_WARNING); return FALSE; } return pack("H*", $m[1].$m[2].$m[3].$m[4].$m[5]); } } # vim:set ts=8 sw=4 sts=4 expandtab: