Как создать последовательную хэш-функцию

Я хочу разработать что-то похожее на jsfiddle, где пользователь может ввести некоторые данные, а затем "сохранить" его и получить уникальный случайный url-адрес, который загружает эти данные.

Я не хочу делать сохранения последовательными, потому что я не хочу, чтобы кто-то захватил все мои записи, так как некоторые могут быть частными. Однако на сервере я хотел бы сохранить его в последовательном порядке.

есть ли функция или техника, которая преобразует число в хэш, который имеет 4 символа без каких-либо столкновения до (62 * 62 * 62 * 62 === 14776336) записи?

например, первая запись на сервере будет называться 1 на сервере, но iUew3 для пользователя, следующая запись будет 2 на сервере, но ueGR для пользователя...

EDIT: я не уверен, что это очевидно, но эта хэш-функция должна быть обратимой, потому что, когда пользователь запрашивает ueGR сервер должен знать, чтобы сервер его файл 2

6 ответов


это можно сделать, но я бы предложил использовать 64 символа, так как это сделает его намного проще. 4 6 бит символов = 24 бит.

используйте комбинацию из них:

  • немного перегруппировав
  • xor с номером
  • поместите его в 24-битную максимальную длину РСЛОС и сделайте пару циклов.

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

...

Примечание: для URL заменить + и / С - и _.

Примечание: хотя это работает, для простого сценария, как ваш, вероятно, проще создать случайное имя файла, пока оно не существует. никого не волнует номер записи.


вот как я его реализовал. Вот спасение.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;

?>

и вот нагрузка.на 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);

?>

надеюсь, это поможет другим.


на мой взгляд, если вы также сохраняя save time of entry на сервере, вы можете создать хэш-функции. hash = func(id, time) только hash = func(id) будет легко решить


Это нечетный набор ограничений. Я обычно использую контрольные суммы MD5 для создания уникальных URL-адресов из данных. Если у пользователя еще нет данных, они не могут угадать URL-адреса.

Я понимаю, что не хочу использовать базу данных-если вы никогда не использовали один прежде, кривая обучения может быть немного крутой.

Я не понимаю ограничения о " хранении вещей последовательно на сервере."Если вам нужно знать порядок, в котором создаются хэши, я бы просто поместите эту информацию в отдельный файл. Возможно, вам придется сделать блокировку файла или какой-то другой вид взлома, чтобы убедиться, что вы можете добавить хэш к этому файлу постепенно.

Если вы хотите короткие URL-адреса, вы можете взять префикс контрольной суммы MD5 или вы можете взять CRC-32 и base64 кодировать его. Оба дадут вам уникальные URL-адреса с разумной вероятностью.


вот обратимый lib, который работает с bcmath
http://blog.kevburnsjr.com/php-unique-hash


этого не может быть обратимым. Единственный способ (тот, который используется сокращателями url и jsfiddle) - сохранить сгенерированный хэш (на самом деле это дайджест) в какой-то структуре таблицы/данных и *посмотреть его при извлечении.

почему это?

переход от, например, 128 символов данных → 4 видимых дайджеста символов, вы потерять много данных.
Вы не можете хранить оставшиеся данные в магических трещинах между этими 4 байтами, есть никто.