回答:
(下部にあるコピーアンドペースト可能な機能)
前に述べたように、以下が機能します。
md5(serialize($array));
ただし、(皮肉なことに)json_encodeは著しく高速であることに注意してください。
md5(json_encode($array));
実際、(1)json_encodeのみがシリアライズよりも高速に実行され、(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.5x)以上高速です(多くの場合300%以上)-これは些細な違いではありません。このライブスクリプトを使用したテストの結果は、次の場所に表示されます。
ここで、注目すべき点の1つは、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-1-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));
}
serialize() w/ md5() took: 0.27773594856262 sec
json_encode() w/ md5() took: 0.34809803962708 sec
json_encode is (79.8%) faster with a difference of (-0.070362091064453 seconds)
(パーセント計算明らかに不正確です)。私の配列は最大2レベルの深さなので、(いつものように)走行距離が異なる場合があることに注意してください。
md5(serialize($array));
私は非常に混雑したパーティーに答えることによって参加していますが、現存する答えのどれも対処しないという重要な考慮事項があります。およびの値は、配列内の要素の順序に依存します!json_encode()
serialize()
これは、配列をソートおよびソートしない、同じ値を持つが異なる順序で追加された2つの配列 の結果です(ポストの下部にあるコード)。
serialize()
1c4f1064ab79e4722f41ab5a8141b210
1ad0f2c7e690c8e3cd5c34f7c9b8573a
json_encode()
db7178ba34f9271bfca3a05c5dddf502
c9661c0852c2bd0e26ef7951b4ca9e6f
Sorted serialize()
1c4f1064ab79e4722f41ab5a8141b210
1c4f1064ab79e4722f41ab5a8141b210
Sorted json_encode()
db7178ba34f9271bfca3a05c5dddf502
db7178ba34f9271bfca3a05c5dddf502
したがって、配列をハッシュするために推奨する2つの方法は次のとおりです。
// 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;
}
答えは、配列値のデータ型に大きく依存します。大きな文字列の場合:
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%
Brockの優れた回答(+1)は別として、適切なハッシュライブラリを使用すると、ハッシュを段階的に更新できるため、1つの巨大な文字列を作成する代わりに、各文字列を順番に更新できるはずです。
見る: hash_update
これは良いヒントになると思います:
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);
についての重要な注意 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;}"
したがって、2番目のオブジェクトの代わりに、phpはリンク "r:2;"を作成します。最初のインスタンスに。これは間違いなくデータをシリアル化するための正しい方法ですが、ハッシュ関数で問題が発生する可能性があります。
// 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);
json_codeを使用するように指示するいくつかの回答があります。
しかし、json_encodeはiso-8859-1文字列では正常に機能しません。特別な文字があるとすぐに、文字列が切り取られます。
私はvar_exportを使用することをお勧めします:
md5(var_export($array, true))
シリアライズほど遅くなく、json_encodeほどバグがありません
現在、最も多く投票されている回答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
関数は元の配列を変更しないでください。)
上ではそれほど簡単に解決策を見つけられなかったので、より簡単な答えを提供したいと思いました。私にとっては、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"