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\Codec; 16 17use Ramsey\Uuid\Builder\UuidBuilderInterface; 18use Ramsey\Uuid\Exception\InvalidArgumentException; 19use Ramsey\Uuid\Exception\InvalidUuidStringException; 20use Ramsey\Uuid\Rfc4122\FieldsInterface; 21use Ramsey\Uuid\Uuid; 22use Ramsey\Uuid\UuidInterface; 23 24use function hex2bin; 25use function implode; 26use function str_replace; 27use function strlen; 28use function substr; 29 30/** 31 * StringCodec encodes and decodes RFC 4122 UUIDs 32 * 33 * @link http://tools.ietf.org/html/rfc4122 34 * 35 * @psalm-immutable 36 */ 37class StringCodec implements CodecInterface 38{ 39 /** 40 * @var UuidBuilderInterface 41 */ 42 private $builder; 43 44 /** 45 * Constructs a StringCodec 46 * 47 * @param UuidBuilderInterface $builder The builder to use when encoding UUIDs 48 */ 49 public function __construct(UuidBuilderInterface $builder) 50 { 51 $this->builder = $builder; 52 } 53 54 public function encode(UuidInterface $uuid): string 55 { 56 /** @var FieldsInterface $fields */ 57 $fields = $uuid->getFields(); 58 59 return $fields->getTimeLow()->toString() 60 . '-' 61 . $fields->getTimeMid()->toString() 62 . '-' 63 . $fields->getTimeHiAndVersion()->toString() 64 . '-' 65 . $fields->getClockSeqHiAndReserved()->toString() 66 . $fields->getClockSeqLow()->toString() 67 . '-' 68 . $fields->getNode()->toString(); 69 } 70 71 /** 72 * @psalm-return non-empty-string 73 * @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty 74 * @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty 75 */ 76 public function encodeBinary(UuidInterface $uuid): string 77 { 78 return $uuid->getFields()->getBytes(); 79 } 80 81 /** 82 * @throws InvalidUuidStringException 83 * 84 * @inheritDoc 85 */ 86 public function decode(string $encodedUuid): UuidInterface 87 { 88 return $this->builder->build($this, $this->getBytes($encodedUuid)); 89 } 90 91 public function decodeBytes(string $bytes): UuidInterface 92 { 93 if (strlen($bytes) !== 16) { 94 throw new InvalidArgumentException( 95 '$bytes string should contain 16 characters.' 96 ); 97 } 98 99 return $this->builder->build($this, $bytes); 100 } 101 102 /** 103 * Returns the UUID builder 104 */ 105 protected function getBuilder(): UuidBuilderInterface 106 { 107 return $this->builder; 108 } 109 110 /** 111 * Returns a byte string of the UUID 112 */ 113 protected function getBytes(string $encodedUuid): string 114 { 115 $parsedUuid = str_replace( 116 ['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'], 117 '', 118 $encodedUuid 119 ); 120 121 $components = [ 122 substr($parsedUuid, 0, 8), 123 substr($parsedUuid, 8, 4), 124 substr($parsedUuid, 12, 4), 125 substr($parsedUuid, 16, 4), 126 substr($parsedUuid, 20), 127 ]; 128 129 if (!Uuid::isValid(implode('-', $components))) { 130 throw new InvalidUuidStringException( 131 'Invalid UUID string: ' . $encodedUuid 132 ); 133 } 134 135 return (string) hex2bin($parsedUuid); 136 } 137} 138