唯一卡号生成
功能概述
该 PHP 类 TkCardFlake
用于生成预付卡卡号。它通过时间戳、序号、工作节点 ID 和 Luhn 校验算法来生成唯一且符合卡号格式的字符串。
主要功能模块
类常量
INIT_DATE
: 初始时间戳,用于计算相对时间。SEQUENCE_MAX
: 序列号的最大值,限制在 999 以内。
构造函数
- 初始化类的实例,设置
workerId
。workerId
不能超过 9,否则抛出异常。
- 初始化类的实例,设置
GetCardInfo
方法- 生成卡号的核心方法,通过当前时间戳和序列号生成卡号,并附加 Luhn 校验码。
now
方法- 返回当前的 Unix 时间戳(秒)。
luhnCheck
方法- 实现 Luhn 算法,用于生成卡号的校验码。
代码优化与说明
<?php
namespace Extend;
use Exception;
// 生成预付卡卡号
class TkCardFlake
{
// 初始化常量
public const INIT_DATE = 1691352000; // '2023-08-07 04:00:00 000';
public const SEQUENCE_MAX = 999; // 序号最大值
public int $workerId = 0;
public int $sequence = 0;
public int $timestamp = 0;
/**
* 构造函数,初始化 workerId
* @param int $workerId
* @throws Exception
*/
public function __construct(int $workerId = 0)
{
if ($workerId > 9) {
throw new Exception('生成卡号失败,workerId不能大于9。');
}
$this->workerId = $workerId;
}
/**
* 生成卡号
* @param string $cardBin 卡片前缀
* @return string
* @throws Exception
*/
public function GetCardInfo(string $cardBin): string
{
$now = $this->now();
if ($this->timestamp == $now) {
$this->sequence++;
if ($this->sequence > self::SEQUENCE_MAX) {
// 当前毫秒内生成的序号已经超出最大范围,等待下一毫秒
do {
$now = $this->now();
} while ($now <= $this->timestamp);
}
} else {
$this->timestamp = $now;
$this->sequence = 0;
}
$difftime = str_pad($this->timestamp - self::INIT_DATE, 10, '0', STR_PAD_LEFT);
$sequence = str_pad($this->sequence, 3, '0', STR_PAD_LEFT);
// 拼接卡号: workerId(1位) + difftime(10位) + sequence(3位)
$no = $this->workerId . $difftime . $sequence;
$cardBinNo = $cardBin . $no;
// 计算Luhn校验码
$checkNo = $this->luhnCheck($cardBinNo) % 10 == 0 ? 0 : 10 - ($this->luhnCheck($cardBinNo) % 10);
return $cardBinNo . $checkNo;
}
/**
* 获取当前秒级时间戳
* @return string
*/
private function now(): string
{
return time();
}
/**
* 计算Luhn校验和
* @param string $number
* @return int
*/
private function luhnCheck(string $number): int
{
$reversedNumber = strrev($number);
$sum = 0;
for ($i = 0; $i < strlen($reversedNumber); $i++) {
$digit = (int)$reversedNumber[$i];
if ($i % 2 == 1) {
$digit *= 2;
if ($digit > 9) {
$digit -= 9;
}
}
$sum += $digit;
}
return $sum;
}
}
代码功能说明
类属性与常量
INIT_DATE
: 起始时间,用于计算相对时间。SEQUENCE_MAX
: 每秒最多生成 1000 个卡号。
GetCardInfo
方法- 根据当前时间戳、序列号和
workerId
生成卡号。 - 使用 Luhn 算法生成校验位。
- 根据当前时间戳、序列号和
luhnCheck
方法- 反转卡号并对奇数位数字加倍,计算总和来生成校验位。
使用方法
- 创建一个
TkCardFlake
实例并传入workerId
。 - 调用
GetCardInfo
方法并传入卡片前缀(cardBin
)来生成卡号。
优化建议
- 将时间戳和序列号处理封装成独立方法,提高代码复用性。
- 确保
workerId
在多实例中唯一,以避免生成重复卡号。
总结
这段代码提供了一个生成唯一预付卡号的高效机制,通过时间戳、序列号和 Luhn 校验的组合确保了卡号的唯一性和有效性。