diff --git a/src/Symfony/Component/Uid/Tests/UlidTest.php b/src/Symfony/Component/Uid/Tests/UlidTest.php index 9a8ee9a78abe..50801a840c32 100644 --- a/src/Symfony/Component/Uid/Tests/UlidTest.php +++ b/src/Symfony/Component/Uid/Tests/UlidTest.php @@ -26,11 +26,16 @@ public function testGenerate() { $a = new Ulid(); $b = new Ulid(); + usleep(-10000); + $c = new Ulid(); $this->assertSame(0, strncmp($a, $b, 20)); + $this->assertSame(0, strncmp($a, $c, 20)); $a = base_convert(strtr(substr($a, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); $b = base_convert(strtr(substr($b, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); + $c = base_convert(strtr(substr($c, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); $this->assertSame(1, $b - $a); + $this->assertSame(1, $c - $b); } public function testWithInvalidUlid() diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index a23481612745..bda82ef6856c 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -137,7 +137,7 @@ public function getDateTime(): \DateTimeImmutable } if (4 > \strlen($time)) { - $time = str_pad($time, 4, '0', \STR_PAD_LEFT); + $time = '000'.$time; } return \DateTimeImmutable::createFromFormat('U.u', substr_replace($time, '.', -3, 0)); @@ -145,25 +145,15 @@ public function getDateTime(): \DateTimeImmutable public static function generate(\DateTimeInterface $time = null): string { - if (null === $time) { - return self::doGenerate(); - } - - if (0 > $time = substr($time->format('Uu'), 0, -3)) { - throw new \InvalidArgumentException('The timestamp must be positive.'); - } - - return self::doGenerate($time); - } - - private static function doGenerate(string $mtime = null): string - { - if (null === $time = $mtime) { + if (null === $mtime = $time) { $time = microtime(false); $time = substr($time, 11).substr($time, 2, 3); + } elseif (0 > $time = $time->format('Uv')) { + throw new \InvalidArgumentException('The timestamp must be positive.'); } - if ($time !== self::$time) { + if ($time > self::$time || (null !== $mtime && $time !== self::$time)) { + randomize: $r = unpack('nr1/nr2/nr3/nr4/nr', random_bytes(10)); $r['r1'] |= ($r['r'] <<= 4) & 0xF0000; $r['r2'] |= ($r['r'] <<= 4) & 0xF0000; @@ -173,19 +163,22 @@ private static function doGenerate(string $mtime = null): string self::$rand = array_values($r); self::$time = $time; } elseif ([0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF] === self::$rand) { - if (null === $mtime) { - usleep(100); + if (\PHP_INT_SIZE >= 8 || 10 > \strlen($time = self::$time)) { + $time = (string) (1 + $time); + } elseif ('999999999' === $mtime = substr($time, -9)) { + $time = (1 + substr($time, 0, -9)).'000000000'; } else { - self::$rand = [0, 0, 0, 0]; + $time = substr_replace($time, str_pad(++$mtime, 9, '0', \STR_PAD_LEFT), -9); } - return self::doGenerate($mtime); + goto randomize; } else { for ($i = 3; $i >= 0 && 0xFFFFF === self::$rand[$i]; --$i) { self::$rand[$i] = 0; } ++self::$rand[$i]; + $time = self::$time; } if (\PHP_INT_SIZE >= 8) {
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: