Last active
November 15, 2016 15:54
-
-
Save prograhammer/7f7e663f85447c9c6d74 to your computer and use it in GitHub Desktop.
80-bit sequential unique identifier (as opposed to a 128-bit UUID)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Creates an 80-bit, binary(10) unique identifier. | |
* | |
* Smaller, so indexes fit better in memory/RAM and the hex representation | |
* is still relatively URL friendly. Sequential, so inserts/indexes faster. | |
* (see https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/) | |
* | |
* 4 bit worker id (supports 16 servers, from 0 to 15) | |
* 60 bit timestamp | |
* 16 bit random clock sequence | |
* | |
* Here are some useful MySQL calls: | |
* SELECT DATE_FORMAT(FROM_UNIXTIME(CONV(SUBSTR(HEX(people.id), 2, 15),16,10)/10000000),'%d %b %Y %T:%f') FROM people; | |
**/ | |
class Snowflake | |
{ | |
/** | |
* Time (in 100ns steps) between the start of the UTC and Unix epochs | |
* @var int | |
*/ | |
const INTERVAL = 0x01b21dd213814000; | |
private $hex; | |
public function __construct($hex = null, $worker = "0") | |
{ | |
if (empty($hex)) { | |
$hex = $this->makeHex($worker); | |
} | |
$this->hex = $hex; | |
} | |
public static function create($worker = "0") | |
{ | |
return new Snowflake(null, $worker); | |
} | |
public static function createFromExisting($hex) | |
{ | |
return new Snowflake($hex); | |
} | |
private function makeHex($worker) | |
{ | |
// Convert decimal worker (0 to 15) to single digit hex (0 to F) | |
$worker = dechex($worker); | |
/** Get time since Gregorian calendar reform in 100ns intervals | |
* This is exceedingly difficult because of PHP's (and pack()'s) | |
* integer size limits. | |
* Note that this will never be more accurate than to the microsecond. | |
* You can also change the interval. | |
*/ | |
// $timestamp = microtime(1) * 10000000 + static::INTERVAL; | |
$timestamp = microtime(1) * 10000000; | |
// Convert to a string representation | |
$timestamp = sprintf("%F", $timestamp); | |
//strip decimal point | |
preg_match("/^\d+/", $timestamp, $timestamp); | |
// And now to a 64-bit binary representation that begins with the worker id | |
$snowflake = base_convert($timestamp[0], 10, 16); | |
$snowflake = str_pad($snowflake, 16, dechex($worker), STR_PAD_LEFT); | |
// Generate a random clock sequence (2 bytes) | |
$snowflake .= bin2hex(mcrypt_create_iv(2, MCRYPT_DEV_URANDOM)); | |
return $snowflake; | |
} | |
public function getHex(){ | |
return $this->hex; | |
} | |
public function getDateTime($format = 'd M Y h:i:s A') | |
{ | |
$timestamp = base_convert(substr($this->hex, 1, 15), 16, 10); | |
$timestamp = sprintf("%d", $timestamp); | |
// $timestamp = ($timestamp) / 10000000 - static::INTERVAL; | |
$timestamp = ($timestamp) / 10000000; | |
return date($format, $timestamp); | |
} | |
} | |
$uid = Snowflake::create(); | |
echo "Hex: ". $uid->getHex()."\n"; // Hex: 003349028aca2aca3642 | |
echo "DateTime: " . $uid->getDateTime(); // DateTime: 29 Sep 2015 08:05:07 PM |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment