एमडी 5 बहु-आयामी सरणी के लिए सबसे अच्छा तरीका PHP?


120

बहु-आयामी सरणी का MD5 (या कोई अन्य हैश) उत्पन्न करने का सबसे अच्छा तरीका क्या है?

मैं आसानी से एक लूप लिख सकता हूं, जो एरे के प्रत्येक स्तर के माध्यम से आगे बढ़ेगा, प्रत्येक मान को एक स्ट्रिंग में बदल देगा, और केवल स्ट्रिंग पर एमडी 5 का प्रदर्शन करेगा।

हालांकि, यह सबसे अच्छा बोझिल लगता है और मुझे आश्चर्य होता है कि क्या कोई फंकी फंक्शन था जो मल्टी-डायमेंशनल ऐरे को लेगा, और इसे।

जवाबों:


260

(नीचे की ओर कॉपी-एन-पेस्ट-सक्षम फ़ंक्शन)

जैसा कि पहले उल्लेख किया गया है, निम्नलिखित काम करेगा।

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.5x) से अधिक तेजी से (अक्सर 300% से अधिक) - यह एक तुच्छ अंतर नहीं है। आप इस लाइव स्क्रिप्ट के साथ परीक्षण के परिणाम यहां देख सकते हैं:

अब, ध्यान देने वाली एक बात है सरणी (1,2,3) एक अलग MD5 को सरणी (3,2,1) के रूप में उत्पन्न करेगी। यदि यह वह नहीं है जो आप चाहते हैं। निम्नलिखित कोड आज़माएं:

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

47
जबरदस्त हंसी! वास्तव में? मुझे "ओवर" ऑप्टिमाइज़ेशन के लिए वोट दिया गया? हकीकत में, PHP की क्रमबद्धता काफी धीमी है। मैं अपने उत्तर को साक्ष्य के साथ अपडेट करूंगा ...
नाथन जेबी

19
नाथन ने यहां जो कुछ भी किया है वह मूल्यवान है भले ही कोई इसका मूल्य न देख सके। यह कुछ स्थितियों में एक मूल्यवान अनुकूलन हो सकता है जो हमारे संदर्भ से बाहर हैं। माइक्रो ऑप्टिमाइज़ेशन कुछ खराब नहीं बल्कि सभी स्थितियों में एक खराब निर्णय है
SeanDowney

13
मैं इसके लिए माइक्रो-ऑप्टिमाइज़ेशन के लिए एक नहीं हूं, लेकिन जहां कोई अतिरिक्त काम नहीं करने के लिए डॉक्यूमेंटेड प्रदर्शन में वृद्धि हुई है, तो इसका उपयोग क्यों नहीं किया जाता है।
बम्परबॉक्स

2
वास्तव में, ऐसा लगता है कि यह निर्भर करता है कि सरणी कितनी गहरी है। मुझे कुछ ऐसी चीज़ों की आवश्यकता है जो जितनी जल्दी हो सके चलाने की ज़रूरत है और जब आपका पीओसी दिखाता है कि json_encode () ~ 300% तेज है, जब मैंने आपके उपयोग-मामले में आपके कोड में $ सरणी चर को बदल दिया, तो यह वापस आ गया 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 स्तर तक गहरी है, इसलिए बस यह ध्यान रखें कि (हमेशा की तरह) आपका माइलेज भिन्न हो सकता है।
samitny

3
ठीक है, मैं नहीं देखता कि नाथन का जवाब शीर्ष उत्तर क्यों नहीं है। गंभीरता से, क्रमबद्ध का उपयोग करें और अपने उपयोगकर्ताओं को एक बहुत ही धीमी साइट के साथ परेशान करें। महाकाव्य +1 @ नथानज.बुरे!
ReSpawN

168
md5(serialize($array));

13
अगर किसी कारण से आप हैश (फिंगरप्रिंट) से मेल खाना चाहते हैं, तो आप "सॉर्ट" या "केएसओआर" सॉर्ट करने पर विचार कर सकते हैं, इसके अलावा कुछ प्रकार के स्क्रबिंग / सफाई को लागू करने की भी आवश्यकता हो सकती है
किसान

