首頁  >  文章  >  後端開發  >  PHP產生UUID的正確姿勢是?

PHP產生UUID的正確姿勢是?

WBOY
WBOY原創
2016-12-01 00:56:292110瀏覽

網上搜索,發現大體都類似如下:

<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>

看了UUID的說明,怎麼感覺這些生成方法 撞擊率 達不到標準啊?

回覆內容:

網上搜索,發現大體都類似如下:

<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>

看了UUID的說明,怎麼感覺這些生成方法 撞擊率 達不到標準啊?

目前許多所謂PHP產生UUID的方法都以隨機數最為其演算法的基礎,這雖然在實務上很難出現重複的幾率,但在理論上顯然是行不通的。

這裡用MongoDb的ObjectId作為例子,個人覺得這種生成方法是可以引入到PHP的。
ObjectId主要分為四塊:時間戳記、毫秒數、機器碼、自增計數。

前兩者就不用細說了,PHP都可以取到,重點在後兩者上。

機器碼主要用於避免在不同主機間產生相同的UUID。
機器碼目前主要的生成方法是根據硬體資訊進行雜湊計算出,而這個方法並不適用於PHP。
主要因為兩點,一是PHP不能直接獲得硬體資訊(需要透過擴展或執行本地命令等方法),二是PHP請求與請求之間無法共享數據,所以每次請求都得拉取機器碼,對性能影響很大。
解決這一問題有個很簡單的辦法,就是在不同機器先計算出機器碼,之後直接寫入配置文件,PHP處理時直接讀取即可。

自增計數主要用於避免在並發處理中產生相同的UUID。
對於自增來說,PHP由於無法在請求間共享數據,所以無法直接實現自增計數。
解決這一問題我們可以引入PHP的兩個擴展,分別是Semaphore和Shared Memory,這兩者都在PHP源碼中集成,透過--enable-sysvsem和--enable-sysvshm就能打開。我們只需要把自增數放置在共享記憶體中,再透過信號量限制訪問,即可達到並發請求共享自增技術的目的了。當然,自增也能透過其他工具來實現。

Linux核心提供有UUID產生介面:
cat /proc/sys/kernel/random/uuid
Linux上一切皆檔案,不管什麼程式,讀取檔案就能取得一個UUID.

自行產生一個唯一值:

<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>

另外看似用openssl_random_pseudo_bytes也能產生不錯的隨機字串:

<code>echo base64_encode(openssl_random_pseudo_bytes(32));</code>
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn