diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php index b48493c13532e..1f4a86be6d59a 100644 --- a/lib/private/Files/Cache/Scanner.php +++ b/lib/private/Files/Cache/Scanner.php @@ -222,15 +222,7 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = // Only update metadata that has changed // i.e. get all the values in $data that are not present in the cache already - // NOTE: we serialize then unserialize here because array_diff_assoc() doesn't - // support multidimensional arrays on its own (and otherwise internally casts any - // embedded array elements to attempt to compare them - not only generating warnings - // like "Array to string conversion" but also, as a resut, overlooking real differences) - $newData = array_diff_assoc( - array_map('serialize', $data), - array_map('serialize', $cacheData->getData()) - ); - $newData = array_map('unserialize', $newData); + $newData = $this->array_diff_assoc_multi($data, $cacheData->getData()); // make it known to the caller that etag has been changed and needs propagation if (isset($newData['etag'])) { @@ -378,6 +370,64 @@ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $loc return $data; } + /** + * Compares $array1 against $array2 and returns all the values in $array1 that are not in $array2 + * Note this is a one-way check - i.e. we don't care about things that are in $array2 that aren't in $array1 + * + * Supports multi-dimensional arrays + * Also checks keys/indexes + * Comparisons are strict just like array_diff_assoc + * Order of keys/values does not matter + * + * @param array $array1 + * @param array|? $array2 + * @return array with the differences between $array1 and $array1 + * @throws \InvalidArgumentException if $array1 isn't an actual array + * + */ + protected function array_diff_assoc_multi($array1, $array2) { + if (!is_array($array1)) { + // this ain't gonna work + throw new \InvalidArgumentException('$array1 must be an array!'); + } + + if (!is_array($array2)) { + // everything is different + return $array1; + } + + $result = []; + + foreach ($array1 as $key => $value) { + + // if $array2 doesn't have the same key, that's a result + if (!array_key_exists($key, $array2)) { + $result[$key] = $value; + continue; + } + + // if $array2's value for the same key is different, that's a result + if ($array2[$key] !== $value && !is_array($value)) { + $result[$key] = $value; + continue; + } + + if (is_array($value)) { + $nestedDiff = $this->array_diff_assoc_multi($value, $array2[$key]); + if (!empty($nestedDiff)) { + $result[$key] = $nestedDiff; + continue; + } + } else { // not an array + if ($array2[$key] != $value) { + $result[$key] = $value; + continue; + } + } + } + return $result; + } + /** * Get the children currently in the cache *