Pregunta

Así que he estado cavando un poco y he estado tratando de armar una función que genera un UUID V4 válido en PHP. Este es lo más cerca que he podido llegar. Mi conocimiento en los operadores bit a bit a hexadecimal, decimales, binarios, de PHP y similares es casi inexistente. Esta función genera un UUID V4 válido hasta un área. Un uuid v4 debe estar en forma de:

xxxxxxxx-xxxx-4xxx-Yxxx-xxxxxxxxxxxx

dónde 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.

¿Fue útil?

Solución

Tomado de este Comenta sobre el manual de PHP, puedes usar esto:

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

Otros consejos

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 mejor generador de números aleatorios que MT_RAND ().

De acuerdo a RFC 4122 - Sección 4.4, necesitas cambiar estos campos:

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

Todos los otros 122 bits deben ser suficientemente aleatorios.

El siguiente enfoque genera 128 bits de datos aleatorios utilizando openssl_random_pseudo_bytes(), hace las permutaciones en los octetos y luego usa bin2hex() y vsprintf() Para hacer el formato 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 aún más simple usando random_bytes():

function guidv4($data = null)
{
    $data = $data ?? random_bytes(16);
    // ...
}

Cualquiera que use compositor dependencias, es posible que desee considerar esta biblioteca: https://github.com/ramsey/uuid

No es más fácil que esto:

Uuid::uuid4();

En los sistemas UNIX, use el núcleo del sistema para generar un UUID para usted.

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

Crédito samble https://serverfault.com/a/529319/210994

¡NOTA!: ¡Uso de este método para obtener un UUID hace que el grupo de entropía, muy rápidamente! Evitaría usar esto donde se llamaría con frecuencia.

En mi búsqueda de una creación de un UUID V4, llegué primero a esta página, luego encontré esto en http://php.net/manual/en/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édito: pavel.volyntsev

Editar: Para aclarar, esta función siempre le dará un UUID V4 (PHP> = 5.3.0).

Cuando la función COM_CREATE_GUID está disponible (generalmente solo en Windows), lo usará y despojará los aparatos ortopédicos.

Si no está presente (Linux), recurrirá a esta fuerte función OpenSSL_RANDOM_PSEUDO_BYTES, usará VSPRINTF para formatearlo en V4 UUID.

Mi respuesta se basa en el comentario comentario de usuario uniqid Pero usa openssl_random_pseudo_bytes función para generar cadenas aleatorias en lugar de leer desde /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

Si utiliza CakePHP puedes usar su método CakeText::uuid(); desde el Caketeexto clase para generar un UUID RFC4122.

Inspirado por broofaRespuesta aquí.

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

Habiendo buscado exactamente lo mismo y casi Implementando una versión de esto yo mismo, pensé que valía la pena mencionar que, si lo estás haciendo dentro de un WordPress Framework, WP tiene su propia función súper diestra para exactamente esto:

$myUUID = wp_generate_uuid4();

Puedes leer la descripción y la fuente aquí.

Una ligera variación de La respuesta de Jack Para agregar soporte para 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));
}

De 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])

¿Qué tal usar MySQL para generar el UUID para usted?

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

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

Estoy seguro de que hay una forma más elegante de hacer la conversión de binario a decimal para el 4xxx y yxxx porciones. Pero si quieres usar openssl_random_pseudo_bytes Como su generador de números crytográficamente seguro, esto es lo que uso:

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))
    );
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top