如何在PHP中创建有效的编码/解码唯一ID

时间:2014-07-28 01:44:05

标签: php base64 unique base32

我正在尝试找到一种将数据库ID编码为短URL的方法,例如1应该成为" Ys47R"。然后我想从" Ys47R"为1我可以使用INT值运行数据库搜索。它需要使用数据库ID是唯一的。该序列不容易猜测,例如1 =" Ys47R",2 =" Ys47S"。它应该是YouTube或者URL's的内容。我已经使用md5base32base64和`bcpow阅读了数百个不同的来源,但是已经空了。

This blog post看起来很有希望,但是一旦我添加了填充和密码,短ID(例如1)变为SDDDG,2变为" SDDDH" 3成了" SDDDI"。它不是很随机。

base32仅使用a-b 0-9 base64最后有==等字符。

然后我尝试了这个:

function getRandomString($db, $length = 7) {

    $validCharacters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $validCharNumber = strlen($validCharacters);
    $result = "";

    for ($i = 0; $i < $length; $i++) {
        $index = mt_rand(0, $validCharNumber - 1);
        $result .= $validCharacters[$index];
    }

哪个有效,但意味着每次都必须运行数据库查询以确保没有冲突,并且数据库中不存在冲突。

有没有一种方法可以创建最短为4个字符的短ID's,其中[a-z][A-Z][0-9]的字符集可以使用数据库中的增量唯一ID进行编码和解码。每个号码都是唯一的。我无法使用base32base64了解先进技巧。

或者我是否对此进行过多调查并且有更简单的方法可以做到这一点?是否最好在上面执行随机字符串函数并查询数据库以始终检查唯一性?

2 个答案:

答案 0 :(得分:0)

您可以使用评论中的功能:http://php.net/manual/en/function.base-convert.php#106546

$initial = '11111111';
$dic = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
var_dump($converted = convBase($initial, '0123456789', $dic)); 
// string(4) "KCvt"
var_dump(convBase($converted, $dic, '0123456789')); 
// string(8) "11111111"

function convBase($numberInput, $fromBaseInput, $toBaseInput)
{
    if ($fromBaseInput==$toBaseInput) return $numberInput;
    $fromBase = str_split($fromBaseInput,1);
    $toBase = str_split($toBaseInput,1);
    $number = str_split($numberInput,1);
    $fromLen=strlen($fromBaseInput);
    $toLen=strlen($toBaseInput);
    $numberLen=strlen($numberInput);
    $retval='';
    if ($toBaseInput == '0123456789')
    {
        $retval=0;
        for ($i = 1;$i <= $numberLen; $i++)
            $retval = bcadd($retval, bcmul(array_search($number[$i-1], $fromBase),bcpow($fromLen,$numberLen-$i)));
        return $retval;
    }
    if ($fromBaseInput != '0123456789')
        $base10=convBase($numberInput, $fromBaseInput, '0123456789');
    else
        $base10 = $numberInput;
    if ($base10<strlen($toBaseInput))
        return $toBase[$base10];
    while($base10 != '0')
    {
        $retval = $toBase[bcmod($base10,$toLen)].$retval;
        $base10 = bcdiv($base10,$toLen,0);
    }
    return $retval;
}

答案 1 :(得分:0)

如果你想要一些对称的混淆,那么base_convert()通常就足够了。

base_convert($id, 10, 36);

将返回1i0g之类的字符串并将其转换回来。

在基本转换之前和之后,您可以添加:

  • 要获得最小字符串长度,我建议您只在70000添加$id。然后在接收端再次减去它。

  • 次要乘法$id *= 3会在生成的字母数字ID范围中添加一些“漏洞”,但不会耗尽可用的字符串空间。

  • 对于某些随意性的外表,有点轻咬:

    $id = ($id & 0xF0F0F0F) << 4    
        | ($id & 0x0F0F0F0) >> 4;
    

    适用于生成混淆的ID字符串,并返回原始字符串。

    为了清楚起见:这是没有任何形式的加密。 只是在连续数字之间移动数字跳跃,看起来更随意。

您仍然可能不喜欢这个答案,但在数据库中生成随机ID是唯一真正阻碍身份证猜测的方法。