PHP最好的方式來MD5多維數組?



arrays multidimensional-array (8)

(底部為複制粘貼功能)

如前所述,以下內容將起作用。

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)將產生與數組(3,2,1)不同的MD5。 如果這不是你想要的。 試試下面的代碼:

//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(或任何其他散列)的最佳方法是什麼?

我可以很容易地編寫一個遍歷數組每個級別的循環,將每個值連接成一個字符串,並簡單地在字符串上執行MD5。

然而,這似乎很麻煩,我想知道是否有一個時髦的函數會採取多維數組,並散列它。


Answer #1

目前最受歡迎的答案md5(serialize($array)); 對物體不適用。

考慮代碼:

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

即使數組不同(它們包含不同的對象),但在使用md5(serialize($array));時它們具有相同的散列值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函數不要更改原始數組。)


Answer #2

我通過回答參加一個非常擁擠的聚會,但是有一個重要的考慮,即現有的答案都沒有解決。 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;
}

Answer #3

有幾個答案告訴使用json_code,

但json_encode在iso-8859-1字符串中不能正常工作,只要有特殊字符,字符串就會被裁剪。

我會建議使用var_export:

md5(var_export($array, true))

不像序列化那麼慢,不像json_encode那樣錯誤


Answer #4

答案高度依賴於數組值的數據類型。 對於大字符串使用:

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%

關聯數組測試源 。 數字數組測試源


Answer #5

請注意, serializejson_encode在鍵值不是從0開始的數字數組或關聯數組上的行為不同。 json_encode會將這樣的數組存儲為一個Object ,所以json_decode返回一個Object ,其中unserialize將返回一個具有完全相同鍵的數組。


Answer #6
// 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);

Answer #7
md5(serialize($array));




md5