Году в 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.