File manager - Edit - /home/linknsbh/sabel-eltaqwa.com/assets/lfm/files/shares/events/thumbs/ramsey.tar
Back
collection/README.md 0000644 00000005416 15213403601 0010157 0 ustar 00 <h1 align="center">ramsey/collection</h1> <p align="center"> <strong>A PHP library for representing and manipulating collections.</strong> </p> <p align="center"> <a href="https://github.com/ramsey/collection"><img src="http://img.shields.io/badge/source-ramsey/collection-blue.svg?style=flat-square" alt="Source Code"></a> <a href="https://packagist.org/packages/ramsey/collection"><img src="https://img.shields.io/packagist/v/ramsey/collection.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/collection.svg?style=flat-square&colorB=%238892BF" alt="PHP Programming Language"></a> <a href="https://github.com/ramsey/collection/blob/master/LICENSE"><img src="https://img.shields.io/packagist/l/ramsey/collection.svg?style=flat-square&colorB=darkcyan" alt="Read License"></a> <a href="https://github.com/ramsey/collection/actions/workflows/continuous-integration.yml"><img src="https://img.shields.io/github/actions/workflow/status/ramsey/collection/continuous-integration.yml?branch=main&logo=github&style=flat-square" alt="Build Status"></a> <a href="https://codecov.io/gh/ramsey/collection"><img src="https://img.shields.io/codecov/c/gh/ramsey/collection?label=codecov&logo=codecov&style=flat-square" alt="Codecov Code Coverage"></a> </p> ## About ramsey/collection is a PHP library for representing and manipulating collections. Much inspiration for this library came from the [Java Collections Framework][java]. 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. ## Installation Install this package as a dependency using [Composer](https://getcomposer.org). ``` bash composer require ramsey/collection ``` ## Usage Examples of how to use this library may be found in the [Wiki pages](https://github.com/ramsey/collection/wiki/Examples). ## Contributing 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. ## Copyright and License The ramsey/collection library is copyright © [Ben Ramsey](https://benramsey.com) and licensed for use under the terms of the MIT License (MIT). Please see [LICENSE](LICENSE) for more information. [java]: http://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html [security.md]: https://github.com/ramsey/collection/blob/main/SECURITY.md collection/LICENSE 0000644 00000002067 15213403601 0007704 0 ustar 00 Copyright (c) 2015-2022 Ben Ramsey <ben@benramsey.com> 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. collection/SECURITY.md 0000644 00000017004 15213403601 0010465 0 ustar 00 <!-- This policy template was created using the HackerOne Policy Builder [1], with guidance from the National Telecommunications and Information Administration Coordinated Vulnerability Disclosure Template [2]. --> # Vulnerability Disclosure Policy (VDP) ## Brand Promise <!-- This is your brand promise. Its objective is to "demonstrate a clear, good faith commitment to customers and other stakeholders potentially impacted by security vulnerabilities" [2]. --> Keeping user information safe and secure is a top priority, and we welcome the contribution of external security researchers. ## Scope <!-- This is your initial scope. It tells vulnerability finders and reporters "which systems and capabilities are 'fair game' versus 'off limits'" [2]. For software packages, this is often a list of currently maintained versions of the package. --> If you believe you've found a security issue in software that is maintained in this repository, we encourage you to notify us. | Version | In scope | Source code | | ------- | :------: | ----------- | | latest | ✅ | https://github.com/ramsey/collection | ## How to Submit a Report <!-- This is your communication process. It tells security researchers how to contact you to report a vulnerability. It may be a link to a web form that uses HTTPS for secure communication, or it may be an email address. Optionally, you may choose to include a PGP public key, so that researchers may send you encrypted messages. --> To submit a vulnerability report, please contact us at security@ramsey.dev. Your submission will be reviewed and validated by a member of our team. ## Safe Harbor <!-- This section assures vulnerability finders and reporters that they will receive good faith responses to their good faith acts. In other words, "we will not take legal action if..." [2]. --> We support safe harbor for security researchers who: * Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. * Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. * Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third party. We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. ## Preferences <!-- The preferences section sets expectations based on priority and submission volume, rather than legal objection or restriction [2]. According to the NTIA [2]: This section is a living document that sets expectations for preferences and priorities, typically maintained by the support and engineering team. This can outline classes of vulnerabilities, reporting style (crash dumps, CVSS scoring, proof-of-concept, etc.), tools, etc. Too many preferences can set the wrong tone or make reporting findings difficult to navigate. This section also sets expectations to the researcher community for what types of issues are considered important or not. --> * Please provide detailed reports with reproducible steps and a clearly defined impact. * Include the version number of the vulnerable package in your report * Social engineering (e.g. phishing, vishing, smishing) is prohibited. <!-- References [1] HackerOne. Policy builder. Retrieved from https://hackerone.com/policy-builder/ [2] NTIA Safety Working Group. 2016. "Early stage" coordinated vulnerability disclosure template: Version 1.1. (15 December 2016). Retrieved from https://www.ntia.doc.gov/files/ntia/publications/ntia_vuln_disclosure_early_stage_template.pdf --> ## Encryption Key for security@ramsey.dev For increased privacy when reporting sensitive issues, you may encrypt your message using the following public key: ``` -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBF+Z9gEBEACbT/pIx8RR0K18t8Z2rDnmEV44YdT7HNsMdq+D6SAlx8UUb6AU jGIbV9dgBgGNtOLU1pxloaJwL9bWIRbj+X/Qb2WNIP//Vz1Y40ox1dSpfCUrizXx kb4p58Xml0PsB8dg3b4RDUgKwGC37ne5xmDnigyJPbiB2XJ6Xc46oPCjh86XROTK wEBB2lY67ClBlSlvC2V9KmbTboRQkLdQDhOaUosMb99zRb0EWqDLaFkZVjY5HI7i 0pTveE6dI12NfHhTwKjZ5pUiAZQGlKA6J1dMjY2unxHZkQj5MlMfrLSyJHZxccdJ xD94T6OTcTHt/XmMpI2AObpewZDdChDQmcYDZXGfAhFoJmbvXsmLMGXKgzKoZ/ls RmLsQhh7+/r8E+Pn5r+A6Hh4uAc14ApyEP0ckKeIXw1C6pepHM4E8TEXVr/IA6K/ z6jlHORixIFX7iNOnfHh+qwOgZw40D6JnBfEzjFi+T2Cy+JzN2uy7I8UnecTMGo3 5t6astPy6xcH6kZYzFTV7XERR6LIIVyLAiMFd8kF5MbJ8N5ElRFsFHPW+82N2HDX c60iSaTB85k6R6xd8JIKDiaKE4sSuw2wHFCKq33d/GamYezp1wO+bVUQg88efljC 2JNFyD+vl30josqhw1HcmbE1TP3DlYeIL5jQOlxCMsgai6JtTfHFM/5MYwARAQAB tBNzZWN1cml0eUByYW1zZXkuZGV2iQJUBBMBCAA+FiEE4drPD+/ofZ570fAYq0bv vXQCywIFAl+Z9gECGwMFCQeGH4AFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ q0bvvXQCywIkEA//Qcwv8MtTCy01LHZd9c7VslwhNdXQDYymcTyjcYw8x7O22m4B 3hXE6vqAplFhVxxkqXB2ef0tQuzxhPHNJgkCE4Wq4i+V6qGpaSVHQT2W6DN/NIhL vS8OdScc6zddmIbIkSrzVVAtjwehFNEIrX3DnbbbK+Iku7vsKT5EclOluIsjlYoX goW8IeReyDBqOe2H3hoCGw6EA0D/NYV2bJnfy53rXVIyarsXXeOLp7eNEH6Td7aW PVSrMZJe1t+knrEGnEdrXWzlg4lCJJCtemGv+pKBUomnyISXSdqyoRCCzvQjqyig 2kRebUX8BXPW33p4OXPj9sIboUOjZwormWwqqbFMO+J4TiVCUoEoheI7emPFRcNN QtPJrjbY1++OznBc0GRpfeUkGoU1cbRl1bnepnFIZMTDLkrVW6I1Y4q8ZVwX3BkE N81ctFrRpHBlU36EdHvjPQmGtuiL77Qq3fWmMv7yTvK1wHJAXfEb0ZJWHZCbck3w l0CVq0Z+UUAOM8Rp1N0N8m92xtapav0qCFU9qzf2J5qX6GRmWv+d29wPgFHzDWBm nnrYYIA4wJLx00U6SMcVBSnNe91B+RfGY5XQhbWPjQQecOGCSDsxaFAq2MeOVJyZ bIjLYfG9GxoLKr5R7oLRJvZI4nKKBc1Kci/crZbdiSdQhSQGlDz88F1OHeCIdQQQ EQgAHRYhBOhdAxHd+lus86YQ57Atl5icjAcbBQJfmfdIAAoJELAtl5icjAcbFVcA /1LqB3ZjsnXDAvvAXZVjSPqofSlpMLeRQP6IM/A9Odq0AQCZrtZc1knOMGEcjppK Rk+sy/R0Mshy8TDuaZIRgh2Ux7kCDQRfmfYBARAAmchKzzVz7IaEq7PnZDb3szQs T/+E9F3m39yOpV4fEB1YzObonFakXNT7Gw2tZEx0eitUMqQ/13jjfu3UdzlKl2bR qA8LrSQRhB+PTC9A1XvwxCUYhhjGiLzJ9CZL6hBQB43qHOmE9XJPme90geLsF+gK u39Waj1SNWzwGg+Gy1Gl5f2AJoDTxznreCuFGj+Vfaczt/hlfgqpOdb9jsmdoE7t 3DSWppA9dRHWwQSgE6J28rR4QySBcqyXS6IMykqaJn7Z26yNIaITLnHCZOSY8zhP ha7GFsN549EOCgECbrnPt9dmI2+hQE0RO0e7SOBNsIf5sz/i7urhwuj0CbOqhjc2 X1AEVNFCVcb6HPi/AWefdFCRu0gaWQxn5g+9nkq5slEgvzCCiKYzaBIcr8qR6Hb4 FaOPVPxO8vndRouq57Ws8XpAwbPttioFuCqF4u9K+tK/8e2/R8QgRYJsE3Cz/Fu8 +pZFpMnqbDEbK3DL3ss+1ed1sky+mDV8qXXeI33XW5hMFnk1JWshUjHNlQmE6ftC U0xSTMVUtwJhzH2zDp8lEdu7qi3EsNULOl68ozDr6soWAvCbHPeTdTOnFySGCleG /3TonsoZJs/sSPPJnxFQ1DtgQL6EbhIwa0ZwU4eKYVHZ9tjxuMX3teFzRvOrJjgs +ywGlsIURtEckT5Y6nMAEQEAAYkCPAQYAQgAJhYhBOHazw/v6H2ee9HwGKtG7710 AssCBQJfmfYBAhsMBQkHhh+AAAoJEKtG7710AssC8NcP/iDAcy1aZFvkA0EbZ85p i7/+ywtE/1wF4U4/9OuLcoskqGGnl1pJNPooMOSBCfreoTB8HimT0Fln0CoaOm4Q pScNq39JXmf4VxauqUJVARByP6zUfgYarqoaZNeuFF0S4AZJ2HhGzaQPjDz1uKVM PE6tQSgQkFzdZ9AtRA4vElTH6yRAgmepUsOihk0b0gUtVnwtRYZ8e0Qt3ie97a73 DxLgAgedFRUbLRYiT0vNaYbainBsLWKpN/T8odwIg/smP0Khjp/ckV60cZTdBiPR szBTPJESMUTu0VPntc4gWwGsmhZJg/Tt/qP08XYo3VxNYBegyuWwNR66zDWvwvGH muMv5UchuDxp6Rt3JkIO4voMT1JSjWy9p8krkPEE4V6PxAagLjdZSkt92wVLiK5x y5gNrtPhU45YdRAKHr36OvJBJQ42CDaZ6nzrzghcIp9CZ7ANHrI+QLRM/csz+AGA szSp6S4mc1lnxxfbOhPPpebZPn0nIAXoZnnoVKdrxBVedPQHT59ZFvKTQ9Fs7gd3 sYNuc7tJGFGC2CxBH4ANDpOQkc5q9JJ1HSGrXU3juxIiRgfA26Q22S9c71dXjElw Ri584QH+bL6kkYmm8xpKF6TVwhwu5xx/jBPrbWqFrtbvLNrnfPoapTihBfdIhkT6 nmgawbBHA02D5xEqB5SU3WJu =eJNx -----END PGP PUBLIC KEY BLOCK----- ``` collection/composer.json 0000644 00000007462 15213403601 0011425 0 ustar 00 { "name": "ramsey/collection", "description": "A PHP library for representing and manipulating collections.", "license": "MIT", "type": "library", "keywords": [ "array", "collection", "hash", "map", "queue", "set" ], "authors": [ { "name": "Ben Ramsey", "email": "ben@benramsey.com", "homepage": "https://benramsey.com" } ], "require": { "php": "^8.1" }, "require-dev": { "captainhook/plugin-composer": "^5.3", "ergebnis/composer-normalize": "^2.45", "fakerphp/faker": "^1.24", "hamcrest/hamcrest-php": "^2.0", "jangregor/phpstan-prophecy": "^2.1", "mockery/mockery": "^1.6", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4", "phpspec/prophecy-phpunit": "^2.3", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.1", "phpstan/phpstan-mockery": "^2.0", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^10.5", "ramsey/coding-standard": "^2.3", "ramsey/conventional-commits": "^1.6", "roave/security-advisories": "dev-latest" }, "prefer-stable": true, "autoload": { "psr-4": { "Ramsey\\Collection\\": "src/" } }, "autoload-dev": { "psr-4": { "Ramsey\\Collection\\Test\\": "tests/" } }, "config": { "allow-plugins": { "captainhook/plugin-composer": true, "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, "phpstan/extension-installer": true }, "sort-packages": true }, "extra": { "captainhook": { "force-install": true }, "ramsey/conventional-commits": { "configFile": "conventional-commits.json" } }, "scripts": { "dev:analyze": [ "@dev:analyze:phpstan" ], "dev:analyze:phpstan": "phpstan analyse --ansi --memory-limit=1G", "dev:build:clean": "git clean -fX build/", "dev:lint": [ "@dev:lint:syntax", "@dev:lint:style" ], "dev:lint:fix": "phpcbf", "dev:lint:style": "phpcs --colors", "dev:lint:syntax": "parallel-lint --colors src/ tests/", "dev:test": [ "@dev:lint", "@dev:analyze", "@dev:test:unit" ], "dev:test:coverage:ci": "phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", "dev:test:coverage:html": "phpunit --colors=always --coverage-html build/coverage/coverage-html/", "dev:test:unit": "phpunit --colors=always", "test": "@dev:test" }, "scripts-descriptions": { "dev:analyze": "Runs all static analysis checks.", "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", "dev:build:clean": "Cleans the build/ directory.", "dev:lint": "Runs all linting checks.", "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", "dev:lint:style": "Checks for coding standards issues.", "dev:lint:syntax": "Checks for syntax errors.", "dev:test": "Runs linting, static analysis, and unit tests.", "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", "dev:test:unit": "Runs unit tests.", "test": "Runs linting, static analysis, and unit tests." } } collection/src/Collection.php 0000644 00000004413 15213403601 0012267 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; /** * A collection represents a group of objects. * * Each object in the collection is of a specific, defined type. * * This is a direct implementation of `CollectionInterface`, provided for * the sake of convenience. * * Example usage: * * ``` * $collection = new \Ramsey\Collection\Collection('My\\Foo'); * $collection->add(new \My\Foo()); * $collection->add(new \My\Foo()); * * foreach ($collection as $foo) { * // Do something with $foo * } * ``` * * It is preferable to subclass `AbstractCollection` to create your own typed * collections. For example: * * ``` * namespace My\Foo; * * class FooCollection extends \Ramsey\Collection\AbstractCollection * { * public function getType() * { * return 'My\\Foo'; * } * } * ``` * * And then use it similarly to the earlier example: * * ``` * $fooCollection = new \My\Foo\FooCollection(); * $fooCollection->add(new \My\Foo()); * $fooCollection->add(new \My\Foo()); * * foreach ($fooCollection as $foo) { * // Do something with $foo * } * ``` * * The benefit with this approach is that you may do type-checking on the * collection object: * * ``` * if ($collection instanceof \My\Foo\FooCollection) { * // the collection is a collection of My\Foo objects * } * ``` * * @template T * @extends AbstractCollection<T> */ class Collection extends AbstractCollection { /** * Constructs a collection object of the specified type, optionally with the * specified data. * * @param string $collectionType The type or class name associated with this * collection. * @param array<array-key, T> $data The initial items to store in the collection. */ public function __construct(private readonly string $collectionType, array $data = []) { parent::__construct($data); } public function getType(): string { return $this->collectionType; } } collection/src/DoubleEndedQueue.php 0000644 00000010300 15213403601 0013343 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Exception\NoSuchElementException; use function array_key_last; use function array_pop; use function array_unshift; /** * This class provides a basic implementation of `DoubleEndedQueueInterface`, to * minimize the effort required to implement this interface. * * @template T * @extends Queue<T> * @implements DoubleEndedQueueInterface<T> */ class DoubleEndedQueue extends Queue implements DoubleEndedQueueInterface { /** * Constructs a double-ended queue (dequeue) object of the specified type, * optionally with the specified data. * * @param string $queueType The type or class name associated with this dequeue. * @param array<array-key, T> $data The initial items to store in the dequeue. */ public function __construct(private readonly string $queueType, array $data = []) { parent::__construct($this->queueType, $data); } /** * @throws InvalidArgumentException if $element is of the wrong type */ public function addFirst(mixed $element): bool { if ($this->checkType($this->getType(), $element) === false) { throw new InvalidArgumentException( 'Value must be of type ' . $this->getType() . '; value is ' . $this->toolValueToString($element), ); } array_unshift($this->data, $element); return true; } /** * @throws InvalidArgumentException if $element is of the wrong type */ public function addLast(mixed $element): bool { return $this->add($element); } public function offerFirst(mixed $element): bool { try { return $this->addFirst($element); } catch (InvalidArgumentException) { return false; } } public function offerLast(mixed $element): bool { return $this->offer($element); } /** * @return T the first element in this queue. * * @throws NoSuchElementException if the queue is empty */ public function removeFirst(): mixed { return $this->remove(); } /** * @return T the last element in this queue. * * @throws NoSuchElementException if this queue is empty. */ public function removeLast(): mixed { return $this->pollLast() ?? throw new NoSuchElementException( 'Can\'t return element from Queue. Queue is empty.', ); } /** * @return T | null the head of this queue, or `null` if this queue is empty. */ public function pollFirst(): mixed { return $this->poll(); } /** * @return T | null the tail of this queue, or `null` if this queue is empty. */ public function pollLast(): mixed { return array_pop($this->data); } /** * @return T the head of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function firstElement(): mixed { return $this->element(); } /** * @return T the tail of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function lastElement(): mixed { return $this->peekLast() ?? throw new NoSuchElementException( 'Can\'t return element from Queue. Queue is empty.', ); } /** * @return T | null the head of this queue, or `null` if this queue is empty. */ public function peekFirst(): mixed { return $this->peek(); } /** * @return T | null the tail of this queue, or `null` if this queue is empty. */ public function peekLast(): mixed { $lastIndex = array_key_last($this->data); if ($lastIndex === null) { return null; } return $this->data[$lastIndex]; } } collection/src/QueueInterface.php 0000644 00000016335 15213403601 0013107 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Ramsey\Collection\Exception\NoSuchElementException; use RuntimeException; /** * A queue is a collection in which the entities in the collection are kept in * order. * * The principal operations on the queue are the addition of entities to the end * (tail), also known as *enqueue*, and removal of entities from the front * (head), also known as *dequeue*. This makes the queue a first-in-first-out * (FIFO) data structure. * * Besides basic array operations, queues provide additional insertion, * extraction, and inspection operations. Each of these methods exists in two * forms: one throws an exception if the operation fails, the other returns a * special value (either `null` or `false`, depending on the operation). The * latter form of the insert operation is designed specifically for use with * capacity-restricted `QueueInterface` implementations; in most * implementations, insert operations cannot fail. * * <table> * <caption>Summary of QueueInterface methods</caption> * <thead> * <tr> * <td></td> * <td><em>Throws exception</em></td> * <td><em>Returns special value</em></td> * </tr> * </thead> * <tbody> * <tr> * <th>Insert</th> * <td><code>add()</code></td> * <td><code>offer()</code></td> * </tr> * <tr> * <th>Remove</th> * <td><code>remove()</code></td> * <td><code>poll()</code></td> * </tr> * <tr> * <th>Examine</th> * <td><code>element()</code></td> * <td><code>peek()</code></td> * </tr> * </tbody> * </table> * * Queues typically, but do not necessarily, order elements in a FIFO * (first-in-first-out) manner. Among the exceptions are priority queues, which * order elements according to a supplied comparator, or the elements' natural * ordering, and LIFO queues (or stacks) which order the elements LIFO * (last-in-first-out). Whatever the ordering used, the head of the queue is * that element which would be removed by a call to remove() or poll(). In a * FIFO queue, all new elements are inserted at the tail of the queue. Other * kinds of queues may use different placement rules. Every `QueueInterface` * implementation must specify its ordering properties. * * The `offer()` method inserts an element if possible, otherwise returning * `false`. This differs from the `add()` method, which can fail to add an * element only by throwing an unchecked exception. The `offer()` method is * designed for use when failure is a normal, rather than exceptional * occurrence, for example, in fixed-capacity (or "bounded") queues. * * The `remove()` and `poll()` methods remove and return the head of the queue. * Exactly which element is removed from the queue is a function of the queue's * ordering policy, which differs from implementation to implementation. The * `remove()` and `poll()` methods differ only in their behavior when the queue * is empty: the `remove()` method throws an exception, while the `poll()` * method returns `null`. * * The `element()` and `peek()` methods return, but do not remove, the head of * the queue. * * `QueueInterface` implementations generally do not allow insertion of `null` * elements, although some implementations do not prohibit insertion of `null`. * Even in the implementations that permit it, `null` should not be inserted * into a queue, as `null` is also used as a special return value by the * `poll()` method to indicate that the queue contains no elements. * * @template T * @extends ArrayInterface<T> */ interface QueueInterface extends ArrayInterface { /** * Ensures that this queue contains the specified element (optional * operation). * * Returns `true` if this queue changed as a result of the call. (Returns * `false` if this queue does not permit duplicates and already contains the * specified element.) * * Queues that support this operation may place limitations on what elements * may be added to this queue. In particular, some queues will refuse to add * `null` elements, and others will impose restrictions on the type of * elements that may be added. Queue classes should clearly specify in their * documentation any restrictions on what elements may be added. * * If a queue refuses to add a particular element for any reason other than * that it already contains the element, it must throw an exception (rather * than returning `false`). This preserves the invariant that a queue always * contains the specified element after this call returns. * * @see self::offer() * * @param T $element The element to add to this queue. * * @return bool `true` if this queue changed as a result of the call. * * @throws RuntimeException if a queue refuses to add a particular element * for any reason other than that it already contains the element. * Implementations should use a more-specific exception that extends * `\RuntimeException`. */ public function add(mixed $element): bool; /** * Retrieves, but does not remove, the head of this queue. * * This method differs from `peek()` only in that it throws an exception if * this queue is empty. * * @see self::peek() * * @return T the head of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function element(): mixed; /** * Inserts the specified element into this queue if it is possible to do so * immediately without violating capacity restrictions. * * When using a capacity-restricted queue, this method is generally * preferable to `add()`, which can fail to insert an element only by * throwing an exception. * * @see self::add() * * @param T $element The element to add to this queue. * * @return bool `true` if the element was added to this queue, else `false`. */ public function offer(mixed $element): bool; /** * Retrieves, but does not remove, the head of this queue, or returns `null` * if this queue is empty. * * @see self::element() * * @return T | null the head of this queue, or `null` if this queue is empty. */ public function peek(): mixed; /** * Retrieves and removes the head of this queue, or returns `null` * if this queue is empty. * * @see self::remove() * * @return T | null the head of this queue, or `null` if this queue is empty. */ public function poll(): mixed; /** * Retrieves and removes the head of this queue. * * This method differs from `poll()` only in that it throws an exception if * this queue is empty. * * @see self::poll() * * @return T the head of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function remove(): mixed; /** * Returns the type associated with this queue. */ public function getType(): string; } collection/src/AbstractCollection.php 0000644 00000026025 15213403601 0013756 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Closure; use Ramsey\Collection\Exception\CollectionMismatchException; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Exception\InvalidPropertyOrMethod; use Ramsey\Collection\Exception\NoSuchElementException; use Ramsey\Collection\Exception\UnsupportedOperationException; use Ramsey\Collection\Tool\TypeTrait; use Ramsey\Collection\Tool\ValueExtractorTrait; use Ramsey\Collection\Tool\ValueToStringTrait; use function array_filter; use function array_key_first; use function array_key_last; use function array_map; use function array_merge; use function array_reduce; use function array_search; use function array_udiff; use function array_uintersect; use function in_array; use function is_int; use function is_object; use function spl_object_id; use function sprintf; use function usort; /** * This class provides a basic implementation of `CollectionInterface`, to * minimize the effort required to implement this interface * * @template T * @extends AbstractArray<T> * @implements CollectionInterface<T> */ abstract class AbstractCollection extends AbstractArray implements CollectionInterface { use TypeTrait; use ValueToStringTrait; use ValueExtractorTrait; /** * @throws InvalidArgumentException if $element is of the wrong type. */ public function add(mixed $element): bool { $this[] = $element; return true; } public function contains(mixed $element, bool $strict = true): bool { return in_array($element, $this->data, $strict); } /** * @throws InvalidArgumentException if $element is of the wrong type. */ public function offsetSet(mixed $offset, mixed $value): void { if ($this->checkType($this->getType(), $value) === false) { throw new InvalidArgumentException( 'Value must be of type ' . $this->getType() . '; value is ' . $this->toolValueToString($value), ); } if ($offset === null) { $this->data[] = $value; } else { $this->data[$offset] = $value; } } public function remove(mixed $element): bool { if (($position = array_search($element, $this->data, true)) !== false) { unset($this[$position]); return true; } return false; } /** * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call column() on this * collection. * * @inheritDoc */ public function column(string $propertyOrMethod): array { $temp = []; foreach ($this->data as $item) { $temp[] = $this->extractValue($item, $propertyOrMethod); } return $temp; } /** * @return T * * @throws NoSuchElementException if this collection is empty. */ public function first(): mixed { $firstIndex = array_key_first($this->data); if ($firstIndex === null) { throw new NoSuchElementException('Can\'t determine first item. Collection is empty'); } return $this->data[$firstIndex]; } /** * @return T * * @throws NoSuchElementException if this collection is empty. */ public function last(): mixed { $lastIndex = array_key_last($this->data); if ($lastIndex === null) { throw new NoSuchElementException('Can\'t determine last item. Collection is empty'); } return $this->data[$lastIndex]; } /** * @return CollectionInterface<T> * * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call sort() on this * collection. */ public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): CollectionInterface { $collection = clone $this; usort( $collection->data, function (mixed $a, mixed $b) use ($propertyOrMethod, $order): int { $aValue = $this->extractValue($a, $propertyOrMethod); $bValue = $this->extractValue($b, $propertyOrMethod); return ($aValue <=> $bValue) * ($order === Sort::Descending ? -1 : 1); }, ); return $collection; } /** * @param callable(T): bool $callback A callable to use for filtering elements. * * @return CollectionInterface<T> */ public function filter(callable $callback): CollectionInterface { $collection = clone $this; $collection->data = array_merge([], array_filter($collection->data, $callback)); return $collection; } /** * @return CollectionInterface<T> * * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call where() on this * collection. */ public function where(?string $propertyOrMethod, mixed $value): CollectionInterface { return $this->filter( fn (mixed $item): bool => $this->extractValue($item, $propertyOrMethod) === $value, ); } /** * @param callable(T): TCallbackReturn $callback A callable to apply to each * item of the collection. * * @return CollectionInterface<TCallbackReturn> * * @template TCallbackReturn */ public function map(callable $callback): CollectionInterface { return new Collection('mixed', array_map($callback, $this->data)); } /** * @param callable(TCarry, T): TCarry $callback A callable to apply to each * item of the collection to reduce it to a single value. * @param TCarry $initial This is the initial value provided to the callback. * * @return TCarry * * @template TCarry */ public function reduce(callable $callback, mixed $initial): mixed { return array_reduce($this->data, $callback, $initial); } /** * @param CollectionInterface<T> $other The collection to check for divergent * items. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if the compared collections are of * differing types. */ public function diff(CollectionInterface $other): CollectionInterface { $this->compareCollectionTypes($other); $diffAtoB = array_udiff($this->data, $other->toArray(), $this->getComparator()); $diffBtoA = array_udiff($other->toArray(), $this->data, $this->getComparator()); $collection = clone $this; $collection->data = array_merge($diffAtoB, $diffBtoA); return $collection; } /** * @param CollectionInterface<T> $other The collection to check for * intersecting items. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if the compared collections are of * differing types. */ public function intersect(CollectionInterface $other): CollectionInterface { $this->compareCollectionTypes($other); $collection = clone $this; $collection->data = array_uintersect($this->data, $other->toArray(), $this->getComparator()); return $collection; } /** * @param CollectionInterface<T> ...$collections The collections to merge. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if unable to merge any of the given * collections or items within the given collections due to type * mismatch errors. */ public function merge(CollectionInterface ...$collections): CollectionInterface { $mergedCollection = clone $this; foreach ($collections as $index => $collection) { if (!$collection instanceof static) { throw new CollectionMismatchException( sprintf('Collection with index %d must be of type %s', $index, static::class), ); } // When using generics (Collection.php, Set.php, etc), // we also need to make sure that the internal types match each other if ($this->getUniformType($collection) !== $this->getUniformType($this)) { throw new CollectionMismatchException( sprintf( 'Collection items in collection with index %d must be of type %s', $index, $this->getType(), ), ); } foreach ($collection as $key => $value) { if (is_int($key)) { $mergedCollection[] = $value; } else { $mergedCollection[$key] = $value; } } } return $mergedCollection; } /** * @param CollectionInterface<T> $other * * @throws CollectionMismatchException */ private function compareCollectionTypes(CollectionInterface $other): void { if (!$other instanceof static) { throw new CollectionMismatchException('Collection must be of type ' . static::class); } // When using generics (Collection.php, Set.php, etc), // we also need to make sure that the internal types match each other if ($this->getUniformType($other) !== $this->getUniformType($this)) { throw new CollectionMismatchException('Collection items must be of type ' . $this->getType()); } } private function getComparator(): Closure { return function (mixed $a, mixed $b): int { // If the two values are object, we convert them to unique scalars. // If the collection contains mixed values (unlikely) where some are objects // and some are not, we leave them as they are. // The comparator should still work and the result of $a < $b should // be consistent but unpredictable since not documented. if (is_object($a) && is_object($b)) { $a = spl_object_id($a); $b = spl_object_id($b); } return $a === $b ? 0 : ($a < $b ? 1 : -1); }; } /** * @param CollectionInterface<mixed> $collection */ private function getUniformType(CollectionInterface $collection): string { return match ($collection->getType()) { 'integer' => 'int', 'boolean' => 'bool', 'double' => 'float', default => $collection->getType(), }; } } collection/src/Sort.php 0000644 00000001155 15213403601 0011123 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; /** * Collection sorting */ enum Sort: string { /** * Sort items in a collection in ascending order. */ case Ascending = 'asc'; /** * Sort items in a collection in descending order. */ case Descending = 'desc'; } collection/src/Set.php 0000644 00000003042 15213403601 0010724 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; /** * A set is a collection that contains no duplicate elements. * * Great care must be exercised if mutable objects are used as set elements. * The behavior of a set is not specified if the value of an object is changed * in a manner that affects equals comparisons while the object is an element in * the set. * * Example usage: * * ``` * $foo = new \My\Foo(); * $set = new Set(\My\Foo::class); * * $set->add($foo); // returns TRUE, the element doesn't exist * $set->add($foo); // returns FALSE, the element already exists * * $bar = new \My\Foo(); * $set->add($bar); // returns TRUE, $bar !== $foo * ``` * * @template T * @extends AbstractSet<T> */ class Set extends AbstractSet { /** * Constructs a set object of the specified type, optionally with the * specified data. * * @param string $setType The type or class name associated with this set. * @param array<array-key, T> $data The initial items to store in the set. */ public function __construct(private readonly string $setType, array $data = []) { parent::__construct($data); } public function getType(): string { return $this->setType; } } collection/src/GenericArray.php 0000644 00000001000 15213403601 0012534 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; /** * `GenericArray` represents a standard array object. * * @extends AbstractArray<mixed> */ class GenericArray extends AbstractArray { } collection/src/CollectionInterface.php 0000644 00000021700 15213403601 0014106 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Ramsey\Collection\Exception\CollectionMismatchException; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Exception\InvalidPropertyOrMethod; use Ramsey\Collection\Exception\NoSuchElementException; use Ramsey\Collection\Exception\UnsupportedOperationException; /** * A collection represents a group of values, known as its elements. * * Some collections allow duplicate elements and others do not. Some are ordered * and others unordered. * * @template T * @extends ArrayInterface<T> */ interface CollectionInterface extends ArrayInterface { /** * Ensures that this collection contains the specified element (optional * operation). * * Returns `true` if this collection changed as a result of the call. * (Returns `false` if this collection does not permit duplicates and * already contains the specified element.) * * Collections that support this operation may place limitations on what * elements may be added to this collection. In particular, some * collections will refuse to add `null` elements, and others will impose * restrictions on the type of elements that may be added. Collection * classes should clearly specify in their documentation any restrictions * on what elements may be added. * * If a collection refuses to add a particular element for any reason other * than that it already contains the element, it must throw an exception * (rather than returning `false`). This preserves the invariant that a * collection always contains the specified element after this call returns. * * @param T $element The element to add to the collection. * * @return bool `true` if this collection changed as a result of the call. * * @throws InvalidArgumentException if the collection refuses to add the * $element for any reason other than that it already contains the element. */ public function add(mixed $element): bool; /** * Returns `true` if this collection contains the specified element. * * @param T $element The element to check whether the collection contains. * @param bool $strict Whether to perform a strict type check on the value. */ public function contains(mixed $element, bool $strict = true): bool; /** * Returns the type associated with this collection. */ public function getType(): string; /** * Removes a single instance of the specified element from this collection, * if it is present. * * @param T $element The element to remove from the collection. * * @return bool `true` if an element was removed as a result of this call. */ public function remove(mixed $element): bool; /** * Returns the values from the given property, method, or array key. * * @param string $propertyOrMethod The name of the property, method, or * array key to evaluate and return. * * @return list<mixed> * * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call column() on this * collection. */ public function column(string $propertyOrMethod): array; /** * Returns the first item of the collection. * * @return T * * @throws NoSuchElementException if this collection is empty. */ public function first(): mixed; /** * Returns the last item of the collection. * * @return T * * @throws NoSuchElementException if this collection is empty. */ public function last(): mixed; /** * Sort the collection by a property, method, or array key with the given * sort order. * * If $propertyOrMethod is `null`, this will sort by comparing each element. * * This will always leave the original collection untouched and will return * a new one. * * @param string | null $propertyOrMethod The property, method, or array key * to sort by. * @param Sort $order The sort order for the resulting collection. * * @return CollectionInterface<T> * * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call sort() on this * collection. */ public function sort(?string $propertyOrMethod = null, Sort $order = Sort::Ascending): self; /** * Filter out items of the collection which don't match the criteria of * given callback. * * This will always leave the original collection untouched and will return * a new one. * * See the {@link http://php.net/manual/en/function.array-filter.php PHP array_filter() documentation} * for examples of how the `$callback` parameter works. * * @param callable(T): bool $callback A callable to use for filtering elements. * * @return CollectionInterface<T> */ public function filter(callable $callback): self; /** * Create a new collection where the result of the given property, method, * or array key of each item in the collection equals the given value. * * This will always leave the original collection untouched and will return * a new one. * * @param string | null $propertyOrMethod The property, method, or array key * to evaluate. If `null`, the element itself is compared to $value. * @param mixed $value The value to match. * * @return CollectionInterface<T> * * @throws InvalidPropertyOrMethod if the $propertyOrMethod does not exist * on the elements in this collection. * @throws UnsupportedOperationException if unable to call where() on this * collection. */ public function where(?string $propertyOrMethod, mixed $value): self; /** * Apply a given callback method on each item of the collection. * * This will always leave the original collection untouched. The new * collection is created by mapping the callback to each item of the * original collection. * * See the {@link http://php.net/manual/en/function.array-map.php PHP array_map() documentation} * for examples of how the `$callback` parameter works. * * @param callable(T): TCallbackReturn $callback A callable to apply to each * item of the collection. * * @return CollectionInterface<TCallbackReturn> * * @template TCallbackReturn */ public function map(callable $callback): self; /** * Apply a given callback method on each item of the collection * to reduce it to a single value. * * See the {@link http://php.net/manual/en/function.array-reduce.php PHP array_reduce() documentation} * for examples of how the `$callback` and `$initial` parameters work. * * @param callable(TCarry, T): TCarry $callback A callable to apply to each * item of the collection to reduce it to a single value. * @param TCarry $initial This is the initial value provided to the callback. * * @return TCarry * * @template TCarry */ public function reduce(callable $callback, mixed $initial): mixed; /** * Create a new collection with divergent items between current and given * collection. * * @param CollectionInterface<T> $other The collection to check for divergent * items. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if the compared collections are of * differing types. */ public function diff(CollectionInterface $other): self; /** * Create a new collection with intersecting item between current and given * collection. * * @param CollectionInterface<T> $other The collection to check for * intersecting items. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if the compared collections are of * differing types. */ public function intersect(CollectionInterface $other): self; /** * Merge current items and items of given collections into a new one. * * @param CollectionInterface<T> ...$collections The collections to merge. * * @return CollectionInterface<T> * * @throws CollectionMismatchException if unable to merge any of the given * collections or items within the given collections due to type * mismatch errors. */ public function merge(CollectionInterface ...$collections): self; } collection/src/AbstractArray.php 0000644 00000010423 15213403601 0012734 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use ArrayIterator; use Traversable; use function count; /** * This class provides a basic implementation of `ArrayInterface`, to minimize * the effort required to implement this interface. * * @template T * @implements ArrayInterface<T> */ abstract class AbstractArray implements ArrayInterface { /** * The items of this array. * * @var array<array-key, T> */ protected array $data = []; /** * Constructs a new array object. * * @param array<array-key, T> $data The initial items to add to this array. */ public function __construct(array $data = []) { // Invoke offsetSet() for each value added; in this way, subclasses // may provide additional logic about values added to the array object. foreach ($data as $key => $value) { $this[$key] = $value; } } /** * Returns an iterator for this array. * * @link http://php.net/manual/en/iteratoraggregate.getiterator.php IteratorAggregate::getIterator() * * @return Traversable<array-key, T> */ public function getIterator(): Traversable { return new ArrayIterator($this->data); } /** * Returns `true` if the given offset exists in this array. * * @link http://php.net/manual/en/arrayaccess.offsetexists.php ArrayAccess::offsetExists() * * @param array-key $offset The offset to check. */ public function offsetExists(mixed $offset): bool { return isset($this->data[$offset]); } /** * Returns the value at the specified offset. * * @link http://php.net/manual/en/arrayaccess.offsetget.php ArrayAccess::offsetGet() * * @param array-key $offset The offset for which a value should be returned. * * @return T the value stored at the offset, or null if the offset * does not exist. */ public function offsetGet(mixed $offset): mixed { return $this->data[$offset]; } /** * Sets the given value to the given offset in the array. * * @link http://php.net/manual/en/arrayaccess.offsetset.php ArrayAccess::offsetSet() * * @param array-key | null $offset The offset to set. If `null`, the value * may be set at a numerically-indexed offset. * @param T $value The value to set at the given offset. */ public function offsetSet(mixed $offset, mixed $value): void { if ($offset === null) { $this->data[] = $value; } else { $this->data[$offset] = $value; } } /** * Removes the given offset and its value from the array. * * @link http://php.net/manual/en/arrayaccess.offsetunset.php ArrayAccess::offsetUnset() * * @param array-key $offset The offset to remove from the array. */ public function offsetUnset(mixed $offset): void { unset($this->data[$offset]); } /** * Returns data suitable for PHP serialization. * * @link https://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.serialize * @link https://www.php.net/serialize * * @return array<array-key, T> */ public function __serialize(): array { return $this->data; } /** * Adds unserialized data to the object. * * @param array<array-key, T> $data */ public function __unserialize(array $data): void { $this->data = $data; } /** * Returns the number of items in this array. * * @link http://php.net/manual/en/countable.count.php Countable::count() */ public function count(): int { return count($this->data); } public function clear(): void { $this->data = []; } /** * @inheritDoc */ public function toArray(): array { return $this->data; } public function isEmpty(): bool { return $this->data === []; } } collection/src/Map/AbstractTypedMap.php 0000644 00000003207 15213403601 0014120 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Tool\TypeTrait; use Ramsey\Collection\Tool\ValueToStringTrait; /** * This class provides a basic implementation of `TypedMapInterface`, to * minimize the effort required to implement this interface. * * @template K of array-key * @template T * @extends AbstractMap<K, T> * @implements TypedMapInterface<K, T> */ abstract class AbstractTypedMap extends AbstractMap implements TypedMapInterface { use TypeTrait; use ValueToStringTrait; /** * @param K $offset * @param T $value * * @inheritDoc */ public function offsetSet(mixed $offset, mixed $value): void { if ($this->checkType($this->getKeyType(), $offset) === false) { throw new InvalidArgumentException( 'Key must be of type ' . $this->getKeyType() . '; key is ' . $this->toolValueToString($offset), ); } if ($this->checkType($this->getValueType(), $value) === false) { throw new InvalidArgumentException( 'Value must be of type ' . $this->getValueType() . '; value is ' . $this->toolValueToString($value), ); } parent::offsetSet($offset, $value); } } collection/src/Map/MapInterface.php 0000644 00000010723 15213403601 0013250 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; use Ramsey\Collection\ArrayInterface; /** * An object that maps keys to values. * * A map cannot contain duplicate keys; each key can map to at most one value. * * @template K of array-key * @template T * @extends ArrayInterface<T> */ interface MapInterface extends ArrayInterface { /** * Returns `true` if this map contains a mapping for the specified key. * * @param K $key The key to check in the map. */ public function containsKey(int | string $key): bool; /** * Returns `true` if this map maps one or more keys to the specified value. * * This performs a strict type check on the value. * * @param T $value The value to check in the map. */ public function containsValue(mixed $value): bool; /** * Return an array of the keys contained in this map. * * @return list<K> */ public function keys(): array; /** * Returns the value to which the specified key is mapped, `null` if this * map contains no mapping for the key, or (optionally) `$defaultValue` if * this map contains no mapping for the key. * * @param K $key The key to return from the map. * @param T | null $defaultValue The default value to use if `$key` is not found. * * @return T | null the value or `null` if the key could not be found. */ public function get(int | string $key, mixed $defaultValue = null): mixed; /** * Associates the specified value with the specified key in this map. * * If the map previously contained a mapping for the key, the old value is * replaced by the specified value. * * @param K $key The key to put or replace in the map. * @param T $value The value to store at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function put(int | string $key, mixed $value): mixed; /** * Associates the specified value with the specified key in this map only if * it is not already set. * * If there is already a value associated with `$key`, this returns that * value without replacing it. * * @param K $key The key to put in the map. * @param T $value The value to store at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function putIfAbsent(int | string $key, mixed $value): mixed; /** * Removes the mapping for a key from this map if it is present. * * @param K $key The key to remove from the map. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function remove(int | string $key): mixed; /** * Removes the entry for the specified key only if it is currently mapped to * the specified value. * * This performs a strict type check on the value. * * @param K $key The key to remove from the map. * @param T $value The value to match. * * @return bool true if the value was removed. */ public function removeIf(int | string $key, mixed $value): bool; /** * Replaces the entry for the specified key only if it is currently mapped * to some value. * * @param K $key The key to replace. * @param T $value The value to set at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function replace(int | string $key, mixed $value): mixed; /** * Replaces the entry for the specified key only if currently mapped to the * specified value. * * This performs a strict type check on the value. * * @param K $key The key to remove from the map. * @param T $oldValue The value to match. * @param T $newValue The value to use as a replacement. * * @return bool true if the value was replaced. */ public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool; } collection/src/Map/TypedMapInterface.php 0000644 00000001443 15213403601 0014255 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; /** * A `TypedMapInterface` represents a map of elements where key and value are * typed. * * @template K of array-key * @template T * @extends MapInterface<K, T> */ interface TypedMapInterface extends MapInterface { /** * Return the type used on the key. */ public function getKeyType(): string; /** * Return the type forced on the values. */ public function getValueType(): string; } collection/src/Map/TypedMap.php 0000644 00000005370 15213403601 0012437 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; /** * A `TypedMap` represents a map of elements where key and value are typed. * * Each element is identified by a key with defined type and a value of defined * type. The keys of the map must be unique. The values on the map can be * repeated but each with its own different key. * * The most common case is to use a string type key, but it's not limited to * this type of keys. * * This is a direct implementation of `TypedMapInterface`, provided for the sake * of convenience. * * Example usage: * * ``` * $map = new TypedMap('string', Foo::class); * $map['x'] = new Foo(); * foreach ($map as $key => $value) { * // do something with $key, it will be a Foo::class * } * * // this will throw an exception since key must be string * $map[10] = new Foo(); * * // this will throw an exception since value must be a Foo * $map['bar'] = 'bar'; * * // initialize map with contents * $map = new TypedMap('string', Foo::class, [ * new Foo(), new Foo(), new Foo() * ]); * ``` * * It is preferable to subclass `AbstractTypedMap` to create your own typed map * implementation: * * ``` * class FooTypedMap extends AbstractTypedMap * { * public function getKeyType() * { * return 'int'; * } * * public function getValueType() * { * return Foo::class; * } * } * ``` * * … but you also may use the `TypedMap` class: * * ``` * class FooTypedMap extends TypedMap * { * public function __constructor(array $data = []) * { * parent::__construct('int', Foo::class, $data); * } * } * ``` * * @template K of array-key * @template T * @extends AbstractTypedMap<K, T> */ class TypedMap extends AbstractTypedMap { /** * Constructs a map object of the specified key and value types, * optionally with the specified data. * * @param string $keyType The data type of the map's keys. * @param string $valueType The data type of the map's values. * @param array<K, T> $data The initial data to set for this map. */ public function __construct( private readonly string $keyType, private readonly string $valueType, array $data = [], ) { parent::__construct($data); } public function getKeyType(): string { return $this->keyType; } public function getValueType(): string { return $this->valueType; } } collection/src/Map/AssociativeArrayMap.php 0000644 00000001042 15213403601 0014613 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; /** * `AssociativeArrayMap` represents a standard associative array object. * * @extends AbstractMap<string, mixed> */ class AssociativeArrayMap extends AbstractMap { } collection/src/Map/AbstractMap.php 0000644 00000011706 15213403601 0013115 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; use Ramsey\Collection\AbstractArray; use Ramsey\Collection\Exception\InvalidArgumentException; use Traversable; use function array_key_exists; use function array_keys; use function in_array; use function var_export; /** * This class provides a basic implementation of `MapInterface`, to minimize the * effort required to implement this interface. * * @template K of array-key * @template T * @extends AbstractArray<T> * @implements MapInterface<K, T> */ abstract class AbstractMap extends AbstractArray implements MapInterface { /** * @param array<K, T> $data The initial items to add to this map. */ public function __construct(array $data = []) { parent::__construct($data); } /** * @return Traversable<K, T> */ public function getIterator(): Traversable { return parent::getIterator(); } /** * @param K $offset The offset to set * @param T $value The value to set at the given offset. * * @inheritDoc */ public function offsetSet(mixed $offset, mixed $value): void { if ($offset === null) { throw new InvalidArgumentException( 'Map elements are key/value pairs; a key must be provided for ' . 'value ' . var_export($value, true), ); } $this->data[$offset] = $value; } public function containsKey(int | string $key): bool { return array_key_exists($key, $this->data); } public function containsValue(mixed $value): bool { return in_array($value, $this->data, true); } /** * @inheritDoc */ public function keys(): array { /** @var list<K> */ return array_keys($this->data); } /** * @param K $key The key to return from the map. * @param T | null $defaultValue The default value to use if `$key` is not found. * * @return T | null the value or `null` if the key could not be found. */ public function get(int | string $key, mixed $defaultValue = null): mixed { return $this[$key] ?? $defaultValue; } /** * @param K $key The key to put or replace in the map. * @param T $value The value to store at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function put(int | string $key, mixed $value): mixed { $previousValue = $this->get($key); $this[$key] = $value; return $previousValue; } /** * @param K $key The key to put in the map. * @param T $value The value to store at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function putIfAbsent(int | string $key, mixed $value): mixed { $currentValue = $this->get($key); if ($currentValue === null) { $this[$key] = $value; } return $currentValue; } /** * @param K $key The key to remove from the map. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function remove(int | string $key): mixed { $previousValue = $this->get($key); unset($this[$key]); return $previousValue; } public function removeIf(int | string $key, mixed $value): bool { if ($this->get($key) === $value) { unset($this[$key]); return true; } return false; } /** * @param K $key The key to replace. * @param T $value The value to set at `$key`. * * @return T | null the previous value associated with key, or `null` if * there was no mapping for `$key`. */ public function replace(int | string $key, mixed $value): mixed { $currentValue = $this->get($key); if ($this->containsKey($key)) { $this[$key] = $value; } return $currentValue; } public function replaceIf(int | string $key, mixed $oldValue, mixed $newValue): bool { if ($this->get($key) === $oldValue) { $this[$key] = $newValue; return true; } return false; } /** * @return array<K, T> */ public function __serialize(): array { /** @var array<K, T> */ return parent::__serialize(); } /** * @return array<K, T> */ public function toArray(): array { /** @var array<K, T> */ return parent::toArray(); } } collection/src/Map/NamedParameterMap.php 0000644 00000006072 15213403601 0014237 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Map; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Tool\TypeTrait; use Ramsey\Collection\Tool\ValueToStringTrait; use function array_combine; use function array_key_exists; use function is_int; /** * `NamedParameterMap` represents a mapping of values to a set of named keys * that may optionally be typed * * @extends AbstractMap<string, mixed> */ class NamedParameterMap extends AbstractMap { use TypeTrait; use ValueToStringTrait; /** * Named parameters defined for this map. * * @var array<string, string> */ private readonly array $namedParameters; /** * Constructs a new `NamedParameterMap`. * * @param array<array-key, string> $namedParameters The named parameters defined for this map. * @param array<string, mixed> $data An initial set of data to set on this map. */ public function __construct(array $namedParameters, array $data = []) { $this->namedParameters = $this->filterNamedParameters($namedParameters); parent::__construct($data); } /** * Returns named parameters set for this `NamedParameterMap`. * * @return array<string, string> */ public function getNamedParameters(): array { return $this->namedParameters; } public function offsetSet(mixed $offset, mixed $value): void { if (!array_key_exists($offset, $this->namedParameters)) { throw new InvalidArgumentException( 'Attempting to set value for unconfigured parameter \'' . $this->toolValueToString($offset) . '\'', ); } if ($this->checkType($this->namedParameters[$offset], $value) === false) { throw new InvalidArgumentException( 'Value for \'' . $offset . '\' must be of type ' . $this->namedParameters[$offset] . '; value is ' . $this->toolValueToString($value), ); } $this->data[$offset] = $value; } /** * Given an array of named parameters, constructs a proper mapping of * named parameters to types. * * @param array<array-key, string> $namedParameters The named parameters to filter. * * @return array<string, string> */ protected function filterNamedParameters(array $namedParameters): array { $names = []; $types = []; foreach ($namedParameters as $key => $value) { if (is_int($key)) { $names[] = $value; $types[] = 'mixed'; } else { $names[] = $key; $types[] = $value; } } return array_combine($names, $types) ?: []; } } collection/src/Tool/ValueToStringTrait.php 0000644 00000004407 15213403601 0014666 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Tool; use DateTimeInterface; use function assert; use function get_resource_type; use function is_array; use function is_bool; use function is_callable; use function is_object; use function is_resource; use function is_scalar; /** * Provides functionality to express a value as string */ trait ValueToStringTrait { /** * Returns a string representation of the value. * * - null value: `'NULL'` * - boolean: `'TRUE'`, `'FALSE'` * - array: `'Array'` * - scalar: converted-value * - resource: `'(type resource #number)'` * - object with `__toString()`: result of `__toString()` * - object DateTime: ISO 8601 date * - object: `'(className Object)'` * - anonymous function: same as object * * @param mixed $value the value to return as a string. */ protected function toolValueToString(mixed $value): string { // null if ($value === null) { return 'NULL'; } // boolean constants if (is_bool($value)) { return $value ? 'TRUE' : 'FALSE'; } // array if (is_array($value)) { return 'Array'; } // scalar types (integer, float, string) if (is_scalar($value)) { return (string) $value; } // resource if (is_resource($value)) { return '(' . get_resource_type($value) . ' resource #' . (int) $value . ')'; } // From here, $value should be an object. assert(is_object($value)); // __toString() is implemented if (is_callable([$value, '__toString'])) { /** @var string */ return $value->__toString(); } // object of type \DateTime if ($value instanceof DateTimeInterface) { return $value->format('c'); } // unknown type return '(' . $value::class . ' Object)'; } } collection/src/Tool/ValueExtractorTrait.php 0000644 00000006056 15213403601 0015072 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Tool; use Ramsey\Collection\Exception\InvalidPropertyOrMethod; use Ramsey\Collection\Exception\UnsupportedOperationException; use ReflectionProperty; use function is_array; use function is_object; use function method_exists; use function property_exists; use function sprintf; /** * Provides functionality to extract the value of a property or method from an object. */ trait ValueExtractorTrait { /** * Returns the type associated with this collection. */ abstract public function getType(): string; /** * Extracts the value of the given property, method, or array key from the * element. * * If `$propertyOrMethod` is `null`, we return the element as-is. * * @param mixed $element The element to extract the value from. * @param string | null $propertyOrMethod The property or method for which the * value should be extracted. * * @return mixed the value extracted from the specified property, method, * or array key, or the element itself. * * @throws InvalidPropertyOrMethod * @throws UnsupportedOperationException */ protected function extractValue(mixed $element, ?string $propertyOrMethod): mixed { if ($propertyOrMethod === null) { return $element; } if (!is_object($element) && !is_array($element)) { throw new UnsupportedOperationException(sprintf( 'The collection type "%s" does not support the $propertyOrMethod parameter', $this->getType(), )); } if (is_array($element)) { return $element[$propertyOrMethod] ?? throw new InvalidPropertyOrMethod(sprintf( 'Key or index "%s" not found in collection elements', $propertyOrMethod, )); } if (property_exists($element, $propertyOrMethod) && method_exists($element, $propertyOrMethod)) { $reflectionProperty = new ReflectionProperty($element, $propertyOrMethod); if ($reflectionProperty->isPublic()) { return $element->$propertyOrMethod; } return $element->{$propertyOrMethod}(); } if (property_exists($element, $propertyOrMethod)) { return $element->$propertyOrMethod; } if (method_exists($element, $propertyOrMethod)) { return $element->{$propertyOrMethod}(); } if (isset($element->$propertyOrMethod)) { return $element->$propertyOrMethod; } throw new InvalidPropertyOrMethod(sprintf( 'Method or property "%s" not defined in %s', $propertyOrMethod, $element::class, )); } } collection/src/Tool/TypeTrait.php 0000644 00000003065 15213403601 0013040 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Tool; use function is_array; use function is_bool; use function is_callable; use function is_float; use function is_int; use function is_numeric; use function is_object; use function is_resource; use function is_scalar; use function is_string; /** * Provides functionality to check values for specific types. */ trait TypeTrait { /** * Returns `true` if value is of the specified type. * * @param string $type The type to check the value against. * @param mixed $value The value to check. */ protected function checkType(string $type, mixed $value): bool { return match ($type) { 'array' => is_array($value), 'bool', 'boolean' => is_bool($value), 'callable' => is_callable($value), 'float', 'double' => is_float($value), 'int', 'integer' => is_int($value), 'null' => $value === null, 'numeric' => is_numeric($value), 'object' => is_object($value), 'resource' => is_resource($value), 'scalar' => is_scalar($value), 'string' => is_string($value), 'mixed' => true, default => $value instanceof $type, }; } } collection/src/Queue.php 0000644 00000007115 15213403601 0011262 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Ramsey\Collection\Exception\InvalidArgumentException; use Ramsey\Collection\Exception\NoSuchElementException; use Ramsey\Collection\Tool\TypeTrait; use Ramsey\Collection\Tool\ValueToStringTrait; use function array_key_first; /** * This class provides a basic implementation of `QueueInterface`, to minimize * the effort required to implement this interface. * * @template T * @extends AbstractArray<T> * @implements QueueInterface<T> */ class Queue extends AbstractArray implements QueueInterface { use TypeTrait; use ValueToStringTrait; /** * Constructs a queue object of the specified type, optionally with the * specified data. * * @param string $queueType The type or class name associated with this queue. * @param array<array-key, T> $data The initial items to store in the queue. */ public function __construct(private readonly string $queueType, array $data = []) { parent::__construct($data); } /** * {@inheritDoc} * * Since arbitrary offsets may not be manipulated in a queue, this method * serves only to fulfill the `ArrayAccess` interface requirements. It is * invoked by other operations when adding values to the queue. * * @throws InvalidArgumentException if $value is of the wrong type. */ public function offsetSet(mixed $offset, mixed $value): void { if ($this->checkType($this->getType(), $value) === false) { throw new InvalidArgumentException( 'Value must be of type ' . $this->getType() . '; value is ' . $this->toolValueToString($value), ); } $this->data[] = $value; } /** * @throws InvalidArgumentException if $value is of the wrong type. */ public function add(mixed $element): bool { $this[] = $element; return true; } /** * @return T * * @throws NoSuchElementException if this queue is empty. */ public function element(): mixed { return $this->peek() ?? throw new NoSuchElementException( 'Can\'t return element from Queue. Queue is empty.', ); } public function offer(mixed $element): bool { try { return $this->add($element); } catch (InvalidArgumentException) { return false; } } /** * @return T | null */ public function peek(): mixed { $index = array_key_first($this->data); if ($index === null) { return null; } return $this[$index]; } /** * @return T | null */ public function poll(): mixed { $index = array_key_first($this->data); if ($index === null) { return null; } $head = $this[$index]; unset($this[$index]); return $head; } /** * @return T * * @throws NoSuchElementException if this queue is empty. */ public function remove(): mixed { return $this->poll() ?? throw new NoSuchElementException( 'Can\'t return element from Queue. Queue is empty.', ); } public function getType(): string { return $this->queueType; } } collection/src/ArrayInterface.php 0000644 00000002045 15213403601 0013072 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use ArrayAccess; use Countable; use IteratorAggregate; /** * `ArrayInterface` provides traversable array functionality to data types. * * @template T * @extends ArrayAccess<array-key, T> * @extends IteratorAggregate<array-key, T> */ interface ArrayInterface extends ArrayAccess, Countable, IteratorAggregate { /** * Removes all items from this array. */ public function clear(): void; /** * Returns a native PHP array representation of this array object. * * @return array<array-key, T> */ public function toArray(): array; /** * Returns `true` if this array is empty. */ public function isEmpty(): bool; } collection/src/Exception/OutOfBoundsException.php 0000644 00000001152 15213403601 0016215 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use OutOfBoundsException as PhpOutOfBoundsException; /** * Thrown when attempting to access an element out of the range of the collection. */ class OutOfBoundsException extends PhpOutOfBoundsException implements CollectionException { } collection/src/Exception/CollectionException.php 0000644 00000000677 15213403601 0016114 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use Throwable; interface CollectionException extends Throwable { } collection/src/Exception/InvalidPropertyOrMethod.php 0000644 00000001233 15213403601 0016724 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use RuntimeException; /** * Thrown when attempting to evaluate a property, method, or array key * that doesn't exist on an element or cannot otherwise be evaluated in the * current context. */ class InvalidPropertyOrMethod extends RuntimeException implements CollectionException { } collection/src/Exception/CollectionMismatchException.php 0000644 00000001100 15213403601 0017560 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use RuntimeException; /** * Thrown when attempting to operate on collections of differing types. */ class CollectionMismatchException extends RuntimeException implements CollectionException { } collection/src/Exception/InvalidArgumentException.php 0000644 00000001146 15213403601 0017102 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use InvalidArgumentException as PhpInvalidArgumentException; /** * Thrown to indicate an argument is not of the expected type. */ class InvalidArgumentException extends PhpInvalidArgumentException implements CollectionException { } collection/src/Exception/UnsupportedOperationException.php 0000644 00000001077 15213403601 0020225 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use RuntimeException; /** * Thrown to indicate that the requested operation is not supported. */ class UnsupportedOperationException extends RuntimeException implements CollectionException { } collection/src/Exception/NoSuchElementException.php 0000644 00000001067 15213403601 0016524 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection\Exception; use RuntimeException; /** * Thrown when attempting to access an element that does not exist. */ class NoSuchElementException extends RuntimeException implements CollectionException { } collection/src/AbstractSet.php 0000644 00000002627 15213403601 0012420 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; /** * This class contains the basic implementation of a collection that does not * allow duplicated values (a set), to minimize the effort required to implement * this specific type of collection. * * @template T * @extends AbstractCollection<T> */ abstract class AbstractSet extends AbstractCollection { public function add(mixed $element): bool { if ($this->contains($element)) { return false; } // Call offsetSet() on the parent instead of add(), since calling // parent::add() will invoke $this->offsetSet(), which will call // $this->contains() a second time. This can cause performance issues // with extremely large collections. For more information, see // https://github.com/ramsey/collection/issues/68. parent::offsetSet(null, $element); return true; } public function offsetSet(mixed $offset, mixed $value): void { if ($this->contains($value)) { return; } parent::offsetSet($offset, $value); } } collection/src/DoubleEndedQueueInterface.php 0000644 00000024171 15213403601 0015177 0 ustar 00 <?php /** * This file is part of the ramsey/collection 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\Collection; use Ramsey\Collection\Exception\NoSuchElementException; use RuntimeException; /** * A linear collection that supports element insertion and removal at both ends. * * Most `DoubleEndedQueueInterface` implementations place no fixed limits on the * number of elements they may contain, but this interface supports * capacity-restricted double-ended queues as well as those with no fixed size * limit. * * This interface defines methods to access the elements at both ends of the * double-ended queue. Methods are provided to insert, remove, and examine the * element. Each of these methods exists in two forms: one throws an exception * if the operation fails, the other returns a special value (either `null` or * `false`, depending on the operation). The latter form of the insert operation * is designed specifically for use with capacity-restricted implementations; in * most implementations, insert operations cannot fail. * * The twelve methods described above are summarized in the following table: * * <table> * <caption>Summary of DoubleEndedQueueInterface methods</caption> * <thead> * <tr> * <th></th> * <th colspan=2>First Element (Head)</th> * <th colspan=2>Last Element (Tail)</th> * </tr> * <tr> * <td></td> * <td><em>Throws exception</em></td> * <td><em>Special value</em></td> * <td><em>Throws exception</em></td> * <td><em>Special value</em></td> * </tr> * </thead> * <tbody> * <tr> * <th>Insert</th> * <td><code>addFirst()</code></td> * <td><code>offerFirst()</code></td> * <td><code>addLast()</code></td> * <td><code>offerLast()</code></td> * </tr> * <tr> * <th>Remove</th> * <td><code>removeFirst()</code></td> * <td><code>pollFirst()</code></td> * <td><code>removeLast()</code></td> * <td><code>pollLast()</code></td> * </tr> * <tr> * <th>Examine</th> * <td><code>firstElement()</code></td> * <td><code>peekFirst()</code></td> * <td><code>lastElement()</code></td> * <td><code>peekLast()</code></td> * </tr> * </tbody> * </table> * * This interface extends the `QueueInterface`. When a double-ended queue is * used as a queue, FIFO (first-in-first-out) behavior results. Elements are * added at the end of the double-ended queue and removed from the beginning. * The methods inherited from the `QueueInterface` are precisely equivalent to * `DoubleEndedQueueInterface` methods as indicated in the following table: * * <table> * <caption>Comparison of QueueInterface and DoubleEndedQueueInterface methods</caption> * <thead> * <tr> * <th>QueueInterface Method</th> * <th>DoubleEndedQueueInterface Method</th> * </tr> * </thead> * <tbody> * <tr> * <td><code>add()</code></td> * <td><code>addLast()</code></td> * </tr> * <tr> * <td><code>offer()</code></td> * <td><code>offerLast()</code></td> * </tr> * <tr> * <td><code>remove()</code></td> * <td><code>removeFirst()</code></td> * </tr> * <tr> * <td><code>poll()</code></td> * <td><code>pollFirst()</code></td> * </tr> * <tr> * <td><code>element()</code></td> * <td><code>firstElement()</code></td> * </tr> * <tr> * <td><code>peek()</code></td> * <td><code>peekFirst()</code></td> * </tr> * </tbody> * </table> * * Double-ended queues can also be used as LIFO (last-in-first-out) stacks. When * a double-ended queue is used as a stack, elements are pushed and popped from * the beginning of the double-ended queue. Stack concepts are precisely * equivalent to `DoubleEndedQueueInterface` methods as indicated in the table * below: * * <table> * <caption>Comparison of stack concepts and DoubleEndedQueueInterface methods</caption> * <thead> * <tr> * <th>Stack concept</th> * <th>DoubleEndedQueueInterface Method</th> * </tr> * </thead> * <tbody> * <tr> * <td><em>push</em></td> * <td><code>addFirst()</code></td> * </tr> * <tr> * <td><em>pop</em></td> * <td><code>removeFirst()</code></td> * </tr> * <tr> * <td><em>peek</em></td> * <td><code>peekFirst()</code></td> * </tr> * </tbody> * </table> * * Note that the `peek()` method works equally well when a double-ended queue is * used as a queue or a stack; in either case, elements are drawn from the * beginning of the double-ended queue. * * While `DoubleEndedQueueInterface` implementations are not strictly required * to prohibit the insertion of `null` elements, they are strongly encouraged to * do so. Users of any `DoubleEndedQueueInterface` implementations that do allow * `null` elements are strongly encouraged *not* to take advantage of the * ability to insert nulls. This is so because `null` is used as a special * return value by various methods to indicated that the double-ended queue is * empty. * * @template T * @extends QueueInterface<T> */ interface DoubleEndedQueueInterface extends QueueInterface { /** * Inserts the specified element at the front of this queue if it is * possible to do so immediately without violating capacity restrictions. * * When using a capacity-restricted double-ended queue, it is generally * preferable to use the `offerFirst()` method. * * @param T $element The element to add to the front of this queue. * * @return bool `true` if this queue changed as a result of the call. * * @throws RuntimeException if a queue refuses to add a particular element * for any reason other than that it already contains the element. * Implementations should use a more-specific exception that extends * `\RuntimeException`. */ public function addFirst(mixed $element): bool; /** * Inserts the specified element at the end of this queue if it is possible * to do so immediately without violating capacity restrictions. * * When using a capacity-restricted double-ended queue, it is generally * preferable to use the `offerLast()` method. * * This method is equivalent to `add()`. * * @param T $element The element to add to the end of this queue. * * @return bool `true` if this queue changed as a result of the call. * * @throws RuntimeException if a queue refuses to add a particular element * for any reason other than that it already contains the element. * Implementations should use a more-specific exception that extends * `\RuntimeException`. */ public function addLast(mixed $element): bool; /** * Inserts the specified element at the front of this queue if it is * possible to do so immediately without violating capacity restrictions. * * When using a capacity-restricted queue, this method is generally * preferable to `addFirst()`, which can fail to insert an element only by * throwing an exception. * * @param T $element The element to add to the front of this queue. * * @return bool `true` if the element was added to this queue, else `false`. */ public function offerFirst(mixed $element): bool; /** * Inserts the specified element at the end of this queue if it is possible * to do so immediately without violating capacity restrictions. * * When using a capacity-restricted queue, this method is generally * preferable to `addLast()` which can fail to insert an element only by * throwing an exception. * * @param T $element The element to add to the end of this queue. * * @return bool `true` if the element was added to this queue, else `false`. */ public function offerLast(mixed $element): bool; /** * Retrieves and removes the head of this queue. * * This method differs from `pollFirst()` only in that it throws an * exception if this queue is empty. * * @return T the first element in this queue. * * @throws NoSuchElementException if this queue is empty. */ public function removeFirst(): mixed; /** * Retrieves and removes the tail of this queue. * * This method differs from `pollLast()` only in that it throws an exception * if this queue is empty. * * @return T the last element in this queue. * * @throws NoSuchElementException if this queue is empty. */ public function removeLast(): mixed; /** * Retrieves and removes the head of this queue, or returns `null` if this * queue is empty. * * @return T | null the head of this queue, or `null` if this queue is empty. */ public function pollFirst(): mixed; /** * Retrieves and removes the tail of this queue, or returns `null` if this * queue is empty. * * @return T | null the tail of this queue, or `null` if this queue is empty. */ public function pollLast(): mixed; /** * Retrieves, but does not remove, the head of this queue. * * This method differs from `peekFirst()` only in that it throws an * exception if this queue is empty. * * @return T the head of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function firstElement(): mixed; /** * Retrieves, but does not remove, the tail of this queue. * * This method differs from `peekLast()` only in that it throws an exception * if this queue is empty. * * @return T the tail of this queue. * * @throws NoSuchElementException if this queue is empty. */ public function lastElement(): mixed; /** * Retrieves, but does not remove, the head of this queue, or returns `null` * if this queue is empty. * * @return T | null the head of this queue, or `null` if this queue is empty. */ public function peekFirst(): mixed; /** * Retrieves, but does not remove, the tail of this queue, or returns `null` * if this queue is empty. * * @return T | null the tail of this queue, or `null` if this queue is empty. */ public function peekLast(): mixed; } uuid/README.md 0000644 00000007456 15213403601 0007000 0 ustar 00 <h1 align="center">ramsey/uuid</h1> <p align="center"> <strong>A PHP library for generating and working with UUIDs.</strong> </p> <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/4.x/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/actions/workflow/status/ramsey/uuid/continuous-integration.yml?branch=4.x&logo=github&style=flat-square" alt="Build Status"></a> <a href="https://app.codecov.io/gh/ramsey/uuid/branch/4.x"><img src="https://img.shields.io/codecov/c/github/ramsey/uuid/4.x?label=codecov&logo=codecov&style=flat-square" alt="Codecov Code Coverage"></a> </p> ramsey/uuid is a PHP library for generating and working with universally unique identifiers (UUIDs). 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 command to install the package and add it as a requirement to your project's `composer.json`: ```bash composer require ramsey/uuid ``` ## Upgrading to Version 4 See the documentation for a thorough upgrade guide: * [Upgrading ramsey/uuid Version 3 to 4](https://uuid.ramsey.dev/en/stable/upgrading/3-to-4.html) ## Documentation Please see <https://uuid.ramsey.dev> for documentation, tips, examples, and frequently asked questions. ## Contributing 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 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/4.x/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/ [contributing.md]: https://github.com/ramsey/uuid/blob/4.x/CONTRIBUTING.md [security.md]: https://github.com/ramsey/uuid/blob/4.x/SECURITY.md [license]: https://github.com/ramsey/uuid/blob/4.x/LICENSE uuid/LICENSE 0000644 00000002067 15213403601 0006517 0 ustar 00 Copyright (c) 2012-2025 Ben Ramsey <ben@benramsey.com> 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. uuid/composer.json 0000644 00000011224 15213403601 0010227 0 ustar 00 { "name": "ramsey/uuid", "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", "license": "MIT", "type": "library", "keywords": [ "uuid", "identifier", "guid" ], "require": { "php": "^8.0", "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "ramsey/collection": "^1.2 || ^2.0" }, "require-dev": { "captainhook/captainhook": "^5.25", "captainhook/plugin-composer": "^5.3", "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "ergebnis/composer-normalize": "^2.47", "mockery/mockery": "^1.6", "paragonie/random-lib": "^2", "php-mock/php-mock": "^2.6", "php-mock/php-mock-mockery": "^1.5", "php-parallel-lint/php-parallel-lint": "^1.4.0", "phpbench/phpbench": "^1.2.14", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.1", "phpstan/phpstan-mockery": "^2.0", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^9.6", "slevomat/coding-standard": "^8.18", "squizlabs/php_codesniffer": "^3.13" }, "replace": { "rhumsaa/uuid": "self.version" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", "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." }, "minimum-stability": "dev", "prefer-stable": true, "autoload": { "psr-4": { "Ramsey\\Uuid\\": "src/" }, "files": [ "src/functions.php" ] }, "autoload-dev": { "psr-4": { "Ramsey\\Uuid\\Benchmark\\": "tests/benchmark/", "Ramsey\\Uuid\\StaticAnalysis\\": "tests/static-analysis/", "Ramsey\\Uuid\\Test\\": "tests/" } }, "config": { "allow-plugins": { "captainhook/plugin-composer": true, "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, "phpstan/extension-installer": true }, "sort-packages": true }, "extra": { "captainhook": { "force-install": true } }, "scripts": { "dev:analyze": "@dev:analyze:phpstan", "dev:analyze:phpstan": "phpstan analyse --ansi --memory-limit 1G", "dev:bench": "@php -d 'error_reporting=24575' vendor/bin/phpbench run", "dev:build:clean": "git clean -fX build/", "dev:lint": [ "@dev:lint:syntax", "@dev:lint:style" ], "dev:lint:fix": "phpcbf --cache=build/cache/phpcs.cache", "dev:lint:style": "phpcs --cache=build/cache/phpcs.cache --colors", "dev:lint:syntax": "parallel-lint --colors src/ tests/", "dev:test": [ "@dev:lint", "@dev:bench", "@dev:analyze", "@dev:test:unit" ], "dev:test:coverage:ci": "@php -d 'xdebug.mode=coverage' vendor/bin/phpunit --colors=always --coverage-text --coverage-clover build/coverage/clover.xml --coverage-cobertura build/coverage/cobertura.xml --coverage-crap4j build/coverage/crap4j.xml --coverage-xml build/coverage/coverage-xml --log-junit build/junit.xml", "dev:test:coverage:html": "@php -d 'xdebug.mode=coverage' vendor/bin/phpunit --colors=always --coverage-html build/coverage/coverage-html/", "dev:test:unit": "phpunit --colors=always", "test": "@dev:test" }, "scripts-descriptions": { "dev:analyze": "Runs all static analysis checks.", "dev:analyze:phpstan": "Runs the PHPStan static analyzer.", "dev:bench": "Runs PHPBench benchmark tests.", "dev:build:clean": "Cleans the build/ directory.", "dev:lint": "Runs all linting checks.", "dev:lint:fix": "Auto-fixes coding standards issues, if possible.", "dev:lint:style": "Checks for coding standards issues.", "dev:lint:syntax": "Checks for syntax errors.", "dev:test": "Runs linting, static analysis, and unit tests.", "dev:test:coverage:ci": "Runs unit tests and generates CI coverage reports.", "dev:test:coverage:html": "Runs unit tests and generates HTML coverage report.", "dev:test:unit": "Runs unit tests.", "test": "Runs linting, static analysis, and unit tests." } } uuid/src/Codec/StringCodec.php 0000644 00000006175 15213403601 0012237 0 ustar 00 <?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\Codec; use Ramsey\Uuid\Builder\UuidBuilderInterface; use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; use function bin2hex; use function hex2bin; use function implode; use function sprintf; use function str_replace; use function strlen; use function substr; /** * StringCodec encodes and decodes RFC 9562 (formerly RFC 4122) UUIDs * * @immutable */ class StringCodec implements CodecInterface { /** * Constructs a StringCodec * * @param UuidBuilderInterface $builder The builder to use when encoding UUIDs */ public function __construct(private UuidBuilderInterface $builder) { } public function encode(UuidInterface $uuid): string { /** @phpstan-ignore possiblyImpure.methodCall */ $hex = bin2hex($uuid->getFields()->getBytes()); /** @var non-empty-string */ return sprintf( '%08s-%04s-%04s-%04s-%012s', substr($hex, 0, 8), substr($hex, 8, 4), substr($hex, 12, 4), substr($hex, 16, 4), substr($hex, 20), ); } /** * @return non-empty-string */ public function encodeBinary(UuidInterface $uuid): string { /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ return $uuid->getFields()->getBytes(); } /** * @throws InvalidUuidStringException * * @inheritDoc */ public function decode(string $encodedUuid): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return $this->builder->build($this, $this->getBytes($encodedUuid)); } public function decodeBytes(string $bytes): UuidInterface { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); } return $this->builder->build($this, $bytes); } /** * Returns the UUID builder */ protected function getBuilder(): UuidBuilderInterface { return $this->builder; } /** * Returns a byte string of the UUID */ protected function getBytes(string $encodedUuid): string { $parsedUuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}', '-'], '', $encodedUuid); $components = [ substr($parsedUuid, 0, 8), substr($parsedUuid, 8, 4), substr($parsedUuid, 12, 4), substr($parsedUuid, 16, 4), substr($parsedUuid, 20), ]; if (!Uuid::isValid(implode('-', $components))) { throw new InvalidUuidStringException('Invalid UUID string: ' . $encodedUuid); } return (string) hex2bin($parsedUuid); } } uuid/src/Codec/CodecInterface.php 0000644 00000003724 15213403601 0012666 0 ustar 00 <?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\Codec; use Ramsey\Uuid\UuidInterface; /** * A codec encodes and decodes a UUID according to defined rules * * @immutable */ interface CodecInterface { /** * Returns a hexadecimal string representation of a UuidInterface * * @param UuidInterface $uuid The UUID for which to create a hexadecimal string representation * * @return non-empty-string Hexadecimal string representation of a UUID * * @pure */ public function encode(UuidInterface $uuid): string; /** * Returns a binary string representation of a UuidInterface * * @param UuidInterface $uuid The UUID for which to create a binary string representation * * @return non-empty-string Binary string representation of a UUID * * @pure */ public function encodeBinary(UuidInterface $uuid): string; /** * Returns a UuidInterface derived from a hexadecimal string representation * * @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 * * @pure */ public function decode(string $encodedUuid): UuidInterface; /** * Returns a UuidInterface derived from a binary string representation * * @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 * * @pure */ public function decodeBytes(string $bytes): UuidInterface; } uuid/src/Codec/OrderedTimeCodec.php 0000644 00000007046 15213403601 0013172 0 ustar 00 <?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\Codec; 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 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 INSERT and * SELECT statements 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. * * @deprecated Please migrate to {@link https://uuid.ramsey.dev/en/stable/rfc4122/version6.html Version 6, reordered time-based UUIDs}. * * @link https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ Storing UUID Values in MySQL * * @immutable */ class OrderedTimeCodec extends StringCodec { /** * Returns a binary string representation of a UUID, with the timestamp fields rearranged for optimized storage * * @return non-empty-string */ public function encodeBinary(UuidInterface $uuid): string { if ( /** @phpstan-ignore possiblyImpure.methodCall */ !($uuid->getFields() instanceof Rfc4122FieldsInterface) /** @phpstan-ignore possiblyImpure.methodCall */ || $uuid->getFields()->getVersion() !== Uuid::UUID_TYPE_TIME ) { throw new InvalidArgumentException('Expected version 1 (time-based) UUID'); } /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $uuid->getFields()->getBytes(); return $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5] . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3] . substr($bytes, 8); } /** * 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); /** @phpstan-ignore possiblyImpure.methodCall */ $fields = $uuid->getFields(); if (!$fields instanceof Rfc4122FieldsInterface || $fields->getVersion() !== Uuid::UUID_TYPE_TIME) { throw new UnsupportedOperationException( 'Attempting to decode a non-time-based UUID using OrderedTimeCodec', ); } return $uuid; } } uuid/src/Codec/TimestampFirstCombCodec.php 0000644 00000006433 15213403601 0014542 0 ustar 00 <?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\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 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. * * ``` * $factory = new UuidFactory(); * * $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder())); * * $factory->setRandomGenerator(new CombGenerator( * $factory->getRandomGenerator(), * $factory->getNumberConverter(), * )); * * $timestampFirstComb = $factory->uuid4(); * ``` * * @deprecated Please migrate to {@link https://uuid.ramsey.dev/en/stable/rfc4122/version7.html Version 7, Unix Epoch Time UUIDs}. * * @link https://web.archive.org/web/20240118030355/https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys * * @immutable */ class TimestampFirstCombCodec extends StringCodec { /** * @return non-empty-string */ public function encode(UuidInterface $uuid): string { /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->swapBytes($uuid->getFields()->getBytes()); 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)) ); } /** * @return non-empty-string */ public function encodeBinary(UuidInterface $uuid): string { /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */ return $this->swapBytes($uuid->getFields()->getBytes()); } /** * @throws InvalidUuidStringException * * @inheritDoc */ public function decode(string $encodedUuid): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->getBytes($encodedUuid); /** @phpstan-ignore possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } public function decodeBytes(string $bytes): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } /** * Swaps bytes according to the timestamp-first COMB rules * * @pure */ private function swapBytes(string $bytes): string { $first48Bits = substr($bytes, 0, 6); $last48Bits = substr($bytes, -6); return substr_replace(substr_replace($bytes, $last48Bits, 0, 6), $first48Bits, -6); } } uuid/src/Codec/GuidStringCodec.php 0000644 00000004070 15213403601 0013040 0 ustar 00 <?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\Codec; use Ramsey\Uuid\Guid\Guid; use Ramsey\Uuid\UuidInterface; use function bin2hex; use function sprintf; use function substr; /** * GuidStringCodec encodes and decodes globally unique identifiers (GUID) * * @see Guid * * @immutable */ class GuidStringCodec extends StringCodec { public function encode(UuidInterface $uuid): string { /** @phpstan-ignore possiblyImpure.methodCall */ $hex = bin2hex($uuid->getFields()->getBytes()); /** @var non-empty-string */ return sprintf( '%02s%02s%02s%02s-%02s%02s-%02s%02s-%04s-%012s', substr($hex, 6, 2), substr($hex, 4, 2), substr($hex, 2, 2), substr($hex, 0, 2), substr($hex, 10, 2), substr($hex, 8, 2), substr($hex, 14, 2), substr($hex, 12, 2), substr($hex, 16, 4), substr($hex, 20), ); } public function decode(string $encodedUuid): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ $bytes = $this->getBytes($encodedUuid); /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ return $this->getBuilder()->build($this, $this->swapBytes($bytes)); } public function decodeBytes(string $bytes): UuidInterface { // Call parent::decode() to preserve the correct byte order. return parent::decode(bin2hex($bytes)); } /** * Swaps bytes according to the GUID rules */ private function swapBytes(string $bytes): string { return $bytes[3] . $bytes[2] . $bytes[1] . $bytes[0] . $bytes[5] . $bytes[4] . $bytes[7] . $bytes[6] . substr($bytes, 8); } } uuid/src/Codec/TimestampLastCombCodec.php 0000644 00000003017 15213403601 0014351 0 ustar 00 <?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\Codec; /** * 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. * * ``` * $factory = new UuidFactory(); * * $factory->setCodec(new TimestampLastCombCodec($factory->getUuidBuilder())); * * $factory->setRandomGenerator(new CombGenerator( * $factory->getRandomGenerator(), * $factory->getNumberConverter(), * )); * * $timestampLastComb = $factory->uuid4(); * ``` * * @deprecated Please use {@see StringCodec} instead. * * @immutable */ class TimestampLastCombCodec extends StringCodec { } uuid/src/UuidInterface.php 0000644 00000006144 15213403601 0011541 0 ustar 00 <?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 JsonSerializable; use Ramsey\Uuid\Fields\FieldsInterface; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; use Serializable; use Stringable; /** * A UUID is a universally unique identifier adhering to an agreed-upon representation format and standard for generation * * @immutable */ interface UuidInterface extends DeprecatedUuidInterface, JsonSerializable, Serializable, Stringable { /** * Returns -1, 0, or 1 if the UUID is less than, equal to, or greater than the other UUID * * The first of two UUIDs is greater than the second if the most significant field in which the UUIDs differ is * greater for the first UUID. * * @param UuidInterface $other The UUID to compare * * @return int<-1,1> -1, 0, or 1 if the UUID is less than, equal to, or greater than $other */ public function compareTo(UuidInterface $other): int; /** * Returns true if the UUID is equal to the provided object * * The result is true if and only if the argument is not null, is a UUID object, has the same variant, and contains * the same value, bit-for-bit, as the UUID. * * @param object | null $other An object to test for equality with this UUID * * @return bool True if the other object is equal to this UUID */ public function equals(?object $other): bool; /** * Returns the binary string representation of the UUID * * @return non-empty-string * * @pure */ public function getBytes(): string; /** * Returns the fields that comprise this UUID */ public function getFields(): FieldsInterface; /** * Returns the hexadecimal representation of the UUID */ public function getHex(): Hexadecimal; /** * Returns the integer representation of the UUID */ public function getInteger(): IntegerObject; /** * 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://www.rfc-editor.org/rfc/rfc9562.html#section-4 RFC 9562, 4. UUID Format * @link https://www.rfc-editor.org/rfc/rfc9562.html#section-7 RFC 9562, 7. IANA Considerations * @link https://www.rfc-editor.org/rfc/rfc4122.html#section-3 RFC 4122, 3. Namespace Registration Template */ public function getUrn(): string; /** * Returns the string standard representation of the UUID * * @return non-empty-string * * @pure */ public function toString(): string; /** * Casts the UUID to the string standard representation * * @return non-empty-string * * @pure */ public function __toString(): string; } uuid/src/DegradedUuid.php 0000644 00000001115 15213403601 0011331 0 ustar 00 <?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; /** * @deprecated DegradedUuid is no longer necessary to represent UUIDs on 32-bit systems. * Transition any type declarations using this class to {@see UuidInterface}. * * @immutable */ class DegradedUuid extends Uuid { } uuid/src/DeprecatedUuidInterface.php 0000644 00000011615 15213403601 0013521 0 ustar 00 <?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 * * @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 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; } uuid/src/UuidFactory.php 0000644 00000035746 15213403601 0011262 0 ustar 00 <?php /** * This file is part of the ramsey/uuid library * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com> * @license http://opensource.org/licenses/MIT MIT */ declare(strict_types=1); namespace Ramsey\Uuid; use DateTimeInterface; use Ramsey\Uuid\Builder\UuidBuilderInterface; use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\TimeConverterInterface; use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface; use Ramsey\Uuid\Generator\DefaultTimeGenerator; use Ramsey\Uuid\Generator\NameGeneratorInterface; use Ramsey\Uuid\Generator\RandomGeneratorInterface; use Ramsey\Uuid\Generator\TimeGeneratorInterface; use Ramsey\Uuid\Generator\UnixTimeGenerator; use Ramsey\Uuid\Lazy\LazyUuidFromString; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Provider\Time\FixedTimeProvider; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; use Ramsey\Uuid\Type\Time; use Ramsey\Uuid\Validator\ValidatorInterface; use function bin2hex; use function hex2bin; use function pack; use function str_pad; use function strtolower; use function substr; use function substr_replace; use function unpack; use const STR_PAD_LEFT; class UuidFactory implements UuidFactoryInterface { private CodecInterface $codec; private DceSecurityGeneratorInterface $dceSecurityGenerator; private NameGeneratorInterface $nameGenerator; private NodeProviderInterface $nodeProvider; private NumberConverterInterface $numberConverter; private RandomGeneratorInterface $randomGenerator; private TimeConverterInterface $timeConverter; private TimeGeneratorInterface $timeGenerator; private TimeGeneratorInterface $unixTimeGenerator; private UuidBuilderInterface $uuidBuilder; private ValidatorInterface $validator; /** * @var bool whether the feature set was provided from outside, or we can operate under "default" assumptions */ private bool $isDefaultFeatureSet; /** * @param FeatureSet | null $features A set of available features in the current environment */ public function __construct(?FeatureSet $features = null) { $this->isDefaultFeatureSet = $features === null; $features = $features ?: new FeatureSet(); $this->codec = $features->getCodec(); $this->dceSecurityGenerator = $features->getDceSecurityGenerator(); $this->nameGenerator = $features->getNameGenerator(); $this->nodeProvider = $features->getNodeProvider(); $this->numberConverter = $features->getNumberConverter(); $this->randomGenerator = $features->getRandomGenerator(); $this->timeConverter = $features->getTimeConverter(); $this->timeGenerator = $features->getTimeGenerator(); $this->uuidBuilder = $features->getBuilder(); $this->validator = $features->getValidator(); $this->unixTimeGenerator = $features->getUnixTimeGenerator(); } /** * Returns the codec used by this factory */ public function getCodec(): CodecInterface { return $this->codec; } /** * Sets the codec to use for this factory * * @param CodecInterface $codec A UUID encoder-decoder */ public function setCodec(CodecInterface $codec): void { $this->isDefaultFeatureSet = false; $this->codec = $codec; } /** * Returns the name generator used by this factory */ public function getNameGenerator(): NameGeneratorInterface { return $this->nameGenerator; } /** * Sets the name generator to use for this factory * * @param NameGeneratorInterface $nameGenerator A generator to generate binary data, based on a namespace and name */ public function setNameGenerator(NameGeneratorInterface $nameGenerator): void { $this->isDefaultFeatureSet = false; $this->nameGenerator = $nameGenerator; } /** * Returns the node provider used by this factory */ public function getNodeProvider(): NodeProviderInterface { return $this->nodeProvider; } /** * Returns the random generator used by this factory */ public function getRandomGenerator(): RandomGeneratorInterface { return $this->randomGenerator; } /** * Returns the time generator used by this factory */ public function getTimeGenerator(): TimeGeneratorInterface { return $this->timeGenerator; } /** * Sets the time generator to use for this factory * * @param TimeGeneratorInterface $generator A generator to generate binary data, based on the time */ public function setTimeGenerator(TimeGeneratorInterface $generator): void { $this->isDefaultFeatureSet = false; $this->timeGenerator = $generator; } /** * Returns the DCE Security generator used by this factory */ public function getDceSecurityGenerator(): DceSecurityGeneratorInterface { return $this->dceSecurityGenerator; } /** * Sets the DCE Security generator to use for this factory * * @param DceSecurityGeneratorInterface $generator A generator to generate binary data, based on a local domain and * local identifier */ public function setDceSecurityGenerator(DceSecurityGeneratorInterface $generator): void { $this->isDefaultFeatureSet = false; $this->dceSecurityGenerator = $generator; } /** * Returns the number converter used by this factory */ public function getNumberConverter(): NumberConverterInterface { return $this->numberConverter; } /** * Sets the random generator to use for this factory * * @param RandomGeneratorInterface $generator A generator to generate binary data, based on some random input */ public function setRandomGenerator(RandomGeneratorInterface $generator): void { $this->isDefaultFeatureSet = false; $this->randomGenerator = $generator; } /** * Sets the number converter to use for this factory * * @param NumberConverterInterface $converter A converter to use for working with large integers (i.e., integers * greater than PHP_INT_MAX) */ public function setNumberConverter(NumberConverterInterface $converter): void { $this->isDefaultFeatureSet = false; $this->numberConverter = $converter; } /** * Returns the UUID builder used by this factory */ public function getUuidBuilder(): UuidBuilderInterface { return $this->uuidBuilder; } /** * Sets the UUID builder to use for this factory * * @param UuidBuilderInterface $builder A builder for constructing instances of UuidInterface */ public function setUuidBuilder(UuidBuilderInterface $builder): void { $this->isDefaultFeatureSet = false; $this->uuidBuilder = $builder; } public function getValidator(): ValidatorInterface { return $this->validator; } /** * Sets the validator to use for this factory * * @param ValidatorInterface $validator A validator to use for validating whether a string is a valid UUID */ public function setValidator(ValidatorInterface $validator): void { $this->isDefaultFeatureSet = false; $this->validator = $validator; } /** * @pure */ public function fromBytes(string $bytes): UuidInterface { return $this->codec->decodeBytes($bytes); } /** * @pure */ public function fromString(string $uuid): UuidInterface { $uuid = strtolower($uuid); return $this->codec->decode($uuid); } /** * @pure */ public function fromInteger(string $integer): UuidInterface { $hex = $this->numberConverter->toHex($integer); $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); return $this->fromString($hex); } public function fromDateTime( DateTimeInterface $dateTime, ?Hexadecimal $node = null, ?int $clockSeq = null, ): UuidInterface { $timeProvider = new FixedTimeProvider(new Time($dateTime->format('U'), $dateTime->format('u'))); $timeGenerator = new DefaultTimeGenerator($this->nodeProvider, $this->timeConverter, $timeProvider); $bytes = $timeGenerator->generate($node?->toString(), $clockSeq); return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); } /** * @pure */ public function fromHexadecimal(Hexadecimal $hex): UuidInterface { return $this->codec->decode($hex->__toString()); } /** * @inheritDoc */ public function uuid1($node = null, ?int $clockSeq = null): UuidInterface { $bytes = $this->timeGenerator->generate($node, $clockSeq); return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); } public function uuid2( int $localDomain, ?IntegerObject $localIdentifier = null, ?Hexadecimal $node = null, ?int $clockSeq = null, ): UuidInterface { $bytes = $this->dceSecurityGenerator->generate($localDomain, $localIdentifier, $node, $clockSeq); return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_DCE_SECURITY); } /** * @inheritDoc * @pure */ public function uuid3($ns, string $name): UuidInterface { return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_MD5, 'md5'); } public function uuid4(): UuidInterface { $bytes = $this->randomGenerator->generate(16); return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_RANDOM); } /** * @inheritDoc * @pure */ public function uuid5($ns, string $name): UuidInterface { return $this->uuidFromNsAndName($ns, $name, Uuid::UUID_TYPE_HASH_SHA1, 'sha1'); } public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface { $bytes = $this->timeGenerator->generate($node?->toString(), $clockSeq); // Rearrange the bytes, according to the UUID version 6 specification. $v6 = $bytes[6] . $bytes[7] . $bytes[4] . $bytes[5] . $bytes[0] . $bytes[1] . $bytes[2] . $bytes[3]; $v6 = bin2hex($v6); // Drop the first four bits, while adding an empty four bits for the version field. This allows us to // reconstruct the correct time from the bytes of this UUID. $v6Bytes = hex2bin(substr($v6, 1, 12) . '0' . substr($v6, -3)); $v6Bytes .= substr($bytes, 8); return $this->uuidFromBytesAndVersion($v6Bytes, Uuid::UUID_TYPE_REORDERED_TIME); } /** * Returns a version 7 (Unix Epoch time) UUID * * @param DateTimeInterface | null $dateTime An optional date/time from which to create the version 7 UUID. If not * provided, the UUID is generated using the current date/time. * * @return UuidInterface A UuidInterface instance that represents a version 7 UUID */ public function uuid7(?DateTimeInterface $dateTime = null): UuidInterface { assert($this->unixTimeGenerator instanceof UnixTimeGenerator); $bytes = $this->unixTimeGenerator->generate(null, null, $dateTime); return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_UNIX_TIME); } /** * Returns a version 8 (custom format) UUID * * The bytes provided may contain any value according to your application's needs. Be aware, however, that other * applications may not understand the semantics of the value. * * @param string $bytes A 16-byte octet string. This is an open blob of data that you may fill with 128 bits of * information. Be aware, however, bits 48 through 51 will be replaced with the UUID version field, and bits 64 * and 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return UuidInterface A UuidInterface instance that represents a version 8 UUID * * @pure */ public function uuid8(string $bytes): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_CUSTOM); } /** * Returns a Uuid created from the provided byte string * * Uses the configured builder and codec and the provided byte string to construct a Uuid object. * * @param string $bytes The byte string from which to construct a UUID * * @return UuidInterface An instance of UuidInterface, created from the provided bytes * * @pure */ public function uuid(string $bytes): UuidInterface { return $this->uuidBuilder->build($this->codec, $bytes); } /** * Returns a version 3 or 5 namespaced Uuid * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * @param string $name The name to hash together with the namespace * @param int $version The version of UUID to create (3 or 5) * @param string $hashAlgorithm The hashing algorithm to use when hashing together the namespace and name * * @return UuidInterface An instance of UuidInterface, created by hashing together the provided namespace and name * * @pure */ private function uuidFromNsAndName( UuidInterface | string $ns, string $name, int $version, string $hashAlgorithm, ): UuidInterface { if (!($ns instanceof UuidInterface)) { $ns = $this->fromString($ns); } $bytes = $this->nameGenerator->generate($ns, $name, $hashAlgorithm); /** @phpstan-ignore possiblyImpure.methodCall */ return $this->uuidFromBytesAndVersion(substr($bytes, 0, 16), $version); } /** * Returns a Uuid created from the provided bytes and version * * @param string $bytes The byte string to convert to a UUID * @param int $version The version to apply to the UUID * * @return UuidInterface An instance of UuidInterface, created from the byte string and version */ private function uuidFromBytesAndVersion(string $bytes, int $version): UuidInterface { /** @var int[] $unpackedTime */ $unpackedTime = unpack('n*', substr($bytes, 6, 2)); $timeHi = $unpackedTime[1]; $timeHiAndVersion = pack('n*', BinaryUtils::applyVersion($timeHi, $version)); /** @var int[] $unpackedClockSeq */ $unpackedClockSeq = unpack('n*', substr($bytes, 8, 2)); $clockSeqHi = $unpackedClockSeq[1]; $clockSeqHiAndReserved = pack('n*', BinaryUtils::applyVariant($clockSeqHi)); $bytes = substr_replace($bytes, $timeHiAndVersion, 6, 2); $bytes = substr_replace($bytes, $clockSeqHiAndReserved, 8, 2); if ($this->isDefaultFeatureSet) { return LazyUuidFromString::fromBytes($bytes); } return $this->uuid($bytes); } } uuid/src/Nonstandard/UuidBuilder.php 0000644 00000004442 15213403601 0013501 0 ustar 00 <?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 * * @immutable */ class UuidBuilder implements UuidBuilderInterface { /** * @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( private NumberConverterInterface $numberConverter, private TimeConverterInterface $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 * * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { try { /** @phpstan-ignore possiblyImpure.new */ return new Uuid($this->buildFields($bytes), $this->numberConverter, $codec, $this->timeConverter); } catch (Throwable $e) { /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing * * @pure */ protected function buildFields(string $bytes): Fields { /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } uuid/src/Nonstandard/Uuid.php 0000644 00000001723 15213403601 0012171 0 ustar 00 <?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 9562 (formerly RFC 4122) * * @immutable * @pure */ final class Uuid extends BaseUuid { public function __construct( Fields $fields, NumberConverterInterface $numberConverter, CodecInterface $codec, TimeConverterInterface $timeConverter, ) { parent::__construct($fields, $numberConverter, $codec, $timeConverter); } } uuid/src/Nonstandard/Fields.php 0000644 00000006466 15213403601 0012502 0 ustar 00 <?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 9562 (formerly RFC 4122) standard * * Since some systems may create nonstandard UUIDs, this implements the {@see FieldsInterface}, so that functionality of * a nonstandard UUID is not degraded, in the event these UUIDs are expected to contain RFC 9562 (formerly RFC 4122) fields. * * Internally, this class represents the fields together as a 16-byte binary string. * * @immutable */ final class Fields implements FieldsInterface { use SerializableFieldsTrait; use VariantTrait; /** * @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(private string $bytes) { if (strlen($this->bytes) !== 16) { throw new InvalidArgumentException( 'The byte string must be 16 bytes long; received ' . strlen($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; } public function isMax(): bool { return false; } } uuid/src/Nonstandard/UuidV6.php 0000644 00000006615 15213403601 0012412 0 ustar 00 <?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\Exception\InvalidArgumentException; use Ramsey\Uuid\Lazy\LazyUuidFromString; use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; use Ramsey\Uuid\Rfc4122\TimeTrait; use Ramsey\Uuid\Rfc4122\UuidInterface; use Ramsey\Uuid\Rfc4122\UuidV1; use Ramsey\Uuid\Uuid as BaseUuid; /** * Reordered time, or version 6, UUIDs include timestamp, clock sequence, and node values that are combined into a * 128-bit unsigned integer * * @deprecated Use {@see \Ramsey\Uuid\Rfc4122\UuidV6} instead. * * @link https://github.com/uuid6/uuid6-ietf-draft UUID version 6 IETF draft * @link http://gh.peabody.io/uuidv6/ "Version 6" UUIDs * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.6 RFC 9562, 5.6. UUID Version 6 * * @immutable */ class UuidV6 extends BaseUuid implements UuidInterface { use TimeTrait; /** * Creates a version 6 (reordered Gregorian time) 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() !== BaseUuid::UUID_TYPE_REORDERED_TIME) { throw new InvalidArgumentException( 'Fields used to create a UuidV6 must represent a version 6 (reordered time) UUID', ); } parent::__construct($fields, $numberConverter, $codec, $timeConverter); } /** * 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 = BaseUuid::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): \Ramsey\Uuid\Rfc4122\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 = BaseUuid::fromBytes((string) hex2bin($hex)); return $uuid->toUuidV6(); } } uuid/src/functions.php 0000644 00000011162 15213403601 0011016 0 ustar 00 <?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 * phpcs:disable Squiz.Functions.GlobalFunction */ declare(strict_types=1); namespace Ramsey\Uuid; use DateTimeInterface; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; /** * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, and the 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 * * @return non-empty-string Version 1 UUID as a string */ function v1($node = null, ?int $clockSeq = null): string { return Uuid::uuid1($node, $clockSeq)->toString(); } /** * Returns a version 2 (DCE Security) UUID from a local domain, local identifier, host ID, clock sequence, and the 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 a 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 non-empty-string Version 2 UUID as a string */ function v2( int $localDomain, ?IntegerObject $localIdentifier = null, ?Hexadecimal $node = null, ?int $clockSeq = null, ): string { return Uuid::uuid2($localDomain, $localIdentifier, $node, $clockSeq)->toString(); } /** * Returns a version 3 (name-based) UUID based on the MD5 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * * @return non-empty-string Version 3 UUID as a string * * @pure */ function v3($ns, string $name): string { return Uuid::uuid3($ns, $name)->toString(); } /** * Returns a version 4 (random) UUID * * @return non-empty-string Version 4 UUID as a string */ function v4(): string { return Uuid::uuid4()->toString(); } /** * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * * @return non-empty-string Version 5 UUID as a string * * @pure */ function v5($ns, string $name): string { return Uuid::uuid5($ns, $name)->toString(); } /** * Returns a version 6 (reordered Gregorian time) UUID from a host ID, sequence number, and the current time * * @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 non-empty-string Version 6 UUID as a string */ function v6(?Hexadecimal $node = null, ?int $clockSeq = null): string { return Uuid::uuid6($node, $clockSeq)->toString(); } /** * Returns a version 7 (Unix Epoch time) UUID * * @param DateTimeInterface|null $dateTime An optional date/time from which to create the version 7 UUID. If not * provided, the UUID is generated using the current date/time. * * @return non-empty-string Version 7 UUID as a string */ function v7(?DateTimeInterface $dateTime = null): string { return Uuid::uuid7($dateTime)->toString(); } /** * Returns a version 8 (custom format) UUID * * The bytes provided may contain any value according to your application's needs. Be aware, however, that other * applications may not understand the semantics of the value. * * @param string $bytes A 16-byte octet string. This is an open blob of data that you may fill with 128 bits of * information. Be aware, however, bits 48 through 51 will be replaced with the UUID version field, and bits 64 and * 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return non-empty-string Version 8 UUID as a string * * @pure */ function v8(string $bytes): string { return Uuid::uuid8($bytes)->toString(); } uuid/src/Validator/GenericValidator.php 0000644 00000002415 15213403601 0014156 0 ustar 00 <?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\Validator; use Ramsey\Uuid\Uuid; use function preg_match; use function str_replace; /** * GenericValidator validates strings as UUIDs of any variant * * @immutable */ final class GenericValidator implements ValidatorInterface { /** * Regular expression pattern for matching a UUID of any variant. */ private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\z'; /** * @return non-empty-string */ public function getPattern(): string { return self::VALID_PATTERN; } public function validate(string $uuid): bool { /** @phpstan-ignore possiblyImpure.functionCall */ $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); /** @phpstan-ignore possiblyImpure.functionCall */ return $uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); } } uuid/src/Validator/ValidatorInterface.php 0000644 00000001733 15213403601 0014504 0 ustar 00 <?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\Validator; /** * A validator validates a string as a proper UUID * * @immutable */ interface ValidatorInterface { /** * Returns the regular expression pattern used by this validator * * @return non-empty-string The regular expression pattern this validator uses */ public function getPattern(): string; /** * Returns true if the provided string represents a UUID * * @param string $uuid The string to validate as a UUID * * @return bool True if the string is a valid UUID, false otherwise * * @pure */ public function validate(string $uuid): bool; } uuid/src/UuidFactoryInterface.php 0000644 00000013323 15213403601 0013066 0 ustar 00 <?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\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; use Ramsey\Uuid\Validator\ValidatorInterface; /** * UuidFactoryInterface defines the common functionality all `UuidFactory` instances must implement */ interface UuidFactoryInterface { /** * Creates a UUID from a byte string * * @param string $bytes A binary string * * @return UuidInterface A UuidInterface instance created from a binary string representation * * @pure */ public function fromBytes(string $bytes): UuidInterface; /** * Creates a UUID from a DateTimeInterface instance * * @param DateTimeInterface $dateTime The date and time * @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 UuidInterface A UuidInterface instance that represents a version 1 UUID created from a DateTimeInterface instance */ public function fromDateTime( DateTimeInterface $dateTime, ?Hexadecimal $node = null, ?int $clockSeq = null, ): UuidInterface; /** * Creates a UUID from a 128-bit integer string * * @param string $integer String representation of 128-bit integer * * @return UuidInterface A UuidInterface instance created from the string representation of a 128-bit integer * * @pure */ public function fromInteger(string $integer): UuidInterface; /** * Creates a UUID from the string standard representation * * @param string $uuid A hexadecimal string * * @return UuidInterface A UuidInterface instance created from a hexadecimal string representation * * @pure */ public function fromString(string $uuid): UuidInterface; /** * Returns the validator used by the factory */ public function getValidator(): ValidatorInterface; /** * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, and the 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 * * @return UuidInterface A UuidInterface instance that represents a version 1 UUID */ public function uuid1($node = null, ?int $clockSeq = null): UuidInterface; /** * Returns a version 2 (DCE Security) UUID from a local domain, local identifier, host ID, clock sequence, and the * 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 a 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 UuidInterface A UuidInterface instance that represents a version 2 UUID */ public function uuid2( int $localDomain, ?IntegerObject $localIdentifier = null, ?Hexadecimal $node = null, ?int $clockSeq = null, ): UuidInterface; /** * Returns a version 3 (name-based) UUID based on the MD5 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 3 UUID * * @pure */ public function uuid3($ns, string $name): UuidInterface; /** * Returns a version 4 (random) UUID * * @return UuidInterface A UuidInterface instance that represents a version 4 UUID */ public function uuid4(): UuidInterface; /** * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 5 UUID * * @pure */ public function uuid5($ns, string $name): UuidInterface; /** * Returns a version 6 (reordered Gregorian time) UUID from a host ID, sequence number, and the current time * * @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 UuidInterface A UuidInterface instance that represents a version 6 UUID */ public function uuid6(?Hexadecimal $node = null, ?int $clockSeq = null): UuidInterface; } uuid/src/Provider/Node/RandomNodeProvider.php 0000644 00000003071 15213403601 0015226 0 ustar 00 <?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\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 generates a random node ID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-6.10 RFC 9562, 6.10. UUIDs That Do Not Identify the Host */ class RandomNodeProvider implements NodeProviderInterface { public function getNode(): Hexadecimal { 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); $nodeLsb = substr($nodeBytes, 3); // Set the multicast bit; see RFC 9562, section 6.10. $nodeMsb = hex2bin(str_pad(dechex(hexdec(bin2hex($nodeMsb)) | 0x010000), 6, '0', STR_PAD_LEFT)); return new Hexadecimal(str_pad(bin2hex($nodeMsb . $nodeLsb), 12, '0', STR_PAD_LEFT)); } } uuid/src/Provider/Node/NodeProviderCollection.php 0000644 00000003560 15213403601 0016104 0 ustar 00 <?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 * * @deprecated this class has been deprecated and will be removed in 5.0.0. The use-case for this class comes from a * pre-`phpstan/phpstan` and pre-`vimeo/psalm` ecosystem, in which type safety had to be mostly enforced at runtime: * that is no longer necessary, now that you can safely verify your code to be correct and use more generic types * like `iterable<T>` instead. * * @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 */ public function unserialize($serialized): void { /** @var array<array-key, NodeProviderInterface> $data */ $data = unserialize($serialized, [ 'allowed_classes' => [ Hexadecimal::class, RandomNodeProvider::class, StaticNodeProvider::class, SystemNodeProvider::class, ], ]); /** @phpstan-ignore-next-line */ $this->data = array_filter($data, fn ($unserialized): bool => $unserialized instanceof NodeProviderInterface); } } uuid/src/Provider/Node/SystemNodeProvider.php 0000644 00000011227 15213403601 0015274 0 ustar 00 <?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\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_contains; use function str_replace; use function strtolower; use function strtoupper; use function substr; use const GLOB_NOSORT; use const PREG_PATTERN_ORDER; /** * 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 { /** * Pattern to match nodes in `ifconfig` and `ipconfig` output. */ 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 found */ protected function getNodeFromSystem(): string { /** @var string | null $node */ static $node = null; if ($node !== null) { return $node; } // First, try a Linux-specific approach. $node = $this->getSysfs(); if ($node === '') { // Search ifconfig output for MAC addresses & return the first one. $node = $this->getIfconfig(); } $node = str_replace([':', '-'], '', $node); return $node; } /** * Returns the network interface configuration for the system * * @codeCoverageIgnore */ protected function getIfconfig(): string { if (str_contains(strtolower((string) ini_get('disable_functions')), 'passthru')) { return ''; } /** @var string $phpOs */ $phpOs = constant('PHP_OS'); ob_start(); switch (strtoupper(substr($phpOs, 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; } $ifconfig = (string) ob_get_clean(); if (preg_match_all(self::IFCONFIG_PATTERN, $ifconfig, $matches, PREG_PATTERN_ORDER)) { foreach ($matches[1] as $iface) { if ($iface !== '00:00:00:00:00:00' && $iface !== '00-00-00-00-00-00') { return $iface; } } } return ''; } /** * Returns MAC address from the first system interface via the sysfs interface */ protected function getSysfs(): string { /** @var string $phpOs */ $phpOs = constant('PHP_OS'); if (strtoupper($phpOs) !== 'LINUX') { return ''; } $addressPaths = glob('/sys/class/net/*/address', GLOB_NOSORT); if ($addressPaths === false || count($addressPaths) === 0) { return ''; } /** @var array<array-key, string> $macs */ $macs = []; array_walk($addressPaths, function (string $addressPath) use (&$macs): void { if (is_readable($addressPath)) { $macs[] = file_get_contents($addressPath); } }); /** @var callable $trim */ $trim = 'trim'; $macs = array_map($trim, $macs); // Remove invalid entries. $macs = array_filter($macs, function (mixed $address): bool { assert(is_string($address)); return $address !== '00:00:00:00:00:00' && preg_match(self::SYSFS_PATTERN, $address); }); /** @var bool | string $mac */ $mac = reset($macs); return (string) $mac; } } uuid/src/Provider/Node/FallbackNodeProvider.php 0000644 00000002500 15213403601 0015501 0 ustar 00 <?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\NodeException; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Type\Hexadecimal; /** * FallbackNodeProvider retrieves the system node ID by stepping through a list of providers until a node ID can be obtained */ class FallbackNodeProvider implements NodeProviderInterface { /** * @param iterable<NodeProviderInterface> $providers Array of node providers */ public function __construct(private iterable $providers) { } public function getNode(): Hexadecimal { $lastProviderException = null; foreach ($this->providers as $provider) { try { return $provider->getNode(); } catch (NodeException $exception) { $lastProviderException = $exception; continue; } } throw new NodeException(message: 'Unable to find a suitable node provider', previous: $lastProviderException); } } uuid/src/Provider/Node/StaticNodeProvider.php 0000644 00000003377 15213403601 0015246 0 ustar 00 <?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 https://www.rfc-editor.org/rfc/rfc9562#section-6.10 RFC 9562, 6.10. UUIDs That Do Not Identify the Host */ class StaticNodeProvider implements NodeProviderInterface { private Hexadecimal $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)); } } uuid/src/Provider/Time/SystemTimeProvider.php 0000644 00000001366 15213403601 0015321 0 ustar 00 <?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\Time; use Ramsey\Uuid\Provider\TimeProviderInterface; use Ramsey\Uuid\Type\Time; use function gettimeofday; /** * SystemTimeProvider retrieves the current time using built-in PHP functions */ class SystemTimeProvider implements TimeProviderInterface { public function getTime(): Time { $time = gettimeofday(); return new Time($time['sec'], $time['usec']); } } uuid/src/Provider/Time/FixedTimeProvider.php 0000644 00000002574 15213403601 0015076 0 ustar 00 <?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\Time; use Ramsey\Uuid\Provider\TimeProviderInterface; use Ramsey\Uuid\Type\Integer as IntegerObject; use Ramsey\Uuid\Type\Time; /** * FixedTimeProvider uses a known time to provide the time * * This provider allows the use of a previously generated, or known, time when generating time-based UUIDs. */ class FixedTimeProvider implements TimeProviderInterface { public function __construct(private Time $time) { } /** * Sets the `usec` component of the time * * @param IntegerObject | int | string $value The `usec` value to set */ public function setUsec($value): void { $this->time = new Time($this->time->getSeconds(), $value); } /** * Sets the `sec` component of the time * * @param IntegerObject | int | string $value The `sec` value to set */ public function setSec($value): void { $this->time = new Time($value, $this->time->getMicroseconds()); } public function getTime(): Time { return $this->time; } } uuid/src/Provider/TimeProviderInterface.php 0000644 00000001066 15213403601 0015034 0 ustar 00 <?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\Type\Time; /** * A time provider retrieves the current time */ interface TimeProviderInterface { /** * Returns a time object */ public function getTime(): Time; } uuid/src/Provider/Dce/SystemDceSecurityProvider.php 0000644 00000014542 15213403601 0016443 0 ustar 00 <?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 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 { /** @var IntegerObject | int | float | string | null $uid */ 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 { /** @var IntegerObject | int | float | string | null $gid */ 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 ''; } return match ($this->getOs()) { 'WIN' => $this->getWindowsUid(), default => trim((string) shell_exec('id -u')), }; } /** * Returns the GID from the system */ private function getSystemGid(): string { if (!$this->hasShellExec()) { return ''; } return match ($this->getOs()) { 'WIN' => $this->getWindowsGid(), default => trim((string) shell_exec('id -g')), }; } /** * Returns true if shell_exec() is available for use */ private function hasShellExec(): bool { return !str_contains(strtolower((string) ini_get('disable_functions')), 'shell_exec'); } /** * Returns the PHP_OS string */ private function getOs(): string { /** @var string $phpOs */ $phpOs = constant('PHP_OS'); return strtoupper(substr($phpOs, 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://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/81d92bba-d22b-4a8c-908a-554ab29148ab Well-known SID Structures * @link https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers#well-known-sids Well-known SIDs * @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), escape: '\\')[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 ''; } $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 ''; } $userGroup = preg_split('/\s{2,}/', (string) $response, -1, PREG_SPLIT_NO_EMPTY); $sid = $userGroup[1] ?? ''; if (($lastHyphen = strrpos($sid, '-')) === false) { return ''; } return trim(substr($sid, $lastHyphen + 1)); } } uuid/src/Provider/DceSecurityProviderInterface.php 0000644 00000001746 15213403601 0016366 0 ustar 00 <?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; } uuid/src/Provider/NodeProviderInterface.php 0000644 00000001214 15213403601 0015016 0 ustar 00 <?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\Type\Hexadecimal; /** * A node provider retrieves or generates a node ID */ interface NodeProviderInterface { /** * Returns a node ID * * @return Hexadecimal The node ID as a hexadecimal string */ public function getNode(): Hexadecimal; } uuid/src/Builder/FallbackBuilder.php 0000644 00000003530 15213403601 0013402 0 ustar 00 <?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 * * @immutable */ class FallbackBuilder implements UuidBuilderInterface { /** * @param iterable<UuidBuilderInterface> $builders An array of UUID builders */ public function __construct(private iterable $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 * * @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, ); } } uuid/src/Builder/BuilderCollection.php 0000644 00000004727 15213403601 0014007 0 ustar 00 <?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 * * @deprecated this class has been deprecated and will be removed in 5.0.0. The use-case for this class comes from a * pre-`phpstan/phpstan` and pre-`vimeo/psalm` ecosystem, in which type safety had to be mostly enforced at runtime: * that is no longer necessary, now that you can safely verify your code to be correct, and use more generic types * like `iterable<T>` instead. * * @extends AbstractCollection<UuidBuilderInterface> */ class BuilderCollection extends AbstractCollection { public function getType(): string { return UuidBuilderInterface::class; } 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 */ 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 { /** @phpstan-ignore instanceof.alwaysTrue */ return $unserialized instanceof UuidBuilderInterface; }, ); } } uuid/src/Builder/UuidBuilderInterface.php 0000644 00000001770 15213403601 0014436 0 ustar 00 <?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\UuidInterface; /** * A UUID builder builds instances of UuidInterface * * @immutable */ interface UuidBuilderInterface { /** * Builds and returns a UuidInterface * * @param CodecInterface $codec The codec to use for building this UuidInterface instance * @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 * * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface; } uuid/src/Builder/DefaultUuidBuilder.php 0000644 00000001071 15213403601 0014114 0 ustar 00 <?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\Rfc4122\UuidBuilder as Rfc4122UuidBuilder; /** * @deprecated Please transition to {@see Rfc4122UuidBuilder}. * * @immutable */ class DefaultUuidBuilder extends Rfc4122UuidBuilder { } uuid/src/Builder/DegradedUuidBuilder.php 0000644 00000004005 15213403601 0014227 0 ustar 00 <?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\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; /** * @deprecated DegradedUuid instances are no longer necessary to support 32-bit systems. Please transition to {@see DefaultUuidBuilder}. * * @immutable */ class DegradedUuidBuilder implements UuidBuilderInterface { private TimeConverterInterface $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( private NumberConverterInterface $numberConverter, ?TimeConverterInterface $timeConverter = null ) { $this->timeConverter = $timeConverter ?: new DegradedTimeConverter(); } /** * Builds and returns a 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 * * @phpstan-impure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { return new DegradedUuid(new Rfc4122Fields($bytes), $this->numberConverter, $codec, $this->timeConverter); } } uuid/src/Uuid.php 0000644 00000057667 15213403601 0007740 0 ustar 00 <?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 BadMethodCallException; use DateTimeInterface; use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\TimeConverterInterface; use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Exception\UnsupportedOperationException; use Ramsey\Uuid\Fields\FieldsInterface; use Ramsey\Uuid\Lazy\LazyUuidFromString; use Ramsey\Uuid\Rfc4122\FieldsInterface as Rfc4122FieldsInterface; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Integer as IntegerObject; use ValueError; use function assert; use function bin2hex; use function method_exists; use function preg_match; use function sprintf; use function str_replace; use function strcmp; use function strlen; use function strtolower; use function substr; /** * Uuid provides constants and static methods for working with and generating UUIDs * * @immutable */ class Uuid implements UuidInterface { use DeprecatedUuidMethodsTrait; /** * When this namespace is specified, the name string is a fully qualified domain name * * @link https://www.rfc-editor.org/rfc/rfc9562#section-6.6 RFC 9562, 6.6. Namespace ID Usage and Allocation */ public const NAMESPACE_DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; /** * When this namespace is specified, the name string is a URL * * @link https://www.rfc-editor.org/rfc/rfc9562#section-6.6 RFC 9562, 6.6. Namespace ID Usage and Allocation */ public const NAMESPACE_URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; /** * When this namespace is specified, the name string is an ISO OID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-6.6 RFC 9562, 6.6. Namespace ID Usage and Allocation */ public const NAMESPACE_OID = '6ba7b812-9dad-11d1-80b4-00c04fd430c8'; /** * When this namespace is specified, the name string is an X.500 DN (in DER or a text output format) * * @link https://www.rfc-editor.org/rfc/rfc9562#section-6.6 RFC 9562, 6.6. Namespace ID Usage and Allocation */ public const NAMESPACE_X500 = '6ba7b814-9dad-11d1-80b4-00c04fd430c8'; /** * The Nil UUID is a special form of UUID that is specified to have all 128 bits set to zero * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.9 RFC 9562, 5.9. Nil UUID */ public const NIL = '00000000-0000-0000-0000-000000000000'; /** * The Max UUID is a special form of UUID that is specified to have all 128 bits set to one * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.10 RFC 9562, 5.10. Max UUID */ public const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff'; /** * Variant: reserved, NCS backward compatibility * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public const RESERVED_NCS = 0; /** * Variant: the UUID layout specified in RFC 9562 (formerly RFC 4122) * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field * @see Uuid::RFC_9562 */ public const RFC_4122 = 2; /** * Variant: the UUID layout specified in RFC 9562 (formerly RFC 4122) * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public const RFC_9562 = 2; /** * Variant: reserved, Microsoft Corporation backward compatibility * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public const RESERVED_MICROSOFT = 6; /** * Variant: reserved for future definition * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public const RESERVED_FUTURE = 7; /** * @deprecated Use {@see ValidatorInterface::getPattern()} instead. */ public const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'; /** * Version 1 (Gregorian time) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_TIME = 1; /** * Version 2 (DCE Security) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_DCE_SECURITY = 2; /** * @deprecated Use {@see Uuid::UUID_TYPE_DCE_SECURITY} instead. */ public const UUID_TYPE_IDENTIFIER = 2; /** * Version 3 (name-based and hashed with MD5) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_HASH_MD5 = 3; /** * Version 4 (random) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_RANDOM = 4; /** * Version 5 (name-based and hashed with SHA1) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_HASH_SHA1 = 5; /** * @deprecated Use {@see Uuid::UUID_TYPE_REORDERED_TIME} instead. */ public const UUID_TYPE_PEABODY = 6; /** * Version 6 (reordered Gregorian time) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_REORDERED_TIME = 6; /** * Version 7 (Unix Epoch time) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_UNIX_TIME = 7; /** * Version 8 (custom format) UUID * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field */ public const UUID_TYPE_CUSTOM = 8; /** * DCE Security principal domain * * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1 */ public const DCE_DOMAIN_PERSON = 0; /** * DCE Security group domain * * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1 */ public const DCE_DOMAIN_GROUP = 1; /** * DCE Security organization domain * * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1 */ public const DCE_DOMAIN_ORG = 2; /** * DCE Security domain string names * * @link https://pubs.opengroup.org/onlinepubs/9696989899/chap11.htm#tagcjh_14_05_01_01 DCE 1.1, §11.5.1.1 */ public const DCE_DOMAIN_NAMES = [ self::DCE_DOMAIN_PERSON => 'person', self::DCE_DOMAIN_GROUP => 'group', self::DCE_DOMAIN_ORG => 'org', ]; /** * @phpstan-ignore property.readOnlyByPhpDocDefaultValue */ private static ?UuidFactoryInterface $factory = null; /** * @var bool flag to detect if the UUID factory was replaced internally, which disables all optimizations for the * default/happy path internal scenarios * @phpstan-ignore property.readOnlyByPhpDocDefaultValue */ private static bool $factoryReplaced = false; protected CodecInterface $codec; protected NumberConverterInterface $numberConverter; protected Rfc4122FieldsInterface $fields; protected TimeConverterInterface $timeConverter; /** * Creates a universally unique identifier (UUID) from an array of fields * * Unless you're making advanced use of this library to generate identifiers that deviate from RFC 9562 (formerly * RFC 4122), you probably do not want to instantiate a UUID directly. Use the static methods, instead: * * ``` * use Ramsey\Uuid\Uuid; * * $timeBasedUuid = Uuid::uuid1(); * $namespaceMd5Uuid = Uuid::uuid3(Uuid::NAMESPACE_URL, 'http://php.net/'); * $randomUuid = Uuid::uuid4(); * $namespaceSha1Uuid = Uuid::uuid5(Uuid::NAMESPACE_URL, 'http://php.net/'); * ``` * * @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, ) { $this->fields = $fields; $this->codec = $codec; $this->numberConverter = $numberConverter; $this->timeConverter = $timeConverter; } /** * @return non-empty-string */ public function __toString(): string { return $this->toString(); } /** * Converts the UUID to a string for JSON serialization */ public function jsonSerialize(): string { return $this->toString(); } /** * Converts the UUID to a string for PHP serialization */ public function serialize(): string { return $this->codec->encode($this); } /** * @return array{bytes: string} */ public function __serialize(): array { return ['bytes' => $this->serialize()]; } /** * Re-constructs the object from its serialized form * * @param string $data The serialized PHP string to unserialize into a UuidInterface instance */ public function unserialize(string $data): void { if (strlen($data) === 16) { /** @var Uuid $uuid */ $uuid = self::getFactory()->fromBytes($data); } else { /** @var Uuid $uuid */ $uuid = self::getFactory()->fromString($data); } /** @phpstan-ignore property.readOnlyByPhpDocAssignNotInConstructor */ $this->codec = $uuid->codec; /** @phpstan-ignore property.readOnlyByPhpDocAssignNotInConstructor */ $this->numberConverter = $uuid->numberConverter; /** @phpstan-ignore property.readOnlyByPhpDocAssignNotInConstructor */ $this->fields = $uuid->fields; /** @phpstan-ignore property.readOnlyByPhpDocAssignNotInConstructor */ $this->timeConverter = $uuid->timeConverter; } /** * @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']); } public function compareTo(UuidInterface $other): int { $compare = strcmp($this->toString(), $other->toString()); if ($compare < 0) { return -1; } if ($compare > 0) { return 1; } return 0; } public function equals(?object $other): bool { if (!$other instanceof UuidInterface) { return false; } return $this->compareTo($other) === 0; } /** * @return non-empty-string */ public function getBytes(): string { return $this->codec->encodeBinary($this); } public function getFields(): FieldsInterface { return $this->fields; } public function getHex(): Hexadecimal { return new Hexadecimal(str_replace('-', '', $this->toString())); } public function getInteger(): IntegerObject { return new IntegerObject($this->numberConverter->fromHex($this->getHex()->toString())); } public function getUrn(): string { return 'urn:uuid:' . $this->toString(); } /** * @return non-empty-string */ public function toString(): string { return $this->codec->encode($this); } /** * Returns the factory used to create UUIDs */ public static function getFactory(): UuidFactoryInterface { if (self::$factory === null) { self::$factory = new UuidFactory(); } return self::$factory; } /** * Sets the factory used to create UUIDs * * @param UuidFactoryInterface $factory A factory that will be used by this class to create UUIDs */ public static function setFactory(UuidFactoryInterface $factory): void { // Note: non-strict equality is intentional here. If the factory is configured differently, every assumption // around purity is broken, and we have to internally decide everything differently. // phpcs:ignore SlevomatCodingStandard.Operators.DisallowEqualOperators.DisallowedNotEqualOperator self::$factoryReplaced = ($factory != new UuidFactory()); self::$factory = $factory; } /** * Creates a UUID from a byte string * * @param string $bytes A binary string * * @return UuidInterface A UuidInterface instance created from a binary string representation * * @throws InvalidArgumentException * * @pure */ public static function fromBytes(string $bytes): UuidInterface { /** @phpstan-ignore impure.staticPropertyAccess */ if (!self::$factoryReplaced && strlen($bytes) === 16) { $base16Uuid = bin2hex($bytes); // Note: we are calling `fromString` internally because we don't know if the given `$bytes` is a valid UUID return self::fromString( substr($base16Uuid, 0, 8) . '-' . substr($base16Uuid, 8, 4) . '-' . substr($base16Uuid, 12, 4) . '-' . substr($base16Uuid, 16, 4) . '-' . substr($base16Uuid, 20, 12), ); } /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromBytes($bytes); } /** * Creates a UUID from the string standard representation * * @param string $uuid A hexadecimal string * * @return UuidInterface A UuidInterface instance created from a hexadecimal string representation * * @throws InvalidArgumentException * * @pure */ public static function fromString(string $uuid): UuidInterface { $uuid = strtolower($uuid); /** @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.functionCall */ if (!self::$factoryReplaced && preg_match(LazyUuidFromString::VALID_REGEX, $uuid) === 1) { /** @phpstan-ignore possiblyImpure.functionCall */ assert($uuid !== ''); /** @phpstan-ignore possiblyImpure.new */ return new LazyUuidFromString($uuid); } /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromString($uuid); } /** * Creates a UUID from a DateTimeInterface instance * * @param DateTimeInterface $dateTime The date and time * @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 UuidInterface A UuidInterface instance that represents a version 1 UUID created from a DateTimeInterface instance */ public static function fromDateTime( DateTimeInterface $dateTime, ?Hexadecimal $node = null, ?int $clockSeq = null ): UuidInterface { return self::getFactory()->fromDateTime($dateTime, $node, $clockSeq); } /** * Creates a UUID from the Hexadecimal object * * @param Hexadecimal $hex Hexadecimal object representing a hexadecimal number * * @return UuidInterface A UuidInterface instance created from the Hexadecimal object representing a hexadecimal number * * @throws InvalidArgumentException * * @pure */ public static function fromHexadecimal(Hexadecimal $hex): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ $factory = self::getFactory(); if (method_exists($factory, 'fromHexadecimal')) { /** @phpstan-ignore possiblyImpure.methodCall */ $uuid = $factory->fromHexadecimal($hex); /** @phpstan-ignore possiblyImpure.functionCall */ assert($uuid instanceof UuidInterface); return $uuid; } throw new BadMethodCallException('The method fromHexadecimal() does not exist on the provided factory'); } /** * Creates a UUID from a 128-bit integer string * * @param string $integer String representation of 128-bit integer * * @return UuidInterface A UuidInterface instance created from the string representation of a 128-bit integer * * @throws InvalidArgumentException * * @pure */ public static function fromInteger(string $integer): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->fromInteger($integer); } /** * Returns true if the provided string is a valid UUID * * @param string $uuid A string to validate as a UUID * * @return bool True if the string is a valid UUID, false otherwise * * @phpstan-assert-if-true =non-empty-string $uuid * * @pure */ public static function isValid(string $uuid): bool { /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ return self::getFactory()->getValidator()->validate($uuid); } /** * Returns a version 1 (Gregorian time) UUID from a host ID, sequence number, and the 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 * * @return UuidInterface A UuidInterface instance that represents a version 1 UUID */ public static function uuid1($node = null, ?int $clockSeq = null): UuidInterface { return self::getFactory()->uuid1($node, $clockSeq); } /** * Returns a version 2 (DCE Security) UUID from a local domain, local identifier, host ID, clock sequence, and the 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 (in a version 2 UUID, the lower 8 bits of this number are * replaced with the domain). * * @return UuidInterface A UuidInterface instance that represents a version 2 UUID */ public static function uuid2( int $localDomain, ?IntegerObject $localIdentifier = null, ?Hexadecimal $node = null, ?int $clockSeq = null ): UuidInterface { return self::getFactory()->uuid2($localDomain, $localIdentifier, $node, $clockSeq); } /** * Returns a version 3 (name-based) UUID based on the MD5 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 3 UUID * * @pure */ public static function uuid3($ns, string $name): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->uuid3($ns, $name); } /** * Returns a version 4 (random) UUID * * @return UuidInterface A UuidInterface instance that represents a version 4 UUID */ public static function uuid4(): UuidInterface { return self::getFactory()->uuid4(); } /** * Returns a version 5 (name-based) UUID based on the SHA-1 hash of a namespace ID and a name * * @param UuidInterface | string $ns The namespace (must be a valid UUID) * @param string $name The name to use for creating a UUID * * @return UuidInterface A UuidInterface instance that represents a version 5 UUID * * @pure */ public static function uuid5($ns, string $name): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ return self::getFactory()->uuid5($ns, $name); } /** * Returns a version 6 (reordered Gregorian time) UUID from a host ID, sequence number, and the current time * * @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 UuidInterface A UuidInterface instance that represents a version 6 UUID */ public static function uuid6( ?Hexadecimal $node = null, ?int $clockSeq = null ): UuidInterface { return self::getFactory()->uuid6($node, $clockSeq); } /** * Returns a version 7 (Unix Epoch time) UUID * * @param DateTimeInterface | null $dateTime An optional date/time from which to create the version 7 UUID. If not * provided, the UUID is generated using the current date/time. * * @return UuidInterface A UuidInterface instance that represents a version 7 UUID */ public static function uuid7(?DateTimeInterface $dateTime = null): UuidInterface { $factory = self::getFactory(); if (method_exists($factory, 'uuid7')) { /** @var UuidInterface */ return $factory->uuid7($dateTime); } throw new UnsupportedOperationException('The provided factory does not support the uuid7() method'); } /** * Returns a version 8 (custom format) UUID * * The bytes provided may contain any value according to your application's needs. Be aware, however, that other * applications may not understand the semantics of the value. * * @param string $bytes A 16-byte octet string. This is an open blob of data that you may fill with 128 bits of * information. Be aware, however, bits 48 through 51 will be replaced with the UUID version field, and bits 64 * and 65 will be replaced with the UUID variant. You MUST NOT rely on these bits for your application needs. * * @return UuidInterface A UuidInterface instance that represents a version 8 UUID * * @pure */ public static function uuid8(string $bytes): UuidInterface { /** @phpstan-ignore possiblyImpure.methodCall */ $factory = self::getFactory(); if (method_exists($factory, 'uuid8')) { /** * @var UuidInterface * @phpstan-ignore possiblyImpure.methodCall */ return $factory->uuid8($bytes); } throw new UnsupportedOperationException('The provided factory does not support the uuid8() method'); } } uuid/src/Converter/Time/UnixTimeConverter.php 0000644 00000005371 15213403601 0015312 0 ustar 00 <?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; /** * UnixTimeConverter converts Unix Epoch timestamps to/from hexadecimal values consisting of milliseconds elapsed since * the Unix Epoch * * @immutable */ class UnixTimeConverter implements TimeConverterInterface { private const MILLISECONDS = 1000; public function __construct(private CalculatorInterface $calculator) { } public function calculateTime(string $seconds, string $microseconds): Hexadecimal { /** @phpstan-ignore possiblyImpure.new */ $timestamp = new Time($seconds, $microseconds); // Convert the seconds into milliseconds. $sec = $this->calculator->multiply( $timestamp->getSeconds(), new IntegerObject(self::MILLISECONDS) /** @phpstan-ignore possiblyImpure.new */ ); // Convert the microseconds into milliseconds; the scale is zero because we need to discard the fractional part. $usec = $this->calculator->divide( RoundingMode::DOWN, // Always round down to stay in the previous millisecond. 0, $timestamp->getMicroseconds(), new IntegerObject(self::MILLISECONDS), /** @phpstan-ignore possiblyImpure.new */ ); /** @var IntegerObject $unixTime */ $unixTime = $this->calculator->add($sec, $usec); /** @phpstan-ignore possiblyImpure.new */ return new Hexadecimal( str_pad( $this->calculator->toHexadecimal($unixTime)->toString(), 12, '0', STR_PAD_LEFT ), ); } public function convertTime(Hexadecimal $uuidTimestamp): Time { $milliseconds = $this->calculator->toInteger($uuidTimestamp); $unixTimestamp = $this->calculator->divide( RoundingMode::HALF_UP, 6, $milliseconds, new IntegerObject(self::MILLISECONDS), /** @phpstan-ignore possiblyImpure.new */ ); $split = explode('.', (string) $unixTimestamp, 2); /** @phpstan-ignore possiblyImpure.new */ return new Time($split[0], $split[1] ?? '0'); } } uuid/src/Converter/Time/GenericTimeConverter.php 0000644 00000007674 15213403601 0015753 0 ustar 00 <?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 * * @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'; public function __construct(private CalculatorInterface $calculator) { } public function calculateTime(string $seconds, string $microseconds): Hexadecimal { /** @phpstan-ignore possiblyImpure.new */ $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), /** @phpstan-ignore possiblyImpure.new */ ); // Convert the microseconds into a count of 100-nanosecond intervals. $usec = $this->calculator->multiply( $timestamp->getMicroseconds(), new IntegerObject(self::MICROSECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); /** * Combine the intervals of seconds and microseconds 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 * @phpstan-ignore possiblyImpure.new */ $uuidTime = $this->calculator->add($sec, $usec, new IntegerObject(self::GREGORIAN_TO_UNIX_INTERVALS)); /** * PHPStan considers CalculatorInterface::toHexadecimal, Hexadecimal:toString impure. * * @phpstan-ignore possiblyImpure.new */ return new Hexadecimal(str_pad($this->calculator->toHexadecimal($uuidTime)->toString(), 16, '0', STR_PAD_LEFT)); } 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), /** @phpstan-ignore possiblyImpure.new */ ); // Convert the 100-nanosecond intervals into seconds and microseconds. $unixTimestamp = $this->calculator->divide( RoundingMode::HALF_UP, 6, $epochNanoseconds, new IntegerObject(self::SECOND_INTERVALS), /** @phpstan-ignore possiblyImpure.new */ ); $split = explode('.', (string) $unixTimestamp, 2); /** @phpstan-ignore possiblyImpure.new */ return new Time($split[0], $split[1] ?? 0); } } uuid/src/Converter/Time/BigNumberTimeConverter.php 0000644 00000002455 15213403601 0016241 0 ustar 00 <?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\BrickMathCalculator; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Time; /** * Previously used to integrate moontoast/math as a bignum arithmetic library, BigNumberTimeConverter is deprecated in * favor of GenericTimeConverter * * @deprecated Please transition to {@see GenericTimeConverter}. * * @immutable */ class BigNumberTimeConverter implements TimeConverterInterface { private TimeConverterInterface $converter; public function __construct() { $this->converter = new GenericTimeConverter(new BrickMathCalculator()); } public function calculateTime(string $seconds, string $microseconds): Hexadecimal { return $this->converter->calculateTime($seconds, $microseconds); } public function convertTime(Hexadecimal $uuidTimestamp): Time { return $this->converter->convertTime($uuidTimestamp); } } uuid/src/Converter/Time/PhpTimeConverter.php 0000644 00000013230 15213403601 0015107 0 ustar 00 <?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\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 * * @immutable */ class PhpTimeConverter implements TimeConverterInterface { /** * The number of 100-nanosecond intervals from the Gregorian calendar epoch to the Unix epoch. */ private const GREGORIAN_TO_UNIX_INTERVALS = 0x01b21dd213814000; /** * The number of 100-nanosecond intervals in one second. */ private const SECOND_INTERVALS = 10_000_000; /** * The number of 100-nanosecond intervals in one microsecond. */ private const MICROSECOND_INTERVALS = 10; private int $phpPrecision; private CalculatorInterface $calculator; private TimeConverterInterface $fallbackConverter; 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 { $seconds = new IntegerObject($seconds); /** @phpstan-ignore possiblyImpure.new */ $microseconds = new IntegerObject($microseconds); /** @phpstan-ignore possiblyImpure.new */ // 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. // @phpstan-ignore function.alreadyNarrowedType (the integer value might have overflowed) if (!is_int($uuidTime)) { return $this->fallbackConverter->calculateTime( $seconds->toString(), $microseconds->toString(), ); } /** @phpstan-ignore possiblyImpure.new */ 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( ($timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS) / self::SECOND_INTERVALS, ); if (count($splitTime) === 0) { return $this->fallbackConverter->convertTime($uuidTimestamp); } /** @phpstan-ignore possiblyImpure.new */ return new Time($splitTime['sec'], $splitTime['usec']); } /** * @param float | int $time The time to split into seconds and microseconds * * @return string[] * * @pure */ private function splitTime(float | int $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 [ 'sec' => $split[0], 'usec' => str_pad((string) $microseconds, 6, '0', STR_PAD_RIGHT), ]; } } uuid/src/Converter/Time/DegradedTimeConverter.php 0000644 00000001150 15213403601 0016055 0 ustar 00 <?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; /** * @deprecated DegradedTimeConverter is no longer necessary for converting time on 32-bit systems. Please transition to * {@see GenericTimeConverter}. * * @immutable */ class DegradedTimeConverter extends BigNumberTimeConverter { } uuid/src/Converter/NumberConverterInterface.php 0000644 00000002712 15213403601 0015717 0 ustar 00 <?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; /** * A number converter converts UUIDs from hexadecimal characters into representations of integers and vice versa * * @immutable */ interface NumberConverterInterface { /** * Converts a hexadecimal number into a string integer representation of the number * * The integer representation returned is a string representation of the integer to accommodate unsigned integers * that are greater than `PHP_INT_MAX`. * * @param string $hex The hexadecimal string representation to convert * * @return numeric-string String representation of an integer * * @pure */ public function fromHex(string $hex): string; /** * 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 that are greater than `PHP_INT_MAX`. * * @return non-empty-string Hexadecimal string * * @pure */ public function toHex(string $number): string; } uuid/src/Converter/Number/GenericNumberConverter.php 0000644 00000002252 15213403601 0016622 0 ustar 00 <?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 * * @immutable */ class GenericNumberConverter implements NumberConverterInterface { public function __construct(private CalculatorInterface $calculator) { } /** * @pure */ public function fromHex(string $hex): string { return $this->calculator->fromBase($hex, 16)->toString(); } /** * @pure */ public function toHex(string $number): string { /** @phpstan-ignore return.type, possiblyImpure.new */ return $this->calculator->toBase(new IntegerObject($number), 16); } } uuid/src/Converter/Number/DegradedNumberConverter.php 0000644 00000001157 15213403601 0016750 0 ustar 00 <?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; /** * @deprecated DegradedNumberConverter is no longer necessary for converting numbers on 32-bit systems. Please * transition to {@see GenericNumberConverter}. * * @immutable */ class DegradedNumberConverter extends BigNumberConverter { } uuid/src/Converter/Number/BigNumberConverter.php 0000644 00000002325 15213403601 0015750 0 ustar 00 <?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\BrickMathCalculator; /** * Previously used to integrate moontoast/math as a bignum arithmetic library, BigNumberConverter is deprecated in favor * of GenericNumberConverter * * @deprecated Please transition to {@see GenericNumberConverter}. * * @immutable */ class BigNumberConverter implements NumberConverterInterface { private NumberConverterInterface $converter; public function __construct() { $this->converter = new GenericNumberConverter(new BrickMathCalculator()); } /** * @pure */ public function fromHex(string $hex): string { return $this->converter->fromHex($hex); } /** * @pure */ public function toHex(string $number): string { return $this->converter->toHex($number); } } uuid/src/Converter/TimeConverterInterface.php 0000644 00000003331 15213403601 0015363 0 ustar 00 <?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; use Ramsey\Uuid\Type\Hexadecimal; use Ramsey\Uuid\Type\Time; /** * A time converter converts timestamps into representations that may be used in UUIDs * * @immutable */ interface TimeConverterInterface { /** * 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 9562 (formerly RFC 4122) variant UUIDs * * @link https://www.rfc-editor.org/rfc/rfc9562#appendix-A RFC 9562, Appendix A. Test Vectors * * @param string $seconds A string representation 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 * * @pure */ 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} * * @pure */ public function convertTime(Hexadecimal $uuidTimestamp): Time; } uuid/src/Fields/SerializableFieldsTrait.php 0000644 00000003557 15213403601 0014766 0 ustar 00 <?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 * * @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 the 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 $data The serialized string representation of the object */ public function unserialize(string $data): void { if (strlen($data) === 16) { $this->__construct($data); } else { $this->__construct(base64_decode($data)); } } /** * @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']); } } uuid/src/Fields/FieldsInterface.php 0000644 00000001361 15213403601 0013243 0 ustar 00 <?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 consist of unsigned integers, the bytes of which are separated into fields and arranged in a particular layout * defined by the specification for the variant * * @immutable */ interface FieldsInterface extends Serializable { /** * Returns the bytes that comprise the fields * * @pure */ public function getBytes(): string; } uuid/src/Lazy/LazyUuidFromString.php 0000644 00000032634 15213403601 0013515 0 ustar 00 <?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\Rfc4122\UuidV1; use Ramsey\Uuid\Rfc4122\UuidV6; 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. * * > [!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. * * @internal this type is used internally for performance reasons and is not supposed to be directly referenced in consumer libraries. */ 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'; private ?UuidInterface $unwrapped = null; /** * @param non-empty-string $uuid */ public function __construct(private string $uuid) { } 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: non-empty-string} */ public function __serialize(): array { return ['string' => $this->uuid]; } /** * {@inheritDoc} * * @param non-empty-string $data */ public function unserialize(string $data): void { $this->uuid = $data; } /** * @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']); } public function getNumberConverter(): NumberConverterInterface { return ($this->unwrapped ?? $this->unwrap())->getNumberConverter(); } /** * @inheritDoc */ public function getFieldsHex(): array { return ($this->unwrapped ?? $this->unwrap())->getFieldsHex(); } public function getClockSeqHiAndReservedHex(): string { return ($this->unwrapped ?? $this->unwrap())->getClockSeqHiAndReservedHex(); } public function getClockSeqLowHex(): string { return ($this->unwrapped ?? $this->unwrap())->getClockSeqLowHex(); } public function getClockSequenceHex(): string { return ($this->unwrapped ?? $this->unwrap())->getClockSequenceHex(); } public function getDateTime(): DateTimeInterface { return ($this->unwrapped ?? $this->unwrap())->getDateTime(); } public function getLeastSignificantBitsHex(): string { return ($this->unwrapped ?? $this->unwrap())->getLeastSignificantBitsHex(); } public function getMostSignificantBitsHex(): string { return ($this->unwrapped ?? $this->unwrap())->getMostSignificantBitsHex(); } public function getNodeHex(): string { return ($this->unwrapped ?? $this->unwrap())->getNodeHex(); } public function getTimeHiAndVersionHex(): string { return ($this->unwrapped ?? $this->unwrap())->getTimeHiAndVersionHex(); } public function getTimeLowHex(): string { return ($this->unwrapped ?? $this->unwrap())->getTimeLowHex(); } public function getTimeMidHex(): string { return ($this->unwrapped ?? $this->unwrap())->getTimeMidHex(); } public function getTimestampHex(): string { return ($this->unwrapped ?? $this->unwrap())->getTimestampHex(); } public function getUrn(): string { return ($this->unwrapped ?? $this->unwrap())->getUrn(); } public function getVariant(): ?int { return ($this->unwrapped ?? $this->unwrap())->getVariant(); } 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(); } public function getBytes(): string { /** * @var non-empty-string * @phpstan-ignore possiblyImpure.functionCall, possiblyImpure.functionCall */ 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. */ public function getClockSeqHiAndReserved(): string { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($fields->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()}. */ 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()}. */ 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. */ public function getNode(): string { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); return $instance->getNumberConverter()->fromHex($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 { $instance = ($this->unwrapped ?? $this->unwrap()); $fields = $instance->getFields(); assert($fields instanceof \Ramsey\Uuid\Rfc4122\FieldsInterface); 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; } private function unwrap(): UuidInterface { return $this->unwrapped = (new UuidFactory())->fromString($this->uuid); } } uuid/src/FeatureSet.php 0000644 00000030072 15213403601 0011056 0 ustar 00 <?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 Ramsey\Uuid\Builder\FallbackBuilder; use Ramsey\Uuid\Builder\UuidBuilderInterface; use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Codec\GuidStringCodec; 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\Generator\UnixTimeGenerator; 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\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 * * A feature set is used by UuidFactory to determine the available features and capabilities of the environment. */ class FeatureSet { private ?TimeProviderInterface $timeProvider = null; private CalculatorInterface $calculator; private CodecInterface $codec; private DceSecurityGeneratorInterface $dceSecurityGenerator; private NameGeneratorInterface $nameGenerator; private NodeProviderInterface $nodeProvider; private NumberConverterInterface $numberConverter; private RandomGeneratorInterface $randomGenerator; private TimeConverterInterface $timeConverter; private TimeGeneratorInterface $timeGenerator; private TimeGeneratorInterface $unixTimeGenerator; private UuidBuilderInterface $builder; private ValidatorInterface $validator; /** * @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 (obsolete) * @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 * * @phpstan-ignore constructor.unusedParameter ($forceNoBigNumber is deprecated) */ public function __construct( bool $useGuids = false, private bool $force32Bit = false, bool $forceNoBigNumber = false, private bool $ignoreSystemNode = false, private bool $enablePecl = false, ) { $this->randomGenerator = $this->buildRandomGenerator(); $this->setCalculator(new BrickMathCalculator()); $this->builder = $this->buildUuidBuilder($useGuids); $this->codec = $this->buildCodec($useGuids); $this->nodeProvider = $this->buildNodeProvider(); $this->nameGenerator = $this->buildNameGenerator(); $this->setTimeProvider(new SystemTimeProvider()); $this->setDceSecurityProvider(new SystemDceSecurityProvider()); $this->validator = new GenericValidator(); assert($this->timeProvider !== null); $this->unixTimeGenerator = $this->buildUnixTimeGenerator(); } /** * Returns the builder configured for this environment */ public function getBuilder(): UuidBuilderInterface { return $this->builder; } /** * Returns the calculator configured for this environment */ public function getCalculator(): CalculatorInterface { return $this->calculator; } /** * Returns the codec configured for this environment */ public function getCodec(): CodecInterface { return $this->codec; } /** * Returns the DCE Security generator configured for this environment */ 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 */ public function getNumberConverter(): NumberConverterInterface { return $this->numberConverter; } /** * Returns the random generator configured for this environment */ public function getRandomGenerator(): RandomGeneratorInterface { return $this->randomGenerator; } /** * Returns the time converter configured for this environment */ public function getTimeConverter(): TimeConverterInterface { return $this->timeConverter; } /** * Returns the time generator configured for this environment */ public function getTimeGenerator(): TimeGeneratorInterface { return $this->timeGenerator; } /** * Returns the Unix Epoch time generator configured for this environment */ public function getUnixTimeGenerator(): TimeGeneratorInterface { return $this->unixTimeGenerator; } /** * Returns the validator configured for this environment */ 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); 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; if (isset($this->timeProvider)) { $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); } /** * Set the validator to use in this environment */ 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); } return new StringCodec($this->builder); } /** * Returns a DCE Security generator configured for this environment */ 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([new SystemNodeProvider(), new RandomNodeProvider()]); } /** * Returns a number converter configured for this environment */ private function buildNumberConverter(CalculatorInterface $calculator): NumberConverterInterface { return new GenericNumberConverter($calculator); } /** * Returns a random generator configured for this environment */ private function buildRandomGenerator(): RandomGeneratorInterface { if ($this->enablePecl) { return new PeclUuidRandomGenerator(); } return (new RandomGeneratorFactory())->getGenerator(); } /** * Returns a time generator configured for this environment * * @param TimeProviderInterface $timeProvider The time provider to use with * the time generator */ private function buildTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface { if ($this->enablePecl) { return new PeclUuidTimeGenerator(); } return (new TimeGeneratorFactory($this->nodeProvider, $this->timeConverter, $timeProvider))->getGenerator(); } /** * Returns a Unix Epoch time generator configured for this environment */ private function buildUnixTimeGenerator(): TimeGeneratorInterface { return new UnixTimeGenerator($this->randomGenerator); } /** * Returns a name generator configured for this environment */ 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($calculator, $genericConverter); } return $genericConverter; } /** * Returns a UUID builder configured for this environment * * @param bool $useGuids Whether to build UUIDs using the GuidStringCodec */ private function buildUuidBuilder(bool $useGuids = false): UuidBuilderInterface { if ($useGuids) { return new GuidBuilder($this->numberConverter, $this->timeConverter); } return new FallbackBuilder([ new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter), new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter), ]); } /** * Returns true if the PHP build is 64-bit */ private function is64BitSystem(): bool { return PHP_INT_SIZE === 8 && !$this->force32Bit; } } uuid/src/Type/Time.php 0000644 00000006544 15213403601 0010635 0 ustar 00 <?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\UnsupportedOperationException; use Ramsey\Uuid\Type\Integer as IntegerObject; use ValueError; use function json_decode; use function json_encode; use function sprintf; /** * A value object representing a timestamp * * This class exists for type-safety purposes, to ensure that timestamps used by ramsey/uuid are truly timestamp * integers and not some other kind of string or integer. * * @immutable */ final class Time implements TypeInterface { private IntegerObject $seconds; private IntegerObject $microseconds; public function __construct( IntegerObject | float | int | string $seconds, IntegerObject | float | int | string $microseconds = 0, ) { $this->seconds = new IntegerObject($seconds); $this->microseconds = new IntegerObject($microseconds); } /** * @pure */ public function getSeconds(): IntegerObject { return $this->seconds; } /** * @pure */ public function getMicroseconds(): IntegerObject { return $this->microseconds; } public function toString(): string { return $this->seconds->toString() . '.' . sprintf('%06s', $this->microseconds->toString()); } public function __toString(): string { return $this->toString(); } /** * @return string[] */ public function jsonSerialize(): array { return [ 'seconds' => $this->getSeconds()->toString(), 'microseconds' => $this->getMicroseconds()->toString(), ]; } public function serialize(): string { return (string) json_encode($this); } /** * @return array{seconds: string, microseconds: string} */ public function __serialize(): array { return [ 'seconds' => $this->getSeconds()->toString(), 'microseconds' => $this->getMicroseconds()->toString(), ]; } /** * Constructs the object from a serialized string representation * * @param string $data The serialized string representation of the object */ public function unserialize(string $data): void { /** @var array{seconds?: float | int | string, microseconds?: float | int | string} $time */ $time = json_decode($data, true); if (!isset($time['seconds']) || !isset($time['microseconds'])) { throw new UnsupportedOperationException('Attempted to unserialize an invalid value'); } $this->__construct($time['seconds'], $time['microseconds']); } /** * @param array{seconds?: string, microseconds?: string} $data */ public function __unserialize(array $data): void { // @codeCoverageIgnoreStart if (!isset($data['seconds']) || !isset($data['microseconds'])) { throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__)); } // @codeCoverageIgnoreEnd $this->__construct($data['seconds'], $data['microseconds']); } } uuid/src/Type/Decimal.php 0000644 00000005761 15213403601 0011275 0 ustar 00 <?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; use function str_starts_with; /** * 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. * * @immutable */ final class Decimal implements NumberInterface { private string $value; private bool $isNegative; public function __construct(float | int | string | self $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 (str_starts_with($value, '+')) { $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 (str_starts_with($value, '-')) { $this->isNegative = true; } else { $this->isNegative = false; } $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 $data The serialized string representation of the object */ public function unserialize(string $data): void { $this->__construct($data); } /** * @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']); } } uuid/src/Type/NumberInterface.php 0000644 00000001165 15213403601 0013002 0 ustar 00 <?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; /** * NumberInterface ensures consistency in numeric values returned by ramsey/uuid * * @immutable */ interface NumberInterface extends TypeInterface { /** * Returns true if this number is less than zero */ public function isNegative(): bool; } uuid/src/Type/Integer.php 0000644 00000007531 15213403601 0011331 0 ustar 00 <?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 assert; use function is_numeric; use function preg_match; use function sprintf; use function substr; /** * A value object representing an integer * * This class exists for type-safety purposes, to ensure that integers returned from ramsey/uuid methods as strings are * truly integers and not some other kind of string. * * To support large integers beyond PHP_INT_MAX and PHP_INT_MIN on both 64-bit and 32-bit systems, we store the integers * as strings. * * @immutable */ final class Integer implements NumberInterface { /** * @var numeric-string */ private string $value; /** * @phpstan-ignore property.readOnlyByPhpDocDefaultValue */ private bool $isNegative = false; public function __construct(self | float | int | string $value) { $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value); } public function isNegative(): bool { return $this->isNegative; } /** * @return numeric-string * * @pure */ public function toString(): string { return $this->value; } /** * @return numeric-string */ 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 $data The serialized string representation of the object */ public function unserialize(string $data): void { $this->__construct($data); } /** * @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']); } /** * @return numeric-string */ private function prepareValue(float | int | string $value): string { $value = (string) $value; $sign = '+'; // If the value contains a sign, remove it for the digit pattern check. if (str_starts_with($value, '-') || str_starts_with($value, '+')) { $sign = substr($value, 0, 1); $value = substr($value, 1); } if (!preg_match('/^\d+$/', $value)) { throw new InvalidArgumentException( 'Value must be a signed integer or a string containing only ' . 'digits 0-9 and, optionally, a sign (+ or -)' ); } // Trim any leading zeros. $value = ltrim($value, '0'); // Set to zero if the string is empty after trimming zeros. if ($value === '') { $value = '0'; } // Add the negative sign back to the value. if ($sign === '-' && $value !== '0') { $value = $sign . $value; /** @phpstan-ignore property.readOnlyByPhpDocAssignNotInConstructor */ $this->isNegative = true; } assert(is_numeric($value)); return $value; } } uuid/src/Type/Hexadecimal.php 0000644 00000005631 15213403601 0012137 0 ustar 00 <?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 preg_match; use function sprintf; use function substr; /** * A value object representing a hexadecimal number * * This class exists for type-safety purposes, to ensure that hexadecimal numbers returned from ramsey/uuid methods as * strings are truly hexadecimal and not some other kind of string. * * @immutable */ final class Hexadecimal implements TypeInterface { /** * @var non-empty-string */ private string $value; /** * @param self | string $value The hexadecimal value to store */ public function __construct(self | string $value) { $this->value = $value instanceof self ? (string) $value : $this->prepareValue($value); } /** * @return non-empty-string * * @pure */ public function toString(): string { return $this->value; } /** * @return non-empty-string */ public function __toString(): string { return $this->toString(); } /** * @return non-empty-string */ public function jsonSerialize(): string { return $this->toString(); } /** * @return non-empty-string */ 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 $data The serialized string representation of the object */ public function unserialize(string $data): void { $this->__construct($data); } /** * @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']); } /** * @return non-empty-string */ private function prepareValue(string $value): string { $value = strtolower($value); if (str_starts_with($value, '0x')) { $value = substr($value, 2); } if (!preg_match('/^[A-Fa-f0-9]+$/', $value)) { throw new InvalidArgumentException('Value must be a hexadecimal number'); } /** @var non-empty-string */ return $value; } } uuid/src/Type/TypeInterface.php 0000644 00000001311 15213403601 0012464 0 ustar 00 <?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 JsonSerializable; use Serializable; /** * TypeInterface ensures consistency in typed values returned by ramsey/uuid * * @immutable */ interface TypeInterface extends JsonSerializable, Serializable { /** * @pure */ public function toString(): string; /** * @pure */ public function __toString(): string; } uuid/src/Generator/UnixTimeGenerator.php 0000644 00000013527 15213403601 0014354 0 ustar 00 <?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 Brick\Math\BigInteger; use DateTimeInterface; use Ramsey\Uuid\Type\Hexadecimal; use function assert; use function hash; use function pack; use function str_pad; use function strlen; use function substr; use function substr_replace; use function unpack; use const PHP_INT_SIZE; use const STR_PAD_LEFT; /** * UnixTimeGenerator generates bytes, combining a 48-bit timestamp in milliseconds since the Unix Epoch with 80 random bits * * Code and concepts within this class are borrowed from the symfony/uid package and are used under the terms of the MIT * license distributed with symfony/uid. * * symfony/uid is copyright (c) Fabien Potencier. * * @link https://symfony.com/components/Uid Symfony Uid component * @link https://github.com/symfony/uid/blob/4f9f537e57261519808a7ce1d941490736522bbc/UuidV7.php Symfony UuidV7 class * @link https://github.com/symfony/uid/blob/6.2/LICENSE MIT License */ class UnixTimeGenerator implements TimeGeneratorInterface { private static string $time = ''; private static ?string $seed = null; private static int $seedIndex = 0; /** @var int[] */ private static array $rand = []; /** @var int[] */ private static array $seedParts; public function __construct( private RandomGeneratorInterface $randomGenerator, private int $intSize = PHP_INT_SIZE, ) { } /** * @param Hexadecimal | int | string | null $node Unused in this generator * @param int | null $clockSeq Unused in this generator * @param DateTimeInterface | null $dateTime A date-time instance to use when generating bytes */ public function generate($node = null, ?int $clockSeq = null, ?DateTimeInterface $dateTime = null): string { if ($dateTime === null) { $time = microtime(false); $time = substr($time, 11) . substr($time, 2, 3); } else { $time = $dateTime->format('Uv'); } if ($time > self::$time || ($dateTime !== null && $time !== self::$time)) { $this->randomize($time); } else { $time = $this->increment(); } if ($this->intSize >= 8) { $time = substr(pack('J', (int) $time), -6); } else { $time = str_pad(BigInteger::of($time)->toBytes(false), 6, "\x00", STR_PAD_LEFT); } assert(strlen($time) === 6); return $time . pack('n*', self::$rand[1], self::$rand[2], self::$rand[3], self::$rand[4], self::$rand[5]); } private function randomize(string $time): void { if (self::$seed === null) { $seed = $this->randomGenerator->generate(16); self::$seed = $seed; } else { $seed = $this->randomGenerator->generate(10); } /** @var int[] $rand */ $rand = unpack('n*', $seed); $rand[1] &= 0x03ff; self::$rand = $rand; self::$time = $time; } /** * Special thanks to Nicolas Grekas (<https://github.com/nicolas-grekas>) for sharing the following information: * * Within the same ms, we increment the rand part by a random 24-bit number. * * Instead of getting this number from random_bytes(), which is slow, we get it by sha512-hashing self::$seed. This * produces 64 bytes of entropy, which we need to split in a list of 24-bit numbers. `unpack()` first splits them * into 16 x 32-bit numbers; we take the first byte of each number to get 5 extra 24-bit numbers. Then, we consume * each number one-by-one and run this logic every 21 iterations. * * `self::$rand` holds the random part of the UUID, split into 5 x 16-bit numbers for x86 portability. We increment * this random part by the next 24-bit number in the `self::$seedParts` list and decrement `self::$seedIndex`. */ private function increment(): string { if (self::$seedIndex === 0 && self::$seed !== null) { self::$seed = hash('sha512', self::$seed, true); /** @var int[] $s */ $s = unpack('l*', self::$seed); $s[] = ($s[1] >> 8 & 0xff0000) | ($s[2] >> 16 & 0xff00) | ($s[3] >> 24 & 0xff); $s[] = ($s[4] >> 8 & 0xff0000) | ($s[5] >> 16 & 0xff00) | ($s[6] >> 24 & 0xff); $s[] = ($s[7] >> 8 & 0xff0000) | ($s[8] >> 16 & 0xff00) | ($s[9] >> 24 & 0xff); $s[] = ($s[10] >> 8 & 0xff0000) | ($s[11] >> 16 & 0xff00) | ($s[12] >> 24 & 0xff); $s[] = ($s[13] >> 8 & 0xff0000) | ($s[14] >> 16 & 0xff00) | ($s[15] >> 24 & 0xff); self::$seedParts = $s; self::$seedIndex = 21; } self::$rand[5] = 0xffff & $carry = self::$rand[5] + 1 + (self::$seedParts[self::$seedIndex--] & 0xffffff); self::$rand[4] = 0xffff & $carry = self::$rand[4] + ($carry >> 16); self::$rand[3] = 0xffff & $carry = self::$rand[3] + ($carry >> 16); self::$rand[2] = 0xffff & $carry = self::$rand[2] + ($carry >> 16); self::$rand[1] += $carry >> 16; if (0xfc00 & self::$rand[1]) { $time = self::$time; $mtime = (int) substr($time, -9); if ($this->intSize >= 8 || strlen($time) < 10) { $time = (string) ((int) $time + 1); } elseif ($mtime === 999999999) { $time = (1 + (int) substr($time, 0, -9)) . '000000000'; } else { $mtime++; $time = substr_replace($time, str_pad((string) $mtime, 9, '0', STR_PAD_LEFT), -9); } $this->randomize($time); } return self::$time; } } uuid/src/Generator/RandomGeneratorInterface.php 0000644 00000001337 15213403601 0015647 0 ustar 00 <?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; /** * A random generator generates strings of random binary data */ interface RandomGeneratorInterface { /** * Generates a string of randomized binary data * * @param int<1, max> $length The number of bytes to generate of random binary data * * @return string A binary string */ public function generate(int $length): string; } uuid/src/Generator/NameGeneratorFactory.php 0000644 00000001267 15213403601 0015020 0 ustar 00 <?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(); } } uuid/src/Generator/PeclUuidNameGenerator.php 0000644 00000002674 15213403601 0015126 0 ustar 00 <?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 { /** * @pure */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string { $uuid = match ($hashAlgorithm) { 'md5' => uuid_generate_md5($ns->toString(), $name), /** @phpstan-ignore possiblyImpure.functionCall */ 'sha1' => uuid_generate_sha1($ns->toString(), $name), /** @phpstan-ignore possiblyImpure.functionCall */ default => throw new NameException( sprintf('Unable to hash namespace and name with algorithm \'%s\'', $hashAlgorithm), ), }; /** @phpstan-ignore possiblyImpure.functionCall */ return (string) uuid_parse($uuid); } } uuid/src/Generator/RandomGeneratorFactory.php 0000644 00000001301 15213403601 0015345 0 ustar 00 <?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; /** * RandomGeneratorFactory retrieves a default random generator, based on the environment */ class RandomGeneratorFactory { /** * Returns a default random generator, based on the current environment */ public function getGenerator(): RandomGeneratorInterface { return new RandomBytesGenerator(); } } uuid/src/Generator/DceSecurityGeneratorInterface.php 0000644 00000003255 15213403601 0016653 0 ustar 00 <?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; } uuid/src/Generator/PeclUuidRandomGenerator.php 0000644 00000001460 15213403601 0015456 0 ustar 00 <?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 function uuid_create; use function uuid_parse; use const UUID_TYPE_RANDOM; /** * PeclUuidRandomGenerator generates strings of random binary data using ext-uuid * * @link https://pecl.php.net/package/uuid ext-uuid */ class PeclUuidRandomGenerator implements RandomGeneratorInterface { public function generate(int $length): string { $uuid = uuid_create(UUID_TYPE_RANDOM); return (string) uuid_parse($uuid); } } uuid/src/Generator/DefaultTimeGenerator.php 0000644 00000007225 15213403601 0015013 0 ustar 00 <?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\TimeConverterInterface; 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 dechex; use function hex2bin; use function is_int; use function pack; use function preg_match; use function sprintf; use function str_pad; use function strlen; use const STR_PAD_LEFT; /** * DefaultTimeGenerator generates strings of binary data based on a node ID, clock sequence, and the current time */ class DefaultTimeGenerator implements TimeGeneratorInterface { public function __construct( private NodeProviderInterface $nodeProvider, private TimeConverterInterface $timeConverter, private TimeProviderInterface $timeProvider, ) { } /** * @throws InvalidArgumentException if the parameters contain invalid values * @throws RandomSourceException if random_int() throws an exception/error * * @inheritDoc */ public function generate($node = null, ?int $clockSeq = null): string { if ($node instanceof Hexadecimal) { $node = $node->toString(); } $node = $this->getValidNode($node); if ($clockSeq === null) { try { // This does not use "stable storage"; see RFC 9562, section 6.3. $clockSeq = random_int(0, 0x3fff); } catch (Throwable $exception) { throw new RandomSourceException($exception->getMessage(), (int) $exception->getCode(), $exception); } } $time = $this->timeProvider->getTime(); $uuidTime = $this->timeConverter->calculateTime( $time->getSeconds()->toString(), $time->getMicroseconds()->toString() ); $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 int | string | 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 */ private function getValidNode(int | string | null $node): string { if ($node === null) { $node = $this->nodeProvider->getNode(); } // Convert the node to hex if it is still an integer. if (is_int($node)) { $node = dechex($node); } if (!preg_match('/^[A-Fa-f0-9]+$/', (string) $node) || strlen((string) $node) > 12) { throw new InvalidArgumentException('Invalid node value'); } return (string) hex2bin(str_pad((string) $node, 12, '0', STR_PAD_LEFT)); } } uuid/src/Generator/NameGeneratorInterface.php 0000644 00000002035 15213403601 0015303 0 ustar 00 <?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 * * @pure */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string; } uuid/src/Generator/PeclUuidTimeGenerator.php 0000644 00000001557 15213403601 0015143 0 ustar 00 <?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 function uuid_create; use function uuid_parse; use const UUID_TYPE_TIME; /** * PeclUuidTimeGenerator generates strings of binary data for time-base UUIDs, using ext-uuid * * @link https://pecl.php.net/package/uuid ext-uuid */ class PeclUuidTimeGenerator implements TimeGeneratorInterface { /** * @inheritDoc */ public function generate($node = null, ?int $clockSeq = null): string { $uuid = uuid_create(UUID_TYPE_TIME); return (string) uuid_parse($uuid); } } uuid/src/Generator/TimeGeneratorInterface.php 0000644 00000002165 15213403601 0015325 0 ustar 00 <?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\Type\Hexadecimal; /** * A time generator generates strings of binary data based on a node ID, clock sequence, and the current time */ interface TimeGeneratorInterface { /** * 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 * * @return string A binary string */ public function generate($node = null, ?int $clockSeq = null): string; } uuid/src/Generator/CombGenerator.php 0000644 00000006642 15213403601 0013472 0 ustar 00 <?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\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 generates COMBs (combined UUID/timestamp) * * 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. * * ``` * $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. * * ``` * $factory->setCodec(new TimestampFirstCombCodec($factory->getUuidBuilder())); * ``` * * @deprecated Please migrate to {@link https://uuid.ramsey.dev/en/stable/rfc4122/version7.html Version 7, Unix Epoch Time UUIDs}. * * @link https://web.archive.org/web/20240118030355/https://www.informit.com/articles/printerfriendly/25862 The Cost of GUIDs as Primary Keys */ class CombGenerator implements RandomGeneratorInterface { public const TIMESTAMP_BYTES = 6; public function __construct( private RandomGeneratorInterface $generator, private NumberConverterInterface $numberConverter ) { } /** * @throws InvalidArgumentException if $length is not a positive integer greater than or equal to CombGenerator::TIMESTAMP_BYTES * * @inheritDoc */ public function generate(int $length): string { if ($length < self::TIMESTAMP_BYTES) { throw new InvalidArgumentException( 'Length must be a positive integer greater than or equal to ' . self::TIMESTAMP_BYTES ); } if ($length % 2 !== 0) { throw new InvalidArgumentException('Length must be an even number'); } $hash = ''; /** @phpstan-ignore greater.alwaysTrue (TIMESTAMP_BYTES constant could change in child classes) */ if (self::TIMESTAMP_BYTES > 0 && $length > self::TIMESTAMP_BYTES) { $hash = $this->generator->generate($length - self::TIMESTAMP_BYTES); } $lsbTime = str_pad( $this->numberConverter->toHex($this->timestamp()), self::TIMESTAMP_BYTES * 2, '0', STR_PAD_LEFT, ); return (string) hex2bin(str_pad(bin2hex($hash), $length - self::TIMESTAMP_BYTES, '0') . $lsbTime); } /** * Returns the current timestamp as a string integer, precise to 0.00001 seconds */ private function timestamp(): string { $time = explode(' ', microtime(false)); return $time[1] . substr($time[0], 2, 5); } } uuid/src/Generator/RandomLibAdapter.php 0000644 00000003016 15213403601 0014103 0 ustar 00 <?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 RandomLib\Factory; use RandomLib\Generator; /** * RandomLibAdapter generates strings of random binary data using the paragonie/random-lib library * * @deprecated This class will be removed in 5.0.0. Use the default RandomBytesGenerator or implement your own generator * that implements RandomGeneratorInterface. * * @link https://packagist.org/packages/paragonie/random-lib paragonie/random-lib */ class RandomLibAdapter implements RandomGeneratorInterface { private Generator $generator; /** * Constructs a RandomLibAdapter * * By default, if no Generator is passed in, this creates a high-strength generator to use when generating random * binary data. * * @param Generator | null $generator The generator to use when generating binary data */ public function __construct(?Generator $generator = null) { if ($generator === null) { $factory = new Factory(); $generator = $factory->getHighStrengthGenerator(); } $this->generator = $generator; } public function generate(int $length): string { return $this->generator->generate($length); } } uuid/src/Generator/RandomBytesGenerator.php 0000644 00000002067 15213403601 0015036 0 ustar 00 <?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\RandomSourceException; use Throwable; /** * RandomBytesGenerator generates strings of random binary data using the built-in `random_bytes()` PHP function * * @link http://php.net/random_bytes random_bytes() */ class RandomBytesGenerator implements RandomGeneratorInterface { /** * @throws RandomSourceException if random_bytes() throws an exception/error * * @inheritDoc */ public function generate(int $length): string { try { return random_bytes($length); } catch (Throwable $exception) { throw new RandomSourceException($exception->getMessage(), (int) $exception->getCode(), $exception); } } } uuid/src/Generator/DefaultNameGenerator.php 0000644 00000002127 15213403601 0014771 0 ustar 00 <?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 { /** * @pure */ public function generate(UuidInterface $ns, string $name, string $hashAlgorithm): string { try { return hash($hashAlgorithm, $ns->getBytes() . $name, true); } catch (ValueError $e) { throw new NameException( message: sprintf('Unable to hash namespace and name with algorithm \'%s\'', $hashAlgorithm), previous: $e, ); } } } uuid/src/Generator/DceSecurityGenerator.php 0000644 00000010347 15213403601 0015032 0 ustar 00 <?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; public function __construct( private NumberConverterInterface $numberConverter, private TimeGeneratorInterface $timeGenerator, private DceSecurityProviderInterface $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 4,294,967,295. 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); return substr_replace($bytes, $domainByte, 9, 1); } } uuid/src/Generator/TimeGeneratorFactory.php 0000644 00000002131 15213403601 0015025 0 ustar 00 <?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\TimeConverterInterface; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Provider\TimeProviderInterface; /** * TimeGeneratorFactory retrieves a default time generator, based on the environment */ class TimeGeneratorFactory { public function __construct( private NodeProviderInterface $nodeProvider, private TimeConverterInterface $timeConverter, private TimeProviderInterface $timeProvider, ) { } /** * Returns a default time generator, based on the current environment */ public function getGenerator(): TimeGeneratorInterface { return new DefaultTimeGenerator($this->nodeProvider, $this->timeConverter, $this->timeProvider); } } uuid/src/DeprecatedUuidMethodsTrait.php 0000644 00000032014 15213403601 0014224 0 ustar 00 <?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\Exception\DateTimeException; use Ramsey\Uuid\Exception\UnsupportedOperationException; 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. * * @deprecated This trait and its methods will be removed in ramsey/uuid 5.0.0. * * @immutable */ trait DeprecatedUuidMethodsTrait { /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getClockSeqHiAndReserved()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getClockSeqLow()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { 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 \Ramsey\Uuid\Fields\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 \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getNode()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getTimeHiAndVersion()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getTimeLow()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { return $this->fields->getTimeMid()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance. * If it is a {@see \Ramsey\Uuid\Rfc4122\FieldsInterface} instance, you may call * {@see \Ramsey\Uuid\Rfc4122\FieldsInterface::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 \Ramsey\Uuid\Fields\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 { if ($this->fields->getVersion() !== 1) { throw new UnsupportedOperationException('Not a time-based UUID'); } return $this->fields->getTimestamp()->toString(); } /** * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\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 \Ramsey\Uuid\Fields\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(); } } uuid/src/Exception/InvalidBytesException.php 0000644 00000001122 15213403601 0015213 0 ustar 00 <?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 { } uuid/src/Exception/NodeException.php 0000644 00000001123 15213403601 0013504 0 ustar 00 <?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 { } uuid/src/Exception/UuidExceptionInterface.php 0000644 00000000666 15213403601 0015361 0 ustar 00 <?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 { } uuid/src/Exception/DateTimeException.php 0000644 00000001124 15213403601 0014314 0 ustar 00 <?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 { } uuid/src/Exception/RandomSourceException.php 0000644 00000001362 15213403601 0015225 0 ustar 00 <?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 { } uuid/src/Exception/BuilderNotFoundException.php 0000644 00000001104 15213403601 0015661 0 ustar 00 <?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 { } uuid/src/Exception/NameException.php 0000644 00000001126 15213403601 0013502 0 ustar 00 <?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 { } uuid/src/Exception/InvalidUuidStringException.php 0000644 00000001267 15213403601 0016234 0 ustar 00 <?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; /** * 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 implements UuidExceptionInterface { } uuid/src/Exception/UnableToBuildUuidException.php 0000644 00000001102 15213403601 0016134 0 ustar 00 <?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 { } uuid/src/Exception/TimeSourceException.php 0000644 00000001104 15213403601 0014675 0 ustar 00 <?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 { } uuid/src/Exception/InvalidArgumentException.php 0000644 00000001134 15213403601 0015712 0 ustar 00 <?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 { } uuid/src/Exception/UnsupportedOperationException.php 0000644 00000001111 15213403601 0017025 0 ustar 00 <?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 LogicException as PhpLogicException; /** * Thrown to indicate that the requested operation is not supported */ class UnsupportedOperationException extends PhpLogicException implements UuidExceptionInterface { } uuid/src/Exception/DceSecurityException.php 0000644 00000001140 15213403601 0015041 0 ustar 00 <?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 { } uuid/src/Guid/Guid.php 0000644 00000004343 15213403601 0010571 0 ustar 00 <?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 GUID definition. * * 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 * * @immutable */ final class Guid extends Uuid { public function __construct( Fields $fields, NumberConverterInterface $numberConverter, CodecInterface $codec, TimeConverterInterface $timeConverter, ) { parent::__construct($fields, $numberConverter, $codec, $timeConverter); } } uuid/src/Guid/GuidBuilder.php 0000644 00000004371 15213403601 0012101 0 ustar 00 <?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 * * @immutable */ class GuidBuilder implements UuidBuilderInterface { /** * @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( private NumberConverterInterface $numberConverter, private TimeConverterInterface $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 * * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { try { /** @phpstan-ignore possiblyImpure.new */ return new Guid($this->buildFields($bytes), $this->numberConverter, $codec, $this->timeConverter); } catch (Throwable $e) { /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing * * @pure */ protected function buildFields(string $bytes): Fields { /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } uuid/src/Guid/Fields.php 0000644 00000011612 15213403601 0011104 0 ustar 00 <?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\MaxTrait; 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 consist of a set of named fields, according to RFC 9562 (formerly RFC 4122) * * @see Guid * * @immutable */ final class Fields implements FieldsInterface { use MaxTrait; use NilTrait; use SerializableFieldsTrait; use VariantTrait; use VersionTrait; /** * @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(private string $bytes) { if (strlen($this->bytes) !== 16) { throw new InvalidArgumentException( 'The byte string must be 16 bytes long; received ' . strlen($this->bytes) . ' bytes', ); } if (!$this->isCorrectVariant()) { throw new InvalidArgumentException( 'The byte string received does not conform to the RFC 9562 (formerly 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 string[] $hex */ $hex = unpack( 'H*', pack( 'v*', hexdec(bin2hex(substr($this->bytes, 2, 2))), hexdec(bin2hex(substr($this->bytes, 0, 2))), ), ); return new Hexadecimal($hex[1] ?? ''); } public function getTimeMid(): Hexadecimal { // Swap the bytes from little endian to network byte order. /** @var string[] $hex */ $hex = unpack('H*', pack('v', hexdec(bin2hex(substr($this->bytes, 4, 2))))); return new Hexadecimal($hex[1] ?? ''); } public function getTimeHiAndVersion(): Hexadecimal { // Swap the bytes from little endian to network byte order. /** @var string[] $hex */ $hex = unpack('H*', pack('v', hexdec(bin2hex(substr($this->bytes, 6, 2))))); return new Hexadecimal($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 { if ($this->isMax()) { $clockSeq = 0xffff; } elseif ($this->isNil()) { $clockSeq = 0x0000; } else { $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() || $this->isMax()) { return null; } /** @var int[] $parts */ $parts = unpack('n*', $this->bytes); return ($parts[4] >> 4) & 0x00f; } private function isCorrectVariant(): bool { if ($this->isNil() || $this->isMax()) { return true; } $variant = $this->getVariant(); return $variant === Uuid::RFC_4122 || $variant === Uuid::RESERVED_MICROSOFT; } } uuid/src/BinaryUtils.php 0000644 00000003035 15213403601 0011253 0 ustar 00 <?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; /** * Provides binary math utilities */ class BinaryUtils { /** * Applies the variant field to the 16-bit clock sequence * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field * * @param int $clockSeq The 16-bit clock sequence value before the variant is applied * * @return int The 16-bit clock sequence multiplexed with the UUID variant * * @pure */ public static function applyVariant(int $clockSeq): int { return ($clockSeq & 0x3fff) | 0x8000; } /** * Applies the version field to the 16-bit `time_hi_and_version` field * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field * * @param int $timeHi The value of the 16-bit `time_hi_and_version` field before the version is applied * @param int $version The 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 * * @pure */ public static function applyVersion(int $timeHi, int $version): int { return ($timeHi & 0x0fff) | ($version << 12); } } uuid/src/Rfc4122/UuidV2.php 0000644 00000010322 15213403601 0011144 0 ustar 00 <?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\Type\Integer as IntegerObject; use Ramsey\Uuid\Uuid; use function hexdec; /** * 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 * * It is important to note that a version 2 UUID suffers from some loss of timestamp fidelity, 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 496,730 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). * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.2 RFC 9562, 5.2. UUID Version 2 * @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) * * @immutable */ final class UuidV2 extends Uuid implements UuidInterface { use TimeTrait; /** * 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 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())); } } uuid/src/Rfc4122/UuidV5.php 0000644 00000004037 15213403601 0011155 0 ustar 00 <?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 a combination of a namespace and name that are hashed into a 128-bit unsigned * integer using the SHA1 hashing algorithm * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.5 RFC 9562, 5.5. UUID Version 5 * * @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); } } uuid/src/Rfc4122/UuidInterface.php 0000644 00000001203 15213403601 0012553 0 ustar 00 <?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; /** * A universally unique identifier (UUID), as defined in RFC 9562 (formerly RFC 4122) * * @link https://www.rfc-editor.org/rfc/rfc9562 RFC 9562 * * @immutable */ interface UuidInterface extends BaseUuidInterface { } uuid/src/Rfc4122/UuidBuilder.php 0000644 00000012003 15213403601 0012241 0 ustar 00 <?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\Time\UnixTimeConverter; use Ramsey\Uuid\Converter\TimeConverterInterface; use Ramsey\Uuid\Exception\UnableToBuildUuidException; use Ramsey\Uuid\Exception\UnsupportedOperationException; use Ramsey\Uuid\Math\BrickMathCalculator; use Ramsey\Uuid\Rfc4122\UuidInterface as Rfc4122UuidInterface; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; use Throwable; /** * UuidBuilder builds instances of RFC 9562 (formerly 4122) UUIDs * * @immutable */ class UuidBuilder implements UuidBuilderInterface { private TimeConverterInterface $unixTimeConverter; /** * 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 Gregorian time extracted * from version 1, 2, and 6 UUIDs to Unix timestamps * @param TimeConverterInterface | null $unixTimeConverter The time converter to use for converter Unix Epoch time * extracted from version 7 UUIDs to Unix timestamps */ public function __construct( private NumberConverterInterface $numberConverter, private TimeConverterInterface $timeConverter, ?TimeConverterInterface $unixTimeConverter = null, ) { $this->unixTimeConverter = $unixTimeConverter ?? new UnixTimeConverter(new BrickMathCalculator()); } /** * 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 * * @pure */ public function build(CodecInterface $codec, string $bytes): UuidInterface { try { /** @var Fields $fields */ $fields = $this->buildFields($bytes); if ($fields->isNil()) { /** @phpstan-ignore possiblyImpure.new */ return new NilUuid($fields, $this->numberConverter, $codec, $this->timeConverter); } if ($fields->isMax()) { /** @phpstan-ignore possiblyImpure.new */ return new MaxUuid($fields, $this->numberConverter, $codec, $this->timeConverter); } return match ($fields->getVersion()) { /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_TIME => new UuidV1($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_DCE_SECURITY /** @phpstan-ignore possiblyImpure.new */ => new UuidV2($fields, $this->numberConverter, $codec, $this->timeConverter), /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_HASH_MD5 => new UuidV3($fields, $this->numberConverter, $codec, $this->timeConverter), /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_RANDOM => new UuidV4($fields, $this->numberConverter, $codec, $this->timeConverter), /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_HASH_SHA1 => new UuidV5($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_REORDERED_TIME /** @phpstan-ignore possiblyImpure.new */ => new UuidV6($fields, $this->numberConverter, $codec, $this->timeConverter), Uuid::UUID_TYPE_UNIX_TIME /** @phpstan-ignore possiblyImpure.new */ => new UuidV7($fields, $this->numberConverter, $codec, $this->unixTimeConverter), /** @phpstan-ignore possiblyImpure.new */ Uuid::UUID_TYPE_CUSTOM => new UuidV8($fields, $this->numberConverter, $codec, $this->timeConverter), default => throw new UnsupportedOperationException( 'The UUID version in the given fields is not supported by this UUID builder', ), }; } catch (Throwable $e) { /** @phpstan-ignore possiblyImpure.methodCall, possiblyImpure.methodCall */ throw new UnableToBuildUuidException($e->getMessage(), (int) $e->getCode(), $e); } } /** * Proxy method to allow injecting a mock for testing * * @pure */ protected function buildFields(string $bytes): FieldsInterface { /** @phpstan-ignore possiblyImpure.new */ return new Fields($bytes); } } uuid/src/Rfc4122/TimeTrait.php 0000644 00000002565 15213403601 0011742 0 ustar 00 <?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\Exception\DateTimeException; use Throwable; use function str_pad; use const STR_PAD_LEFT; /** * Provides common functionality for getting the time from a time-based UUID * * @immutable */ trait TimeTrait { /** * Returns a DateTimeInterface object representing the timestamp associated with the UUID * * @return DateTimeImmutable A PHP DateTimeImmutable instance representing the timestamp of a time-based 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); } } } uuid/src/Rfc4122/MaxUuid.php 0000644 00000001205 15213403601 0011402 0 ustar 00 <?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 max UUID is a special form of UUID that has all 128 bits set to one (`1`) * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.10 RFC 9562, 5.10. Max UUID * * @immutable */ final class MaxUuid extends Uuid implements UuidInterface { } uuid/src/Rfc4122/UuidV3.php 0000644 00000004032 15213403601 0011146 0 ustar 00 <?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 a combination of a namespace and name that are hashed into a 128-bit unsigned * integer using the MD5 hashing algorithm * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.3 RFC 9562, 5.3. UUID Version 3 * * @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); } } uuid/src/Rfc4122/VersionTrait.php 0000644 00000004270 15213403601 0012464 0 ustar 00 <?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; /** * Provides common functionality for handling the version, as defined by RFC 9562 (formerly RFC 4122) * * @immutable */ trait VersionTrait { /** * Returns the UUID version * * The version number describes how the UUID was generated and has the following meaning: * * 1. Gregorian time UUID * 2. DCE security UUID * 3. Name-based UUID hashed with MD5 * 4. Randomly generated UUID * 5. Name-based UUID hashed with SHA-1 * 6. Reordered Gregorian time UUID * 7. Unix Epoch time UUID * 8. Custom format UUID * * This returns `null` if the UUID is not an RFC 9562 (formerly RFC 4122) variant, since the version is only * meaningful for this variant. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field * * @pure */ abstract public function getVersion(): ?int; /** * Returns true if these fields represent a max UUID */ abstract public function isMax(): bool; /** * 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 9562 (formerly RFC 4122) * * @return bool True if the UUID version is valid, false otherwise */ private function isCorrectVersion(): bool { if ($this->isNil() || $this->isMax()) { return true; } return match ($this->getVersion()) { Uuid::UUID_TYPE_TIME, Uuid::UUID_TYPE_DCE_SECURITY, Uuid::UUID_TYPE_HASH_MD5, Uuid::UUID_TYPE_RANDOM, Uuid::UUID_TYPE_HASH_SHA1, Uuid::UUID_TYPE_REORDERED_TIME, Uuid::UUID_TYPE_UNIX_TIME, Uuid::UUID_TYPE_CUSTOM => true, default => false, }; } } uuid/src/Rfc4122/UuidV1.php 0000644 00000003767 15213403601 0011162 0 ustar 00 <?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; /** * Gregorian time, or version 1, UUIDs include timestamp, clock sequence, and node values, combined into a 128-bit unsigned integer * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.1 RFC 9562, 5.1. UUID Version 1 * * @immutable */ final class UuidV1 extends Uuid implements UuidInterface { use TimeTrait; /** * Creates a version 1 (Gregorian time) 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); } } uuid/src/Rfc4122/MaxTrait.php 0000644 00000001510 15213403601 0011556 0 ustar 00 <?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 max UUIDs * * @immutable */ trait MaxTrait { /** * Returns the bytes that comprise the fields * * @pure */ abstract public function getBytes(): string; /** * Returns true if the byte string represents a max UUID * * @pure */ public function isMax(): bool { return $this->getBytes() === "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; } } uuid/src/Rfc4122/UuidV8.php 0000644 00000004363 15213403601 0011162 0 ustar 00 <?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; /** * Custom format, or version 8, UUIDs provide an RFC-compatible format for experimental or vendor-specific uses * * The only requirement for version 8 UUIDs is that the version and variant bits must be set. Otherwise, implementations * are free to set the other bits according to their needs. As a result, the uniqueness of version 8 UUIDs is * implementation-specific and should not be assumed. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.8 RFC 9562, 5.8. UUID Version 8 * * @immutable */ final class UuidV8 extends Uuid implements UuidInterface { /** * Creates a version 8 (custom format) 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_CUSTOM) { throw new InvalidArgumentException( 'Fields used to create a UuidV8 must represent a version 8 (custom format) UUID', ); } parent::__construct($fields, $numberConverter, $codec, $timeConverter); } } uuid/src/Rfc4122/NilTrait.php 0000644 00000001424 15213403601 0011557 0 ustar 00 <?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 * * @immutable */ trait NilTrait { /** * Returns the bytes that comprise the fields * * @pure */ 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"; } } uuid/src/Rfc4122/UuidV4.php 0000644 00000003657 15213403601 0011163 0 ustar 00 <?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 * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.4 RFC 9562, 5.4. UUID Version 4 * * @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); } } uuid/src/Rfc4122/FieldsInterface.php 0000644 00000010324 15213403601 0013057 0 ustar 00 <?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; /** * UUID fields, as defined by RFC 4122 * * This interface defines the fields of an RFC 4122 variant UUID. Since RFC 9562 removed the concept of fields and * instead defined layouts that are specific to a given version, this interface is a legacy artifact of the earlier, and * now obsolete, RFC 4122. * * 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 https://www.rfc-editor.org/rfc/rfc4122#section-4.1 RFC 4122, 4.1. Format * @link https://www.rfc-editor.org/rfc/rfc9562#section-4 RFC 9562, 4. UUID Format * * @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 9562 (formerly RFC 4122) variant * - 6 - Reserved, Microsoft Corporation backward compatibility * - 7 - Reserved for future definition * * For RFC 9562 (formerly RFC 4122) variant UUIDs, this value should always be the integer `2`. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public function getVariant(): int; /** * Returns the UUID version * * The version number describes how the UUID was generated and has the following meaning: * * 1. Gregorian time UUID * 2. DCE security UUID * 3. Name-based UUID hashed with MD5 * 4. Randomly generated UUID * 5. Name-based UUID hashed with SHA-1 * 6. Reordered Gregorian time UUID * 7. Unix Epoch time UUID * 8. Custom format UUID * * This returns `null` if the UUID is not an RFC 9562 (formerly RFC 4122) variant, since the version is only * meaningful for this variant. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.2 RFC 9562, 4.2. Version Field * * @pure */ public function getVersion(): ?int; /** * Returns true if these fields represent a nil UUID * * The nil UUID is a special form of UUID that is specified to have all 128 bits set to zero. * * @pure */ public function isNil(): bool; } uuid/src/Rfc4122/Fields.php 0000644 00000013543 15213403601 0011244 0 ustar 00 <?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 9562 (formerly RFC 4122) variant UUIDs consist of a set of named fields * * Internally, this class represents the fields together as a 16-byte binary string. * * @immutable */ final class Fields implements FieldsInterface { use MaxTrait; use NilTrait; use SerializableFieldsTrait; use VariantTrait; use VersionTrait; /** * @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 9562 (formerly RFC 4122) UUID * @throws InvalidArgumentException if the byte string does not contain a valid version */ public function __construct(private string $bytes) { if (strlen($this->bytes) !== 16) { throw new InvalidArgumentException( 'The byte string must be 16 bytes long; ' . 'received ' . strlen($this->bytes) . ' bytes', ); } if (!$this->isCorrectVariant()) { throw new InvalidArgumentException( 'The byte string received does not conform to the RFC 9562 (formerly RFC 4122) variant', ); } if (!$this->isCorrectVersion()) { throw new InvalidArgumentException( 'The byte string received does not contain a valid RFC 9562 (formerly RFC 4122) version', ); } } /** * @pure */ public function getBytes(): string { return $this->bytes; } public function getClockSeq(): Hexadecimal { if ($this->isMax()) { $clockSeq = 0xffff; } elseif ($this->isNil()) { $clockSeq = 0x0000; } else { $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 timestamp * fidelity, for version 2 UUIDs. The timestamp can be off by a range of 0 to 429.4967295 seconds (or 7 minutes, 9 * seconds, and 496,730 microseconds). * * For version 6 UUIDs, the timestamp order is reversed from the typical RFC 9562 (formerly 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 { return new Hexadecimal(match ($this->getVersion()) { Uuid::UUID_TYPE_DCE_SECURITY => sprintf( '%03x%04s%08s', hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, $this->getTimeMid()->toString(), '' ), Uuid::UUID_TYPE_REORDERED_TIME => sprintf( '%08s%04s%03x', $this->getTimeLow()->toString(), $this->getTimeMid()->toString(), hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff ), // The Unix timestamp in version 7 UUIDs is a 48-bit number, but for consistency, we will return a 60-bit // number, padded to the left with zeros. Uuid::UUID_TYPE_UNIX_TIME => sprintf( '%011s%04s', $this->getTimeLow()->toString(), $this->getTimeMid()->toString(), ), default => sprintf( '%03x%04s%08s', hexdec($this->getTimeHiAndVersion()->toString()) & 0x0fff, $this->getTimeMid()->toString(), $this->getTimeLow()->toString() ), }); } public function getVersion(): ?int { if ($this->isNil() || $this->isMax()) { return null; } /** @var int[] $parts */ $parts = unpack('n*', $this->bytes); return $parts[4] >> 12; } private function isCorrectVariant(): bool { if ($this->isNil() || $this->isMax()) { return true; } return $this->getVariant() === Uuid::RFC_4122; } } uuid/src/Rfc4122/NilUuid.php 0000644 00000001204 15213403601 0011376 0 ustar 00 <?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 a special form of UUID that has all 128 bits set to zero (`0`) * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.9 RFC 9562, 5.9. Nil UUID * * @immutable */ final class NilUuid extends Uuid implements UuidInterface { } uuid/src/Rfc4122/Validator.php 0000644 00000002467 15213403601 0011766 0 ustar 00 <?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 9562 (formerly RFC 4122) variant * * @immutable */ final class Validator implements ValidatorInterface { private const VALID_PATTERN = '\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-' . '[1-8][0-9A-Fa-f]{3}-[ABab89][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}\z'; /** * @return non-empty-string */ public function getPattern(): string { return self::VALID_PATTERN; } public function validate(string $uuid): bool { /** @phpstan-ignore possiblyImpure.functionCall */ $uuid = strtolower(str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid)); /** @phpstan-ignore possiblyImpure.functionCall */ return $uuid === Uuid::NIL || $uuid === Uuid::MAX || preg_match('/' . self::VALID_PATTERN . '/Dms', $uuid); } } uuid/src/Rfc4122/VariantTrait.php 0000644 00000005775 15213403601 0012456 0 ustar 00 <?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 str_starts_with; use function strlen; use function substr; use function unpack; use const STR_PAD_LEFT; /** * Provides common functionality for handling the variant, as defined by RFC 9562 (formerly RFC 4122) * * @immutable */ trait VariantTrait { /** * Returns the bytes that comprise the fields */ abstract public function getBytes(): string; /** * 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 9562 (formerly RFC 4122) variant * - 6 - Reserved, Microsoft Corporation backward compatibility * - 7 - Reserved for future definition * * For RFC 9562 (formerly RFC 4122) variant UUIDs, this value should always be the integer `2`. * * @link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 RFC 9562, 4.1. Variant Field */ public function getVariant(): int { if (strlen($this->getBytes()) !== 16) { throw new InvalidBytesException('Invalid number of bytes'); } // According to RFC 9562, sections {@link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 4.1} and // {@link https://www.rfc-editor.org/rfc/rfc9562#section-5.10 5.10}, the Max UUID falls within the range // of the future variant. if ($this->isMax()) { return Uuid::RESERVED_FUTURE; } // According to RFC 9562, sections {@link https://www.rfc-editor.org/rfc/rfc9562#section-4.1 4.1} and // {@link https://www.rfc-editor.org/rfc/rfc9562#section-5.9 5.9}, the Nil UUID falls within the range // of the Apollo NCS variant. if ($this->isNil()) { return Uuid::RESERVED_NCS; } /** @var int[] $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. $msb = substr(str_pad(decbin($parts[5]), 16, '0', STR_PAD_LEFT), 0, 3); if ($msb === '111') { return Uuid::RESERVED_FUTURE; } elseif ($msb === '110') { return Uuid::RESERVED_MICROSOFT; } elseif (str_starts_with($msb, '10')) { return Uuid::RFC_4122; } return Uuid::RESERVED_NCS; } } uuid/src/Rfc4122/UuidV7.php 0000644 00000003770 15213403601 0011162 0 ustar 00 <?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; /** * Unix Epoch time, or version 7, UUIDs include a timestamp in milliseconds since the Unix Epoch, along with random bytes * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.7 RFC 9562, 5.7. UUID Version 7 * * @immutable */ final class UuidV7 extends Uuid implements UuidInterface { use TimeTrait; /** * Creates a version 7 (Unix Epoch time) 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_UNIX_TIME) { throw new InvalidArgumentException( 'Fields used to create a UuidV7 must represent a version 7 (Unix Epoch time) UUID', ); } parent::__construct($fields, $numberConverter, $codec, $timeConverter); } } uuid/src/Rfc4122/UuidV6.php 0000644 00000001400 15213403601 0011145 0 ustar 00 <?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\Nonstandard\UuidV6 as NonstandardUuidV6; /** * Reordered Gregorian time, or version 6, UUIDs include timestamp, clock sequence, and node values that are combined * into a 128-bit unsigned integer * * @link https://www.rfc-editor.org/rfc/rfc9562#section-5.6 RFC 9562, 5.6. UUID Version 6 * * @immutable */ final class UuidV6 extends NonstandardUuidV6 implements UuidInterface { } uuid/src/Math/RoundingMode.php 0000644 00000011455 15213403601 0012276 0 ustar 00 <?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 of 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 { /** * 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; /** * Private constructor. This class is not instantiable. * * @codeCoverageIgnore */ private function __construct() { } } uuid/src/Math/CalculatorInterface.php 0000644 00000007416 15213403601 0013620 0 ustar 00 <?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 * * @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 * * @pure */ 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 * * @pure */ 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 * * @pure */ 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 * * @pure */ 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 * * @pure */ 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 * * @pure */ public function toBase(IntegerObject $value, int $base): string; /** * Converts an Integer instance to a Hexadecimal instance * * @pure */ public function toHexadecimal(IntegerObject $value): Hexadecimal; /** * Converts a Hexadecimal instance to an Integer instance * * @pure */ public function toInteger(Hexadecimal $value): IntegerObject; } uuid/src/Math/BrickMathCalculator.php 0000644 00000011702 15213403601 0013555 0 ustar 00 <?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 * * @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()); } /** @phpstan-ignore possiblyImpure.new */ 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()); } /** @phpstan-ignore possiblyImpure.new */ 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()); } /** @phpstan-ignore possiblyImpure.new */ return new IntegerObject((string) $product); } public function divide( int $roundingMode, int $scale, NumberInterface $dividend, NumberInterface ...$divisors, ): NumberInterface { /** @phpstan-ignore possiblyImpure.methodCall */ $brickRounding = $this->getBrickRoundingMode($roundingMode); $quotient = BigDecimal::of($dividend->toString()); foreach ($divisors as $divisor) { $quotient = $quotient->dividedBy($divisor->toString(), $scale, $brickRounding); } if ($scale === 0) { /** @phpstan-ignore possiblyImpure.new */ return new IntegerObject((string) $quotient->toBigInteger()); } /** @phpstan-ignore possiblyImpure.new */ return new Decimal((string) $quotient); } public function fromBase(string $value, int $base): IntegerObject { try { /** @phpstan-ignore possiblyImpure.new */ 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 { /** @phpstan-ignore possiblyImpure.new */ 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 * * @return BrickMathRounding::* */ private function getBrickRoundingMode(int $roundingMode) { return self::ROUNDING_MODE_MAP[$roundingMode] ?? BrickMathRounding::UNNECESSARY; } }
| ver. 1.4 |
Github
|
.
| PHP 8.2.31 | Generation time: 2.2 |
proxy
|
phpinfo
|
Settings