Как сгенерировать непонятный крошечный URL-адрес на основе идентификатора?

Я заинтересован в создании крошечных ссылок, похожих на ссылки. Моя идея заключалась в том, чтобы просто сохранить увеличивающийся идентификатор для каждого опубликованного длинного URL-адреса, а затем преобразовать этот идентификатор в его базовый 36-вариант, например, следующий в PHP:

$tinyurl = base_convert($id, 10, 36)

Проблема здесь в том, что результат можно угадать, в то время как трудно угадать, каким будет следующий URL-адрес, хотя он остается коротким (крошечным). Например. atm, если мой последний tinyurl был a1, следующим будет a2. Для меня это плохо.

Итак, как мне убедиться, что полученный крошечный URL-адрес не такой уж угадываемый, но все же короткий?


person Tom    schedule 06.08.2010    source источник


Ответы (9)


То, что вы просите, - это баланс между сокращением информации (URL-адреса их индексов в вашей базе данных) и искусственным увеличением информации (для создания дыр в вашей последовательности).

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

По сути, вы хотите объявить n из N действующих идентификаторов. Выберите N меньше, чтобы сделать URL-адреса короче, и уменьшите n, чтобы сгенерировать URL-адреса, которые трудно угадать. Увеличьте n и N, чтобы генерировать больше URL-адресов, когда будут взяты более короткие.

Чтобы назначить идентификаторы, вы можете просто взять любой тип случайного генератора или хеш-функции и ограничить его целевым диапазоном N. Если вы обнаружите столкновение, выберите следующее случайное значение. Если вы достигли числа n уникальных идентификаторов, вы должны увеличить диапазон набора идентификаторов (n и N).

person relet    schedule 06.08.2010
comment
По поводу вашего последнего абзаца. Я думаю, ему нужна ценность, которую он может перевернуть, то есть ему нужна инъективная функция. - person Artefacto; 07.08.2010
comment
Нет, на самом деле он хочет непостижимой функции. ;) Поскольку он все равно должен хранить URL-адреса в базе данных, он может использовать случайное число в качестве индекса. Обратный ход достигнут. - person relet; 07.08.2010
comment
Правда, не обязательно быть инъекционным. - person Tom; 07.08.2010

Я бы просто crc32 url

$url = 'http://www.google.com';
$tinyurl = hash('crc32', $url ); // db85f073

минусы: постоянный идентификатор длиной 8 символов

person dev-null-dweller    schedule 06.08.2010
comment
Мне нравится эта идея, но 8-символьный код - это своего рода проблема - с сокращениями URL-адресов в наши дни учитывается каждый символ, а 8 - это немного больше. - person Joe Enos; 07.08.2010

Это действительно дешево, но если пользователь не знает, что это происходит, то это не так угадать, но префикс и постфикс фактического идентификатора с 2 или 3 случайными числами / буквами.

Если бы я увидел 9d2a1me3, я бы не подумал, что следующим в серии будет dm2a2dq2.

person BarrettJ    schedule 06.08.2010

Попробуйте Xor'ing $ id с некоторым значением, например $id ^ 46418 - и для преобразования обратно к исходному идентификатору вы просто снова выполняете тот же Xor, то есть $mungedId ^ 46418. Сложите это вместе с вашим base_convert и, возможно, некоторой заменой символов в результирующей строке, и будет довольно сложно угадать URL-адрес.

person Will A    schedule 06.08.2010
comment
Для немного решительного хакера - уверен - для Джо Паблика не так уж и много. - person Will A; 07.08.2010

Другой способ - установить максимальное количество символов для URL-адреса (допустим, n). Затем вы можете выбрать случайное число от 1 до n !, которое будет вашим числом перестановки.

На каком новом URL-адресе вы должны увеличить идентификатор и использовать номер перестановки, чтобы связать фактический идентификатор, который будет использоваться. Наконец, вы должны кодировать свой URL-адрес по базе 32 (или что-то еще). Это было бы совершенно случайно и полностью обратимо.

person Artefacto    schedule 06.08.2010
comment
Тем не менее, таким образом возможны повторяющиеся идентификаторы, поэтому вам придется проверить это и снова увеличить, если они дублируются. - person Tom; 07.08.2010

Если вам нужна инъективная функция, вы можете использовать любую форму шифрования. Например:

<?php
$key = "my secret";
$enc = mcrypt_ecb (MCRYPT_3DES, $key, "42", MCRYPT_ENCRYPT);
$f = unpack("H*", $enc);
$value = reset($f);
var_dump($value); //string(16) "1399e6a37a6e9870"

Чтобы повернуть вспять:

$rf = pack("H*", $value);
$dec = rtrim(mcrypt_ecb (MCRYPT_3DES, $key, $rf, MCRYPT_DECRYPT), "\x00");
var_dump($dec); //string(2) "42"

Это не даст вам число по основанию 32; он предоставит вам зашифрованные данные с каждым байтом, преобразованным в базу 16 (т. е. преобразование является глобальным). Если вам действительно нужно, вы можете тривиально преобразовать это в базу 10, а затем в базу 32 с помощью любой библиотеки, которая поддерживает большие целые числа.

person Artefacto    schedule 06.08.2010
comment
Имейте в виду, что полученный URL должен быть коротким (1399e6a37a6e9870 слишком длинным). - person Tom; 07.08.2010
comment
@Tom Ну, он мог бы преобразовать его в базу 64 или около того и получить (я думаю) 11 символов. Или используйте - person Artefacto; 07.08.2010

Вы можете заранее определить 4-значные коды (все возможные комбинации), затем рандомизировать этот список и сохранить его в этом случайном порядке в таблице данных. Если вам нужно новое значение, просто возьмите первое сверху и удалите его из списка. Это быстро, не требует вычислений на лету и гарантирует конечному пользователю псевдослучайность.

person Joe Enos    schedule 06.08.2010
comment
Я должен отметить, что это именно то, что я сделал для сокращения URL-адресов, и начать работу с ним немного затруднительно. Возможных комбинаций очень много, а это значит, что вы начинаете с огромного файла базы данных для такой простой концепции. - person Joe Enos; 07.08.2010
comment
@relet Что именно вы имеете в виду? Тот факт, что есть ограниченное количество, которое не может увеличиваться? Если это так, то, как только у вас заканчиваются 4-значные коды, вычислите все 5-значные коды и вставьте их в свою таблицу очереди. - person Joe Enos; 07.08.2010

Hashids - это библиотека с открытым исходным кодом, которая генерирует короткие, уникальные, непоследовательные, похожие на YouTube идентификаторы от одного или нескольких чисел. Вы можете думать об этом как о алгоритме сокрытия чисел.

Он преобразует числа вроде 347 в строки типа yr8 или массив вроде [27, 986] в 3kTMd. Вы также можете декодировать эти идентификаторы обратно. Это полезно для объединения нескольких параметров в один или простого использования их в качестве коротких UID.

Используйте его, когда вы не хотите открывать идентификаторы своей базы данных пользователю.

Он позволяет использовать произвольный алфавит, а также соль, поэтому идентификаторы уникальны только для вас.

Добавочный ввод искажен, чтобы его нельзя было угадать.

Коллизий нет, потому что метод основан на преобразовании целых чисел в шестнадцатеричные.

Он был написан с целью размещения созданных идентификаторов в видимых местах, таких как URL. Таким образом, алгоритм избегает генерации наиболее распространенных ругательств английского языка.

Пример кода

$hashids = new Hashids();
$id = $hashids->encode(1, 2, 3); // o2fXhV
$numbers = $hashids->decode($id); // [1, 2, 3]
person Demis Palma ツ    schedule 16.10.2016

Я закончил тем, что создал сумму идентификатора md5, использую первые 4 буквенно-цифровых символа, и если это дубликат, просто увеличивайте длину до тех пор, пока он не перестанет быть дубликатом.

function idToTinyurl($id) {
    $md5 = md5($id);
    for ($i = 4; $i < strlen($md5); $i++) {
        $possibleTinyurl = substr($md5, 0, $i);
        $res = mysql_query("SELECT id FROM tabke WHERE tinyurl='".$possibleTinyurl."' LIMIT 1");
        if (mysql_num_rows($res) == 0) return $possibleTinyurl;
    }
    return $md5;
}

Принял ответ relet, поскольку он привел меня к этой стратегии.

person Tom    schedule 06.08.2010