【问题标题】:How to create a efficient encode/decode unique ID in PHP如何在 PHP 中创建高效的编码/解码唯一 ID
【发布时间】:2014-09-19 04:20:59
【问题描述】:

我正在尝试找到一种将数据库 ID 编码为短 URL 的方法,例如1 应该变成“Ys47R”。然后我想将它从“Ys47R”解码回 1,这样我就可以使用 INT 值运行数据库搜索。它需要使用数据库ID 是唯一的。序列不应轻易猜到,例如 1 = "Ys47R", 2 = "Ys47S"。它应该类似于 YouTube 或 bitly 的 URL's。我已经阅读了数百个使用 md5、base32、base64 和 `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];
    }

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

有没有一种方法可以创建简短的ID's,最少 4 个字符,[a-z][A-Z][0-9] 的字符集可以编码和解码回来,在每个数字都是唯一的数据库中使用增量唯一 ID。我无法理解使用base32 或base64 的高级技术。

或者我是否对此进行了太多研究,并且有更简单的方法可以做到这一点?最好是做上面的随机字符串函数,一直查询数据库检查唯一性吗?

【问题讨论】:

  • 目的是什么?如果编码的数字不可预测,那么是的,您必须随机生成它们,检查是否存在并将它们存储在您的表实际 id 键旁边。
  • 目的是把 url 变成 bit.ly 类型的 url。因此,我可以使用 $_GET 参数来获取 id,将其转换回原始 int,以便我可以检查数据库他们所指的页面,以便我可以提取详细信息。因此,经过大量阅读后,我看到了两个选项,1 创建和检查 db,当创建大量页面时,也会增加发生冲突的机会,或者正如其他人提到的那样,像 youtube、bitly 和 using 那样即时创建它base64 表示创建时不对数据库进行检查,可以即时完成,每个数字都是唯一的,最多可达数十亿
  • 主题明确。但是为什么要转换页面ID?它是否意味着伪安全功能?这基本上只是混淆。 (对于那个 base32 来说,通过添加一个基值来提高输出长度就足够了,再加上一些洗牌。)
  • 没错,应该是更多的混淆,加上好看的url。一个例子是用户将向客户发送报告链接,因此看起来不错的短网址。同时,虽然不是机密和公共知识,但我不希望有人开始在 url 中从用户或客户端输入 id 号的 1、2、3、4 来查看其他人的工作,等等。
  • 你能用 base64 减去 == 符号做洗牌位并将其解码回来吗?这是我在提到它时找到的链接,它没有说明他们如何使用 base64 创建 ID,但类似的概念是使用 $_get 获取唯一短网址 stackoverflow.com/questions/2308579/…

标签: php base64 unique base32


【解决方案1】:

您可以使用 cmets 中的函数: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;
}

【讨论】:

  • 我确实看到了这个和那个方法让我回到我关于短 ID 的问题,例如 1。如果你看一下,如果你输入 1,生成的 id 也是 1,即使你去11结果是a,所以我这里提到了两个问题,也不是像“Ys47R”这样的ID,也不是不可预知的,一切都是那么容易猜到的。
  • @user3882771 ,如果你真的需要从Ys47R开始,只需在编码前加上数字'893269206',在解码后减去。
  • 感谢尝试,似乎达到了预期的效果
【解决方案2】:

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

base_convert($id, 10, 36);

将返回像1i0g 这样的字符串并将它们转换回来。

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

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

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

  • 对于一些随意的外观,一点点移动:

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

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

    明确一点:这是没有任何形式的加密。它只是在连续数字之间移动数字跳跃,看起来稍微随意一些。

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

【讨论】:

  • 进行数据库检查会比即时编码和解码更快还是更好?
  • 使用分析器,而不是猜测。如果实施得当,两者都不重要。
  • 是的,我可以为您搜索:Simplest way to profile a PHP script
  • 谢谢,我刚刚意识到创建一个随机 ID 并将其保存到数据库中,然后检查它是否存在,所以我还需要创建一个检测方法来识别组合何时用完并且我需要增加 randomID 的长度以适应更多组合。似乎要实现一些基本的东西需要很多麻烦,我想知道 bit.ly、youtube 是如何做到的。他们是否会搜索数百万条记录以查看 ID 是否存在?当它们达到极限时,增加长度?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 1970-01-01
  • 2014-05-14
  • 1970-01-01
相关资源
最近更新 更多