/** * @param $array1 array * @param $array2 array * @param $show_type boolean * @return array|boolean */ function arrayDiffRecursive($array1, $array2, $show_type = false) { $diff = []; foreach ($array1 as $key => $value) { if (!(isset($array2[$key]) || array_key_exists($key, $array2))) { $diff[$key] = $value; } elseif (is_array($value)) { if (!is_array($array2[$key])) { $diff[$key] = $value; } else { $sub_diff = arrayDiffRecursive($value, $array2[$key]); if ($sub_diff !== false) { $diff[$key] = $sub_diff; } } } elseif (is_array($array2[$key])) { $diff[$key] = $value; } elseif ($array2[$key] !== $value) { $diff[$key] = strval($value); if ($show_type && gettype($value) !== gettype($array2[$key])) { $diff[$key] .= '(' . gettype($value) . ')'; } } } return $diff ? $diff : false; }
/** * Assumes a checked value is the same than an assumed value * * @param $test string the name of the test (ie 'Method_Name[.test_name]') * @param $check mixed the checked value * @param $assume mixed the assumed value * @return boolean true if the checked value corresponds to the assumed value */ protected function assume($test, $check, $assume) { $duration = round((microtime(true) - $this->start_time) * 1000000); $check = $this->toArray($check); $assume = $this->toArray($assume); if (is_array($check) && is_array($assume)) { $diff1 = arrayDiffRecursive($check, $assume, true); $diff2 = arrayDiffRecursive($assume, $check, true); $ok = !$diff1 && !$diff2; } else { $diff1 = $check; $diff2 = $assume; $ok = $check === $assume; } if ($ok) { if ($duration > 9999) { $duration = round($duration / 1000) . 'ms'; } else { $duration .= 'μs'; } $result = '<span style="color:green;font-weight:bold">OK</span> (<i>' . $duration . '</i>)'; } else { $result = '<span style="color:red;font-weight:bold">BAD</span>' . '<pre style="color:red;font-weight:bold;">[' . print_r($check, true) . ']</pre>' . '<pre style="color:blue;font-weight:bold;">[' . print_r($assume, true) . ']</pre>' . ($diff1 ? '<pre style="color:orange;font-weight:bold;">[' . print_r($diff1, true) . ']</pre>' : '') . ($diff2 ? '<pre style="color:orange;font-weight:bold;">[' . print_r($diff2, true) . ']</pre>' : ''); } echo '<li>' . str_replace(get_class($this) . '::', '', $test) . ' : ' . $result; return $result === 'OK'; }
/** * Рекурсивно вычесть массив $array2 из массива $array1 * * @param array $array1 * @param array $array2 * @return array */ function &arrayDiffRecursive(&$array1, &$array2) { $result = $array1; foreach ($array2 as $key2 => &$value2) { if (!is_array($value2) && ($key_result = array_search($value2, $result)) !== FALSE) { unset($result[$key_result]); continue; } if (isset($result[$key2]) && is_array($result[$key2]) && is_array($value2)) { $result[$key2] = arrayDiffRecursive($result[$key2], $value2); } } return $result; }
/** * Получить список разрешения доступа с уже вычтеным из него списком запрещения доступа * Метод вызывается рекурсивно и способна свалиться в цикл, если существует цикл в исходных массивах * * @param mixed $role * @return array */ private function getAllow($role) { $storageKey = __CLASS__ . '_' . __METHOD__ . '_' . $role; /** * Если в сессии не сохранён список, то вычисляем и сохраняем в сессию */ if (($allow = $this->storage()->get($storageKey)) === FALSE) { /** * Получение прямых списков разрешения и запрещения доступа для переданной роли */ $allow = isset($this->allow[$role]) ? $this->allow[$role] : array(); $deny = isset($this->deny[$role]) ? $this->deny[$role] : array(); /** * Разворачивание всей иерархии, если она есть */ if (isset($this->hierarchy[$role])) { foreach ($this->hierarchy[$role] as &$parent) { $temp = $this->getAllow($parent); $allow = arrayMergeUniqueRecursive($allow, $temp); } } /** * Вычитание из списка разрешения доступа списка запрета доступа */ $allow = arrayDiffRecursive($allow, $deny); /** * Сохранение списка разрешения доступа в сессию */ $this->storage()->set($storageKey, $allow); } return $allow; }