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;
16
 
17
use DateTimeInterface;
18
use Ramsey\Uuid\Builder\UuidBuilderInterface;
19
use Ramsey\Uuid\Codec\CodecInterface;
20
use Ramsey\Uuid\Converter\NumberConverterInterface;
21
use Ramsey\Uuid\Converter\TimeConverterInterface;
22
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
23
use Ramsey\Uuid\Generator\DefaultTimeGenerator;
24
use Ramsey\Uuid\Generator\NameGeneratorInterface;
25
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
26
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
27
use Ramsey\Uuid\Generator\UnixTimeGenerator;
28
use Ramsey\Uuid\Lazy\LazyUuidFromString;
29
use Ramsey\Uuid\Provider\NodeProviderInterface;
30
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
31
use Ramsey\Uuid\Type\Hexadecimal;
32
use Ramsey\Uuid\Type\Integer as IntegerObject;
33
use Ramsey\Uuid\Type\Time;
34
use Ramsey\Uuid\Validator\ValidatorInterface;
35
 
36
use function bin2hex;
37
use function hex2bin;
38
use function pack;
39
use function str_pad;
40
use function strtolower;
41
use function substr;
42
use function substr_replace;
43
use function unpack;
44
 
45
use const STR_PAD_LEFT;
46
 
47
class UuidFactory implements UuidFactoryInterface
48
{
49
    private CodecInterface $codec;
50
    private DceSecurityGeneratorInterface $dceSecurityGenerator;
51
    private NameGeneratorInterface $nameGenerator;
52
    private NodeProviderInterface $nodeProvider;
53
    private NumberConverterInterface $numberConverter;
54
    private RandomGeneratorInterface $randomGenerator;
55
    private TimeConverterInterface $timeConverter;
56
    private TimeGeneratorInterface $timeGenerator;
57
    private TimeGeneratorInterface $unixTimeGenerator;
58
    private UuidBuilderInterface $uuidBuilder;
59
    private ValidatorInterface $validator;
60
 
61
    /**
62
     * @var bool whether the feature set was provided from outside, or we can
63
     *     operate under "default" assumptions
64
     */
65
    private bool $isDefaultFeatureSet;
66
 
67
    /**
68
     * @param FeatureSet|null $features A set of available features in the current environment
69
     */
70
    public function __construct(?FeatureSet $features = null)
71
    {
72
        $this->isDefaultFeatureSet = $features === null;
73
 
74
        $features = $features ?: new FeatureSet();
75
 
76
        $this->codec = $features->getCodec();
77
        $this->dceSecurityGenerator = $features->getDceSecurityGenerator();
78
        $this->nameGenerator = $features->getNameGenerator();
79
        $this->nodeProvider = $features->getNodeProvider();
80
        $this->numberConverter = $features->getNumberConverter();
81
        $this->randomGenerator = $features->getRandomGenerator();
82
        $this->timeConverter = $features->getTimeConverter();
83
        $this->timeGenerator = $features->getTimeGenerator();
84
        $this->uuidBuilder = $features->getBuilder();
85
        $this->validator = $features->getValidator();
86
        $this->unixTimeGenerator = $features->getUnixTimeGenerator();
87
    }
88
 
89
    /**
90
     * Returns the codec used by this factory
91
     */
92
    public function getCodec(): CodecInterface
93
    {
94
        return $this->codec;
95
    }
96
 
97
    /**
98
     * Sets the codec to use for this factory
99
     *
100
     * @param CodecInterface $codec A UUID encoder-decoder
101
     */
102
    public function setCodec(CodecInterface $codec): void
103
    {
104
        $this->isDefaultFeatureSet = false;
105
 
106
        $this->codec = $codec;
107
    }
108
 
109
    /**
110
     * Returns the name generator used by this factory
111
     */
112
    public function getNameGenerator(): NameGeneratorInterface
113
    {
114
        return $this->nameGenerator;
115
    }
116
 
117
    /**
118
     * Sets the name generator to use for this factory
119
     *
120
     * @param NameGeneratorInterface $nameGenerator A generator to generate
121
     *     binary data, based on a namespace and name
122
     */
123
    public function setNameGenerator(NameGeneratorInterface $nameGenerator): void
124
    {
125
        $this->isDefaultFeatureSet = false;
126
 
127
        $this->nameGenerator = $nameGenerator;
128
    }
129
 
130
    /**
131
     * Returns the node provider used by this factory
132
     */
133
    public function getNodeProvider(): NodeProviderInterface
134
    {
135
        return $this->nodeProvider;
136
    }
137
 
138
    /**
139
     * Returns the random generator used by this factory
140
     */
141
    public function getRandomGenerator(): RandomGeneratorInterface
142
    {
143
        return $this->randomGenerator;
144
    }
145
 
146
    /**
147
     * Returns the time generator used by this factory
148
     */
149
    public function getTimeGenerator(): TimeGeneratorInterface
150
    {
151
        return $this->timeGenerator;
152
    }
153
 
154
    /**
155
     * Sets the time generator to use for this factory
156
     *
157
     * @param TimeGeneratorInterface $generator A generator to generate binary
158
     *     data, based on the time
159
     */
160
    public function setTimeGenerator(TimeGeneratorInterface $generator): void
161
    {
162
        $this->isDefaultFeatureSet = false;
163
 
164
        $this->timeGenerator = $generator;
165
    }
166
 
167
    /**
168
     * Returns the DCE Security generator used by this factory
169
     */
170
    public function getDceSecurityGenerator(): DceSecurityGeneratorInterface
171
    {
172
        return $this->dceSecurityGenerator;
173
    }
174
 
175
    /**
176
     * Sets the DCE Security generator to use for this factory
177
     *
178
     * @param DceSecurityGeneratorInterface $generator A generator to generate
179
     *     binary data, based on a local domain and local identifier
180
     */
181
    public function setDceSecurityGenerator(DceSecurityGeneratorInterface $generator): void
182
    {
183
        $this->isDefaultFeatureSet = false;
184
 
185
        $this->dceSecurityGenerator = $generator;
186
    }
187
 
188
    /**
189
     * Returns the number converter used by this factory
190
     */
191
    public function getNumberConverter(): NumberConverterInterface
192
    {
193
        return $this->numberConverter;
194
    }
195
 
196
    /**
197
     * Sets the random generator to use for this factory
198
     *
199
     * @param RandomGeneratorInterface $generator A generator to generate binary
200
     *     data, based on some random input
201
     */
202
    public function setRandomGenerator(RandomGeneratorInterface $generator): void
203
    {
204
        $this->isDefaultFeatureSet = false;
205
 
206
        $this->randomGenerator = $generator;
207
    }
208
 
209
    /**
210
     * Sets the number converter to use for this factory
211
     *
212
     * @param NumberConverterInterface $converter A converter to use for working
213
     *     with large integers (i.e. integers greater than PHP_INT_MAX)
214
     */
215
    public function setNumberConverter(NumberConverterInterface $converter): void
216
    {
217
        $this->isDefaultFeatureSet = false;
218
 
219
        $this->numberConverter = $converter;
220
    }
221
 
222
    /**
223
     * Returns the UUID builder used by this factory
224
     */
225
    public function getUuidBuilder(): UuidBuilderInterface
226
    {
227
        return $this->uuidBuilder;
228
    }
229
 
230
    /**
231
     * Sets the UUID builder to use for this factory
232
     *
233
     * @param UuidBuilderInterface $builder A builder for constructing instances
234
     *     of UuidInterface
235
     */
236
    public function setUuidBuilder(UuidBuilderInterface $builder): void
237
    {
238
        $this->isDefaultFeatureSet = false;
239
 
240
        $this->uuidBuilder = $builder;
241
    }
242
 
243
    /**
244
     * @psalm-mutation-free
245
     */
246
    public function getValidator(): ValidatorInterface
247
    {
248
        return $this->validator;
249
    }
250
 
251
    /**
252
     * Sets the validator to use for this factory
253
     *
254
     * @param ValidatorInterface $validator A validator to use for validating
255
     *     whether a string is a valid UUID
256
     */
257
    public function setValidator(ValidatorInterface $validator): void
258
    {
259
        $this->isDefaultFeatureSet = false;
260
 
261
        $this->validator = $validator;
262
    }
263
 
264
    /**
265
     * @psalm-pure
266
     */
267
    public function fromBytes(string $bytes): UuidInterface
268
    {
269
        return $this->codec->decodeBytes($bytes);
270
    }
271
 
272
    /**
273
     * @psalm-pure
274
     */
275
    public function fromString(string $uuid): UuidInterface
276
    {
277
        $uuid = strtolower($uuid);
278
 
279
        return $this->codec->decode($uuid);
280
    }
281
 
282
    /**
283
     * @psalm-pure
284
     */
285
    public function fromInteger(string $integer): UuidInterface
286
    {
287
        $hex = $this->numberConverter->toHex($integer);
288
        $hex = str_pad($hex, 32, '0', STR_PAD_LEFT);
289
 
290
        return $this->fromString($hex);
291
    }
292
 
293
    public function fromDateTime(
294
        DateTimeInterface $dateTime,
295
        ?Hexadecimal $node = null,
296
        ?int $clockSeq = null
297
    ): UuidInterface {
298
        $timeProvider = new FixedTimeProvider(
299
            new Time($dateTime->format('U'), $dateTime->format('u'))
300
        );
301
 
302
        $timeGenerator = new DefaultTimeGenerator(
303
            $this->nodeProvider,
304
            $this->timeConverter,
305
            $timeProvider
306
        );
307
 
308
        $nodeHex = $node ? $node->toString() : null;
309
 
310
        $bytes = $timeGenerator->generate($nodeHex, $clockSeq);
311
 
312
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
313
    }
314
 
315
    /**
316
     * @psalm-pure
317
     */
318
    public function fromHexadecimal(Hexadecimal $hex): UuidInterface
319
    {
320
        return $this->codec->decode($hex->__toString());
321
    }
322
 
323
    /**
324
     * @inheritDoc
325
     */
326
    public function uuid1($node = null, ?int $clockSeq = null): UuidInterface
327
    {
328
        $bytes = $this->timeGenerator->generate($node, $clockSeq);
329
 
330
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
331
    }
332
 
333
    public function uuid2(
334
        int $localDomain,
335
        ?IntegerObject $localIdentifier = null,
336
        ?Hexadecimal $node = null,
337
        ?int $clockSeq = null
338
    ): UuidInterface {
339
        $bytes = $this->dceSecurityGenerator->generate(
340
            $localDomain,
341
            $localIdentifier,
342
            $node,
343
            $clockSeq
344
        );
345
 
346
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY);
347
    }
