MD5の多次元配列にPHPの最善の方法?


Answers

md5(serialize($array));
Question

多次元配列のMD5(または他のハッシュ)を生成する最良の方法は何ですか?

私は簡単に配列の各レベルを横断し、各値を文字列に連結し、単に文字列に対してMD5を実行するループを書くことができました。

しかし、これはせいぜい面倒だと思っていて、多次元配列をとり、ハッシュしてしまうファンキーな関数があるのか​​どうか疑問に思いました。




私はこれが良いヒントになると思う:

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



答えは、配列値のデータ型に大きく依存します。 ビッグストリングを使用するには:

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%

連想配列テストソース 。 数値配列テストソース




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



md5(serialize($array));

動作しますが、ハッシュは配列の順番によって変わります(それは問題ではないかもしれません)。




現在、最も多く投票された回答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関数は元の配列を変更しないでください)。




Links