PHP语言基于用户ID生成唯一邀请码

需求

需要根据用户 ID(数值型)生成一个唯一的的邀请码,用于邀请新用户注册。

需求分析

从业务需求上来看,邀请码有以下几个强制性的要求:

  1. 不可重复:不同用户 ID 生成的邀请码是不同的。
  2. 唯一确定:一个用户 ID 只能生成一个邀请码。
  3. 长度不能太长,6-10 位是合适的区间
  4. 是否可逆:是否需要通过邀请码反推对应的用户 ID 是什么

在这些需求的约束下,我们来看看相对来说比较通用的邀请码生成算法。

26个字母+10个数字,去掉容易混淆的,O、0、I、1等字符就剩下32个。

<?php

class InvitationCodeUtil {

    // 定义字符集
   private static array $CHARS = ["Y","2","U","K","X","V","C","F","N","S","6","8","G","Z","Q","7","A","9","P","H","5","M","R","L","D","J","4","T","W","E","3","B"];

    private const CHARS_LENGTH = 32;
    private const SLAT = 3312427;
    private const PRIME1 = 3;
    private const PRIME2 = 11;

    // 生成邀请码
    public static function gen($id, $length = 6): string
    {
        // 对 ID 进行加密处理
        $id = $id * self::PRIME1 + self::SLAT;
        $b = [];
        $b[0] = $id;
        for ($i = 0; $i < $length - 1; $i++) {
            $b[$i + 1] = $b[$i] / self::CHARS_LENGTH;
            $b[$i] = (int) ($b[$i] + $i * $b[0]) % self::CHARS_LENGTH;
        }

        // 计算邀请码索引
        $tmp = 0;
        for ($i = 0; $i < $length - 2; $i++) {
            $tmp += $b[$i];
        }
        $b[$length - 1] = $tmp * self::PRIME1 % self::CHARS_LENGTH;

        // 混淆生成邀请码
        $codeIndexArray = [];
        for ($i = 0; $i < $length; $i++) {
            $codeIndexArray[$i] = $b[$i * self::PRIME2 % $length];
        }

        $buffer = '';
        foreach ($codeIndexArray as $index) {
            $buffer .= self::$CHARS[$index];
        }
        return $buffer;
    }

    // 解密邀请码获取原始 ID
    public static function decode($code): ?int
    {

        $length = strlen($code);

        // 将字符转换为对应数字
        $a = [];
        for ($i = 0; $i < $length; $i++) {
            $c = $code[$i];
            $index = self::findIndex($c);
            if ($index == -1) {
                return null;
            }
            $a[$i * self::PRIME2 % $length] = $index;
        }

        // 逆向计算出原始 ID
        $b = [];
        for ($i = $length - 2; $i >= 0; $i--) {
            $b[$i] = ($a[$i] - $a[0] * $i + self::CHARS_LENGTH * $i) % self::CHARS_LENGTH;
        }

        $res = 0;
        for ($i = $length - 2; $i >= 0; $i--) {
            $res += $b[$i];
            $res *= ($i > 0 ? self::CHARS_LENGTH : 1);
        }
        return (int) (($res - self::SLAT) / self::PRIME1);
    }

    // 查找字符在字符集中的位置
    public static function findIndex($c): int
    {
        foreach (self::$CHARS as $key => $char) {
            if ($char == $c) {
                return $key;
            }
        }
        return -1;
    }
}

// 测试示例
$id = 123456;
$encryptedCode = InvitationCodeUtil::gen($id);
echo "加密后的邀请码: $encryptedCode\n";  // 8N79U4

$decodedUID = InvitationCodeUtil::decode($encryptedCode);
echo "解密后的 UID: $decodedUID\n";  // 123456

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值