348
 
349
    /**
350
     * @inheritDoc
351
     * @psalm-pure
352
     */
353
    public function uuid3($ns, string $name): UuidInterface
354
    {
355
        return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_MD5, 'md5');
356
    }
357
 
358
    public function uuid4(): UuidInterface
359
    {
360
        $bytes = $this->randomGenerator->generate(16);
361
 
362
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM);
363
    }
364
 
365
    /**
366
     * @inheritDoc
367
     * @psalm-pure
368
     */
369
    public function uuid5($ns, string $name): UuidInterface
370
    {
371
        return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1');
372
    }
373
 
374
    public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface
375
    {
376
        $nodeHex = $node ? $node->toString() : null;
377
        $bytes = $this->timeGenerator->generate($nodeHex, $clockSeq);
378
 
379
        // Rearrange the bytes, according to the UUID version 6 specification.
380
        $v6 = $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5]
381
            . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3];
382
        $v6 = bin2hex($v6);
383
 
384
        // Drop the first four bits, while adding an empty four bits for the
385
        // version field. This allows us to reconstruct the correct time from
386
        // the bytes of this UUID.
387
        $v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3));
388
        $v6Bytes .= substr($bytes, 8);
389
 
390
        return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME);
391
    }
392
 
393
    /**
394
     * Returns a version 7 (Unix Epoch time) UUID
395
     *
396
     * @param DateTimeInterface|null $dateTime An optional date/time from which
397
     *     to create the version 7 UUID. If not provided, the UUID is generated
398
     *     using the current date/time.
399
     *
400
     * @return UuidInterface A UuidInterface instance that represents a
401
     *     version 7 UUID
402
     */
