Conn =& $this->Application->GetADODBConnection(); } /** * Returns information about registered regular events * * @param bool $from_cache * * @return Array */ function getRegularEvents($from_cache = false) { static $agents = null; if ($from_cache) { return Array ( reBEFORE => $this->beforeRegularEvents, reAFTER => $this->afterRegularEvents, ); } else { if (!isset($agents)) { $sql = 'SELECT * FROM ' . $this->Application->getUnitOption('agent', 'TableName') . ' WHERE Status = ' . STATUS_ACTIVE . ' AND LastRunStatus <> ' . AGENT_LAST_RUN_RUNNING; $all_agents = $this->Conn->Query($sql); $agents = Array ( reBEFORE => Array (), reAFTER => Array (), ); foreach ($all_agents as $agent_data) { $agents[ $agent_data['RunMode'] ][ $agent_data['AgentName'] ] = Array ( 'EventName' => $agent_data['Event'], 'RunInterval' => (int)$agent_data['RunInterval'], 'LastRunOn' => (int)$agent_data['LastRunOn'], 'NextRunOn' => (int)$agent_data['NextRunOn'], ); } } return $agents; } } /** * Set's new enviroment parameter mappings * between their names as application vars * * @param Array $new_query_maps * @access public */ /*function setQueryMaps($new_query_maps) { $this->queryMaps = $new_query_maps; }*/ /** * Adds new query map to already parsed query maps * * @param string $prefix */ function setQueryMap($prefix_special) { list($prefix) = explode('.', $prefix_special); $query_map = $this->getQueryMap($prefix); if ($query_map) { $this->queryMaps[$prefix_special] = $query_map; } else { unset($this->queryMaps[$prefix]); } // 'passed' is set later in ProcessRequest - do we really need it here? (it breakes HTTPQuery initialization...) // $this->Application->SetVar('passed', implode(',', array_keys($this->queryMaps)) ); return $query_map; } /** * Returns QueryMap for requested unit config. In case if unit config is a clone, then get parent item's (from prefix) config to create clone * * @param string $prefix * @return Array */ function getQueryMap($prefix) { $query_map = $this->Application->getUnitOption($prefix, 'QueryString'); if (!$query_map) { if (preg_match('/(.*?)-(.*)/', $prefix, $regs)) { // #prefix - format for configs, that are only cloned & optionally used for hooking (without # is old format) $check_prefixes = Array ('#'.$regs[2], $regs[2]); foreach ($check_prefixes as $check_prefix) { if ($this->Application->UnitConfigReader->prefixRegistred($check_prefix)) { return $this->Application->getUnitOption($check_prefix, 'QueryString'); } } } } return $query_map; } /** * Registers new regular event * * @param string $short_name name to be used to store last maintenace run info * @param string $event_name * @param int $run_interval run interval in seconds * @param int $type before or after regular event */ function registerRegularEvent($short_name, $event_name, $run_interval, $type = reBEFORE) { if($type == reBEFORE) { $this->beforeRegularEvents[$short_name] = Array('EventName' => $event_name, 'RunInterval' => $run_interval); } else { $this->afterRegularEvents[$short_name] = Array('EventName' => $event_name, 'RunInterval' => $run_interval); } } function registerBuildEvent($pseudo_class,$build_event_name) { $this->buildEvents[$pseudo_class]=$build_event_name; } /** * Returns build event by pseudo class * name if any defined in config * * @param string $pseudo_class * @return kEvent * @access public */ function &getBuildEvent($pseudo_class) { $false = false; if( !isset($this->buildEvents[$pseudo_class]) ) return $false; $event = new kEvent(); $event->Name=$this->buildEvents[$pseudo_class]; $event->MasterEvent=null; return $event; } /** * Check if event is called twice, that causes recursion * * @param kEvent $event */ function isRecursion(&$event) { $event_key = $event->getPrefixSpecial().':'.$event->Name; return in_array($event_key, $this->recursionStack) ? true : false; } function pushEvent(&$event) { $event_key = $event->getPrefixSpecial().':'.$event->Name; array_push($this->recursionStack, $event_key); } function popEvent() { array_pop($this->recursionStack); } /** * Allows to process any type of event * * @param kEvent $event * @access public */ function HandleEvent(&$event) { if ($this->isRecursion($event)) { return true; } $this->pushEvent($event); if( !$this->Application->prefixRegistred($event->Prefix) ) { $unit_config_reader =& $this->Application->recallObject('kUnitConfigReader'); $unit_config_reader->loadConfig($event->Prefix); if( !$this->Application->prefixRegistred($event->Prefix) ) { trigger_error('Prefix '.$event->Prefix.' not registred (requested event '.$event->Name.')', E_USER_NOTICE); return false; } } if (!$event->SkipBeforeHooks) { $this->processHooks($event, hBEFORE); if ($event->status == erFATAL) return true; } $event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler'); /* @var $event_handler kEventHandler */ $event_handler->processEvent($event); if ($event->status == erFATAL) return true; if (!$event->SkipAfterHooks) { $this->processHooks($event, hAFTER); } $this->popEvent(); return true; } /** * Returns event names given in POST * * @return Array */ function _getEventsFromPost() { $events = $this->Application->GetVar('events'); if ($events === false) { return Array (); } $ret = Array (); foreach ($events as $prefix_special => $event_name) { if (!$event_name) { continue; } if (is_array($event_name)) { // HTML-input names like "events[prefix.special][event_name]", input value don't matter $event_name = key($event_name); $this->Application->SetVar($prefix_special . '_event', $event_name); } // HTML-input names like "events[prefix.special]", input value is event name $ret[$prefix_special] = $event_name; } return $ret; } function ProcessRequest() { $this->processOpener(); // 1. get events from $_POST $events = $this->_getEventsFromPost(); // 2. if nothing there, then try to find them in $_GET if ($this->queryMaps && !$events) { // if we got $_GET type submit (links, not javascript) foreach ($this->queryMaps as $prefix_special => $query_map) { $query_map = array_flip($query_map); if (isset($query_map['event'])) { $event_name = $this->Application->GetVar($prefix_special . '_event'); if ($event_name) { $events[$prefix_special] = $event_name; } } } // used ? $actions = $this->Application->GetVar('do'); if ($actions) { list ($prefix, $event_name) = explode('_', $actions); if ($event_name) { $events[$prefix] = $event_name; } } } // 3. store all prefixes passed before event processing, because they are used by GetTopmostPrefix $all_passed = explode(',', $this->Application->GetVar('passed')); foreach ($events as $prefix_special => $event_name) { if (!$event_name) continue; $prefix_special = explode('.',$prefix_special); array_push($all_passed, $prefix_special[0]); } $this->Application->SetVar('all_passed', implode(',', $all_passed)); foreach ($events as $prefix_special => $event_name) { $event = new kEvent(); $event->Name = $event_name; $event->Prefix_Special = $prefix_special; $prefix_special = explode('.',$prefix_special); $event->Prefix = $prefix_special[0]; // array_push($passed, $prefix_special[0]); $event->Special = isset($prefix_special[1]) ? $prefix_special[1] : ''; $event->redirect_params = Array('opener' => 's', 'pass' => 'all'); $event->redirect = true; $event_handler =& $this->Application->recallObject($event->Prefix.'_EventHandler'); /* @var $event_handler kEventHandler */ if (preg_match('/(.*?)-(.*)/', $event->Prefix, $regs) && $this->Application->UnitConfigReader->prefixRegistred($regs[1])) { // this is event from cloned config -> load parent config to create valid clone $this->Application->UnitConfigReader->loadConfig($regs[1]); $this->Application->HandleEvent( new kEvent($regs[1].':OnAfterConfigRead') ); } $event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true)); if (($this->Application->RecallVar('user_id') == -1) || $event_handler->CheckPermission($event)) { $this->HandleEvent($event); } if ($event->status == erSTOP) { // event requested to stop processing at this point safeDefine('DBG_SKIP_REPORTING', 1); $this->Application->Session->SaveData(); exit; } if ($event->status == erPERM_FAIL) { // should do redirect but to no_permissions template $event->redirect = $this->Application->IsAdmin() ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate'); $event->redirect_params['pass'] = 'm'; $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $event->redirect_params['m_cat_id'] = $themes_helper->getPageByTemplate($event->redirect); // restore stuff, that processOpener() changed $wid = $this->Application->GetVar('m_wid'); $this->Application->RestoreVar(rtrim('opener_stack_'.$wid, '_')); // don't save last_template, because no_permission template does js history.back and could cause invalid opener_stack content $this->Application->SetVar('skip_last_template', 1); } if ( ($event->status == erSUCCESS || $event->status == erPERM_FAIL) && ($event->redirect === true || strlen($event->redirect) > 0)) { // we need to pass category if the action was submitted to self-template, with the category passed // and it has not explicly set redirect template or pass_cateogry param if ($event->redirect === true && !isset($event->redirect_params['pass_category']) && $this->Application->GetVar('m_cat_id')) { $event->redirect_params['pass_category'] = 1; } $wid = $this->Application->GetVar('m_wid'); if ($wid && $event->redirect_params['opener'] == 'u') { $event->redirect_params['opener'] = 's'; // because Application->HREF will react differently when 'opener' = 'u' $event->redirect = defined('CLOSE_POPUP_TPL') ? CLOSE_POPUP_TPL : 'incs/close_popup'; } $this->Application->Redirect($event->redirect, $event->redirect_params, null, $event->redirect_script); } } $this->Application->SetVar('events', $events); $this->Application->SetVar('passed', implode(',', $all_passed)); } function processOpener() { $wid = $this->Application->GetVar('m_wid'); $opener_stack = $this->Application->RecallVar(rtrim('opener_stack_'.$wid, '_')); $opener_stack = $opener_stack ? unserialize($opener_stack) : Array(); $opener_action = $this->Application->GetVar('m_opener'); switch ($opener_action) { case 'r': // "reset" opener stack $opener_stack = Array(); break; case 'd': // "down/push" new template to opener stack, deeplevel++ if ($this->Application->GetVar('front')) { $front_session =& $this->Application->recallObject('Session.front'); array_push($opener_stack, '../'.$front_session->RecallVar('last_template') ); } else { array_push($opener_stack, $this->Application->RecallVar('last_template') ); } break; case 'u': // "up/pop" last template from opener stack, deeplevel-- array_pop($opener_stack); break; case 'p': // pop-up - generate new wid $parent_wid = $this->Application->GetVar('m_wid'); // window_id of popup's parent window $popup_wid = (int)$this->Application->RecallVar('last_wid') + 1; $this->Application->StoreVar('last_wid', $popup_wid); $this->Application->SetVar('m_wid', $popup_wid); if ($this->Application->GetVar('front')) { $front_session =& $this->Application->recallObject('Session.front'); $last_template = $front_session->RecallVar(rtrim('last_template_popup_'.$parent_wid, '_')); $last_template = '../'.$last_template; } else { if ($this->Application->GetVar('merge_opener_stack')) { // get last template from parent (that was closed) window opener stack $parent_opener_stack_name = rtrim('opener_stack_' . $parent_wid, '_'); $parent_opener_stack = unserialize( $this->Application->RecallVar($parent_opener_stack_name) ); $last_template = array_pop($parent_opener_stack); if ($parent_opener_stack) { $this->Application->StoreVar($parent_opener_stack_name, serialize($parent_opener_stack)); } else { $this->Application->RemoveVar($parent_opener_stack_name); } } else { $last_template = $this->Application->RecallVar(rtrim('last_template_popup_'.$parent_wid, '_')); } } $opener_stack = Array ( $last_template ); $this->Application->SetVar('m_opener', 's'); $wid = $popup_wid; /*// store window relations $window_relations = $this->Application->RecallVar('window_relations'); $window_relations = $window_relations ? unserialize($window_relations) : Array (); $window_relations[$popup_wid] = $parent_wid; $this->Application->StoreVar('window_relations', serialize($window_relations));*/ break; default: // "s/0," stay on same deep level break; } $this->Application->SetVar('m_opener', 's'); $this->Application->StoreVar(rtrim('opener_stack_'.$wid, '_'), serialize($opener_stack)); } /** * Allows to add new element to opener stack * * @param string $template * @param Array $params * @param string $pass */ function openerStackPush($template, $params, $pass = 'all', $wid = null) { if (!isset($wid)) { $wid = $this->Application->GetVar('m_wid'); } /*// get parent window wid, when this was popup $window_relations = $this->Application->RecallVar('window_relations'); $window_relations = $window_relations ? unserialize($window_relations) : Array (); $wid = array_key_exists($wid, $window_relations) ? $window_relations[$wid] : false;*/ // get opener stack $stack_name = rtrim('opener_stack_' . $wid, '_'); $opener_stack = $this->Application->RecallVar($stack_name); $opener_stack = $opener_stack ? unserialize($opener_stack) : Array (); // change opener stack $default_params = Array ('m_opener' => 'u', '__URLENCODE__' => 1); $redirect_params = array_merge_recursive2($default_params, $params); $new_level = $this->Application->BuildEnv($template, $redirect_params, $pass, true); array_push($opener_stack, 'index.php|' . ltrim($new_level, ENV_VAR_NAME . '=') ); $this->Application->StoreVar($stack_name, serialize($opener_stack)); } /** * Allows to change last element in opener stack * * @param string $template * @param Array $params * @param string $pass */ function openerStackChange($params = Array(), $pass_events = true, $wid = null) { if (!isset($wid)) { $wid = $this->Application->GetVar('m_wid'); } // get opener stack $stack_name = rtrim('opener_stack_' . $wid, '_'); $opener_stack = $this->Application->RecallVar($stack_name); $opener_stack = $opener_stack ? unserialize($opener_stack) : Array (); // change opener stack list ($index_file, $env) = explode('|', $opener_stack[ count($opener_stack) - 1 ], 2); $vars = $this->Application->HttpQuery->processQueryString($env, 'pass'); $vars = array_merge_recursive2($vars, $params); // save opener stack $new_level = $this->Application->BuildEnv($vars['t'], $vars, $vars['pass'], $pass_events, false); $opener_stack[ count($opener_stack) - 1 ] = $index_file . '|' . $new_level; $this->Application->StoreVar($stack_name, serialize($opener_stack)); } function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional) { if ( !$this->Application->prefixRegistred($hookto_prefix) && $hookto_prefix != '*' ) { if ($this->Application->isDebugMode()) { trigger_error('Prefix '.$hookto_prefix.' doesn\'t exist when trying to hook from '.$do_prefix.':'.$do_event.'', E_USER_WARNING); } return; } $hookto_prefix_special = rtrim($hookto_prefix.'.'.$hookto_special, '.'); if ($mode == hBEFORE) { $this->beforeHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array( 'DoPrefix' => $do_prefix, 'DoSpecial' => $do_special, 'DoEvent' => $do_event, 'Conditional' => $conditional, ); } elseif ($mode == hAFTER) { $this->afterHooks[strtolower($hookto_prefix_special.'.'.$hookto_event)][] = Array( 'DoPrefix' => $do_prefix, 'DoSpecial' => $do_special, 'DoEvent' => $do_event, 'Conditional' => $conditional, ); } } /** * Enter description here... * * @param kEvent $event * @param int $mode hBEFORE or hAFTER * @param string $event_key * @return Array */ function &_getHooks(&$event, $mode, $event_key = null) { $event_key = isset($event_key) ? $event_key : $event->Prefix_Special; if ($mode == hBEFORE) { $mode_hooks =& $this->beforeHooks; } else { $mode_hooks =& $this->afterHooks; } if (!isset($mode_hooks[strtolower($event_key.'.'.$event->Name)])) { $hooks = array(); return $hooks; } return $mode_hooks[strtolower($event_key.'.'.$event->Name)]; } /** * Enter description here... * * @param kEvent $event * @param int $mode hBEFORE or hAFTER */ function processHooks(&$event, $mode) { // * - get hooks that are valid with any special of given prefix $hooks = array_merge( // given prefix, any special $this->_getHooks($event, $mode, $event->Prefix.'.*'), // given special, given special $this->_getHooks($event, $mode), // any prefix, any special $this->_getHooks($event, $mode, '*.*'), // any prefix, given special $this->_getHooks($event, $mode, rtrim('*.' . $event->Special, '.')) ); if ($hooks) { foreach ($hooks as $hook) { if ($hook['DoSpecial'] == '*') { // use same special as master event $hook['DoSpecial'] = $event->Special; } $prefix_special = rtrim($hook['DoPrefix'].'_'.$hook['DoSpecial'], '_'); if ( $hook['Conditional'] && !$this->Application->GetVar($prefix_special) ) { continue; } if ($this->Application->prefixRegistred($hook['DoPrefix'])) { // run hook only, when it's config is found $hook_event = new kEvent( Array('name'=>$hook['DoEvent'],'prefix'=>$hook['DoPrefix'],'special'=>$hook['DoSpecial']) ); $hook_event->MasterEvent =& $event; $this->HandleEvent($hook_event); } } } } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @access public */ function setEvent($prefix_special,$event_name) { $actions =& $this->Application->recallObject('kActions'); $actions->Set('events['.$prefix_special.']',$event_name); } /** * Run registred regular events with specified event type * * @param int $event_type */ function RunRegularEvents($event_type = reBEFORE, $from_cron=false) { if (defined('IS_INSTALL')) return ; // if RegularEvents are set to run from cron if (!$from_cron && $this->Application->ConfigValue('UseCronForRegularEvent')) return ; $agents = $this->getRegularEvents(); $events_source = $agents[$event_type]; $user_id = $this->Application->RecallVar('user_id'); $this->Application->StoreVar('user_id', -1, true); // to prevent permission checking inside events, true for optional storage foreach ($events_source as $short_name => $event_data) { $next_run = $event_data['NextRunOn']; $last_run = $event_data['LastRunOn']; if ($next_run && ($next_run > adodb_mktime())) { continue; } else { $event = new kEvent($event_data['EventName']); if (!$this->Application->prefixRegistred($event->Prefix)) { // don't process agents, left from disabled modules continue; } $start_time = adodb_mktime(); $fields_hash = Array ( 'LastRunOn' => $start_time, 'LastRunStatus' => AGENT_LAST_RUN_RUNNING, 'NextRunOn' => $start_time + $event_data['RunInterval'], ); $this->Conn->doUpdate( $fields_hash, $this->Application->getUnitOption('agent', 'TableName'), 'AgentName = ' . $this->Conn->qstr($short_name) ); $event->redirect = false; $this->Application->HandleEvent($event); $now = adodb_mktime(); $next_run = $event_data['RunInterval'] ? $start_time + $event_data['RunInterval'] : $now; while ($next_run < $now) { // in case event execution took longer, then RunInterval (don't use <=, because RunInterval can be 0) $next_run += $event_data['RunInterval']; } $fields_hash = Array ( 'NextRunOn' => $next_run, 'RunTime' => round(($now - $start_time) / 60), 'LastRunStatus' => $event->status == erSUCCESS ? AGENT_LAST_RUN_SUCCEDED : AGENT_LAST_RUN_FAILED, ); $this->Conn->doUpdate( $fields_hash, $this->Application->getUnitOption('agent', 'TableName'), 'AgentName = ' . $this->Conn->qstr($short_name) ); } } $this->Application->StoreVar('user_id', $user_id, true); // true for optional } /** * Allows to determine, that required event is beeing processed right now * * @param string $event_key Event name in format prefix[.special]:event_name * @return bool */ function eventRunning($event_key) { return array_search($event_key, $this->recursionStack) !== false; } } ?>