12

任何人都可以推荐一种用于 URL 缩短的首选算法吗?我正在使用 PHP 进行编码。最初我想写一些东西,从一个字符开始,比如“a”并遍历请求,在数据库中创建记录,因此必须将字符增加到 b、c、d ... A、B 等等合适的。

然而,我突然意识到这个算法可能非常繁重/笨拙,并且可能有更好的方法来做到这一点。

我在 Google 上阅读了一些内容,有些人似乎是通过数据库 ID 列的基本转换来完成的。这不是我太熟悉的东西。

有人可以详细说明并向我解释这将如何工作吗?几个代码示例也会很棒。

我显然不想要一个完整的解决方案,因为我想自己学习,但只是一个关于它如何工作的解释/伪代码会很好。

4

7 回答 7

17

大多数缩短服务只使用一个随着每个条目递增的计数器,并将基数从 10 转换为 64。

PHP 中的实现可能如下所示:

function encode($number) {
    return strtr(rtrim(base64_encode(pack('i', $number)), '='), '+/', '-_');
}
function decode($base64) {
    $number = unpack('i', base64_decode(str_pad(strtr($base64, '-_', '+/'), strlen($base64) % 4, '=')));
    return $number[1];
}

$number = mt_rand(0, PHP_INT_MAX);
var_dump(decode(encode($number)) === $number);

encode函数接受一个整数,将其转换为字节 ( pack),使用 Base-64 编码 ( base64_encode) 对其进行编码,修剪尾随填充=( rtrim),并分别替换字符+/by-_( strtr)。该decode函数是反函数encode并且完全相反(添加尾随填充除外)。

的额外用途strtr是将原始 Base-64 字母表转换为URL 和文件名安全字母表+并且/需要使用百分比编码进行编码。

于 2010-08-18T17:00:25.897 回答
4

您可以使用 base_convert 函数使用数据库 ID 进行从 10 到 36 的基本转换。

<?php
   $id = 315;
   echo base_convert($id, 10, 36), "\n";
?>

或者您可以重用以下页面评论中提出的一些想法:

http://php.net/manual/en/function.base-convert.php

于 2010-08-18T16:16:18.127 回答
2

假设你的 PRIMARY KEY 是一个 INT 并且它是 auto_increments,下面的代码会让你开始 =)。

<?php

    $inSQL = "INSERT INTO short_urls() VALUES();";
    $inResult = mysql_query($inSQL);
    $databaseID = base_convert(mysql_insert_id(), 10, 36);

    // $databaseID is now your short URL

?>

编辑:包括来自 HGF 答案的 base_convert。我忘记在原始帖子中使用 base_convert 了。

于 2010-08-18T16:08:27.583 回答
1

我曾经通过类似于如何从十进制转换为十六进制的算法来打破 ID,但它将使用 62 个字符而不是十六进制将使用的 16 个字符。

'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'

示例:如果您更改 ID = 1234567890,您将获得kv7yl1作为您的密钥。

于 2010-08-18T16:17:44.113 回答
1

我采用了“轻”的解决方案。根据用户请求,我使用此 python 片段生成唯一标识符(检查 db 中的冲突):

url_hash = base64.b64encode(os.urandom(int(math.ceil(0.75*7))))[:6]

并将其存储在数据库中。

于 2010-08-18T16:32:58.907 回答
1

原生 PHP base_convert() 适用于小范围的数字,但如果您确实需要对较大的值进行编码,请考虑使用类似此处提供的实现,如果您只是为编码提供更多合法字符,它将适用于 base 64 及以上.

http://af-design.com/blog/2010/08/10/working-with-big-integers-in-php/

于 2010-08-18T17:18:08.090 回答
0

在这里试试这个方法:

hash_hmac('joaat', "http://www.example.com/long/url/", "secretkey");

它将为您提供适合专业网址缩短器的哈希值,例如:' 142ecd53 '

于 2015-08-23T02:50:56.663 回答