Función PHP para generar v4 UUID



Answers

En lugar de dividirlo en campos individuales, es más fácil generar un bloque aleatorio de datos y cambiar las posiciones de bytes individuales. También debe usar un generador de números aleatorios mejor que mt_rand ().

De acuerdo con RFC 4122 - Sección 4.4 , necesita cambiar estos campos:

  1. time_hi_and_version (bits 4-7 del 7º octeto),
  2. clock_seq_hi_and_reserved (bit 6 y 7 del noveno octeto)

Todos los otros 122 bits deben ser lo suficientemente aleatorios.

El siguiente enfoque genera 128 bits de datos aleatorios usando openssl_random_pseudo_bytes() , realiza las permutaciones en los octetos y luego utiliza bin2hex() y vsprintf() para realizar el formateo 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));

Con PHP 7, generar secuencias de bytes aleatorias es incluso más simple usando random_bytes() :

echo guidv4(random_bytes(16));
Question

Así que he estado investigando y he intentado reconstruir una función que genera un UUID v4 válido en PHP. Esto es lo más cerca que he podido venir. Mi conocimiento en operadores bit a bit hexadecimales, decimales, binarios, de PHP y similares casi no existe. Esta función genera un UUID v4 válido hasta un área. Un UUID v4 debe tener la forma de:

xxxxxxxx-xxxx- 4 xxx- y xxx-xxxxxxxxxxxx

donde y es 8, 9, A o B. Aquí es donde las funciones fallan ya que no se adhiere a eso.

Esperaba que alguien con más conocimiento que yo en esta área pudiera echarme una mano y ayudarme a arreglar esta función para que se adhiera a esa regla.

La función es la siguiente:

<?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;
}

?>

Gracias a cualquiera que pueda ayudarme.




Si usa CakePHP puede usar su método CakeText::uuid(); de la clase CakeText para generar un uuid RFC4122.




Desde tom, en 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])



Inspirado por la respuesta de broofa here .

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');

O si no puede usar funciones anónimas.

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');



en los sistemas Unix, use el kernel del sistema para generar un uuid para usted.

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

Credit Samveen en https://serverfault.com/a/529319/210994

¡Nota !: ¡Usar este método para obtener un uuid de hecho agota el conjunto de entropía, muy rápidamente! Evitaría usar esto donde se llamaría con frecuencia.




Links