Domanda

Quindi ho scavato un po 'di scatto e ho provato a mettere insieme una funzione che genera un V4 UUID valido in PHP. Questo è il più vicino che sono stato in grado di venire. La mia conoscenza in esadecimazione, decimale, binario, operatori bitwise di PHP e simili sono quasi non esistenti. Questa funzione genera un V4 UUID valido fino a un'area. Un UUID V4 dovrebbe essere sotto forma di:

xxxxxxxx-xxxx-4xxx-yXXX-XXXXXXXXXXXX

dove y è 8, 9, A o B. Questo è dove le funzioni falliscono in quanto non aderisce a questo.

Speravo che qualcuno con più conoscenza di me in quest'area potesse darmi una mano e aiutarmi a sistemare questa funzione in modo che aderisca a quella regola.

La funzione è la seguente:

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

?>

Grazie a chiunque possa aiutarmi.

È stato utile?

Soluzione

Preso da questo Commenta il manuale PHP, potresti usare questo:

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

Altri suggerimenti

Invece di abbatterlo in singoli campi, è più facile generare un blocco casuale di dati e modificare le singole posizioni di byte. Dovresti anche usare un generatore di numeri casuali migliori di MT_rand ().

Secondo RFC 4122 - Sezione 4.4, devi cambiare questi campi:

  1. time_hi_and_version (bit 4-7 del 7 ° ottetto),
  2. clock_seq_hi_and_reserved (bit 6 e 7 del 9 ° ottetto)

Tutti gli altri 122 bit dovrebbero essere sufficientemente casuali.

Il seguente approccio genera 128 bit di dati casuali utilizzando openssl_random_pseudo_bytes(), fa le permutazioni sugli ottetti e quindi usi bin2hex() e vsprintf() per fare la formattazione finale.

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, la generazione di sequenze di byte casuali è ancora più semplice usando random_bytes():

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

Chiunque usi compositore dipendenze, potresti voler considerare questa biblioteca: https://github.com/ramsey/uuid

Non è più facile di questo:

Uuid::uuid4();

Sui sistemi UNIX, usa il kernel del sistema per generare un UUID per te.

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

Credito Samveen https://serverfault.com/a/529319/210994

Nota!: Utilizzare questo metodo per ottenere un UUID in realtà esaurisce la piscina entropia, molto rapidamente! Eviterei di usarlo dove verrebbe chiamato frequentemente.

Nella mia ricerca di una creazione di un V4 UUID, sono venuto prima a questa pagina, poi l'ho trovato su 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));
}

Credito: Pavel.Volyntensev

Modifica: per chiarire, questa funzione ti darà sempre un V4 UUID (PHP> = 5.3.0).

Quando è disponibile la funzione COM_CREATE_GUID (di solito solo su Windows), la userà e spoglia le parentesi graffe.

Se non presente (Linux), ricadrà su questa forte funzione casuale OpenSSL_RANDOM_PSEUDO_BYTE, userà quindi VSPRINTF per formattarla in V4 UUID.

La mia risposta si basa sul commento Commento utente uniqid Ma usa opensssl_random_pseudo_bytes funzione per generare stringa casuale anziché leggere da /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

Se usi CakePHP Puoi usare il loro metodo CakeText::uuid(); dal CakeText Classe per generare un UUID RFC4122.

Ispirato da broofaRisposta qui.

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 se non è in grado di utilizzare funzioni anonime.

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

Avendo cercato la stessa identica cosa e quasi Implementando una versione di questo da solo, ho pensato che valesse la pena menzionarlo, se lo stai facendo all'interno di a WordPress framework, WP ha la sua funzione super pratica esattamente per questo:

$myUUID = wp_generate_uuid4();

Puoi leggere la descrizione e la fonte qui.

Una leggera variazione su La risposta di Jack Per aggiungere supporto per 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));
}

Da Tom, in poi 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])

Che ne dici di usare MySQL per generare l'UUID per te?

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

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

Sono sicuro che esiste un modo più elegante per fare la conversione dal binario a decimale per il 4xxx e yxxx porzioni. Ma se vuoi usare openssl_random_pseudo_bytes Come il tuo generatore di numeri critograficamente sicuro, questo è ciò che 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))
    );
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top