Вход Регистрация
Файл: vendor/ramsey/uuid/src/Generator/UnixTimeGenerator.php
Строк: 234
<?php

/**
 * This file is part of the ramsey/uuid library
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
 * @license http://opensource.org/licenses/MIT MIT
 */

declare(strict_types=1);

namespace 
RamseyUuidGenerator;

use 
BrickMathBigInteger;
use 
DateTimeImmutable;
use 
DateTimeInterface;
use 
RamseyUuidTypeHexadecimal;

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 that combine 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 $dateTime A date-time instance to use when
     *     generating bytes
     *
     * @inheritDoc
     */
    
public function generate($node null, ?int $clockSeq null, ?DateTimeInterface $dateTime null): string
    
{
        
$time = ($dateTime ?? new DateTimeImmutable('now'))->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);
        }

        
/** @var non-empty-string */
        
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 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 of these
     * numbers to get 5 extra 24-bit numbers. Then, we consume those numbers
     * 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.
     *
     * @link https://twitter.com/nicolasgrekas/status/1583356938825261061 Tweet from Nicolas Grekas
     */
    
private function increment(): string
    
{
        if (
self::$seedIndex === && self::$seed !== null) {
            
self::$seed hash('sha512'self::$seedtrue);

            
/** @var int[] $s */
            
$s unpack('l*'self::$seed);
            
$s[] = ($s[1] >> 0xff0000) | ($s[2] >> 16 0xff00) | ($s[3] >> 24 0xff);
            
$s[] = ($s[4] >> 0xff0000) | ($s[5] >> 16 0xff00) | ($s[6] >> 24 0xff);
            
$s[] = ($s[7] >> 0xff0000) | ($s[8] >> 16 0xff00) | ($s[9] >> 24 0xff);
            
$s[] = ($s[10] >> 0xff0000) | ($s[11] >> 16 0xff00) | ($s[12] >> 24 0xff);
            
$s[] = ($s[13] >> 0xff0000) | ($s[14] >> 16 0xff00) | ($s[15] >> 24 0xff);

            
self::$seedParts $s;
            
self::$seedIndex 21;
        }

        
self::$rand[5] = 0xffff $carry self::$rand[5] + + (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 >= || strlen($time) < 10) {
                
$time = (string) ((int) $time 1);
            } elseif (
$mtime === 999999999) {
                
$time = (+ (int) substr($time0, -9)) . '000000000';
            } else {
                
$mtime++;
                
$time substr_replace($timestr_pad((string) $mtime9'0'STR_PAD_LEFT), -9);
            }

            
$this->randomize($time);
        }

        return 
self::$time;
    }
}
Онлайн: 0
Реклама