forked from christianchristensen/iPhone-IMAP-Notes
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f0aae4f
commit c0e1721
Showing
2 changed files
with
319 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,314 @@ | ||
<?php | ||
/* | ||
DrUUID RFC4122 library for PHP5 | ||
by J. King (http://jkingweb.ca/) | ||
Licensed under MIT license | ||
See http://jkingweb.ca/code/php/lib.uuid/ | ||
for documentation | ||
Last revised 2011-03-20 | ||
*/ | ||
|
||
/* | ||
Copyright (c) 2009 J. King | ||
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, subject to the following | ||
conditions: | ||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
|
||
class UUID { | ||
const MD5 = 3; | ||
const SHA1 = 5; | ||
const clearVer = 15; // 00001111 Clears all bits of version byte with AND | ||
const clearVar = 63; // 00111111 Clears all relevant bits of variant byte with AND | ||
const varRes = 224; // 11100000 Variant reserved for future use | ||
const varMS = 192; // 11000000 Microsft GUID variant | ||
const varRFC = 128; // 10000000 The RFC 4122 variant (this variant) | ||
const varNCS = 0; // 00000000 The NCS compatibility variant | ||
const version1 = 16; // 00010000 | ||
const version3 = 48; // 00110000 | ||
const version4 = 64; // 01000000 | ||
const version5 = 80; // 01010000 | ||
const interval = 122192928000000000.0; // Time (in 100ns steps) between the start of the UTC and Unix epochs | ||
const nsDNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; | ||
const nsURL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; | ||
const nsOID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; | ||
const nsX500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; | ||
protected static $randomFunc = 'randomTwister'; | ||
protected static $randomSource = NULL; | ||
//instance properties | ||
protected $bytes; | ||
protected $hex; | ||
protected $string; | ||
protected $urn; | ||
protected $version; | ||
protected $variant; | ||
protected $node; | ||
protected $time; | ||
|
||
public static function mint($ver = 1, $node = NULL, $ns = NULL, $time = NULL) { | ||
/* Create a new UUID based on provided data. */ | ||
switch((int) $ver) { | ||
case 1: | ||
return new self(self::mintTime($node, $ns, $time)); | ||
case 2: | ||
// Version 2 is not supported | ||
throw new UUIDException("Version 2 is unsupported."); | ||
case 3: | ||
return new self(self::mintName(self::MD5, $node, $ns)); | ||
case 4: | ||
return new self(self::mintRand()); | ||
case 5: | ||
return new self(self::mintName(self::SHA1, $node, $ns)); | ||
default: | ||
throw new UUIDException("Selected version is invalid or unsupported."); | ||
} | ||
} | ||
|
||
public static function import($uuid) { | ||
/* Import an existing UUID. */ | ||
return new self(self::makeBin($uuid, 16)); | ||
} | ||
|
||
public static function compare($a, $b) { | ||
/* Compares the binary representations of two UUIDs. | ||
The comparison will return true if they are bit-exact, | ||
or if neither is valid. */ | ||
if (self::makeBin($a, 16)==self::makeBin($b, 16)) | ||
return TRUE; | ||
else | ||
return FALSE; | ||
} | ||
|
||
public static function seq() { | ||
/* Generate a random clock sequence; this is just two random bytes */ | ||
return self::ramdonBytes(2); | ||
} | ||
|
||
public function __toString() { | ||
return $this->string; | ||
} | ||
|
||
public function __get($var) { | ||
switch($var) { | ||
case "bytes": | ||
return $this->bytes; | ||
case "hex": | ||
return bin2hex($this->bytes); | ||
case "string": | ||
return $this->__toString(); | ||
case "urn": | ||
return "urn:uuid:".$this->__toString(); | ||
case "version": | ||
return ord($this->bytes[6]) >> 4; | ||
case "variant": | ||
$byte = ord($this->bytes[8]); | ||
if ($byte >= self::varRes) | ||
return 3; | ||
if ($byte >= self::varMS) | ||
return 2; | ||
if ($byte >= self::varRFC) | ||
return 1; | ||
else | ||
return 0; | ||
case "node": | ||
if (ord($this->bytes[6])>>4==1) | ||
return bin2hex(substr($this->bytes,10)); | ||
else | ||
return NULL; | ||
case "time": | ||
if (ord($this->bytes[6])>>4==1) { | ||
// Restore contiguous big-endian byte order | ||
$time = bin2hex($this->bytes[6].$this->bytes[7].$this->bytes[4].$this->bytes[5].$this->bytes[0].$this->bytes[1].$this->bytes[2].$this->bytes[3]); | ||
// Clear version flag | ||
$time[0] = "0"; | ||
// Do some reverse arithmetic to get a Unix timestamp | ||
$time = (hexdec($time) - self::interval) / 10000000; | ||
return $time; | ||
} | ||
else | ||
return NULL; | ||
default: | ||
return NULL; | ||
} | ||
} | ||
|
||
protected function __construct($uuid) { | ||
if (strlen($uuid) != 16) | ||
throw new UUIDException("Input must be a valid UUID."); | ||
$this->bytes = $uuid; | ||
// Optimize the most common use | ||
$this->string = | ||
bin2hex(substr($uuid,0,4))."-". | ||
bin2hex(substr($uuid,4,2))."-". | ||
bin2hex(substr($uuid,6,2))."-". | ||
bin2hex(substr($uuid,8,2))."-". | ||
bin2hex(substr($uuid,10,6)); | ||
} | ||
|
||
protected static function mintTime($node = NULL, $seq = NULL, $time = NULL) { | ||
/* Generates a Version 1 UUID. | ||
These are derived from the time at which they were generated. */ | ||
// Do a sanity check on clock sequence | ||
if ($seq !== NULL && strlen($seq) != 2) { | ||
throw UUIDException("Clock sequence most be a two-byte binary string."); | ||
} | ||
// If no time is specified, get time since Gregorian calendar | ||
// reform in 100ns intervals. This is exceedingly difficult | ||
// because of PHP's (and pack()'s) integer size limits | ||
// Note that this will never be more accurate than to the microsecond | ||
// Specifying a time for this method should only ever be used for | ||
// debugging purposes, lest uniqueness be compromised | ||
$time = ($time !== NULL) ? (float) $time : microtime(1); | ||
$time = $time * 10000000 + self::interval; | ||
// Convert to a string representation | ||
$time = sprintf("%F", $time); | ||
preg_match("/^\d+/", $time, $time); //strip decimal point | ||
// And now to a 64-bit binary representation | ||
$time = base_convert($time[0], 10, 16); | ||
$time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT)); | ||
// Reorder bytes to their proper locations in the UUID | ||
$uuid = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1]; | ||
// Generate a random clock sequence if one is not provided | ||
// Please consult Sections 4.1.5 and 4.2.1 of RFC 4122 for | ||
// guidance regarding when to use a new clock sequence | ||
$uuid .= ($seq !== NULL) ? $seq : self::randomBytes(2); | ||
// set variant | ||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC); | ||
// set version | ||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1); | ||
// Set the final 'node' parameter, a MAC address | ||
if ($node) | ||
$node = self::makeBin($node, 6); | ||
if (!$node) { | ||
// If no node was provided or if the node was invalid, | ||
// generate a random MAC address and set the multicast bit | ||
$node = self::randomBytes(6); | ||
$node[0] = pack("C", ord($node[0]) | 1); | ||
} | ||
$uuid .= $node; | ||
return $uuid; | ||
} | ||
|
||
protected static function mintRand() { | ||
/* Generate a Version 4 UUID. | ||
These are derived soly from random numbers. */ | ||
// generate random fields | ||
$uuid = self::randomBytes(16); | ||
// set variant | ||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC); | ||
// set version | ||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4); | ||
return $uuid; | ||
} | ||
|
||
protected static function mintName($ver, $node, $ns) { | ||
/* Generates a Version 3 or Version 5 UUID. | ||
These are derived from a hash of a name and its namespace, in binary form. */ | ||
if (!$node) | ||
throw new UUIDException("A name-string is required for Version 3 or 5 UUIDs."); | ||
// if the namespace UUID isn't binary, make it so | ||
$ns = self::makeBin($ns, 16); | ||
if (!$ns) | ||
throw new UUIDException("A valid UUID namespace is required for Version 3 or 5 UUIDs."); | ||
switch($ver) { | ||
case self::MD5: | ||
$version = self::version3; | ||
$uuid = md5($ns.$node,1); | ||
break; | ||
case self::SHA1: | ||
$version = self::version5; | ||
$uuid = substr(sha1($ns.$node,1),0, 16); | ||
break; | ||
} | ||
// set variant | ||
$uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC); | ||
// set version | ||
$uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version); | ||
return ($uuid); | ||
} | ||
|
||
protected static function makeBin($str, $len) { | ||
/* Insure that an input string is either binary or hexadecimal. | ||
Returns binary representation, or false on failure. */ | ||
if ($str instanceof self) | ||
return $str->bytes; | ||
if (strlen($str)==$len) | ||
return $str; | ||
else | ||
$str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace | ||
$str = preg_replace("/[^a-f0-9]/is", "", $str); // strip non-hex characters | ||
if (strlen($str) != ($len * 2)) | ||
return FALSE; | ||
else | ||
return pack("H*", $str); | ||
} | ||
|
||
public static function initRandom() { | ||
/* Look for a system-provided source of randomness, which is usually crytographically secure. | ||
/dev/urandom is tried first because tests suggest CAPICOM is quite slow to initialize. */ | ||
if (is_readable('/dev/urandom')) { | ||
self::$randomSource = fopen('/dev/urandom', 'rb'); | ||
self::$randomFunc = 'randomFRead'; | ||
} | ||
else if (class_exists('COM', 0)) { | ||
try { | ||
self::$randomSource = new COM('CAPICOM.Utilities.1'); // See http://msdn.microsoft.com/en-us/library/aa388182(VS.85).aspx | ||
self::$randomFunc = 'randomCOM'; | ||
} | ||
catch(Exception $e) {} | ||
} | ||
return self::$randomFunc; | ||
} | ||
|
||
public static function randomBytes($bytes) { | ||
return call_user_func(array('self', self::$randomFunc), $bytes); | ||
} | ||
|
||
protected static function randomTwister($bytes) { | ||
/* Get the specified number of random bytes, using mt_rand(). | ||
Randomness is returned as a string of bytes. */ | ||
$rand = ""; | ||
for ($a = 0; $a < $bytes; $a++) { | ||
$rand .= chr(mt_rand(0, 255)); | ||
} | ||
return $rand; | ||
} | ||
|
||
protected static function randomFRead($bytes) { | ||
/* Get the specified number of random bytes using a file handle | ||
previously opened with UUID::initRandom(). | ||
Randomness is returned as a string of bytes. */ | ||
return fread(self::$randomSource, $bytes); | ||
} | ||
|
||
protected static function randomCOM($bytes) { | ||
/* Get the specified number of random bytes using Windows' | ||
randomness source via a COM object previously created by UUID::initRandom(). | ||
Randomness is returned as a string of bytes. */ | ||
return base64_decode(self::$randomSource->GetRandom($bytes,0)); // straight binary mysteriously doesn't work, hence the base64 | ||
} | ||
} | ||
|
||
class UUIDException extends Exception { | ||
} |