514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * This file is part of the ramsey/uuid library
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view the LICENSE
 | 
						|
 * file that was distributed with this source code.
 | 
						|
 *
 | 
						|
 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
 | 
						|
 * @license http://opensource.org/licenses/MIT MIT
 | 
						|
 */
 | 
						|
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace Ramsey\Uuid;
 | 
						|
 | 
						|
use DateTimeInterface;
 | 
						|
use Ramsey\Uuid\Builder\UuidBuilderInterface;
 | 
						|
use Ramsey\Uuid\Codec\CodecInterface;
 | 
						|
use Ramsey\Uuid\Converter\NumberConverterInterface;
 | 
						|
use Ramsey\Uuid\Converter\TimeConverterInterface;
 | 
						|
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
 | 
						|
use Ramsey\Uuid\Generator\DefaultTimeGenerator;
 | 
						|
use Ramsey\Uuid\Generator\NameGeneratorInterface;
 | 
						|
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
 | 
						|
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
 | 
						|
use Ramsey\Uuid\Generator\UnixTimeGenerator;
 | 
						|
use Ramsey\Uuid\Lazy\LazyUuidFromString;
 | 
						|
use Ramsey\Uuid\Provider\NodeProviderInterface;
 | 
						|
use Ramsey\Uuid\Provider\Time\FixedTimeProvider;
 | 
						|
use Ramsey\Uuid\Type\Hexadecimal;
 | 
						|
use Ramsey\Uuid\Type\Integer as IntegerObject;
 | 
						|
use Ramsey\Uuid\Type\Time;
 | 
						|
use Ramsey\Uuid\Validator\ValidatorInterface;
 | 
						|
 | 
						|
use function bin2hex;
 | 
						|
use function hex2bin;
 | 
						|
use function pack;
 | 
						|
use function str_pad;
 | 
						|
use function strtolower;
 | 
						|
use function substr;
 | 
						|
use function substr_replace;
 | 
						|
use function unpack;
 | 
						|
 | 
						|
use const STR_PAD_LEFT;
 | 
						|
 | 
						|
