401 lines
12 KiB
PHP
401 lines
12 KiB
PHP
<?php
|
|
namespace Phast;
|
|
class UUIDParseFailureKind
|
|
{
|
|
const FORMAT = 2;
|
|
}
|
|
class UUIDParseNumbers
|
|
{
|
|
const NOSPACE = 2;
|
|
}
|
|
class UUIDParseResult
|
|
{
|
|
public $Kind;
|
|
public $Message;
|
|
|
|
public UUID $parsedGuid;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->parsedGuid = new UUID();
|
|
}
|
|
|
|
public function setFailure(/*UUIDParseFailureKind*/ $kind, $message)
|
|
{
|
|
$this->Kind = $kind;
|
|
$this->Message = $message;
|
|
}
|
|
}
|
|
|
|
class UUID
|
|
{
|
|
|
|
private static $urand = null;
|
|
|
|
public function __construct()
|
|
{
|
|
if (UUID::$urand == null)
|
|
{
|
|
UUID::$urand = @fopen ( '/dev/urandom', 'rb' );
|
|
}
|
|
$this->_a = 0;
|
|
$this->_b = 0;
|
|
$this->_c = 0;
|
|
$this->_d = 0;
|
|
$this->_e = 0;
|
|
$this->_f = 0;
|
|
$this->_g = 0;
|
|
$this->_h = 0;
|
|
$this->_i = 0;
|
|
$this->_j = 0;
|
|
$this->_k = 0;
|
|
}
|
|
|
|
private static function StringToInt(string $guidString, int &$parsePos, int $requiredLength, int $flags, int &$result, UUIDParseResult &$parseResult)
|
|
{
|
|
$parseWhat = substr($guidString, $parsePos, $requiredLength);
|
|
$result = intval($parseWhat, 16);
|
|
$parsePos += $requiredLength;
|
|
return true;
|
|
}
|
|
private static function StringToLong(string $guidString, int &$parsePos, int $flags, int &$result, UUIDParseResult &$parseResult)
|
|
{
|
|
return UUID::StringToInt($guidString, $parsePos, 16, $flags, $result, $parseResult);
|
|
}
|
|
|
|
private static function TryParseGuidWithDashes(string $guidString) : UUIDParseResult
|
|
{
|
|
$startPos = 0;
|
|
$temp = 0;
|
|
$templ = 0;
|
|
$currentPos = 0;
|
|
$result = new UUIDParseResult();
|
|
$hasDashes = true;
|
|
|
|
// check to see that it's the proper length
|
|
if ($guidString[0] == '{')
|
|
{
|
|
if (strlen($guidString) != 38 || $guidString[37] != '}')
|
|
{
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_GuidInvLen[{38]");
|
|
return $result;
|
|
}
|
|
$startPos = 1;
|
|
}
|
|
else if ($guidString[0] == '(')
|
|
{
|
|
if (strlen($guidString) != 38 || $guidString[37] != ')')
|
|
{
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_GuidInvLen[(38]");
|
|
return $result;
|
|
}
|
|
$startPos = 1;
|
|
}
|
|
else if (strlen($guidString) != 36)
|
|
{
|
|
if (strlen($guidString) != 32)
|
|
{
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_GuidInvLen[36]");
|
|
return $result;
|
|
}
|
|
else
|
|
{
|
|
$hasDashes = false;
|
|
}
|
|
}
|
|
|
|
if ($hasDashes)
|
|
{
|
|
if ($guidString[8 + $startPos] != '-' ||
|
|
$guidString[13 + $startPos] != '-' ||
|
|
$guidString[18 + $startPos] != '-' ||
|
|
$guidString[23 + $startPos] != '-') {
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_GuidDashes");
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
$currentPos = $startPos;
|
|
|
|
if (!UUID::StringToInt($guidString, $currentPos, 8, UUIDParseNumbers::NOSPACE, $temp, $result))
|
|
{
|
|
return $result;
|
|
}
|
|
$result->parsedGuid->_a = $temp;
|
|
|
|
if ($hasDashes)
|
|
{
|
|
++$currentPos; //Increment past the '-';
|
|
}
|
|
|
|
if (!UUID::StringToInt($guidString, $currentPos, 4, UUIDParseNumbers::NOSPACE, $temp, $result))
|
|
return $result;
|
|
$result->parsedGuid->_b = $temp;
|
|
if ($hasDashes)
|
|
{
|
|
++$currentPos; //Increment past the '-';
|
|
}
|
|
|
|
if (!UUID::StringToInt($guidString, $currentPos, 4, UUIDParseNumbers::NOSPACE, $temp, $result))
|
|
return $result;
|
|
$result->parsedGuid->_c = $temp;
|
|
if ($hasDashes)
|
|
{
|
|
++$currentPos; //Increment past the '-';
|
|
}
|
|
|
|
if (!UUID::StringToInt($guidString, $currentPos, 4, UUIDParseNumbers::NOSPACE, $temp, $result))
|
|
return $result;
|
|
|
|
if ($hasDashes)
|
|
{
|
|
++$currentPos; //Increment past the '-';
|
|
}
|
|
$startPos = $currentPos;
|
|
|
|
if (!UUID::StringToLong($guidString, $currentPos, UUIDParseNumbers::NOSPACE, $templ, $result)) {
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_StrToLong");
|
|
return $result;
|
|
}
|
|
/*
|
|
if ($currentPos - $startPos != 12) {
|
|
$result->setFailure(UUIDParseFailureKind::FORMAT, "Format_GuidInvLen(*)");
|
|
return $result;
|
|
}
|
|
*/
|
|
$result->parsedGuid->_d = $temp >> 8;
|
|
$result->parsedGuid->_e = $temp;
|
|
$temp = ($templ >> 32);
|
|
$result->parsedGuid->_f = ($temp >> 8);
|
|
$result->parsedGuid->_g = ($temp);
|
|
$temp = ($templ);
|
|
$result->parsedGuid->_h = ($temp >> 24);
|
|
$result->parsedGuid->_i = ($temp >> 16);
|
|
$result->parsedGuid->_j = ($temp >> 8);
|
|
$result->parsedGuid->_k = ($temp);
|
|
return $result;
|
|
}
|
|
|
|
public static function parse(string $value)
|
|
{
|
|
$result = UUID::TryParseGuidWithDashes($value);
|
|
return $result->parsedGuid;
|
|
}
|
|
|
|
public function __is_equal(UUID $uuid)
|
|
{
|
|
/*
|
|
if (
|
|
$uuid->clock_seq_hi_and_reserved == $this->clock_seq_hi_and_reserved
|
|
&& $uuid->node == $this->node
|
|
&& $uuid->time_hi_and_version == $this->time_hi_and_version
|
|
&& $uuid->time_low == $this->time_low
|
|
&& $uuid->time_mid == $this->time_mid
|
|
)
|
|
{
|
|
return true;
|
|
}
|
|
*/
|
|
if (
|
|
$uuid->_a == $this->_a
|
|
&& $uuid->_b == $this->_b
|
|
&& $uuid->_c == $this->_c
|
|
&& $uuid->_d == $this->_d
|
|
&& $uuid->_e == $this->_e
|
|
&& $uuid->_f == $this->_f
|
|
&& $uuid->_g == $this->_g
|
|
&& $uuid->_h == $this->_h
|
|
&& $uuid->_i == $this->_i
|
|
&& $uuid->_j == $this->_j
|
|
&& $uuid->_k == $this->_k
|
|
)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
public function __is_not_equal(UUID $uuid)
|
|
{
|
|
return !$this->__is_equal($uuid);
|
|
}
|
|
|
|
private static function init_bits()
|
|
{
|
|
$pr_bits = false;
|
|
/*
|
|
if (is_a ( $this, 'uuid' ))
|
|
{
|
|
*/
|
|
if (is_resource ( UUID::$urand ))
|
|
{
|
|
$pr_bits .= @fread ( UUID::$urand, 16 );
|
|
}
|
|
// }
|
|
if (! $pr_bits)
|
|
{
|
|
$fp = @fopen ( '/dev/urandom', 'rb' );
|
|
if ($fp !== false)
|
|
{
|
|
$pr_bits .= @fread ( $fp, 16 );
|
|
@fclose ( $fp );
|
|
}
|
|
else
|
|
{
|
|
// If /dev/urandom isn't available (eg: in non-unix systems), use mt_rand().
|
|
$pr_bits = "";
|
|
for($cnt = 0; $cnt < 16; $cnt ++)
|
|
{
|
|
$pr_bits .= chr ( mt_rand ( 0, 255 ) );
|
|
}
|
|
}
|
|
}
|
|
return $pr_bits;
|
|
}
|
|
|
|
/**
|
|
* @brief Generates a Universally Unique IDentifier, version 4.
|
|
*
|
|
* This function generates a truly random UUID. The built in CakePHP String::uuid() function
|
|
* is not cryptographically secure. You should uses this function instead.
|
|
*
|
|
* @see http://tools.ietf.org/html/rfc4122#section-4.4
|
|
* @see http://en.wikipedia.org/wiki/UUID
|
|
* @return UUID A UUID, made up of 32 hex digits and 4 hyphens.
|
|
*/
|
|
public static function generate()
|
|
{
|
|
$uuid = new UUID();
|
|
|
|
$pr_bits = UUID::init_bits();
|
|
|
|
$uuid->_a = ((int)$pr_bits[3] << 24) | ((int)$pr_bits[2] << 16) | ((int)$pr_bits[1] << 8) | $pr_bits[0];
|
|
$uuid->_b = /*(short)*/(((int)$pr_bits[5] << 8) | $pr_bits[4]);
|
|
$uuid->_c = /*(short)*/(((int)$pr_bits[7] << 8) | $pr_bits[6]);
|
|
$uuid->_d = $pr_bits[8];
|
|
$uuid->_e = $pr_bits[9];
|
|
$uuid->_f = $pr_bits[10];
|
|
$uuid->_g = $pr_bits[11];
|
|
$uuid->_h = $pr_bits[12];
|
|
$uuid->_i = $pr_bits[13];
|
|
$uuid->_j = $pr_bits[14];
|
|
$uuid->_k = $pr_bits[15];
|
|
|
|
return $uuid;
|
|
}
|
|
|
|
private static function __Generate_Old()
|
|
{
|
|
$uuid = new UUID();
|
|
$pr_bits = UUID::init_bits();
|
|
|
|
$time_low = bin2hex ( substr ( $pr_bits, 0, 4 ) );
|
|
$time_mid = bin2hex ( substr ( $pr_bits, 4, 2 ) );
|
|
$time_hi_and_version = bin2hex ( substr ( $pr_bits, 6, 2 ) );
|
|
$clock_seq_hi_and_reserved = bin2hex ( substr ( $pr_bits, 8, 2 ) );
|
|
$node = bin2hex ( substr ( $pr_bits, 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;
|
|
|
|
|
|
$uuid->time_low = $time_low;
|
|
$uuid->time_mid = $time_mid;
|
|
$uuid->time_hi_and_version = $time_hi_and_version;
|
|
$uuid->clock_seq_hi_and_reserved = $clock_seq_hi_and_reserved;
|
|
$uuid->node = $node;
|
|
return $uuid;
|
|
}
|
|
|
|
private $time_low;
|
|
private $time_mid;
|
|
private $time_hi_and_version;
|
|
private $clock_seq_hi_and_reserved;
|
|
private $node;
|
|
|
|
|
|
private static function HexToChar(int $a) : string
|
|
{
|
|
$a = $a & 0xf;
|
|
return chr((($a > 9) ? $a - 10 + 0x61 : $a + 0x30));
|
|
}
|
|
private static function HexsToChars(int $a, int $b, bool $hex = false)
|
|
{
|
|
$guidChars = "";
|
|
if ($hex) {
|
|
$guidChars = "0x";
|
|
}
|
|
$guidChars .= UUID::HexToChar($a>>4);
|
|
$guidChars .= UUID::HexToChar($a);
|
|
if ($hex)
|
|
{
|
|
$guidChars .= ",0x";
|
|
}
|
|
$guidChars .= UUID::HexToChar($b>>4);
|
|
$guidChars .= UUID::HexToChar($b);
|
|
return $guidChars;
|
|
}
|
|
|
|
private $_a, $_b, $_c, $_d, $_e, $_f, $_g, $_h, $_i, $_j, $_k;
|
|
|
|
public function __toString()
|
|
{
|
|
//return $this->format(strtoupper( sprintf ( '%08s%04s%04x%04x%012s', $this->time_low, $this->time_mid, $this->time_hi_and_version, $this->clock_seq_hi_and_reserved, $this->node ) ));
|
|
$dash = true;
|
|
$guidChars = "{";
|
|
$guidChars .= UUID::HexsToChars($this->_a >> 24, $this->_a >> 16);
|
|
$guidChars .= UUID::HexsToChars($this->_a >> 8, $this->_a);
|
|
if ($dash) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_b >> 8, $this->_b);
|
|
if ($dash) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_c >> 8, $this->_c);
|
|
if ($dash) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_d, $this->_e);
|
|
if ($dash) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_f, $this->_g);
|
|
$guidChars .= UUID::HexsToChars($this->_h, $this->_i);
|
|
$guidChars .= UUID::HexsToChars($this->_j, $this->_k);
|
|
$guidChars .= "}";
|
|
return $guidChars;
|
|
}
|
|
public function __toStringFormat($includeDashes = false, $prefix = "{", $suffix = "}")
|
|
{
|
|
$guidChars = $prefix;
|
|
$guidChars .= UUID::HexsToChars($this->_a >> 24, $this->_a >> 16);
|
|
$guidChars .= UUID::HexsToChars($this->_a >> 8, $this->_a);
|
|
if ($includeDashes) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_b >> 8, $this->_b);
|
|
if ($includeDashes) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_c >> 8, $this->_c);
|
|
if ($includeDashes) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_d, $this->_e);
|
|
if ($includeDashes) $guidChars .= '-';
|
|
$guidChars .= UUID::HexsToChars($this->_f, $this->_g);
|
|
$guidChars .= UUID::HexsToChars($this->_h, $this->_i);
|
|
$guidChars .= UUID::HexsToChars($this->_j, $this->_k);
|
|
$guidChars .= $suffix;
|
|
return $guidChars;
|
|
}
|
|
|
|
private static function format($input)
|
|
{
|
|
$output = $input;
|
|
$output = substr($output, 0, 8) . "-" . substr($output, 8, 4) . "-" . substr($output, 12, 4) . "-" . substr($output, 16, 4) . "-" . substr($output, 20);
|
|
return "{" . $output . "}";
|
|
}
|
|
}
|
|
?>
|