1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Util |
4
|
|
|
* |
5
|
|
|
* @copyright Copyright (c) Gjero Krsteski (http://krsteski.de) |
6
|
|
|
* @license http://opensource.org/licenses/MIT MIT License |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace Pimf\Util; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* A class that generates RFC 4122 UUIDs |
13
|
|
|
* |
14
|
|
|
* <pre> |
15
|
|
|
* This specification defines a Uniform Resource Name namespace for |
16
|
|
|
* UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally |
17
|
|
|
* Unique IDentifier). A UUID is 128 bits long, and requires no central |
18
|
|
|
* registration process. |
19
|
|
|
* </pre> |
20
|
|
|
* |
21
|
|
|
* @package Util |
22
|
|
|
* @author Gjero Krsteski <[email protected]> |
23
|
|
|
* @see http://www.ietf.org/rfc/rfc4122.txt |
24
|
|
|
*/ |
25
|
|
|
final class Uuid |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* 32-bit integer that identifies this host. |
29
|
|
|
* |
30
|
|
|
* @var integer |
31
|
|
|
*/ |
32
|
|
|
private static $node = null; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Process identifier. |
36
|
|
|
* |
37
|
|
|
* @var integer |
38
|
|
|
*/ |
39
|
|
|
private static $pid = null; |
40
|
|
|
|
41
|
|
|
private static $hostIp, $hostName; |
42
|
|
|
|
43
|
|
|
public static function setup($hostIp, $hostName) |
44
|
|
|
{ |
45
|
|
|
self::$hostIp = $hostIp; |
46
|
|
|
self::$hostName = $hostName; |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Returns a 32-bit integer that identifies this host. |
51
|
|
|
* |
52
|
|
|
* The node identifier needs to be unique among nodes |
53
|
|
|
* in a cluster for a given application in order to |
54
|
|
|
* avoid collisions between generated identifiers. |
55
|
|
|
* |
56
|
|
|
* @return integer |
57
|
|
|
*/ |
58
|
|
|
private static function getNodeId() |
59
|
|
|
{ |
60
|
|
|
if (self::$hostIp !== null) { |
61
|
|
|
return ip2long(self::$hostIp); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
self::$hostIp = '127.0.0.1'; |
65
|
|
|
|
66
|
|
|
if (self::$hostName !== null) { |
67
|
|
|
self::$hostIp = crc32(self::$hostName); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
View Code Duplication |
if (true === function_exists('php_uname')) { |
|
|
|
|
71
|
|
|
self::$hostName = php_uname('n'); |
72
|
|
|
self::$hostIp = gethostbyname(self::$hostName); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
View Code Duplication |
if (true === function_exists('gethostname')) { |
|
|
|
|
76
|
|
|
self::$hostName = gethostname(); |
77
|
|
|
self::$hostIp = gethostbyname(self::$hostName); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
return ip2long(self::$hostIp); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Returns a process identifier. |
85
|
|
|
* |
86
|
|
|
* In multi-process servers, this should be the system process ID. |
87
|
|
|
* In multi-threaded servers, this should be some unique ID to |
88
|
|
|
* prevent two threads from generating precisely the same UUID |
89
|
|
|
* at the same time. |
90
|
|
|
* |
91
|
|
|
* @return integer |
92
|
|
|
*/ |
93
|
|
|
private static function getLockId() |
94
|
|
|
{ |
95
|
|
|
return getmypid(); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Generate an RFC 4122 UUID. |
100
|
|
|
* |
101
|
|
|
* This is pseudo-random UUID influenced by the system clock, IP |
102
|
|
|
* address and process ID. |
103
|
|
|
* |
104
|
|
|
* The intended use is to generate an identifier that can uniquely |
105
|
|
|
* identify user generated posts, comments etc. made to a website. |
106
|
|
|
* This generation process should be sufficient to avoid collisions |
107
|
|
|
* between nodes in a cluster, and between apache children on the |
108
|
|
|
* same host. |
109
|
|
|
* |
110
|
|
|
* @return string |
111
|
|
|
*/ |
112
|
|
|
public static function generate() |
113
|
|
|
{ |
114
|
|
|
if (self::$node === null) { |
115
|
|
|
self::$node = self::getNodeId(); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
if (self::$pid === null) { |
119
|
|
|
self::$pid = self::getLockId(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
list($time_mid, $time_lo) = explode(' ', microtime()); |
123
|
|
|
|
124
|
|
|
$time_low = (int)$time_lo; |
125
|
|
|
$time_mid = (int)substr($time_mid, 2); |
126
|
|
|
|
127
|
|
|
$time_and_version = mt_rand(0, 0xfff); |
128
|
|
|
|
129
|
|
|
// version 4 UUID |
130
|
|
|
$time_and_version |= 0x4000; |
131
|
|
|
|
132
|
|
|
$clock_seq_low = mt_rand(0, 0xff); |
133
|
|
|
|
134
|
|
|
// type is pseudo-random |
135
|
|
|
$clock_seq_high = mt_rand(0, 0x3f); |
136
|
|
|
$clock_seq_high |= 0x80; |
137
|
|
|
|
138
|
|
|
$node_low = self::$pid; |
139
|
|
|
$node = self::$node; |
140
|
|
|
|
141
|
|
|
return sprintf( |
142
|
|
|
'%08x-%04x-%04x-%02x%02x-%04x%08x', $time_low, $time_mid & 0xffff, $time_and_version, $clock_seq_high, |
143
|
|
|
$clock_seq_low, $node_low, |
144
|
|
|
$node |
145
|
|
|
); |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.