From f8ed6da4ed7efad8b9c9e493cf8b7400e9aab6f8 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Tue, 3 Oct 2023 19:22:04 +0900 Subject: [PATCH] Support both UUIDv4 and UUIDv7 in Security::getRandomUUID() --- common/framework/Security.php | 26 ++++++++++++++++++++++---- tests/unit/framework/SecurityTest.php | 10 ++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/common/framework/Security.php b/common/framework/Security.php index 42e0457df..014cc90ef 100644 --- a/common/framework/Security.php +++ b/common/framework/Security.php @@ -252,13 +252,31 @@ class Security /** * Generate a random UUID. * + * The code for UUIDv4 is based on https://stackoverflow.com/a/15875555/481206 + * + * @param int $version (4 or 7) * @return string */ - public static function getRandomUUID(): string + public static function getRandomUUID(int $version = 4): string { - $randpool = self::getRandom(16, 'binary'); - $randpool[6] = chr(ord($randpool[6]) & 0x0f | 0x40); - $randpool[8] = chr(ord($randpool[8]) & 0x3f | 0x80); + if ($version === 4) + { + $randpool = self::getRandom(16, 'binary'); + $randpool[6] = chr(ord($randpool[6]) & 0x0f | 0x40); + $randpool[8] = chr(ord($randpool[8]) & 0x3f | 0x80); + } + elseif ($version === 7) + { + $timestamp = microtime(false); + $timestamp = substr(pack('J', (intval(substr($timestamp, -10), 10) * 1000) + intval(substr($timestamp, 2, 3), 10)), -6); + $randpool = $timestamp . self::getRandom(10, 'binary'); + $randpool[6] = chr(ord($randpool[6]) & 0x0f | 0x70); + $randpool[8] = chr(ord($randpool[8]) & 0x3f | 0x80); + } + else + { + throw new Exception('Invalid UUID version: ' . $version); + } return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($randpool), 4)); } diff --git a/tests/unit/framework/SecurityTest.php b/tests/unit/framework/SecurityTest.php index bd2d448cf..f85a22033 100644 --- a/tests/unit/framework/SecurityTest.php +++ b/tests/unit/framework/SecurityTest.php @@ -83,6 +83,16 @@ class SecurityTest extends \Codeception\TestCase\Test { $this->assertRegExp($regex, Rhymix\Framework\Security::getRandomUUID()); } + for ($i = 0; $i < 10; $i++) + { + $this->assertRegExp($regex, Rhymix\Framework\Security::getRandomUUID(4)); + } + + $regex = '/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/'; + for ($i = 0; $i < 10; $i++) + { + $this->assertRegExp($regex, Rhymix\Framework\Security::getRandomUUID(7)); + } } public function testCompareStrings()