Overview

Namespaces

  • NGS
    • Client
      • Exception
    • Converter
    • Patterns
  • PHP

Classes

  • BigDecimal
  • BigInt
  • ByteStream
  • LocalDate
  • Location
  • Money
  • Name
  • Point
  • S3
  • Timestamp
  • Utils
  • UUID
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: namespace NGS;
  3: 
  4: require_once(__DIR__.'/Utils.php');
  5: 
  6: use NGS\Utils;
  7: 
  8: /**
  9:  * UUID implementation
 10:  */
 11: class UUID
 12: {
 13:     /**
 14:      * @var string
 15:      */
 16:     private $value;
 17: 
 18:     /**
 19:      * Constructs new UUID from UUID string, existing instance, or by generating
 20:      * version 4 UUID
 21:      * @param null|string|\NGS\UUID
 22:      * @throws \InvalidArgumentException
 23:      */
 24:     public function __construct($value = null)
 25:     {
 26:         if (null === $value) {
 27:             $this->value = self::_v4();
 28:         }
 29:         elseif (is_string($value)) {
 30:             if (!self::isValid($value)) {
 31:                 throw new \InvalidArgumentException('UUID could not be constructed from invalid value: "'.$value.'"');
 32:             }
 33:             $this->value = $value;
 34:         }
 35:         elseif ($value instanceof \NGS\UUID) {
 36:             $this->value = $value->value;
 37:         }
 38:         else {
 39:             throw new \InvalidArgumentException('UUID could not be constructed from type "'.gettype($value).'"');
 40:         }
 41:     }
 42: 
 43:     /**
 44:      * Creates array of UUIDs from array by constructing UUID instance from each element of array as __construct
 45:      * argument.
 46:      * arguments
 47:      * @param array $items
 48:      * @return array Array of UUID instances
 49:      * @throws \InvalidArgumentException
 50:      */
 51:     public static function toArray(array $items, $allowNullValues=false)
 52:     {
 53:         $results = array();
 54:         try {
 55:             foreach ($items as $key => $val) {
 56:                 if ($allowNullValues && $val===null) {
 57:                     $results[] = null;
 58:                 } elseif ($val === null) {
 59:                     throw new \InvalidArgumentException('Null value found in provided array');
 60:                 } elseif(!$val instanceof \NGS\UUID) {
 61:                     $results[] = new \NGS\UUID($val);
 62:                 } else {
 63:                     $results[] = $val;
 64:                 }
 65:             }
 66:         }
 67:         catch(\Exception $e) {
 68:             throw new \InvalidArgumentException('Element at index '.$key.' could not be converted to UUID!', 42, $e);
 69:         }
 70:         return $results;
 71:     }
 72: 
 73:     /**
 74:      * Allows accessing UUID string value as property, e.g. $instance->value
 75:      * @param string $name
 76:      * @return string
 77:      * @throws \InvalidArgumentException
 78:      */
 79:     public function __get($name)
 80:     {
 81:         if($name==='value') {
 82:             return $this->value;
 83:         }
 84:         else {
 85:             throw new \InvalidArgumentException('UUID: Cannot get undefined property "'.$name.'"');
 86:         }
 87:     }
 88: 
 89:     /**
 90:      * Constructs new UUID instance by with generated version 3 UUID (MD5 hash)
 91:      * @param    string|\NGS\UUID uuid $namespace
 92:      * @param    string    $name
 93:      * @return \NGS\UUID
 94:      * @throws \InvalidArgumentException
 95:      */
 96:     public static function v3($namespace, $name)
 97:     {
 98:         if ($namespace instanceof \NGS\UUID) {
 99:             $namespace = $namespace->value;
100:         }
101:         elseif (!is_string($namespace)) {
102:             throw new \InvalidArgumentException('Cannot create uuid v3 from invalid namespace type: "'.Utils::getType($namespace).'"');
103:         }
104:         if(!is_string($name)) {
105:             throw new \InvalidArgumentException('Cannot create uuid v3 from invalid name type: "'.Utils::getType($namespace).'"');
106:         }
107:         return new UUID(self::_v3($namespace, $name));
108:     }
109: 
110:     /**
111:      * Constructs new UUID instance with generated version 4 UUID (random)
112:      * @return \NGS\UUID
113:      */
114:     public static function v4()
115:     {
116:         return new UUID(self::_v4());
117:     }
118: 
119:     /**
120:      * Constructs new UUID instance with generated version 5 UUID (SHA-1 hash)
121:      * @param    string|\NGS\UUID uuid $namespace
122:      * @param    string    $name
123:      * @return \NGS\UUID
124:      * @throws \InvalidArgumentException
125:      */
126:     public static function v5($namespace, $name)
127:     {
128:         if ($namespace instanceof \NGS\UUID) {
129:             $namespace = $namespace->value;
130:         }
131:         elseif (!is_string($namespace)) {
132:             throw new \InvalidArgumentException('Cannot create uuid v5 from invalid namespace type: "'.Utils::getType($namespace).'"');
133:         }
134:         if(!is_string($name)) {
135:             throw new \InvalidArgumentException('Cannot create uuid v5 from invalid name type: "'.Utils::getType($namespace).'"');
136:         }
137:         return new UUID(self::_v5($namespace, $name));
138:     }
139: 
140:     /**
141:      * Gets UUID string value
142:      * @return string
143:      */
144:     public function __toString()
145:     {
146:         return $this->value;
147:     }
148: 
149:     /**
150:      * Validates UUID string
151:      * @param string $uuid
152:      * @return bool
153:      */
154:     public static function isValid($uuid)
155:     {
156:         if (!is_string($uuid)) {
157:             throw new \InvalidArgumentException('UUID value was not a string, type was: '.\NGS\Utils::gettype($uuid));
158:         }
159:         return preg_match('/^\{?[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?'.
160:             '[0-9a-f]{4}\-?[0-9a-f]{12}\}?$/i', $uuid) === 1;
161:     }
162: 
163:     /**
164:      * Generate v3 UUID
165:      *
166:      * Version 3 UUIDs are named based. They require a namespace (another
167:      * valid UUID) and a value (the name). Given the same namespace and
168:      * name, the output is always the same.
169:      *
170:      * @param    uuid    $namespace
171:      * @param    string    $name
172:      */
173:     private static function _v3($namespace, $name)
174:     {
175:         if(!self::isValid($namespace)) {
176:             throw new \InvalidArgumentException('Cannot create uuid v3 from invalid namespace with value: "'.$namespace.'"');
177:         }
178: 
179:         // Get hexadecimal components of namespace
180:         $nhex = str_replace(array('-','{','}'), '', $namespace);
181: 
182:         // Binary Value
183:         $nstr = '';
184: 
185:         // Convert Namespace UUID to bits
186:         for($i = 0; $i < strlen($nhex); $i+=2)
187:         {
188:             $nstr .= chr(hexdec($nhex[$i].$nhex[$i+1]));
189:         }
190: 
191:         // Calculate hash value
192:         $hash = md5($nstr . $name);
193: 
194:         return sprintf('%08s-%04s-%04x-%04x-%12s',
195: 
196:             // 32 bits for "time_low"
197:             substr($hash, 0, 8),
198: 
199:             // 16 bits for "time_mid"
200:             substr($hash, 8, 4),
201: 
202:             // 16 bits for "time_hi_and_version",
203:             // four most significant bits holds version number 3
204:             (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
205: 
206:             // 16 bits, 8 bits for "clk_seq_hi_res",
207:             // 8 bits for "clk_seq_low",
208:             // two most significant bits holds zero and one for variant DCE1.1
209:             (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
210: 
211:             // 48 bits for "node"
212:             substr($hash, 20, 12)
213:         );
214:     }
215: 
216:     /**
217:      *
218:      * Generate v4 UUID
219:      *
220:      * Version 4 UUIDs are pseudo-random.
221:      */
222:     private static function _v4()
223:     {
224:         return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
225: 
226:             // 32 bits for "time_low"
227:             mt_rand(0, 0xffff), mt_rand(0, 0xffff),
228: 
229:             // 16 bits for "time_mid"
230:             mt_rand(0, 0xffff),
231: 
232:             // 16 bits for "time_hi_and_version",
233:             // four most significant bits holds version number 4
234:             mt_rand(0, 0x0fff) | 0x4000,
235: 
236:             // 16 bits, 8 bits for "clk_seq_hi_res",
237:             // 8 bits for "clk_seq_low",
238:             // two most significant bits holds zero and one for variant DCE1.1
239:             mt_rand(0, 0x3fff) | 0x8000,
240: 
241:             // 48 bits for "node"
242:             mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
243:         );
244:     }
245: 
246:     /**
247:      * Generate v5 UUID
248:      *
249:      * Version 5 UUIDs are named based. They require a namespace (another
250:      * valid UUID) and a value (the name). Given the same namespace and
251:      * name, the output is always the same.
252:      *
253:      * @param    uuid    $namespace
254:      * @param    string    $name
255:      */
256:     private static function _v5($namespace, $name)
257:     {
258:         if(!self::isValid($namespace)) {
259:             throw new \InvalidArgumentException('Cannot create uuid v5 from invalid namespace with value: "'.$namespace.'"');
260:         }
261: 
262:         // Get hexadecimal components of namespace
263:         $nhex = str_replace(array('-','{','}'), '', $namespace);
264: 
265:         // Binary Value
266:         $nstr = '';
267: 
268:         // Convert Namespace UUID to bits
269:         for($i = 0; $i < strlen($nhex); $i+=2)
270:         {
271:             $nstr .= chr(hexdec($nhex[$i].$nhex[$i+1]));
272:         }
273: 
274:         // Calculate hash value
275:         $hash = sha1($nstr . $name);
276: 
277:         return sprintf('%08s-%04s-%04x-%04x-%12s',
278: 
279:             // 32 bits for "time_low"
280:             substr($hash, 0, 8),
281: 
282:             // 16 bits for "time_mid"
283:             substr($hash, 8, 4),
284: 
285:             // 16 bits for "time_hi_and_version",
286:             // four most significant bits holds version number 5
287:             (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x5000,
288: 
289:             // 16 bits, 8 bits for "clk_seq_hi_res",
290:             // 8 bits for "clk_seq_low",
291:             // two most significant bits holds zero and one for variant DCE1.1
292:             (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
293: 
294:             // 48 bits for "node"
295:             substr($hash, 20, 12)
296:         );
297:     }
298: }
299: 
API documentation generated by ApiGen 2.8.0