Home > Article > Backend Development > What is the correct way to generate UUID with PHP?
After searching online, I found that they are generally similar to the following:
<code> $chars = md5(uniqid(mt_rand(), true)); $uuid = substr($chars,0,8) . '-'; $uuid .= substr($chars,8,4) . '-'; $uuid .= substr($chars,12,4) . '-'; $uuid .= substr($chars,16,4) . '-'; $uuid .= substr($chars,20,12); return $prefix . $uuid;</code>
<code> mt_srand ( ( double ) microtime () * 10000 ); //optional for php 4.2.0 and up.随便数播种,4.2.0以后不需要了。 $charid = strtoupper ( md5 ( uniqid ( rand (), true ) ) ); //根据当前时间(微秒计)生成唯一id. $hyphen = chr ( 45 ); $uuid = '' . substr ( $charid, 0, 8 ) . $hyphen . substr ( $charid, 8, 4 ) . $hyphen . substr ( $charid, 12, 4 ) . $hyphen . substr ( $charid, 16, 4 ) . $hyphen . substr ( $charid, 20, 12 ); return $uuid;</code>
After reading the description of UUID, why do I feel that the impact rate of these generation methods does not meet the standards?
After searching online, I found that they are generally similar to the following:
<code> $chars = md5(uniqid(mt_rand(), true)); $uuid = substr($chars,0,8) . '-'; $uuid .= substr($chars,8,4) . '-'; $uuid .= substr($chars,12,4) . '-'; $uuid .= substr($chars,16,4) . '-'; $uuid .= substr($chars,20,12); return $prefix . $uuid;</code>
<code> mt_srand ( ( double ) microtime () * 10000 ); //optional for php 4.2.0 and up.随便数播种,4.2.0以后不需要了。 $charid = strtoupper ( md5 ( uniqid ( rand (), true ) ) ); //根据当前时间(微秒计)生成唯一id. $hyphen = chr ( 45 ); $uuid = '' . substr ( $charid, 0, 8 ) . $hyphen . substr ( $charid, 8, 4 ) . $hyphen . substr ( $charid, 12, 4 ) . $hyphen . substr ( $charid, 16, 4 ) . $hyphen . substr ( $charid, 20, 12 ); return $uuid;</code>
After reading the description of UUID, why do I feel that the impact rate of these generation methods does not meet the standards?
At present, many so-called PHP methods for generating UUIDs use random numbers as the basis of their algorithms. Although it is difficult to have a chance of repetition in practice, it is obviously not feasible in theory.
MongoDb’s ObjectId is used as an example here. I personally feel that this generation method can be introduced into PHP.
ObjectId is mainly divided into four parts: timestamp, milliseconds, machine code, and auto-increment count.
There is no need to go into details about the first two, PHP can be obtained, the focus is on the latter two.
Machine code is mainly used to avoid generating the same UUID between different hosts.
The current main method of generating machine code is hash calculation based on hardware information, and this method is not suitable for PHP.
Mainly because of two points, one is that PHP cannot directly obtain hardware information (it needs to be extended or executed local commands, etc.), and the other is that data cannot be shared between PHP requests, so each request has to pull the machine code. The performance impact is huge.
There is a very simple way to solve this problem, which is to first calculate the machine code on different machines, then directly write it into the configuration file, and then read it directly during PHP processing.
Auto-incrementing count is mainly used to avoid generating the same UUID in concurrent processing.
For auto-increment, PHP cannot directly implement auto-increment counting because it cannot share data between requests.
To solve this problem, we can introduce two extensions of PHP, namely Semaphore and Shared Memory, both of which are integrated in the PHP source code and can be opened through --enable-sysvsem and --enable-sysvshm. We only need to place the auto-increment number in the shared memory and then restrict access through the semaphore to achieve the purpose of concurrent requests to share the auto-increment technology. Of course, self-increment can also be achieved through other tools.
The Linux kernel provides a UUID generation interface: cat /proc/sys/kernel/random/uuid
Everything on Linux is a file. No matter what program, you can get a UUID by reading the file.
Generate a unique value by yourself:
<code>php best.php <?php echo uniqid(mt_rand().'_', true)."\n"; echo uniqid(mt_rand().'_', true)."\n"; //代码前后两次调用输出都不一样: 405797689_58295933a5de69.42485678 748054035_58295933a5e072.26553654 //如果运行时再加上远程用户地址/端口/进程PID的话,唯一性应该都已经够用了. echo uniqid($_SERVER['REMOTE_ADDR'].'_'.$_SERVER['REMOTE_PORT'].'_'.getmypid().'_'.mt_rand().'_', true)."\n"; echo uniqid($_SERVER['REMOTE_ADDR'].'_'.$_SERVER['REMOTE_PORT'].'_'.getmypid().'_'.mt_rand().'_', true)."\n";</code>
In addition, it seems that using openssl_random_pseudo_bytes
can also generate a good random string:
<code>echo base64_encode(openssl_random_pseudo_bytes(32));</code>