web-dev-qa-db-fra.com

PHP fonction pour générer v4 UUID

J'ai donc fouillé un peu et essayé de rassembler une fonction générant un UUID v4 valide en PHP. C'est le plus proche que j'ai pu venir. Mes connaissances en hexadécimal, décimal, binaire, les opérateurs de bits au format PHP et autres sont presque inexistantes. Cette fonction génère un UUID v4 valide jusqu'à une zone. Un UUID v4 devrait être sous la forme de:

xxxxxxxx-xxxx - 4 xxx - y xxx-xxxxxxxxxxxx

y est égal à 8, 9, A ou B. Les fonctions échouent car elles n'adhèrent pas à cela.

J'espérais que quelqu'un ayant plus de connaissances que moi dans ce domaine pourrait me donner un coup de main et m'aider à réparer cette fonction afin qu'elle respecte cette règle.

La fonction est la suivante:

<?php

function gen_uuid() {
 $uuid = array(
  'time_low'  => 0,
  'time_mid'  => 0,
  'time_hi'  => 0,
  'clock_seq_hi' => 0,
  'clock_seq_low' => 0,
  'node'   => array()
 );

 $uuid['time_low'] = mt_Rand(0, 0xffff) + (mt_Rand(0, 0xffff) << 16);
 $uuid['time_mid'] = mt_Rand(0, 0xffff);
 $uuid['time_hi'] = (4 << 12) | (mt_Rand(0, 0x1000));
 $uuid['clock_seq_hi'] = (1 << 7) | (mt_Rand(0, 128));
 $uuid['clock_seq_low'] = mt_Rand(0, 255);

 for ($i = 0; $i < 6; $i++) {
  $uuid['node'][$i] = mt_Rand(0, 255);
 }

 $uuid = sprintf('%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x',
  $uuid['time_low'],
  $uuid['time_mid'],
  $uuid['time_hi'],
  $uuid['clock_seq_hi'],
  $uuid['clock_seq_low'],
  $uuid['node'][0],
  $uuid['node'][1],
  $uuid['node'][2],
  $uuid['node'][3],
  $uuid['node'][4],
  $uuid['node'][5]
 );

 return $uuid;
}

?>

Merci à tous ceux qui peuvent m'aider.

186
anomareh

Tiré de this commentez le manuel de PHP, vous pouvez utiliser ceci:

function gen_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
        // 32 bits for "time_low"
        mt_Rand( 0, 0xffff ), mt_Rand( 0, 0xffff ),

        // 16 bits for "time_mid"
        mt_Rand( 0, 0xffff ),

        // 16 bits for "time_hi_and_version",
        // four most significant bits holds version number 4
        mt_Rand( 0, 0x0fff ) | 0x4000,

        // 16 bits, 8 bits for "clk_seq_hi_res",
        // 8 bits for "clk_seq_low",
        // two most significant bits holds zero and one for variant DCE1.1
        mt_Rand( 0, 0x3fff ) | 0x8000,

        // 48 bits for "node"
        mt_Rand( 0, 0xffff ), mt_Rand( 0, 0xffff ), mt_Rand( 0, 0xffff )
    );
}
248
William

Au lieu de les décomposer en champs individuels, il est plus facile de générer un bloc de données aléatoire et de modifier les positions des octets individuels. Vous devriez également utiliser un meilleur générateur de nombres aléatoires que mt_Rand ().

Selon RFC 4122 - Section 4.4 , vous devez modifier ces champs:

  1. time_hi_and_version (bits 4 à 7 du 7ème octet),
  2. clock_seq_hi_and_reserved (bits 6 et 7 du 9ème octet)

Les 122 autres bits doivent être suffisamment aléatoires. 

L'approche suivante génère 128 bits de données aléatoires à l'aide de openssl_random_pseudo_bytes() , effectue les permutations sur les octets, puis utilise bin2hex() et vsprintf() pour effectuer le formatage final.

