Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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
 
13
declare(strict_types=1);
14
 
15
namespace Ramsey\Uuid\Rfc4122;
16
 
17
use Ramsey\Uuid\Exception\InvalidArgumentException;
18
use Ramsey\Uuid\Fields\SerializableFieldsTrait;
19
use Ramsey\Uuid\Type\Hexadecimal;
20
use Ramsey\Uuid\Uuid;
21
 
22
use function bin2hex;
23
use function dechex;
24
use function hexdec;
25
use function sprintf;
26
use function str_pad;
27
use function strlen;
28
use function substr;
29
use function unpack;
30
 
31
use const STR_PAD_LEFT;
32
 
33
/**
34
 * RFC 4122 variant UUIDs are comprised of a set of named fields
35
 *
36
 * Internally, this class represents the fields together as a 16-byte binary
37
 * string.
38
 *
39
 * @psalm-immutable
40
 */
41
final class Fields implements FieldsInterface
42
{
43
    use MaxTrait;
44
    use NilTrait;
45
    use SerializableFieldsTrait;
46
    use VariantTrait;
47
    use VersionTrait;
48
 
49
    /**
50
     * @param string $bytes A 16-byte binary string representation of a UUID
51
     *
52
     * @throws InvalidArgumentException if the byte string is not exactly 16 bytes
53
     * @throws InvalidArgumentException if the byte string does not represent an RFC 4122 UUID
54
     * @throws InvalidArgumentException if the byte string does not contain a valid version
55
     */
56
    public function __construct(private string $bytes)
57
    {
58
        if (strlen($this->bytes) !== 16) {
59
            throw new InvalidArgumentException(
60
                'The byte string must be 16 bytes long; '
61
                . 'received ' . strlen($this->bytes) . ' bytes'
62
            );
63
        }
64
 
65
        if (!$this->isCorrectVariant()) {
66
            throw new InvalidArgumentException(
67
                'The byte string received does not conform to the RFC 4122 variant'
68
            );
69
        }
70
 
71
        if (!$this->isCorrectVersion()) {
72
            throw new InvalidArgumentException(
73
                'The byte string received does not contain a valid RFC 4122 version'
74
            );
75
        }
76
    }
77
 
78
    public function getBytes(): string
79
    {
80
        return $this->bytes;
81
    }
82
 
83
    public function getClockSeq(): Hexadecimal
84
    {
85
        if ($this->isMax()) {
86
            $clockSeq = 0xffff;
87
        } elseif ($this->isNil()) {
88
            $clockSeq = 0x0000;
89
        } else {
90
            $clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
91
        }
92
 
93
        return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
94
    }
95
 
96
    public function getClockSeqHiAndReserved(): Hexadecimal
97
    {
98
        return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1)));
99
    }
100
 
101
    public function getClockSeqLow(): Hexadecimal
102
    {
103
        return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1)));
104
    }
105
 
106
    public function getNode(): Hexadecimal
107
    {
108
        return new Hexadecimal(bin2hex(substr($this->bytes, 10)));
109
    }
110
 
111
    public function getTimeHiAndVersion(): Hexadecimal
112
    {
113
        return new Hexadecimal(bin2hex(substr($this->bytes, 6, 2)));
114
    }
115
 
116
    public function getTimeLow(): Hexadecimal
117
    {
118
        return new Hexadecimal(bin2hex(substr($this->bytes, 0, 4)));
119
    }
120
 
121
    public function getTimeMid(): Hexadecimal
122
    {
123
        return new Hexadecimal(bin2hex(substr($this->bytes, 4, 2)));
124
    }
125
 
126
    /**
127
     * Returns the full 60-bit timestamp, without the version
128
     *
129
     * For version 2 UUIDs, the time_low field is the local identifier and
130
     * should not be returned as part of the time. For this reason, we set the
131
     * bottom 32 bits of the timestamp to 0's. As a result, there is some loss
132
     * of fidelity of the timestamp, for version 2 UUIDs. The timestamp can be
133
     * off by a range of 0 to 429.4967295 seconds (or 7 minutes, 9 seconds, and
134
     * 496730 microseconds).
135
     *
136
     * For version 6 UUIDs, the timestamp order is reversed from the typical RFC
137
     * 4122 order (the time bits are in the correct bit order, so that it is
138
     * monotonically increasing). In returning the timestamp value, we put the
139
     * bits in the order: time_low + time_mid + time_hi.
140
     */
141
    public function getTimestamp(): Hexadecimal
142
    {
143
        $timestamp = match ($this->getVersion()) {
144
            Uuid::UUID_TYPE_DCE_SECURITY => sprintf(
145
                '%03x%04s%08s',
146
                hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
147
                $this->getTimeMid()->toString(),
148
                ''
149
            ),
150
            Uuid::UUID_TYPE_REORDERED_TIME => sprintf(
151
                '%08s%04s%03x',
152
                $this->getTimeLow()->toString(),
153
                $this->getTimeMid()->toString(),
154
                hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff
155
            ),
156
            // The Unix timestamp in version 7 UUIDs is a 48-bit number,
157
            // but for consistency, we will return a 60-bit number, padded
158
            // to the left with zeros.
159
            Uuid::UUID_TYPE_UNIX_TIME => sprintf(
160
                '%011s%04s',
161
                $this->getTimeLow()->toString(),
162
                $this->getTimeMid()->toString(),
163
            ),
164
            default => sprintf(
165
                '%03x%04s%08s',
166
                hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
167
                $this->getTimeMid()->toString(),
168
                $this->getTimeLow()->toString()
169
            ),
170
        };
171
 
172
        return new Hexadecimal($timestamp);
173
    }
174
 
175
    public function getVersion(): ?int
176
    {
177
        if ($this->isNil() || $this->isMax()) {
178
            return null;
179
        }
180
 
181
        /** @var int[] $parts */
182
        $parts = unpack('n*', $this->bytes);
183
 
184
        return $parts[4] >> 12;
185
    }
186
 
187
    private function isCorrectVariant(): bool
188
    {
189
        if ($this->isNil() || $this->isMax()) {
190
            return true;
191
        }
192
 
193
        return $this->getVariant() === Uuid::RFC_4122;
194
    }
195
}