AbstractUid.php 5.5 KB

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