首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實作固定長度純數字編碼生成器(訂單號/卡號/用戶ID)

     編輯:PHP 綜合知識

應用場景

電商訂單號、會員卡號、用戶邀請碼等業務常需「固定長度、純數字、唯一、無規律可循」的編碼。直接使用自增 ID 會洩露業務量,且長度不固定。本文介紹一個基於時間戳 + ID 混淆編碼的解決方案。

核心類別設計

<?php
namespace Minyifei\Libs;

class SequenceNumber {
    // 各長度對應的位元映射表(核心混淆邏輯)
    private static function _getMapbit($width) {
        $mapBits = [
            4 => [10, 2, 11, 3, 0, 1, 9, 7, 12, 6, 4, 8, 5],
            5 => [4, 3, 13, 15, 7, 8, 6, 2, 1, 10, 5, 12, 0, 11, 14, 9],
            6 => [2, 7, 10, 9, 16, 3, 6, 8, 0, 4, 1, 12, 11, 13, 18, 5, 15, 17, 14],
            7 => [18, 0, 2, 22, 8, 3, 1, 14, 17, 12, 4, 19, 11, 9, 13, 5, 6, 15, 10, 16, 20, 7, 21],
            8 => [11, 8, 4, 0, 16, 14, 22, 7, 3, 5, 13, 18, 24, 25, 23, 10, 1, 12, 6, 21, 17, 2, 15, 9, 19, 20],
            9 => [24, 23, 27, 3, 9, 16, 25, 13, 28, 12, 0, 4, 10, 18, 11, 2, 17, 1, 21, 26, 5, 15, 7, 20, 22, 14, 19, 6, 8],
            10 => [32, 3, 1, 28, 21, 18, 30, 7, 12, 22, 20, 13, 16, 15, 6, 17, 9, 25, 11, 8, 4, 27, 14, 31, 5, 23, 24, 29, 0, 10, 19, 26, 2],
            11 => [9, 13, 2, 29, 11, 32, 14, 33, 24, 8, 27, 4, 22, 20, 5, 0, 21, 25, 17, 28, 34, 6, 23, 26, 30, 3, 7, 19, 16, 15, 12, 31, 1, 35, 10, 18],
            12 => [31, 4, 16, 33, 35, 29, 17, 37, 12, 28, 32, 22, 7, 10, 14, 26, 0, 9, 8, 3, 20, 2, 13, 5, 36, 27, 23, 15, 19, 34, 38, 11, 24, 25, 30, 21, 18, 6, 1],
        ];
        return $mapBits[intval($width)] ?? [];
    }

    // 時間戳格式化(預設 YmdHis)
    private static $_fmt = 'YmdHis';
    private static function _fmtTS($ts = null) {
        return date(self::$_fmt, $ts ?? time());
    }

    /**
     * 核心編碼演算法:位元置換 + 偏移量
     * @param int $id      來源 ID(通常為資料庫自增主鍵)
     * @param int $width   輸出長度(不含前綴)
     * @return string 固定長度數字字串
     */
    public static function encode($id, $width) {
        $maximum = (int)str_repeat('9', $width);        // 該長度最大值(如 999999)
        $superscript = (int)(log($maximum) / log(2));   // 所需位元數
        $r = 0;
        $sign = 1 << $superscript;                     // 最高位標記
        $id |= $sign;                                   // 確保 ID 不為 0
        
        $mapbit = self::_getMapbit($width);
        for ($x = 0; $x < $superscript; $x++) {
            $bit = ($id >> $x) & 1;                    // 取出第 x 位
            $r |= ($bit << $mapbit[$x]);               // 映射到新位置
        }
        
        // 偏移量確保結果滿足固定長度
        $r += $maximum - pow(2, $superscript) + 1;
        return sprintf("%0{$width}s", $r);              // 左補零
    }

    /**
     * 公開介面:帶前綴的編碼
     * @param int $id      業務 ID
     * @param int $prefix  前綴(如 10 表訂單,20 表用戶)
     * @param int $width   編碼長度
     * @return string 完整編碼
     */
    public static function generateNumber($id, $prefix = 10, $width = 8) {
        return sprintf("%s%s", $prefix, self::encode($id, $width));
    }

    /**
     * 含時間戳的唯一編碼(適合訂單號)
     * @param int $id     業務 ID
     * @param int $width  編碼長度
     * @param int $ts     時間戳(預設當前)
     * @return string 如 20240115123045 + 8位編碼
     */
    public static function get($id, $width, $ts = null) {
        return sprintf('%s%s', self::_fmtTS($ts), self::encode($id, $width));
    }
}

使用範例

// 訂單號:時間戳(14位) + 8位混淆碼 = 22位純數字
$orderNo = SequenceNumber::get($orderId, 8); 
// 輸出範例:2024011512304573928104

// 用戶邀請碼:前綴 20 + 6位混淆碼 = 8位
$inviteCode = SequenceNumber::generateNumber($userId, 20, 6);
// 輸出範例:20483921

// 純編碼(無前綴、無時間)
$code = SequenceNumber::encode(12345, 8);
// 輸出範例:03928104

演算法特性分析

特性說明
唯一性同一 ID + 同一長度 + 同一時間戳 = 固定輸出;不同 ID 輸出極大概率不同
不可逆性位元置換映射表單向,難以從編碼反推原始 ID
固定長度sprintf 左補零保證輸出長度恆定
無規律性映射表打亂位元順序,連續 ID 生成的編碼無明顯規律
效能純位元運算,微秒級完成,支援高併發

注意事項

  • ID 範圍限制:$width 決定最大可編碼 ID。如 width=8 最大支援 ~9999 萬筆,超過會衝突
  • 映射表固定:生產環境切勿修改映射表,否則歷史編碼無法驗證
  • 分散式場景:多節點需確保 ID 全域唯一(可用 Snowflake 算法生成 ID 再編碼)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved