drupal/core/includes/uuid.inc

155 lines
3.7 KiB
PHP

<?php
/**
* @file
* Handling of universally unique identifiers.
*/
/**
* Interface that defines a UUID backend.
*/
interface UuidInterface {
/**
* Generates a Universally Unique IDentifier (UUID).
*
* @return
* A 32 byte integer represented as a hex string formatted with 4 hypens.
*/
public function generate();
}
/**
* Factory class for UUIDs.
*
* Determines which UUID implementation to use, and uses that to generate
* and validate UUIDs.
*/
class Uuid {
/**
* Holds the UUID implementation.
*/
protected $plugin;
/**
* This constructor instantiates the correct UUID object.
*/
public function __construct() {
$class = $this->determinePlugin();
$this->plugin = new $class();
}
/**
* Generates an universally unique identifier.
*
* @see UuidInterface::generate()
*/
public function generate() {
return $this->plugin->generate();
}
/**
* Check that a string appears to be in the format of a UUID.
*
* Plugins should not implement validation, since UUIDs should be in a
* consistent format across all plugins.
*
* @param $uuid
* The string to test.
*
* @return
* TRUE if the string is well formed.
*/
public function isValid($uuid) {
return preg_match("/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/", $uuid);
}
/**
* Determines the optimal implementation to use for generating UUIDs.
*
* The selection is made based on the enabled PHP extensions with the
* most performant available option chosen.
*
* @return
* The class name for the optimal UUID generator.
*/
protected function determinePlugin() {
static $plugin;
if (!empty($plugin)) {
return $plugin;
}
$plugin = 'UuidPhp';
// Debian/Ubuntu uses the (broken) OSSP extension as their UUID
// implementation. The OSSP implementation is not compatible with the
// PECL functions.
if (function_exists('uuid_create') && !function_exists('uuid_make')) {
$plugin = 'UuidPecl';
}
// Try to use the COM implementation for Windows users.
elseif (function_exists('com_create_guid')) {
$plugin = 'UuidCom';
}
return $plugin;
}
}
/**
* UUID implementation using the PECL extension.
*/
class UuidPecl implements UuidInterface {
public function generate() {
return uuid_create(UUID_TYPE_DEFAULT);
}
}
/**
* UUID implementation using the Windows internal GUID extension.
*
* @see http://php.net/com_create_guid
*/
class UuidCom implements UuidInterface {
public function generate() {
// Remove {} wrapper and make lower case to keep result consistent.
return drupal_strtolower(trim(com_create_guid(), '{}'));
}
}
/**
* Generates an UUID v4 using PHP code.
*
* Loosely based on Ruby's UUIDTools generate_random logic.
*
* @see http://uuidtools.rubyforge.org/api/classes/UUIDTools/UUID.html
*/
class UuidPhp implements UuidInterface {
public function generate() {
$hex = substr(hash('sha256', drupal_random_bytes(16)), 0, 32);
// The field names refer to RFC 4122 section 4.1.2.
$time_low = substr($hex, 0, 8);
$time_mid = substr($hex, 8, 4);
$time_hi_and_version = base_convert(substr($hex, 12, 4), 16, 10);
$time_hi_and_version &= 0x0FFF;
$time_hi_and_version |= (4 << 12);
$clock_seq_hi_and_reserved = base_convert(substr($hex, 16, 4), 16, 10);
$clock_seq_hi_and_reserved &= 0x3F;
$clock_seq_hi_and_reserved |= 0x80;
$clock_seq_low = substr($hex, 20, 2);
$nodes = substr($hex, 20);
$uuid = sprintf('%s-%s-%04x-%02x%02x-%s',
$time_low, $time_mid,
$time_hi_and_version, $clock_seq_hi_and_reserved,
$clock_seq_low, $nodes);
return $uuid;
}
}