class UuidFactory implements UuidFactoryInterface
 | 
						|
{
 | 
						|
    private CodecInterface $codec;
 | 
						|
    private DceSecurityGeneratorInterface $dceSecurityGenerator;
 | 
						|
    private NameGeneratorInterface $nameGenerator;
 | 
						|
    private NodeProviderInterface $nodeProvider;
 | 
						|
    private NumberConverterInterface $numberConverter;
 | 
						|
    private RandomGeneratorInterface $randomGenerator;
 | 
						|
    private TimeConverterInterface $timeConverter;
 | 
						|
    private TimeGeneratorInterface $timeGenerator;
 | 
						|
    private TimeGeneratorInterface $unixTimeGenerator;
 | 
						|
    private UuidBuilderInterface $uuidBuilder;
 | 
						|
    private ValidatorInterface $validator;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var bool whether the feature set was provided from outside, or we can
 | 
						|
     *     operate under "default" assumptions
 | 
						|
     */
 | 
						|
    private bool $isDefaultFeatureSet;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param FeatureSet|null $features A set of available features in the current environment
 | 
						|
     */
 | 
						|
    public function __construct(?FeatureSet $features = null)
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = $features === null;
 | 
						|
 | 
						|
        $features = $features ?: new FeatureSet();
 | 
						|
 | 
						|
        $this->codec = $features->getCodec();
 | 
						|
        $this->dceSecurityGenerator = $features->getDceSecurityGenerator();
 | 
						|
        $this->nameGenerator = $features->getNameGenerator();
 | 
						|
        $this->nodeProvider = $features->getNodeProvider();
 | 
						|
        $this->numberConverter = $features->getNumberConverter();
 | 
						|
        $this->randomGenerator = $features->getRandomGenerator();
 | 
						|
        $this->timeConverter = $features->getTimeConverter();
 | 
						|
        $this->timeGenerator = $features->getTimeGenerator();
 | 
						|
        $this->uuidBuilder = $features->getBuilder();
 | 
						|
        $this->validator = $features->getValidator();
 | 
						|
        $this->unixTimeGenerator = $features->getUnixTimeGenerator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the codec used by this factory
 | 
						|
     */
 | 
						|
    public function getCodec(): CodecInterface
 | 
						|
    {
 | 
						|
        return $this->codec;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the codec to use for this factory
 | 
						|
     *
 | 
						|
     * @param CodecInterface $codec A UUID encoder-decoder
 | 
						|
     */
 | 
						|
    public function setCodec(CodecInterface $codec): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->codec = $codec;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the name generator used by this factory
 | 
						|
     */
 | 
						|
    public function getNameGenerator(): NameGeneratorInterface
 | 
						|
    {
 | 
						|
        return $this->nameGenerator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the name generator to use for this factory
 | 
						|
     *
 | 
						|
     * @param NameGeneratorInterface $nameGenerator A generator to generate
 | 
						|
     *     binary data, based on a namespace and name
 | 
						|
     */
 | 
						|
    public function setNameGenerator(NameGeneratorInterface $nameGenerator): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->nameGenerator = $nameGenerator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the node provider used by this factory
 | 
						|
     */
 | 
						|
    public function getNodeProvider(): NodeProviderInterface
 | 
						|
    {
 | 
						|
        return $this->nodeProvider;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the random generator used by this factory
 | 
						|
     */
 | 
						|
    public function getRandomGenerator(): RandomGeneratorInterface
 | 
						|
    {
 | 
						|
        return $this->randomGenerator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the time generator used by this factory
 | 
						|
     */
 | 
						|
    public function getTimeGenerator(): TimeGeneratorInterface
 | 
						|
    {
 | 
						|
        return $this->timeGenerator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the time generator to use for this factory
 | 
						|
     *
 | 
						|
     * @param TimeGeneratorInterface $generator A generator to generate binary
 | 
						|
     *     data, based on the time
 | 
						|
     */
 | 
						|
    public function setTimeGenerator(TimeGeneratorInterface $generator): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->timeGenerator = $generator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the DCE Security generator used by this factory
 | 
						|
     */
 | 
						|
    public function getDceSecurityGenerator(): DceSecurityGeneratorInterface
 | 
						|
    {
 | 
						|
        return $this->dceSecurityGenerator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the DCE Security generator to use for this factory
 | 
						|
     *
 | 
						|
     * @param DceSecurityGeneratorInterface $generator A generator to generate
 | 
						|
     *     binary data, based on a local domain and local identifier
 | 
						|
     */
 | 
						|
    public function setDceSecurityGenerator(DceSecurityGeneratorInterface $generator): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->dceSecurityGenerator = $generator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the number converter used by this factory
 | 
						|
     */
 | 
						|
    public function getNumberConverter(): NumberConverterInterface
 | 
						|
    {
 | 
						|
        return $this->numberConverter;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the random generator to use for this factory
 | 
						|
     *
 | 
						|
     * @param RandomGeneratorInterface $generator A generator to generate binary
 | 
						|
     *     data, based on some random input
 | 
						|
     */
 | 
						|
    public function setRandomGenerator(RandomGeneratorInterface $generator): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->randomGenerator = $generator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the number converter to use for this factory
 | 
						|
     *
 | 
						|
     * @param NumberConverterInterface $converter A converter to use for working
 | 
						|
     *     with large integers (i.e. integers greater than PHP_INT_MAX)
 | 
						|
     */
 | 
						|
    public function setNumberConverter(NumberConverterInterface $converter): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->numberConverter = $converter;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the UUID builder used by this factory
 | 
						|
     */
 | 
						|
    public function getUuidBuilder(): UuidBuilderInterface
 | 
						|
    {
 | 
						|
        return $this->uuidBuilder;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the UUID builder to use for this factory
 | 
						|
     *
 | 
						|
     * @param UuidBuilderInterface $builder A builder for constructing instances
 | 
						|
     *     of UuidInterface
 | 
						|
     */
 | 
						|
    public function setUuidBuilder(UuidBuilderInterface $builder): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->uuidBuilder = $builder;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @psalm-mutation-free
 | 
						|
     */
 | 
						|
    public function getValidator(): ValidatorInterface
 | 
						|
    {
 | 
						|
        return $this->validator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Sets the validator to use for this factory
 | 
						|
     *
 | 
						|
     * @param ValidatorInterface $validator A validator to use for validating
 | 
						|
     *     whether a string is a valid UUID
 | 
						|
     */
 | 
						|
    public function setValidator(ValidatorInterface $validator): void
 | 
						|
    {
 | 
						|
        $this->isDefaultFeatureSet = false;
 | 
						|
 | 
						|
        $this->validator = $validator;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function fromBytes(string $bytes): UuidInterface
 | 
						|
    {
 | 
						|
        return $this->codec->decodeBytes($bytes);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function fromString(string $uuid): UuidInterface
 | 
						|
    {
 | 
						|
        $uuid = strtolower($uuid);
 | 
						|
 | 
						|
        return $this->codec->decode($uuid);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function fromInteger(string $integer): UuidInterface
 | 
						|
    {
 | 
						|
        $hex = $this->numberConverter->toHex($integer);
 | 
						|
        $hex = str_pad($hex, 32, '0', STR_PAD_LEFT);
 | 
						|
 | 
						|
        return $this->fromString($hex);
 | 
						|
    }
 | 
						|
 | 
						|
    public function fromDateTime(
 | 
						|
        DateTimeInterface $dateTime,
 | 
						|
        ?Hexadecimal $node = null,
 | 
						|
        ?int $clockSeq = null
 | 
						|
    ): UuidInterface {
 | 
						|
        $timeProvider = new FixedTimeProvider(
 | 
						|
            new Time($dateTime->format('U'), $dateTime->format('u'))
 | 
						|
        );
 | 
						|
 | 
						|
        $timeGenerator = new DefaultTimeGenerator(
 | 
						|
            $this->nodeProvider,
 | 
						|
            $this->timeConverter,
 | 
						|
            $timeProvider
 | 
						|
        );
 | 
						|
 | 
						|
        $nodeHex = $node ? $node->toString() : null;
 | 
						|
 | 
						|
        $bytes = $timeGenerator->generate($nodeHex, $clockSeq);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function fromHexadecimal(Hexadecimal $hex): UuidInterface
 | 
						|
    {
 | 
						|
        return $this->codec->decode($hex->__toString());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritDoc
 | 
						|
     */
 | 
						|
    public function uuid1($node = null, ?int $clockSeq = null): UuidInterface
 | 
						|
    {
 | 
						|
        $bytes = $this->timeGenerator->generate($node, $clockSeq);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME);
 | 
						|
    }
 | 
						|
 | 
						|
    public function uuid2(
 | 
						|
        int $localDomain,
 | 
						|
        ?IntegerObject $localIdentifier = null,
 | 
						|
        ?Hexadecimal $node = null,
 | 
						|
        ?int $clockSeq = null
 | 
						|
    ): UuidInterface {
 | 
						|
        $bytes = $this->dceSecurityGenerator->generate(
 | 
						|
            $localDomain,
 | 
						|
            $localIdentifier,
 | 
						|
            $node,
 | 
						|
            $clockSeq
 | 
						|
        );
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritDoc
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function uuid3($ns, string $name): UuidInterface
 | 
						|
    {
 | 
						|
        return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_MD5, 'md5');
 | 
						|
    }
 | 
						|
 | 
						|
    public function uuid4(): UuidInterface
 | 
						|
    {
 | 
						|
        $bytes = $this->randomGenerator->generate(16);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @inheritDoc
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function uuid5($ns, string $name): UuidInterface
 | 
						|
    {
 | 
						|
        return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1');
 | 
						|
    }
 | 
						|
 | 
						|
    public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface
 | 
						|
    {
 | 
						|
        $nodeHex = $node ? $node->toString() : null;
 | 
						|
        $bytes = $this->timeGenerator->generate($nodeHex, $clockSeq);
 | 
						|
 | 
						|
        // Rearrange the bytes, according to the UUID version 6 specification.
 | 
						|
        $v6 = $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5]
 | 
						|
            . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3];
 | 
						|
        $v6 = bin2hex($v6);
 | 
						|
 | 
						|
        // Drop the first four bits, while adding an empty four bits for the
 | 
						|
        // version field. This allows us to reconstruct the correct time from
 | 
						|
        // the bytes of this UUID.
 | 
						|
        $v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3));
 | 
						|
        $v6Bytes .= substr($bytes, 8);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a version 7 (Unix Epoch time) UUID
 | 
						|
     *
 | 
						|
     * @param DateTimeInterface|null $dateTime An optional date/time from which
 | 
						|
     *     to create the version 7 UUID. If not provided, the UUID is generated
 | 
						|
     *     using the current date/time.
 | 
						|
     *
 | 
						|
     * @return UuidInterface A UuidInterface instance that represents a
 | 
						|
     *     version 7 UUID
 | 
						|
     */
 | 
						|
    public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface
 | 
						|
    {
 | 
						|
        assert($this->unixTimeGenerator instanceof UnixTimeGenerator);
 | 
						|
        $bytes = $this->unixTimeGenerator->generate(null, null, $dateTime);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a version 8 (Custom) UUID
 | 
						|
     *
 | 
						|
     * The bytes provided may contain any value according to your application's
 | 
						|
     * needs. Be aware, however, that other applications may not understand the
 | 
						|
     * semantics of the value.
 | 
						|
     *
 | 
						|
     * @param string $bytes A 16-byte octet string. This is an open blob
 | 
						|
     *     of data that you may fill with 128 bits of information. Be aware,
 | 
						|
     *     however, bits 48 through 51 will be replaced with the UUID version
 | 
						|
     *     field, and bits 64 and 65 will be replaced with the UUID variant. You
 | 
						|
     *     MUST NOT rely on these bits for your application needs.
 | 
						|
     *
 | 
						|
     * @return UuidInterface A UuidInterface instance that represents a
 | 
						|
     *     version 8 UUID
 | 
						|
     */
 | 
						|
    public function uuid8(string $bytes): UuidInterface
 | 
						|
    {
 | 
						|
        return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a Uuid created from the provided byte string
 | 
						|
     *
 | 
						|
     * Uses the configured builder and codec and the provided byte string to
 | 
						|
     * construct a Uuid object.
 | 
						|
     *
 | 
						|
     * @param string $bytes The byte string from which to construct a UUID
 | 
						|
     *
 | 
						|
     * @return UuidInterface An instance of UuidInterface, created from the
 | 
						|
     *     provided bytes
 | 
						|
     *
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    public function uuid(string $bytes): UuidInterface
 | 
						|
    {
 | 
						|
        /** @psalm-suppress ImpurePropertyFetch */
 | 
						|
        return $this->uuidBuilder->build($this->codec, $bytes);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a version 3 or 5 namespaced Uuid
 | 
						|
     *
 | 
						|
     * @param string|UuidInterface $ns The namespace (must be a valid UUID)
 | 
						|
     * @param string $name The name to hash together with the namespace
 | 
						|
     * @param int $version The version of UUID to create (3 or 5)
 | 
						|
     * @param string $hashAlgorithm The hashing algorithm to use when hashing
 | 
						|
     *     together the namespace and name
 | 
						|
     *
 | 
						|
     * @return UuidInterface An instance of UuidInterface, created by hashing
 | 
						|
     *     together the provided namespace and name
 | 
						|
     *
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    private function uuidFromNsAndName(
 | 
						|
        UuidInterface | string $ns,
 | 
						|
        string $name,
 | 
						|
        int $version,
 | 
						|
        string $hashAlgorithm
 | 
						|
    ): UuidInterface {
 | 
						|
        if (!($ns instanceof UuidInterface)) {
 | 
						|
            $ns = $this->fromString($ns);
 | 
						|
        }
 | 
						|
 | 
						|
        $bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm);
 | 
						|
 | 
						|
        return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an RFC 4122 variant Uuid, created from the provided bytes and version
 | 
						|
     *
 | 
						|
     * @param string $bytes The byte string to convert to a UUID
 | 
						|
     * @param int $version The RFC 4122 version to apply to the UUID
 | 
						|
     *
 | 
						|
     * @return UuidInterface An instance of UuidInterface, created from the
 | 
						|
     *     byte string and version
 | 
						|
     *
 | 
						|
     * @psalm-pure
 | 
						|
     */
 | 
						|
    private function uuidFromBytesAndVersion(string $bytes, int $version): UuidInterface
 | 
						|
    {
 | 
						|
        /** @var array $unpackedTime */
 | 
						|
        $unpackedTime = unpack('n*', substr($bytes, 6, 2));
 | 
						|
        $timeHi = (int) $unpackedTime[1];
 | 
						|
        $timeHiAndVersion = pack('n*', BinaryUtils::applyVersion($timeHi, $version));
 | 
						|
 | 
						|
        /** @var array $unpackedClockSeq */
 | 
						|
        $unpackedClockSeq = unpack('n*', substr($bytes, 8, 2));
 | 
						|
        $clockSeqHi = (int) $unpackedClockSeq[1];
 | 
						|
        $clockSeqHiAndReserved = pack('n*', BinaryUtils::applyVariant($clockSeqHi));
 | 
						|
 | 
						|
        $bytes = substr_replace($bytes, $timeHiAndVersion, 6, 2);
 | 
						|
        $bytes = substr_replace($bytes, $clockSeqHiAndReserved, 8, 2);
 | 
						|
 | 
						|
        if ($this->isDefaultFeatureSet) {
 | 
						|
            return LazyUuidFromString::fromBytes($bytes);
 | 
						|
        }
 | 
						|
 | 
						|
        /** @psalm-suppress ImpureVariable */
 | 
						|
        return $this->uuid($bytes);
 | 
						|
    }
 | 
						|
}
 |