Году в 2006 мы разрабатывали свой клон Ютюба. В этом проекте многие вещи пришлось разрабатывать с нуля. Например, мне очень хотелось использовать в проекте хеши подобные тем, что использует Ютюб. С ходу решения не нашлось и пришлось поразмышлять:
- Хеш Ютюба содержит 11 символов.
- Алфавит хеша состоит из 64 символов (по 26 заглавных и строчных букв латинского алфавита, 10 цифр, дефис и символ подчеркивания).
- На кодирование всех символов этого алфавита нужно 6 бит (2^6 = 64).
- Хеш Ютюба содержит 11 символов, т.е. 66 бит.
- Можно предположить что берется какой-то хеш в 64 бита, например половина MD5, дополняется до 66 и дробится на куски по 6 бит.
- Каждый кусок — это символ нашего алфавита.
Тогда у меня получился такой код:
function get_ylhash($data=null, $long=false)
{
if (is_null($data))
{
if ( substr(PHP_VERSION, 0, 1) == '5')
{ // PHP5
$data = md5(uniqid(rand(), true), true);
}
else
{ // < PHP5
$data = md5(uniqid(rand(), true));
$data = pack('H*', $data);
}
}
if (!$long)
{
$data = substr($data, 0, 8);
}
$alphabet = '0123456789_abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$result = '';
$m = $a = 0;
for ($i=0, $len=strlen($data); $i<$len; $i++)
{
$c = ord($data{$i});
$result .= $alphabet{($c << $m | $a) & 63};
$a = $c >> (6-$m);
$m += 2;
if ( ($m==6) || ($i==$len-1) )
{
$result .= $alphabet{$a};
$m = $a = 0;
}
}
return $result;
}
Шли годы, я использовал эти ютюбоподобные хеши в дальнейших проектах, пока до меня наконец дошло: преобразование бинарной последовательности в строку состоящую из символов алфавита с 64 знаками называется Base64. Немного погуглив я нашел rfc3548.txt, в разделе 4 которого описан стандарт Base64-кодирования для использования в URL и именах файлов.
В итоге получилась такая функция:
function get_ylhash($data=null, $long=false)
{
$trans = array
(
'+' => '-',
'/' => '_',
'=' => '',
);
if (is_null($data))
{
$data = crypt( mt_rand().uniqid(), mt_rand().uniqid() );
}
$data = md5($data, true);
if(!$long)
{
$data = substr($data, 0, 8);
}
$data = strtr(base64_encode($data), $trans);
return $data;
}
Исходный код на GitHub.