upgraded dependencies

This commit is contained in:
RafficMohammed
2023-01-08 01:59:16 +05:30
parent 51056e3aad
commit f9ae387337
6895 changed files with 133617 additions and 178680 deletions

View File

@@ -1,5 +1,3 @@
MIT License
Copyright (c) 2012-2021 Ben Ramsey <ben@benramsey.com>
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -1,44 +1,29 @@
# ramsey/uuid
<h1 align="center">ramsey/uuid</h1>
*IMPORTANT: This is the 3.x series. Please upgrade to the 4.x series.*
<p align="center">
<strong>A PHP library for generating and working with UUIDs.</strong>
</p>
*NOTICE: Formerly known as `rhumsaa/uuid`, The package and namespace names have
changed to `ramsey/uuid` and `Ramsey\Uuid`, respectively.*
<p align="center">
<a href="https://github.com/ramsey/uuid"><img src="http://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square" alt="Source Code"></a>
<a href="https://packagist.org/packages/ramsey/uuid"><img src="https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=release" alt="Download Package"></a>
<a href="https://php.net"><img src="https://img.shields.io/packagist/php-v/ramsey/uuid.svg?style=flat-square&colorB=%238892BF" alt="PHP Programming Language"></a>
<a href="https://github.com/ramsey/uuid/blob/main/LICENSE"><img src="https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan" alt="Read License"></a>
<a href="https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml"><img src="https://img.shields.io/github/workflow/status/ramsey/uuid/build/main?logo=github&style=flat-square" alt="Build Status"></a>
<a href="https://codecov.io/gh/ramsey/uuid"><img src="https://img.shields.io/codecov/c/gh/ramsey/uuid?label=codecov&logo=codecov&style=flat-square" alt="Codecov Code Coverage"></a>
<a href="https://shepherd.dev/github/ramsey/uuid"><img src="https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fshepherd.dev%2Fgithub%2Framsey%2Fuuid%2Fcoverage" alt="Psalm Type Coverage"></a>
</p>
[![Source Code][badge-source]][source]
[![Series][badge-series]][series]
[![Upgrade][badge-upgrade]][upgrade]
[![PHP Version][badge-php]][php]
[![Software License][badge-license]][license]
[![Build Status][badge-build]][build]
[![Coverage Status][badge-coverage]][coverage]
ramsey/uuid is a PHP library for generating and working with universally unique
identifiers (UUIDs).
ramsey/uuid is a PHP 5.4+ library for generating and working with
[RFC 4122][rfc4122] version 1, 3, 4, and 5 universally unique identifiers
(UUID).
This project adheres to a [Contributor Code of Conduct][conduct]. By
participating in this project and its community, you are expected to uphold this
code.
From [Wikipedia](http://en.wikipedia.org/wiki/Universally_unique_identifier):
> The intent of UUIDs is to enable distributed systems to uniquely identify
> information without significant central coordination. In this context the word
> unique should be taken to mean "practically unique" rather than "guaranteed
> unique". Since the identifiers have a finite size, it is possible for two
> differing items to share the same identifier. The identifier size and
> generation process need to be selected so as to make this sufficiently
> improbable in practice. Anyone can create a UUID and use it to identify
> something with reasonable confidence that the same identifier will never be
> unintentionally created by anyone to identify something else. Information
> labeled with UUIDs can therefore be later combined into a single database
> without needing to resolve identifier (ID) conflicts.
This project adheres to a [code of conduct](CODE_OF_CONDUCT.md).
By participating in this project and its community, you are expected to
uphold this code.
Much inspiration for this library came from the [Java][javauuid] and
[Python][pyuuid] UUID libraries.
## Installation
The preferred method of installation is via [Composer][]. Run the following
@@ -49,110 +34,38 @@ command to install the package and add it as a requirement to your project's
composer require ramsey/uuid
```
## Upgrading to Version 4
## Upgrading from 2.x to 3.x
See the documentation for a thorough upgrade guide:
While we have made significant internal changes to the library, we have made
every effort to ensure a seamless upgrade path from the 2.x series of this
library to 3.x.
* [Upgrading ramsey/uuid Version 3 to 4](https://uuid.ramsey.dev/en/latest/upgrading/3-to-4.html)
One major breaking change is the transition from the `Rhumsaa` root namespace to
`Ramsey`. In most cases, all you will need is to change the namespace to
`Ramsey` in your code, and everything will "just work."
Here are full details on the breaking changes to the public API of this library:
1. All namespace references of `Rhumsaa` have changed to `Ramsey`. Simply change
the namespace to `Ramsey` in your code and everything should work.
2. The console application has moved to
[ramsey/uuid-console](https://packagist.org/packages/ramsey/uuid-console).
If using the console functionality, use Composer to require
`ramsey/uuid-console`.
3. The Doctrine field type mapping has moved to
[ramsey/uuid-doctrine](https://packagist.org/packages/ramsey/uuid-doctrine).
If using the Doctrine functionality, use Composer to require
`ramsey/uuid-doctrine`.
## What to do if you see a "rhumsaa/uuid is abandoned" message
When installing your project's dependencies using Composer, you might see the
following message:
```
Package rhumsaa/uuid is abandoned, you should avoid using it. Use
ramsey/uuid instead.
```
Don't panic. Simply execute the following commands with Composer:
``` bash
composer remove rhumsaa/uuid
composer require ramsey/uuid=^2.9
```
After doing so, you will have the latest ramsey/uuid package in the 2.x series,
and there will be no need to modify any code; the namespace in the 2.x series is
still `Rhumsaa`.
## Requirements
Some methods in this library have requirements due to integer size restrictions
on 32-bit and 64-bit builds of PHP. A 64-bit build of PHP and the
[Moontoast\Math][] library are recommended. However, this library is designed to
work on 32-bit builds of PHP without Moontoast\Math, with some degraded
functionality. Please check the API documentation for more information.
If a particular requirement is not present, then an
`UnsatisfiedDependencyException` is thrown, allowing one to catch a bad call in
an environment where the call is not supported and gracefully degrade.
## Examples
See the [cookbook on the wiki][wiki-cookbook] for more examples and approaches
to specific use-cases.
```php
<?php
require 'vendor/autoload.php';
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
try {
// Generate a version 1 (time-based) UUID object
$uuid1 = Uuid::uuid1();
echo $uuid1->toString() . "\n"; // i.e. e4eaaaf2-d142-11e1-b3e4-080027620cdd
// Generate a version 3 (name-based and hashed with MD5) UUID object
$uuid3 = Uuid::uuid3(Uuid::NAMESPACE_DNS, 'php.net');
echo $uuid3->toString() . "\n"; // i.e. 11a38b9a-b3da-360f-9353-a5a725514269
// Generate a version 4 (random) UUID object
$uuid4 = Uuid::uuid4();
echo $uuid4->toString() . "\n"; // i.e. 25769c6c-d34d-4bfe-ba98-e0ee856f3e7a
// Generate a version 5 (name-based and hashed with SHA1) UUID object
$uuid5 = Uuid::uuid5(Uuid::NAMESPACE_DNS, 'php.net');
echo $uuid5->toString() . "\n"; // i.e. c4a760a8-dbcf-5254-a0d9-6a4474bd1b62
} catch (UnsatisfiedDependencyException $e) {
// Some dependency was not met. Either the method cannot be called on a
// 32-bit system, or it can, but it relies on Moontoast\Math to be present.
echo 'Caught exception: ' . $e->getMessage() . "\n";
}
```
## Documentation
Please see <https://uuid.ramsey.dev> for documentation, tips, examples, and
frequently asked questions.
## Contributing
Contributions are welcome! Please read [CONTRIBUTING.md][] for details.
Contributions are welcome! To contribute, please familiarize yourself with
[CONTRIBUTING.md](CONTRIBUTING.md).
## Coordinated Disclosure
Keeping user information safe and secure is a top priority, and we welcome the
contribution of external security researchers. If you believe you've found a
security issue in software that is maintained in this repository, please read
[SECURITY.md][] for instructions on submitting a vulnerability report.
## ramsey/uuid for Enterprise
Available as part of the Tidelift Subscription.
The maintainers of ramsey/uuid and thousands of other packages are working with
Tidelift to deliver commercial support and maintenance for the open source
packages you use to build your applications. Save time, reduce risk, and improve
code health, while paying the maintainers of the exact packages you use.
[Learn more.](https://tidelift.com/subscription/pkg/packagist-ramsey-uuid?utm_source=undefined&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
## Copyright and License
@@ -160,28 +73,11 @@ The ramsey/uuid library is copyright © [Ben Ramsey](https://benramsey.com/) and
licensed for use under the MIT License (MIT). Please see [LICENSE][] for more
information.
[rfc4122]: http://tools.ietf.org/html/rfc4122
[conduct]: https://github.com/ramsey/uuid/blob/master/.github/CODE_OF_CONDUCT.md
[conduct]: https://github.com/ramsey/uuid/blob/main/CODE_OF_CONDUCT.md
[javauuid]: http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html
[pyuuid]: http://docs.python.org/3/library/uuid.html
[composer]: http://getcomposer.org/
[moontoast\math]: https://packagist.org/packages/moontoast/math
[wiki-cookbook]: https://github.com/ramsey/uuid/wiki/Ramsey%5CUuid-Cookbook
[contributing.md]: https://github.com/ramsey/uuid/blob/master/.github/CONTRIBUTING.md
[badge-source]: https://img.shields.io/badge/source-ramsey/uuid-blue.svg?style=flat-square
[badge-series]: https://img.shields.io/badge/series-3.x-darkcyan.svg?style=flat-square
[badge-upgrade]: https://img.shields.io/packagist/v/ramsey/uuid.svg?style=flat-square&label=upgrade&colorB=darkred
[badge-license]: https://img.shields.io/packagist/l/ramsey/uuid.svg?style=flat-square&colorB=darkcyan
[badge-php]: https://img.shields.io/packagist/php-v/ramsey/uuid/3.x-dev.svg?style=flat-square&colorB=%238892BF
[badge-build]: https://img.shields.io/github/actions/workflow/status/ramsey/uuid/continuous-integration.yml?branch=3.x&logo=github&style=flat-square
[badge-coverage]: https://img.shields.io/codecov/c/gh/ramsey/uuid/3.x.svg?style=flat-square&logo=codecov
[source]: https://github.com/ramsey/uuid/tree/3.x
[series]: https://packagist.org/packages/ramsey/uuid
[upgrade]: https://packagist.org/packages/ramsey/uuid
[license]: https://github.com/ramsey/uuid/blob/master/LICENSE
[php]: https://php.net
[build]: https://github.com/ramsey/uuid/actions/workflows/continuous-integration.yml?query=branch%3A3.x
[coverage]: https://app.codecov.io/gh/ramsey/uuid/branch/3.x
[contributing.md]: https://github.com/ramsey/uuid/blob/main/CONTRIBUTING.md
[security.md]: https://github.com/ramsey/uuid/blob/main/SECURITY.md
[license]: https://github.com/ramsey/uuid/blob/main/LICENSE

View File

@@ -1,67 +1,65 @@
{
"name": "ramsey/uuid",
"type": "library",
"description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
"keywords": ["uuid", "identifier", "guid"],
"homepage": "https://github.com/ramsey/uuid",
"license": "MIT",
"authors": [
{
"name": "Ben Ramsey",
"email": "ben@benramsey.com",
"homepage": "https://benramsey.com"
},
{
"name": "Marijn Huizendveld",
"email": "marijn.huizendveld@gmail.com"
},
{
"name": "Thibaud Fabre",
"email": "thibaud@aztech.io"
}
"description": "A PHP library for generating and working with universally unique identifiers (UUIDs).",
"keywords": [
"uuid",
"identifier",
"guid"
],
"license": "MIT",
"require": {
"php": "^5.4 | ^7.0 | ^8.0",
"php": "^7.2 || ^8.0",
"ext-json": "*",
"paragonie/random_compat": "^1 | ^2 | ^9.99.99",
"symfony/polyfill-ctype": "^1.8"
},
"require-dev": {
"codeception/aspect-mock": "^1 | ^2",
"doctrine/annotations": "^1.2",
"goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2",
"mockery/mockery": "^0.9.11 | ^1",
"moontoast/math": "^1.1",
"nikic/php-parser": "<=4.5.0",
"paragonie/random-lib": "^2",
"php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0",
"squizlabs/php_codesniffer": "^3.5",
"yoast/phpunit-polyfills": "^1.0"
},
"suggest": {
"ext-ctype": "Provides support for PHP Ctype functions",
"ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
"ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator",
"ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
"moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
"ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type.",
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"phpstan/extension-installer": true,
"dealerdirect/phpcodesniffer-composer-installer": true,
"ergebnis/composer-normalize": true,
"captainhook/plugin-composer": true
}
"brick/math": "^0.8 || ^0.9",
"ramsey/collection": "^1.0",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-php80": "^1.14"
},
"replace": {
"rhumsaa/uuid": "self.version"
},
"require-dev": {
"captainhook/captainhook": "^5.10",
"captainhook/plugin-composer": "^5.3",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
"doctrine/annotations": "^1.8",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
"moontoast/math": "^1.1",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-mockery": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpunit/phpunit": "^8.5 || ^9",
"slevomat/coding-standard": "^7.0",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
"ext-ctype": "Enables faster processing of character classification using ctype functions.",
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
},
"config": {
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-main": "4.x-dev"
},
"captainhook": {
"force-install": true
}
},
"autoload": {
"psr-4": {
"Ramsey\\Uuid\\": "src/"
@@ -72,24 +70,38 @@
},
"autoload-dev": {
"psr-4": {
"Ramsey\\Uuid\\Benchmark\\": "tests/benchmark/",
"Ramsey\\Uuid\\StaticAnalysis\\": "tests/static-analysis/",
"Ramsey\\Uuid\\Test\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"analyze": [
"@phpstan",
"@psalm"
],
"build:clean": "git clean -fX build/",
"lint": "parallel-lint src tests",
"phpcs": "phpcs src tests --standard=psr2 -sp --colors",
"lint:paths": "parallel-lint",
"phpbench": "phpbench run",
"phpcbf": "phpcbf -vpw --cache=build/cache/phpcs.cache",
"phpcs": "phpcs --cache=build/cache/phpcs.cache",
"phpstan": [
"phpstan analyse --no-progress",
"phpstan analyse -c phpstan-tests.neon --no-progress"
],
"phpunit": "phpunit --verbose --colors=always",
"phpunit-coverage": "phpunit --verbose --colors=always --coverage-html build/coverage",
"psalm": "psalm --show-info=false --config=psalm.xml",
"test": [
"@lint",
"@phpbench",
"@phpcs",
"@phpstan",
"@psalm",
"@phpunit"
]
},
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"rss": "https://github.com/ramsey/uuid/releases.atom",
"source": "https://github.com/ramsey/uuid",
"wiki": "https://github.com/ramsey/uuid/wiki"
}
}

View File

@@ -1,5 +1,17 @@
<?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;
/**
@@ -8,32 +20,42 @@ namespace Ramsey\Uuid;
class BinaryUtils
{
/**
* Applies the RFC 4122 variant field to the `clock_seq_hi_and_reserved` field
* Applies the RFC 4122 variant field to the 16-bit clock sequence
*
* @param $clockSeqHi
* @return int The high field of the clock sequence multiplexed with the variant
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*
* @param int $clockSeq The 16-bit clock sequence value before the RFC 4122
* variant is applied
*
* @return int The 16-bit clock sequence multiplexed with the UUID variant
*
* @psalm-pure
*/
public static function applyVariant($clockSeqHi)
public static function applyVariant(int $clockSeq): int
{
// Set the variant to RFC 4122
$clockSeqHi = $clockSeqHi & 0x3f;
$clockSeqHi |= 0x80;
$clockSeq = $clockSeq & 0x3fff;
$clockSeq |= 0x8000;
return $clockSeqHi;
return $clockSeq;
}
/**
* Applies the RFC 4122 version number to the `time_hi_and_version` field
* Applies the RFC 4122 version number to the 16-bit `time_hi_and_version` field
*
* @param string $timeHi
* @param integer $version
* @return int The high field of the timestamp multiplexed with the version number
* @link http://tools.ietf.org/html/rfc4122#section-4.1.3
* @link http://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*
* @param int $timeHi The value of the 16-bit `time_hi_and_version` field
* before the RFC 4122 version is applied
* @param int $version The RFC 4122 version to apply to the `time_hi` field
*
* @return int The 16-bit time_hi field of the timestamp multiplexed with
* the UUID version number
*
* @psalm-pure
*/
public static function applyVersion($timeHi, $version)
public static function applyVersion(int $timeHi, int $version): int
{
$timeHi = hexdec($timeHi) & 0x0fff;
$timeHi = $timeHi & 0x0fff;
$timeHi |= $version << 12;
return $timeHi;

View File

@@ -0,0 +1,80 @@
<?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\Builder;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Traversable;
/**
* A collection of UuidBuilderInterface objects
*
* @extends AbstractCollection<UuidBuilderInterface>
*/
class BuilderCollection extends AbstractCollection
{
public function getType(): string
{
return UuidBuilderInterface::class;
}
/**
* @psalm-mutation-free
* @psalm-suppress ImpureMethodCall
* @psalm-suppress InvalidTemplateParam
*/
public function getIterator(): Traversable
{
return parent::getIterator();
}
/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress RedundantConditionGivenDocblockType
*/
public function unserialize($serialized): void
{
/** @var array<array-key, UuidBuilderInterface> $data */
$data = unserialize($serialized, [
'allowed_classes' => [
BrickMathCalculator::class,
GenericNumberConverter::class,
GenericTimeConverter::class,
GuidBuilder::class,
NonstandardUuidBuilder::class,
PhpTimeConverter::class,
Rfc4122UuidBuilder::class,
],
]);
$this->data = array_filter(
$data,
function ($unserialized): bool {
return $unserialized instanceof UuidBuilderInterface;
}
);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,48 +8,19 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Builder;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
/**
* DefaultUuidBuilder is the default UUID builder for ramsey/uuid; it builds
* instances of Uuid objects
* @deprecated Transition to {@see Rfc4122UuidBuilder}.
*
* @psalm-immutable
*/
class DefaultUuidBuilder implements UuidBuilderInterface
class DefaultUuidBuilder extends Rfc4122UuidBuilder
{
/**
* @var NumberConverterInterface
*/
private $converter;
/**
* Constructs the DefaultUuidBuilder
*
* @param NumberConverterInterface $converter The number converter to use when constructing the Uuid
*/
public function __construct(NumberConverterInterface $converter)
{
$this->converter = $converter;
}
/**
* Builds a Uuid
*
* @param CodecInterface $codec The codec to use for building this Uuid
* @param array $fields An array of fields from which to construct the Uuid;
* see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
* @return Uuid
*/
public function build(CodecInterface $codec, array $fields)
{
return new Uuid($fields, $this->converter, $codec);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,47 +8,69 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Builder;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\Time\DegradedTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\DegradedUuid;
use Ramsey\Uuid\Rfc4122\Fields as Rfc4122Fields;
use Ramsey\Uuid\UuidInterface;
/**
* DegradedUuidBuilder builds instances of DegradedUuid
* @deprecated DegradedUuid instances are no longer necessary to support 32-bit
* systems. Transition to {@see DefaultUuidBuilder}.
*
* @psalm-immutable
*/
class DegradedUuidBuilder implements UuidBuilderInterface
{
/**
* @var NumberConverterInterface
*/
private $converter;
private $numberConverter;
/**
* Constructs the DegradedUuidBuilder
*
* @param NumberConverterInterface $converter The number converter to use when constructing the DegradedUuid
* @var TimeConverterInterface
*/
public function __construct(NumberConverterInterface $converter)
{
$this->converter = $converter;
private $timeConverter;
/**
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the DegradedUuid
* @param TimeConverterInterface|null $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
NumberConverterInterface $numberConverter,
?TimeConverterInterface $timeConverter = null
) {
$this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter ?: new DegradedTimeConverter();
}
/**
* Builds a DegradedUuid
* Builds and returns a DegradedUuid
*
* @param CodecInterface $codec The codec to use for building this DegradedUuid
* @param array $fields An array of fields from which to construct the DegradedUuid;
* see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
* @return DegradedUuid
* @param CodecInterface $codec The codec to use for building this DegradedUuid instance
* @param string $bytes The byte string from which to construct a UUID
*
* @return DegradedUuid The DegradedUuidBuild returns an instance of Ramsey\Uuid\DegradedUuid
*
* @psalm-pure
*/
public function build(CodecInterface $codec, array $fields)
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
return new DegradedUuid($fields, $this->converter, $codec);
return new DegradedUuid(
new Rfc4122Fields($bytes),
$this->numberConverter,
$codec,
$this->timeConverter
);
}
}

View File

@@ -0,0 +1,74 @@
<?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\Builder;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Exception\BuilderNotFoundException;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\UuidInterface;
/**
* FallbackBuilder builds a UUID by stepping through a list of UUID builders
* until a UUID can be constructed without exceptions
*
* @psalm-immutable
*/
class FallbackBuilder implements UuidBuilderInterface
{
/**
* @var BuilderCollection
*/
private $builders;
/**
* @param BuilderCollection $builders An array of UUID builders
*/
public function __construct(BuilderCollection $builders)
{
$this->builders = $builders;
}
/**
* Builds and returns a UuidInterface instance using the first builder that
* succeeds
*
* @param CodecInterface $codec The codec to use for building this instance
* @param string $bytes The byte string from which to construct a UUID
*
* @return UuidInterface an instance of a UUID object
*
* @psalm-pure
*/
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
$lastBuilderException = null;
foreach ($this->builders as $builder) {
try {
return $builder->build($codec, $bytes);
} catch (UnableToBuildUuidException $exception) {
$lastBuilderException = $exception;
continue;
}
}
throw new BuilderNotFoundException(
'Could not find a suitable builder for the provided codec and fields',
0,
$lastBuilderException
);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,28 +8,32 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Builder;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\UuidInterface;
/**
* UuidBuilderInterface builds instances UuidInterface
* A UUID builder builds instances of UuidInterface
*
* @psalm-immutable
*/
interface UuidBuilderInterface
{
/**
* Builds an instance of a UuidInterface
* Builds and returns a UuidInterface
*
* @param CodecInterface $codec The codec to use for building this UuidInterface instance
* @param array $fields An array of fields from which to construct a UuidInterface instance;
* see {@see \Ramsey\Uuid\UuidInterface::getFieldsHex()} for array structure.
* @return UuidInterface
* @param string $bytes The byte string from which to construct a UUID
*
* @return UuidInterface Implementations may choose to return more specific
* instances of UUIDs that implement UuidInterface
*
* @psalm-pure
*/
public function build(CodecInterface $codec, array $fields);
public function build(CodecInterface $codec, string $bytes): UuidInterface;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,54 +8,64 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
use InvalidArgumentException;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\UuidInterface;
/**
* CodecInterface represents a UUID coder-decoder
* A codec encodes and decodes a UUID according to defined rules
*
* @psalm-immutable
*/
interface CodecInterface
{
/**
* Encodes a UuidInterface as a string representation of a UUID
* Returns a hexadecimal string representation of a UuidInterface
*
* @param UuidInterface $uuid The UUID for which to create a hexadecimal
* string representation
*
* @param UuidInterface $uuid
* @return string Hexadecimal string representation of a UUID
*
* @psalm-return non-empty-string
*/
public function encode(UuidInterface $uuid);
public function encode(UuidInterface $uuid): string;
/**
* Encodes a UuidInterface as a binary representation of a UUID
* Returns a binary string representation of a UuidInterface
*
* @param UuidInterface $uuid The UUID for which to create a binary string
* representation
*
* @param UuidInterface $uuid
* @return string Binary string representation of a UUID
*
* @psalm-return non-empty-string
*/
public function encodeBinary(UuidInterface $uuid);
public function encodeBinary(UuidInterface $uuid): string;
/**
* Decodes a string representation of a UUID into a UuidInterface object instance
* Returns a UuidInterface derived from a hexadecimal string representation
*
* @param string $encodedUuid
* @return UuidInterface
* @throws InvalidUuidStringException
* @param string $encodedUuid The hexadecimal string representation to
* convert into a UuidInterface instance
*
* @return UuidInterface An instance of a UUID decoded from a hexadecimal
* string representation
*/
public function decode($encodedUuid);
public function decode(string $encodedUuid): UuidInterface;
/**
* Decodes a binary representation of a UUID into a UuidInterface object instance
* Returns a UuidInterface derived from a binary string representation
*
* @param string $bytes
* @return UuidInterface
* @throws InvalidUuidStringException
* @throws InvalidArgumentException if string has not 16 characters
* @param string $bytes The binary string representation to convert into a
* UuidInterface instance
*
* @return UuidInterface An instance of a UUID decoded from a binary string
* representation
*/
public function decodeBytes($bytes);
public function decodeBytes(string $bytes): UuidInterface;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,97 +8,48 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\Guid\Guid;
use Ramsey\Uuid\UuidInterface;
use function bin2hex;
use function substr;
/**
* GuidStringCodec encodes and decodes globally unique identifiers (GUID)
*
* @link https://en.wikipedia.org/wiki/Globally_unique_identifier
* @see Guid
*
* @psalm-immutable
*/
class GuidStringCodec extends StringCodec
{
/**
* Encodes a UuidInterface as a string representation of a GUID
*
* @param UuidInterface $uuid
* @return string Hexadecimal string representation of a GUID
*/
public function encode(UuidInterface $uuid)
public function decode(string $encodedUuid): UuidInterface
{
$components = array_values($uuid->getFieldsHex());
$bytes = $this->getBytes($encodedUuid);
// Swap byte-order on the first three fields
$this->swapFields($components);
return vsprintf(
'%08s-%04s-%04s-%02s%02s-%012s',
$components
);
return $this->getBuilder()->build($this, $this->swapBytes($bytes));
}
/**
* Encodes a UuidInterface as a binary representation of a GUID
*
* @param UuidInterface $uuid
* @return string Binary string representation of a GUID
*/
public function encodeBinary(UuidInterface $uuid)
{
$components = array_values($uuid->getFieldsHex());
return hex2bin(implode('', $components));
}
/**
* Decodes a string representation of a GUID into a UuidInterface object instance
*
* @param string $encodedUuid
* @return UuidInterface
* @throws InvalidUuidStringException
*/
public function decode($encodedUuid)
{
$components = $this->extractComponents($encodedUuid);
$this->swapFields($components);
return $this->getBuilder()->build($this, $this->getFields($components));
}
/**
* Decodes a binary representation of a GUID into a UuidInterface object instance
*
* @param string $bytes
* @return UuidInterface
* @throws InvalidUuidStringException
*/
public function decodeBytes($bytes)
public function decodeBytes(string $bytes): UuidInterface
{
// Specifically call parent::decode to preserve correct byte order
return parent::decode(bin2hex($bytes));
}
/**
* Swaps fields to support GUID byte order
*
* @param array $components An array of UUID components (the UUID exploded on its dashes)
* @return void
* Swaps bytes according to the GUID rules
*/
protected function swapFields(array &$components)
private function swapBytes(string $bytes): string
{
$hex = unpack('H*', pack('L', hexdec($components[0])));
$components[0] = $hex[1];
$hex = unpack('H*', pack('S', hexdec($components[1])));
$components[1] = $hex[1];
$hex = unpack('H*', pack('S', hexdec($components[2])));
$components[2] = $hex[1];
return $bytes[3] . $bytes[2] . $bytes[1] . $bytes[0]
. $bytes[5] . $bytes[4]
. $bytes[7] . $bytes[6]
. substr($bytes, 8);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,62 +8,106 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
use InvalidArgumentException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use function strlen;
use function substr;
/**
* OrderedTimeCodec optimizes the bytes to increment UUIDs when time goes by, to improve database INSERTs.
* The string value will be unchanged from StringCodec. Only works for UUID type 1.
* OrderedTimeCodec encodes and decodes a UUID, optimizing the byte order for
* more efficient storage
*
* For binary representations of version 1 UUID, this codec may be used to
* reorganize the time fields, making the UUID closer to sequential when storing
* the bytes. According to Percona, this optimization can improve database
* INSERTs and SELECTs using the UUID column as a key.
*
* The string representation of the UUID will remain unchanged. Only the binary
* representation is reordered.
*
* **PLEASE NOTE:** Binary representations of UUIDs encoded with this codec must
* be decoded with this codec. Decoding using another codec can result in
* malformed UUIDs.
*
* @link https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ Storing UUID Values in MySQL
*
* @psalm-immutable
*/
class OrderedTimeCodec extends StringCodec
{
/**
* Encodes a UuidInterface as an optimized binary representation of a UUID
* Returns a binary string representation of a UUID, with the timestamp
* fields rearranged for optimized storage
*
* @param UuidInterface $uuid
* @return string Binary string representation of a UUID
* @inheritDoc
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function encodeBinary(UuidInterface $uuid)
public function encodeBinary(UuidInterface $uuid): string
{
$fields = $uuid->getFieldsHex();
$optimized = [
$fields['time_hi_and_version'],
$fields['time_mid'],
$fields['time_low'],
$fields['clock_seq_hi_and_reserved'],
$fields['clock_seq_low'],
$fields['node'],
];
return hex2bin(implode('', $optimized));
}
/**
* Decodes an optimized binary representation of a UUID into a UuidInterface object instance
*
* @param string $bytes
* @return UuidInterface
* @throws InvalidArgumentException if string has not 16 characters
*/
public function decodeBytes($bytes)
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException('$bytes string should contain 16 characters.');
if (
!($uuid->getFields() instanceof Rfc4122FieldsInterface)
|| $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME
) {
throw new InvalidArgumentException(
'Expected RFC 4122 version 1 (time-based) UUID'
);
}
$hex = unpack('H*', $bytes)[1];
$bytes = $uuid->getFields()->getBytes();
// Rearrange the fields to their original order
$hex = substr($hex, 8, 4) . substr($hex, 12, 4) . substr($hex, 4, 4) . substr($hex, 0, 4) . substr($hex, 16);
/** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
return $bytes[6] . $bytes[7]
. $bytes[4] . $bytes[5]
. $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3]
. substr($bytes, 8);
}
return $this->decode($hex);
/**
* Returns a UuidInterface derived from an ordered-time binary string
* representation
*
* @throws InvalidArgumentException if $bytes is an invalid length
*
* @inheritDoc
*/
public function decodeBytes(string $bytes): UuidInterface
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException(
'$bytes string should contain 16 characters.'
);
}
// Rearrange the bytes to their original order.
$rearrangedBytes = $bytes[4] . $bytes[5] . $bytes[6] . $bytes[7]
. $bytes[2] . $bytes[3]
. $bytes[0] . $bytes[1]
. substr($bytes, 8);
$uuid = parent::decodeBytes($rearrangedBytes);
if (
!($uuid->getFields() instanceof Rfc4122FieldsInterface)
|| $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME
) {
throw new UnsupportedOperationException(
'Attempting to decode a non-time-based UUID using '
. 'OrderedTimeCodec'
);
}
return $uuid;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,23 +8,31 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
use InvalidArgumentException;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use function hex2bin;
use function implode;
use function str_replace;
use function strlen;
use function substr;
/**
* StringCodec encodes and decodes RFC 4122 UUIDs
*
* @link http://tools.ietf.org/html/rfc4122
*
* @psalm-immutable
*/
class StringCodec implements CodecInterface
{
@@ -33,138 +42,97 @@ class StringCodec implements CodecInterface
private $builder;
/**
* Constructs a StringCodec for use encoding and decoding UUIDs
* Constructs a StringCodec
*
* @param UuidBuilderInterface $builder The UUID builder to use when encoding UUIDs
* @param UuidBuilderInterface $builder The builder to use when encoding UUIDs
*/
public function __construct(UuidBuilderInterface $builder)
{
$this->builder = $builder;
}
/**
* Encodes a UuidInterface as a string representation of a UUID
*
* @param UuidInterface $uuid
* @return string Hexadecimal string representation of a UUID
*/
public function encode(UuidInterface $uuid)
public function encode(UuidInterface $uuid): string
{
$fields = array_values($uuid->getFieldsHex());
/** @var FieldsInterface $fields */
$fields = $uuid->getFields();
return vsprintf(
'%08s-%04s-%04s-%02s%02s-%012s',
$fields
);
return $fields->getTimeLow()->toString()
. '-'
. $fields->getTimeMid()->toString()
. '-'
. $fields->getTimeHiAndVersion()->toString()
. '-'
. $fields->getClockSeqHiAndReserved()->toString()
. $fields->getClockSeqLow()->toString()
. '-'
. $fields->getNode()->toString();
}
/**
* Encodes a UuidInterface as a binary representation of a UUID
*
* @param UuidInterface $uuid
* @return string Binary string representation of a UUID
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function encodeBinary(UuidInterface $uuid)
public function encodeBinary(UuidInterface $uuid): string
{
return hex2bin($uuid->getHex());
/** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
return $uuid->getFields()->getBytes();
}
/**
* Decodes a string representation of a UUID into a UuidInterface object instance
*
* @param string $encodedUuid
* @return UuidInterface
* @throws InvalidUuidStringException
*
* @inheritDoc
*/
public function decode($encodedUuid)
public function decode(string $encodedUuid): UuidInterface
{
$components = $this->extractComponents($encodedUuid);
$fields = $this->getFields($components);
return $this->builder->build($this, $fields);
return $this->builder->build($this, $this->getBytes($encodedUuid));
}
/**
* Decodes a binary representation of a UUID into a UuidInterface object instance
*
* @param string $bytes
* @return UuidInterface
* @throws InvalidArgumentException if string has not 16 characters
*/
public function decodeBytes($bytes)
public function decodeBytes(string $bytes): UuidInterface
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException('$bytes string should contain 16 characters.');
throw new InvalidArgumentException(
'$bytes string should contain 16 characters.'
);
}
$hexUuid = unpack('H*', $bytes);
return $this->decode($hexUuid[1]);
return $this->builder->build($this, $bytes);
}
/**
* Returns the UUID builder
*
* @return UuidBuilderInterface
*/
protected function getBuilder()
protected function getBuilder(): UuidBuilderInterface
{
return $this->builder;
}
/**
* Returns an array of UUID components (the UUID exploded on its dashes)
*
* @param string $encodedUuid
* @return array
* @throws InvalidUuidStringException
* Returns a byte string of the UUID
*/
protected function extractComponents($encodedUuid)
protected function getBytes(string $encodedUuid): string
{
$nameParsed = str_replace([
'urn:',
'uuid:',
'{',
'}',
'-'
], '', $encodedUuid);
$parsedUuid = str_replace(
['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'],
'',
$encodedUuid
);
// We have stripped out the dashes and are breaking up the string using
// substr(). In this way, we can accept a full hex value that doesn't
// contain dashes.
$components = [
substr($nameParsed, 0, 8),
substr($nameParsed, 8, 4),
substr($nameParsed, 12, 4),
substr($nameParsed, 16, 4),
substr($nameParsed, 20)
substr($parsedUuid, 0, 8),
substr($parsedUuid, 8, 4),
substr($parsedUuid, 12, 4),
substr($parsedUuid, 16, 4),
substr($parsedUuid, 20),
];
$nameParsed = implode('-', $components);
if (!Uuid::isValid($nameParsed)) {
throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid);
if (!Uuid::isValid(implode('-', $components))) {
throw new InvalidUuidStringException(
'Invalid UUID string: ' . $encodedUuid
);
}
return $components;
}
/**
* Returns the fields that make up this UUID
*
* @see \Ramsey\Uuid\UuidInterface::getFieldsHex()
* @param array $components
* @return array
*/
protected function getFields(array $components)
{
return [
'time_low' => str_pad($components[0], 8, '0', STR_PAD_LEFT),
'time_mid' => str_pad($components[1], 4, '0', STR_PAD_LEFT),
'time_hi_and_version' => str_pad($components[2], 4, '0', STR_PAD_LEFT),
'clock_seq_hi_and_reserved' => str_pad(substr($components[3], 0, 2), 2, '0', STR_PAD_LEFT),
'clock_seq_low' => str_pad(substr($components[3], 2), 2, '0', STR_PAD_LEFT),
'node' => str_pad($components[4], 12, '0', STR_PAD_LEFT)
];
return (string) hex2bin($parsedUuid);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,102 +8,106 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\UuidInterface;
use function bin2hex;
use function sprintf;
use function substr;
use function substr_replace;
/**
* TimestampFirstCombCodec encodes and decodes COMB UUIDs which have the timestamp as the first 48 bits.
* To be used with MySQL, PostgreSQL, Oracle.
* TimestampFirstCombCodec encodes and decodes COMBs, with the timestamp as the
* first 48 bits
*
* In contrast with the TimestampLastCombCodec, the TimestampFirstCombCodec
* adds the timestamp to the first 48 bits of the COMB. To generate a
* timestamp-first COMB, set the TimestampFirstCombCodec as the codec, along
* with the CombGenerator as the random generator.
*
* ``` php
* $factory = new UuidFactory();
*
* $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder()));
*
* $factory->setRandomGenerator(new CombGenerator(
* $factory->getRandomGenerator(),
* $factory->getNumberConverter()
* ));
*
* $timestampFirstComb = $factory->uuid4();
* ```
*
* @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys
*
* @psalm-immutable
*/
class TimestampFirstCombCodec extends StringCodec
{
/**
* Encodes a UuidInterface as a string representation of a timestamp first COMB UUID
*
* @param UuidInterface $uuid
*
* @return string Hexadecimal string representation of a GUID
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function encode(UuidInterface $uuid)
public function encode(UuidInterface $uuid): string
{
$sixPieceComponents = array_values($uuid->getFieldsHex());
$bytes = $this->swapBytes($uuid->getFields()->getBytes());
$this->swapTimestampAndRandomBits($sixPieceComponents);
return vsprintf(
'%08s-%04s-%04s-%02s%02s-%012s',
$sixPieceComponents
return sprintf(
'%08s-%04s-%04s-%04s-%012s',
bin2hex(substr($bytes, 0, 4)),
bin2hex(substr($bytes, 4, 2)),
bin2hex(substr($bytes, 6, 2)),
bin2hex(substr($bytes, 8, 2)),
bin2hex(substr($bytes, 10))
);
}
/**
* Encodes a UuidInterface as a binary representation of timestamp first COMB UUID
*
* @param UuidInterface $uuid
*
* @return string Binary string representation of timestamp first COMB UUID
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function encodeBinary(UuidInterface $uuid)
public function encodeBinary(UuidInterface $uuid): string
{
$stringEncoding = $this->encode($uuid);
return hex2bin(str_replace('-', '', $stringEncoding));
/** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
return $this->swapBytes($uuid->getFields()->getBytes());
}
/**
* Decodes a string representation of timestamp first COMB UUID into a UuidInterface object instance
*
* @param string $encodedUuid
*
* @return UuidInterface
* @throws InvalidUuidStringException
*
* @inheritDoc
*/
public function decode($encodedUuid)
public function decode(string $encodedUuid): UuidInterface
{
$fivePieceComponents = $this->extractComponents($encodedUuid);
$bytes = $this->getBytes($encodedUuid);
$this->swapTimestampAndRandomBits($fivePieceComponents);
return $this->getBuilder()->build($this, $this->swapBytes($bytes));
}
return $this->getBuilder()->build($this, $this->getFields($fivePieceComponents));
public function decodeBytes(string $bytes): UuidInterface
{
return $this->getBuilder()->build($this, $this->swapBytes($bytes));
}
/**
* Decodes a binary representation of timestamp first COMB UUID into a UuidInterface object instance
*
* @param string $bytes
*
* @return UuidInterface
* @throws InvalidUuidStringException
* Swaps bytes according to the timestamp-first COMB rules
*/
public function decodeBytes($bytes)
private function swapBytes(string $bytes): string
{
return $this->decode(bin2hex($bytes));
}
$first48Bits = substr($bytes, 0, 6);
$last48Bits = substr($bytes, -6);
/**
* Swaps the first 48 bits with the last 48 bits
*
* @param array $components An array of UUID components (the UUID exploded on its dashes)
*
* @return void
*/
protected function swapTimestampAndRandomBits(array &$components)
{
$last48Bits = $components[4];
if (count($components) == 6) {
$last48Bits = $components[5];
$components[5] = $components[0] . $components[1];
} else {
$components[4] = $components[0] . $components[1];
}
$bytes = substr_replace($bytes, $last48Bits, 0, 6);
$bytes = substr_replace($bytes, $first48Bits, -6);
$components[0] = substr($last48Bits, 0, 8);
$components[1] = substr($last48Bits, 8, 4);
return $bytes;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,15 +8,43 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Codec;
/**
* TimestampLastCombCodec encodes and decodes COMB UUIDs which have the timestamp as the last 48 bits.
* To be used with MSSQL.
* TimestampLastCombCodec encodes and decodes COMBs, with the timestamp as the
* last 48 bits
*
* The CombGenerator when used with the StringCodec (and, by proxy, the
* TimestampLastCombCodec) adds the timestamp to the last 48 bits of the COMB.
* The TimestampLastCombCodec is provided for the sake of consistency. In
* practice, it is identical to the standard StringCodec but, it may be used
* with the CombGenerator for additional context when reading code.
*
* Consider the following code. By default, the codec used by UuidFactory is the
* StringCodec, but here, we explicitly set the TimestampLastCombCodec. It is
* redundant, but it is clear that we intend this COMB to be generated with the
* timestamp appearing at the end.
*
* ``` php
* $factory = new UuidFactory();
*
* $factory->setCodec(new TimestampLastCombCodec($factory->getUuidBuilder()));
*
* $factory->setRandomGenerator(new CombGenerator(
* $factory->getRandomGenerator(),
* $factory->getNumberConverter()
* ));
*
* $timestampLastComb = $factory->uuid4();
* ```
*
* @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys
*
* @psalm-immutable
*/
class TimestampLastCombCodec extends StringCodec
{

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,48 +8,50 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter\Number;
use Moontoast\Math\BigNumber;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Math\BrickMathCalculator;
/**
* BigNumberConverter converts UUIDs from hexadecimal characters into
* moontoast/math `BigNumber` representations of integers and vice versa
* Previously used to integrate moontoast/math as a bignum arithmetic library,
* BigNumberConverter is deprecated in favor of GenericNumberConverter
*
* @deprecated Transition to {@see GenericNumberConverter}.
*
* @psalm-immutable
*/
class BigNumberConverter implements NumberConverterInterface
{
/**
* Converts a hexadecimal number into a `Moontoast\Math\BigNumber` representation
*
* @param string $hex The hexadecimal string representation to convert
* @return BigNumber
* @var NumberConverterInterface
*/
public function fromHex($hex)
{
$number = BigNumber::convertToBase10($hex, 16);
private $converter;
return new BigNumber($number);
public function __construct()
{
$this->converter = new GenericNumberConverter(new BrickMathCalculator());
}
/**
* Converts an integer or `Moontoast\Math\BigNumber` integer representation
* into a hexadecimal string representation
*
* @param int|string|BigNumber $integer An integer or `Moontoast\Math\BigNumber`
* @return string Hexadecimal string
* @inheritDoc
* @psalm-pure
*/
public function toHex($integer)
public function fromHex(string $hex): string
{
if (!$integer instanceof BigNumber) {
$integer = new BigNumber($integer);
}
return $this->converter->fromHex($hex);
}
return BigNumber::convertFromBase10($integer, 16);
/**
* @inheritDoc
* @psalm-pure
*/
public function toHex(string $number): string
{
return $this->converter->toHex($number);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,52 +8,18 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter\Number;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Converter\NumberConverterInterface;
/**
* DegradedNumberConverter throws `UnsatisfiedDependencyException` exceptions
* if attempting to use number conversion functionality in an environment that
* does not support large integers (i.e. when moontoast/math is not available)
* @deprecated DegradedNumberConverter is no longer necessary for converting
* numbers on 32-bit systems. Transition to {@see GenericNumberConverter}.
*
* @psalm-immutable
*/
class DegradedNumberConverter implements NumberConverterInterface
class DegradedNumberConverter extends BigNumberConverter
{
/**
* Throws an `UnsatisfiedDependencyException`
*
* @param string $hex The hexadecimal string representation to convert
* @return void
* @throws UnsatisfiedDependencyException
*/
public function fromHex($hex)
{
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' without support for large '
. 'integers, since integer is an unsigned '
. '128-bit integer; Moontoast\Math\BigNumber is required.'
);
}
/**
* Throws an `UnsatisfiedDependencyException`
*
* @param mixed $integer An integer representation to convert
* @return void
* @throws UnsatisfiedDependencyException
*/
public function toHex($integer)
{
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' without support for large '
. 'integers, since integer is an unsigned '
. '128-bit integer; Moontoast\Math\BigNumber is required. '
);
}
}

View File

@@ -0,0 +1,63 @@
<?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\Converter\Number;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Math\CalculatorInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
/**
* GenericNumberConverter uses the provided calculator to convert decimal
* numbers to and from hexadecimal values
*
* @psalm-immutable
*/
class GenericNumberConverter implements NumberConverterInterface
{
/**
* @var CalculatorInterface
*/
private $calculator;
public function __construct(CalculatorInterface $calculator)
{
$this->calculator = $calculator;
}
/**
* @inheritDoc
* @psalm-pure
* @psalm-return numeric-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function fromHex(string $hex): string
{
return $this->calculator->fromBase($hex, 16)->toString();
}
/**
* @inheritDoc
* @psalm-pure
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function toHex(string $number): string
{
/** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
return $this->calculator->toBase(new IntegerObject($number), 16);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,42 +8,50 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
/**
* NumberConverterInterface converts UUIDs from hexadecimal characters into
* A number converter converts UUIDs from hexadecimal characters into
* representations of integers and vice versa
*
* @psalm-immutable
*/
interface NumberConverterInterface
{
/**
* Converts a hexadecimal number into an integer representation of the number
* Converts a hexadecimal number into an string integer representation of
* the number
*
* The integer representation returned may be an object or a string
* representation of the integer, depending on the implementation.
* The integer representation returned is a string representation of the
* integer, to accommodate unsigned integers greater than PHP_INT_MAX.
*
* @param string $hex The hexadecimal string representation to convert
* @return mixed
* @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
*
* @return string String representation of an integer
*
* @psalm-return numeric-string
*
* @psalm-pure
*/
public function fromHex($hex);
public function fromHex(string $hex): string;
/**
* Converts an integer representation into a hexadecimal string representation
* of the number
* Converts a string integer representation into a hexadecimal string
* representation of the number
*
* @param string $number A string integer representation to convert; this
* must be a numeric string to accommodate unsigned integers greater
* than PHP_INT_MAX.
*
* @param mixed $integer An integer representation to convert; this may be
* a true integer, a string integer, or a object representation that
* this converter can understand
* @return string Hexadecimal string
* @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
*
* @psalm-return non-empty-string
*
* @psalm-pure
*/
public function toHex($integer);
public function toHex(string $number): string;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,53 +8,44 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter\Time;
use Moontoast\Math\BigNumber;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Time;
/**
* BigNumberTimeConverter uses the moontoast/math library's `BigNumber` to
* provide facilities for converting parts of time into representations that may
* be used in UUIDs
* Previously used to integrate moontoast/math as a bignum arithmetic library,
* BigNumberTimeConverter is deprecated in favor of GenericTimeConverter
*
* @deprecated Transition to {@see GenericTimeConverter}.
*
* @psalm-immutable
*/
class BigNumberTimeConverter implements TimeConverterInterface
{
/**
* Uses the provided seconds and micro-seconds to calculate the time_low,
* time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
*
* @param string $seconds
* @param string $microSeconds
* @return string[] An array containing `low`, `mid`, and `high` keys
* @link http://tools.ietf.org/html/rfc4122#section-4.2.2
* @var TimeConverterInterface
*/
public function calculateTime($seconds, $microSeconds)
private $converter;
public function __construct()
{
$uuidTime = new BigNumber('0');
$this->converter = new GenericTimeConverter(new BrickMathCalculator());
}
$sec = new BigNumber($seconds);
$sec->multiply('10000000');
public function calculateTime(string $seconds, string $microseconds): Hexadecimal
{
return $this->converter->calculateTime($seconds, $microseconds);
}
$usec = new BigNumber($microSeconds);
$usec->multiply('10');
$uuidTime
->add($sec)
->add($usec)
->add('122192928000000000');
$uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16));
return [
'low' => substr($uuidTimeHex, 8),
'mid' => substr($uuidTimeHex, 4, 4),
'hi' => substr($uuidTimeHex, 0, 4),
];
public function convertTime(Hexadecimal $uuidTimestamp): Time
{
return $this->converter->convertTime($uuidTimestamp);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,36 +8,18 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter\Time;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
/**
* DegradedTimeConverter throws `UnsatisfiedDependencyException` exceptions
* if attempting to use time conversion functionality in an environment that
* does not support large integers (i.e. when moontoast/math is not available)
* @deprecated DegradedTimeConverter is no longer necessary for converting
* time on 32-bit systems. Transition to {@see GenericTimeConverter}.
*
* @psalm-immutable
*/
class DegradedTimeConverter implements TimeConverterInterface
class DegradedTimeConverter extends BigNumberTimeConverter
{
/**
* Throws an `UnsatisfiedDependencyException`
*
* @param string $seconds
* @param string $microSeconds
* @return void
* @throws UnsatisfiedDependencyException if called on a 32-bit system and `Moontoast\Math\BigNumber` is not present
*/
public function calculateTime($seconds, $microSeconds)
{
throw new UnsatisfiedDependencyException(
'When calling ' . __METHOD__ . ' on a 32-bit system, '
. 'Moontoast\Math\BigNumber must be present.'
);
}
}

View File

@@ -0,0 +1,124 @@
<?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\Converter\Time;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Math\CalculatorInterface;
use Ramsey\Uuid\Math\RoundingMode;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\Time;
use function explode;
use function str_pad;
use const STR_PAD_LEFT;
/**
* GenericTimeConverter uses the provided calculator to calculate and convert
* time values
*
* @psalm-immutable
*/
class GenericTimeConverter implements TimeConverterInterface
{
/**
* The number of 100-nanosecond intervals from the Gregorian calendar epoch
* to the Unix epoch.
*/
private const GREGORIAN_TO_UNIX_INTERVALS = '122192928000000000';
/**
* The number of 100-nanosecond intervals in one second.
*/
private const SECOND_INTERVALS = '10000000';
/**
* The number of 100-nanosecond intervals in one microsecond.
*/
private const MICROSECOND_INTERVALS = '10';
/**
* @var CalculatorInterface
*/
private $calculator;
public function __construct(CalculatorInterface $calculator)
{
$this->calculator = $calculator;
}
public function calculateTime(string $seconds, string $microseconds): Hexadecimal
{
$timestamp = new Time($seconds, $microseconds);
// Convert the seconds into a count of 100-nanosecond intervals.
$sec = $this->calculator->multiply(
$timestamp->getSeconds(),
new IntegerObject(self::SECOND_INTERVALS)
);
// Convert the microseconds into a count of 100-nanosecond intervals.
$usec = $this->calculator->multiply(
$timestamp->getMicroseconds(),
new IntegerObject(self::MICROSECOND_INTERVALS)
);
// Combine the seconds and microseconds intervals and add the count of
// 100-nanosecond intervals from the Gregorian calendar epoch to the
// Unix epoch. This gives us the correct count of 100-nanosecond
// intervals since the Gregorian calendar epoch for the given seconds
// and microseconds.
/** @var IntegerObject $uuidTime */
$uuidTime = $this->calculator->add(
$sec,
$usec,
new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)
);
$uuidTimeHex = str_pad(
$this->calculator->toHexadecimal($uuidTime)->toString(),
16,
'0',
STR_PAD_LEFT
);
return new Hexadecimal($uuidTimeHex);
}
public function convertTime(Hexadecimal $uuidTimestamp): Time
{
// From the total, subtract the number of 100-nanosecond intervals from
// the Gregorian calendar epoch to the Unix epoch. This gives us the
// number of 100-nanosecond intervals from the Unix epoch, which also
// includes the microtime.
$epochNanoseconds = $this->calculator->subtract(
$this->calculator->toInteger($uuidTimestamp),
new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)
);
// Convert the 100-nanosecond intervals into seconds and microseconds.
$unixTimestamp = $this->calculator->divide(
RoundingMode::HALF_UP,
6,
$epochNanoseconds,
new IntegerObject(self::SECOND_INTERVALS)
);
$split = explode('.', (string) $unixTimestamp, 2);
return new Time($split[0], $split[1] ?? 0);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,41 +8,176 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter\Time;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Math\CalculatorInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\Time;
use function count;
use function dechex;
use function explode;
use function is_float;
use function is_int;
use function str_pad;
use function strlen;
use function substr;
use const STR_PAD_LEFT;
use const STR_PAD_RIGHT;
/**
* PhpTimeConverter uses built-in PHP functions and standard math operations
* available to the PHP programming language to provide facilities for
* converting parts of time into representations that may be used in UUIDs
*
* @psalm-immutable
*/
class PhpTimeConverter implements TimeConverterInterface
{
/**
* Uses the provided seconds and micro-seconds to calculate the time_low,
* time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
*
* @param string $seconds
* @param string $microSeconds
* @return string[] An array containing `low`, `mid`, and `high` keys
* @link http://tools.ietf.org/html/rfc4122#section-4.2.2
* The number of 100-nanosecond intervals from the Gregorian calendar epoch
* to the Unix epoch.
*/
public function calculateTime($seconds, $microSeconds)
private const GREGORIAN_TO_UNIX_INTERVALS = 0x01b21dd213814000;
/**
* The number of 100-nanosecond intervals in one second.
*/
private const SECOND_INTERVALS = 10000000;
/**
* The number of 100-nanosecond intervals in one microsecond.
*/
private const MICROSECOND_INTERVALS = 10;
/**
* @var CalculatorInterface
*/
private $calculator;
/**
* @var TimeConverterInterface
*/
private $fallbackConverter;
/**
* @var int
*/
private $phpPrecision;
public function __construct(
?CalculatorInterface $calculator = null,
?TimeConverterInterface $fallbackConverter = null
) {
if ($calculator === null) {
$calculator = new BrickMathCalculator();
}
if ($fallbackConverter === null) {
$fallbackConverter = new GenericTimeConverter($calculator);
}
$this->calculator = $calculator;
$this->fallbackConverter = $fallbackConverter;
$this->phpPrecision = (int) ini_get('precision');
}
public function calculateTime(string $seconds, string $microseconds): Hexadecimal
{
// 0x01b21dd213814000 is the number of 100-ns intervals between the
// UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
$uuidTime = ($seconds * 10000000) + ($microSeconds * 10) + 0x01b21dd213814000;
$seconds = new IntegerObject($seconds);
$microseconds = new IntegerObject($microseconds);
// Calculate the count of 100-nanosecond intervals since the Gregorian
// calendar epoch for the given seconds and microseconds.
$uuidTime = ((int) $seconds->toString() * self::SECOND_INTERVALS)
+ ((int) $microseconds->toString() * self::MICROSECOND_INTERVALS)
+ self::GREGORIAN_TO_UNIX_INTERVALS;
// Check to see whether we've overflowed the max/min integer size.
// If so, we will default to a different time converter.
/** @psalm-suppress RedundantCondition */
if (!is_int($uuidTime)) {
return $this->fallbackConverter->calculateTime(
$seconds->toString(),
$microseconds->toString()
);
}
return new Hexadecimal(str_pad(dechex($uuidTime), 16, '0', STR_PAD_LEFT));
}
public function convertTime(Hexadecimal $uuidTimestamp): Time
{
$timestamp = $this->calculator->toInteger($uuidTimestamp);
// Convert the 100-nanosecond intervals into seconds and microseconds.
$splitTime = $this->splitTime(
((int) $timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS)
/ self::SECOND_INTERVALS
);
if (count($splitTime) === 0) {
return $this->fallbackConverter->convertTime($uuidTimestamp);
}
return new Time($splitTime['sec'], $splitTime['usec']);
}
/**
* @param int|float $time The time to split into seconds and microseconds
*
* @return string[]
*/
private function splitTime($time): array
{
$split = explode('.', (string) $time, 2);
// If the $time value is a float but $split only has 1 element, then the
// float math was rounded up to the next second, so we want to return
// an empty array to allow use of the fallback converter.
if (is_float($time) && count($split) === 1) {
return [];
}
if (count($split) === 1) {
return [
'sec' => $split[0],
'usec' => '0',
];
}
// If the microseconds are less than six characters AND the length of
// the number is greater than or equal to the PHP precision, then it's
// possible that we lost some precision for the microseconds. Return an
// empty array, so that we can choose to use the fallback converter.
if (strlen($split[1]) < 6 && strlen((string) $time) >= $this->phpPrecision) {
return [];
}
$microseconds = $split[1];
// Ensure the microseconds are no longer than 6 digits. If they are,
// truncate the number to the first 6 digits and round up, if needed.
if (strlen($microseconds) > 6) {
$roundingDigit = (int) substr($microseconds, 6, 1);
$microseconds = (int) substr($microseconds, 0, 6);
if ($roundingDigit >= 5) {
$microseconds++;
}
}
return [
'low' => sprintf('%08x', $uuidTime & 0xffffffff),
'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff),
'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff),
'sec' => $split[0],
'usec' => str_pad((string) $microseconds, 6, '0', STR_PAD_RIGHT),
];
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,31 +8,51 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Converter;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Time;
/**
* TimeConverterInterface provides facilities for converting parts of time into
* representations that may be used in UUIDs
* A time converter converts timestamps into representations that may be used
* in UUIDs
*
* @psalm-immutable
*/
interface TimeConverterInterface
{
/**
* Uses the provided seconds and micro-seconds to calculate the time_low,
* time_mid, and time_high fields used by RFC 4122 version 1 UUIDs
* Uses the provided seconds and micro-seconds to calculate the count of
* 100-nanosecond intervals since UTC 00:00:00.00, 15 October 1582, for
* RFC 4122 variant UUIDs
*
* @param string $seconds
* @param string $microSeconds
* @return string[] An array guaranteed to contain `low`, `mid`, and `hi` keys
* @throws UnsatisfiedDependencyException if called on a 32-bit system and
* `Moontoast\Math\BigNumber` is not present
* @link http://tools.ietf.org/html/rfc4122#section-4.2.2
* @link http://tools.ietf.org/html/rfc4122#section-4.2.2 RFC 4122, § 4.2.2: Generation Details
*
* @param string $seconds A string representation of the number of seconds
* since the Unix epoch for the time to calculate
* @param string $microseconds A string representation of the micro-seconds
* associated with the time to calculate
*
* @return Hexadecimal The full UUID timestamp as a Hexadecimal value
*
* @psalm-pure
*/
public function calculateTime($seconds, $microSeconds);
public function calculateTime(string $seconds, string $microseconds): Hexadecimal;
/**
* Converts a timestamp extracted from a UUID to a Unix timestamp
*
* @param Hexadecimal $uuidTimestamp A hexadecimal representation of a UUID
* timestamp; a UUID timestamp is a count of 100-nanosecond intervals
* since UTC 00:00:00.00, 15 October 1582.
*
* @return Time An instance of {@see Time}
*
* @psalm-pure
*/
public function convertTime(Hexadecimal $uuidTimestamp): Time;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,110 +8,18 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid;
use DateTime;
use Moontoast\Math\BigNumber;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
/**
* DegradedUuid represents an RFC 4122 UUID on 32-bit systems
* @deprecated DegradedUuid is no longer necessary to represent UUIDs on 32-bit
* systems. Transition typehints to {@see UuidInterface}.
*
* @see Uuid
* @psalm-immutable
*/
class DegradedUuid extends Uuid
{
/**
* @inheritdoc
*/
public function getDateTime()
{
if ($this->getVersion() != 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
$time = $this->converter->fromHex($this->getTimestampHex());
$ts = new BigNumber($time, 20);
$ts->subtract('122192928000000000');
$ts->divide('10000000.0');
$ts->floor();
$unixTime = $ts->getValue();
return new DateTime("@{$unixTime}");
}
/**
* For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
* called on a 32-bit system
*
* @throws UnsatisfiedDependencyException if called on a 32-bit system
*/
public function getFields()
{
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some '
. 'values overflow the system max integer value'
. '; consider calling getFieldsHex instead'
);
}
/**
* For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
* called on a 32-bit system
*
* @throws UnsatisfiedDependencyException if called on a 32-bit system
*/
public function getNode()
{
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node '
. 'is an unsigned 48-bit integer and can overflow the system '
. 'max integer value'
. '; consider calling getNodeHex instead'
);
}
/**
* For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
* called on a 32-bit system
*
* @throws UnsatisfiedDependencyException if called on a 32-bit system
*/
public function getTimeLow()
{
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low '
. 'is an unsigned 32-bit integer and can overflow the system '
. 'max integer value'
. '; consider calling getTimeLowHex instead'
);
}
/**
* For degraded UUIDs, throws an `UnsatisfiedDependencyException` when
* called on a 32-bit system
*
* @throws UnsatisfiedDependencyException if called on a 32-bit system
* @throws UnsupportedOperationException If this UUID is not a version 1 UUID
*/
public function getTimestamp()
{
if ($this->getVersion() != 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
throw new UnsatisfiedDependencyException(
'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp '
. 'is an unsigned 60-bit integer and can overflow the system '
. 'max integer value'
. '; consider calling getTimestampHex instead'
);
}
}

View File

@@ -0,0 +1,147 @@
<?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\Converter\NumberConverterInterface;
/**
* This interface encapsulates deprecated methods for ramsey/uuid; this
* interface and its methods will be removed in ramsey/uuid 5.0.0.
*
* @psalm-immutable
*/
interface DeprecatedUuidInterface
{
/**
* @deprecated This method will be removed in 5.0.0. There is no alternative
* recommendation, so plan accordingly.
*/
public function getNumberConverter(): NumberConverterInterface;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance.
*
* @return string[]
*/
public function getFieldsHex(): array;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeqHiAndReserved()}.
*/
public function getClockSeqHiAndReservedHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeqLow()}.
*/
public function getClockSeqLowHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getClockSeq()}.
*/
public function getClockSequenceHex(): string;
/**
* @deprecated In ramsey/uuid version 5.0.0, this will be removed from the
* interface. It is available at {@see UuidV1::getDateTime()}.
*/
public function getDateTime(): DateTimeInterface;
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getLeastSignificantBitsHex(): string;
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getMostSignificantBitsHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getNode()}.
*/
public function getNodeHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeHiAndVersion()}.
*/
public function getTimeHiAndVersionHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeLow()}.
*/
public function getTimeLowHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimeMid()}.
*/
public function getTimeMidHex(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getTimestamp()}.
*/
public function getTimestampHex(): string;
/**
* @deprecated In ramsey/uuid version 5.0.0, this will be removed from this
* interface. It has moved to {@see \Ramsey\Uuid\Rfc4122\UuidInterface::getUrn()}.
*/
public function getUrn(): string;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVariant()}.
*/
public function getVariant(): ?int;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVersion()}.
*/
public function getVersion(): ?int;
}

View File

@@ -0,0 +1,370 @@
<?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 DateTimeImmutable;
use DateTimeInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Throwable;
use function str_pad;
use function substr;
use const STR_PAD_LEFT;
/**
* This trait encapsulates deprecated methods for ramsey/uuid; this trait and
* its methods will be removed in ramsey/uuid 5.0.0.
*
* @psalm-immutable
*/
trait DeprecatedUuidMethodsTrait
{
/**
* @var Rfc4122FieldsInterface
*/
protected $fields;
/**
* @var NumberConverterInterface
*/
protected $numberConverter;
/**
* @var TimeConverterInterface
*/
protected $timeConverter;
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getClockSeqHiAndReserved(): string
{
return $this->numberConverter->fromHex($this->fields->getClockSeqHiAndReserved()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}.
*/
public function getClockSeqHiAndReservedHex(): string
{
return $this->fields->getClockSeqHiAndReserved()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getClockSeqLow(): string
{
return $this->numberConverter->fromHex($this->fields->getClockSeqLow()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}.
*/
public function getClockSeqLowHex(): string
{
return $this->fields->getClockSeqLow()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getClockSequence(): string
{
return $this->numberConverter->fromHex($this->fields->getClockSeq()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}.
*/
public function getClockSequenceHex(): string
{
return $this->fields->getClockSeq()->toString();
}
/**
* @deprecated This method will be removed in 5.0.0. There is no alternative
* recommendation, so plan accordingly.
*/
public function getNumberConverter(): NumberConverterInterface
{
return $this->numberConverter;
}
/**
* @deprecated In ramsey/uuid version 5.0.0, this will be removed.
* It is available at {@see UuidV1::getDateTime()}.
*
* @return DateTimeImmutable An immutable instance of DateTimeInterface
*
* @throws UnsupportedOperationException if UUID is not time-based
* @throws DateTimeException if DateTime throws an exception/error
*/
public function getDateTime(): DateTimeInterface
{
if ($this->fields->getVersion() !== 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
$time = $this->timeConverter->convertTime($this->fields->getTimestamp());
try {
return new DateTimeImmutable(
'@'
. $time->getSeconds()->toString()
. '.'
. str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
);
} catch (Throwable $e) {
throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance.
*
* @return string[]
*/
public function getFieldsHex(): array
{
return [
'time_low' => $this->fields->getTimeLow()->toString(),
'time_mid' => $this->fields->getTimeMid()->toString(),
'time_hi_and_version' => $this->fields->getTimeHiAndVersion()->toString(),
'clock_seq_hi_and_reserved' => $this->fields->getClockSeqHiAndReserved()->toString(),
'clock_seq_low' => $this->fields->getClockSeqLow()->toString(),
'node' => $this->fields->getNode()->toString(),
];
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getLeastSignificantBits(): string
{
$leastSignificantHex = substr($this->getHex()->toString(), 16);
return $this->numberConverter->fromHex($leastSignificantHex);
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getLeastSignificantBitsHex(): string
{
return substr($this->getHex()->toString(), 16);
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getMostSignificantBits(): string
{
$mostSignificantHex = substr($this->getHex()->toString(), 0, 16);
return $this->numberConverter->fromHex($mostSignificantHex);
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*/
public function getMostSignificantBitsHex(): string
{
return substr($this->getHex()->toString(), 0, 16);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getNode()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getNode(): string
{
return $this->numberConverter->fromHex($this->fields->getNode()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getNode()}.
*/
public function getNodeHex(): string
{
return $this->fields->getNode()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getTimeHiAndVersion(): string
{
return $this->numberConverter->fromHex($this->fields->getTimeHiAndVersion()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}.
*/
public function getTimeHiAndVersionHex(): string
{
return $this->fields->getTimeHiAndVersion()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getTimeLow(): string
{
return $this->numberConverter->fromHex($this->fields->getTimeLow()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}.
*/
public function getTimeLowHex(): string
{
return $this->fields->getTimeLow()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getTimeMid(): string
{
return $this->numberConverter->fromHex($this->fields->getTimeMid()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}.
*/
public function getTimeMidHex(): string
{
return $this->fields->getTimeMid()->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*/
public function getTimestamp(): string
{
if ($this->fields->getVersion() !== 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
return $this->numberConverter->fromHex($this->fields->getTimestamp()->toString());
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}.
*/
public function getTimestampHex(): string
{
if ($this->fields->getVersion() !== 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
return $this->fields->getTimestamp()->toString();
}
/**
* @deprecated This has moved to {@see Rfc4122FieldsInterface::getUrn()} and
* is available on {@see \Ramsey\Uuid\Rfc4122\UuidV1},
* {@see \Ramsey\Uuid\Rfc4122\UuidV3}, {@see \Ramsey\Uuid\Rfc4122\UuidV4},
* and {@see \Ramsey\Uuid\Rfc4122\UuidV5}.
*/
public function getUrn(): string
{
return 'urn:uuid:' . $this->toString();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVariant()}.
*/
public function getVariant(): ?int
{
return $this->fields->getVariant();
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call
* {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::getVersion()}.
*/
public function getVersion(): ?int
{
return $this->fields->getVersion();
}
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that no suitable builder could be found
*/
class BuilderNotFoundException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that the PHP DateTime extension encountered an exception/error
*/
class DateTimeException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,25 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate an exception occurred while dealing with DCE Security
* (version 2) UUIDs
*/
class DceSecurityException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use InvalidArgumentException as PhpInvalidArgumentException;
/**
* Thrown to indicate that the argument received is not valid
*/
class InvalidArgumentException extends PhpInvalidArgumentException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that the bytes being operated on are invalid in some way
*/
class InvalidBytesException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,18 +8,18 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Exception;
use InvalidArgumentException;
/**
* Thrown to indicate that the parsed UUID string is invalid.
* Thrown to indicate that the string received is not a valid UUID
*
* The InvalidArgumentException that this extends is the ramsey/uuid version
* of this exception. It exists in the same namespace as this class.
*/
class InvalidUuidStringException extends InvalidArgumentException
class InvalidUuidStringException extends InvalidArgumentException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,25 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that an error occurred while attempting to hash a
* namespace and name
*/
class NameException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that attempting to fetch or create a node ID encountered an error
*/
class NodeException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,27 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that the source of random data encountered an error
*
* This exception is used mostly to indicate that random_bytes() or random_int()
* threw an exception. However, it may be used for other sources of random data.
*/
class RandomSourceException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate that the source of time encountered an error
*/
class TimeSourceException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,24 @@
<?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\Exception;
use RuntimeException as PhpRuntimeException;
/**
* Thrown to indicate a builder is unable to build a UUID
*/
class UnableToBuildUuidException extends PhpRuntimeException implements UuidExceptionInterface
{
}

View File

@@ -1,25 +0,0 @@
<?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
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
namespace Ramsey\Uuid\Exception;
use RuntimeException;
/**
* Thrown to indicate that the requested operation has dependencies that have not
* been satisfied.
*/
class UnsatisfiedDependencyException extends RuntimeException
{
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,18 +8,17 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Exception;
use RuntimeException;
use LogicException as PhpLogicException;
/**
* Thrown to indicate that the requested operation is not supported.
* Thrown to indicate that the requested operation is not supported
*/
class UnsupportedOperationException extends RuntimeException
class UnsupportedOperationException extends PhpLogicException implements UuidExceptionInterface
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
use Throwable;
interface UuidExceptionInterface extends Throwable
{
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,41 +8,58 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\PeclUuidTimeGenerator;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\Number\BigNumberConverter;
use Ramsey\Uuid\Converter\Number\DegradedNumberConverter;
use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter;
use Ramsey\Uuid\Converter\Time\DegradedTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Provider\Time\SystemTimeProvider;
use Ramsey\Uuid\Builder\BuilderCollection;
use Ramsey\Uuid\Builder\FallbackBuilder;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Builder\DefaultUuidBuilder;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Codec\StringCodec;
use Ramsey\Uuid\Codec\GuidStringCodec;
use Ramsey\Uuid\Builder\DegradedUuidBuilder;
use Ramsey\Uuid\Codec\StringCodec;
use Ramsey\Uuid\Converter\Number\GenericNumberConverter;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\Time\GenericTimeConverter;
use Ramsey\Uuid\Converter\Time\PhpTimeConverter;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Generator\DceSecurityGenerator;
use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface;
use Ramsey\Uuid\Generator\NameGeneratorFactory;
use Ramsey\Uuid\Generator\NameGeneratorInterface;
use Ramsey\Uuid\Generator\PeclUuidNameGenerator;
use Ramsey\Uuid\Generator\PeclUuidRandomGenerator;
use Ramsey\Uuid\Generator\PeclUuidTimeGenerator;
use Ramsey\Uuid\Generator\RandomGeneratorFactory;
use Ramsey\Uuid\Generator\RandomGeneratorInterface;
use Ramsey\Uuid\Generator\TimeGeneratorFactory;
use Ramsey\Uuid\Generator\TimeGeneratorInterface;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Guid\GuidBuilder;
use Ramsey\Uuid\Math\BrickMathCalculator;
use Ramsey\Uuid\Math\CalculatorInterface;
use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder;
use Ramsey\Uuid\Provider\Dce\SystemDceSecurityProvider;
use Ramsey\Uuid\Provider\DceSecurityProviderInterface;
use Ramsey\Uuid\Provider\Node\FallbackNodeProvider;
use Ramsey\Uuid\Provider\Node\NodeProviderCollection;
use Ramsey\Uuid\Provider\Node\RandomNodeProvider;
use Ramsey\Uuid\Provider\Node\SystemNodeProvider;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\Time\SystemTimeProvider;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder;
use Ramsey\Uuid\Validator\GenericValidator;
use Ramsey\Uuid\Validator\ValidatorInterface;
use const PHP_INT_SIZE;
/**
* FeatureSet detects and exposes available features in the current environment
* (32- or 64-bit, available dependencies, etc.)
*
* A feature set is used by UuidFactory to determine the available features and
* capabilities of the environment.
*/
class FeatureSet
{
@@ -75,6 +93,16 @@ class FeatureSet
*/
private $codec;
/**
* @var DceSecurityGeneratorInterface
*/
private $dceSecurityGenerator;
/**
* @var NameGeneratorInterface
*/
private $nameGenerator;
/**
* @var NodeProviderInterface
*/
@@ -85,6 +113,11 @@ class FeatureSet
*/
private $numberConverter;
/**
* @var TimeConverterInterface
*/
private $timeConverter;
/**
* @var RandomGeneratorInterface
*/
@@ -96,117 +129,197 @@ class FeatureSet
private $timeGenerator;
/**
* Constructs a `FeatureSet` for use by a `UuidFactory` to determine or set
* features available to the environment
*
* @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec`
* @param bool $force32Bit Whether to force the use of 32-bit functionality
* @var TimeProviderInterface
*/
private $timeProvider;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* @var CalculatorInterface
*/
private $calculator;
/**
* @param bool $useGuids True build UUIDs using the GuidStringCodec
* @param bool $force32Bit True to force the use of 32-bit functionality
* (primarily for testing purposes)
* @param bool $forceNoBigNumber Whether to disable the use of moontoast/math
* `BigNumber` (primarily for testing purposes)
* @param bool $ignoreSystemNode Whether to disable attempts to check for
* the system host ID (primarily for testing purposes)
* @param bool $enablePecl Whether to enable the use of the `PeclUuidTimeGenerator`
* @param bool $forceNoBigNumber True to disable the use of moontoast/math
* (primarily for testing purposes)
* @param bool $ignoreSystemNode True to disable attempts to check for the
* system node ID (primarily for testing purposes)
* @param bool $enablePecl True to enable the use of the PeclUuidTimeGenerator
* to generate version 1 UUIDs
*/
public function __construct(
$useGuids = false,
$force32Bit = false,
$forceNoBigNumber = false,
$ignoreSystemNode = false,
$enablePecl = false
bool $useGuids = false,
bool $force32Bit = false,
bool $forceNoBigNumber = false,
bool $ignoreSystemNode = false,
bool $enablePecl = false
) {
$this->disableBigNumber = $forceNoBigNumber;
$this->disable64Bit = $force32Bit;
$this->ignoreSystemNode = $ignoreSystemNode;
$this->enablePecl = $enablePecl;
$this->numberConverter = $this->buildNumberConverter();
$this->builder = $this->buildUuidBuilder();
$this->setCalculator(new BrickMathCalculator());
$this->builder = $this->buildUuidBuilder($useGuids);
$this->codec = $this->buildCodec($useGuids);
$this->nodeProvider = $this->buildNodeProvider();
$this->nameGenerator = $this->buildNameGenerator();
$this->randomGenerator = $this->buildRandomGenerator();
$this->setTimeProvider(new SystemTimeProvider());
$this->setDceSecurityProvider(new SystemDceSecurityProvider());
$this->validator = new GenericValidator();
}
/**
* Returns the builder configured for this environment
*
* @return UuidBuilderInterface
*/
public function getBuilder()
public function getBuilder(): UuidBuilderInterface
{
return $this->builder;
}
/**
* Returns the UUID UUID coder-decoder configured for this environment
*
* @return CodecInterface
* Returns the calculator configured for this environment
*/
public function getCodec()
public function getCalculator(): CalculatorInterface
{
return $this->calculator;
}
/**
* Returns the codec configured for this environment
*/
public function getCodec(): CodecInterface
{
return $this->codec;
}
/**
* Returns the system node ID provider configured for this environment
*
* @return NodeProviderInterface
* Returns the DCE Security generator configured for this environment
*/
public function getNodeProvider()
public function getDceSecurityGenerator(): DceSecurityGeneratorInterface
{
return $this->dceSecurityGenerator;
}
/**
* Returns the name generator configured for this environment
*/
public function getNameGenerator(): NameGeneratorInterface
{
return $this->nameGenerator;
}
/**
* Returns the node provider configured for this environment
*/
public function getNodeProvider(): NodeProviderInterface
{
return $this->nodeProvider;
}
/**
* Returns the number converter configured for this environment
*
* @return NumberConverterInterface
*/
public function getNumberConverter()
public function getNumberConverter(): NumberConverterInterface
{
return $this->numberConverter;
}
/**
* Returns the random UUID generator configured for this environment
*
* @return RandomGeneratorInterface
* Returns the random generator configured for this environment
*/
public function getRandomGenerator()
public function getRandomGenerator(): RandomGeneratorInterface
{
return $this->randomGenerator;
}
/**
* Returns the time-based UUID generator configured for this environment
*
* @return TimeGeneratorInterface
* Returns the time converter configured for this environment
*/
public function getTimeGenerator()
public function getTimeConverter(): TimeConverterInterface
{
return $this->timeConverter;
}
/**
* Returns the time generator configured for this environment
*/
public function getTimeGenerator(): TimeGeneratorInterface
{
return $this->timeGenerator;
}
/**
* Sets the time provider for use in this environment
*
* @param TimeProviderInterface $timeProvider
* Returns the validator configured for this environment
*/
public function setTimeProvider(TimeProviderInterface $timeProvider)
public function getValidator(): ValidatorInterface
{
return $this->validator;
}
/**
* Sets the calculator to use in this environment
*/
public function setCalculator(CalculatorInterface $calculator): void
{
$this->calculator = $calculator;
$this->numberConverter = $this->buildNumberConverter($calculator);
$this->timeConverter = $this->buildTimeConverter($calculator);
/** @psalm-suppress RedundantPropertyInitializationCheck */
if (isset($this->timeProvider)) {
$this->timeGenerator = $this->buildTimeGenerator($this->timeProvider);
}
}
/**
* Sets the DCE Security provider to use in this environment
*/
public function setDceSecurityProvider(DceSecurityProviderInterface $dceSecurityProvider): void
{
$this->dceSecurityGenerator = $this->buildDceSecurityGenerator($dceSecurityProvider);
}
/**
* Sets the node provider to use in this environment
*/
public function setNodeProvider(NodeProviderInterface $nodeProvider): void
{
$this->nodeProvider = $nodeProvider;
$this->timeGenerator = $this->buildTimeGenerator($this->timeProvider);
}
/**
* Sets the time provider to use in this environment
*/
public function setTimeProvider(TimeProviderInterface $timeProvider): void
{
$this->timeProvider = $timeProvider;
$this->timeGenerator = $this->buildTimeGenerator($timeProvider);
}
/**
* Determines which UUID coder-decoder to use and returns the configured
* codec for this environment
*
* @param bool $useGuids Whether to build UUIDs using the `GuidStringCodec`
* @return CodecInterface
* Set the validator to use in this environment
*/
protected function buildCodec($useGuids = false)
public function setValidator(ValidatorInterface $validator): void
{
$this->validator = $validator;
}
/**
* Returns a codec configured for this environment
*
* @param bool $useGuids Whether to build UUIDs using the GuidStringCodec
*/
private function buildCodec(bool $useGuids = false): CodecInterface
{
if ($useGuids) {
return new GuidStringCodec($this->builder);
@@ -216,57 +329,60 @@ class FeatureSet
}
/**
* Determines which system node ID provider to use and returns the configured
* system node ID provider for this environment
*
* @return NodeProviderInterface
* Returns a DCE Security generator configured for this environment
*/
protected function buildNodeProvider()
private function buildDceSecurityGenerator(
DceSecurityProviderInterface $dceSecurityProvider
): DceSecurityGeneratorInterface {
return new DceSecurityGenerator(
$this->numberConverter,
$this->timeGenerator,
$dceSecurityProvider
);
}
/**
* Returns a node provider configured for this environment
*/
private function buildNodeProvider(): NodeProviderInterface
{
if ($this->ignoreSystemNode) {
return new RandomNodeProvider();
}
return new FallbackNodeProvider([
return new FallbackNodeProvider(new NodeProviderCollection([
new SystemNodeProvider(),
new RandomNodeProvider()
]);
new RandomNodeProvider(),
]));
}
/**
* Determines which number converter to use and returns the configured
* number converter for this environment
*
* @return NumberConverterInterface
* Returns a number converter configured for this environment
*/
protected function buildNumberConverter()
private function buildNumberConverter(CalculatorInterface $calculator): NumberConverterInterface
{
if ($this->hasBigNumber()) {
return new BigNumberConverter();
return new GenericNumberConverter($calculator);
}
/**
* Returns a random generator configured for this environment
*/
private function buildRandomGenerator(): RandomGeneratorInterface
{
if ($this->enablePecl) {
return new PeclUuidRandomGenerator();
}
return new DegradedNumberConverter();
}
/**
* Determines which random UUID generator to use and returns the configured
* random UUID generator for this environment
*
* @return RandomGeneratorInterface
*/
protected function buildRandomGenerator()
{
return (new RandomGeneratorFactory())->getGenerator();
}
/**
* Determines which time-based UUID generator to use and returns the configured
* time-based UUID generator for this environment
* Returns a time generator configured for this environment
*
* @param TimeProviderInterface $timeProvider
* @return TimeGeneratorInterface
* @param TimeProviderInterface $timeProvider The time provider to use with
* the time generator
*/
protected function buildTimeGenerator(TimeProviderInterface $timeProvider)
private function buildTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface
{
if ($this->enablePecl) {
return new PeclUuidTimeGenerator();
@@ -274,62 +390,60 @@ class FeatureSet
return (new TimeGeneratorFactory(
$this->nodeProvider,
$this->buildTimeConverter(),
$this->timeConverter,
$timeProvider
))->getGenerator();
}
/**
* Determines which time converter to use and returns the configured
* time converter for this environment
*
* @return TimeConverterInterface
* Returns a name generator configured for this environment
*/
protected function buildTimeConverter()
private function buildNameGenerator(): NameGeneratorInterface
{
if ($this->enablePecl) {
return new PeclUuidNameGenerator();
}
return (new NameGeneratorFactory())->getGenerator();
}
/**
* Returns a time converter configured for this environment
*/
private function buildTimeConverter(CalculatorInterface $calculator): TimeConverterInterface
{
$genericConverter = new GenericTimeConverter($calculator);
if ($this->is64BitSystem()) {
return new PhpTimeConverter();
return new PhpTimeConverter($calculator, $genericConverter);
}
if ($this->hasBigNumber()) {
return new BigNumberTimeConverter();
}
return new DegradedTimeConverter();
return $genericConverter;
}
/**
* Determines which UUID builder to use and returns the configured UUID
* builder for this environment
* Returns a UUID builder configured for this environment
*
* @return UuidBuilderInterface
* @param bool $useGuids Whether to build UUIDs using the GuidStringCodec
*/
protected function buildUuidBuilder()
private function buildUuidBuilder(bool $useGuids = false): UuidBuilderInterface
{
if ($this->is64BitSystem()) {
return new DefaultUuidBuilder($this->numberConverter);
if ($useGuids) {
return new GuidBuilder($this->numberConverter, $this->timeConverter);
}
return new DegradedUuidBuilder($this->numberConverter);
/** @psalm-suppress ImpureArgument */
return new FallbackBuilder(new BuilderCollection([
new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter),
new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter),
]));
}
/**
* Returns true if the system has `Moontoast\Math\BigNumber`
*
* @return bool
* Returns true if the PHP build is 64-bit
*/
protected function hasBigNumber()
private function is64BitSystem(): bool
{
return class_exists('Moontoast\Math\BigNumber') && !$this->disableBigNumber;
}
/**
* Returns true if the system is 64-bit, false otherwise
*
* @return bool
*/
protected function is64BitSystem()
{
return PHP_INT_SIZE == 8 && !$this->disable64Bit;
return PHP_INT_SIZE === 8 && !$this->disable64Bit;
}
}

View File

@@ -0,0 +1,32 @@
<?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\Fields;
use Serializable;
/**
* UUIDs are comprised of unsigned integers, the bytes of which are separated
* into fields and arranged in a particular layout defined by the specification
* for the variant
*
* @psalm-immutable
*/
interface FieldsInterface extends Serializable
{
/**
* Returns the bytes that comprise the fields
*/
public function getBytes(): string;
}

View File

@@ -0,0 +1,86 @@
<?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\Fields;
use ValueError;
use function base64_decode;
use function sprintf;
use function strlen;
/**
* Provides common serialization functionality to fields
*
* @psalm-immutable
*/
trait SerializableFieldsTrait
{
/**
* @param string $bytes The bytes that comprise the fields
*/
abstract public function __construct(string $bytes);
/**
* Returns the bytes that comprise the fields
*/
abstract public function getBytes(): string;
/**
* Returns a string representation of object
*/
public function serialize(): string
{
return $this->getBytes();
}
/**
* @return array{bytes: string}
*/
public function __serialize(): array
{
return ['bytes' => $this->getBytes()];
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
if (strlen($serialized) === 16) {
$this->__construct($serialized);
} else {
$this->__construct(base64_decode($serialized));
}
}
/**
* @param array{bytes: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['bytes'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['bytes']);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,27 +8,58 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Exception;
use InvalidArgumentException;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use function bin2hex;
use function explode;
use function hex2bin;
use function microtime;
use function str_pad;
use function substr;
use const STR_PAD_LEFT;
/**
* CombGenerator provides functionality to generate COMB (combined GUID/timestamp)
* sequential UUIDs
* CombGenerator generates COMBs (combined UUID/timestamp)
*
* @link https://en.wikipedia.org/wiki/Globally_unique_identifier#Sequential_algorithms
* The CombGenerator, when used with the StringCodec (and, by proxy, the
* TimestampLastCombCodec) or the TimestampFirstCombCodec, combines the current
* timestamp with a UUID (hence the name "COMB"). The timestamp either appears
* as the first or last 48 bits of the COMB, depending on the codec used.
*
* By default, COMBs will have the timestamp set as the last 48 bits of the
* identifier.
*
* ``` php
* $factory = new UuidFactory();
*
* $factory->setRandomGenerator(new CombGenerator(
* $factory->getRandomGenerator(),
* $factory->getNumberConverter()
* ));
*
* $comb = $factory->uuid4();
* ```
*
* To generate a COMB with the timestamp as the first 48 bits, set the
* TimestampFirstCombCodec as the codec.
*
* ``` php
* $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder()));
* ```
*
* @link https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys
*/
class CombGenerator implements RandomGeneratorInterface
{
const TIMESTAMP_BYTES = 6;
public const TIMESTAMP_BYTES = 6;
/**
* @var RandomGeneratorInterface
@@ -39,50 +71,54 @@ class CombGenerator implements RandomGeneratorInterface
*/
private $converter;
/**
* Constructs a `CombGenerator` using a random-number generator and a number converter
*
* @param RandomGeneratorInterface $generator Random-number generator for the non-time part.
* @param NumberConverterInterface $numberConverter Instance of number converter.
*/
public function __construct(RandomGeneratorInterface $generator, NumberConverterInterface $numberConverter)
{
public function __construct(
RandomGeneratorInterface $generator,
NumberConverterInterface $numberConverter
) {
$this->converter = $numberConverter;
$this->randomGenerator = $generator;
}
/**
* Generates a string of binary data of the specified length
* @throws InvalidArgumentException if $length is not a positive integer
* greater than or equal to CombGenerator::TIMESTAMP_BYTES
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
* @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
* @throws InvalidArgumentException if length is not a positive integer
* @throws Exception
* @inheritDoc
*/
public function generate($length)
public function generate(int $length): string
{
if ($length < self::TIMESTAMP_BYTES || $length < 0) {
throw new InvalidArgumentException('Length must be a positive integer.');
throw new InvalidArgumentException(
'Length must be a positive integer greater than or equal to ' . self::TIMESTAMP_BYTES
);
}
$hash = '';
if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) {
$hash = $this->randomGenerator->generate($length - self::TIMESTAMP_BYTES);
}
$lsbTime = str_pad($this->converter->toHex($this->timestamp()), self::TIMESTAMP_BYTES * 2, '0', STR_PAD_LEFT);
$lsbTime = str_pad(
$this->converter->toHex($this->timestamp()),
self::TIMESTAMP_BYTES * 2,
'0',
STR_PAD_LEFT
);
return hex2bin(str_pad(bin2hex($hash), $length - self::TIMESTAMP_BYTES, '0') . $lsbTime);
return (string) hex2bin(
str_pad(
bin2hex($hash),
$length - self::TIMESTAMP_BYTES,
'0'
)
. $lsbTime
);
}
/**
* Returns current timestamp as integer, precise to 0.00001 seconds
*
* @return string
* Returns current timestamp a string integer, precise to 0.00001 seconds
*/
private function timestamp()
private function timestamp(): string
{
$time = explode(' ', microtime(false));

View File

@@ -0,0 +1,160 @@
<?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\Generator;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Exception\DceSecurityException;
use Ramsey\Uuid\Provider\DceSecurityProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Uuid;
use function hex2bin;
use function in_array;
use function pack;
use function str_pad;
use function strlen;
use function substr_replace;
use const STR_PAD_LEFT;
/**
* DceSecurityGenerator generates strings of binary data based on a local
* domain, local identifier, node ID, clock sequence, and the current time
*/
class DceSecurityGenerator implements DceSecurityGeneratorInterface
{
private const DOMAINS = [
Uuid::DCE_DOMAIN_PERSON,
Uuid::DCE_DOMAIN_GROUP,
Uuid::DCE_DOMAIN_ORG,
];
/**
* Upper bounds for the clock sequence in DCE Security UUIDs.
*/
private const CLOCK_SEQ_HIGH = 63;
/**
* Lower bounds for the clock sequence in DCE Security UUIDs.
*/
private const CLOCK_SEQ_LOW = 0;
/**
* @var NumberConverterInterface
*/
private $numberConverter;
/**
* @var TimeGeneratorInterface
*/
private $timeGenerator;
/**
* @var DceSecurityProviderInterface
*/
private $dceSecurityProvider;
public function __construct(
NumberConverterInterface $numberConverter,
TimeGeneratorInterface $timeGenerator,
DceSecurityProviderInterface $dceSecurityProvider
) {
$this->numberConverter = $numberConverter;
$this->timeGenerator = $timeGenerator;
$this->dceSecurityProvider = $dceSecurityProvider;
}
public function generate(
int $localDomain,
?IntegerObject $localIdentifier = null,
?Hexadecimal $node = null,
?int $clockSeq = null
): string {
if (!in_array($localDomain, self::DOMAINS)) {
throw new DceSecurityException(
'Local domain must be a valid DCE Security domain'
);
}
if ($localIdentifier && $localIdentifier->isNegative()) {
throw new DceSecurityException(
'Local identifier out of bounds; it must be a value between 0 and 4294967295'
);
}
if ($clockSeq > self::CLOCK_SEQ_HIGH || $clockSeq < self::CLOCK_SEQ_LOW) {
throw new DceSecurityException(
'Clock sequence out of bounds; it must be a value between 0 and 63'
);
}
switch ($localDomain) {
case Uuid::DCE_DOMAIN_ORG:
if ($localIdentifier === null) {
throw new DceSecurityException(
'A local identifier must be provided for the org domain'
);
}
break;
case Uuid::DCE_DOMAIN_PERSON:
if ($localIdentifier === null) {
$localIdentifier = $this->dceSecurityProvider->getUid();
}
break;
case Uuid::DCE_DOMAIN_GROUP:
default:
if ($localIdentifier === null) {
$localIdentifier = $this->dceSecurityProvider->getGid();
}
break;
}
$identifierHex = $this->numberConverter->toHex($localIdentifier->toString());
// The maximum value for the local identifier is 0xffffffff, or
// 4294967295. This is 8 hexadecimal digits, so if the length of
// hexadecimal digits is greater than 8, we know the value is greater
// than 0xffffffff.
if (strlen($identifierHex) > 8) {
throw new DceSecurityException(
'Local identifier out of bounds; it must be a value between 0 and 4294967295'
);
}
$domainByte = pack('n', $localDomain)[1];
$identifierBytes = (string) hex2bin(str_pad($identifierHex, 8, '0', STR_PAD_LEFT));
if ($node instanceof Hexadecimal) {
$node = $node->toString();
}
// Shift the clock sequence 8 bits to the left, so it matches 0x3f00.
if ($clockSeq !== null) {
$clockSeq = $clockSeq << 8;
}
$bytes = $this->timeGenerator->generate($node, $clockSeq);
// Replace bytes in the time-based UUID with DCE Security values.
$bytes = substr_replace($bytes, $identifierBytes, 0, 4);
$bytes = substr_replace($bytes, $domainByte, 9, 1);
return $bytes;
}
}

View File

@@ -0,0 +1,53 @@
<?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\Generator;
use Ramsey\Uuid\Rfc4122\UuidV2;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
/**
* A DCE Security generator generates strings of binary data based on a local
* domain, local identifier, node ID, clock sequence, and the current time
*
* @see UuidV2
*/
interface DceSecurityGeneratorInterface
{
/**
* Generate a binary string from a local domain, local identifier, node ID,
* clock sequence, and current time
*
* @param int $localDomain The local domain to use when generating bytes,
* according to DCE Security
* @param IntegerObject|null $localIdentifier The local identifier for the
* given domain; this may be a UID or GID on POSIX systems, if the local
* domain is person or group, or it may be a site-defined identifier
* if the local domain is org
* @param Hexadecimal|null $node A 48-bit number representing the hardware
* address
* @param int|null $clockSeq A 14-bit number used to help avoid duplicates
* that could arise when the clock is set backwards in time or if the
* node ID changes
*
* @return string A binary string
*/
public function generate(
int $localDomain,
?IntegerObject $localIdentifier = null,
?Hexadecimal $node = null,
?int $clockSeq = null
): string;
}

View File

@@ -0,0 +1,48 @@
<?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\Generator;
use Ramsey\Uuid\Exception\NameException;
use Ramsey\Uuid\UuidInterface;
use ValueError;
use function hash;
/**
* DefaultNameGenerator generates strings of binary data based on a namespace,
* name, and hashing algorithm
*/
class DefaultNameGenerator implements NameGeneratorInterface
{
/** @psalm-pure */
public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string
{
try {
/** @var string|bool $bytes */
$bytes = @hash($hashAlgorithm, $ns->getBytes() . $name, true);
} catch (ValueError $e) {
$bytes = false; // keep same behavior than PHP 7
}
if ($bytes === false) {
throw new NameException(sprintf(
'Unable to hash namespace and name with algorithm \'%s\'',
$hashAlgorithm
));
}
return (string) $bytes;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,25 +8,35 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Exception;
use InvalidArgumentException;
use Ramsey\Uuid\BinaryUtils;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Exception\RandomSourceException;
use Ramsey\Uuid\Exception\TimeSourceException;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Throwable;
use function ctype_xdigit;
use function dechex;
use function hex2bin;
use function is_int;
use function pack;
use function sprintf;
use function str_pad;
use function strlen;
use const STR_PAD_LEFT;
/**
* DefaultTimeGenerator provides functionality to generate strings of binary
* data for version 1 UUIDs based on a host ID, sequence number, and the current
* time
* DefaultTimeGenerator generates strings of binary data based on a node ID,
* clock sequence, and the current time
*/
class DefaultTimeGenerator implements TimeGeneratorInterface
{
@@ -44,14 +55,6 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
*/
private $timeProvider;
/**
* Constructs a `DefaultTimeGenerator` using a node provider, time converter,
* and time provider
*
* @param NodeProviderInterface $nodeProvider
* @param TimeConverterInterface $timeConverter
* @param TimeProviderInterface $timeProvider
*/
public function __construct(
NodeProviderInterface $nodeProvider,
TimeConverterInterface $timeConverter,
@@ -63,79 +66,82 @@ class DefaultTimeGenerator implements TimeGeneratorInterface
}
/**
* Generate a version 1 UUID from a host ID, sequence number, and the current time
* @throws InvalidArgumentException if the parameters contain invalid values
* @throws RandomSourceException if random_int() throws an exception/error
*
* If $node is not given, we will attempt to obtain the local hardware
* address. If $clockSeq is given, it is used as the sequence number;
* otherwise a random 14-bit sequence number is chosen.
*
* @param int|string $node A 48-bit number representing the hardware address
* This number may be represented as an integer or a hexadecimal string.
* @param int $clockSeq A 14-bit number used to help avoid duplicates that
* could arise when the clock is set backwards in time or if the node ID
* changes.
* @return string A binary string
* @throws UnsatisfiedDependencyException if called on a 32-bit system and
* `Moontoast\Math\BigNumber` is not present
* @throws InvalidArgumentException
* @throws Exception if it was not possible to gather sufficient entropy
* @inheritDoc
*/
public function generate($node = null, $clockSeq = null)
public function generate($node = null, ?int $clockSeq = null): string
{
if ($node instanceof Hexadecimal) {
$node = $node->toString();
}
$node = $this->getValidNode($node);
if ($clockSeq === null) {
// Not using "stable storage"; see RFC 4122, Section 4.2.1.1
$clockSeq = random_int(0, 0x3fff);
try {
// This does not use "stable storage"; see RFC 4122, Section 4.2.1.1.
$clockSeq = random_int(0, 0x3fff);
} catch (Throwable $exception) {
throw new RandomSourceException(
$exception->getMessage(),
(int) $exception->getCode(),
$exception
);
}
}
// Create a 60-bit time value as a count of 100-nanosecond intervals
// since 00:00:00.00, 15 October 1582
$timeOfDay = $this->timeProvider->currentTime();
$uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']);
$time = $this->timeProvider->getTime();
$timeHi = BinaryUtils::applyVersion($uuidTime['hi'], 1);
$clockSeqHi = BinaryUtils::applyVariant($clockSeq >> 8);
$hex = vsprintf(
'%08s%04s%04s%02s%02s%012s',
[
$uuidTime['low'],
$uuidTime['mid'],
sprintf('%04x', $timeHi),
sprintf('%02x', $clockSeqHi),
sprintf('%02x', $clockSeq & 0xff),
$node,
]
$uuidTime = $this->timeConverter->calculateTime(
$time->getSeconds()->toString(),
$time->getMicroseconds()->toString()
);
return hex2bin($hex);
$timeHex = str_pad($uuidTime->toString(), 16, '0', STR_PAD_LEFT);
if (strlen($timeHex) !== 16) {
throw new TimeSourceException(sprintf(
'The generated time of \'%s\' is larger than expected',
$timeHex
));
}
$timeBytes = (string) hex2bin($timeHex);
return $timeBytes[4] . $timeBytes[5] . $timeBytes[6] . $timeBytes[7]
. $timeBytes[2] . $timeBytes[3]
. $timeBytes[0] . $timeBytes[1]
. pack('n*', $clockSeq)
. $node;
}
/**
* Uses the node provider given when constructing this instance to get
* the node ID (usually a MAC address)
*
* @param string|int $node A node value that may be used to override the node provider
* @return string Hexadecimal representation of the node ID
* @param string|int|null $node A node value that may be used to override the node provider
*
* @return string 6-byte binary string representation of the node
*
* @throws InvalidArgumentException
* @throws Exception
*/
protected function getValidNode($node)
private function getValidNode($node): string
{
if ($node === null) {
$node = $this->nodeProvider->getNode();
}
// Convert the node to hex, if it is still an integer
// Convert the node to hex, if it is still an integer.
if (is_int($node)) {
$node = sprintf('%012x', $node);
$node = dechex($node);
}
if (!ctype_xdigit($node) || strlen($node) > 12) {
if (!ctype_xdigit((string) $node) || strlen((string) $node) > 12) {
throw new InvalidArgumentException('Invalid node value');
}
return strtolower(sprintf('%012s', $node));
return (string) hex2bin(str_pad((string) $node, 12, '0', STR_PAD_LEFT));
}
}

View File

@@ -1,45 +0,0 @@
<?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
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
namespace Ramsey\Uuid\Generator;
/**
* MtRandRandomGenerator provides functionality to generate strings of random
* binary data using the `mt_rand()` PHP function
*
* @deprecated The mt_rand() function is not a reliable source of randomness.
* The default RandomBytesGenerator, which uses the random_bytes() function,
* is recommended as the safest and most reliable source of randomness.
* <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
* @link http://php.net/mt_rand
*/
class MtRandGenerator implements RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
*/
public function generate($length)
{
$bytes = '';
for ($i = 1; $i <= $length; $i++) {
$bytes = chr(mt_rand(0, 255)) . $bytes;
}
return $bytes;
}
}

View File

@@ -0,0 +1,30 @@
<?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\Generator;
/**
* NameGeneratorFactory retrieves a default name generator, based on the
* environment
*/
class NameGeneratorFactory
{
/**
* Returns a default name generator, based on the current environment
*/
public function getGenerator(): NameGeneratorInterface
{
return new DefaultNameGenerator();
}
}

View File

@@ -0,0 +1,38 @@
<?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\Generator;
use Ramsey\Uuid\UuidInterface;
/**
* A name generator generates strings of binary data created by hashing together
* a namespace with a name, according to a hashing algorithm
*/
interface NameGeneratorInterface
{
/**
* Generate a binary string from a namespace and name hashed together with
* the specified hashing algorithm
*
* @param UuidInterface $ns The namespace
* @param string $name The name to use for creating a UUID
* @param string $hashAlgorithm The hashing algorithm to use
*
* @return string A binary string
*
* @psalm-pure
*/
public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string;
}

View File

@@ -1,43 +0,0 @@
<?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
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
namespace Ramsey\Uuid\Generator;
/**
* OpenSslRandomGenerator provides functionality to generate strings of random
* binary data using the `openssl_random_pseudo_bytes()` PHP function
*
* The use of this generator requires PHP to be compiled using the
* `--with-openssl` option.
*
* @deprecated The openssl_random_pseudo_bytes() function is not a reliable
* source of randomness. The default RandomBytesGenerator, which uses the
* random_bytes() function, is recommended as the safest and most reliable
* source of randomness.
* <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
* @link http://php.net/openssl_random_pseudo_bytes
*/
class OpenSslGenerator implements RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
*/
public function generate($length)
{
return openssl_random_pseudo_bytes($length);
}
}

View File

@@ -0,0 +1,54 @@
<?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\Generator;
use Ramsey\Uuid\Exception\NameException;
use Ramsey\Uuid\UuidInterface;
use function sprintf;
use function uuid_generate_md5;
use function uuid_generate_sha1;
use function uuid_parse;
/**
* PeclUuidNameGenerator generates strings of binary data from a namespace and a
* name, using ext-uuid
*
* @link https://pecl.php.net/package/uuid ext-uuid
*/
class PeclUuidNameGenerator implements NameGeneratorInterface
{
/** @psalm-pure */
public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string
{
switch ($hashAlgorithm) {
case 'md5':
$uuid = uuid_generate_md5($ns->toString(), $name);
break;
case 'sha1':
$uuid = uuid_generate_sha1($ns->toString(), $name);
break;
default:
throw new NameException(sprintf(
'Unable to hash namespace and name with algorithm \'%s\'',
$hashAlgorithm
));
}
return uuid_parse($uuid);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,28 +8,25 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use function uuid_create;
use function uuid_parse;
use const UUID_TYPE_RANDOM;
/**
* PeclUuidRandomGenerator provides functionality to generate strings of random
* binary data using the PECL UUID PHP extension
* PeclUuidRandomGenerator generates strings of random binary data using ext-uuid
*
* @link https://pecl.php.net/package/uuid
* @link https://pecl.php.net/package/uuid ext-uuid
*/
class PeclUuidRandomGenerator implements RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
*/
public function generate($length)
public function generate(int $length): string
{
$uuid = uuid_create(UUID_TYPE_RANDOM);

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,29 +8,29 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use function uuid_create;
use function uuid_parse;
use const UUID_TYPE_TIME;
/**
* PeclUuidTimeGenerator provides functionality to generate strings of binary
* data for version 1 UUIDs using the PECL UUID PHP extension
* PeclUuidTimeGenerator generates strings of binary data for time-base UUIDs,
* using ext-uuid
*
* @link https://pecl.php.net/package/uuid
* @link https://pecl.php.net/package/uuid ext-uuid
*/
class PeclUuidTimeGenerator implements TimeGeneratorInterface
{
/**
* Generate a version 1 UUID using the PECL UUID extension
*
* @param int|string $node Not used in this context
* @param int $clockSeq Not used in this context
* @return string A binary string
* @inheritDoc
*/
public function generate($node = null, $clockSeq = null)
public function generate($node = null, ?int $clockSeq = null): string
{
$uuid = uuid_create(UUID_TYPE_TIME);

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,33 +8,38 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Exception;
use Ramsey\Uuid\Exception\RandomSourceException;
use Throwable;
/**
* RandomBytesGenerator provides functionality to generate strings of random
* binary data using `random_bytes()` function in PHP 7+ or paragonie/random_compat
* RandomBytesGenerator generates strings of random binary data using the
* built-in `random_bytes()` PHP function
*
* @link http://php.net/random_bytes
* @link https://github.com/paragonie/random_compat
* @link http://php.net/random_bytes random_bytes()
*/
class RandomBytesGenerator implements RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
* @throws RandomSourceException if random_bytes() throws an exception/error
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
* @throws Exception if it was not possible to gather sufficient entropy
* @inheritDoc
*/
public function generate($length)
public function generate(int $length): string
{
return random_bytes($length);
try {
return random_bytes($length);
} catch (Throwable $exception) {
throw new RandomSourceException(
$exception->getMessage(),
(int) $exception->getCode(),
$exception
);
}
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,24 +8,22 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
/**
* A factory for retrieving a random generator, based on the environment
* RandomGeneratorFactory retrieves a default random generator, based on the
* environment
*/
class RandomGeneratorFactory
{
/**
* Returns a default random generator, based on the current environment
*
* @return RandomGeneratorInterface
*/
public static function getGenerator()
public function getGenerator(): RandomGeneratorInterface
{
return new RandomBytesGenerator();
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,31 +8,23 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Exception;
use InvalidArgumentException;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
/**
* RandomGeneratorInterface provides functionality to generate strings of random
* binary data
* A random generator generates strings of random binary data
*/
interface RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
* Generates a string of randomized binary data
*
* @param int $length The number of bytes of random binary data to generate
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
* @throws UnsatisfiedDependencyException if `Moontoast\Math\BigNumber` is not present
* @throws InvalidArgumentException
* @throws Exception if it was not possible to gather sufficient entropy
*/
public function generate($length);
public function generate(int $length): string;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,21 +8,20 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use RandomLib\Generator;
use RandomLib\Factory;
use RandomLib\Generator;
/**
* RandomLibAdapter provides functionality to generate strings of random
* binary data using the paragonie/random-lib library
* RandomLibAdapter generates strings of random binary data using the
* paragonie/random-lib library
*
* @link https://packagist.org/packages/paragonie/random-lib
* @link https://packagist.org/packages/paragonie/random-lib paragonie/random-lib
*/
class RandomLibAdapter implements RandomGeneratorInterface
{
@@ -31,31 +31,24 @@ class RandomLibAdapter implements RandomGeneratorInterface
private $generator;
/**
* Constructs a `RandomLibAdapter` using a `RandomLib\Generator`
* Constructs a RandomLibAdapter
*
* By default, if no `Generator` is passed in, this creates a high-strength
* By default, if no Generator is passed in, this creates a high-strength
* generator to use when generating random binary data.
*
* @param Generator $generator An paragonie/random-lib `Generator`
* @param Generator|null $generator The generator to use when generating binary data
*/
public function __construct(Generator $generator = null)
public function __construct(?Generator $generator = null)
{
$this->generator = $generator;
if ($this->generator === null) {
if ($generator === null) {
$factory = new Factory();
$this->generator = $factory->getHighStrengthGenerator();
$generator = $factory->getHighStrengthGenerator();
}
$this->generator = $generator;
}
/**
* Generates a string of random binary data of the specified length
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
*/
public function generate($length)
public function generate(int $length): string
{
return $this->generator->generate($length);
}

View File

@@ -1,41 +0,0 @@
<?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
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
namespace Ramsey\Uuid\Generator;
/**
* SodiumRandomGenerator provides functionality to generate strings of random
* binary data using the PECL libsodium extension
*
* @deprecated As of PHP 7.2.0, the libsodium extension is bundled with PHP, and
* the random_bytes() PHP function is now the recommended method for
* generating random byes. The default RandomBytesGenerator uses the
* random_bytes() function.
* <em>This generator will be removed in ramsey/uuid 4.0.0.</em>
* @link http://pecl.php.net/package/libsodium
* @link https://paragonie.com/book/pecl-libsodium
*/
class SodiumRandomGenerator implements RandomGeneratorInterface
{
/**
* Generates a string of random binary data of the specified length
*
* @param integer $length The number of bytes of random binary data to generate
* @return string A binary string
*/
public function generate($length)
{
return \Sodium\randombytes_buf($length);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,11 +8,10 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Ramsey\Uuid\Converter\TimeConverterInterface;
@@ -19,7 +19,8 @@ use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Provider\TimeProviderInterface;
/**
* A factory for retrieving a time generator, based on the environment
* TimeGeneratorFactory retrieves a default time generator, based on the
* environment
*/
class TimeGeneratorFactory
{
@@ -38,14 +39,6 @@ class TimeGeneratorFactory
*/
private $timeProvider;
/**
* Constructs a `TimeGeneratorFactory` using a node provider, time converter,
* and time provider
*
* @param NodeProviderInterface $nodeProvider
* @param TimeConverterInterface $timeConverter
* @param TimeProviderInterface $timeProvider
*/
public function __construct(
NodeProviderInterface $nodeProvider,
TimeConverterInterface $timeConverter,
@@ -58,10 +51,8 @@ class TimeGeneratorFactory
/**
* Returns a default time generator, based on the current environment
*
* @return TimeGeneratorInterface
*/
public function getGenerator()
public function getGenerator(): TimeGeneratorInterface
{
return new DefaultTimeGenerator(
$this->nodeProvider,

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,37 +8,31 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Generator;
use Exception;
use InvalidArgumentException;
use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* TimeGeneratorInterface provides functionality to generate strings of binary
* data for version 1 UUIDs based on a host ID, sequence number, and the current
* time
* A time generator generates strings of binary data based on a node ID,
* clock sequence, and the current time
*/
interface TimeGeneratorInterface
{
/**
* Generate a version 1 UUID from a host ID, sequence number, and the current time
* Generate a binary string from a node ID, clock sequence, and current time
*
* @param Hexadecimal|int|string|null $node A 48-bit number representing the
* hardware address; this number may be represented as an integer or a
* hexadecimal string
* @param int|null $clockSeq A 14-bit number used to help avoid duplicates
* that could arise when the clock is set backwards in time or if the
* node ID changes
*
* @param int|string $node A 48-bit number representing the hardware address
* This number may be represented as an integer or a hexadecimal string.
* @param int $clockSeq A 14-bit number used to help avoid duplicates that
* could arise when the clock is set backwards in time or if the node ID
* changes.
* @return string A binary string
* @throws UnsatisfiedDependencyException if called on a 32-bit system and
* `Moontoast\Math\BigNumber` is not present
* @throws InvalidArgumentException
* @throws Exception if it was not possible to gather sufficient entropy
*/
public function generate($node = null, $clockSeq = null);
public function generate($node = null, ?int $clockSeq = null): string;
}

194
vendor/ramsey/uuid/src/Guid/Fields.php vendored Normal file
View File

@@ -0,0 +1,194 @@
<?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\Guid;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Fields\SerializableFieldsTrait;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Rfc4122\NilTrait;
use Ramsey\Uuid\Rfc4122\VariantTrait;
use Ramsey\Uuid\Rfc4122\VersionTrait;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Uuid;
use function bin2hex;
use function dechex;
use function hexdec;
use function pack;
use function sprintf;
use function str_pad;
use function strlen;
use function substr;
use function unpack;
use const STR_PAD_LEFT;
/**
* GUIDs are comprised of a set of named fields, according to RFC 4122
*
* @see Guid
*
* @psalm-immutable
*/
final class Fields implements FieldsInterface
{
use NilTrait;
use SerializableFieldsTrait;
use VariantTrait;
use VersionTrait;
/**
* @var string
*/
private $bytes;
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
* @throws InvalidArgumentException if the byte string is not exactly 16 bytes
* @throws InvalidArgumentException if the byte string does not represent a GUID
* @throws InvalidArgumentException if the byte string does not contain a valid version
*/
public function __construct(string $bytes)
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
. 'received ' . strlen($bytes) . ' bytes'
);
}
$this->bytes = $bytes;
if (!$this->isCorrectVariant()) {
throw new InvalidArgumentException(
'The byte string received does not conform to the RFC '
. '4122 or Microsoft Corporation variants'
);
}
if (!$this->isCorrectVersion()) {
throw new InvalidArgumentException(
'The byte string received does not contain a valid version'
);
}
}
public function getBytes(): string
{
return $this->bytes;
}
public function getTimeLow(): Hexadecimal
{
// Swap the bytes from little endian to network byte order.
/** @var array $hex */
$hex = unpack(
'H*',
pack(
'v*',
hexdec(bin2hex(substr($this->bytes, 2, 2))),
hexdec(bin2hex(substr($this->bytes, 0, 2)))
)
);
return new Hexadecimal((string) ($hex[1] ?? ''));
}
public function getTimeMid(): Hexadecimal
{
// Swap the bytes from little endian to network byte order.
/** @var array $hex */
$hex = unpack(
'H*',
pack(
'v',
hexdec(bin2hex(substr($this->bytes, 4, 2)))
)
);
return new Hexadecimal((string) ($hex[1] ?? ''));
}
public function getTimeHiAndVersion(): Hexadecimal
{
// Swap the bytes from little endian to network byte order.
/** @var array $hex */
$hex = unpack(
'H*',
pack(
'v',
hexdec(bin2hex(substr($this->bytes, 6, 2)))
)
);
return new Hexadecimal((string) ($hex[1] ?? ''));
}
public function getTimestamp(): Hexadecimal
{
return new Hexadecimal(sprintf(
'%03x%04s%08s',
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
$this->getTimeMid()->toString(),
$this->getTimeLow()->toString()
));
}
public function getClockSeq(): Hexadecimal
{
$clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
}
public function getClockSeqHiAndReserved(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1)));
}
public function getClockSeqLow(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1)));
}
public function getNode(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 10)));
}
public function getVersion(): ?int
{
if ($this->isNil()) {
return null;
}
/** @var array $parts */
$parts = unpack('n*', $this->bytes);
return ((int) $parts[4] >> 4) & 0x00f;
}
private function isCorrectVariant(): bool
{
if ($this->isNil()) {
return true;
}
$variant = $this->getVariant();
return $variant === Uuid::RFC_4122 || $variant === Uuid::RESERVED_MICROSOFT;
}
}

61
vendor/ramsey/uuid/src/Guid/Guid.php vendored Normal file
View File

@@ -0,0 +1,61 @@
<?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\Guid;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Uuid;
/**
* Guid represents a UUID with "native" (little-endian) byte order
*
* From Wikipedia:
*
* > The first three fields are unsigned 32- and 16-bit integers and are subject
* > to swapping, while the last two fields consist of uninterpreted bytes, not
* > subject to swapping. This byte swapping applies even for versions 3, 4, and
* > 5, where the canonical fields do not correspond to the content of the UUID.
*
* The first three fields of a GUID are encoded in little-endian byte order,
* while the last three fields are in network (big-endian) byte order. This is
* according to the history of the Microsoft definition of a GUID.
*
* According to the .NET Guid.ToByteArray method documentation:
*
* > Note that the order of bytes in the returned byte array is different from
* > the string representation of a Guid value. The order of the beginning
* > four-byte group and the next two two-byte groups is reversed, whereas the
* > order of the last two-byte group and the closing six-byte group is the
* > same.
*
* @link https://en.wikipedia.org/wiki/Universally_unique_identifier#Variants UUID Variants on Wikipedia
* @link https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid Windows GUID structure
* @link https://docs.microsoft.com/en-us/dotnet/api/system.guid .NET Guid Struct
* @link https://docs.microsoft.com/en-us/dotnet/api/system.guid.tobytearray .NET Guid.ToByteArray Method
*
* @psalm-immutable
*/
final class Guid extends Uuid
{
public function __construct(
Fields $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
}

View File

@@ -0,0 +1,89 @@
<?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\Guid;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\UuidInterface;
use Throwable;
/**
* GuidBuilder builds instances of Guid
*
* @see Guid
*
* @psalm-immutable
*/
class GuidBuilder implements UuidBuilderInterface
{
/**
* @var NumberConverterInterface
*/
private $numberConverter;
/**
* @var TimeConverterInterface
*/
private $timeConverter;
/**
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Guid
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
NumberConverterInterface $numberConverter,
TimeConverterInterface $timeConverter
) {
$this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter;
}
/**
* Builds and returns a Guid
*
* @param CodecInterface $codec The codec to use for building this Guid instance
* @param string $bytes The byte string from which to construct a UUID
*
* @return Guid The GuidBuilder returns an instance of Ramsey\Uuid\Guid\Guid
*
* @psalm-pure
*/
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
try {
return new Guid(
$this->buildFields($bytes),
$this->numberConverter,
$codec,
$this->timeConverter
);
} catch (Throwable $e) {
throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* Proxy method to allow injecting a mock, for testing
*/
protected function buildFields(string $bytes): Fields
{
return new Fields($bytes);
}
}

View File

@@ -0,0 +1,575 @@
<?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\Lazy;
use DateTimeInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Fields\FieldsInterface;
use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\UuidFactory;
use Ramsey\Uuid\UuidInterface;
use ValueError;
use function assert;
use function bin2hex;
use function hex2bin;
use function sprintf;
use function str_replace;
use function substr;
/**
* Lazy version of a UUID: its format has not been determined yet, so it is mostly only usable for string/bytes
* conversion. This object optimizes instantiation, serialization and string conversion time, at the cost of
* increased overhead for more advanced UUID operations.
*
* @internal this type is used internally for performance reasons, and is not supposed to be directly referenced
* in consumer libraries.
*
* @psalm-immutable
*
* Note: the {@see FieldsInterface} does not declare methods that deprecated API
* relies upon: the API has been ported from the {@see \Ramsey\Uuid\Uuid} definition,
* and is deprecated anyway.
* Note: the deprecated API from {@see \Ramsey\Uuid\Uuid} is in use here (on purpose): it will be removed
* once the deprecated API is gone from this class too.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
*/
final class LazyUuidFromString implements UuidInterface
{
public const VALID_REGEX = '/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/ms';
/**
* @var string
* @psalm-var non-empty-string
*/
private $uuid;
/** @var UuidInterface|null */
private $unwrapped;
/** @psalm-param non-empty-string $uuid */
public function __construct(string $uuid)
{
$this->uuid = $uuid;
}
/** @psalm-pure */
public static function fromBytes(string $bytes): self
{
$base16Uuid = bin2hex($bytes);
return new self(
substr($base16Uuid, 0, 8)
. '-'
. substr($base16Uuid, 8, 4)
. '-'
. substr($base16Uuid, 12, 4)
. '-'
. substr($base16Uuid, 16, 4)
. '-'
. substr($base16Uuid, 20, 12)
);
}
public function serialize(): string
{
return $this->uuid;
}
/**
* @return array{string: string}
*
* @psalm-return array{string: non-empty-string}
*/
public function __serialize(): array
{
return ['string' => $this->uuid];
}
/**
* {@inheritDoc}
*
* @param string $serialized
*
* @psalm-param non-empty-string $serialized
*/
public function unserialize($serialized): void
{
$this->uuid = $serialized;
}
/**
* @param array{string: string} $data
*
* @psalm-param array{string: non-empty-string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
}
/** @psalm-suppress DeprecatedMethod */
public function getNumberConverter(): NumberConverterInterface
{
return ($this->unwrapped ?? $this->unwrap())
->getNumberConverter();
}
/**
* {@inheritDoc}
*
* @psalm-suppress DeprecatedMethod
*/
public function getFieldsHex(): array
{
return ($this->unwrapped ?? $this->unwrap())
->getFieldsHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getClockSeqHiAndReservedHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getClockSeqHiAndReservedHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getClockSeqLowHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getClockSeqLowHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getClockSequenceHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getClockSequenceHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getDateTime(): DateTimeInterface
{
return ($this->unwrapped ?? $this->unwrap())
->getDateTime();
}
/** @psalm-suppress DeprecatedMethod */
public function getLeastSignificantBitsHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getLeastSignificantBitsHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getMostSignificantBitsHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getMostSignificantBitsHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getNodeHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getNodeHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getTimeHiAndVersionHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getTimeHiAndVersionHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getTimeLowHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getTimeLowHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getTimeMidHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getTimeMidHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getTimestampHex(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getTimestampHex();
}
/** @psalm-suppress DeprecatedMethod */
public function getUrn(): string
{
return ($this->unwrapped ?? $this->unwrap())
->getUrn();
}
/** @psalm-suppress DeprecatedMethod */
public function getVariant(): ?int
{
return ($this->unwrapped ?? $this->unwrap())
->getVariant();
}
/** @psalm-suppress DeprecatedMethod */
public function getVersion(): ?int
{
return ($this->unwrapped ?? $this->unwrap())
->getVersion();
}
public function compareTo(UuidInterface $other): int
{
return ($this->unwrapped ?? $this->unwrap())
->compareTo($other);
}
public function equals(?object $other): bool
{
if (! $other instanceof UuidInterface) {
return false;
}
return $this->uuid === $other->toString();
}
/**
* {@inheritDoc}
*
* @psalm-suppress MoreSpecificReturnType
* @psalm-suppress LessSpecificReturnStatement we know that {@see self::$uuid} is a non-empty string, so
* we know that {@see hex2bin} will retrieve a non-empty string too.
*/
public function getBytes(): string
{
/** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
return (string) hex2bin(str_replace('-', '', $this->uuid));
}
public function getFields(): FieldsInterface
{
return ($this->unwrapped ?? $this->unwrap())
->getFields();
}
public function getHex(): Hexadecimal
{
return ($this->unwrapped ?? $this->unwrap())
->getHex();
}
public function getInteger(): IntegerObject
{
return ($this->unwrapped ?? $this->unwrap())
->getInteger();
}
public function toString(): string
{
return $this->uuid;
}
public function __toString(): string
{
return $this->uuid;
}
public function jsonSerialize(): string
{
return $this->uuid;
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getClockSeqHiAndReserved(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getClockSeqHiAndReserved()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getClockSeqLow(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getClockSeqLow()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getClockSequence(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getClockSeq()
->toString()
);
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getLeastSignificantBits(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(substr($instance->getHex()->toString(), 16));
}
/**
* @deprecated This method will be removed in 5.0.0. There is no direct
* alternative, but the same information may be obtained by splitting
* in half the value returned by {@see UuidInterface::getHex()}.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getMostSignificantBits(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(substr($instance->getHex()->toString(), 0, 16));
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getNode()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getNode(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getNode()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getTimeHiAndVersion(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getTimeHiAndVersion()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getTimeLow(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getTimeLow()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getTimeMid(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
return $instance->getNumberConverter()
->fromHex(
$instance->getFields()
->getTimeMid()
->toString()
);
}
/**
* @deprecated Use {@see UuidInterface::getFields()} to get a
* {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
* instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}
* and use the arbitrary-precision math library of your choice to
* convert it to a string integer.
*
* @psalm-suppress UndefinedInterfaceMethod
* @psalm-suppress DeprecatedMethod
* @psalm-suppress MixedArgument
* @psalm-suppress MixedMethodCall
*/
public function getTimestamp(): string
{
$instance = ($this->unwrapped ?? $this->unwrap());
$fields = $instance->getFields();
if ($fields->getVersion() !== 1) {
throw new UnsupportedOperationException('Not a time-based UUID');
}
return $instance->getNumberConverter()
->fromHex($fields->getTimestamp()->toString());
}
public function toUuidV1(): UuidV1
{
$instance = ($this->unwrapped ?? $this->unwrap());
if ($instance instanceof UuidV1) {
return $instance;
}
assert($instance instanceof UuidV6);
return $instance->toUuidV1();
}
public function toUuidV6(): UuidV6
{
$instance = ($this->unwrapped ?? $this->unwrap());
assert($instance instanceof UuidV6);
return $instance;
}
/**
* @psalm-suppress ImpureMethodCall the retrieval of the factory is a clear violation of purity here: this is a
* known pitfall of the design of this library, where a value object contains
* a mutable reference to a factory. We use a fixed factory here, so the violation
* will not have real-world effects, as this object is only instantiated with the
* default factory settings/features.
* @psalm-suppress InaccessibleProperty property {@see $unwrapped} is used as a cache: we don't expose it to the
* outside world, so we should be fine here.
*/
private function unwrap(): UuidInterface
{
return $this->unwrapped = (new UuidFactory())
->fromString($this->uuid);
}
}

View File

@@ -0,0 +1,144 @@
<?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\Math;
use Brick\Math\BigDecimal;
use Brick\Math\BigInteger;
use Brick\Math\Exception\MathException;
use Brick\Math\RoundingMode as BrickMathRounding;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Type\Decimal;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\NumberInterface;
/**
* A calculator using the brick/math library for arbitrary-precision arithmetic
*
* @psalm-immutable
*/
final class BrickMathCalculator implements CalculatorInterface
{
private const ROUNDING_MODE_MAP = [
RoundingMode::UNNECESSARY => BrickMathRounding::UNNECESSARY,
RoundingMode::UP => BrickMathRounding::UP,
RoundingMode::DOWN => BrickMathRounding::DOWN,
RoundingMode::CEILING => BrickMathRounding::CEILING,
RoundingMode::FLOOR => BrickMathRounding::FLOOR,
RoundingMode::HALF_UP => BrickMathRounding::HALF_UP,
RoundingMode::HALF_DOWN => BrickMathRounding::HALF_DOWN,
RoundingMode::HALF_CEILING => BrickMathRounding::HALF_CEILING,
RoundingMode::HALF_FLOOR => BrickMathRounding::HALF_FLOOR,
RoundingMode::HALF_EVEN => BrickMathRounding::HALF_EVEN,
];
public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface
{
$sum = BigInteger::of($augend->toString());
foreach ($addends as $addend) {
$sum = $sum->plus($addend->toString());
}
return new IntegerObject((string) $sum);
}
public function subtract(NumberInterface $minuend, NumberInterface ...$subtrahends): NumberInterface
{
$difference = BigInteger::of($minuend->toString());
foreach ($subtrahends as $subtrahend) {
$difference = $difference->minus($subtrahend->toString());
}
return new IntegerObject((string) $difference);
}
public function multiply(NumberInterface $multiplicand, NumberInterface ...$multipliers): NumberInterface
{
$product = BigInteger::of($multiplicand->toString());
foreach ($multipliers as $multiplier) {
$product = $product->multipliedBy($multiplier->toString());
}
return new IntegerObject((string) $product);
}
public function divide(
int $roundingMode,
int $scale,
NumberInterface $dividend,
NumberInterface ...$divisors
): NumberInterface {
$brickRounding = $this->getBrickRoundingMode($roundingMode);
$quotient = BigDecimal::of($dividend->toString());
foreach ($divisors as $divisor) {
$quotient = $quotient->dividedBy($divisor->toString(), $scale, $brickRounding);
}
if ($scale === 0) {
return new IntegerObject((string) $quotient->toBigInteger());
}
return new Decimal((string) $quotient);
}
public function fromBase(string $value, int $base): IntegerObject
{
try {
return new IntegerObject((string) BigInteger::fromBase($value, $base));
} catch (MathException | \InvalidArgumentException $exception) {
throw new InvalidArgumentException(
$exception->getMessage(),
(int) $exception->getCode(),
$exception
);
}
}
public function toBase(IntegerObject $value, int $base): string
{
try {
return BigInteger::of($value->toString())->toBase($base);
} catch (MathException | \InvalidArgumentException $exception) {
throw new InvalidArgumentException(
$exception->getMessage(),
(int) $exception->getCode(),
$exception
);
}
}
public function toHexadecimal(IntegerObject $value): Hexadecimal
{
return new Hexadecimal($this->toBase($value, 16));
}
public function toInteger(Hexadecimal $value): IntegerObject
{
return $this->fromBase($value->toString(), 16);
}
/**
* Maps ramsey/uuid rounding modes to those used by brick/math
*/
private function getBrickRoundingMode(int $roundingMode): int
{
return self::ROUNDING_MODE_MAP[$roundingMode] ?? 0;
}
}

View File

@@ -0,0 +1,106 @@
<?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\Math;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\NumberInterface;
/**
* A calculator performs arithmetic operations on numbers
*
* @psalm-immutable
*/
interface CalculatorInterface
{
/**
* Returns the sum of all the provided parameters
*
* @param NumberInterface $augend The first addend (the integer being added to)
* @param NumberInterface ...$addends The additional integers to a add to the augend
*
* @return NumberInterface The sum of all the parameters
*/
public function add(NumberInterface $augend, NumberInterface ...$addends): NumberInterface;
/**
* Returns the difference of all the provided parameters
*
* @param NumberInterface $minuend The integer being subtracted from
* @param NumberInterface ...$subtrahends The integers to subtract from the minuend
*
* @return NumberInterface The difference after subtracting all parameters
*/
public function subtract(NumberInterface $minuend, NumberInterface ...$subtrahends): NumberInterface;
/**
* Returns the product of all the provided parameters
*
* @param NumberInterface $multiplicand The integer to be multiplied
* @param NumberInterface ...$multipliers The factors by which to multiply the multiplicand
*
* @return NumberInterface The product of multiplying all the provided parameters
*/
public function multiply(NumberInterface $multiplicand, NumberInterface ...$multipliers): NumberInterface;
/**
* Returns the quotient of the provided parameters divided left-to-right
*
* @param int $roundingMode The RoundingMode constant to use for this operation
* @param int $scale The scale to use for this operation
* @param NumberInterface $dividend The integer to be divided
* @param NumberInterface ...$divisors The integers to divide $dividend by, in
* the order in which the division operations should take place
* (left-to-right)
*
* @return NumberInterface The quotient of dividing the provided parameters left-to-right
*/
public function divide(
int $roundingMode,
int $scale,
NumberInterface $dividend,
NumberInterface ...$divisors
): NumberInterface;
/**
* Converts a value from an arbitrary base to a base-10 integer value
*
* @param string $value The value to convert
* @param int $base The base to convert from (i.e., 2, 16, 32, etc.)
*
* @return IntegerObject The base-10 integer value of the converted value
*/
public function fromBase(string $value, int $base): IntegerObject;
/**
* Converts a base-10 integer value to an arbitrary base
*
* @param IntegerObject $value The integer value to convert
* @param int $base The base to convert to (i.e., 2, 16, 32, etc.)
*
* @return string The value represented in the specified base
*/
public function toBase(IntegerObject $value, int $base): string;
/**
* Converts an Integer instance to a Hexadecimal instance
*/
public function toHexadecimal(IntegerObject $value): Hexadecimal;
/**
* Converts a Hexadecimal instance to an Integer instance
*/
public function toInteger(Hexadecimal $value): IntegerObject;
}

View File

@@ -0,0 +1,146 @@
<?php
/**
* This file was originally part of brick/math
*
* Copyright (c) 2013-present Benjamin Morel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @link https://github.com/brick/math brick/math at GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Math;
/**
* Specifies a rounding behavior for numerical operations capable of discarding
* precision.
*
* Each rounding mode indicates how the least significant returned digit of a
* rounded result is to be calculated. If fewer digits are returned than the
* digits needed to represent the exact numerical result, the discarded digits
* will be referred to as the discarded fraction regardless the digits'
* contribution to the value of the number. In other words, considered as a
* numerical value, the discarded fraction could have an absolute value greater
* than one.
*/
final class RoundingMode
{
/**
* Private constructor. This class is not instantiable.
*
* @codeCoverageIgnore
*/
private function __construct()
{
}
/**
* Asserts that the requested operation has an exact result, hence no
* rounding is necessary.
*/
public const UNNECESSARY = 0;
/**
* Rounds away from zero.
*
* Always increments the digit prior to a nonzero discarded fraction.
* Note that this rounding mode never decreases the magnitude of the
* calculated value.
*/
public const UP = 1;
/**
* Rounds towards zero.
*
* Never increments the digit prior to a discarded fraction (i.e.,
* truncates). Note that this rounding mode never increases the magnitude of
* the calculated value.
*/
public const DOWN = 2;
/**
* Rounds towards positive infinity.
*
* If the result is positive, behaves as for UP; if negative, behaves as for
* DOWN. Note that this rounding mode never decreases the calculated value.
*/
public const CEILING = 3;
/**
* Rounds towards negative infinity.
*
* If the result is positive, behave as for DOWN; if negative, behave as for
* UP. Note that this rounding mode never increases the calculated value.
*/
public const FLOOR = 4;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant,
* in which case round up.
*
* Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves
* as for DOWN. Note that this is the rounding mode commonly taught at
* school.
*/
public const HALF_UP = 5;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant,
* in which case round down.
*
* Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves
* as for DOWN.
*/
public const HALF_DOWN = 6;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant,
* in which case round towards positive infinity.
*
* If the result is positive, behaves as for HALF_UP; if negative, behaves
* as for HALF_DOWN.
*/
public const HALF_CEILING = 7;
/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant,
* in which case round towards negative infinity.
*
* If the result is positive, behaves as for HALF_DOWN; if negative, behaves
* as for HALF_UP.
*/
public const HALF_FLOOR = 8;
/**
* Rounds towards the "nearest neighbor" unless both neighbors are
* equidistant, in which case rounds towards the even neighbor.
*
* Behaves as for HALF_UP if the digit to the left of the discarded fraction
* is odd; behaves as for HALF_DOWN if it's even.
*
* Note that this is the rounding mode that statistically minimizes
* cumulative error when applied repeatedly over a sequence of calculations.
* It is sometimes known as "Banker's rounding", and is chiefly used in the
* USA.
*/
public const HALF_EVEN = 9;
}

View File

@@ -0,0 +1,133 @@
<?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\Nonstandard;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Fields\SerializableFieldsTrait;
use Ramsey\Uuid\Rfc4122\FieldsInterface;
use Ramsey\Uuid\Rfc4122\VariantTrait;
use Ramsey\Uuid\Type\Hexadecimal;
use function bin2hex;
use function dechex;
use function hexdec;
use function sprintf;
use function str_pad;
use function strlen;
use function substr;
use const STR_PAD_LEFT;
/**
* Nonstandard UUID fields do not conform to the RFC 4122 standard
*
* Since some systems may create nonstandard UUIDs, this implements the
* Rfc4122\FieldsInterface, so that functionality of a nonstandard UUID is not
* degraded, in the event these UUIDs are expected to contain RFC 4122 fields.
*
* Internally, this class represents the fields together as a 16-byte binary
* string.
*
* @psalm-immutable
*/
final class Fields implements FieldsInterface
{
use SerializableFieldsTrait;
use VariantTrait;
/**
* @var string
*/
private $bytes;
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
* @throws InvalidArgumentException if the byte string is not exactly 16 bytes
*/
public function __construct(string $bytes)
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
. 'received ' . strlen($bytes) . ' bytes'
);
}
$this->bytes = $bytes;
}
public function getBytes(): string
{
return $this->bytes;
}
public function getClockSeq(): Hexadecimal
{
$clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
}
public function getClockSeqHiAndReserved(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1)));
}
public function getClockSeqLow(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1)));
}
public function getNode(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 10)));
}
public function getTimeHiAndVersion(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 6, 2)));
}
public function getTimeLow(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 0, 4)));
}
public function getTimeMid(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 4, 2)));
}
public function getTimestamp(): Hexadecimal
{
return new Hexadecimal(sprintf(
'%03x%04s%08s',
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
$this->getTimeMid()->toString(),
$this->getTimeLow()->toString()
));
}
public function getVersion(): ?int
{
return null;
}
public function isNil(): bool
{
return false;
}
}

