4

Example: Uuid generated from v4 of php : 8bc278cb-2fb6-413b-add6-8ba39bf830e8

I want to convert this into two 64 bit integers.

I've tried using hexdec of php but it's return value is of numbers. I want datatype integer.

Interestingly :

I have tried using hexdec with the above uuid and used this output to dechex. Some how, not getting the same value?

Any insights into this will be appreciated.

riser101
  • 610
  • 6
  • 23
  • Random UUID (v4) has 2^122 combinations in total. While 64bit integer has, well, 2^64 combinations. It doesn't seems possible for the later to contain all possible data in the prior one. – Koala Yeung Oct 05 '16 at 07:37
  • https://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates – Koala Yeung Oct 05 '16 at 07:37
  • [Here](https://stackoverflow.com/questions/56786533/how-to-convert-byte-array-to-float-in-php) is how to convert byte array into float in PHP. – Syed Azhar Abbas Jun 27 '19 at 08:15

2 Answers2

5

UUID is a 128bit data type. Excluding the 6 reserved bits, there are 122 data bits in it. Makes it impossible to fully convert any UUID to a 64bit integer. You'll at least need to store it as 2 64bit numbers or 4 32bit numbers.

You can unpack the UUID into binary, then unpack it as 4 32bit unsigned character:

function uuidToHex($uuid) {
    return str_replace('-', '', $uuid);
}

function hexToUuid($hex) {
    $regex = '/^([\da-f]{8})([\da-f]{4})([\da-f]{4})([\da-f]{4})([\da-f]{12})$/';
    return preg_match($regex, $hex, $matches) ?
        "{$matches[1]}-{$matches[2]}-{$matches[3]}-{$matches[4]}-{$matches[5]}" :
        FALSE;
}

function hexToIntegers($hex) {
    $bin = pack('h*', $hex);
    return unpack('L*', $bin);
}

function integersToHex($integers) {
    $args = $integers; $args[0] = 'L*'; ksort($args);
    $bin = call_user_func_array('pack', $args);
    $results = unpack('h*', $bin);
    return $results[1];
}

$uuid = '1968ec4a-2a73-11df-9aca-00012e27a270';
var_dump($uuid);

$integers = hexToIntegers(uuidToHex('1968ec4a-2a73-11df-9aca-00012e27a270'));
var_dump($integers);

$uuid = hexToUuid(integersToHex($integers));
var_dump($uuid);

It will returns

string(36) "1968ec4a-2a73-11df-9aca-00012e27a270"
array(4) {
  [1]=>
  int(2764998289)
  [2]=>
  int(4245764002)
  [3]=>
  int(268479657)
  [4]=>
  int(120222434)
}
string(36) "1968ec4a-2a73-11df-9aca-00012e27a270"

$integers is an array 4 32bit numbers that represents the hex.

Reference

  1. Stack Overflow: 16 bytes binary form of canonical uuid representation in php
  2. Stack Overflow: How to convert byte array to integer in php?
  3. PHP Manual: pack()
Community
  • 1
  • 1
Koala Yeung
  • 7,475
  • 3
  • 30
  • 50
  • I have tried re-forming the hex from the two 64 bit integers that your function returns. It's not matching ```1968ec4a-2a73-11df-9aca-00012e27a270```. Ideally it should match. – riser101 Oct 05 '16 at 08:31
  • Can you show me the code you use to re-format the 2 64bit integer into hex? – Koala Yeung Oct 05 '16 at 08:37
3

While it's common in other languages (like Java) to get the least significant and most significant bits of a UUID as two unsigned 64-bit integers, PHP has trouble with this because all integers in PHP are signed. Even if using a 64-bit build of PHP, you will run into integer overflows when trying to get a real integer value of the least or most significant bits of a UUID.

The maximum integer value on 64-bit PHP is 9,223,372,036,854,775,807, while an unsigned 64-bit integer has a max value of 18,446,744,073,709,551,615. A UUID as two 64-bit integers needs to support values up to 18,446,744,073,709,551,615.

As an earlier answer mentioned, it might be better to split up the UUID into four unsigned 32-bit integers, if you need to split it up like that. (The max value of an unsigned 32-bit integer is 4,294,967,295, which 64-bit PHP can support.)

If you're simply interested in storing a UUID in a more optimized way, you can convert it to a 16-byte binary string:

$uuid = '1968ec4a-2a73-11df-9aca-00012e27a270';

$binaryUuid = hex2bin(str_replace('-', '', $uuid));
ramsey
  • 608
  • 7
  • 12