function guidv4($data)
{
    assert(strlen($data) == 16);

    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

echo guidv4(openssl_random_pseudo_bytes(16));

Avec PHP 7, la génération de séquences d’octets aléatoires est encore plus simple avec random_bytes() :

echo guidv4(random_bytes(16));
310
Ja͢ck

Si vous utilisez des dépendances composer, vous pouvez envisager cette bibliothèque: https://github.com/ramsey/uuid

Cela ne devient pas plus facile que cela:

Uuid::uuid4();
102
djule5

sur les systèmes Unix, utilisez le noyau système pour générer un uuid pour vous.

file_get_contents('/proc/sys/kernel/random/uuid')

Crédit Samveen sur https://serverfault.com/a/529319/210994

Note !: L'utilisation de cette méthode pour obtenir un uuid épuise le pool d'entropie très rapidement! Je voudrais éviter d'utiliser ceci où il serait appelé fréquemment. 

16
ThorSummoner

Dans ma recherche d’une création de vuid u4, j’ai commencé par cette page, puis j’ai trouvé ceci sur http://php.net/manual/fr/function.com-create-guid.php

function guidv4()
{
    if (function_exists('com_create_guid') === true)
        return trim(com_create_guid(), '{}');

    $data = openssl_random_pseudo_bytes(16);
    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

crédit: pavel.volyntsev

Edit: pour clarifier, cette fonction vous donnera toujours un uuid v4 (PHP> = 5.3.0).

Lorsque la fonction com_create_guid est disponible (généralement sous Windows), elle l'utilise et supprime les accolades.

S'il n'est pas présent (Linux), il aura recours à cette fonction aléatoire fort openssl_random_pseudo_bytes, il utilisera ensuite vsprintf pour le formater en v4 uuid.

8
Arie

Inspiré par la réponse de broofa _ { ici _.

preg_replace_callback('/[xy]/', function ($matches)
{
  return dechex('x' == $matches[0] ? mt_Rand(0, 15) : (mt_Rand(0, 15) & 0x3 | 0x8));
}
, 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx');

Ou si impossible d'utiliser des fonctions anonymes.

preg_replace_callback('/[xy]/', create_function(
  '$matches',
  'return dechex("x" == $matches[0] ? mt_Rand(0, 15) : (mt_Rand(0, 15) & 0x3 | 0x8));'
)
, 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx');
5
MichaelRushton

Ma réponse est basée sur comment commentaire utilisateur uniqid mais il utilise openssl_random_pseudo_bytes function pour générer une chaîne aléatoire au lieu de lire /dev/urandom

function guid()
{
    $randomString = openssl_random_pseudo_bytes(16);
    $time_low = bin2hex(substr($randomString, 0, 4));
    $time_mid = bin2hex(substr($randomString, 4, 2));
    $time_hi_and_version = bin2hex(substr($randomString, 6, 2));
    $clock_seq_hi_and_reserved = bin2hex(substr($randomString, 8, 2));
    $node = bin2hex(substr($randomString, 10, 6));

    /**
     * Set the four most significant bits (bits 12 through 15) of the
     * time_hi_and_version field to the 4-bit version number from
     * Section 4.1.3.
     * @see http://tools.ietf.org/html/rfc4122#section-4.1.3
    */
    $time_hi_and_version = hexdec($time_hi_and_version);
    $time_hi_and_version = $time_hi_and_version >> 4;
    $time_hi_and_version = $time_hi_and_version | 0x4000;

    /**
     * Set the two most significant bits (bits 6 and 7) of the
     * clock_seq_hi_and_reserved to zero and one, respectively.
     */
    $clock_seq_hi_and_reserved = hexdec($clock_seq_hi_and_reserved);
    $clock_seq_hi_and_reserved = $clock_seq_hi_and_reserved >> 2;
    $clock_seq_hi_and_reserved = $clock_seq_hi_and_reserved | 0x8000;

    return sprintf('%08s-%04s-%04x-%04x-%012s', $time_low, $time_mid, $time_hi_and_version, $clock_seq_hi_and_reserved, $node);
} // guid
5
Victor Smirnov

Si vous utilisez CakePHP, vous pouvez utiliser leur méthode CakeText::uuid(); à partir de CakeText class pour générer un RFU4122 uuid.

2
bish

Une légère variation sur La réponse de Jack pour ajouter le support pour PHP <7:

// Get an RFC-4122 compliant globaly unique identifier
function get_guid() {
    $data = PHP_MAJOR_VERSION < 7 ? openssl_random_pseudo_bytes(16) : random_bytes(16);
    $data[6] = chr(ord($data[6]) & 0x0f | 0x40);    // Set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80);    // Set bits 6-7 to 10
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
1
Danny Beckett

Pourquoi ne pas utiliser mysql pour générer l'uuid pour vous?

$conn = new mysqli($servername, $username, $password, $dbname, $port);

$query = 'SELECT UUID()';
echo $conn->query($query)->fetch_row()[0];
1
Hoan

De tom, sur http://www.php.net/manual/en/function.uniqid.php

$r = unpack('v*', fread(fopen('/dev/random', 'r'),16));
$uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
    $r[1], $r[2], $r[3], $r[4] & 0x0fff | 0x4000,
    $r[5] & 0x3fff | 0x8000, $r[6], $r[7], $r[8])
1
amgine

Je suis sûr qu'il existe un moyen plus élégant de convertir les valeurs binaires en décimales pour les portions 4xxx et yxxx. Mais si vous voulez utiliser openssl_random_pseudo_bytes comme générateur de nombre sécurisé sur le plan de la cryptographie, voici ce que j’utilise:

return sprintf('%s-%s-%04x-%04x-%s',
    bin2hex(openssl_random_pseudo_bytes(4)),
    bin2hex(openssl_random_pseudo_bytes(2)),
    hexdec(bin2hex(openssl_random_pseudo_bytes(2))) & 0x0fff | 0x4000,
    hexdec(bin2hex(openssl_random_pseudo_bytes(2))) & 0x3fff | 0x8000,
    bin2hex(openssl_random_pseudo_bytes(6))
    );
0
Baracus