AbstractUid.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Uid;
  11. /**
  12. * @author Nicolas Grekas <p@tchwork.com>
  13. */
  14. abstract class AbstractUid implements \JsonSerializable, \Stringable
  15. {
  16. /**
  17. * The identifier in its canonic representation.
  18. */
  19. protected string $uid;
  20. /**
  21. * Whether the passed value is valid for the constructor of the current class.
  22. */
  23. abstract public static function isValid(string $uid): bool;
  24. /**
  25. * Creates an AbstractUid from an identifier represented in any of the supported formats.
  26. *
  27. * @throws \InvalidArgumentException When the passed value is not valid
  28. */
  29. abstract public static function fromString(string $uid): static;
  30. /**
  31. * @throws \InvalidArgumentException When the passed value is not valid
  32. */
  33. public static function fromBinary(string $uid): static
  34. {
  35. if (16 !== \strlen($uid)) {
  36. throw new \InvalidArgumentException('Invalid binary uid provided.');
  37. }
  38. return static::fromString($uid);
  39. }
  40. /**
  41. * @throws \InvalidArgumentException When the passed value is not valid
  42. */
  43. public static function fromBase58(string $uid): static
  44. {
  45. if (22 !== \strlen($uid)) {
  46. throw new \InvalidArgumentException('Invalid base-58 uid provided.');
  47. }
  48. return static::fromString($uid);
  49. }
  50. /**
  51. * @throws \InvalidArgumentException When the passed value is not valid
  52. */
  53. public static function fromBase32(string $uid): static
  54. {
  55. if (26 !== \strlen($uid)) {
  56. throw new \InvalidArgumentException('Invalid base-32 uid provided.');
  57. }
  58. return static::fromString($uid);
  59. }
  60. /**
  61. * @throws \InvalidArgumentException When the passed value is not valid
  62. */
  63. public static function fromRfc4122(string $uid): static
  64. {
  65. if (36 !== \strlen($uid)) {
  66. throw new \InvalidArgumentException('Invalid RFC4122 uid provided.');
  67. }
  68. return static::fromString($uid);
  69. }
  70. /**
  71. * Returns the identifier as a raw binary string.
  72. */
  73. abstract public function toBinary(): string;
  74. /**
  75. * Returns the identifier as a base58 case-sensitive string.
  76. *
  77. * @example 2AifFTC3zXgZzK5fPrrprL (len=22)
  78. */
  79. public function toBase58(): string
  80. {
  81. return strtr(sprintf('%022s', BinaryUtil::toBase($this->toBinary(), BinaryUtil::BASE58)), '0', '1');
  82. }
  83. /**
  84. * Returns the identifier as a base32 case-insensitive string.
  85. *
  86. * @see https://tools.ietf.org/html/rfc4648#section-6
  87. *
  88. * @example 09EJ0S614A9FXVG9C5537Q9ZE1 (len=26)
  89. */
  90. public function toBase32(): string
  91. {
  92. $uid = bin2hex($this->toBinary());
  93. $uid = sprintf('%02s%04s%04s%04s%04s%04s%04s',
  94. base_convert(substr($uid, 0, 2), 16, 32),
  95. base_convert(substr($uid, 2, 5), 16, 32),
  96. base_convert(substr($uid, 7, 5), 16, 32),
  97. base_convert(substr($uid, 12, 5), 16, 32),
  98. base_convert(substr($uid, 17, 5), 16, 32),
  99. base_convert(substr($uid, 22, 5), 16, 32),
  100. base_convert(substr($uid, 27, 5), 16, 32)
  101. );
  102. return strtr($uid, 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ');
  103. }
  104. /**
  105. * Returns the identifier as a RFC4122 case-insensitive string.
  106. *
  107. * @see https://tools.ietf.org/html/rfc4122#section-3
  108. *
  109. * @example 09748193-048a-4bfb-b825-8528cf74fdc1 (len=36)
  110. */
  111. public function toRfc4122(): string
  112. {
  113. // don't use uuid_unparse(), it's slower
  114. $uuid = bin2hex($this->toBinary());
  115. $uuid = substr_replace($uuid, '-', 8, 0);
  116. $uuid = substr_replace($uuid, '-', 13, 0);
  117. $uuid = substr_replace($uuid, '-', 18, 0);
  118. return substr_replace($uuid, '-', 23, 0);
  119. }
  120. /**
  121. * Returns the identifier as a prefixed hexadecimal case insensitive string.
  122. *
  123. * @example 0x09748193048a4bfbb8258528cf74fdc1 (len=34)
  124. */
  125. public function toHex(): string
  126. {
  127. return '0x'.bin2hex($this->toBinary());
  128. }
  129. /**
  130. * Returns whether the argument is an AbstractUid and contains the same value as the current instance.
  131. */
  132. public function equals(mixed $other): bool
  133. {
  134. if (!$other instanceof self) {
  135. return false;
  136. }
  137. return $this->uid === $other->uid;
  138. }
  139. public function compare(self $other): int
  140. {
  141. return (\strlen($this->uid) - \strlen($other->uid)) ?: ($this->uid <=> $other->uid);
  142. }
  143. final public function toString(): string
  144. {
  145. return $this->__toString();
  146. }
  147. public function __toString(): string
  148. {
  149. return $this->uid;
  150. }
  151. public function jsonSerialize(): string
  152. {
  153. return $this->uid;
  154. }
  155. }