diff --git a/src/Notes.php b/src/Notes.php index b56df99..6f6844b 100644 --- a/src/Notes.php +++ b/src/Notes.php @@ -50,15 +50,16 @@ public function index() { return $index; } - public function retrieve($msgid = NULL) { - } - public function create($msg = '') { + $uuid = UUID(); } - public function delete($msgid = NULL) { + public function retrieve($msgid = NULL) { } public function update($msgid = NULL) { } + + public function delete($msgid = NULL) { + } } \ No newline at end of file diff --git a/src/lib.uuid.php b/src/lib.uuid.php new file mode 100644 index 0000000..16b32e9 --- /dev/null +++ b/src/lib.uuid.php @@ -0,0 +1,314 @@ +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 { +}