如何设计顺序类似哈希的函数

时间:2012-03-21 11:52:18

标签: php algorithm hash

我想开发类似于jsfiddle的东西,用户可以在其中输入一些数据,然后“保存”它并获得一个加载该数据的独特随机查找URL。

我不想让保存顺序,因为我不希望任何人抓住我的所有条目,因为有些可能是私人的。但是在服务器上我想按顺序保存它。

(62 * 62 * 62 * 62 === 14776336)条目之前,是否存在将数字转换为具有4个字符且没有任何冲突的哈希的函数或技术?

例如,服务器上的第一个条目将在服务器上命名为1,而iUew3将命名为用户,服务器上的下一个条目将为2,但{{1} }给用户......

编辑:我不确定它是否显而易见,但这种类似哈希的函数需要是可逆的,因为当用户请求ueGR时,服务器需要知道服务器文件ueGR

6 个答案:

答案 0 :(得分:8)

可以这样做,但我建议使用64个字符,因为这会使它变得容易多了。 4个6位字符= 24位。

使用以下组合:

  • 位重新排序
  • xor,带数字
  • 将其放入24位最大长度LFSR并进行几个循环。

强烈建议使用LFSR,因为它会进行良好的加扰。其余的是可选的。所有这些操作都是可逆的,并保证每个输出都是唯一

当您计算“混洗”数字时,只需将其打包成二进制字符串并使用base64_encode对其进行编码。

对于解码,只需执行这些操作的反转。

样本(2 ^ 24长的独特序列):

function lfsr($x) {
    return ($x >> 1) ^ (($x&1) ? 0xe10000 : 0);
}
function to_4($x) {
    for($i=0;$i<24;$i++)
        $x = lfsr($x);
    $str = pack("CCC", $x >> 16, ($x >> 8) & 0xff, $x & 0xff);
    return base64_encode($str);
}

function rev_lfsr($x) {
    $bit = $x & 0x800000;
    $x = $x ^ ($bit ? 0xe10000 : 0);
    return ($x << 1) + ($bit ? 1 : 0);
}
function from_4($str) {
    $str = base64_decode($str);
    $x = unpack("C*", $str);
    $x = $x[1]*65536 + $x[2] * 256 + $x[3];
    for($i=0;$i<24;$i++)
        $x = rev_lfsr($x);
    return $x;
}

for($i=0; $i<256; $i++) {
    $enc = to_4($i);
    echo $enc . " " . from_4($enc) . "\n";
}

输出:

AAAA 0
kgQB 1
5ggD 2
dAwC 3
DhAH 4
nBQG 5
6BgE 6
ehwF 7
HCAO 8
jiQP 9
+igN 10
aCwM 11
EjAJ 12
gDQI 13
9DgK 14
ZjwL 15
OEAc 16
qkQd 17
3kgf 18
TEwe 19
NlAb 20
pFQa 21
0FgY 22

...

注意:对于使用+/替换-_的网址。

注意:虽然这有效,但对于像你这样的简单场景,创建随机文件名可能更容易,直到它不存在。没有人关心参赛作品的数量。

答案 1 :(得分:1)

以下是我实施它的方式。这是save.php文件(有人可以告诉我它是否有任何设计缺陷):

<?php

$index = file_get_contents('saves/data/placeholder');
$index++;
file_put_contents('saves/data/placeholder', $index);

$string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
do {
    $hash = $string[rand(0, 61)] . $string[rand(0, 61)] . $string[rand(0, 61)] . $string[rand(0, 61)];
} while (file_exists('saves/' . $hash));

file_put_contents('saves/' . $hash, $index);
file_put_contents('saves/data/' . $index, $_REQUEST['data']);

echo $hash;

?>

这是load.php:

<?php

if (!file_exists('saves/' . $_REQUEST['file'])) {
    file_put_contents('saves/data/log', 'requested saves/' . $_REQUEST['file'] . "\n", FILE_APPEND);
    die();
}
$file_pointer = file_get_contents('saves/' . $_REQUEST['file']);

if (!file_exists('saves/data/' . $file_pointer)) {
    file_put_contents('saves/data/log', 'requested saves/data/' . $file_pointer . 'from ' . $_REQUEST['file'] . "\n", FILE_APPEND);
    die();
}
echo file_get_contents('saves/data/' . $file_pointer);

?>

希望这有助于其他人。

答案 2 :(得分:0)

在我看来,如果你还在服务器上保留save time of entry,你可以生成一个哈希函数。 hash = func(id, time),但只有hash = func(id)才能轻松解决

答案 3 :(得分:0)

这是一组奇怪的约束。我经常使用MD5校验和从数据生成唯一的URL。如果用户还没有数据,则无法猜出网址。

我确实理解不想使用数据库 - 如果您以前从未使用过数据库,那么学习曲线可能会有点陡峭。

我不明白“在服务器上按顺序存储事物”的限制。如果您需要知道创建哈希的顺序,我只需将该信息放在一个单独的文件中。您可能必须执行文件锁定或其他类型的黑客攻击,以确保您可以逐步将哈希值附加到该文件。

如果您想要短网址,您可以使用MD5校验和的前缀,也可以使用CRC-32和base64对其进行编码。两者都会为您提供具有相当好概率的唯一网址。

答案 4 :(得分:0)

这是一个可逆的lib,与bcmath一起工作 http://blog.kevburnsjr.com/php-unique-hash

答案 5 :(得分:-1)

这实际上不可逆转。唯一的方法(url shorteners和jsfiddle使用的方法)是将生成的哈希(实际上它是摘要)存储在某种表格/数据结构中,并在检索时查找。

为什么会这样?

传递,例如128个数据字符→4个可见字符摘要,您会丢失大量数据 你不能将剩下的数据存储在这4个字节之间的神奇裂缝中,没有。