代码之家  ›  专栏  ›  技术社区  ›  anomareh

生成v4 uuid的php函数

  •  188
  • anomareh  · 技术社区  · 15 年前

    所以我一直在做一些深入的研究,我一直在尝试拼凑一个在PHP中生成有效v4 uuid的函数。这是我能来的最近的一次。我对十六进制、十进制、二进制、PHP的位运算符等的知识几乎是不存在的。此函数在一个区域之前生成一个有效的v4 uuid。v4 uuid的形式应为:

    XXXXXXXX-XXXX XX- Y XXX-XXXXXXXXXXX

    在哪里? 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;
    }
    
    ?>
    

    感谢任何能帮我的人。

    12 回复  |  直到 6 年前
        1
  •  248
  •   William    15 年前

    取自 this 关于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 )
        );
    }
    
        2
  •  310
  •   JaÍ¢ck    10 年前

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

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

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

    其他所有122位都应足够随机。

    下面的方法生成128位随机数据,使用 openssl_random_pseudo_bytes() ,对八位字节进行排列,然后使用 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));
    

    使用php 7,使用 random_bytes() :

    echo guidv4(random_bytes(16));
    
        3
  •  103
  •   Jules    10 年前

    任何人使用 作曲家 依赖项,您可能需要考虑此库: https://github.com/ramsey/uuid

    再简单不过了:

    Uuid::uuid4();
    
        4
  •  16
  •   ThorSummoner    8 年前

    在UNIX系统上,使用系统内核为您生成UUID。

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

    信贷Samveen on https://serverfault.com/a/529319/210994

    注意!:使用这种方法得到一个uuid,实际上会很快地耗尽熵池!我会避免在经常被调用的地方使用这个。

        5
  •  8
  •   Arie    7 年前

    在搜索创建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));
    }
    

    学分:Pavel.Volyntsev

    编辑:为了澄清,此函数将始终为您提供一个v4 uuid(php>=5.3.0)。

    当com-create-guid函数可用时(通常仅在Windows上),它将使用该函数并去掉大括号。

    如果不存在(Linux),它将返回到这个强随机openssl_random_pseudo_bytes函数,然后使用vsprintf将其格式化为v4 uuid。

        6
  •  5
  •   Bill    12 年前

    我的回答是基于评论 uniqid user comment 但它使用 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
    
        7
  •  5
  •   Community CDub    8 年前

    受到启发 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');
    

    或者如果无法使用匿名函数。

    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');
    
        8
  •  2
  •   bish    7 年前

    如果你使用 CakePHP 你可以用他们的方法 CakeText::uuid(); CakeText 类以生成rfc4122 uuid。

        9
  •  1
  •   amgine    12 年前

    来自汤姆 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])
    
        10
  •  1
  •   Hoan Dang    8 年前

    使用mysql为您生成uuid怎么样?

    $conn = new mysqli($servername, $username, $password, $dbname, $port);
    
    $query = 'SELECT UUID()';
    echo $conn->query($query)->fetch_row()[0];
    
        11
  •  1
  •   indextwo    6 年前

    找到了完全相同的东西 几乎 我自己实现了这个版本,我认为值得一提的是,如果你在 文字出版社 框架,wp有它自己的超方便的功能来实现这一点:

    $myUUID = wp_generate_uuid4();

    您可以阅读描述和来源 here .

        12
  •  0
  •   Baracus    6 年前

    我相信有一种更优雅的方法可以将 4xxx yxxx 部分。但是如果你想用 openssl_random_pseudo_bytes 作为你的crytography安全数字生成器,我使用的是:

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