9
दूसरे उत्तर से json_encode की तुलना में सीरियल बहुत अधिक धीमा है। अपने सर्वर को खुशी दें और json_encode का उपयोग करें! :)
s3m3n

3
ऐसा लगता है कि आपको यह जानने के लिए कि आपको json_encode या serialize का उपयोग करना चाहिए, अपने स्वयं के सरणी को बेंचमार्क करने की आवश्यकता है। सरणी के आधार पर यह भिन्न होता है।
21

मेरा मानना ​​है कि यह एक गलत तरीका है, कृपया मेरी व्याख्या नीचे देखें।
टर्मिनेट

1
@joelpittet - नहींं। उस ड्रुपल लिंक में दोनों उदाहरणों में कीड़े हैं। मेरे जवाब में टिप्पणियाँ नीचे देखें। ;) ईजी dl.dropboxusercontent.com/u/4115701/Screenshots/…
नाथन जेबी

26

मैं जवाब देकर बहुत भीड़ वाली पार्टी में शामिल हो रहा हूं, लेकिन एक महत्वपूर्ण विचार यह है कि कोई भी अतिरिक्त जवाब नहीं देता है। के मूल्य 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";

मेरा त्वरित डीप_स्कॉर्ट () कार्यान्वयन, इस मामले में फिट बैठता है, लेकिन अपनी परियोजनाओं पर उपयोग करने से पहले इसे जांचें:

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

11

उत्तर अत्यधिक प्रकार के सरणी मानों पर निर्भर करता है। बड़े तार के उपयोग के लिए:

md5(serialize($array));

छोटे तार और पूर्णांक के लिए:

md5(json_encode($array));

4 अंतर्निहित PHP फ़ंक्शंस सरणी को स्ट्रिंग में बदल सकते हैं: क्रमबद्ध करें () , json_encode () , var_export () , print_r ()

सूचना: json_encode () फ़ंक्शन धीमा हो जाता है, जबकि सहवर्ती सरणियों को मानों के रूप में संसाधित करते हैं। इस मामले में क्रमबद्ध () फ़ंक्शन का उपयोग करने पर विचार करें ।

कुंजी और मूल्यों में 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%

सहयोगी सरणी परीक्षण स्रोत । न्यूमेरिक एरे टेस्ट सोर्स


क्या आप बता सकते हैं कि बड़े और छोटे तार क्या हैं ?
AL

1
@AL शॉर्ट स्ट्रिंग्स - स्ट्रिंग्स जिसमें 25-30 चार्ट से कम होते हैंबड़े तार - 25-30 से अधिक सभी युक्त।
अलेक्जेंडर यानचुक

7

ब्रॉक के उत्कृष्ट उत्तर (+1) के अलावा, कोई भी सभ्य हैशिंग लाइब्रेरी आपको वेतन वृद्धि में हैश को अपडेट करने की अनुमति देती है, इसलिए आपको एक विशाल स्ट्रिंग बनाने के बजाय प्रत्येक स्ट्रिंग के साथ क्रमिक रूप से अपडेट करने में सक्षम होना चाहिए।

देख: hash_update


यह ध्यान देने योग्य है, कि यदि आप छोटे टुकड़ों के साथ अपडेट कर रहे हैं तो यह विधि अक्षम है; हालांकि यह बड़ी फ़ाइलों के बड़े हिस्से के लिए अच्छा है।
wrygiel

@wrygiel यह सच नहीं है। एमडी 5 के लिए, संपीड़न हमेशा 64-बाइट ब्लॉक में किया जाता है (कोई फर्क नहीं पड़ता कि आपके "बड़े चंक्स" का आकार क्या है), और, यदि आपने अभी तक एक ब्लॉक नहीं भरा है, तो ब्लॉक भरने तक कोई प्रसंस्करण नहीं होता है। (जब आप हैश को अंतिम रूप देते हैं, तो अंतिम ब्लॉक को पूर्ण प्रसंस्करण तक ले जाया जाता है , अंतिम प्रसंस्करण के हिस्से के रूप में।) अधिक पृष्ठभूमि के लिए, मर्कले-डैमगार्ड निर्माण (जो MD5, SHA-1, और SHA-2 पढ़ें) सभी पर आधारित हैं )।
क्रिस जस्टर-यंग

आप सही हे। मैं किसी अन्य साइट पर एक टिप्पणी द्वारा पूरी तरह से गुमराह किया गया था।
7

@wrygiel यही कारण है कि यह "इंटरनेट पर पाया" एक विचार का पालन करते हुए अपने स्वयं के अनुसंधान करने के लिए भुगतान करता है। ;-) ऐसा कहते हुए, वह अंतिम टिप्पणी मेरे लिए लिखना आसान था, क्योंकि मैंने वास्तव में एमडी 5 को खरोंच से कुछ साल पहले (मेरी योजना प्रोग्रामिंग कौशल का अभ्यास करने के लिए) लागू किया था, इसलिए मैं इसके कामकाज को अच्छी तरह से जानता हूं।
क्रिस जस्टर-यंग

यह वही है जो मैं चाहता हूं। मेमोरी में डेटा के बड़े ट्रक को स्थानांतरित करना और कॉपी करना कभी-कभी स्वीकार्य नहीं होता है। इसलिए क्रम-बद्धता का उपयोग करते हुए अन्य उत्तरों की तरह प्रदर्शन के मामले में यह बहुत बुरा विचार है। लेकिन यह एपीआई अभी भी लापता है अगर मैं केवल एक निश्चित ऑफसेट से स्ट्रिंग का हिस्सा हैश करना चाहता हूं।
जियानवू चेन

4
md5(serialize($array));

काम करेगा, लेकिन सरणी के क्रम के आधार पर हैश बदल जाएगा (हालांकि यह कोई फर्क नहीं पड़ता)।


3

ध्यान दें कि अलग-अलग तरीके से कार्य करें serializeऔर json_encodeजब यह संख्यात्मक सरणियों की बात आती है, जहां कुंजियां 0 या साहचर्य सरणियों पर शुरू नहीं होती हैं। json_encodeइस तरह के सरणियों को एक के रूप में संग्रहीत करेगा Object, इसलिए json_decodeएक रिटर्न देता है Object, जहां unserializeएक ही कुंजी के साथ एक सरणी वापस आ जाएगी।


3

मुझे लगता है कि यह एक अच्छी टिप हो सकती है:

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

2

के बारे में महत्वपूर्ण नोट 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;}"

दूसरी वस्तु php के बजाय बस लिंक बनाएँ "r: 2;" पहले उदाहरण के लिए। यह निश्चित रूप से डेटा को क्रमबद्ध करने का अच्छा और सही तरीका है, लेकिन यह आपके हैशिंग फ़ंक्शन के साथ मुद्दों को जन्म दे सकता है।


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

1

json_code का उपयोग करने के लिए कई उत्तर बता रहे हैं,

लेकिन json_encode iso-8859-1 स्ट्रिंग के साथ ठीक काम नहीं करता है, जैसे ही कोई विशेष चार्ट होता है, स्ट्रिंग क्रॉप हो जाती है।

मैं var_export का उपयोग करने की सलाह दूंगा:

md5(var_export($array, true))

नहीं के रूप में धीमी गति के रूप में क्रमबद्ध, नहीं json_encode के रूप में बग के रूप में


इतना तेज़ नहीं है, सबसे अच्छा विकल्प md4 का उपयोग करना है, var_export भी धीमा है
user956584

0

वर्तमान में सबसे अधिक मतदान का जवाब 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फ़ंक्शन को मूल सरणी नहीं बदलें।)


0

मैंने समाधान इतनी आसानी से नहीं देखा था इसलिए मैं एक सरल उत्तर देना चाहता था। मेरे लिए, जब तक मैं 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"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.