Convert auto increment ID to 9 digit random serial number
我有一个带有用户的MySQL数据库。 每行都有一个唯一的自动增量ID(1,2,3 ...)。 现在,我需要将其转换为唯一且随机的序列号,我可以将其转换回ID-全部使用PHP。
用户ID从1到99999999999(INT(11))。
所有序列号均应至少包含9位数字,且切勿以0开头。
用户应该不容易发现如何猜测有效的序列号。
谢谢 :)
您可以进行一些简单的"加密"。以('秘密')素数
ID到序列号
1 2 | serial = id^base mod p serial = 42^17 % 27407 = 24978 |
序列号到ID
1 2 | id = serial^inv mod p id = 24978^12897 % 27407 = 42 |
这可以通过平方求幂快速计算。只能使用0到27407之间的ID(如果不够,请使用更大的质数),并且所有ID都具有唯一的可逆序列号。
为了增加模糊度,您可以将结果与某些值进行XOR。
这不是真正的密码学,只是由于晦涩难懂的愚蠢安全性,但是将需要大多数人付出相当大的努力才能破解。
我不建议您做您想做的事情。
您会看到,通常用
因此,改为更新数据库结构以存储哈希值。该结构可能有点像
在哈希中,您可以使用任何逻辑
1 2 |
哈希是加密的一种方式,也是有原因的。无论如何,为了验证哈希,您可以再次执行相同的算法
1 2 3 4 5 6 7 8 |
最简单的答案是使用带有秘密盐作为键的哈希函数
1 2 3 | $secretKey = 'oh no nobody will guess this'; $userId = 312; $serialNumber = hash('sha256', $secretKey . $userId); |
哈希当然是单向的,所以您也必须将序列号存储在数据库中,因为您无法根据给定的序列号计算ID。
这是一个非常有趣的问题。希望我了解您在寻找什么。这是我想出的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | $test_limit = 25; $test_ids = array(1, 99999999999); for($i=0; $i<($test_limit-2); $i++) $test_ids[] = mt_rand(1, 99999999999); foreach($test_ids as $tii=>$ti) { $serial = getSerialUsingId($ti); $id = getIdUsingSerial($serial); if($id!=$ti) echo 'Test '.($tii+1).' (id: '.$ti.') FAILED! (serial: '.$serial.")\ "; else echo 'Test '.($tii+1).' (id: '.$ti.') was a success! (serial: '.$serial.")\ "; } function getMask($index, $places=8) { $masks = array ( 0xac976f4, 0x1c70f81, 0x441f67f, 0x5fb0b87, 0xf1542d2, 0xfa28851, 0x91bbd8c, 0x30a5448, 0x46a2708, 0x5856fbf, 0x65fa462, 0xf24337b, 0xea2c390, 0x8561da4, 0x9f77b25 ); if($places==4) return $masks[$index] & 0x0000FFFF; else return $masks[$index]; }// getMask function getSerialUsingId($id) { $prepend = ''; $mask_index = mt_rand(0, 14); // 8 hex places can only handle up to 4294967295 // If the number is greater than than that then get the additional bytes and treat separate if($id>0xffffffff) { $packed = pack('d', $id); $hex_pack = unpack('H*', $packed); $hex_string = substr($hex_pack[1],4); $bytes = array_reverse(explode("\ ", chunk_split($hex_string, 2,"\ "))); foreach($bytes as $bi=>$b) if(!$b) unset($bytes[$bi]); $truncated_bytes = array_splice($bytes,0,count($bytes)-4); $truncated = implode('', $truncated_bytes); $prepend = dechex(hexdec($truncated) ^ getMask($mask_index, 4)); } $serial = dechex($mask_index+1).$prepend.str_pad(dechex($id ^ getMask($mask_index)), 8, '0', STR_PAD_LEFT); return $serial; }// getSerialUsingId function getIdUsingSerial($serial) { $mask_index = hexdec($serial[0])-1; $serial = substr($serial, 1); $prepended = false; if(strlen($serial)>9) { $prepended = substr($serial, 0, 4); $serial = substr($serial, 4); } $id = hexdec($serial) ^ getMask($mask_index); if($prepended) { $unmasked_prepended = dechex(hexdec($prepended) ^ getMask($mask_index, 4)); $bytes = array_reverse(array_merge ( explode("\ ", chunk_split($unmasked_prepended, 2,"\ ")), explode("\ ", chunk_split(dechex($id), 2,"\ ")), array('00','00') )); foreach($bytes as $bi=>$b) if(!$b) unset($bytes[$bi]); $packed = pack('H*', implode('', $bytes)); $unpacked = unpack('d', $packed); $id = $unpacked[1]; } return $id; }// getIdUsingSerial |
基本上,序列号以十六进制表示,第一个十六进制数字确定在其余数字上使用哪个位掩码。这使所有序列的长度为9个字符,但id大于4294967295(0xFFFFFF)时除外,在这种情况下,序列将具有4个附加的十六进制数字,这些数字也将根据第一个数字进行屏蔽。合理?希望它可以满足您非常特殊的要求,或者至少可以接受并根据您的需要进行工作。
运行代码的示例输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | Test 1 (id: 1) was a success! (serial: 60fa28850) Test 2 (id: 99999999999) was a success! (serial: 24db649b1e87e) Test 3 (id: 487808132) was a success! (serial: 31952aafb) Test 4 (id: 227726272) was a success! (serial: 40869d847) Test 5 (id: 836896236) was a success! (serial: 53ef7473e) Test 6 (id: 958345007) was a success! (serial: 93d750827) Test 7 (id: 164308905) was a success! (serial: 30d8ad1d6) Test 8 (id: 715018588) was a success! (serial: 1205727a8) Test 9 (id: 1127737044) was a success! (serial: 8403db29c) Test 10 (id: 409934489) was a success! (serial: 81b654ed1) Test 11 (id: 907129123) was a success! (serial: f3fe6ca06) Test 12 (id: 720453497) was a success! (serial: b2cae9b1b) Test 13 (id: 500526447) was a success! (serial: 1171c1b9b) Test 14 (id: 322340582) was a success! (serial: 119fff012) Test 15 (id: 1176988677) was a success! (serial: b4078c867) Test 16 (id: 698755861) was a success! (serial: 92dcc0c1d) Test 17 (id: 555569451) was a success! (serial: 52e0813f9) Test 18 (id: 227332917) was a success! (serial: a0809bc8a) Test 19 (id: 819326158) was a success! (serial: 334941ab1) Test 20 (id: 659803411) was a success! (serial: d29f10e83) Test 21 (id: 895574245) was a success! (serial: d3bc3a375) Test 22 (id: 539979792) was a success! (serial: 425d47b97) Test 23 (id: 933093554) was a success! (serial: 83497b4fa) Test 24 (id: 959556569) was a success! (serial: 93d5b8cd1) Test 25 (id: 668064949) was a success! (serial: 22616d334) |
首先,因为您希望能够将其从X转换为Y并将其从Y转换为X,所以它不能是随机的。可以按照以下步骤进行数学操作:
1.使用常量数字或ID本身中的数字将ID的长度补全为9。
提醒您:您不能使用随机数字!否则,它不会同时起作用。
2.进行数学运算,例如将每个数字增加1。
请注意,如果此数学操作完全更改一位数字,则几乎
无法取回。
例如,如果您将每个数字加2,然后又有几个数字:8,9
除非您使用"结转"方法,否则您将遇到麻烦。
因此,我建议将每个数字增加X,但如果DIGIT + X> 10,则将其保留为DIGIT。
3.如何转换回去?只需简单地向后执行这些步骤。