生成多维数组的MD5(或任何其他散列)的最佳方式是什么?PHP最好的方式来MD5多维数组?
我可以很容易地编写一个遍历数组每个级别的循环,将每个值连接成一个字符串,并简单地在字符串上执行MD5。
但是,这似乎很麻烦,我想知道是否有一个时髦的功能,将采取多维数组,并散列它。
生成多维数组的MD5(或任何其他散列)的最佳方式是什么?PHP最好的方式来MD5多维数组?
我可以很容易地编写一个遍历数组每个级别的循环,将每个值连接成一个字符串,并简单地在字符串上执行MD5。
但是,这似乎很麻烦,我想知道是否有一个时髦的功能,将采取多维数组,并散列它。
(复印 - 正糊能够在底部功能)
正如之前提到的那样,下面的工作。
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));
编辑:还有的是一些问题,是否扭转秩序将产生相同的结果。所以,我(正确)来完成,在这里:
正如你所看到的,结果是完全一样的。这里是(修正)测试originally created by someone related to 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));
辉煌!非常感谢,从来不知道这件事。 – 2010-02-12 19:09:43
如果由于某种原因想要匹配散列(指纹),您可能需要考虑对数组进行排序“sort”或“ksort”,另外还可能需要执行某种类型的清理/清理 – farinspace 2011-05-11 18:15:00
序列化比soooooooo慢得多从第二个答案json_encode。做你的服务器的乐趣,并使用json_encode! :) – s3m3n 2013-05-05 17:19:21
除了布鲁克的出色答卷(+1),任何像样的哈希库允许你更新的增量散列值,所以你应该能够与每个字符串依次进行更新,而不是建立一个巨大的字符串。
参见:hash_update
值得注意的是,如果您使用小碎片进行更新,则此方法效率低下;尽管如此,它对于大块文件来说也很好。 – wrygiel 2012-09-15 18:41:59
@wrygiel这是不正确的。对于MD5,压缩总是以64字节的块(不管你的“大块”的大小如何)进行,并且如果你还没有填满块,则在块填满之前不进行处理。 (当你完成散列时,最后一个块被填充到一个完整的块,作为最终处理的一部分。)更多背景信息,请阅读[Merkle-Damgard构造](http://en.wikipedia.org/wiki/Merkle -Damgard_construction)(其中MD5,SHA-1和SHA-2都基于此)。 – 2012-09-16 01:06:21
你说得对。我被其他网站的评论完全误导了。 – wrygiel 2012-09-20 07:54:35
md5(serialize($array));
的工作,但散列将取决于阵列的顺序改变(可能不虽然重要)。
不是e说明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
没那么快,最好的选择是使用md4,var_export是也很慢 – user956584 2015-08-10 19:53:48
回答是高度依赖于数据类型数组值。 对于大字符串使用:
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%
联想数组test source。 数字阵列test source。
你能解释什么是*大*和*短字符串*? – 2015-10-21 16:25:20
@ A.L *短字符串* - 包含少于25-30个字符的字符串。 *大字符串* - 全部包含超过25-30个字符。 – 2015-10-22 07:39:46
我正在通过回答加入非常拥挤的派对,但是有一个重要的考虑因素,那就是现有的答案都不存在。 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)));
的的选择或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 – Brett 2016-04-28 05:58:46
当前最高票数的答案md5(serialize($array));
不能很好地与对象配合使用。使用md5(serialize($array));
当
$a = array(new \stdClass());
$b = array(new \stdClass());
即使阵列是不同的(它们包含不同的对象),它们具有相同的散列:
考虑代码。所以你的散列没用!
为了避免这个问题,您可以在序列化之前用spl_object_hash()
替换结果对象。如果你的数组有多个层次,你也应该递归地做。
下面的代码也按键排序数组,正如dotancohen所建议的。
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
功能不要改变原来的数组)
// 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);
哈哈!真?我被投票赞成“过度”优化?实际上,PHP的序列化速度要慢得多。我会用证据更新我的答案... – 2011-10-12 14:03:03
如果任何人对仅测试JSON(不涉及MD5)感兴趣,请参阅[看这里](http://stackoverflow.com/questions/804045/preferred -method-to-store-php-arrays-json-encode-vs-serialize)(具有讽刺意味的是,Shrapnel上校也在这里进行调试)。 – 2011-10-12 14:40:56
我不是拖钓。 – 2011-10-12 14:49:38