更快,如果可能的话,更少的内存成本方法生成字母数字代码?

时间:2011-09-02 08:30:17

标签: php

我正在尝试在没有数据库的情况下进行非常简单的短URL重定向。

这是我到目前为止所做的:

<?php
$name = $_GET['file'];
$name = preg_replace("/[^A-Za-z0-9]/", '', $name);
$file = 'data/' . $name;

// File found
if (is_file($file))
{
    // Read the first line, we don't use file_get_contents as the data folder is protected and must be read internally
    $f = fopen($file, 'r');
    $data = fgets($f);
    fclose($f);

    // Redirect to the real URL
    header("Location: $data");
}
else
{
    // What a shame the URL does not exist
    header("Location: http://www.mydomain.com/");
}

exit();
?>
  • 我想知道什么会更快,如果 从中生成字母数字代码的可能更少的内存成本方法 6到8个字符,不会与现有的字符发生冲突 数据文件夹?

3 个答案:

答案 0 :(得分:1)

正如我所看到的,您要为每个要添加到数据文件夹的新文件生成字母数字代码,并且这些文件的内容是您要重定向到的位置。

你使用的方法对我来说很好。只是一些建议:

您可以使用$name MD5哈希来命名数据文件夹中的文件,这样您就不需要删除此行中的非字母字符:

preg_replace("/[^A-Za-z0-9]/", '', $name);

只需计算哈希值来获取文件名:

file_name = md5($name);

这样的文件名也是唯一的。

另一个建议是,如果您真的不想使用数据库,请使用XML文件来存储重定向。使用SimpleXML可以轻松完成(请参阅示例)。

答案 1 :(得分:1)

您是否还要求对于任何给定的网址,必须能够查找短代码?只计算数字的系统就可以生成唯一的文件名,但当然这不是一种可重复的方法,所以如果同一个网址多次进行,每次都会出现不同的密钥。

如果这是可以接受的,那么我只是建议一个计数器,可能在36(基于不区分大小写的字母数字)或类似的位置,以给你最大的密钥空间大小。您可以拥有一个包含当前计数的文件(也可以存储在内存中但需要在重新启动时重新加载)然后您必须注意多线程访问同时读取下一个值。

如果您需要给定的URL始终具有相同的ID,那么您可以使用第二个目录存储以url命名的文件(根据需要进行转义),其中包含您第一次为它们生成的密钥。生成新密钥时,您可以在此文件目录中查找,如果该网址已有密钥,则返回该密钥,如果该密钥存在,则返回该密钥。

正如您所看到的,这基本上粗略地复制了数据库将使用两个目录基本上是url和key表上的索引的方式。

我能想到的唯一另一种方法是让一些一对一的功能保证您正在查看的输入以生成一定长度的字符串。我想不出你会在哪里找到这样的功能。压缩算法是最接近的东西,但它们当然会生成不太适合您需要的输出(因为它压缩到的二进制文件可能与原始字符串一样大,一旦它被base64编码或类似)

fardjad建议的散列函数可能没问题但是没有办法从散列值返回到url并且无法保证两个输入是唯一的(尽管它们不是这样的可能性是极小)。

我怀疑fardjad的解决方案在实践中会达到你需要的程度,但这取决于它需要多么强大。

我最后应该注意到我从来没有写过或关注过较短的网址服务,所以我所说的都不是专家建议,只是考虑如果我没有做过研究我会怎么做。 :)

答案 2 :(得分:1)

如果我说错了你的粘贴代码是url重定向逻辑,而不是文件名生成,对吧?我建议您使用单线程进程(例如,node.js服务器)来生成和维护max_number值。

每次需要新文件名时,只需向该服务器发送请求即可。服务器递增max_number并返回其当前值。然后在PHP代码中,将此整数转换为由字母数字字符组成的字符串。 PHP gmp_strval函数可以通过将数字转换为base-62格式来完成此任务。

这种方式是安全的,因为它以简单的方式保证绝对唯一性。我想这是许多公共网址缩短服务使用的常用方法,因为我注意到它们的字符串会自然增加。

当然,gmp_strval功能可以在您自己的代码中轻松实现,如果它在您的计算机上不可用。这里有一些例子:How to convert an integer in any base to a string?

这种服务越短越好。但是如果你想要6-8个字符,只需要以base-62字符串“100000”(十进制形式的916132832)开头。