1<?php
2
3/**
4 * This file is part of the ramsey/uuid library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13declare(strict_types=1);
14
15namespace Ramsey\Uuid;
16
17use DateTimeInterface;
18use Ramsey\Uuid\Codec\CodecInterface;
19use Ramsey\Uuid\Converter\NumberConverterInterface;
20use Ramsey\Uuid\Converter\TimeConverterInterface;
21use Ramsey\Uuid\Fields\FieldsInterface;
22use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
23use Ramsey\Uuid\Type\Hexadecimal;
24use Ramsey\Uuid\Type\Integer as IntegerObject;
25
26use function str_replace;
27use function strcmp;
28
29/**
30 * Uuid provides constants and static methods for working with and generating UUIDs
31 *
32 * @psalm-immutable
33 */
34class Uuid implements UuidInterface
35{
36 use DeprecatedUuidMethodsTrait;
37
38 /**
39 * When this namespace is specified, the name string is a fully-qualified
40 * domain name
41 *
42 * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs
43 */
44 public const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
45
46 /**
47 * When this namespace is specified, the name string is a URL
48 *
49 * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs
50 */
51 public const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
52
53 /**
54 * When this namespace is specified, the name string is an ISO OID
55 *
56 * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs
57 */
58 public const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8';
59
60 /**
61 * When this namespace is specified, the name string is an X.500 DN in DER
62 * or a text output format
63 *
64 * @link http://tools.ietf.org/html/rfc4122#appendix-C RFC 4122, Appendix C: Some Name Space IDs
65 */
66 public const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8';
67
68 /**
69 * The nil UUID is a special form of UUID that is specified to have all 128
70 * bits set to zero
71 *
72 * @link http://tools.ietf.org/html/rfc4122#section-4.1.7 RFC 4122, § 4.1.7: Nil UUID
73 */
74 public const NIL = '00000000-0000-0000-0000-000000000000';
75
76 /**
77 * Variant: reserved, NCS backward compatibility
78 *
79 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
80 */
81 public const RESERVED_NCS = 0;
82
83 /**
84 * Variant: the UUID layout specified in RFC 4122
85 *
86 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
87 */
88 public const RFC_4122 = 2;
89
90 /**
91 * Variant: reserved, Microsoft Corporation backward compatibility
92 *
93 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
94 */
95 public const RESERVED_MICROSOFT = 6;
96
97 /**
98 * Variant: reserved for future definition
99 *
100 * @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
101 */
102 public const RESERVED_FUTURE = 7;
103
104 /**
105 * @deprecated Use {@see ValidatorInterface::getPattern()} instead.
106 */
107 public const VALID_PATTERN = '^[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}$';
108
109 /**
110 * Version 1 (time-based) UUID
111 *
112 * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
113 */
114 public const UUID_TYPE_TIME = 1;
115
116 /**
117 * Version 2 (DCE Security) UUID
118 *
119 * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
120 */
121 public const UUID_TYPE_DCE_SECURITY = 2;
122
123 /**
124 * @deprecated Use {@see Uuid::UUID_TYPE_DCE_SECURITY} instead.
125 */
126 public const UUID_TYPE_IDENTIFIER = 2;
127
128 /**
129 * Version 3 (name-based and hashed with MD5) UUID
130 *
131 * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
132 */
133 public const UUID_TYPE_HASH_MD5 = 3;
134
135 /**
136 * Version 4 (random) UUID
137 *
138 * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
139 */
140 public const UUID_TYPE_RANDOM = 4;
141
142 /**
143 * Version 5 (name-based and hashed with SHA1) UUID
144 *
145 * @link https://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
146 */
147 public const UUID_TYPE_HASH_SHA1 = 5;
148
149 /**
150 * Version 6 (ordered-time) UUID
151 *
152 * This is named `UUID_TYPE_PEABODY`, since the specification is still in
153 * draft form, and the primary author/editor's name is Brad Peabody.
154 *
155 * @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft
156 * @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs
157 */
158 public const UUID_TYPE_PEABODY = 6;
159
160 /**
161 * DCE Security principal domain
162 *
163 * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1
164 */
165 public const DCE_DOMAIN_PERSON = 0;
166
167 /**
168 * DCE Security group domain
169 *
170 * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1
171 */
172 public const DCE_DOMAIN_GROUP = 1;
173
174 /**
175 * DCE Security organization domain
176 *
177 * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1
178 */
179 public const DCE_DOMAIN_ORG = 2;
180
181 /**
182 * DCE Security domain string names
183 *
184 * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1
185 */
186 public const DCE_DOMAIN_NAMES = [
187 self::DCE_DOMAIN_PERSON => 'person',
188 self::DCE_DOMAIN_GROUP => 'group',
189 self::DCE_DOMAIN_ORG => 'org',
190 ];
191
192 /**
193 * @var UuidFactoryInterface|null
194 */
195 private static $factory = null;
196
197 /**
198 * @var CodecInterface
199 */
200 protected $codec;
201
202 /**
203 * The fields that make up this UUID
204 *
205 * @var Rfc4122FieldsInterface
206 */
207 protected $fields;
208
209 /**
210 * @var NumberConverterInterface
211 */
212 protected $numberConverter;
213
214 /**
215 * @var TimeConverterInterface
216 */
217 protected $timeConverter;
218
219 /**
220 * Creates a universally unique identifier (UUID) from an array of fields
221 *
222 * Unless you're making advanced use of this library to generate identifiers
223 * that deviate from RFC 4122, you probably do not want to instantiate a
224 * UUID directly. Use the static methods, instead:
225 *
226 * ```
227 * use Ramsey\Uuid\Uuid;
228 *
229 * $timeBasedUuid = Uuid::uuid1();
230 * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/');
231 * $randomUuid = Uuid::uuid4();
232 * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/');
233 * ```
234 *
235 * @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
236 * @param NumberConverterInterface $numberConverter The number converter to use
237 * for converting hex values to/from integers
238 * @param CodecInterface $codec The codec to use when encoding or decoding
239 * UUID strings
240 * @param TimeConverterInterface $timeConverter The time converter to use
241 * for converting timestamps extracted from a UUID to unix timestamps
242 */
243 public function __construct(
244 Rfc4122FieldsInterface $fields,
245 NumberConverterInterface $numberConverter,
246 CodecInterface $codec,
247 TimeConverterInterface $timeConverter
248 ) {
249 $this->fields = $fields;
250 $this->codec = $codec;
251 $this->numberConverter = $numberConverter;
252 $this->timeConverter = $timeConverter;
253 }
254
255 /**
256 * @psalm-return non-empty-string
257 */
258 public function __toString(): string
259 {
260 return $this->toString();
261 }
262
263 /**
264 * Converts the UUID to a string for JSON serialization
265 */
266 public function jsonSerialize(): string
267 {
268 return $this->toString();
269 }
270
271 /**
272 * Converts the UUID to a string for PHP serialization
273 */
274 public function serialize(): string
275 {
276 return $this->toString();
277 }
278
279 /**
280 * Re-constructs the object from its serialized form
281 *
282 * @param string $serialized The serialized PHP string to unserialize into
283 * a UuidInterface instance
284 *
285 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
286 */
287 public function unserialize($serialized): void
288 {
289 /** @var \Ramsey\Uuid\Uuid $uuid */
290 $uuid = self::fromString($serialized);
291 $this->codec = $uuid->codec;
292 $this->numberConverter = $uuid->numberConverter;
293 $this->fields = $uuid->fields;
294 $this->timeConverter = $uuid->timeConverter;
295 }
296
297 public function compareTo(UuidInterface $other): int
298 {
299 $compare = strcmp($this->toString(), $other->toString());
300
301 if ($compare < 0) {
302 return -1;
303 }
304
305 if ($compare > 0) {
306 return 1;
307 }
308
309 return 0;
310 }
311
312 public function equals(?object $other): bool
313 {
314 if (!$other instanceof UuidInterface) {
315 return false;
316 }
317
318 return $this->compareTo($other) === 0;
319 }
320
321 /**
322 * @psalm-return non-empty-string
323 */
324 public function getBytes(): string
325 {
326 return $this->codec->encodeBinary($this);
327 }
328
329 public function getFields(): FieldsInterface
330 {
331 return $this->fields;
332 }
333
334 public function getHex(): Hexadecimal
335 {
336 return new Hexadecimal(str_replace('-', '', $this->toString()));
337 }
338
339 public function getInteger(): IntegerObject
340 {
341 return new IntegerObject($this->numberConverter->fromHex($this->getHex()->toString()));
342 }
343
344 /**
345 * @psalm-return non-empty-string
346 */
347 public function toString(): string
348 {
349 return $this->codec->encode($this);
350 }
351
352 /**
353 * Returns the factory used to create UUIDs
354 */
355 public static function getFactory(): UuidFactoryInterface
356 {
357 if (self::$factory === null) {
358 self::$factory = new UuidFactory();
359 }
360
361 return self::$factory;
362 }
363
364 /**
365 * Sets the factory used to create UUIDs
366 *
367 * @param UuidFactoryInterface $factory A factory that will be used by this
368 * class to create UUIDs
369 */
370 public static function setFactory(UuidFactoryInterface $factory): void
371 {
372 self::$factory = $factory;
373 }
374
375 /**
376 * Creates a UUID from a byte string
377 *
378 * @param string $bytes A binary string
379 *
380 * @return UuidInterface A UuidInterface instance created from a binary
381 * string representation
382 *
383 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
384 * but under constant factory setups, this method operates in functionally pure manners
385 */
386 public static function fromBytes(string $bytes): UuidInterface
387 {
388 return self::getFactory()->fromBytes($bytes);
389 }
390
391 /**
392 * Creates a UUID from the string standard representation
393 *
394 * @param string $uuid A hexadecimal string
395 *
396 * @return UuidInterface A UuidInterface instance created from a hexadecimal
397 * string representation
398 *
399 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
400 * but under constant factory setups, this method operates in functionally pure manners
401 */
402 public static function fromString(string $uuid): UuidInterface
403 {
404 return self::getFactory()->fromString($uuid);
405 }
406
407 /**
408 * Creates a UUID from a DateTimeInterface instance
409 *
410 * @param DateTimeInterface $dateTime The date and time
411 * @param Hexadecimal|null $node A 48-bit number representing the hardware
412 * address
413 * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
414 * that could arise when the clock is set backwards in time or if the
415 * node ID changes
416 *
417 * @return UuidInterface A UuidInterface instance that represents a
418 * version 1 UUID created from a DateTimeInterface instance
419 */
420 public static function fromDateTime(
421 DateTimeInterface $dateTime,
422 ?Hexadecimal $node = null,
423 ?int $clockSeq = null
424 ): UuidInterface {
425 return self::getFactory()->fromDateTime($dateTime, $node, $clockSeq);
426 }
427
428 /**
429 * Creates a UUID from a 128-bit integer string
430 *
431 * @param string $integer String representation of 128-bit integer
432 *
433 * @return UuidInterface A UuidInterface instance created from the string
434 * representation of a 128-bit integer
435 *
436 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
437 * but under constant factory setups, this method operates in functionally pure manners
438 */
439 public static function fromInteger(string $integer): UuidInterface
440 {
441 return self::getFactory()->fromInteger($integer);
442 }
443
444 /**
445 * Returns true if the provided string is a valid UUID
446 *
447 * @param string $uuid A string to validate as a UUID
448 *
449 * @return bool True if the string is a valid UUID, false otherwise
450 *
451 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
452 * but under constant factory setups, this method operates in functionally pure manners
453 */
454 public static function isValid(string $uuid): bool
455 {
456 return self::getFactory()->getValidator()->validate($uuid);
457 }
458
459 /**
460 * Returns a version 1 (time-based) UUID from a host ID, sequence number,
461 * and the current time
462 *
463 * @param Hexadecimal|int|string|null $node A 48-bit number representing the
464 * hardware address; this number may be represented as an integer or a
465 * hexadecimal string
466 * @param int $clockSeq A 14-bit number used to help avoid duplicates that
467 * could arise when the clock is set backwards in time or if the node ID
468 * changes
469 *
470 * @return UuidInterface A UuidInterface instance that represents a
471 * version 1 UUID
472 */
473 public static function uuid1($node = null, ?int $clockSeq = null): UuidInterface
474 {
475 return self::getFactory()->uuid1($node, $clockSeq);
476 }
477
478 /**
479 * Returns a version 2 (DCE Security) UUID from a local domain, local
480 * identifier, host ID, clock sequence, and the current time
481 *
482 * @param int $localDomain The local domain to use when generating bytes,
483 * according to DCE Security
484 * @param IntegerObject|null $localIdentifier The local identifier for the
485 * given domain; this may be a UID or GID on POSIX systems, if the local
486 * domain is person or group, or it may be a site-defined identifier
487 * if the local domain is org
488 * @param Hexadecimal|null $node A 48-bit number representing the hardware
489 * address
490 * @param int|null $clockSeq A 14-bit number used to help avoid duplicates
491 * that could arise when the clock is set backwards in time or if the
492 * node ID changes (in a version 2 UUID, the lower 8 bits of this number
493 * are replaced with the domain).
494 *
495 * @return UuidInterface A UuidInterface instance that represents a
496 * version 2 UUID
497 */
498 public static function uuid2(
499 int $localDomain,
500 ?IntegerObject $localIdentifier = null,
501 ?Hexadecimal $node = null,
502 ?int $clockSeq = null
503 ): UuidInterface {
504 return self::getFactory()->uuid2($localDomain, $localIdentifier, $node, $clockSeq);
505 }
506
507 /**
508 * Returns a version 3 (name-based) UUID based on the MD5 hash of a
509 * namespace ID and a name
510 *
511 * @param string|UuidInterface $ns The namespace (must be a valid UUID)
512 * @param string $name The name to use for creating a UUID
513 *
514 * @return UuidInterface A UuidInterface instance that represents a
515 * version 3 UUID
516 *
517 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
518 * but under constant factory setups, this method operates in functionally pure manners
519 */
520 public static function uuid3($ns, string $name): UuidInterface
521 {
522 return self::getFactory()->uuid3($ns, $name);
523 }
524
525 /**
526 * Returns a version 4 (random) UUID
527 *
528 * @return UuidInterface A UuidInterface instance that represents a
529 * version 4 UUID
530 */
531 public static function uuid4(): UuidInterface
532 {
533 return self::getFactory()->uuid4();
534 }
535
536 /**
537 * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a
538 * namespace ID and a name
539 *
540 * @param string|UuidInterface $ns The namespace (must be a valid UUID)
541 * @param string $name The name to use for creating a UUID
542 *
543 * @return UuidInterface A UuidInterface instance that represents a
544 * version 5 UUID
545 *
546 * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants,
547 * but under constant factory setups, this method operates in functionally pure manners
548 */
549 public static function uuid5($ns, string $name): UuidInterface
550 {
551 return self::getFactory()->uuid5($ns, $name);
552 }
553
554 /**
555 * Returns a version 6 (ordered-time) UUID from a host ID, sequence number,
556 * and the current time
557 *
558 * @param Hexadecimal|null $node A 48-bit number representing the hardware
559 * address
560 * @param int $clockSeq A 14-bit number used to help avoid duplicates that
561 * could arise when the clock is set backwards in time or if the node ID
562 * changes
563 *
564 * @return UuidInterface A UuidInterface instance that represents a
565 * version 6 UUID
566 */
567 public static function uuid6(
568 ?Hexadecimal $node = null,
569 ?int $clockSeq = null
570 ): UuidInterface {
571 return self::getFactory()->uuid6($node, $clockSeq);
572 }
573}
574