PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / vendor / ramsey / uuid / src / Generator / UnixTimeGenerator.php

UnixTimeGenerator.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at vendor/ramsey/uuid/src/Generator/UnixTimeGenerator.php

166 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * This file is part of the ramsey/uuid library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <[email protected]>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13 declare(strict_types=1);
14
15 namespace Ramsey\Uuid\Generator;
16
17 use Brick\Math\BigInteger;
18 use DateTimeInterface;
19 use Ramsey\Uuid\Type\Hexadecimal;
20
21 use function assert;
22 use function hash;
23 use function pack;
24 use function str_pad;
25 use function strlen;
26 use function substr;
27 use function substr_replace;
28 use function unpack;
29
30 use const PHP_INT_SIZE;
31 use const STR_PAD_LEFT;
32
33 /**
34 * UnixTimeGenerator generates bytes, combining a 48-bit timestamp in milliseconds since the Unix Epoch with 80 random bits
35 *
36 * Code and concepts within this class are borrowed from the symfony/uid package and are used under the terms of the MIT
37 * license distributed with symfony/uid.
38 *
39 * symfony/uid is copyright (c) Fabien Potencier.
40 *
41 * @link https://symfony.com/components/Uid Symfony Uid component
42 * @link https://github.com/symfony/uid/blob/4f9f537e57261519808a7ce1d941490736522bbc/UuidV7.php Symfony UuidV7 class
43 * @link https://github.com/symfony/uid/blob/6.2/LICENSE MIT License
44 */
45 class UnixTimeGenerator implements TimeGeneratorInterface
46 {
47 private static string $time = '';
48 private static ?string $seed = null;
49 private static int $seedIndex = 0;
50
51 /** @var int[] */
52 private static array $rand = [];
53
54 /** @var int[] */
55 private static array $seedParts;
56
57 public function __construct(
58 private RandomGeneratorInterface $randomGenerator,
59 private int $intSize = PHP_INT_SIZE,
60 ) {
61 }
62
63 /**
64 * @param Hexadecimal | int | string | null $node Unused in this generator
65 * @param int | null $clockSeq Unused in this generator
66 * @param DateTimeInterface | null $dateTime A date-time instance to use when generating bytes
67 */
68 public function generate($node = null, ?int $clockSeq = null, ?DateTimeInterface $dateTime = null): string
69 {
70 if ($dateTime === null) {
71 $time = microtime(false);
72 $time = substr($time, 11) . substr($time, 2, 3);
73 } else {
74 $time = $dateTime->format('Uv');
75 }
76
77 if ($time > self::$time || ($dateTime !== null && $time !== self::$time)) {
78 $this->randomize($time);
79 } else {
80 $time = $this->increment();
81 }
82
83 if ($this->intSize >= 8) {
84 $time = substr(pack('J', (int) $time), -6);
85 } else {
86 $time = str_pad(BigInteger::of($time)->toBytes(false), 6, "\x00", STR_PAD_LEFT);
87 }
88
89 assert(strlen($time) === 6);
90
91 return $time . pack('n*', self::$rand[1], self::$rand[2], self::$rand[3], self::$rand[4], self::$rand[5]);
92 }
93
94 private function randomize(string $time): void
95 {
96 if (self::$seed === null) {
97 $seed = $this->randomGenerator->generate(16);
98 self::$seed = $seed;
99 } else {
100 $seed = $this->randomGenerator->generate(10);
101 }
102
103 /** @var int[] $rand */
104 $rand = unpack('n*', $seed);
105 $rand[1] &= 0x03ff;
106
107 self::$rand = $rand;
108 self::$time = $time;
109 }
110
111 /**
112 * Special thanks to Nicolas Grekas (<https://github.com/nicolas-grekas>) for sharing the following information:
113 *
114 * Within the same ms, we increment the rand part by a random 24-bit number.
115 *
116 * Instead of getting this number from random_bytes(), which is slow, we get it by sha512-hashing self::$seed. This
117 * produces 64 bytes of entropy, which we need to split in a list of 24-bit numbers. `unpack()` first splits them
118 * into 16 x 32-bit numbers; we take the first byte of each number to get 5 extra 24-bit numbers. Then, we consume
119 * each number one-by-one and run this logic every 21 iterations.
120 *
121 * `self::$rand` holds the random part of the UUID, split into 5 x 16-bit numbers for x86 portability. We increment
122 * this random part by the next 24-bit number in the `self::$seedParts` list and decrement `self::$seedIndex`.
123 */
124 private function increment(): string
125 {
126 if (self::$seedIndex === 0 && self::$seed !== null) {
127 self::$seed = hash('sha512', self::$seed, true);
128
129 /** @var int[] $s */
130 $s = unpack('l*', self::$seed);
131 $s[] = ($s[1] >> 8 & 0xff0000) | ($s[2] >> 16 & 0xff00) | ($s[3] >> 24 & 0xff);
132 $s[] = ($s[4] >> 8 & 0xff0000) | ($s[5] >> 16 & 0xff00) | ($s[6] >> 24 & 0xff);
133 $s[] = ($s[7] >> 8 & 0xff0000) | ($s[8] >> 16 & 0xff00) | ($s[9] >> 24 & 0xff);
134 $s[] = ($s[10] >> 8 & 0xff0000) | ($s[11] >> 16 & 0xff00) | ($s[12] >> 24 & 0xff);
135 $s[] = ($s[13] >> 8 & 0xff0000) | ($s[14] >> 16 & 0xff00) | ($s[15] >> 24 & 0xff);
136
137 self::$seedParts = $s;
138 self::$seedIndex = 21;
139 }
140
141 self::$rand[5] = 0xffff & $carry = self::$rand[5] + 1 + (self::$seedParts[self::$seedIndex--] & 0xffffff);
142 self::$rand[4] = 0xffff & $carry = self::$rand[4] + ($carry >> 16);
143 self::$rand[3] = 0xffff & $carry = self::$rand[3] + ($carry >> 16);
144 self::$rand[2] = 0xffff & $carry = self::$rand[2] + ($carry >> 16);
145 self::$rand[1] += $carry >> 16;
146
147 if (0xfc00 & self::$rand[1]) {
148 $time = self::$time;
149 $mtime = (int) substr($time, -9);
150
151 if ($this->intSize >= 8 || strlen($time) < 10) {
152 $time = (string) ((int) $time + 1);
153 } elseif ($mtime === 999999999) {
154 $time = (1 + (int) substr($time, 0, -9)) . '000000000';
155 } else {
156 $mtime++;
157 $time = substr_replace($time, str_pad((string) $mtime, 9, '0', STR_PAD_LEFT), -9);
158 }
159
160 $this->randomize($time);
161 }
162
163 return self::$time;
164 }
165 }
166