W3CAPI 在线教程 | 菜鸟教程_LOGO
文档目录
文档目录
我的书签
 

PHP

PHP 生成唯一订单号、唯一ID的方法

在应用软件开发中,经常需要生成一种长度一致并且不能重复的字符串序列或者数字编号ID,来保证一条数据记录的唯一性,比如电商平台中的订单编号、会员系统中的邀请码、激活码等等,这里总结一下在PHP中生成唯一序列的几种方法以及他们的用例和注意事项。

W3CAPI
1
2020-04-25 22:58:25

生成唯一订单号、唯一字符序列的算法

我们要想生成唯一的字符序列,首先需要了解生成的算法都有哪些?然后根据这些算法的实现进行分析,最后选择执行效率最好的算法。下面是我想到的一些算法:
  1. 使用随机数或随机字符:但是随机数可能会存在重复,需要再使用查表法进行判重(判断重复)
  2. 使用时间戳:时间戳在高并发的时候也会存在重复,需要再使用查表法进行判重(判断重复)
  3. 使用随机数或随机字符串+时间戳:在高并发的时候也会存在重复,需要再使用查表法进行判重(判断重复)
  4. 使用随机数或随机字符串+时间戳+其他标识(用户ID、商品ID、订单ID等等):高并发不会发生重复,不用查表
我现在想到的也就这些了,基本的思路就是:使用各种方法来使生成的字符序列不会和之前生成的重复,下面我们来看具体的实例。

PHP 使用时间戳和随机数生成唯一订单号和唯一ID

一、第一种方法

md5(time() . mt_rand(1,1000000)); //重复几率非常大,需要配合查表和并发锁

二、第二种方法

date('Ymd') . str_pad(mt_rand(1, 99999), 10, '0', STR_PAD_LEFT).rand(1000,9999); //和第一种方法类似

三、第三种方法

date('Ymd').substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(1000, 9999)); //使用了毫秒,相比较重复率降低很多

PHP 使用其他标识和时间戳和随机数生成唯一订单号和唯一ID

一、第一种方法:使用内置函数uniqid、结合随机数和时间戳

uniqid函数是PHP 提供的一个内置函数,它的功能是获取一个带前缀、基于当前时间微秒数的唯一ID,但是它不保证返回值的唯一性。 由于绝大多数系统使用 NTP 或者类似服务调整系统的时间,所以系统时间经常发生变化。 此外,进程/线程可能不会返回唯一的 ID,我们可以用它来结合随机数生成,实例如下:
function uuid() {
    if (function_exists ( 'com_create_guid' )) {
        return com_create_guid (); //com_create_guid()是php自带的生成唯一id方法,php5之后好像已经被移除了
    } else {
        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 = '' . //chr(123)// "{"
            substr ( $charid, 0, 8 ) . $hyphen . substr ( $charid, 8, 4 ) . $hyphen . substr ( $charid, 12, 4 ) . $hyphen . substr ( $charid, 16, 4 ) . $hyphen . substr ( $charid, 20, 12 );
        //.chr(125);// "}"
        return $uuid;
    }
}

二、第二种方法:使用内置函数uniqid、结合HTTP请求上下文数据

function create_guid($namespace = '') {
    static $guid = '';
    $uid = uniqid("", true);
    $data = $namespace;
    $data .= $_SERVER['REQUEST_TIME'];
    $data .= $_SERVER['HTTP_USER_AGENT'];
    $data .= $_SERVER['SERVER_ADDR'];
    $data .= $_SERVER['SERVER_PORT'];
    $data .= $_SERVER['REMOTE_ADDR'];
    $data .= $_SERVER['REMOTE_PORT'];
    $hash = strtoupper(hash('ripemd128', $uid . $guid . md5($data)));
    $guid = '{' .
        substr($hash,  0,  8) .
        '-' .
        substr($hash,  8,  4) .
        '-' .
        substr($hash, 12,  4) .
        '-' .
        substr($hash, 16,  4) .
        '-' .
        substr($hash, 20, 12) .
        '}';
    return $guid;
}

三、第三种方法

date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8).rand(1000,9999); //类似第一种方法

四、第四种方法:使用加法运算提高唯一性

function create_seq() {
    $order_id_main = date('YmdHis') . rand(10000000, 99999999);
    $order_id_len = strlen($order_id_main);
    $order_id_sum = 0;
    for ($i = 0; $i < $order_id_len; $i++) {
        $order_id_sum += (int)(substr($order_id_main, $i, 1)); //这里对生成的随机序列进行加法运算使重复率降低
    }
    $nid = $order_id_main . str_pad((100 - $order_id_sum % 100) % 100, 2, '0', STR_PAD_LEFT);
    return $nid;
}
​​​​​这个方法生成24位唯一订单号码,格式:YYYY-MMDD-HHII-SS-NNNN,NNNN-CC,其中:YYYY=年份,MM=月份,DD=日期,HH=24格式小时,II=分,SS=秒,NNNNNNNN=随机数,CC=检查码,大家可以根据这种思想稍微进行改变就可以适应自己想要的实现了。

五、第五种方法

function create_seq() {
    $yCode = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
    $orderSn = $yCode[intval(date('Y')) - 2011] . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
    return $orderSn;
}
该方法采用了更多的随机可能来组合,用上了英文字母、年月日、Unix 时间戳和微秒数、随机数,重复的可能性大大降低,使用字母很有代表性,一个字母对应一个年份,总共16位。
相关提问
敬请期待