diff --git a/lib/setuplib.php b/lib/setuplib.php index d18e809efb8..1f5e69fc0bd 100644 --- a/lib/setuplib.php +++ b/lib/setuplib.php @@ -610,25 +610,25 @@ function get_exception_info($ex) { } /** - * Generate a uuid. + * Generate a V4 UUID. * - * Unique is hard. Very hard. Attempt to use the PECL UUID functions if available, and if not then revert to + * Unique is hard. Very hard. Attempt to use the PECL UUID function if available, and if not then revert to * constructing the uuid using mt_rand. * * It is important that this token is not solely based on time as this could lead * to duplicates in a clustered environment (especially on VMs due to poor time precision). * + * @see https://tools.ietf.org/html/rfc4122 + * * @return string The uuid. */ function generate_uuid() { $uuid = ''; - if (function_exists("uuid_create")) { - $context = null; - uuid_create($context); - - uuid_make($context, UUID_MAKE_V4); - uuid_export($context, UUID_FMT_STR, $uuid); + // Check if PECL UUID extension is available. + if (function_exists('uuid_time')) { + // Create a V4 UUID. + $uuid = uuid_create(UUID_TYPE_RANDOM); } else { // Fallback uuid generation based on: // "http://www.php.net/manual/en/function.uniqid.php#94959". diff --git a/lib/tests/setuplib_test.php b/lib/tests/setuplib_test.php index e38124e6ad7..e51a7335f03 100644 --- a/lib/tests/setuplib_test.php +++ b/lib/tests/setuplib_test.php @@ -476,4 +476,30 @@ class core_setuplib_testcase extends advanced_testcase { public function test_get_real_size($input, $expectedbytes) { $this->assertEquals($expectedbytes, get_real_size($input)); } + + /** + * Validate the given V4 UUID. + * + * @param string $value The candidate V4 UUID + * @return bool True if valid; otherwise, false. + */ + protected static function is_valid_uuid_v4($value) { + // Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-Yxxx-xxxxxxxxxxxx + // where x is any hexadecimal digit and Y is one of 8, 9, aA, or bB. + // First, the size is 36 (32 + 4 dashes). + if (strlen($value) != 36) { + return false; + } + // Finally, check the format. + $uuidv4pattern = '/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i'; + return (preg_match($uuidv4pattern, $value) === 1); + } + + /** + * Test the generate_uuid() function. + */ + public function test_generate_uuid() { + $uuid = generate_uuid(); + $this->assertTrue(self::is_valid_uuid_v4($uuid), "Invalid v4 UUID: '$uuid'"); + } }