Application->recallObject('EventManager'); $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); $config_vars = Array( 'SessionTimeout', 'SessionCookieName', 'SessionReferrerCheck', 'CookieSessions', 'UseCronForRegularEvent', 'User_GuestGroup', 'User_LoggedInGroup', 'SessionTimeout', 'UseModRewrite', 'UseOutputCompression', 'OutputCompressionLevel', ); foreach ($config_vars as $var) { $this->Application->ConfigValue($var); } $cache = Array( 'Factory.Files' => $this->Application->Factory->Files, 'Factory.realClasses' => $this->Application->Factory->realClasses, 'Factory.Dependencies' => $this->Application->Factory->Dependencies, 'ConfigReader.prefixFiles' => $this->prefixFiles, 'EventManager.buildEvents' => $event_manager->buildEvents, 'EventManager.beforeRegularEvents' => $event_manager->beforeRegularEvents, 'EventManager.afterRegularEvents' => $event_manager->afterRegularEvents, 'EventManager.beforeHooks' => $event_manager->beforeHooks, 'EventManager.afterHooks' => $event_manager->afterHooks, 'TagsAggregator.data' => $aggregator->_Array, // the following caches should be reset based on admin interaction (adjusting config, enabling modules etc) 'Application.Caches.ConfigVariables' => $this->Application->Caches['ConfigVariables'], 'Application.ConfigCacheIds' => $this->Application->ConfigCacheIds, 'Application.ConfigHash' => $this->Application->ConfigHash, 'Application.ReplacementTemplates' => $this->Application->ReplacementTemplates, 'Application.ModuleInfo' => $this->Application->ModuleInfo, ); $conn =& $this->Application->GetADODBConnection(); $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("configs_parsed", '.$conn->qstr(serialize($cache)).', '.adodb_mktime().')'); $conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_files", '.$conn->qstr(serialize($this->configFiles)).', '.adodb_mktime().')'); unset($this->configFiles); } function RestoreParsedData() { $conn =& $this->Application->GetADODBConnection(); $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"'); if ($data && $data['Cached'] > 0 ) { $cache = unserialize($data['Data']); $this->Application->Factory->Files = $cache['Factory.Files']; $this->Application->Factory->realClasses = $cache['Factory.realClasses']; $this->Application->Factory->Dependencies = $cache['Factory.Dependencies']; $this->prefixFiles = $cache['ConfigReader.prefixFiles']; $event_manager =& $this->Application->recallObject('EventManager'); $event_manager->buildEvents = $cache['EventManager.buildEvents']; $event_manager->beforeRegularEvents = $cache['EventManager.beforeRegularEvents']; $event_manager->afterRegularEvents = $cache['EventManager.afterRegularEvents']; $event_manager->beforeHooks = $cache['EventManager.beforeHooks']; $event_manager->afterHooks = $cache['EventManager.afterHooks']; $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); $aggregator->_Array = $cache['TagsAggregator.data']; $this->Application->ConfigHash = $cache['Application.ConfigHash']; $this->Application->Caches['ConfigVariables'] = $cache['Application.ConfigCacheIds']; $this->Application->ConfigCacheIds = $cache['Application.ConfigCacheIds']; $this->Application->ReplacementTemplates = $cache['Application.ReplacementTemplates']; $this->Application->ModuleInfo = $cache['Application.ModuleInfo']; return true; } else return false; } function ResetParsedData($include_sections = false) { $conn =& $this->Application->GetADODBConnection(); $conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"'); if ($include_sections) { $conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"'); } } function scanModules($folderPath, $cache = true) { if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) { // disable config caching during installation $cache = false; } if ($cache) { $restored = $this->RestoreParsedData(); if ($restored) return; } $this->ProcessAllConfigs = true; $this->includeConfigFiles($folderPath, $cache); $this->ParseConfigs(); // tell AfterConfigRead to store cache if neede // can't store it here beacuse AfterConfigRead needs ability to change config data $this->StoreCache = $cache; } function findConfigFiles($folderPath) { // if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted $reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/'; $folderPath = preg_replace($reg_exp, '', $folderPath, 1); // this make sense, since $folderPath may NOT contain FULL_PATH $fh = opendir(FULL_PATH.$folderPath); while (($sub_folder = readdir($fh))) { $full_path = FULL_PATH.$folderPath.'/'.$sub_folder; if ($this->isDir($full_path)) { if (file_exists(FULL_PATH.$this->getConfigName($folderPath.'/'.$sub_folder))) { $this->configFiles[] = $this->getConfigName($folderPath.'/'.$sub_folder); } $this->findConfigFiles($full_path); // if (filemtime($full_path) > $cached) { } } } } function includeConfigFiles($folderPath, $cache = true) { $this->Application->refreshModuleInfo(); $conn =& $this->Application->GetADODBConnection(); $data = $conn->GetRow('SELECT Data, Cached FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_files"'); if ($cache && $data) { $this->configFiles = unserialize($data['Data']); shuffle($this->configFiles); $files_cached = $data['Cached']; } else { $this->findConfigFiles($folderPath); // search from base directory } foreach ($this->configFiles as $filename) { $prefix = $this->PreloadConfigFile($filename); if (!$prefix) { trigger_error('Prefix not defined in config file '.$filename, E_USER_ERROR); } } } /** * Process all read config files - called ONLY when there is no cache! * */ function ParseConfigs() { $prioritized_configs = array(); foreach ($this->configData as $prefix => $config) { if (isset($config['ConfigPriority'])) { $prioritized_configs[$prefix] = $config['ConfigPriority']; continue; } $this->parseConfig($prefix); } asort($prioritized_configs); foreach ($prioritized_configs as $prefix => $priority) { $this->parseConfig($prefix); } foreach ($this->configData as $prefix => $config) { $this->ProcessDependencies($prefix); $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix'); } } function AfterConfigRead() { // if (!$this->ProcessAllConfigs) return ; $this->FinalStage = true; foreach ($this->configData as $prefix => $config) { if (in_array($prefix, $this->AfterConfigProcessed)) continue; $this->Application->HandleEvent( new kEvent($prefix.':OnAfterConfigRead') ); $this->AfterConfigProcessed[] = $prefix; } if ($this->StoreCache) $this->CacheParsedData(); } /** * Register nessasary classes * This method should only process the data which is cached! * * @param string $prefix * @access private */ function parseConfig($prefix) { $config =& $this->configData[$prefix]; $event_manager =& $this->Application->recallObject('EventManager'); $register_classes = getArrayValue($config,'RegisterClasses'); if (!$register_classes) $register_classes = Array(); $class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass'); foreach($class_params as $param_name) { if ( !(isset($config[$param_name]) ) ) continue; $config[$param_name]['pseudo'] = $this->getPrefixByParamName($param_name,$prefix); $register_classes[] = $config[$param_name]; } foreach($register_classes as $class_info) { $require_classes = getArrayValue($class_info, 'require_classes'); if ($require_classes) { if (!is_array($require_classes)) { $require_classes = array($require_classes); } if (!isset($config['_Dependencies'][$class_info['class']])) { $config['_Dependencies'][$class_info['class']] = array(); } $config['_Dependencies'][$class_info['class']] = array_merge($config['_Dependencies'][$class_info['class']], $require_classes); } $this->Application->registerClass( $class_info['class'], $config['BasePath'].'/'.$class_info['file'], $class_info['pseudo']/*, getArrayValue($class_info, 'require_classes')*/ ); if (getArrayValue($class_info, 'build_event')) { $event_manager->registerBuildEvent($class_info['pseudo'],$class_info['build_event']); } } $regular_events = getArrayValue($config, 'RegularEvents'); if($regular_events) { foreach($regular_events as $short_name => $regular_event_info) { $event_manager->registerRegularEvent( $short_name, $config['Prefix'].':'.$regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'] ); } } $hooks = getArrayValue($config, 'Hooks'); if (is_array($hooks) && count($hooks) > 0) { foreach ($hooks as $hook) { if (isset($config['ParentPrefix']) && $hook['HookToPrefix'] == $config['ParentPrefix']) { trigger_error('Depricated Hook Usage [prefix: '.$config['Prefix'].'; do_prefix: '.$hook['DoPrefix'].'] use #PARENT# as HookToPrefix value, where HookToPrefix is same as ParentPrefix', E_USER_NOTICE); } if ($hook['HookToPrefix'] == '') { $hook['HookToPrefix'] = $config['Prefix']; // new: set hooktoprefix to current prefix if not set } if (isset($config['ParentPrefix'])) { // new: allow to set hook to parent prefix what ever it is if ($hook['HookToPrefix'] == '#PARENT#') { $hook['HookToPrefix'] = $config['ParentPrefix']; } if ($hook['DoPrefix'] == '#PARENT#') { $hook['DoPrefix'] = $config['ParentPrefix']; } } elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') { continue; // we need parent prefix but it's not set ! } $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix']; if ( !is_array($hook['HookToEvent']) ) { $hook_events = Array( $hook['HookToEvent'] ); } else { $hook_events = $hook['HookToEvent']; } foreach ($hook_events as $hook_event) { $this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']); } } } if ( is_array(getArrayValue($config, 'AggregateTags')) ) { foreach ($config['AggregateTags'] as $aggregate_tag) { if (isset($config['ParentPrefix'])) { if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) { trigger_error('Depricated Aggregate Tag Usage [prefix: '.$config['Prefix'].'; AggregateTo: '.$aggregate_tag['AggregateTo'].'] use #PARENT# as AggregateTo value, where AggregateTo is same as ParentPrefix', E_USER_NOTICE); } if ($aggregate_tag['AggregateTo'] == '#PARENT#') { $aggregate_tag['AggregateTo'] = $config['ParentPrefix']; } } $aggregate_tag['LocalPrefix'] = $config['Prefix']; $this->Application->registerAggregateTag($aggregate_tag); } } if (isset($config['ReplacementTemplates']) && $config['ReplacementTemplates']) { // replacement templates defined in this config $this->Application->ReplacementTemplates = array_merge_recursive2($this->Application->ReplacementTemplates, $config['ReplacementTemplates']); } if ( $this->Application->isDebugMode() && constOn('DBG_VALIDATE_CONFIGS') && isset($config['TableName']) ) { global $debugger; $tablename = $config['TableName']; $conn =& $this->Application->GetADODBConnection(); $res = $conn->Query("DESCRIBE $tablename"); foreach ($res as $field) { $f_name = $field['Field']; if (getArrayValue($config, 'Fields')) { if ( !array_key_exists ($f_name, $config['Fields']) ) { $debugger->appendHTML("Config Warning: Field $f_name exists in the database, but is not defined in config file for prefix ".$config['Prefix']."!"); safeDefine('DBG_RAISE_ON_WARNINGS', 1); } else { $options = $config['Fields'][$f_name]; if ($field['Null'] == '') { if ( $f_name != $config['IDField'] && !isset($options['not_null']) && !isset($options['required']) ) { $debugger->appendHTML("Config Error: Field $f_name in config for prefix ".$config['Prefix']." is NOT NULL in the database, but is not configured as not_null or required!"); safeDefine('DBG_RAISE_ON_WARNINGS', 1); } if ( isset($options['not_null']) && !isset($options['default']) ) { $debugger->appendHTML("Config Error: Field $f_name in config for prefix ".$config['Prefix']." is described as NOT NULL, but does not have DEFAULT value!"); safeDefine('DBG_RAISE_ON_WARNINGS', 1); } } } } } } } function ProcessDependencies($prefix) { $config =& $this->configData[$prefix]; $deps = getArrayValue($config, '_Dependencies'); if (!$deps) return ; foreach ($deps as $real_class => $requires) { foreach ($requires as $class) { $this->Application->registerDependency($real_class, $class); } } unset($config['_Dependencies']); } function postProcessConfig($prefix, $config_key, $dst_prefix_var) { $main_config =& $this->configData[$prefix]; $sub_configs = getArrayValue($main_config, $config_key); if (!$sub_configs) { return array(); } unset($main_config[$config_key]); $processed = array(); foreach ($sub_configs as $sub_prefix => $sub_config) { if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) { $this->loadConfig($sub_prefix); } $sub_config['Prefix'] = $sub_prefix; $this->configData[$sub_prefix] = array_merge_recursive2($this->configData[$$dst_prefix_var], $sub_config); // when merging empty array to non-empty results non-empty array, but empty is required foreach ($sub_config as $sub_key => $sub_value) { if (!$sub_value) { unset($this->configData[$sub_prefix][$sub_key]); } } if ($config_key == 'Clones') { $this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix]; } $this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var); if ($config_key == 'AggregateConfigs') { $processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed); } elseif ($this->ProcessAllConfigs) { $this->parseConfig($sub_prefix); } array_push($processed, $sub_prefix); } if (!$prefix) { // configs, that used only for cloning & not used ifself unset($this->configData[$prefix]); } return array_unique($processed); } function PreloadConfigFile($filename) { $config_found = file_exists(FULL_PATH.$filename) && $this->configAllowed($filename); if( defined('DEBUG_MODE') && DEBUG_MODE && constOn('DBG_PROFILE_INCLUDES') ) { if ( in_array($filename, get_required_files()) ) return; global $debugger; if($config_found) { $file = FULL_PATH.$filename; $debugger->ProfileStart('inc_'.crc32($file), $file); include_once($file); $debugger->ProfileFinish('inc_'.crc32($file)); $debugger->profilerAddTotal('includes', 'inc_'.crc32($file)); } } else { if ($config_found) include_once(FULL_PATH.$filename); } if ($config_found) { if (isset($config) && $config) { // config file is included for 1st time -> save it's content for future processing $prefix = isset($config['Prefix']) ? $config['Prefix'] : ''; preg_match('/\/(.*)\//U', $filename, $rets); $config['ModuleFolder'] = $rets[1]; $config['BasePath'] = dirname(FULL_PATH.$filename); if (isset($config['AdminTemplatePath'])) { // append template base folder for admin templates path of this prefix $module_templates = $rets[1] == 'kernel' ? '' : $rets[1].'/'; $config['AdminTemplatePath'] = $module_templates.$config['AdminTemplatePath']; } $this->configData[$prefix] = $config; $this->prefixFiles[$prefix] = $filename; return $prefix; } elseif ($prefix = array_search($filename, $this->prefixFiles)) { // attempt is made to include config file twice or more, but include_once prevents that, // but file exists on hdd, then it is already saved to all required arrays, just return it's prefix return $prefix; } } return 'dummy'; } function loadConfig($prefix) { if (!isset($this->prefixFiles[$prefix])) { if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace(); trigger_error('Configuration file for prefix '.$prefix.' is unknown', E_USER_ERROR); return ; } $file = $this->prefixFiles[$prefix]; $prefix = $this->PreloadConfigFile($file); $clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones); if ($this->FinalStage) { array_unshift($clones, $prefix); $clones = array_unique($clones); foreach ($clones as $a_prefix) { $this->Application->HandleEvent( new kEvent($a_prefix.':OnAfterConfigRead') ); } } } /** * Reads unit (specified by $prefix) * option specified by $option * * @param string $prefix * @param string $name * @param mixed $default * @return string * @access public */ function getUnitOption($prefix, $name, $default = false) { if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) { if (!isset($this->configData[$rets[1]])) { $this->loadConfig($rets[1]); } $ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false; // $ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]); } else { if (!isset($this->configData[$prefix])) { $this->loadConfig($prefix); } $ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false; // $ret = getArrayValue($this->configData, $prefix, $name); } return $ret === false ? $default : $ret; } /** * Read all unit with $prefix options * * @param string $prefix * @return Array * @access public */ function getUnitOptions($prefix) { if (!isset($this->configData[$prefix])) { $this->loadConfig($prefix); } return $this->configData[$prefix]; } /** * Set's new unit option value * * @param string $prefix * @param string $name * @param string $value * @access public */ function setUnitOption($prefix, $name, $value) { if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) { if (!isset($this->configData[$rets[1]])) { $this->loadConfig($rets[1]); } $this->configData[$rets[1]][$name][$rets[2]] = $value; } else { if (!isset($this->configData[$prefix])) { $this->loadConfig($prefix); } $this->configData[$prefix][$name] = $value; } } function getPrefixByParamName($paramName,$prefix) { $pseudo_class_map=Array( 'ItemClass'=>'%s', 'ListClass'=>'%s_List', 'EventHandlerClass'=>'%s_EventHandler', 'TagProcessorClass'=>'%s_TagProcessor' ); return sprintf($pseudo_class_map[$paramName],$prefix); } /** * Get's config file name based * on folder name supplied * * @param string $folderPath * @return string * @access private */ function getConfigName($folderPath) { return $folderPath.'/'.basename($folderPath).'_config.php'; } /** * is_dir ajustment to work with * directory listings too * * @param string $folderPath * @return bool * @access private */ function isDir($folderPath) { $base_name = basename($folderPath); $ret = !( $base_name == '.' || $base_name == '..' ); return $ret && is_dir($folderPath); } /** * Checks if config file is allowed for includion (if module of config is installed) * * @param string $config_path relative path from in-portal directory */ function configAllowed($config_path) { if (defined('IS_INSTALL') && IS_INSTALL) { // at installation start no modules in db and kernel configs could not be read return true; } $module_found = false; if (!$this->Application->ModuleInfo) return false; if (preg_match('/\/plugins\//', $config_path)) return true; if (preg_match('/\/core\//', $config_path)) return true; foreach($this->Application->ModuleInfo as $module_name => $module_info) { $module_path = '/'.$module_info['Path']; if (preg_match('/^'.preg_quote($module_path, '/').'/', $config_path)) { // if (substr($config_path, 0, strlen($module_path)) == $module_path) { // config file path starts with module folder path $module_found = true; break; } } return $module_found; } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ function prefixRegistred($prefix) { return isset($this->prefixFiles[$prefix]) ? true : false; } } ?>