Мой клиент генерирует промо-коды купонов, которые являются не более чем 32-мя символами MD5-хешей.
Моя задача состоит в том, чтобы уменьшить строку MD5 с 32 до менее чем 10 символов таким образом, чтобы хеш можно было воссоздать из уменьшенной строки.
Сокращение важно, поскольку пользователям было бы проще воспроизвести уменьшенный хэш.
Например: 719bedacf2e560b27f39d80accc67ffd => ZjKa1Gh
(не математически верно)
Я сталкивался с этим: Как уменьшить длину хеш-значения?
Это предполагает: Используя другую базу
Я не знаю, как сделать это в PHP, можем ли мы декодировать строку в ее ASCII и перекодировать ее?
Есть ли в PHP встроенные функции, которые я могу использовать в этом случае?
Обновление с помощью https://packagist.org/packages/aza/math
$original = '719bedacf2e560b27f39d80accc67ffd';
$long1 = NumeralSystem::convert($original, 16, 10);
$short = NumeralSystem::convertTo($long1, 62);
$long2 = NumeralSystem::convertFrom($short, 62);
$recovered = NumeralSystem::convert($long2, 10, 16);
var_dump($long1);
var_dump($short);
var_dump($long2);
var_dump($recovered);
// output
string(39) "151012390170261082849236619706853916669"string(22) "3SNOKWefotgnnCmWnYkTOf"string(39) "151012390170261082849236619706853916669"string(32) "719bedacf2e560b27f39d80accc67ffd"
Кажется, самое низкое, что я могу достичь из 32 символов MD5 — это 22 символа таким образом. Я все еще ищу способы, которыми я мог бы еще уменьшить его до 10 символов.
Обновление: использование первой половины MD5
$original = '719bedacf2e560b';
$coupon = NumeralSystem::convert($original, 16, 62);
$recovered = NumeralSystem::convert($coupon, 62, 16);
var_dump($coupon);
var_dump($recovered);
// output
string(10) "bnMR3RjZil"string(15) "719bedacf2e560b"
Если пользователь предоставляет bnMR3RjZil
Я могу использовать это, чтобы воссоздать 719bedacf2e560b
а затем сделать MySQL LIKE
поиск, чтобы получить полный MD5. Если он возвращает строку, я могу продолжить рекламную деятельность.
Криптографический хэш на самом деле представляет собой последовательность битов, но его можно интерпретировать как число. Таким образом, вы можете теоретически использовать старый добрый base_convert () Выразить в большой базе. К сожалению, эта функция работает только до основания 36 и ограничена действительными числами (то есть короткими целыми числами, которые вписываются в PHP_INT_MAX
) — иначе происходит потеря данных.
Здесь на помощь приходят сторонние библиотеки. Единственная проблема заключается в том, что их, как правило, трудно найти, потому что они обычно предназначены для очень конкретных случаев использования (биткойн, обфускация идентификаторов и т. Д.).
Я нашел, например, аза / математика, что, вероятно, излишне, но должно сделать работу. У меня не было возможности протестировать его, но все должно получиться так:
$original = '719bedacf2e560b27f39d80accc67ffd';
$short = NumeralSystem::convert($original, 16, 62);
$recovered = NumeralSystem::convert($short, 62, 16);
Моя задача состоит в том, чтобы уменьшить строку MD5 с 32 до менее чем 10 символов таким образом, чтобы хеш можно было воссоздать из уменьшенной строки.
Это невозможно Хеш MD5 составляет 128 бит; символ ASCII составляет 7 бит. Невозможно сохранить хеш MD5 в количестве менее 128 ÷ 7 = 18,2 (округление до 19) символов ASCII, и даже это будет включать непечатные управляющие символы.
Способ использования другой базы может быть следующим. Обратите внимание, что приведенный ниже код просто для иллюстрации метода, для его эффективной реализации необходимо работать непосредственно с двоичным представлением.
Идея состоит в том, что вы интерпретируете свою входную строку как последовательность из 128 битов. Теперь, если вы укажете, что ваш новый алфавит (символы новой базовой системы) A-Za-z0-9+-
, у вас есть 64 символа, что означает, что вам нужно 6 бит для кодирования каждого из них. Поэтому вы можете сначала преобразовать свою входную строку в двоичное представление, разделить это представление на куски по 6 битов и выразить каждый кусок в указанном наборе символов A-Za-z0-9+-
:
<?php
$s = "719bedacf2e560b27f39d80accc67ffd";
function conv($s){
$ret = base_convert($s, 16, 2);
return str_repeat("0", 8 - strlen($ret)) . $ret;
}
$binary_repr = implode(array_map(conv, str_split($s, 2)), '');
$items = str_split($binary_repr, 6);
function item2char($str){
$code = base_convert($str, 2, 10);
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-';
return $alphabet[$code];
}
$result = implode(array_map(item2char, $items), '');
echo $result;
?>
Как отмечено в комментариях, это в основном идея:
<?php
$s = "719bedacf2e560b27f39d80accc67ffd";
echo base64_encode(hex2bin($s));
//cZvtrPLlYLJ/OdgKzMZ//Q==
echo bin2hex(base64_decode("cZvtrPLlYLJ/OdgKzMZ//Q=="));
//719bedacf2e560b27f39d80accc67ffd
?>