1. ホーム
  2. php

[解決済み] 多次元配列の MD5 を行う PHP の最良の方法とは?

2022-06-27 04:17:15

質問

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

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

しかし、これは最高に面倒に思えるので、多次元配列を受け取り、それをハッシュ化するファンキーな関数があるかどうか疑問に思いました。

どのように解決するのか?

(下部にコピー&ペースト可能な機能あり)

前述したように、以下のようにするとうまくいきます。

md5(serialize($array));

しかし、(皮肉にも)json_encodeが実行するのは 顕著に より高速です。

md5(json_encode($array));

実際、(1) json_encode単独ではserializeよりも高速に動作し、(2) json_encodeではより小さな文字列を生成するため、md5が処理する量が少なくなるため、ここでは2倍の速度向上が期待できます。

編集してください。 この主張を裏付ける証拠がここにあります。

<?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%以上)高速です -- これは些細な違いではありません。このライブスクリプトによるテスト結果はこちらでご覧になれます。

さて、一つ注意すべきことは、array(1,2,3) は array(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));
}