PHP beste manier om MD5 multidimensionale array te maken?

Wat is de beste manier om een ​​MD5 (of een andere hash) van een multidimensionale array te genereren?

Ik zou gemakkelijk een lus kunnen schrijven die door elk niveau van de array zou gaan, elke waarde in een string zou samenvoegen en eenvoudig de MD5 op de string zou uitvoeren.

Dit lijkt echter op zijn best omslachtig en ik vroeg me af of er een funky functie was die een multidimensionale array zou nemen en deze zou hashen.


Antwoord 1, autoriteit 100%

(Copy-n-paste-functie onderaan)

Zoals eerder vermeld, zal het volgende werken.

md5(serialize($array));

Het is echter vermeldenswaard dat (ironisch genoeg) json_encode aanzienlijksneller presteert:

md5(json_encode($array));

In feite is de snelheidsverhoging hier tweevoudig, aangezien (1) json_encode alleen sneller presteert dan serialiseren, en (2) json_encode een kleinere string produceert en daarom minder voor md5 om te verwerken.

Bewerken:hier is bewijs om deze bewering te ondersteunen:

<?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 is consistent meer dan 250% (2,5x) sneller (vaak meer dan 300%) — dit is geen triviaal verschil. U kunt de resultaten van de test met dit livescript hier zien:

Een ding om op te merken is dat array(1,2,3) een andere MD5 zal produceren als array(3,2,1). Alsdit NIET is wat je wilt. Probeer de volgende code:

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

Bewerken:er is enige vraag geweest of het omkeren van de volgorde dezelfde resultaten zou opleveren. Dus ik heb dat hier (correct) gedaan:

Zoals je kunt zien, zijn de resultaten precies hetzelfde. Hier is de (gecorrigeerde) test oorspronkelijk gemaakt door iemand gerelateerd aan Drupal:

En voor de goede orde, hier is een functie/methode die je kunt kopiëren en plakken (getest 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));
}

Antwoord 2, autoriteit 59%

md5(serialize($array));

Antwoord 3, autoriteit 9%

Ik sluit me aan bij een erg druk gezelschap door te antwoorden, maar er is een belangrijke overweging die geen van de bestaande antwoorden adresseert. De waarde van json_encode()en serialize()zijn beide afhankelijk van de volgorde van elementen in de array!

Hier zijn de resultaten van het niet sorteren en sorteren van de arrays, op twee arrays met identieke waarden maar toegevoegd in een andere volgorde(code onderaan bericht):

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

Daarom zijn de twee methoden die ik zou aanraden om een array te hashende volgende zijn:

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

De keuze voor json_encode()of serialize()moet bepaald worden door te testen op het type gegevens dat jijbent met behulp van . Door mijn eigen testen op puur tekstuele en numerieke gegevens, als de code niet duizenden keren een strakke lus draait, is het verschil niet eens de moeite waard om te benchmarken. Ik gebruik persoonlijk json_encode()voor dat soort gegevens.

Hier is de code die wordt gebruikt om de sorteertest hierboven te genereren:

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

Mijn snelle deep_ksort()-implementatie past in dit geval, maar controleer het voordat je het op je eigen projecten gebruikt:

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

Antwoord 4

in sommige gevallen is het misschien beter om http_build_queryte gebruiken om array naar string te converteren :

md5( http_build_query( $array ) );

Other episodes