Intereting Posts
Загрузите содержимое нескольких файлов на сервере с помощью PHP Функция возвращает только буквенно-цифровые символы из строки? Случайный PHP FastCGI / Сброс соединения с помощью одноранговых / неполных заголовков php: как добавить нечетный / четный цикл в массив что является самым надежным методом для получения файла с удаленного сервера в php Как использовать Google Analytics для отслеживания открытых ставок, ставок по электронной почте? Печать на принтер Zebra в php Вход CURL по сценарию на сайт Joomla Привлечение к власти в PHP Есть ли разница между операторами «и» и «&&» в PHP? regex php, строка соответствия с переменным текстом (буквы, цифры, подчеркивание, ) Выбор списка игнорирует первое значение при использовании функции onchange, PHP, JAVASCRIPT Лучшая практика для путей PHP Неустранимая ошибка: вызов функции-члена toOptionArray () для объекта без объекта Префикс метода подчеркивания

PHP лучший способ для многомерного массива MD5?

Каков наилучший способ генерации MD5 (или любого другого хэша) многомерного массива?

Я мог бы легко написать цикл, который проходил бы через каждый уровень массива, объединяя каждое значение в строку и просто выполняя MD5 в строке.

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

(Функция copy-n-paste в нижней части)

Как упоминалось ранее, будет работать следующее.

md5(serialize($array)); 

Однако стоит отметить, что (по иронии судьбы) json_encode работает заметно быстрее:

 md5(json_encode($array)); 

Фактически, увеличение скорости здесь двоякое: (1) только json_encode выполняет быстрее, чем сериализует, и (2) json_encode производит меньшую строку и, следовательно, меньше для md5 для обработки.

Изменить: Вот доказательства, подтверждающие это утверждение:

 <?php //this is the array I'm using -- it's multidimensional. $array = unserialize('a:6:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}i:5;a:5:{i:0;a:0:{}i:1;a:4:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}i:3;a:6:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}i:5;a:5:{i:0;a:0:{}i:1;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:3:{i:0;a:0:{}i:1;a:0:{}i:2;a:0:{}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}}}}i:2;s:5:"hello";i:3;a:2:{i:0;a:0:{}i:1;a:0:{}}i:4;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:1:{i:0;a:0:{}}}}}}}}}'); //The serialize test $b4_s = microtime(1); for ($i=0;$i<10000;$i++) { $serial = md5(serialize($array)); } echo 'serialize() w/ md5() took: '.($sTime = microtime(1)-$b4_s).' sec<br/>'; //The json test $b4_j = microtime(1); for ($i=0;$i<10000;$i++) { $serial = md5(json_encode($array)); } echo 'json_encode() w/ md5() took: '.($jTime = microtime(1)-$b4_j).' sec<br/><br/>'; echo 'json_encode is <strong>'.( round(($sTime/$jTime)*100,1) ).'%</strong> faster with a difference of <strong>'.($sTime-$jTime).' seconds</strong>'; 

JSON_ENCODE постоянно превышает 250% (2,5 раза) быстрее (часто более 300%) – это не тривиальная разница. Результаты этого теста вы можете увидеть здесь:

Теперь стоит отметить, что массив (1,2,3) будет генерировать другой массив MD5 (3,2,1). Если это НЕ то, что вы хотите. Попробуйте следующий код:

 //Optionally make a copy of the array (if you want to preserve the original order) $original = $array; array_multisort($array); $hash = md5(json_encode($array)); 

Редактирование. Был вопрос о том, будут ли обратные ордера иметь одинаковые результаты. Итак, я сделал это ( правильно ) здесь:

Как вы можете видеть, результаты точно такие же. Вот ( исправленный ) тест, первоначально созданный кем-то, связанным с Drupal :

