Overview

Namespaces

  • cassandra
  • None
  • PHP
  • phpcassa
    • Batch
    • Connection
    • Index
    • Iterator
    • Schema
      • DataType
    • Util
    • UUID

Classes

  • AbstractColumnFamily
  • ColumnFamily
  • ColumnSlice
  • SuperColumnFamily
  • SystemManager
  • UUID
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: namespace phpcassa;
  3: /*
  4:    DrUUID RFC4122 library for PHP5
  5:     by J. King (http://jkingweb.ca/)
  6:    Licensed under MIT license
  7: 
  8:    See http://jkingweb.ca/code/php/lib.uuid/
  9:     for documentation
 10: 
 11:    Last revised 2010-02-15
 12: */
 13: 
 14: /*
 15: Copyright (c) 2009 J. King
 16: 
 17: Permission is hereby granted, free of charge, to any person
 18: obtaining a copy of this software and associated documentation
 19: files (the "Software"), to deal in the Software without
 20: restriction, including without limitation the rights to use,
 21: copy, modify, merge, publish, distribute, sublicense, and/or sell
 22: copies of the Software, and to permit persons to whom the
 23: Software is furnished to do so, subject to the following
 24: conditions:
 25: 
 26: The above copyright notice and this permission notice shall be
 27: included in all copies or substantial portions of the Software.
 28: 
 29: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 30: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 31: OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 32: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 33: HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 34: WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 35: FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 36: OTHER DEALINGS IN THE SOFTWARE.
 37: */
 38: 
 39: use phpcassa\UUID\UUIDException;
 40: use phpcassa\Util\Clock;
 41: 
 42: /**
 43:  * @package phpcassa
 44:  */
 45: class UUID {
 46:     const MD5  = 3;
 47:     const SHA1 = 5;
 48:     const clearVer = 15;  // 00001111  Clears all bits of version byte with AND
 49:     const clearVar = 63;  // 00111111  Clears all relevant bits of variant byte with AND
 50:     const varRes   = 224; // 11100000  Variant reserved for future use
 51:     const varMS    = 192; // 11000000  Microsft GUID variant
 52:     const varRFC   = 128; // 10000000  The RFC 4122 variant (this variant)
 53:     const varNCS   = 0;   // 00000000  The NCS compatibility variant
 54:     const version1 = 16;  // 00010000
 55:     const version3 = 48;  // 00110000
 56:     const version4 = 64;  // 01000000
 57:     const version5 = 80;  // 01010000
 58:     const interval = 0x01b21dd213814000; // Time (in 100ns steps) between the start of the UTC and Unix epochs
 59:     const nsDNS  = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
 60:     const nsURL  = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
 61:     const nsOID  = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
 62:     const nsX500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
 63:     protected static $randomFunc = 'randomTwister';
 64:     protected static $randomSource = NULL;
 65: 
 66:     //instance properties
 67:     protected $bytes;
 68:     protected $hex;
 69:     protected $string;
 70:     protected $urn;
 71:     protected $version;
 72:     protected $variant;
 73:     protected $node;
 74:     protected $time;
 75: 
 76:     /**
 77:      * Generate a v1 UUID (timestamp based)
 78:      * @param string $node what to use for the MAC portion of the UUID.  This will be generated
 79:      *        randomly if left as NULL
 80:      * @param int $time timestamp to use for the UUID.  This should be a number of microseconds
 81:      *        since the UNIX epoch.
 82:      * @return string a byte[] representation of a UUID
 83:      */
 84:     public static function uuid1($node=null, $time=null) {
 85:         return UUID::mint(1, $node, null, $time);
 86:     }
 87: 
 88:     /**
 89:      * Generate a v3 UUID
 90:      * @return string a byte[] representation of a UUID 
 91:      */
 92:     static public function uuid3($node=null, $namespace=null) {
 93:         return UUID::mint(3, $node, $namespace);
 94:     }
 95: 
 96:     /**
 97:      * Generate a v4 UUID
 98:      * @return string a byte[] representation of a UUID 
 99:      */
100:     static public function uuid4() {
101:         return UUID::mint(4);
102:     }
103: 
104:     /**
105:      * Generate a v5 UUID
106:      * @return string a byte[] representation of a UUID 
107:      */
108:     static public function uuid5($node, $namespace=null) {
109:         return UUID::mint(5, $node, $namespace);
110:     }
111: 
112:     /**
113:      * Import an existing UUID.
114:      */
115:     public static function import($uuid) {
116:         return new self(self::makeBin($uuid, 16));
117:     }
118: 
119:  /**
120:   * Create a new UUID based on provided data.
121:   * @param int $ver the UUID version to generate.
122:   */
123:  public static function mint($ver = 1, $node = NULL, $ns = NULL, $time = NULL) {
124:   switch((int) $ver) {
125:    case 1:
126:     return new self(self::mintTime($node, $time));
127:    case 2:
128:     // Version 2 is not supported 
129:     throw new UUIDException("Version 2 is unsupported.");
130:    case 3:
131:     return new self(self::mintName(self::MD5, $node, $ns));
132:    case 4:
133:     return new self(self::mintRand());
134:    case 5:
135:     return new self(self::mintName(self::SHA1, $node, $ns));
136:    default:
137:     throw new UUIDException("Selected version is invalid or unsupported.");
138:   }
139:  }
140: 
141:  /**
142:   * Compare the binary representations of two UUIDs.
143:   * The comparison will return true if they are bit-exact,
144:   * or if neither is valid.
145:   */
146:  public static function compare($a, $b) {
147:   if (self::makeBin($a, 16)==self::makeBin($b, 16))
148:    return TRUE;
149:   else
150:    return FALSE;
151:  }
152: 
153:  public function __toString() {
154:   return $this->string;
155:  }
156: 
157:  public function __get($var) {
158:   switch($var) {
159:    case "bytes":
160:     return $this->bytes;
161:    case "hex":
162:     return bin2hex($this->bytes);
163:    case "string":
164:     return $this->__toString();
165:    case "urn":
166:     return "urn:uuid:".$this->__toString();
167:    case "version":
168:     return ord($this->bytes[6]) >> 4;
169:    case "variant":
170:     $byte = ord($this->bytes[8]);
171:     if ($byte >= self::varRes)
172:      return 3;
173:     if ($byte >= self::varMS)
174:      return 2;
175:     if ($byte >= self::varRFC)
176:      return 1;
177:     else
178:      return 0;
179:    case "node":
180:     if (ord($this->bytes[6])>>4==1)
181:      return bin2hex(substr($this->bytes,10));
182:     else
183:      return NULL; 
184:    case "time":
185:     if (ord($this->bytes[6])>>4==1) {
186:      // Restore contiguous big-endian byte order
187:      $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]);
188:      // Clear version flag
189:      $time[0] = "0"; 
190:      // Do some reverse arithmetic to get a Unix timestamp
191:      $time = (hexdec($time) - self::interval) / 10000000;
192:      return $time;
193:     }
194:     else
195:      return NULL;
196:    default:
197:     return NULL;
198:   }
199:  }
200: 
201:  protected function __construct($uuid) {
202:   if (strlen($uuid) != 16)
203:    throw new UUIDException("Input must be a 128-bit integer.");
204:   $this->bytes  = $uuid;
205:   // Optimize the most common use
206:   $this->string = 
207:    bin2hex(substr($uuid,0,4))."-".
208:    bin2hex(substr($uuid,4,2))."-".
209:    bin2hex(substr($uuid,6,2))."-".
210:    bin2hex(substr($uuid,8,2))."-".
211:    bin2hex(substr($uuid,10,6));
212:  }
213: 
214:  protected static function get_time() {
215:     $time1 = microtime();
216:     settype($time1, 'string'); //convert to string to keep trailing zeroes
217:     $time2 = explode(" ", $time1);
218:     $sub_secs = preg_replace('/0./', '', $time2[0], 1);
219:     $time3 = ($time2[1].$sub_secs)/100;
220:     return $time3;
221:  }
222: 
223: 
224:  protected static function mintTime($node = NULL, $time_arg = NULL) {
225:   /* Generates a Version 1 UUID.  
226:      These are derived from the time at which they were generated. */
227:   // Get time since Gregorian calendar reform in 100ns intervals
228:   // This is exceedingly difficult because of PHP's (and pack()'s) 
229:   //  integer size limits.
230:   // Note that this will never be more accurate than to the microsecond.
231:   if ($time_arg == NULL) {
232:    $time = Clock::get_time() * 10 + self::interval;
233:   } else {
234:    $time = $time_arg * 10 + self::interval;
235:   }
236:   // Convert to a string representation
237:   $time = sprintf("%F", $time);
238:   preg_match("/^\d+/", $time, $time); //strip decimal point
239:   // And now to a 64-bit binary representation
240:   $time = base_convert($time[0], 10, 16);
241:   $time = pack("H*", str_pad($time, 16, "0", STR_PAD_LEFT));
242:   // Reorder bytes to their proper locations in the UUID
243:   $uuid  = $time[4].$time[5].$time[6].$time[7].$time[2].$time[3].$time[0].$time[1];
244:   // Generate a random clock sequence
245:   $uuid .= self::randomBytes(2);
246:   // set variant
247:   $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
248:   // set version
249:   $uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version1);
250:   // Set the final 'node' parameter, a MAC address
251:   if ($node) 
252:    $node = self::makeBin($node, 6);
253:   if (!$node) { 
254:     // If no node was provided or if the node was invalid, 
255:     //  generate a random MAC address and set the multicast bit
256:    $node = self::randomBytes(6);
257:    $node[0] = pack("C", ord($node[0]) | 1);
258:   }
259:   $uuid .= $node;
260:   return $uuid;
261:  }
262: 
263:  protected static function mintRand() {
264:   /* Generate a Version 4 UUID.  
265:      These are derived soly from random numbers. */
266:   // generate random fields
267:   $uuid = self::randomBytes(16);
268:   // set variant
269:   $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
270:   // set version
271:   $uuid[6] = chr(ord($uuid[6]) & self::clearVer | self::version4);
272:   return $uuid;
273:  }
274: 
275:  protected static function mintName($ver, $node, $ns) {
276:   /* Generates a Version 3 or Version 5 UUID.
277:      These are derived from a hash of a name and its namespace, in binary form. */
278:   if (!$node)
279:    throw new UUIDException("A name-string is required for Version 3 or 5 UUIDs.");
280:   // if the namespace UUID isn't binary, make it so
281:   $ns = self::makeBin($ns, 16);
282:   if (!$ns)
283:    throw new UUIDException("A binary namespace is required for Version 3 or 5 UUIDs.");
284:   switch($ver) {
285:    case self::MD5: 
286:     $version = self::version3;
287:     $uuid = md5($ns.$node,1);
288:     break;
289:    case self::SHA1:
290:     $version = self::version5;
291:     $uuid = substr(sha1($ns.$node,1),0, 16);
292:     break;
293:   }
294:   // set variant
295:   $uuid[8] = chr(ord($uuid[8]) & self::clearVar | self::varRFC);
296:   // set version
297:   $uuid[6] = chr(ord($uuid[6]) & self::clearVer | $version);
298:   return ($uuid);
299:  }
300: 
301:  protected static function makeBin($str, $len) {
302:   /* Insure that an input string is either binary or hexadecimal.
303:      Returns binary representation, or false on failure. */
304:   if ($str instanceof self)
305:    return $str->bytes;
306:   if (strlen($str)==$len)
307:    return $str;
308:   else
309:    $str = preg_replace("/^urn:uuid:/is", "", $str); // strip URN scheme and namespace
310:    $str = preg_replace("/[^a-f0-9]/is", "", $str);  // strip non-hex characters
311:    if (strlen($str) != ($len * 2))
312:     return FALSE;
313:    else
314:     return pack("H*", $str);
315:  }
316: 
317:  public static function initRandom() {
318:   /* Look for a system-provided source of randomness, which is usually crytographically secure.
319:      /dev/urandom is tried first simply out of bias for Linux systems. */
320:   if (is_readable('/dev/urandom')) {
321:    self::$randomSource = fopen('/dev/urandom', 'rb');
322:    self::$randomFunc = 'randomFRead';
323:   }
324:   else if (class_exists('COM', 0)) {
325:    try {
326:     self::$randomSource = new COM('CAPICOM.Utilities.1');  // See http://msdn.microsoft.com/en-us/library/aa388182(VS.85).aspx
327:     self::$randomFunc = 'randomCOM';
328:    }
329:    catch(Exception $e) {}
330:   }
331:   return self::$randomFunc;
332:  } 
333: 
334:  public static function randomBytes($bytes) {
335:   return call_user_func(array('self', self::$randomFunc), $bytes);
336:  } 
337: 
338:  protected static function randomTwister($bytes) {
339:   /* Get the specified number of random bytes, using mt_rand().
340:      Randomness is returned as a string of bytes. */
341:   $rand = "";
342:   for ($a = 0; $a < $bytes; $a++) {
343:    $rand .= chr(mt_rand(0, 255));
344:   } 
345:   return $rand;
346:  }
347:  
348:  protected static function randomFRead($bytes) {
349:   /* Get the specified number of random bytes using a file handle 
350:      previously opened with UUID::initRandom().
351:      Randomness is returned as a string of bytes. */
352:   return fread(self::$randomSource, $bytes);
353:  }
354:  
355:  protected static function randomCOM($bytes) {
356:   /* Get the specified number of random bytes using Windows'
357:      randomness source via a COM object previously created by UUID::initRandom().
358:      Randomness is returned as a string of bytes. */
359:   return base64_decode(self::$randomSource->GetRandom($bytes,0)); // straight binary mysteriously doesn't work, hence the base64
360:  }
361: }
362: 
phpcassa API documentation generated by ApiGen 2.8.0