123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- <?php
- namespace loyalsoft;
- /**
- * 激活码数据结构
- */
- class ActiveCode {
- /**
- * 平台编号
- * @var int
- */
- public $plat;
- /**
- * 礼包编号
- * @var int
- */
- public $package;
- /**
- * 编号
- * @var int
- */
- public $number;
- }
- /**
- * 在定制的Base32(去掉了 0 和 o, 1 和 l. 使用剩余的 24个小写字母和8个数字)基础上使用
- * 密码本算法打乱字母规律, 并对number进行了散列, 增加猜解难度.
- * @author gwang 2016.2
- */
- class CipheredBase32 {
- const codeLength = 10; # 兑换码的长度固定为10
- /**
- * 密码本
- * @return string
- */
- public static function charMap() {
- return GameConstants::GetCipherString(); # 密码本
- }
- /**
- * 解码
- * @param string $codeString
- * @return \ActiveCode
- * @throws \Exception
- */
- public static function Decode($codeString) {
- if (self::codeLength != strlen($codeString)) { # 校验兑换码字符串长度
- return "activecode length wrong!";
- } else {
- $bytesof5bits = array(); # 将字符串转为索引数组:=[0..32]{10}
- $cipher = self::charMap();
- for ($i = 0; $i < self::codeLength; $i++) {
- $c = $codeString[$i]; # 取字符
- $b = strpos($cipher, $c); # 按照密码本还原真实字符的索引
- if ($b < 32 && $b > -1) { # 索引范围校验
- $bytesof5bits[] = $b;
- } else {
- // CLogUtil::console("b ($b)is not a valid index ");
- }
- }
- $by8bits = self::fetch5BitByte($bytesof5bits); # 将索引数组转为字节数组:=[0..256]{5}
- $activeCode = new ActiveCode(); # 创建对象
- $activeCode->plat = $by8bits[1]; # 第一个字节: 平台
- $activeCode->package = $by8bits[3]; # 第二个字节: 礼包编号
- $i = 0; # 临时变量
- $i += ($by8bits[0] ^ $by8bits[3] ^ $by8bits[1]); # 剩余字节为兑换码的编号, 低8位
- $i += ( $by8bits[4] ^ $by8bits[3] ^ $by8bits[1] ) << 8; # 高8位
- $i += ($by8bits[2] ^ $by8bits[3] ^ $by8bits[1] ) << 16; # 第17-24位
- $i += ($by8bits[5] ^ $by8bits[3] ^ $by8bits[1] ) << 24; # 第25-32位
- $i = self::uint32val($i); # 提取编号(32位环境,大int值会转为float进行运算)
- $i = 4294967295 - $i; # 补码才是真正的编号
- $i /= 85889; # 编号再除以一个特殊值才还原为最终编号
- if (intval($i) - $i == 0) { # 确认是合法整数
- $activeCode->number = intval($i);
- }
- return $activeCode;
- }
- }
- /**
- * php本身没有unint类型, 网上找的,具体代码看不懂--gwang
- * @param type $var
- * @return type
- */
- static function uint32val($var) {
- if (is_string($var)) { # 字符串
- if (PHP_INT_MAX > 2147483647) { # 大于32位
- $var = intval($var);
- } else { # 利用float来避免数值较大时损失高位信息
- $var = floatval($var);
- }
- }
- if (!is_int($var)) {
- $var = intval($var); # 再次强转int
- }
- if ((0 > $var) || ($var > 4294967295)) {
- $var &= 4294967295; # uint32最大值
- if (0 > $var) {
- $var = sprintf('%u', $var); # 转为uint(string)
- }
- }
- return $var;
- }
- /**
- * 转换 10个 5bit Bytes 到 6个 8bit Bytes
- * @param array $data 长度不小于10的字节数组
- * @return array
- */
- static function fetch5BitByte($data) {
- $ret5 = array();
- $ret5[0] = ( $data[0] + intval(( $data[1] & 0x7) << 5)); # 5 + 3 = 8
- $ret5[1] = ( intval(($data[1] & 0x18 ) >> 3) # 2 + 5 + 1 = 8
- + intval($data[2] << 2) + intval(($data[3] & 0x1) << 7));
- $ret5[2] = ( intval(($data[3] & 0x1E) >> 1) # 4 + 4 = 8
- + intval(($data[4] & 0xf) << 4));
- $ret5[3] = ( intval(($data[4] & 0x10) >> 4) # 1 + 5 + 2 = 8
- + intval($data[5] << 1) + intval(($data[6] & 0x3) << 6));
- $ret5[4] = ( intval(($data[6] & 0x1C) >> 2) + intval($data[7] << 3)); # 3 + 5 = 8
- $ret5[5] = ( intval(($data[8]) + intval($data[9] << 5))); # 5 + 3 = 8
- return $ret5;
- }
- }
|