PHP最好的MD5多维数组方式?

时间:2010-02-12 18:37:37

标签: php arrays multidimensional-array hash md5

生成多维数组的MD5(或任何其他哈希)的最佳方法是什么?

我可以轻松编写一个循环,遍历数组的每个级别,将每个值连接成一个字符串,然后简单地在字符串上执行MD5。

然而,这看起来很麻烦,我想知道是否有一个带有多维数组的时髦函数,并将其哈希。

14 个答案:

答案 0 :(得分:232)

(底部的可复制粘贴功能)

如前所述,以下内容可行。

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));
}

答案 1 :(得分:168)

md5(serialize($array));

答案 2 :(得分:21)

我通过回答加入了一个非常拥挤的聚会,但有一个重要的考虑因素是现存的答案都没有解决。 serialize() serialize() 1c4f1064ab79e4722f41ab5a8141b210 1ad0f2c7e690c8e3cd5c34f7c9b8573a json_encode() db7178ba34f9271bfca3a05c5dddf502 c9661c0852c2bd0e26ef7951b4ca9e6f Sorted serialize() 1c4f1064ab79e4722f41ab5a8141b210 1c4f1064ab79e4722f41ab5a8141b210 Sorted json_encode() db7178ba34f9271bfca3a05c5dddf502 db7178ba34f9271bfca3a05c5dddf502 的值都取决于数组中元素的顺序!

以下是未对数组进行排序和排序的结果,两个具有相同值但以不同顺序添加的数组 (帖子底部的代码):< / p>

// 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"; 来获取该类型的数据。

以下是用于生成上述排序测试的代码:

/*
* 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;
}

我的快速deep_ksort()实现符合这种情况,但在使用您自己的项目之前检查它:

npm install http-proxy

答案 3 :(得分:8)

答案在很大程度上取决于数组值的数据类型。 对于大字符串使用:

md5(serialize($array));

对于短字符串和整数使用:

md5(json_encode($array));

4个内置PHP函数可以将数组转换为字符串: serialize()json_encode()var_export()print_r()

  

注意: json_encode()函数在处理以字符串作为值的关联数组时会变慢。在这种情况下,请考虑使用serialize()函数。

在键和值中使用md5-hashes(32 char)测试多维数组的结果:

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

答案 4 :(得分:7)

除了Brock的优秀答案(+1)之外,任何体面的散列库都允许您以增量方式更新散列,因此您应该能够按顺序更新每个字符串,而不必构建一个巨大的字符串。

请参阅:hash_update

答案 5 :(得分:3)

md5(serialize($array));

可行,但哈希值会根据数组的顺序而改变(尽管可能无关紧要)。

答案 6 :(得分:3)

请注意,serializejson_encode在键不以0开始的数字数组或关联数组时的行为方式不同。 json_encode会将此类数组存储为Object,因此json_decode会返回Object,其中unserialize将返回一个具有完全相同键的数组。

答案 7 :(得分:3)

我认为这可能是一个很好的提示:

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);

答案 8 :(得分:2)

关于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只需创建链接&#34; r:2;&#34;到第一个例子。它绝对是序列化数据的好方法,但它可能会导致散列函数出现问题。

答案 9 :(得分:2)

completed=1

答案 10 :(得分:0)

有几个答案告诉我们使用json_code,

但是json_encode对iso-8859-1字符串不起作用,只要有一个特殊的字符串,字符串就会被裁剪。

我建议使用var_export:

md5(var_export($array, true))

不像序列化那么慢,不像json_encode

那样有问题

答案 11 :(得分:0)

目前投票最多的答案md5(serialize($array));不适用于对象。

考虑代码:

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

尽管数组不同(它们包含不同的对象),但在使用md5(serialize($array));时它们具有相同的哈希值。所以你的哈希是没用的!

为避免此问题,您可以在序列化之前替换结果为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函数不要改变原始数组。)

答案 12 :(得分:0)

上面我不太容易看到解决方案,因此我想提出一个简单的答案。对我来说,直到使用kso​​rt(键排序),我都获得了相同的键:

首先与Ksort排序,然后在json_encode上执行sha1:

ksort($array)
$hash = sha1(json_encode($array) //be mindful of UTF8

示例:

$arr1 = array( 'dealer' => '100', 'direction' => 'ASC', 'dist' => '500', 'limit' => '1', 'zip' => '10601');
ksort($arr1);

$arr2 = array( 'direction' => 'ASC', 'limit' => '1', 'zip' => '10601', 'dealer' => '100', 'dist' => '5000');
ksort($arr2);

var_dump(sha1(json_encode($arr1)));
var_dump(sha1(json_encode($arr2)));

更改后的数组和哈希的输出:

string(40) "502c2cbfbe62e47eb0fe96306ecb2e6c7e6d014c"
string(40) "b3319c58edadab3513832ceeb5d68bfce2fb3983"

答案 13 :(得分:0)

在某些情况下,最好使用 http_build_query 将数组转换为字符串:

md5( http_build_query( $array ) );