И для хорошей меры, вот функция / метод, который вы можете скопировать и вставить (проверено в 5.3.3-1ubuntu9.5):

 function array_md5(Array $array) { //since we're inside a function (which uses a copied array, not //a referenced array), you shouldn't need to copy the array array_multisort($array); return md5(json_encode($array)); } 
 md5(serialize($array)); 

Я присоединяюсь к очень переполненной вечеринке, отвечая, но есть важное соображение, что ни один из существующих ответов не подходит. Значение json_encode() и serialize() зависит от порядка элементов в массиве!

Ниже приведены результаты не сортировки и сортировки массивов на двух массивах с одинаковыми значениями, но добавленных в другом порядке (код внизу сообщения) :

  serialize() 1c4f1064ab79e4722f41ab5a8141b210 1ad0f2c7e690c8e3cd5c34f7c9b8573a json_encode() db7178ba34f9271bfca3a05c5dddf502 c9661c0852c2bd0e26ef7951b4ca9e6f Sorted serialize() 1c4f1064ab79e4722f41ab5a8141b210 1c4f1064ab79e4722f41ab5a8141b210 Sorted json_encode() db7178ba34f9271bfca3a05c5dddf502 db7178ba34f9271bfca3a05c5dddf502 

Поэтому два метода, которые я бы рекомендовал для хэш-массива :

 // You will need to write your own deep_ksort(), or see // my example below md5( serialize(deep_ksort($array)) ); md5( json_encode(deep_ksort($array)) ); 

Выбор json_encode() или serialize() должен определяться путем тестирования типа данных, которые вы используете . По моему собственному тестированию на чисто текстовые и числовые данные, если код не работает в узком цикле тысячи раз, то разница даже не стоит бенчмаркинга. Я лично использую json_encode() для этого типа данных.

Вот код, используемый для генерации теста сортировки выше:

 $a = array(); $a['aa'] = array( 'aaa'=>'AAA', 'bbb'=>'ooo', 'qqq'=>'fff',); $a['bb'] = array( 'aaa'=>'BBBB', 'iii'=>'dd',); $b = array(); $b['aa'] = array( 'aaa'=>'AAA', 'qqq'=>'fff', 'bbb'=>'ooo',); $b['bb'] = array( 'iii'=>'dd', 'aaa'=>'BBBB',); echo " serialize()\n"; echo md5(serialize($a))."\n"; echo md5(serialize($b))."\n"; echo "\n json_encode()\n"; echo md5(json_encode($a))."\n"; echo md5(json_encode($b))."\n"; $a = deep_ksort($a); $b = deep_ksort($b); echo "\n Sorted serialize()\n"; echo md5(serialize($a))."\n"; echo md5(serialize($b))."\n"; echo "\n Sorted json_encode()\n"; echo md5(json_encode($a))."\n"; echo md5(json_encode($b))."\n"; 

Моя быстрая реализация deep_ksort (), подходит для этого случая, но проверяет ее перед использованием в ваших собственных проектах:

 /* * Sort an array by keys, and additionall sort its array values by keys * * Does not try to sort an object, but does iterate its properties to * sort arrays in properties */ function deep_ksort($input) { if ( !is_object($input) && !is_array($input) ) { return $input; } foreach ( $input as $k=>$v ) { if ( is_object($v) || is_array($v) ) { $input[$k] = deep_ksort($v); } } if ( is_array($input) ) { ksort($input); } // Do not sort objects return $input; } 

Помимо превосходного ответа Брок (+1), любая достойная хеширующая библиотека позволяет вам обновлять хэш с шагом, поэтому вы должны иметь возможность обновлять каждую строку последовательно, вместо этого нужно создать одну гигантскую строку.

См .: hash_update

Ответ сильно зависит от типов данных значений массива. Для больших строк используйте:

 md5(serialize($array)); 

Для коротких строк и целых чисел используйте:

 md5(json_encode($array)); 

4 встроенных PHP-функций могут преобразовывать массив в строку: serialize () , json_encode () , var_export () , print_r () .

Примечание. Функция json_encode () замедляется при обработке ассоциативных массивов со строками в качестве значений. В этом случае рассмотрим возможность использования функции serialize () .

Результаты испытаний для многомерного массива с md5-хэшами (32 символа) в ключах и значениях:

 Test name Repeats Result Performance serialize 10000 0.761195 sec +0.00% print_r 10000 1.669689 sec -119.35% json_encode 10000 1.712214 sec -124.94% var_export 10000 1.735023 sec -127.93% 

Результат теста для числового многомерного массива:

 Test name Repeats Result Performance json_encode 10000 1.040612 sec +0.00% var_export 10000 1.753170 sec -68.47% serialize 10000 1.947791 sec -87.18% print_r 10000 9.084989 sec -773.04% 

Источник тестового источника ассоциативного массива. Числовой массив.

 md5(serialize($array)); 

Будет работать, но хэш будет меняться в зависимости от порядка массива (что может быть неважно, хотя).

Обратите внимание, что serialize и json_encode действуют по-разному, когда речь заходит о числовых массивах, где ключи не начинаются с 0 или ассоциативных массивов. json_encode будет хранить такие массивы как Object , поэтому json_decode возвращает Object , где unserialize вернет массив с точно такими же ключами.

Я думаю, что это может быть хорошим советом:

 Class hasharray { public function array_flat($in,$keys=array(),$out=array()){ foreach($in as $k => $v){ $keys[] = $k; if(is_array($v)){ $out = $this->array_flat($v,$keys,$out); }else{ $out[implode("/",$keys)] = $v; } array_pop($keys); } return $out; } public function array_hash($in){ $a = $this->array_flat($in); ksort($a); return md5(json_encode($a)); } } $h = new hasharray; echo $h->array_hash($multi_dimensional_array); 

Важное примечание о serialize()

Я не рекомендую использовать его как часть функции хэширования, потому что он может возвращать другой результат для следующих примеров. Посмотрите пример ниже:

Простой пример:

 $a = new \stdClass; $a->test = 'sample'; $b = new \stdClass; $b->one = $a; $b->two = clone $a; 

Производит

 "O:8:"stdClass":2:{s:3:"one";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}s:3:"two";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}}" 

Но следующий код:

 <?php $a = new \stdClass; $a->test = 'sample'; $b = new \stdClass; $b->one = $a; $b->two = $a; 

Вывод:

 "O:8:"stdClass":2:{s:3:"one";O:8:"stdClass":1:{s:4:"test";s:6:"sample";}s:3:"two";r:2;}" 

Поэтому вместо второго объекта php просто создайте ссылку «r: 2;» в первую очередь. Это определенно хороший и правильный способ сериализации данных, но это может привести к проблемам с вашей функцией хэширования.

есть несколько ответов, говорящих на использование json_code,

но json_encode не работает нормально с строкой iso-8859-1, как только появляется специальный символ, строка обрезается.

я бы советовал использовать var_export:

 md5(var_export($array, true)) 

не так медленно, как сериализация, а не как прослушивание json_encode

В настоящее время самый проголосовавший ответ md5(serialize($array)); не работает с объектами.

Рассмотрим код:

  $a = array(new \stdClass()); $b = array(new \stdClass()); 

Даже если массивы разные (они содержат разные объекты), они имеют один и тот же хеш при использовании md5(serialize($array)); , Так что ваш хэш бесполезен!

Чтобы избежать этой проблемы, перед сериализацией вы можете заменить объекты с результатом spl_object_hash() . Вы также должны сделать это рекурсивно, если ваш массив имеет несколько уровней.

Код ниже также сортирует массивы по клавишам, как предположили дотанокен.

 function replaceObjectsWithHashes(array $array) { foreach ($array as &$value) { if (is_array($value)) { $value = $this->replaceObjectsInArrayWithHashes($value); } elseif (is_object($value)) { $value = spl_object_hash($value); } } ksort($array); return $array; } 

Теперь вы можете использовать md5(serialize(replaceObjectsWithHashes($array))) .

(Обратите внимание, что массив в PHP является типом значений. Таким replaceObjectsWithHashes функция replaceObjectsWithHashes НЕ меняет исходный массив.)

 // Convert nested arrays to a simple array $array = array(); array_walk_recursive($input, function ($a) use (&$array) { $array[] = $a; }); sort($array); $hash = md5(json_encode($array)); ---- These arrays have the same hash: $arr1 = array(0 => array(1, 2, 3), 1, 2); $arr2 = array(0 => array(1, 3, 2), 1, 2);