PHP函数生成v4 UUID

ano*_*reh 215 php uuid function

所以我一直在做一些挖掘,我一直在努力拼凑一个在PHP中生成有效的v4 UUID的函数.这是我能够来的最接近的.我在十六进制,十进制,二进制,PHP的按位运算符等方面的知识几乎不存在.此函数生成有效的v4 UUID直到一个区域.v4 UUID应采用以下形式:

xxxxxxxx-xxxx- 4 xxx- y xxx-xxxxxxxxxxxx

其中y 是8,9,A或B.这是函数失败的地方,因为它不符合它.

我希望在这个领域有比我更多知识的人可以帮助我解决这个问题并帮助我解决这个问题.

功能如下:

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

?>
Run Code Online (Sandbox Code Playgroud)

感谢任何可以帮助我的人.

Ja͢*_*͢ck 345

不是将其分解为单个字段,而是更容易生成随机数据块并更改单个字节位置.您还应该使用比mt_rand()更好的随机数生成器.

根据RFC 4122 - 第4.4节,您需要更改这些字段:

  1. time_hi_and_version (第7个八位字节的4-7位),
  2. clock_seq_hi_and_reserved (第9个八位字节的第6和第7位)

所有其他122位应该足够随机.

以下方法使用openssl_random_pseudo_bytes(),生成128位随机数据,在八位字节上进行排列,然后使用bin2hex()vsprintf()进行最终格式化.

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));
Run Code Online (Sandbox Code Playgroud)

使用PHP 7,生成随机字节序列甚至更简单random_bytes():

function guidv4($data = null)
{
    $data = $data ?? random_bytes(16);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

  • 对于没有openssl扩展名的*nix用户的替代方法:`$ data = file_get_contents('/ dev/urandom',NULL,NULL,0,16);` (9认同)
  • 有没有理由不将random_bytes(16)调用放在guidv4函数中,因此不必将任何参数传递给guidv4? (8认同)
  • 另外,我会比mt_rand更信任OpenSSL. (5认同)
  • 小改进:为$ data设置NULL默认值,然后函数的第一行是:`$ data = $ data ?? random_bytes(16);`现在您可以指定自己的随机数据源,或让函数为您执行此操作.:-) (5认同)
  • @BrunoAugusto它是随机的,并且极不可能(有一个好的随机源)来获得重复,但在数据库级别强制执行它是一个很好的做法. (2认同)

Wil*_*iam 263

从这关于PHP手册的评论中,您可以使用:

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 )
    );
}
Run Code Online (Sandbox Code Playgroud)

  • 此函数**将创建重复项,因此在需要唯一值时请避免使用它.请注意,给定相同的种子,mt_rand()将始终生成相同的随机数序列.因此,每次重复种子时,都会生成相同的UUID.为了解决这个问题,你需要使用时间和mac地址来播种它,但是我不知道你会怎么做,因为mt_srand()需要一个整数. (40认同)
  • @PavlePredic mt_srand(crc32(serialize([microtime(true),'USER_IP','ETC']))); (我是另一个威廉:P) (12认同)
  • PHP文档明确警告mt_rand()不会生成加密安全值.换句话说,由此函数生成的值可以是可预测的.如果您需要确保UUID不可预测,您应该使用下面的Jack解决方案,该解决方案使用openssl_random_pseudo_bytes()函数. (12认同)
  • 如果用垃圾填满每个字段,那么生成UUID的关键是什么呢? (6认同)
  • PHP 7.0+ 定义了函数 random_bytes() ,它将始终生成加密安全的随机字节,如果无法生成,则抛出异常。这甚至比 openssl_random_psuedo_bytes() 更好,后者的输出在某些情况下有时不加密安全。 (3认同)

dju*_*le5 110

任何使用作曲家依赖关系的人,您可能想要考虑这个库:https://github.com/ramsey/uuid

它没有比这更容易:

Uuid::uuid4();
Run Code Online (Sandbox Code Playgroud)

  • 哦,我不知道....五行代码与加载具有依赖项的库相比?我更喜欢杰克的功能.因人而异 (23认同)
  • UUID不只是随机字符串.它的工作原理有一个规范.为了生成一个适当的随机UUID,我不必担心以后会被拒绝,我宁愿使用一个经过测试的库,而不是使用自己的实现. (16认同)
  • +1给斯蒂芬.Ramsey uuid比uuid4具有更多功能.我不是香蕉!在这里你有整个丛林! (6认同)
  • 这是一个UUIDv4。它是随机的(大多数情况下,但有一点点)。这不是密码学。反对“自己动手”的偏执是愚蠢的。 (3认同)
  • 使用该库的开销是不存在的,并且它有*测试*。+1表示没有重新发明轮子。 (2认同)

Tho*_*ner 19

在unix系统上,使用系统内核为您生成一个uuid.

file_get_contents('/proc/sys/kernel/random/uuid')
Run Code Online (Sandbox Code Playgroud)

来自https://serverfault.com/a/529319/210994的 Samveen信用卡

注意!:使用这种方法得到一个uuid确实耗尽了熵池,非常快!我会避免在频繁调用的地方使用它.

  • 除了可移植性之外,请注意随机源是`/ dev/random`,如果熵池耗尽则会阻塞. (2认同)

Dan*_*ett 12

Jack添加对 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));
}
Run Code Online (Sandbox Code Playgroud)


Cri*_*sco 12

// php version >= 7
$uuid = vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex(random_bytes(16)), 4));
Run Code Online (Sandbox Code Playgroud)

  • 请在您的代码中添加解释,以帮助其他人理解它的作用。 (3认同)
  • 它是否正确?快速测试返回“c0a062b7-b225-c294-b8a0-06b98931a45b”,它与 xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 不匹配。它返回 ac 而不是 4。 (2认同)

Ari*_*rie 9

在我寻找创建v4 uuid的过程中,我首先来到这个页面,然后在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));
}
Run Code Online (Sandbox Code Playgroud)

credit:pavel.volyntsev

编辑:澄清一下,这个函数总会给你一个v4 uuid(PHP> = 5.3.0).

当com_create_guid函数可用时(通常仅在Windows上),它将使用它并去除花括号.

如果不存在(Linux),它将依赖于这个强大的随机openssl_random_pseudo_bytes函数,然后它将使用vsprintf将其格式化为v4 uuid.


Ser*_*huk 6

使用Symfony Polyfill / Uuid
然后你可以生成 uuid 作为本机 php 函数:

$uuid = uuid_create(UUID_TYPE_RANDOM);
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请阅读官方 Symfony blop 帖子 - https://symfony.com/blog/introducing-the-new-symfony-uuid-polyfill

  • uuid_create(UUID_TYPE_TIME) 以包含日期。注意:这给出了真实的 UUID,而不是假的 (2认同)

小智 6

适用于 PHP >= 7 的加密安全 UUID v4。

<?php

function uuid4() {
    /* 32 random HEX + space for 4 hyphens */
    $out = bin2hex(random_bytes(18));

    $out[8]  = "-";
    $out[13] = "-";
    $out[18] = "-";
    $out[23] = "-";

    /* UUID v4 */
    $out[14] = "4";
    
    /* variant 1 - 10xx */
    $out[19] = ["8", "9", "a", "b"][random_int(0, 3)];

    return $out;
}

echo uuid4();
Run Code Online (Sandbox Code Playgroud)

输出:c68469d2-065b-4b17-b36f-5c40efb5f6cd


Vic*_*nov 5

我的回答是基于评论uniqid用户评论,但它使用openssl_random_pseudo_bytes函数生成随机字符串而不是从/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
Run Code Online (Sandbox Code Playgroud)


bis*_*ish 5

如果你使用CakePHP,你可以用自己的方法CakeText::uuid();CakeText类来生成一个RFC4122 UUID。