php8
[web.mtrack] / MTrack / UUID.php
1 <?php # vim:ts=2:sw=2:noet:
2 /* For licensing and copyright terms, see the file named LICENSE */
3 /* Copyright (c) 2007, OmniTI Computer Consulting, Inc.
4  * All Rights Reserved.
5  */
6
7 /** 
8  * A class for working with RFC 4122 UUIDs
9  */
10 class OmniTI_Util_UUID {
11         public $binary;
12
13         function __construct($src = null) {
14                 if ($src !== null) {
15                         switch (strlen($src)) {
16                                 case 36: /* with -'s */
17                                         $src = str_replace('-', '', $src);
18                                 case 32: /* with -'s stripped */
19                                         $this->binary = pack('H*', $src);
20                                         break;
21                                 case 16: /* binary string */
22                                         $this->binary = $src;
23                                         break;
24                                 case 24: /* base64 encoded binary */
25                                         $this->binary = base64_decode(
26                                                 str_replace(
27                                                         array('@', '-', '_'),
28                                                         array('=', '/', '+'),
29                                                         $src));
30                                         break;
31                                 default:
32                                         $this->binary = null;
33                         }
34                 } else {
35                         $this->generate();
36                 }
37         }
38
39         /** 
40          * returns a 32-bit integer that identifies this host.
41          * The node identifier needs to be unique among nodes
42          * in a cluster for a given application in order to
43          * avoid collisions between generated identifiers.
44          * You may extend and override this method if you
45          * want to substitute an alternative means of determining
46          * the node identifier */
47         protected function getNodeId() {
48                 if (isset($_SERVER['SERVER_ADDR'])) {
49                         $node = ip2long($_SERVER['SERVER_ADDR']);
50                 } else {
51                         /* running from the CLI most likely;
52                          * inspect the environment to see if we can
53                          * deduce the hostname, and from there, the
54                          * IP address */
55                         static $names = array('HOSTNAME', 'HOST');
56                         foreach ($names as $name) {
57                                 if (isset($_ENV[$name])) {
58                                         $host = $_ENV[$name];
59                                 } else {
60                                         $host = getenv($name);
61                                 }
62                                 if (strlen($host)) break;
63                         }
64                         if (!strlen($host)) {
65                                 // punt 
66                                 $node = ip2long('127.0.0.1');
67                         } else {
68                                 $ip = gethostbyname($host);
69                                 if (strlen($ip)) {
70                                         $node = ip2long($ip);
71                                 } else {
72                                         // punt
73                                         $node = crc32($host);
74                                 }
75                         }
76                 }
77                 return $node;
78         }
79
80         /** 
81          * returns a process identifier.
82          * In multi-process servers, this should be the system process ID.
83          * In multi-threaded servers, this should be some unique ID to
84          * prevent two threads from generating precisely the same UUID
85          * at the same time.
86          */
87         protected function getLockId() {
88                 if (function_exists('zend_thread_id')) {
89                         return zend_thread_id();
90                 }
91                 return getmypid();
92         }
93
94         /** 
95          * generate an RFC 4122 UUID.
96          * This is psuedo-random UUID influenced by the system clock, IP
97          * address and process ID. 
98          *
99          * The intended use is to generate an identifier that can uniquely
100          * identify user generated posts, comments etc. made to a website.
101          * This generation process should be sufficient to avoid collisions
102          * between nodes in a cluster, and between apache children on the
103          * same host.
104          *
105          */
106         function generate() {
107                 $node = $this->getNodeId();
108                 $pid = $this->getLockId();
109
110                 list($time_mid, $time_lo) = explode(' ', microtime());
111                 $time_lo = (int)$time_lo;
112                 $time_mid = (int)substr($time_mid, 2);
113
114                 $time_hi = mt_rand(0, 0xfff);
115                 /* version 4 UUID */
116                 $time_hi |= 0x4000;
117
118                 $clock_lo = mt_rand(0, 0xff);
119                 $node_lo = $pid;
120
121                 /* type is psuedo-random */
122                 $clock_hi = mt_rand(0, 0x3f);
123                 $clock_hi |= 0x80;
124
125                 $this->binary = pack('NnnCCnN',
126                         $time_lo, $time_mid & 0xffff, $time_hi,
127                         $clock_hi, $clock_lo, $node_lo, $node);
128         }
129
130         /** 
131          * render the UUID as an RFC4122 standard string representation
132          * of the binary bits.
133          */
134         function toRFC4122String($dashes = true) {
135                 $uuid = unpack('Ntl/ntm/nth/Cch/Ccl/nnl/Nn', $this->binary);
136                 $fmt = $dashes ?
137                         "%08x-%04x-%04x-%02x%02x-%04x%08x" :
138                         "%08x%04x%04x%02x%02x%04x%08x";
139                 return sprintf($fmt,
140                         $uuid['tl'], $uuid['tm'], $uuid['th'],
141                         $uuid['ch'], $uuid['cl'], $uuid['nl'], $uuid['n']);
142         }
143
144         /** 
145          * render the UUID using a modified base64 representation
146          * of the binary bits.  This string is shorter than the standard
147          * representation, but is not part of any standard specification.
148          */
149         function toShortString() {
150                 return str_replace(
151                                 array('=', '/', '+'),
152                                 array('@', '-', '_'),
153                                 base64_encode($this->binary));
154         }
155
156 }
157
158 ?>