403
    public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
404
    {
405
        assert($this->unixTimeGenerator instanceof UnixTimeGenerator);
406
        $bytes = $this->unixTimeGenerator->generate(null, null, $dateTime);
407
 
408
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
409
    }
410
 
411
    /**
412
     * Returns a version 8 (Custom) UUID
413
     *
414
     * The bytes provided may contain any value according to your application's
415
     * needs. Be aware, however, that other applications may not understand the
416
     * semantics of the value.
417
     *
418
     * @param string $bytes A 16-byte octet string. This is an open blob
419
     *     of data that you may fill with 128 bits of information. Be aware,
420
     *     however, bits 48 through 51 will be replaced with the UUID version
421
     *     field, and bits 64 and 65 will be replaced with the UUID variant. You
422
     *     MUST NOT rely on these bits for your application needs.
423
     *
424
     * @return UuidInterface A UuidInterface instance that represents a
425
     *     version 8 UUID
426
     */
427
    public function uuid8(string $bytes): UuidInterface
428
    {
429
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM);
430
    }
431
 
432
    /**
433
     * Returns a Uuid created from the provided byte string
434
     *
435
     * Uses the configured builder and codec and the provided byte string to
436
     * construct a Uuid object.
437
     *
438
     * @param string $bytes The byte string from which to construct a UUID
439
     *
440
     * @return UuidInterface An instance of UuidInterface, created from the
441
     *     provided bytes
442
     *
443
     * @psalm-pure
444
     */
