Мне нужна очень быстрая функция хэширования строк, которая хорошо вписывается в веб-приложение, написанное на PHP.
Проблема, которую я пытаюсь преодолеть, заключается в назначении идентификаторов разрешениям в системе управления доступом. Я думаю об использовании хешированных строк для представления идентификаторов разрешений. Таким образом, я смогу проверить разрешения таким образом:
if ($Auth->isAllowed($user, "blog.comment")) { // Do some operation } ... if ($Auth->isAllowed($user, "profile.avatar.change")) { // Do some other operation }
Таблица БД будет отображать хэширование прав на роли пользователя. Чтобы проверить, разрешено ли пользователю делать «profile.avatar.change», соответствующая строка будет хеширована и проверена на таблице DB.
Это очень удобно, и вам не придется беспокоиться о сохранении уникальных идентификаторов доступа среди разных модулей. Но функция хеширования должна быть очень эффективной.
Первое, хотя было почему он не использовал простую функцию md5
? ,
Пытаюсь написать хэш самостоятельно
Одной из наиболее часто упоминаемых функций является простая хэш -функция Бернштейна, также называемая Times 33 with Addition
. Он используется в php
для zend для создания хэшей для ключей ассоциативного массива . В php
он может быть реализован следующим образом:
function djb2($s){ $word = str_split($s); $length = count($word); $hashAddress = 5381; for ($counter = 0; $counter < $length; $counter++){ $hashAddress = (($hashAddress << 5) + $hashAddress) + $word[$counter]; } return $hashAddress; } echo djb2("stackoverflow");
Проблема в том, что когда она реализована таким образом, она довольно медленная. Тесты показывают, что он ~ 3 раза медленнее , чем md5
. Поэтому нам нужно найти самую быструю внутреннюю реализацию hash
функции .
Поиск лучшего внутреннего хэша
Просто возьмите все algos и измерьте время, чтобы хэш миллион строк.
function testing($algo, $str) { $start = microtime(true); for($ax = 0; $ax < 1000000; $ax++){ hash($algo, $str); } $end = microtime(true); return ($end - $start); } $algos = hash_algos(); $times = []; foreach($algos as $algo){ $times[$algo] = testing($algo, "stackoverflow"); } // sort by time ASC asort($times); foreach($times as $algo => $time){ echo "$algo -> " . round($time, 2)."sec\n"; }
Мои результаты были:
fnv1a32 -> 0.29sec fnv132 -> 0.3sec crc32b -> 0.3sec adler32 -> 0.3sec crc32 -> 0.31sec joaat -> 0.31sec fnv1a64 -> 0.31sec fnv164 -> 0.31sec md4 -> 0.46sec md5 -> 0.54sec ... md2 -> 6.32sec
Результат слегка меняется от исполнения к исполнению – первые 8 альгос перетасовываются из-за их близких скоростей и зависимости от нагрузки на сервер.
Что нужно выбрать?
Вы можете взять любую из вышеперечисленных функций выше: $hash = hash('crc32', $string);
, На самом деле широко используемая функция md5
в 1,7 раза медленнее лидеров.
бонус
Существуют и другие функции, такие как SuperFastHash , которые не реализованы в php
коде, но они в 4 раза быстрее, чем crc32
.
Используйте xxHash . Он также используется PrestoDB . Реализация PHP на GitHub
Время обработки функции хэширования в большинстве случаев может считаться незначительным. Если вам нужен небольшой хеш (8 символов), вы можете просто использовать функцию crc32.
<?php $hash = hash('crc32', 'WhatDoYouWant'); ?>
Вы также можете комбинировать хеш с uniqid для создания случайного хэша.
<?php $hash = hash('crc32', uniqid()); ?>