首页 文章

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

提问于
浏览
101

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

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

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

13 回答

  • 20

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

  • 0

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

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

    (底部的复制粘贴功能)

    如前所述,以下内容将起作用 .

    md5(serialize($array));
    

    但是,值得注意的是(具有讽刺意味的是)json_encode的执行速度明显更快:

    md5(json_encode($array));
    

    事实上,速度增加在这里是两倍,因为(1)json_encode单独执行比串行化更快,(2)json_encode产生更小的字符串,因此md5处理更少 .

    Edit: 以下是支持这一说法的证据:

    <?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
    '; //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

    '; 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) . If 这不是你想要的 . 请尝试以下代码:

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

    Edit: 这里(正确地)完成了's been some question as to whether reversing the order would produce the same results. So, I':

    如您所见,结果完全相同 . 这是(更正的)测试originally created by someone related to Drupal

    And for good measure, here's a function/method you can copy and paste (tested in 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));
    }
    
  • 6
    md5(serialize($array));
    
  • 0

    我通过回答加入了一个非常拥挤的聚会,但有一个重要的考虑因素是现存的答案都没有解决 . The value of json_encode() and serialize() both depend upon the order of elements in the array!

    以下是 two arrays with identical values but added in a different order (帖子底部的代码)未对数组进行排序和排序的结果:

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

    因此,我建议 hash an array 的两种方法是:

    // 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() 的选择应为 determined by testing on the type of data that you are using . 通过我自己对纯文本和数值数据的测试,如果代码没有运行数千次紧密循环,那么差异甚至不值得基准测试 . 我个人使用 json_encode() 来表示这种类型的数据 .

    Here is the code used to generate the sorting test above:

    $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";
    

    My quick deep_ksort() implementation, fits this case but check it before using on your own projects:

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

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

    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 .

  • 2

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

    见:hash_update

  • 7
    md5(serialize($array));
    

    将工作,但哈希将根据数组的顺序而改变(尽管可能无关紧要) .

  • 1

    关于 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;”到第一个例子 . 这绝对是序列化数据的好方法,但它可能会导致散列函数出现问题 .

  • 3
    // 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);
    
  • 1

    有几个答案告诉你使用json_code,

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

    我建议使用var_export:

    md5(var_export($array, true))
    

    不像序列化那么慢,不像json_encode那样有问题

  • 224

    Currently the most up-voted answer md5(serialize($array)); doesn't work well with objects.

    考虑代码:

    $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 函数不要改变原始数组 . )

  • 166

    我没有在上面看到解决方案,所以我想提供一个更简单的答案 . 对我来说,我使用相同的密钥,直到我使用ksort(密钥排序):

    先用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"
    

相关问题