445
    public function uuid(string $bytes): UuidInterface
446
    {
447
        /** @psalm-suppress ImpurePropertyFetch */
448
        return $this->uuidBuilder->build($this->codec, $bytes);
449
    }
450
 
451
    /**
452
     * Returns a version 3 or 5 namespaced Uuid
453
     *
454
     * @param string|UuidInterface $ns The namespace (must be a valid UUID)
455
     * @param string $name The name to hash together with the namespace
456
     * @param int $version The version of UUID to create (3 or 5)
457
     * @param string $hashAlgorithm The hashing algorithm to use when hashing
458
     *     together the namespace and name
459
     *
460
     * @return UuidInterface An instance of UuidInterface, created by hashing
461
     *     together the provided namespace and name
462
     *
463
     * @psalm-pure
464
     */
465
    private function uuidFromNsAndName(
466
        UuidInterface | string $ns,
467
        string $name,
468
        int $version,
469
        string $hashAlgorithm
470
    ): UuidInterface {
471
        if (!($ns instanceof UuidInterface)) {
472
            $ns = $this->fromString($ns);
473
        }
474
 
475
        $bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm);
476
 
477
        return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version);
478
    }
479
 
480
    /**
481
     * Returns an RFC 4122 variant Uuid, created from the provided bytes and version
482
     *
483
     * @param string $bytes The byte string to convert to a UUID
484
     * @param int $version The RFC 4122 version to apply to the UUID
485
     *
486
     * @return UuidInterface An instance of UuidInterface, created from the
487
     *     byte string and version
488
     *
489
     * @psalm-pure
490
     */
491
    private function uuidFromBytesAndVersion(string $bytes, int $version): UuidInterface
492
    {
493
        /** @var array $unpackedTime */
494
        $unpackedTime = unpack('n*', substr($bytes, 6, 2));
495
        $timeHi = (int) $unpackedTime[1];
496
        $timeHiAndVersion = pack('n*', BinaryUtils::applyVersion($timeHi, $version));
497
 
498
        /** @var array $unpackedClockSeq */
499
        $unpackedClockSeq = unpack('n*', substr($bytes, 8, 2));
500
        $clockSeqHi = (int) $unpackedClockSeq[1];
501
        $clockSeqHiAndReserved = pack('n*', BinaryUtils::applyVariant($clockSeqHi));
502
 
503
        $bytes = substr_replace($bytes, $timeHiAndVersion, 6, 2);
504
        $bytes = substr_replace($bytes, $clockSeqHiAndReserved, 8, 2);
505
 
506
        if ($this->isDefaultFeatureSet) {
507
            return LazyUuidFromString::fromBytes($bytes);
508
        }
509
 
510
        /** @psalm-suppress ImpureVariable */
511
        return $this->uuid($bytes);
512
    }
513
}