用于URL缩短算法的PHP实现

时间:2011-02-01 10:18:44

标签: php url

我发现Marcel Jackwerth'sHow to code a URL shortener?的回复是问题的一个很好的答案,但我的问题是它在PHP中的外观如何?这是Marcel's answer


你需要一个Bijective Function f(必须没有x1 != x2,这将f(x1) = f(x2);而且每一个你都会找到斧头{{1} })。这是必要的,以便您可以为f(x)=y函数找到反函数g('abc') = 123

我会继续您的“转换数字到字符串”方法(但是如果您的f(123)='abc' prime 并且更高,您会意识到提议的算法会失败比52)。

如何将id转换为缩短的网址

  • 想想你想要使用的字母。在你的情况下是[a-zA-Z0-9]。它包含62个字母。
  • 使用自动生成的唯一数字键(自动递增id):例如125(十进制数)
  • 现在你必须将125(基数10)转换为 X (基数为62)。然后这将是{2} {1}(2×62 + 1 = 125)。
  • 现在将符号{2}和{1}映射到您的字母表。说{0} ='a',{25} ='z'等等。我们将{2} ='c'和{1} ='b'。所以'/ cb'将是你缩短的网址。

如何将缩短的网址id解析为初始abc

  • 如果你想反向做这件事,那就不是很困难了。 'e9a'将被解析为“第4,第61,第0个字母”= {4} {61} {0},即4×62×62 + 61×62 + 0 = 19158.您将只需要使用id 19158找到您的数据库记录。

4 个答案:

答案 0 :(得分:1)

function convert($src, $srcAlphabet, $dstAlphabet) {
    $srcBase = strlen($srcAlphabet);
    $dstBase = strlen($dstAlphabet);

    $wet = $src;
    $val = 0;
    $mlt = 1;

    while ($l = strlen($wet)) {
        $digit = $wet[$l - 1];
        $val += $mlt * strpos($srcAlphabet, $digit);
        $wet = substr($wet, 0, $l - 1);
        $mlt *= $srcBase;
    }

    $wet = $val;
    $dst = '';

    while ($wet >= $dstBase) {
        $digitVal = $wet % $dstBase;
        $digit = $dstAlphabet[$digitVal];
        $dst = $digit . $dst;
        $wet /= $dstBase;
    }

    $digit = $dstAlphabet[$wet];
    $dst = $digit . $dst;

    return $dst;
}

// prints cb
print convert('125', '0123456789', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');

// prints 19158
print convert('e9a', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', '0123456789');

答案 1 :(得分:0)

我喜欢这个PHP函数,它允许你自定义字母表(并删除令人困惑的0 / O等)。

// From http://snipplr.com/view/22246/base62-encode--decode/
private function base_encode($val, $base=62, $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
    $str = '';
    do {
        $i = fmod($val, $base);
        $str = $chars[$i] . $str;
        $val = ($val - $i) / $base;
    } while($val > 0);
    return $str;
}

按照URL查找反向'解码'功能。

答案 2 :(得分:0)

Marcel解决方案的主要问题是它使用零位作为占位符。通过在碱基之间进行转换,选择代表0的数字不可避免地出现在转换数字的前面。

例如,如果使用提供的机制使用“ABCD”将基数10整数转换为基数4,则无法获得以字母“A”开头的输出,因为它表示新基数中的零和不会在数字前加上前缀。你可能会认为5是“AA”,而是“BA”。没有办法强制该算法生成“AA”,因为它就像在十进制中写“00”,其值与“0”相同。

这是PHP中使用整个色域的替代解决方案:

function encode($n, $alphabet = 'ABCD') {
    $output = '';

    if($n == 0) {
        $output = $alphabet[0];
    }
    else {
        $digits = floor(log($n, strlen($alphabet))) + 1;

        for($z = 0; $z < $digits; $z++) {
            $digit = $n % 4;
            $output = $alphabet[$digit] . $output;
            $n = floor($n / 4) - 1;
        }
    }
    return $output;
}

function decode($code, $alphabet = 'ABCD') {
    $n = 0;
    $code = str_split($code);
    $unit = 1;
    while($letter = array_pop($code)) {
        $n += (strpos($alphabet, $letter) + 1) * $unit;
        $unit = $unit * strlen($alphabet);
    }

    return $n - 1;
}

echo encode(25); // should output "ABB"
echo decode('ABB'); // should output 25

将第二个参数更改/传递给要使用的字符列表,而不是“ABCD”的短4字符字典。

答案 3 :(得分:-1)

您需要做的就是在不同的基础系统基础10到基础62之间进行转换

https://github.com/infinitas/infinitas/blob/dev/core/short_urls/models/short_url.php