我有一个用户的MySQL数据库。每行都有一个唯一的自动增量ID(1,2,3 ...)。现在我需要将其转换为一个独特且随机的序列号,我可以将其转换回ID - 所有这些都使用PHP。
用户ID从1到99999999999(INT(11))。
所有序列号应至少有9位数字,绝不能以0开头。 用户不应该轻易弄清楚如何猜测工作序列号。
谢谢:)
答案 0 :(得分:2)
你可以做一些简单的'加密'。取一个('秘密')素数p
27407
和base
17
(例如)。计算基础mod inv
的乘法逆p-1
,12897
。 wolframalpha可以为您做到这一点。
ID序列号
serial = id^base mod p
serial = 42^17 % 27407 = 24978
Serial to id
id = serial^inv mod p
id = 24978^12897 % 27407 = 42
这可以通过exponentiation bysquaring快速计算出来。只能使用介于0和27407之间的ID,(如果不足以采用更大的素数)并且都具有唯一的可逆序列号。
要增加隐匿性,您可以将结果与某些值进行异或。
这不是真正的加密法,只是愚蠢的security through obscurity,但会让大多数人付出相当大的努力来破解。
答案 1 :(得分:1)
最简单的答案是使用带有密钥
的秘密盐的哈希函数$secretKey = 'oh no nobody will guess this';
$userId = 312;
$serialNumber = hash('sha256', $secretKey . $userId);
哈希当然是单向运行的,因此您也必须将序列号存储在数据库中,因为您无法从给定的序列号计算ID。
答案 2 :(得分:1)
我不会建议你做你想做的事。
您看,autoincrement
通常用于表示不断避免冗余数据并仍保持可读性。
因此,请更新数据库结构以存储哈希值。结构可能有点像id
,hash
,name
等等。
在哈希中,您可以使用任何逻辑
$hash = sha1("secretanswer".$userid);
$trimmedhash = substr($has,0,9); //get a 9 digit random hash
哈希是单向加密的方式,也是有原因的。无论如何,为了验证散列,你可以再次做同样的算法
$userid = "getthissomehow";
$hash = sha1("secretanswer".$userid);
$trimmedhash = substr($has,0,9);
$prevhash = "asfaf23rfs"; //get previously stored hash somehow
if($trimmedhash == $prevhash) {
//valid
}
答案 3 :(得分:0)
首先,因为你希望能够将它从X转换为Y,从Y转换为X,所以它不能是随机的。可以做的只是数学操作,遵循以下步骤:
1.使用ID本身的常数或数字完成ID的长度为9。 只是提醒一下:你不能使用随机数字!否则它将无法双向工作。
2.进行数学操作,比如将每个数字增加1。 请注意,如果此数学运算完全改变其中一个数字,那么它几乎就是 不可能得到它。 例如,如果您将每个数字增加2并且有下一个数字:8,9 除非你使用“遗留”方法,否则你会遇到麻烦。 因此我建议将每个数字增加X,但如果DIGIT + X> 10,留下DIGIT。
3.如何将其转换回来?简单地说,向后按这些步骤。
答案 4 :(得分:0)
这是一个非常有趣的问题。希望我理解你在寻找什么。这就是我想出的:
$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.")\n";
else echo 'Test '.($tii+1).' (id: '.$ti.') was a success! (serial: '.$serial.")\n";
}
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("\n", chunk_split($hex_string, 2, "\n")));
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("\n", chunk_split($unmasked_prepended, 2, "\n")),
explode("\n", chunk_split(dechex($id), 2, "\n")),
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为> 1。 4294967295(0xFFFFFF)在这种情况下,串行将有4个额外的十六进制数字,这些数字也根据第一个数字被屏蔽。合理?希望它能满足您非常特殊的要求,或者您至少可以接受它并使其按您需要的方式工作。
运行代码的示例输出:
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)