Skip to content

Commit ceb7434

Browse files
[Uid] Ensure ULIDs are monotonic even when the time goes backward
1 parent 1f4cfc7 commit ceb7434

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

src/Symfony/Component/Uid/Tests/UlidTest.php

+5
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@ public function testGenerate()
2626
{
2727
$a = new Ulid();
2828
$b = new Ulid();
29+
usleep(-10000);
30+
$c = new Ulid();
2931

3032
$this->assertSame(0, strncmp($a, $b, 20));
33+
$this->assertSame(0, strncmp($a, $c, 20));
3134
$a = base_convert(strtr(substr($a, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10);
3235
$b = base_convert(strtr(substr($b, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10);
36+
$c = base_convert(strtr(substr($c, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10);
3337
$this->assertSame(1, $b - $a);
38+
$this->assertSame(1, $c - $b);
3439
}
3540

3641
public function testWithInvalidUlid()

src/Symfony/Component/Uid/Ulid.php

+4-3
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function getDateTime(): \DateTimeImmutable
137137
}
138138

139139
if (4 > \strlen($time)) {
140-
$time = str_pad($time, 4, '0', \STR_PAD_LEFT);
140+
$time = '000'.$time;
141141
}
142142

143143
return \DateTimeImmutable::createFromFormat('U.u', substr_replace($time, '.', -3, 0));
@@ -149,7 +149,7 @@ public static function generate(\DateTimeInterface $time = null): string
149149
return self::doGenerate();
150150
}
151151

152-
if (0 > $time = substr($time->format('Uu'), 0, -3)) {
152+
if (0 > $time = $time->format('Uv')) {
153153
throw new \InvalidArgumentException('The timestamp must be positive.');
154154
}
155155

@@ -163,7 +163,7 @@ private static function doGenerate(string $mtime = null): string
163163
$time = substr($time, 11).substr($time, 2, 3);
164164
}
165165

166-
if ($time !== self::$time) {
166+
if ($time > self::$time || (null !== $mtime && $time !== self::$time)) {
167167
$r = unpack('nr1/nr2/nr3/nr4/nr', random_bytes(10));
168168
$r['r1'] |= ($r['r'] <<= 4) & 0xF0000;
169169
$r['r2'] |= ($r['r'] <<= 4) & 0xF0000;
@@ -186,6 +186,7 @@ private static function doGenerate(string $mtime = null): string
186186
}
187187

188188
++self::$rand[$i];
189+
$time = self::$time;
189190
}
190191

191192
if (\PHP_INT_SIZE >= 8) {

0 commit comments

Comments
 (0)