|
|
|
|
@ -16,14 +16,14 @@ namespace CodeHydrater; |
|
|
|
|
*/ |
|
|
|
|
class uuidv7 { |
|
|
|
|
|
|
|
|
|
public static function base32EncodedUUID(): string { |
|
|
|
|
public static function base32_encoded_UUIDv7(): string { |
|
|
|
|
$uuid = self::generateUUIDv7(); |
|
|
|
|
$uuidHex = str_replace('-', '', $uuid); |
|
|
|
|
return self::base32Encode($uuidHex); |
|
|
|
|
return self::base32_encode($uuidHex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function generateUUIDv7(): string { |
|
|
|
|
$timestamp = microtime(true) * 10000; // current timestamp in milliseconds |
|
|
|
|
$timestamp = (int)(microtime(true) * 1000); // Real Unix milliseconds |
|
|
|
|
$timeHex = str_pad(dechex((int)$timestamp), 12, '0', STR_PAD_LEFT); |
|
|
|
|
|
|
|
|
|
$randomHex = bin2hex(random_bytes(10)); |
|
|
|
|
@ -32,13 +32,17 @@ class uuidv7 { |
|
|
|
|
'%s-%s-%s-%s-%s', |
|
|
|
|
substr($timeHex, 0, 8), |
|
|
|
|
substr($timeHex, 8, 4), |
|
|
|
|
'7' . substr($timeHex, 12, 3) . substr($randomHex, 0, 1), // UUIDv7 |
|
|
|
|
substr($randomHex, 1, 4), |
|
|
|
|
substr($randomHex, 5, 12) |
|
|
|
|
'7' . substr($randomHex, 0, 3), // UUIDv7 |
|
|
|
|
substr($randomHex, 3, 4), |
|
|
|
|
substr($randomHex, 7, 12) |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function base32Encode(string $hex): string { |
|
|
|
|
/** |
|
|
|
|
* NOTE: the absence of O like Orange and I like Internet, so |
|
|
|
|
* Zero and One are present but not IO... |
|
|
|
|
*/ |
|
|
|
|
public static function base32_encode(string $hex): string { |
|
|
|
|
$base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; |
|
|
|
|
$binary = ''; |
|
|
|
|
|
|
|
|
|
@ -56,13 +60,60 @@ class uuidv7 { |
|
|
|
|
return $base32; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function base32_decode(string $base32): string { |
|
|
|
|
$base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; |
|
|
|
|
$binary = ''; |
|
|
|
|
|
|
|
|
|
// Convert each base32 character to 5-bit binary |
|
|
|
|
foreach (str_split(strtoupper($base32)) as $char) { |
|
|
|
|
$pos = strpos($base32Chars, $char); |
|
|
|
|
if ($pos === false) { |
|
|
|
|
throw new InvalidArgumentException("Invalid base32 character: $char"); |
|
|
|
|
} |
|
|
|
|
$binary .= str_pad(decbin($pos), 5, '0', STR_PAD_LEFT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Split binary string into 4-bit chunks and convert to hex |
|
|
|
|
$hex = ''; |
|
|
|
|
foreach (str_split($binary, 4) as $chunk) { |
|
|
|
|
// Skip incomplete chunks at the end (padding) |
|
|
|
|
if (strlen($chunk) < 4) break; |
|
|
|
|
$hex .= dechex(bindec($chunk)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $hex; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function get_timestamp_from_UUIDv7(string $uuid): int { |
|
|
|
|
// Remove hyphens and extract the time parts |
|
|
|
|
$cleaned = str_replace('-', '', $uuid); |
|
|
|
|
|
|
|
|
|
// Reconstruct the full 12-character timestamp hex |
|
|
|
|
$timeHex = |
|
|
|
|
substr($cleaned, 0, 8) . // First 8 chars (time_low) |
|
|
|
|
substr($cleaned, 8, 4); // Next 4 chars (time_mid) |
|
|
|
|
|
|
|
|
|
// Convert to decimal (custom scaled time) |
|
|
|
|
$customTime = hexdec($timeHex); |
|
|
|
|
|
|
|
|
|
// Reverse the scaling: divide by 1000 to get seconds |
|
|
|
|
$unixSeconds = (int)($customTime / 1000); |
|
|
|
|
|
|
|
|
|
return $unixSeconds; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static function get_formated_date(int $timestamp) { |
|
|
|
|
return date('Y-m-d H:i:s', $timestamp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @example Database SQL: |
|
|
|
|
CREATE TABLE test_table ( |
|
|
|
|
id CHAR(36) PRIMARY KEY, |
|
|
|
|
name VARCHAR(255) NOT NULL, |
|
|
|
|
id CHAR(36) PRIMARY KEY, -- IMPORTANT PART, to use generateUUIDv7 (UUIDv7) |
|
|
|
|
-- OR CHAR(26) for base32_encoded_UUIDv7 (BASE32 UUIDv7)... |
|
|
|
|
name VARCHAR(255) NOT NULL, -- BLA BLA |
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
|
|
|
|
); |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |