I have 2 multi-dimensional arrays. Essentially, one of them is an array that is constantly updated. I would like to find the updates aka additions and deletions between the arrays. For instance, I have some data as follows:
Updated/new array (Array #1):
Array ( [CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [msexchassistantname] => cn=CIGdeadp1,cn=Users,dc=test,dc=io [memberof] => Array ( [0] => CN=CIGdeadp1,CN=Users,DC=test,DC=io [1] => CN=CASUsers,CN=Users,DC=test,DC=io [2] => CN=CloudNCUsers,CN=Users,DC=test,DC=io [3] => CN=CloudEmailUsers,CN=Users,DC=test,DC=io ) [whenchanged] => 20201004180306.0Z [usnchanged] => 33404 [distinguishedname] => CN=Joe Dope,CN=Users,DC=test,DC=io ) [CN=Ronald,CN=Users,DC=test,DC=io] => Array ( [usnchanged] => 1342 [whenchanged] => 20191106190201.0Z ) )
Old array (Array #2):
[CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [msexchassistantname] => cn=CIGdeadp1,cn=Users,dc=test,dc=io [memberof] => Array ( [0] => CN=CIGdeadp1,CN=Users,DC=test,DC=io [1] => CN=CASUsers,CN=Users,DC=test,DC=io [2] => CN=CloudNCUsers,CN=Users,DC=test,DC=io [3] => CN=CloudOfficeUsers,CN=Users,DC=test,DC=io ) [othermailbox] => Array ( [0] => jdope1@gmail.com [1] => foobar@gmail.com ) [whenchanged] => 20200929142821.0Z [usnchanged] => 32855 [distinguishedname] => CN=Joe Dope,CN=Users,DC=test,DC=io )
What I’ve done so far is the following:
$array = []; $array["CN=Joe Dope,CN=Users,DC=test,DC=io"] = array("msexchassistantname" => ("cn=CIGdeadp1,cn=Users,dc=test,dc=io"), "memberof" => array("0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudEmailUsers,CN=Users,DC=test,DC=io" ), "whenchanged" => "20201004180306.0Z", "usnchanged" => "33404", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io"); $array["CN=Ronald,CN=Users,DC=test,DC=io"] = array("usnchanged" => "1342", "whenchanged" => "20191106190201.0Z"); $array2 = []; $array2["CN=Joe Dope,CN=Users,DC=test,DC=io"] = array("msexchassistantname" => "cn=CIGdeadp1,cn=Users,dc=test,dc=io", "memberof" => array("0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudOfficeUsers,CN=Users,DC=test,DC=io"), "othermailbox" => array("0" => "jdope1@gmail.com", "1" => "foobar@gmail.com"), "whenchanged" => "20200929142821.0Z", "usnchanged" => "32855", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io"); function check_diff_multi($array1, $array2){ $result = array(); foreach($array1 as $key => $val) { if(is_array($val) && isset($array2[$key])) { $tmp = check_diff_multi($val, $array2[$key]); if($tmp) { $result[$key] = $tmp; } } elseif(!isset($array2[$key])) { $result[$key] = null; } elseif($val !== $array2[$key]) { $result[$key] = $array2[$key]; } if(isset($array2[$key])) { unset($array2[$key]); } } $result = array_merge($result, $array2); return $result; } $full_difference = array_merge(check_diff_multi($array, $array2), check_diff_multi($array2, $array)); print_r($full_difference);
This doesn’t give me the exact output I want.
Here’s the output it gives me:
Array ( [CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [memberof] => Array ( [0] => CN=CloudEmailUsers,CN=Users,DC=test,DC=io ) [othermailbox] => [whenchanged] => 20201004180306.0Z [usnchanged] => 33404 [distinguishedname] => CN=Joe Dope,CN=Users,DC=test,DC=io ) [CN=Ronald,CN=Users,DC=test,DC=io] => Array ( [usnchanged] => 1342 [whenchanged] => 20191106190201.0Z ) )
What I would like is something more like this:
Array ( [CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [memberof] => Array ( [3] => CN=CloudOfficeUsers,CN=Users,DC=test,DC=io (Deleted) [3] => CN=CloudEmailUsers,CN=Users,DC=test,DC=io (Updated) ) [othermailbox] => Array (Deleted) ( [0] => jdope1@gmail.com (Deleted) [1] => foobar@gmail.com (Deleted) ) [whenchanged] => 20201004180306.0Z (Added) [whenchanged] => 20200929142821.0Z (Deleted) [usnchanged] => 33404 (Added) [usnchanged] => 32855 (Deleted) ) [CN=Ronald,CN=Users,DC=test,DC=io] => Array (Added) ( [usnchanged] => 1342 (Added) [whenchanged] => 20191106190201.0Z (Added) ) )
Any help would be very much appreciated. Thanks!
EDIT:
Forgot to add an edge case for if arrays inside the multi-dimensional array have the same values.
<?php $array[ "CN=Joe Dope,CN=Users,DC=test,DC=io" ] = array( "msexchassistantname" => ( "cn=CIGdeadp1,cn=Users,dc=test,dc=io" ), "memberof" => array( "0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudEmailUsers,CN=Users,DC=test,DC=io" ), "objectclass" => array( "0" => "top", "1" => "person" ), "whenchanged" => "20201004180306.0Z", "usnchanged" => "33404", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io" ); $array[ "CN=Ronald,CN=Users,DC=test,DC=io" ] = array( "usnchanged" => "1342", "whenchanged" => "20191106190201.0Z" ); $array2[ "CN=Joe Dope,CN=Users,DC=test,DC=io" ] = array( "msexchassistantname" => "cn=CIGdeadp1,cn=Users,dc=test,dc=io", "memberof" => array( "0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudOfficeUsers,CN=Users,DC=test,DC=io" ), "objectclass" => array( "0" => "top", "1" => "person" ), "othermailbox" => array( "0" => "jdope1@gmail.com", "1" => "foobar@gmail.com" ), "whenchanged" => "20200929142821.0Z", "usnchanged" => "32855", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io" ); # Main recursive function to compare function recordChanges($old, $new, &$result) { # Loop through the old array to see what is removed foreach($old as $k => $v) { # If the old and new have the same key if(isset($new[$k])) { # If array, recurse the array if(is_array($v)) { recordChanges($old[$k], $new[$k], $result[$k]); } # Note if the old is different else { $append = ($old[$k] == $new[$k])? "" : " (Deleted)"; if(!empty($append)) $result[$k.$append] = $v; } } # Note a straight delete else { $d = ' (Deleted)'; $nk = (is_array($v))? $k.$d : $k; $result[$nk] = (is_array($v))? appendKeys($v, $d) : $v.$d; } } # Now go through the new array foreach($new as $k => $v) { # See if there is a matching old array if(isset($old[$k])) { # Recurse for changes if(is_array($v)) { recordChanges($old[$k], $new[$k], $result[$k]); } # If not in old, note update else { $append = ($old[$k] == $new[$k])? "" : " (Updated)"; if(!empty($append)) $result[$k.$append] = $v; } } # If not in old, note as new else { $d = ' (Added)'; $nk = (is_array($v))? $k.$d : $k; $result[$nk] = (is_array($v))? appendKeys($v, $d) : $v.$d; } ksort($result); } } # This will just do a full recurse and append without any conditions function appendKeys($array, $append) { $new = []; foreach($array as $k => $v) { $nk = (is_array($v))? $k.$append : $k; $new[$nk] = (is_array($v))? appendKeys($v, $append) : $v.$append; } ksort($new); return $new; } $result = []; recordChanges($array2, $array, $result); print_r($result); ?>
So now we have 2 objectclass’s that are the same in each array. Upon running the code, we get the following:
Array ( [CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [memberof] => Array ( [3 (Deleted)] => CN=CloudOfficeUsers,CN=Users,DC=test,DC=io [3 (Updated)] => CN=CloudEmailUsers,CN=Users,DC=test,DC=io ) [objectclass] => [othermailbox (Deleted)] => Array ( [0] => jdope1@gmail.com (Deleted) [1] => foobar@gmail.com (Deleted) ) [usnchanged (Deleted)] => 32855 [usnchanged (Updated)] => 33404 [whenchanged (Deleted)] => 20200929142821.0Z [whenchanged (Updated)] => 20201004180306.0Z ) [CN=Ronald,CN=Users,DC=test,DC=io (Added)] => Array ( [usnchanged] => 1342 (Added) [whenchanged] => 20191106190201.0Z (Added) ) )
If we could remove the [objectclass] =>
it would be great.
Advertisement
Answer
You could probably do this with a recursive array iterator but I am just using a couple functions. The first function recordChanges()
, could be refactored since the top half is using the same logic (essentially) as the second half, but you get the idea:
<?php $array[ "CN=Joe Dope,CN=Users,DC=test,DC=io" ] = array( "msexchassistantname" => ( "cn=CIGdeadp1,cn=Users,dc=test,dc=io" ), "memberof" => array( "0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudEmailUsers,CN=Users,DC=test,DC=io" ), "whenchanged" => "20201004180306.0Z", "usnchanged" => "33404", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io" ); $array[ "CN=Ronald,CN=Users,DC=test,DC=io" ] = array( "usnchanged" => "1342", "whenchanged" => "20191106190201.0Z" ); $array2[ "CN=Joe Dope,CN=Users,DC=test,DC=io" ] = array( "msexchassistantname" => "cn=CIGdeadp1,cn=Users,dc=test,dc=io", "memberof" => array( "0" => "CN=CIGdeadp1,CN=Users,DC=test,DC=io", "1" => "CN=CASUsers,CN=Users,DC=test,DC=io", "2" => "CN=CloudNCUsers,CN=Users,DC=test,DC=io", "3" => "CN=CloudOfficeUsers,CN=Users,DC=test,DC=io" ), "othermailbox" => array( "0" => "jdope1@gmail.com", "1" => "foobar@gmail.com" ), "whenchanged" => "20200929142821.0Z", "usnchanged" => "32855", "distinguishedname" => "CN=Joe Dope,CN=Users,DC=test,DC=io" ); # Main recursive function to compare function recordChanges($old, $new, &$result) { # Loop through the old array to see what is removed foreach($old as $k => $v) { # If the old and new have the same key if(isset($new[$k])) { # If array, recurse the array if(is_array($v)) { recordChanges($old[$k], $new[$k], $result[$k]); } # Note if the old is different else { $append = ($old[$k] == $new[$k])? "" : " (Deleted)"; if(!empty($append)) $result[$k.$append] = $v; } } # Note a straight delete else { $d = ' (Deleted)'; $nk = (is_array($v))? $k.$d : $k; $result[$nk] = (is_array($v))? appendKeys($v, $d) : $v.$d; } } # Now go through the new array foreach($new as $k => $v) { # See if there is a matching old array if(isset($old[$k])) { # Recurse for changes if(is_array($v)) { recordChanges($old[$k], $new[$k], $result[$k]); } # If not in old, note update else { $append = ($old[$k] == $new[$k])? "" : " (Updated)"; if(!empty($append)) $result[$k.$append] = $v; } } # If not in old, note as new else { $d = ' (Added)'; $nk = (is_array($v))? $k.$d : $k; $result[$nk] = (is_array($v))? appendKeys($v, $d) : $v.$d; } ksort($result); } } # This will just do a full recurse and append without any conditions function appendKeys($array, $append) { $new = []; foreach($array as $k => $v) { $nk = (is_array($v))? $k.$append : $k; $new[$nk] = (is_array($v))? appendKeys($v, $append) : $v.$append; } ksort($new); return $new; } $result = []; recordChanges($array2, $array, $result); print_r($result);
This will give you:
Array ( [CN=Joe Dope,CN=Users,DC=test,DC=io] => Array ( [memberof] => Array ( [3 (Deleted)] => CN=CloudOfficeUsers,CN=Users,DC=test,DC=io [3 (Updated)] => CN=CloudEmailUsers,CN=Users,DC=test,DC=io ) [othermailbox (Deleted)] => Array ( [0] => jdope1@gmail.com (Deleted) [1] => foobar@gmail.com (Deleted) ) [usnchanged (Deleted)] => 32855 [usnchanged (Updated)] => 33404 [whenchanged (Deleted)] => 20200929142821.0Z [whenchanged (Updated)] => 20201004180306.0Z ) [CN=Ronald,CN=Users,DC=test,DC=io (Added)] => Array ( [usnchanged] => 1342 (Added) [whenchanged] => 20191106190201.0Z (Added) ) )
Note that you can not have the same-named key because they will overwrite each other, so to keep keys, you would have to append the keys.