9

我有兴趣创建像链接这样的小 url。我的想法是简单地为每个发布的长 url 存储一个递增的标识符,然后将此 id 转换为它的 base 36 变体,如下面的 PHP :

$tinyurl = base_convert($id, 10, 36)

这里的问题是结果是可以猜测的,虽然很难猜测下一个 url 将是什么,同时仍然很短(很小)。例如。atm 如果我的上一个 tinyurl 是 a1,下一个将是 a2。这对我来说是一件坏事。

那么,我如何确保生成的小 url 不是那么容易猜到但仍然很短?

4

9 回答 9

9

您要求的是减少信息(数据库中其索引的 URL)和人为增加信息(在您的序列中创建漏洞)之间的平衡。

你必须决定两者对你有多重要。另一个问题是您是否只是不希望顺序 URL 是可猜测的,或者让它们足够随机以使猜测任何有效 URL 变得困难。

基本上,您想在 N 个有效 id 中声明 n 个。选择N更小可以使URL更短,并且使n更小以生成难以猜测的URL。当使用较短的 URL 时,使 n 和 N 更大以生成更多的 URL。

要分配 id,您可以采用任何类型的随机生成器或散列函数并将其限制在您的目标范围 N。如果检测到冲突,请选择下一个随机值。如果您已达到 n 个唯一 ID 的计数,则必须增加 ID 集的范围(n 和 N)。

于 2010-08-06T21:45:16.093 回答
5

我会简单地 crc32 url

$url = 'http://www.google.com';
$tinyurl = hash('crc32', $url ); // db85f073

缺点:常量 8 字符长标识符

于 2010-08-06T21:44:59.590 回答
4

这真的很便宜,但是如果用户不知道它正在发生,那么它就不是那么容易猜到了,而是用 2 或 3 个随机数字/字母对实际 id 进行前缀和后缀。

如果我看到 9d2a1me3,我不会猜到 dm2a2dq2 是该系列的下一个。

于 2010-08-06T21:45:06.540 回答
3

尝试将 $id 与某个值进行异或,例如$id ^ 46418- 并转换回您的原始 id,您只需再次执行相同的异或,即$mungedId ^ 46418。将其与您的 base_convert 堆叠在一起,并且可能在结果字符串中交换一些字符,猜测 URL 会变得非常棘手。

于 2010-08-06T21:45:06.867 回答
2

另一种方法是设置 URL 的最大字符数(假设它是n)。然后,您可以选择一个介于 1 和 n! 之间的随机数,这将是您的排列数。

在哪个新 URL 上,您将增加 id 并使用排列编号来关联将使用的实际 id。最后,您将对您的 URL 进行 base 32(或其他)编码。这将是完全随机且完全可逆的。

于 2010-08-06T22:18:39.460 回答
1

如果你想要一个单射函数,你可以使用任何形式的加密。例如:

<?php
$key = "my secret";
$enc = mcrypt_ecb (MCRYPT_3DES, $key, "42", MCRYPT_ENCRYPT);
$f = unpack("H*", $enc);
$value = reset($f);
var_dump($value); //string(16) "1399e6a37a6e9870"

扭转:

$rf = pack("H*", $value);
$dec = rtrim(mcrypt_ecb (MCRYPT_3DES, $key, $rf, MCRYPT_DECRYPT), "\x00");
var_dump($dec); //string(2) "42"

这不会给你一个以 32 为底的数字;它将为您提供每个字节转换为基数 16 的加密数据(即,转换是全局的)。如果您真的需要,您可以使用任何支持大整数的库将其简单地转换为以 10 为底,然后以 32 为底。

于 2010-08-06T21:55:32.937 回答
0

您可以预先定义 4 个字符的代码(所有可能的组合),然后将该列表随机化并以该随机顺序将其存储在数据表中。当您想要一个新值时,只需从顶部抓取第一个值并将其从列表中删除。它速度快,无需即时计算,并保证最终用户的伪随机性。

于 2010-08-06T21:50:35.380 回答
0

Hashids是一个开源库,可以从一个或多个数字生成短的、唯一的、非连续的、类似 YouTube 的 ID 。您可以将其视为一种混淆数字的算法

它将像 347 这样的数字转换成像 "yr8" 这样的字符串,或者像 [27, 986] 这样的数组转换成 "3kTMd"。您还可以将这些 id 解码回来。这对于将多个参数捆绑到一个或简单地将它们用作短 UID 很有用。

您不想向用户公开数据库ID时使用它。

它允许自定义字母表和盐,所以 id 只对你来说是唯一的。

增量输入被破坏以保持不可猜测。

没有冲突,因为该方法基于整数到十六进制的转换。

编写它的目的是将创建的 id 放置在可见的位置,例如 URL。因此,该算法避免生成最常见的英语诅咒词。

代码示例

$hashids = new Hashids();
$id = $hashids->encode(1, 2, 3); // o2fXhV
$numbers = $hashids->decode($id); // [1, 2, 3]
于 2016-10-16T22:40:53.283 回答
-1

我最终创建了一个标识符的 md5 总和,使用它的前 4 个字母数字,如果这是重复的,只需增加长度直到它不再是重复的。

function idToTinyurl($id) {
    $md5 = md5($id);
    for ($i = 4; $i < strlen($md5); $i++) {
        $possibleTinyurl = substr($md5, 0, $i);
        $res = mysql_query("SELECT id FROM tabke WHERE tinyurl='".$possibleTinyurl."' LIMIT 1");
        if (mysql_num_rows($res) == 0) return $possibleTinyurl;
    }
    return $md5;
}

接受 relet 的回答,因为它引导我采用这种策略。

于 2010-08-06T23:43:48.493 回答