View File

@@ -0,0 +1,37 @@
<?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\Nonstandard;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Uuid as BaseUuid;
/**
* Nonstandard\Uuid is a UUID that doesn't conform to RFC 4122
*
* @psalm-immutable
*/
final class Uuid extends BaseUuid
{
public function __construct(
Fields $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
}

View File

@@ -0,0 +1,88 @@
<?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\Nonstandard;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\UuidInterface;
use Throwable;
/**
* Nonstandard\UuidBuilder builds instances of Nonstandard\Uuid
*
* @psalm-immutable
*/
class UuidBuilder implements UuidBuilderInterface
{
/**
* @var NumberConverterInterface
*/
private $numberConverter;
/**
* @var TimeConverterInterface
*/
private $timeConverter;
/**
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Nonstandard\Uuid
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
NumberConverterInterface $numberConverter,
TimeConverterInterface $timeConverter
) {
$this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter;
}
/**
* Builds and returns a Nonstandard\Uuid
*
* @param CodecInterface $codec The codec to use for building this instance
* @param string $bytes The byte string from which to construct a UUID
*
* @return Uuid The Nonstandard\UuidBuilder returns an instance of
* Nonstandard\Uuid
*
* @psalm-pure
*/
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
try {
return new Uuid(
$this->buildFields($bytes),
$this->numberConverter,
$codec,
$this->timeConverter
);
} catch (Throwable $e) {
throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* Proxy method to allow injecting a mock, for testing
*/
protected function buildFields(string $bytes): Fields
{
return new Fields($bytes);
}
}

View File

@@ -0,0 +1,133 @@
<?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\Nonstandard;
use DateTimeImmutable;
use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Lazy\LazyUuidFromString;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Rfc4122\UuidInterface;
use Ramsey\Uuid\Rfc4122\UuidV1;
use Ramsey\Uuid\Uuid;
use Throwable;
use function hex2bin;
use function str_pad;
use function substr;
use const STR_PAD_LEFT;
/**
* Ordered-time, or version 6, UUIDs include timestamp, clock sequence, and node
* values that are combined into a 128-bit unsigned integer
*
* @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft
* @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs
*
* @psalm-immutable
*/
final class UuidV6 extends Uuid implements UuidInterface
{
/**
* Creates a version 6 (time-based) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_PEABODY) {
throw new InvalidArgumentException(
'Fields used to create a UuidV6 must represent a '
. 'version 6 (ordered-time) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
/**
* Returns a DateTimeInterface object representing the timestamp associated
* with the UUID
*
* @return DateTimeImmutable A PHP DateTimeImmutable instance representing
* the timestamp of a version 6 UUID
*/
public function getDateTime(): DateTimeInterface
{
$time = $this->timeConverter->convertTime($this->fields->getTimestamp());
try {
return new DateTimeImmutable(
'@'
. $time->getSeconds()->toString()
. '.'
. str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
);
} catch (Throwable $e) {
throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* Converts this UUID into an instance of a version 1 UUID
*/
public function toUuidV1(): UuidV1
{
$hex = $this->getHex()->toString();
$hex = substr($hex, 7, 5)
. substr($hex, 13, 3)
. substr($hex, 3, 4)
. '1' . substr($hex, 0, 3)
. substr($hex, 16);
/** @var LazyUuidFromString $uuid */
$uuid = Uuid::fromBytes((string) hex2bin($hex));
return $uuid->toUuidV1();
}
/**
* Converts a version 1 UUID into an instance of a version 6 UUID
*/
public static function fromUuidV1(UuidV1 $uuidV1): UuidV6
{
$hex = $uuidV1->getHex()->toString();
$hex = substr($hex, 13, 3)
. substr($hex, 8, 4)
. substr($hex, 0, 5)
. '6' . substr($hex, 5, 3)
. substr($hex, 16);
/** @var LazyUuidFromString $uuid */
$uuid = Uuid::fromBytes((string) hex2bin($hex));
return $uuid->toUuidV6();
}
}

View File

@@ -0,0 +1,234 @@
<?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\Provider\Dce;
use Ramsey\Uuid\Exception\DceSecurityException;
use Ramsey\Uuid\Provider\DceSecurityProviderInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use function escapeshellarg;
use function preg_split;
use function str_getcsv;
use function strpos;
use function strrpos;
use function strtolower;
use function strtoupper;
use function substr;
use function trim;
use const PREG_SPLIT_NO_EMPTY;
/**
* SystemDceSecurityProvider retrieves the user or group identifiers from the system
*/
class SystemDceSecurityProvider implements DceSecurityProviderInterface
{
/**
* @throws DceSecurityException if unable to get a user identifier
*
* @inheritDoc
*/
public function getUid(): IntegerObject
{
static $uid = null;
if ($uid instanceof IntegerObject) {
return $uid;
}
if ($uid === null) {
$uid = $this->getSystemUid();
}
if ($uid === '') {
throw new DceSecurityException(
'Unable to get a user identifier using the system DCE '
. 'Security provider; please provide a custom identifier or '
. 'use a different provider'
);
}
$uid = new IntegerObject($uid);
return $uid;
}
/**
* @throws DceSecurityException if unable to get a group identifier
*
* @inheritDoc
*/
public function getGid(): IntegerObject
{
static $gid = null;
if ($gid instanceof IntegerObject) {
return $gid;
}
if ($gid === null) {
$gid = $this->getSystemGid();
}
if ($gid === '') {
throw new DceSecurityException(
'Unable to get a group identifier using the system DCE '
. 'Security provider; please provide a custom identifier or '
. 'use a different provider'
);
}
$gid = new IntegerObject($gid);
return $gid;
}
/**
* Returns the UID from the system
*/
private function getSystemUid(): string
{
if (!$this->hasShellExec()) {
return '';
}
switch ($this->getOs()) {
case 'WIN':
return $this->getWindowsUid();
case 'DAR':
case 'FRE':
case 'LIN':
default:
return trim((string) shell_exec('id -u'));
}
}
/**
* Returns the GID from the system
*/
private function getSystemGid(): string
{
if (!$this->hasShellExec()) {
return '';
}
switch ($this->getOs()) {
case 'WIN':
return $this->getWindowsGid();
case 'DAR':
case 'FRE':
case 'LIN':
default:
return trim((string) shell_exec('id -g'));
}
}
/**
* Returns true if shell_exec() is available for use
*/
private function hasShellExec(): bool
{
$disabledFunctions = strtolower((string) ini_get('disable_functions'));
return strpos($disabledFunctions, 'shell_exec') === false;
}
/**
* Returns the PHP_OS string
*/
private function getOs(): string
{
return strtoupper(substr(constant('PHP_OS'), 0, 3));
}
/**
* Returns the user identifier for a user on a Windows system
*
* Windows does not have the same concept as an effective POSIX UID for the
* running script. Instead, each user is uniquely identified by an SID
* (security identifier). The SID includes three 32-bit unsigned integers
* that make up a unique domain identifier, followed by an RID (relative
* identifier) that we will use as the UID. The primary caveat is that this
* UID may not be unique to the system, since it is, instead, unique to the
* domain.
*
* @link https://www.lifewire.com/what-is-an-sid-number-2626005 What Is an SID Number?
* @link https://bit.ly/30vE7NM Well-known SID Structures
* @link https://bit.ly/2FWcYKJ Well-known security identifiers in Windows operating systems
* @link https://www.windows-commandline.com/get-sid-of-user/ Get SID of user
*/
private function getWindowsUid(): string
{
$response = shell_exec('whoami /user /fo csv /nh');
if ($response === null) {
return '';
}
$sid = str_getcsv(trim((string) $response))[1] ?? '';
if (($lastHyphen = strrpos($sid, '-')) === false) {
return '';
}
return trim(substr($sid, $lastHyphen + 1));
}
/**
* Returns a group identifier for a user on a Windows system
*
* Since Windows does not have the same concept as an effective POSIX GID
* for the running script, we will get the local group memberships for the
* user running the script. Then, we will get the SID (security identifier)
* for the first group that appears in that list. Finally, we will return
* the RID (relative identifier) for the group and use that as the GID.
*
* @link https://www.windows-commandline.com/list-of-user-groups-command-line/ List of user groups command line
*/
private function getWindowsGid(): string
{
$response = shell_exec('net user %username% | findstr /b /i "Local Group Memberships"');
if ($response === null) {
return '';
}
/** @var string[] $userGroups */
$userGroups = preg_split('/\s{2,}/', (string) $response, -1, PREG_SPLIT_NO_EMPTY);
$firstGroup = trim($userGroups[1] ?? '', "* \t\n\r\0\x0B");
if ($firstGroup === '') {
return '';
}
$response = shell_exec('wmic group get name,sid | findstr /b /i ' . escapeshellarg($firstGroup));
if ($response === null) {
return '';
}
/** @var string[] $userGroup */
$userGroup = preg_split('/\s{2,}/', (string) $response, -1, PREG_SPLIT_NO_EMPTY);
$sid = $userGroup[1] ?? '';
if (($lastHyphen = strrpos($sid, '-')) === false) {
return '';
}
return trim((string) substr($sid, $lastHyphen + 1));
}
}

View File

@@ -0,0 +1,41 @@
<?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\Provider;
use Ramsey\Uuid\Rfc4122\UuidV2;
use Ramsey\Uuid\Type\Integer as IntegerObject;
/**
* A DCE provider provides access to local domain identifiers for version 2,
* DCE Security, UUIDs
*
* @see UuidV2
*/
interface DceSecurityProviderInterface
{
/**
* Returns a user identifier for the system
*
* @link https://en.wikipedia.org/wiki/User_identifier User identifier
*/
public function getUid(): IntegerObject;
/**
* Returns a group identifier for the system
*
* @link https://en.wikipedia.org/wiki/Group_identifier Group identifier
*/
public function getGid(): IntegerObject;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,53 +8,53 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Node;
use Exception;
use Ramsey\Uuid\Exception\NodeException;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* FallbackNodeProvider attempts to gain the system host ID from an array of
* providers, falling back to the next in line in the event a host ID can not be
* obtained
* FallbackNodeProvider retrieves the system node ID by stepping through a list
* of providers until a node ID can be obtained
*/
class FallbackNodeProvider implements NodeProviderInterface
{
/**
* @var NodeProviderInterface[]
* @var NodeProviderCollection
*/
private $nodeProviders;
/**
* Constructs a `FallbackNodeProvider` using an array of node providers
*
* @param NodeProviderInterface[] $providers Array of node providers
* @param NodeProviderCollection $providers Array of node providers
*/
public function __construct(array $providers)
public function __construct(NodeProviderCollection $providers)
{
$this->nodeProviders = $providers;
}
/**
* Returns the system node ID by iterating over an array of node providers
* and returning the first non-empty value found
*
* @return string System node ID as a hexadecimal string
* @throws Exception
*/
public function getNode()
public function getNode(): Hexadecimal
{
$lastProviderException = null;
foreach ($this->nodeProviders as $provider) {
if ($node = $provider->getNode()) {
return $node;
try {
return $provider->getNode();
} catch (NodeException $exception) {
$lastProviderException = $exception;
continue;
}
}
return null;
throw new NodeException(
'Unable to find a suitable node provider',
0,
$lastProviderException
);
}
}

View File

@@ -0,0 +1,61 @@
<?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\Provider\Node;
use Ramsey\Collection\AbstractCollection;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* A collection of NodeProviderInterface objects
*
* @extends AbstractCollection<NodeProviderInterface>
*/
class NodeProviderCollection extends AbstractCollection
{
public function getType(): string
{
return NodeProviderInterface::class;
}
/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress RedundantConditionGivenDocblockType
*/
public function unserialize($serialized): void
{
/** @var array<array-key, NodeProviderInterface> $data */
$data = unserialize($serialized, [
'allowed_classes' => [
Hexadecimal::class,
RandomNodeProvider::class,
StaticNodeProvider::class,
SystemNodeProvider::class,
],
]);
$this->data = array_filter(
$data,
function ($unserialized): bool {
return $unserialized instanceof NodeProviderInterface;
}
);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,33 +8,44 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Node;
use Exception;
use Ramsey\Uuid\Exception\RandomSourceException;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Throwable;
use function bin2hex;
use function dechex;
use function hex2bin;
use function hexdec;
use function str_pad;
use function substr;
use const STR_PAD_LEFT;
/**
* RandomNodeProvider provides functionality to generate a random node ID, in
* the event that the node ID could not be obtained from the host system
* RandomNodeProvider generates a random node ID
*
* @link http://tools.ietf.org/html/rfc4122#section-4.5
* @link http://tools.ietf.org/html/rfc4122#section-4.5 RFC 4122, § 4.5: Node IDs that Do Not Identify the Host
*/
class RandomNodeProvider implements NodeProviderInterface
{
/**
* Returns the system node ID
*
* @return string System node ID as a hexadecimal string
* @throws Exception if it was not possible to gather sufficient entropy
*/
public function getNode()
public function getNode(): Hexadecimal
{
$nodeBytes = random_bytes(6);
try {
$nodeBytes = random_bytes(6);
} catch (Throwable $exception) {
throw new RandomSourceException(
$exception->getMessage(),
(int) $exception->getCode(),
$exception
);
}
// Split the node bytes for math on 32-bit systems.
$nodeMsb = substr($nodeBytes, 0, 3);
@@ -52,6 +64,6 @@ class RandomNodeProvider implements NodeProviderInterface
// Recombine the node bytes.
$node = $nodeMsb . $nodeLsb;
return str_pad(bin2hex($node), 12, '0', STR_PAD_LEFT);
return new Hexadecimal(str_pad(bin2hex($node), 12, '0', STR_PAD_LEFT));
}
}

View File

@@ -0,0 +1,76 @@
<?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\Provider\Node;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use function dechex;
use function hexdec;
use function str_pad;
use function substr;
use const STR_PAD_LEFT;
/**
* StaticNodeProvider provides a static node value with the multicast bit set
*
* @link http://tools.ietf.org/html/rfc4122#section-4.5 RFC 4122, § 4.5: Node IDs that Do Not Identify the Host
*/
class StaticNodeProvider implements NodeProviderInterface
{
/**
* @var Hexadecimal
*/
private $node;
/**
* @param Hexadecimal $node The static node value to use
*/
public function __construct(Hexadecimal $node)
{
if (strlen($node->toString()) > 12) {
throw new InvalidArgumentException(
'Static node value cannot be greater than 12 hexadecimal characters'
);
}
$this->node = $this->setMulticastBit($node);
}
public function getNode(): Hexadecimal
{
return $this->node;
}
/**
* Set the multicast bit for the static node value
*/
private function setMulticastBit(Hexadecimal $node): Hexadecimal
{
$nodeHex = str_pad($node->toString(), 12, '0', STR_PAD_LEFT);
$firstOctet = substr($nodeHex, 0, 2);
$firstOctet = str_pad(
dechex(hexdec($firstOctet) | 0x01),
2,
'0',
STR_PAD_LEFT
);
return new Hexadecimal($firstOctet . substr($nodeHex, 2));
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,50 +8,86 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Node;
use Ramsey\Uuid\Exception\NodeException;
use Ramsey\Uuid\Provider\NodeProviderInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use function array_filter;
use function array_map;
use function array_walk;
use function count;
use function ob_get_clean;
use function ob_start;
use function preg_match;
use function preg_match_all;
use function reset;
use function str_replace;
use function strpos;
use function strtolower;
use function strtoupper;
use function substr;
use const GLOB_NOSORT;
use const PREG_PATTERN_ORDER;
/**
* SystemNodeProvider provides functionality to get the system node ID (MAC
* address) using external system calls
* SystemNodeProvider retrieves the system node ID, if possible
*
* The system node ID, or host ID, is often the same as the MAC address for a
* network interface on the host.
*/
class SystemNodeProvider implements NodeProviderInterface
{
/**
* Returns the system node ID
*
* @return string|false System node ID as a hexadecimal string, or false if it is not found
* Pattern to match nodes in ifconfig and ipconfig output.
*/
public function getNode()
private const IFCONFIG_PATTERN = '/[^:]([0-9a-f]{2}([:-])[0-9a-f]{2}(\2[0-9a-f]{2}){4})[^:]/i';
/**
* Pattern to match nodes in sysfs stream output.
*/
private const SYSFS_PATTERN = '/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i';
public function getNode(): Hexadecimal
{
$node = $this->getNodeFromSystem();
if ($node === '') {
throw new NodeException(
'Unable to fetch a node for this system'
);
}
return new Hexadecimal($node);
}
/**
* Returns the system node, if it can find it
*/
protected function getNodeFromSystem(): string
{
static $node = null;
if ($node !== null) {
return $node;
return (string) $node;
}
$pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/';
$matches = [];
// first try a linux specific way
// First, try a Linux-specific approach.
$node = $this->getSysfs();
// Search the ifconfig output for all MAC addresses and return
// the first one found
if ($node === false) {
if (preg_match_all($pattern, $this->getIfconfig(), $matches, PREG_PATTERN_ORDER)) {
$node = $matches[1][0];
}
}
if ($node !== false) {
$node = str_replace([':', '-'], '', $node);
if ($node === '') {
// Search ifconfig output for MAC addresses & return the first one.
$node = $this->getIfconfig();
}
$node = str_replace([':', '-'], '', $node);
return $node;
}
@@ -58,11 +95,12 @@ class SystemNodeProvider implements NodeProviderInterface
* Returns the network interface configuration for the system
*
* @codeCoverageIgnore
* @return string
*/
protected function getIfconfig()
protected function getIfconfig(): string
{
if (strpos(strtolower(ini_get('disable_functions')), 'passthru') !== false) {
$disabledFunctions = strtolower((string) ini_get('disable_functions'));
if (strpos($disabledFunctions, 'passthru') !== false) {
return '';
}
@@ -70,40 +108,50 @@ class SystemNodeProvider implements NodeProviderInterface
switch (strtoupper(substr(constant('PHP_OS'), 0, 3))) {
case 'WIN':
passthru('ipconfig /all 2>&1');
break;
case 'DAR':
passthru('ifconfig 2>&1');
break;
case 'FRE':
passthru('netstat -i -f link 2>&1');
break;
case 'LIN':
default:
passthru('netstat -ie 2>&1');
break;
}
return ob_get_clean();
$ifconfig = (string) ob_get_clean();
$node = '';
if (preg_match_all(self::IFCONFIG_PATTERN, $ifconfig, $matches, PREG_PATTERN_ORDER)) {
$node = $matches[1][0] ?? '';
}
return $node;
}
/**
* Returns mac address from the first system interface via the sysfs interface
*
* @return string|bool
* Returns MAC address from the first system interface via the sysfs interface
*/
protected function getSysfs()
protected function getSysfs(): string
{
$mac = false;
$mac = '';
if (strtoupper(constant('PHP_OS')) === 'LINUX') {
$addressPaths = glob('/sys/class/net/*/address', GLOB_NOSORT);
if (empty($addressPaths)) {
return false;
if ($addressPaths === false || count($addressPaths) === 0) {
return '';
}
$macs = [];
array_walk($addressPaths, function ($addressPath) use (&$macs) {
array_walk($addressPaths, function (string $addressPath) use (&$macs): void {
if (is_readable($addressPath)) {
$macs[] = file_get_contents($addressPath);
}
@@ -111,18 +159,15 @@ class SystemNodeProvider implements NodeProviderInterface
$macs = array_map('trim', $macs);
// remove invalid entries
$macs = array_filter($macs, function ($mac) {
return
// localhost adapter
$mac !== '00:00:00:00:00:00' &&
// must match mac adress
preg_match('/^([0-9a-f]{2}:){5}[0-9a-f]{2}$/i', $mac);
// Remove invalid entries.
$macs = array_filter($macs, function (string $address) {
return $address !== '00:00:00:00:00:00'
&& preg_match(self::SYSFS_PATTERN, $address);
});
$mac = reset($macs);
}
return $mac;
return (string) $mac;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,26 +8,23 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider;
use Exception;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* NodeProviderInterface provides functionality to get the node ID (or host ID
* in the form of the system's MAC address) from a specific type of node provider
* A node provider retrieves or generates a node ID
*/
interface NodeProviderInterface
{
/**
* Returns the system node ID
* Returns a node ID
*
* @return string System node ID as a hexadecimal string
* @throws Exception if it was not possible to gather sufficient entropy
* @return Hexadecimal The node ID as a hexadecimal string
*/
public function getNode();
public function getNode(): Hexadecimal;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,70 +8,55 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Time;
use InvalidArgumentException;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Type\Time;
/**
* FixedTimeProvider uses an previously-generated timestamp to provide the time
* FixedTimeProvider uses an known time to provide the time
*
* This provider allows the use of a previously-generated timestamp, such as one
* stored in a database, when creating version 1 UUIDs.
* This provider allows the use of a previously-generated, or known, time
* when generating time-based UUIDs.
*/
class FixedTimeProvider implements TimeProviderInterface
{
/**
* @var int[] Array containing `sec` and `usec` components of a timestamp
* @var Time
*/
private $fixedTime;
/**
* Constructs a `FixedTimeProvider` using the provided `$timestamp`
*
* @param int[] Array containing `sec` and `usec` components of a timestamp
* @throws InvalidArgumentException if the `$timestamp` does not contain `sec` or `usec` components
*/
public function __construct(array $timestamp)
public function __construct(Time $time)
{
if (!array_key_exists('sec', $timestamp) || !array_key_exists('usec', $timestamp)) {
throw new InvalidArgumentException('Array must contain sec and usec keys.');
}
$this->fixedTime = $timestamp;
$this->fixedTime = $time;
}
/**
* Sets the `usec` component of the timestamp
* Sets the `usec` component of the time
*
* @param int $value The `usec` value to set
* @param int|string|IntegerObject $value The `usec` value to set
*/
public function setUsec($value)
public function setUsec($value): void
{
$this->fixedTime['usec'] = $value;
$this->fixedTime = new Time($this->fixedTime->getSeconds(), $value);
}
/**
* Sets the `sec` component of the timestamp
* Sets the `sec` component of the time
*
* @param int $value The `sec` value to set
* @param int|string|IntegerObject $value The `sec` value to set
*/
public function setSec($value)
public function setSec($value): void
{
$this->fixedTime['sec'] = $value;
$this->fixedTime = new Time($value, $this->fixedTime->getMicroseconds());
}
/**
* Returns a timestamp array
*
* @return int[] Array containing `sec` and `usec` components of a timestamp
*/
public function currentTime()
public function getTime(): Time
{
return $this->fixedTime;
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,27 +8,26 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider\Time;
use Ramsey\Uuid\Provider\TimeProviderInterface;
use Ramsey\Uuid\Type\Time;
use function gettimeofday;
/**
* SystemTimeProvider uses built-in PHP functions to provide the time
* SystemTimeProvider retrieves the current time using built-in PHP functions
*/
class SystemTimeProvider implements TimeProviderInterface
{
/**
* Returns a timestamp array
*
* @return int[] Array containing `sec` and `usec` components of a timestamp
*/
public function currentTime()
public function getTime(): Time
{
return gettimeofday();
$time = gettimeofday();
return new Time($time['sec'], $time['usec']);
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* This file is part of the ramsey/uuid library
*
@@ -7,23 +8,21 @@
*
* @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
* @license http://opensource.org/licenses/MIT MIT
* @link https://benramsey.com/projects/ramsey-uuid/ Documentation
* @link https://packagist.org/packages/ramsey/uuid Packagist
* @link https://github.com/ramsey/uuid GitHub
*/
declare(strict_types=1);
namespace Ramsey\Uuid\Provider;
use Ramsey\Uuid\Type\Time;
/**
* TimeProviderInterface provides functionality to get the time from a specific
* type of time provider
* A time provider retrieves the current time
*/
interface TimeProviderInterface
{
/**
* Returns a timestamp array
*
* @return int[] Array guaranteed to contain `sec` and `usec` components of a timestamp
* Returns a time object
*/
public function currentTime();
public function getTime(): Time;
}

View File

@@ -0,0 +1,194 @@
<?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\Rfc4122;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Fields\SerializableFieldsTrait;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Uuid;
use function bin2hex;
use function dechex;
use function hexdec;
use function sprintf;
use function str_pad;
use function strlen;
use function substr;
use function unpack;
use const STR_PAD_LEFT;
/**
* RFC 4122 variant UUIDs are comprised of a set of named fields
*
* Internally, this class represents the fields together as a 16-byte binary
* string.
*
* @psalm-immutable
*/
final class Fields implements FieldsInterface
{
use NilTrait;
use SerializableFieldsTrait;
use VariantTrait;
use VersionTrait;
/**
* @var string
*/
private $bytes;
/**
* @param string $bytes A 16-byte binary string representation of a UUID
*
* @throws InvalidArgumentException if the byte string is not exactly 16 bytes
* @throws InvalidArgumentException if the byte string does not represent an RFC 4122 UUID
* @throws InvalidArgumentException if the byte string does not contain a valid version
*/
public function __construct(string $bytes)
{
if (strlen($bytes) !== 16) {
throw new InvalidArgumentException(
'The byte string must be 16 bytes long; '
. 'received ' . strlen($bytes) . ' bytes'
);
}
$this->bytes = $bytes;
if (!$this->isCorrectVariant()) {
throw new InvalidArgumentException(
'The byte string received does not conform to the RFC 4122 variant'
);
}
if (!$this->isCorrectVersion()) {
throw new InvalidArgumentException(
'The byte string received does not contain a valid RFC 4122 version'
);
}
}
public function getBytes(): string
{
return $this->bytes;
}
public function getClockSeq(): Hexadecimal
{
$clockSeq = hexdec(bin2hex(substr($this->bytes, 8, 2))) & 0x3fff;
return new Hexadecimal(str_pad(dechex($clockSeq), 4, '0', STR_PAD_LEFT));
}
public function getClockSeqHiAndReserved(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 8, 1)));
}
public function getClockSeqLow(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 9, 1)));
}
public function getNode(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 10)));
}
public function getTimeHiAndVersion(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 6, 2)));
}
public function getTimeLow(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 0, 4)));
}
public function getTimeMid(): Hexadecimal
{
return new Hexadecimal(bin2hex(substr($this->bytes, 4, 2)));
}
/**
* Returns the full 60-bit timestamp, without the version
*
* For version 2 UUIDs, the time_low field is the local identifier and
* should not be returned as part of the time. For this reason, we set the
* bottom 32 bits of the timestamp to 0's. As a result, there is some loss
* of fidelity of the timestamp, for version 2 UUIDs. The timestamp can be
* off by a range of 0 to 429.4967295 seconds (or 7 minutes, 9 seconds, and
* 496730 microseconds).
*
* For version 6 UUIDs, the timestamp order is reversed from the typical RFC
* 4122 order (the time bits are in the correct bit order, so that it is
* monotonically increasing). In returning the timestamp value, we put the
* bits in the order: time_low + time_mid + time_hi.
*/
public function getTimestamp(): Hexadecimal
{
switch ($this->getVersion()) {
case Uuid::UUID_TYPE_DCE_SECURITY:
$timestamp = sprintf(
'%03x%04s%08s',
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
$this->getTimeMid()->toString(),
''
);
break;
case Uuid::UUID_TYPE_PEABODY:
$timestamp = sprintf(
'%08s%04s%03x',
$this->getTimeLow()->toString(),
$this->getTimeMid()->toString(),
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff
);
break;
default:
$timestamp = sprintf(
'%03x%04s%08s',
hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff,
$this->getTimeMid()->toString(),
$this->getTimeLow()->toString()
);
}
return new Hexadecimal($timestamp);
}
public function getVersion(): ?int
{
if ($this->isNil()) {
return null;
}
/** @var array $parts */
$parts = unpack('n*', $this->bytes);
return (int) $parts[4] >> 12;
}
private function isCorrectVariant(): bool
{
if ($this->isNil()) {
return true;
}
return $this->getVariant() === Uuid::RFC_4122;
}
}

View File

@@ -0,0 +1,126 @@
<?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\Rfc4122;
use Ramsey\Uuid\Fields\FieldsInterface as BaseFieldsInterface;
use Ramsey\Uuid\Type\Hexadecimal;
/**
* RFC 4122 defines fields for a specific variant of UUID
*
* The fields of an RFC 4122 variant UUID are:
*
* * **time_low**: The low field of the timestamp, an unsigned 32-bit integer
* * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer
* * **time_hi_and_version**: The high field of the timestamp multiplexed with
* the version number, an unsigned 16-bit integer
* * **clock_seq_hi_and_reserved**: The high field of the clock sequence
* multiplexed with the variant, an unsigned 8-bit integer
* * **clock_seq_low**: The low field of the clock sequence, an unsigned
* 8-bit integer
* * **node**: The spatially unique node identifier, an unsigned 48-bit
* integer
*
* @link http://tools.ietf.org/html/rfc4122#section-4.1 RFC 4122, § 4.1: Format
*
* @psalm-immutable
*/
interface FieldsInterface extends BaseFieldsInterface
{
/**
* Returns the full 16-bit clock sequence, with the variant bits (two most
* significant bits) masked out
*/
public function getClockSeq(): Hexadecimal;
/**
* Returns the high field of the clock sequence multiplexed with the variant
*/
public function getClockSeqHiAndReserved(): Hexadecimal;
/**
* Returns the low field of the clock sequence
*/
public function getClockSeqLow(): Hexadecimal;
/**
* Returns the node field
*/
public function getNode(): Hexadecimal;
/**
* Returns the high field of the timestamp multiplexed with the version
*/
public function getTimeHiAndVersion(): Hexadecimal;
/**
* Returns the low field of the timestamp
*/
public function getTimeLow(): Hexadecimal;
/**
* Returns the middle field of the timestamp
*/
public function getTimeMid(): Hexadecimal;
/**
* Returns the full 60-bit timestamp, without the version
*/
public function getTimestamp(): Hexadecimal;
/**
* Returns the variant
*
* The variant number describes the layout of the UUID. The variant
* number has the following meaning:
*
* - 0 - Reserved for NCS backward compatibility
* - 2 - The RFC 4122 variant
* - 6 - Reserved, Microsoft Corporation backward compatibility
* - 7 - Reserved for future definition
*
* For RFC 4122 variant UUIDs, this value should always be the integer `2`.
*
* @link http://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*/
public function getVariant(): int;
/**
* Returns the version
*
* The version number describes how the UUID was generated and has the
* following meaning:
*
* 1. Time-based UUID
* 2. DCE security UUID
* 3. Name-based UUID hashed with MD5
* 4. Randomly generated UUID
* 5. Name-based UUID hashed with SHA-1
*
* This returns `null` if the UUID is not an RFC 4122 variant, since version
* is only meaningful for this variant.
*
* @link http://tools.ietf.org/html/rfc4122#section-4.1.3 RFC 4122, § 4.1.3: Version
*/
public function getVersion(): ?int;
/**
* Returns true if these fields represent a nil UUID
*
* The nil UUID is special form of UUID that is specified to have all 128
* bits set to zero.
*/
public function isNil(): bool;
}

View File

@@ -0,0 +1,41 @@
<?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\Rfc4122;
/**
* Provides common functionality for nil UUIDs
*
* The nil UUID is special form of UUID that is specified to have all 128 bits
* set to zero.
*
* @link https://tools.ietf.org/html/rfc4122#section-4.1.7 RFC 4122, § 4.1.7: Nil UUID
*
* @psalm-immutable
*/
trait NilTrait
{
/**
* Returns the bytes that comprise the fields
*/
abstract public function getBytes(): string;
/**
* Returns true if the byte string represents a nil UUID
*/
public function isNil(): bool
{
return $this->getBytes() === "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
}
}

View File

@@ -0,0 +1,27 @@
<?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\Rfc4122;
use Ramsey\Uuid\Uuid;
/**
* The nil UUID is special form of UUID that is specified to have all 128 bits
* set to zero
*
* @psalm-immutable
*/
final class NilUuid extends Uuid implements UuidInterface
{
}

View File

@@ -0,0 +1,111 @@
<?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\Rfc4122;
use Ramsey\Uuid\Builder\UuidBuilderInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\UnableToBuildUuidException;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Nonstandard\UuidV6;
use Ramsey\Uuid\Rfc4122\UuidInterface as Rfc4122UuidInterface;
use Ramsey\Uuid\UuidInterface;
use Throwable;
/**
* UuidBuilder builds instances of RFC 4122 UUIDs
*
* @psalm-immutable
*/
class UuidBuilder implements UuidBuilderInterface
{
/**
* @var NumberConverterInterface
*/
private $numberConverter;
/**
* @var TimeConverterInterface
*/
private $timeConverter;
/**
* Constructs the DefaultUuidBuilder
*
* @param NumberConverterInterface $numberConverter The number converter to
* use when constructing the Uuid
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to Unix timestamps
*/
public function __construct(
NumberConverterInterface $numberConverter,
TimeConverterInterface $timeConverter
) {
$this->numberConverter = $numberConverter;
$this->timeConverter = $timeConverter;
}
/**
* Builds and returns a Uuid
*
* @param CodecInterface $codec The codec to use for building this Uuid instance
* @param string $bytes The byte string from which to construct a UUID
*
* @return Rfc4122UuidInterface UuidBuilder returns instances of Rfc4122UuidInterface
*
* @psalm-pure
*/
public function build(CodecInterface $codec, string $bytes): UuidInterface
{
try {
$fields = $this->buildFields($bytes);
if ($fields->isNil()) {
return new NilUuid($fields, $this->numberConverter, $codec, $this->timeConverter);
}
switch ($fields->getVersion()) {
case 1:
return new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter);
case 2:
return new UuidV2($fields, $this->numberConverter, $codec, $this->timeConverter);
case 3:
return new UuidV3($fields, $this->numberConverter, $codec, $this->timeConverter);
case 4:
return new UuidV4($fields, $this->numberConverter, $codec, $this->timeConverter);
case 5:
return new UuidV5($fields, $this->numberConverter, $codec, $this->timeConverter);
case 6:
return new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter);
}
throw new UnsupportedOperationException(
'The UUID version in the given fields is not supported '
. 'by this UUID builder'
);
} catch (Throwable $e) {
throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* Proxy method to allow injecting a mock, for testing
*/
protected function buildFields(string $bytes): FieldsInterface
{
return new Fields($bytes);
}
}

View File

@@ -0,0 +1,36 @@
<?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\Rfc4122;
use Ramsey\Uuid\UuidInterface as BaseUuidInterface;
/**
* Also known as a Leach-Salz variant UUID, an RFC 4122 variant UUID is a
* universally unique identifier defined by RFC 4122
*
* @link https://tools.ietf.org/html/rfc4122 RFC 4122
*
* @psalm-immutable
*/
interface UuidInterface extends BaseUuidInterface
{
/**
* Returns the string standard representation of the UUID as a URN
*
* @link http://en.wikipedia.org/wiki/Uniform_Resource_Name Uniform Resource Name
* @link https://tools.ietf.org/html/rfc4122#section-3 RFC 4122, § 3: Namespace Registration Template
*/
public function getUrn(): string;
}

View File

@@ -0,0 +1,92 @@
<?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\Rfc4122;
use DateTimeImmutable;
use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
use Throwable;
use function str_pad;
use const STR_PAD_LEFT;
/**
* Time-based, or version 1, UUIDs include timestamp, clock sequence, and node
* values that are combined into a 128-bit unsigned integer
*
* @psalm-immutable
*/
final class UuidV1 extends Uuid implements UuidInterface
{
/**
* Creates a version 1 (time-based) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_TIME) {
throw new InvalidArgumentException(
'Fields used to create a UuidV1 must represent a '
. 'version 1 (time-based) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
/**
* Returns a DateTimeInterface object representing the timestamp associated
* with the UUID
*
* The timestamp value is only meaningful in a time-based UUID, which
* has version type 1.
*
* @return DateTimeImmutable A PHP DateTimeImmutable instance representing
* the timestamp of a version 1 UUID
*/
public function getDateTime(): DateTimeInterface
{
$time = $this->timeConverter->convertTime($this->fields->getTimestamp());
try {
return new DateTimeImmutable(
'@'
. $time->getSeconds()->toString()
. '.'
. str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
);
} catch (Throwable $e) {
throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
}
}
}

View File

@@ -0,0 +1,143 @@
<?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\Rfc4122;
use DateTimeImmutable;
use DateTimeInterface;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\DateTimeException;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Ramsey\Uuid\Uuid;
use Throwable;
use function hexdec;
use function str_pad;
use const STR_PAD_LEFT;
/**
* DCE Security version, or version 2, UUIDs include local domain identifier,
* local ID for the specified domain, and node values that are combined into a
* 128-bit unsigned integer
*
* @link https://publications.opengroup.org/c311 DCE 1.1: Authentication and Security Services
* @link https://publications.opengroup.org/c706 DCE 1.1: Remote Procedure Call
* @link https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01 DCE 1.1: Auth & Sec, §5.2.1.1
* @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1: Auth & Sec, §11.5.1.1
* @link https://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm DCE 1.1: RPC, Appendix A
* @link https://github.com/google/uuid Go package for UUIDs (includes DCE implementation)
*
* @psalm-immutable
*/
final class UuidV2 extends Uuid implements UuidInterface
{
/**
* Creates a version 2 (DCE Security) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_DCE_SECURITY) {
throw new InvalidArgumentException(
'Fields used to create a UuidV2 must represent a '
. 'version 2 (DCE Security) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
/**
* Returns a DateTimeInterface object representing the timestamp associated
* with the UUID
*
* It is important to note that a version 2 UUID suffers from some loss of
* fidelity of the timestamp, due to replacing the time_low field with the
* local identifier. When constructing the timestamp value for date
* purposes, we replace the local identifier bits with zeros. As a result,
* the timestamp can be off by a range of 0 to 429.4967295 seconds (or 7
* minutes, 9 seconds, and 496730 microseconds).
*
* Astute observers might note this value directly corresponds to 2^32 - 1,
* or 0xffffffff. The local identifier is 32-bits, and we have set each of
* these bits to 0, so the maximum range of timestamp drift is 0x00000000
* to 0xffffffff (counted in 100-nanosecond intervals).
*
* @return DateTimeImmutable A PHP DateTimeImmutable instance representing
* the timestamp of a version 2 UUID
*/
public function getDateTime(): DateTimeInterface
{
$time = $this->timeConverter->convertTime($this->fields->getTimestamp());
try {
return new DateTimeImmutable(
'@'
. $time->getSeconds()->toString()
. '.'
. str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
);
} catch (Throwable $e) {
throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
}
}
/**
* Returns the local domain used to create this version 2 UUID
*/
public function getLocalDomain(): int
{
/** @var Rfc4122FieldsInterface $fields */
$fields = $this->getFields();
return (int) hexdec($fields->getClockSeqLow()->toString());
}
/**
* Returns the string name of the local domain
*/
public function getLocalDomainName(): string
{
return Uuid::DCE_DOMAIN_NAMES[$this->getLocalDomain()];
}
/**
* Returns the local identifier for the domain used to create this version 2 UUID
*/
public function getLocalIdentifier(): IntegerObject
{
/** @var Rfc4122FieldsInterface $fields */
$fields = $this->getFields();
return new IntegerObject(
$this->numberConverter->fromHex($fields->getTimeLow()->toString())
);
}
}

View File

@@ -0,0 +1,58 @@
<?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\Rfc4122;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
/**
* Version 3 UUIDs are named-based, using combination of a namespace and name
* that are hashed into a 128-bit unsigned integer using MD5
*
* @psalm-immutable
*/
final class UuidV3 extends Uuid implements UuidInterface
{
/**
* Creates a version 3 (name-based, MD5-hashed) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_HASH_MD5) {
throw new InvalidArgumentException(
'Fields used to create a UuidV3 must represent a '
. 'version 3 (name-based, MD5-hashed) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
}

View File

@@ -0,0 +1,58 @@
<?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\Rfc4122;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
/**
* Random, or version 4, UUIDs are randomly or pseudo-randomly generated 128-bit
* integers
*
* @psalm-immutable
*/
final class UuidV4 extends Uuid implements UuidInterface
{
/**
* Creates a version 4 (random) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_RANDOM) {
throw new InvalidArgumentException(
'Fields used to create a UuidV4 must represent a '
. 'version 4 (random) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
}

View File

@@ -0,0 +1,58 @@
<?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\Rfc4122;
use Ramsey\Uuid\Codec\CodecInterface;
use Ramsey\Uuid\Converter\NumberConverterInterface;
use Ramsey\Uuid\Converter\TimeConverterInterface;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface;
use Ramsey\Uuid\Uuid;
/**
* Version 5 UUIDs are named-based, using combination of a namespace and name
* that are hashed into a 128-bit unsigned integer using SHA1
*
* @psalm-immutable
*/
final class UuidV5 extends Uuid implements UuidInterface
{
/**
* Creates a version 5 (name-based, SHA1-hashed) UUID
*
* @param Rfc4122FieldsInterface $fields The fields from which to construct a UUID
* @param NumberConverterInterface $numberConverter The number converter to use
* for converting hex values to/from integers
* @param CodecInterface $codec The codec to use when encoding or decoding
* UUID strings
* @param TimeConverterInterface $timeConverter The time converter to use
* for converting timestamps extracted from a UUID to unix timestamps
*/
public function __construct(
Rfc4122FieldsInterface $fields,
NumberConverterInterface $numberConverter,
CodecInterface $codec,
TimeConverterInterface $timeConverter
) {
if ($fields->getVersion() !== Uuid::UUID_TYPE_HASH_SHA1) {
throw new InvalidArgumentException(
'Fields used to create a UuidV5 must represent a '
. 'version 5 (named-based, SHA1-hashed) UUID'
);
}
parent::__construct($fields, $numberConverter, $codec, $timeConverter);
}
}

View File

@@ -0,0 +1,49 @@
<?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\Rfc4122;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\Validator\ValidatorInterface;
use function preg_match;
use function str_replace;
/**
* Rfc4122\Validator validates strings as UUIDs of the RFC 4122 variant
*
* @psalm-immutable
*/
final class Validator implements ValidatorInterface
{
private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-'
. '[1-5]{1}[0-9A-Fa-f]{3}-[ABab89]{1}[0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z';
/**
* @psalm-return non-empty-string
* @psalm-suppress MoreSpecificReturnType we know that the retrieved `string` is never empty
* @psalm-suppress LessSpecificReturnStatement we know that the retrieved `string` is never empty
*/
public function getPattern(): string
{
return self::VALID_PATTERN;
}
public function validate(string $uuid): bool
{
$uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid);
return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid);
}
}

View File

@@ -0,0 +1,90 @@
<?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\Rfc4122;
use Ramsey\Uuid\Exception\InvalidBytesException;
use Ramsey\Uuid\Uuid;
use function decbin;
use function str_pad;
use function strlen;
use function strpos;
use function substr;
use function unpack;
use const STR_PAD_LEFT;
/**
* Provides common functionality for handling the variant, as defined by RFC 4122
*
* @psalm-immutable
*/
trait VariantTrait
{
/**
* Returns the bytes that comprise the fields
*/
abstract public function getBytes(): string;
/**
* Returns the variant identifier, according to RFC 4122, for the given bytes
*
* The following values may be returned:
*
* - `0` -- Reserved, NCS backward compatibility.
* - `2` -- The variant specified in RFC 4122.
* - `6` -- Reserved, Microsoft Corporation backward compatibility.
* - `7` -- Reserved for future definition.
*
* @link https://tools.ietf.org/html/rfc4122#section-4.1.1 RFC 4122, § 4.1.1: Variant
*
* @return int The variant identifier, according to RFC 4122
*/
public function getVariant(): int
{
if (strlen($this->getBytes()) !== 16) {
throw new InvalidBytesException('Invalid number of bytes');
}
/** @var array $parts */
$parts = unpack('n*', $this->getBytes());
// $parts[5] is a 16-bit, unsigned integer containing the variant bits
// of the UUID. We convert this integer into a string containing a
// binary representation, padded to 16 characters. We analyze the first
// three characters (three most-significant bits) to determine the
// variant.
$binary = str_pad(
decbin((int) $parts[5]),
16,
'0',
STR_PAD_LEFT
);
$msb = substr($binary, 0, 3);
if ($msb === '111') {
$variant = Uuid::RESERVED_FUTURE;
} elseif ($msb === '110') {
$variant = Uuid::RESERVED_MICROSOFT;
} elseif (strpos($msb, '10') === 0) {
$variant = Uuid::RFC_4122;
} else {
$variant = Uuid::RESERVED_NCS;
}
return $variant;
}
}

View File

@@ -0,0 +1,57 @@
<?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\Rfc4122;
/**
* Provides common functionality for handling the version, as defined by RFC 4122
*
* @psalm-immutable
*/
trait VersionTrait
{
/**
* Returns the version
*/
abstract public function getVersion(): ?int;
/**
* Returns true if these fields represent a nil UUID
*/
abstract public function isNil(): bool;
/**
* Returns true if the version matches one of those defined by RFC 4122
*
* @return bool True if the UUID version is valid, false otherwise
*/
private function isCorrectVersion(): bool
{
if ($this->isNil()) {
return true;
}
switch ($this->getVersion()) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
return true;
}
return false;
}
}

137
vendor/ramsey/uuid/src/Type/Decimal.php vendored Normal file
View File

@@ -0,0 +1,137 @@
<?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\Type;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use ValueError;
use function is_numeric;
use function sprintf;
/**
* A value object representing a decimal
*
* This class exists for type-safety purposes, to ensure that decimals
* returned from ramsey/uuid methods as strings are truly decimals and not some
* other kind of string.
*
* To support values as true decimals and not as floats or doubles, we store the
* decimals as strings.
*
* @psalm-immutable
*/
final class Decimal implements NumberInterface
{
/**
* @var string
*/
private $value;
/**
* @var bool
*/
private $isNegative = false;
/**
* @param mixed $value The decimal value to store
*/
public function __construct($value)
{
$value = (string) $value;
if (!is_numeric($value)) {
throw new InvalidArgumentException(
'Value must be a signed decimal or a string containing only '
. 'digits 0-9 and, optionally, a decimal point or sign (+ or -)'
);
}
// Remove the leading +-symbol.
if (strpos($value, '+') === 0) {
$value = substr($value, 1);
}
// For cases like `-0` or `-0.0000`, convert the value to `0`.
if (abs((float) $value) === 0.0) {
$value = '0';
}
if (strpos($value, '-') === 0) {
$this->isNegative = true;
}
$this->value = $value;
}
public function isNegative(): bool
{
return $this->isNegative;
}
public function toString(): string
{
return $this->value;
}
public function __toString(): string
{
return $this->toString();
}
public function jsonSerialize(): string
{
return $this->toString();
}
public function serialize(): string
{
return $this->toString();
}
/**
* @return array{string: string}
*/
public function __serialize(): array
{
return ['string' => $this->toString()];
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
$this->__construct($serialized);
}
/**
* @param array{string: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
}
}

Some files were not shown because too many files have changed in this diff Show More