Stack = Array(); } function Push($values) { array_push($this->Stack, $values); } function Pop() { if ($this->Count() > 0) { return array_pop($this->Stack); } else { return false; } } function Get() { if ($this->Count() > 0) { // return end($this->Stack); return $this->Stack[count($this->Stack)-1]; } else { return false; } } function Update($values) { $this->Stack[count($this->Stack)-1] = $values; } function Count() { return count($this->Stack); } } class clsCachedPermissions { var $Allow = Array(); var $Deny = Array(); var $CatId; function clsCachedPermissions($CatId) { $this->CatId = $CatId; } function SetCatId($CatId) { $this->CatId = $CatId; } function CheckPermArray($Perm) { if (!isset($this->Allow[$Perm])) { $this->Allow[$Perm] = array(); $this->Deny[$Perm] = array(); } } function AddAllow($Perm, $GroupId) { $this->CheckPermArray($Perm); if (!in_array($GroupId, $this->Allow[$Perm])) { array_push($this->Allow[$Perm], $GroupId); $this->RemoveDeny($Perm, $GroupId); } } function AddDeny($Perm, $GroupId) { $this->CheckPermArray($Perm); if (!in_array($GroupId, $this->Deny[$Perm])) { array_push($this->Deny[$Perm], $GroupId); $this->RemoveAllow($Perm, $GroupId); } } function RemoveDeny($Perm, $GroupId) { if (in_array($GroupId, $this->Deny[$Perm])) { array_splice($this->Deny[$Perm], array_search($GroupId, $this->Deny[$Perm]), 1); } } function RemoveAllow($Perm, $GroupId) { if (in_array($GroupId, $this->Allow[$Perm])) { array_splice($this->Allow[$Perm], array_search($GroupId, $this->Allow[$Perm]), 1); } } function GetInsertSQL() { $values = array(); $has_deny = array(); // don't write DACL at all /*foreach ($this->Deny as $perm => $groups) { if (count($groups) > 0) { $values[] = '('.$this->CatId.', '.$perm.', "", "'.join(',', $groups).'")'; $has_deny[] = $perm; } }*/ foreach ($this->Allow as $perm => $groups) { // if (in_array($perm, $has_deny)) continue; if (count($groups) > 0) { $values[] = '(' .$this->CatId. ', ' .$perm. ', "' .join(',', $groups). '", "")'; } } if (!$values) return ''; $sql = 'INSERT INTO '.TABLE_PREFIX.'PermCache (CategoryId, PermId, ACL, DACL) VALUES '.join(',', $values); return $sql; } } class kPermCacheUpdater extends kHelper { var $Stack; var $iteration; var $totalCats; var $doneCats; var $table; var $primaryLanguageId = 0; var $languageCount = 0; var $root_prefixes = Array(); function Init($prefix, $special, $event_params = null) { parent::Init($prefix, $special, $event_params); $continuing = $event_params['continue']; // cache widely used values to speed up process: begin $ml_helper =& $this->Application->recallObject('kMultiLanguageHelper'); $this->languageCount = $ml_helper->getLanguageCount(); $this->primaryLanguageId = $this->Application->GetDefaultLanguageId(); // cache widely used values to speed up process: end foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $this->root_prefixes[ $module_info['RootCat'] ] = $module_info['Var']; } $this->iteration = 0; $this->table = $this->Application->GetTempName('permCacheUpdate'); if ($continuing == 1) { $this->InitUpdater(); } elseif ($continuing == 2) { $this->getData(); } } function InitUpdater() { $this->Stack =& new clsRecursionStack(); $sql = 'DELETE FROM '.TABLE_PREFIX.'PermCache'; $this->Conn->Query($sql); $this->initData(); } function getDonePercent() { if(!$this->totalCats)return 0; return min(100, intval( round( $this->doneCats / $this->totalCats * 100 ) )); } function getData() { $tmp = $this->Conn->GetOne('SELECT data FROM '.$this->table); if ($tmp) $tmp = unserialize($tmp); $this->totalCats = isset($tmp['totalCats']) ? $tmp['totalCats'] : 0; $this->doneCats = isset($tmp['doneCats']) ? $tmp['doneCats'] : 0; if (isset($tmp['stack'])) { $this->Stack = $tmp['stack']; } else { $this->Stack = & new clsRecursionStack(); } } function setData() { $tmp = Array ( 'totalCats' => $this->totalCats, 'doneCats' => $this->doneCats, 'stack' => $this->Stack, ); $this->Conn->Query('DELETE FROM '.$this->table); $fields_hash = Array('data' => serialize($tmp)); $this->Conn->doInsert($fields_hash, $this->table); } function initData() { $this->clearData(); // drop table before starting anyway $this->Conn->Query('CREATE TABLE '.$this->table.'(data LONGTEXT)'); $this->totalCats = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Category'); $this->doneCats = 0; } function clearData() { $this->Conn->Query('DROP TABLE IF EXISTS '.$this->table); } function DoTheJob() { $data = $this->Stack->Get(); if ($data === false) { //If Stack is empty $data['current_id'] = 0; $data['titles'] = Array(); $data['parent_path'] = Array(); $data['named_path'] = Array(); $data['category_template'] = ''; $data['item_template'] = ''; $this->Stack->Push($data); } if (!isset($data['queried'])) { $this->QueryTitle($data); $this->QueryChildren($data); $this->QueryPermissions($data); $data['queried'] = 1; if ($sql = $data['perms']->GetInsertSQL()) { $this->Conn->Query($sql); // $this->doneCats++; // moved to the place where it pops out of the stack by Kostja } $this->iteration++; } // start with first child if we haven't started yet if (!isset($data['current_child'])) $data['current_child'] = 0; // if we have more children if (isset($data['children'][$data['current_child']])) { $next_data = Array(); $next_data['titles'] = $data['titles']; $next_data['parent_path'] = $data['parent_path']; $next_data['named_path'] = $data['named_path']; $next_data['category_template'] = $data['category_template']; $next_data['item_template'] = $data['item_template']; $next_data['current_id'] = $data['children'][ $data['current_child'] ]; //next iteration should process child $next_data['perms'] = $data['perms']; //we should copy our permissions to child - inheritance $next_data['perms']->SetCatId($next_data['current_id']); $data['current_child']++; $this->Stack->Update($data); //we need to update ourself for the iteration after the next (or further) return to next child $this->Stack->Push($next_data); //next iteration should process this child return true; } else { $this->UpdateCachedPath($data); $this->Stack->Pop(); //remove ourself from stack if we have finished all the childs (or there are none) // we are getting here if we finished with current level, so check if it's first level - then bail out. $this->doneCats++; // moved by Kostja from above, seems to fix the prob return $this->Stack->Count() > 0; } } function UpdateCachedPath(&$data) { $fields_hash = Array ( 'ParentPath' => '|'.implode('|', $data['parent_path']).'|', 'NamedParentPath' => implode('/', $data['named_path'] ), 'CachedCategoryTemplate' => $data['category_template'], ); $i = 1; while ($i <= $this->languageCount) { $fields_hash['l'.$i.'_CachedNavbar'] = implode('&|&', $data['titles'][$i]); $i++; } $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$data['current_id']); } function QueryTitle(&$data) { $category_id = $data['current_id']; $sql = 'SELECT * FROM '.TABLE_PREFIX.'Category WHERE CategoryId = '.$category_id; $record = $this->Conn->GetRow($sql); if ($record) { $i = 1; while ($i <= $this->languageCount) { $data['titles'][$i][] = $record['l'.$i.'_Name'] ? $record['l'.$i.'_Name'] : $record['l'.$this->primaryLanguageId.'_Name']; $i++; } $data['parent_path'][] = $category_id; $data['named_path'][] = $record['Filename']; // it is one of the modules root category $root_prefix = isset($this->root_prefixes[$category_id]) ? $this->root_prefixes[$category_id] : false; if ($root_prefix) { $fields_hash = Array(); if (!$record['CategoryTemplate']) { $record['CategoryTemplate'] = $this->Application->ConfigValue($root_prefix.'_CategoryTemplate'); $fields_hash['CategoryTemplate'] = $record['CategoryTemplate']; } $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Category', 'CategoryId = '.$category_id); } // if explicitly set, then use it; use parent template otherwise if ($record['CategoryTemplate']) { $data['category_template'] = $record['CategoryTemplate']; } } } function QueryChildren(&$data) { $sql = 'SELECT CategoryId FROM '.TABLE_PREFIX.'Category WHERE ParentId = '.$data['current_id']; $data['children'] = $this->Conn->GetCol($sql); } function QueryPermissions(&$data) { // don't search for section "view" permissions here :) $sql = 'SELECT ipc.PermissionConfigId, ip.GroupId, ip.PermissionValue FROM '.TABLE_PREFIX.'Permissions AS ip LEFT JOIN '.TABLE_PREFIX.'PermissionConfig AS ipc ON ipc.PermissionName = ip.Permission WHERE (CatId = '.$data['current_id'].') AND (Permission LIKE "%.VIEW") AND (ip.Type = 0)'; $records = $this->Conn->Query($sql); //create permissions array only if we don't have it yet (set by parent) if (!isset($data['perms'])) { $data['perms'] = new clsCachedPermissions($data['current_id']); } foreach ($records as $record) { if ($record['PermissionValue'] == 1) { $data['perms']->AddAllow($record['PermissionConfigId'], $record['GroupId']); } else { $data['perms']->AddDeny($record['PermissionConfigId'], $record['GroupId']); } } } } ?>