Index: branches/5.0.x/core/kernel/utility/unit_config_reader.php =================================================================== --- branches/5.0.x/core/kernel/utility/unit_config_reader.php (revision 13241) +++ branches/5.0.x/core/kernel/utility/unit_config_reader.php (revision 13242) @@ -1,992 +1,992 @@ <?php /** * @version $Id$ * @package In-Portal * @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved. * @license GNU/GPL * In-Portal is Open Source software. * This means that this software may have been modified pursuant * the GNU General Public License, and as distributed it includes * or is derivative of works licensed under the GNU General Public License * or other free or open source software licenses. * See http://www.in-portal.org/license for copyright notices and details. */ defined('FULL_PATH') or die('restricted access!'); class kUnitConfigReader extends kBase { /** * Configs readed * * @var Array * @access private */ var $configData = Array(); var $configFiles = Array(); var $CacheExpired = false; var $prefixFiles = array(); var $ProcessAllConfigs = false; var $FinalStage = false; var $StoreCache = false; var $AfterConfigProcessed = array(); /** * Escaped directory separator for using in regular expressions * * @var string */ var $_directorySeparator = ''; /** * Folders to skip during unit config search * * @var Array */ var $_skipFolders = Array ('CVS', '.svn', 'admin_templates', 'libchart'); /** * Scan kernel and user classes * for available configs * * @access protected */ function Init($prefix,$special) { parent::Init($prefix,$special); $this->_directorySeparator = preg_quote( DIRECTORY_SEPARATOR ); $this->_skipFolders[] = trim(WRITEBALE_BASE, '/'); // system folder (where web server can write) $editor_path = explode('/', trim(EDITOR_PATH, '/')); $this->_skipFolders[] = array_pop($editor_path); // last of cmseditor folders } function CacheParsedData() { $event_manager =& $this->Application->recallObject('EventManager'); $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); $config_vars = Array ( 'SessionTimeout', 'SessionCookieName', 'SessionBrowserSignatureCheck', 'SessionIPAddressCheck', 'CookieSessions', 'UseCronForRegularEvent', 'User_GuestGroup', 'User_LoggedInGroup', 'SessionTimeout', 'UseModRewrite', 'UseOutputCompression', 'OutputCompressionLevel', 'KeepSessionOnBrowserClose', 'Config_Server_Time', 'Config_Site_Time', 'UseChangeLog', 'UseVisitorTracking', ); 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.RewriteListeners' => $this->Application->RewriteListeners, 'Application.ModuleInfo' => $this->Application->ModuleInfo, ); $conn =& $this->Application->GetADODBConnection(); if (isset($this->Application->Memcached)) { $this->Application->Memcached->set('master:configs_parsed', serialize($cache)); $this->Application->Memcached->set('master:config_files', serialize($this->configFiles)); } else { $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().')'); } $cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s'); $conn->Query('REPLACE ' . TABLE_PREFIX . 'Cache (VarName, Data, Cached) VALUES ("last_cache_rebuild", ' . $conn->qstr($cache_rebuild_by) . ', ' . adodb_mktime() . ')'); unset($this->configFiles); } function RestoreParsedData() { $conn =& $this->Application->GetADODBConnection(); if (!isset($this->Application->Memcached) || !($data = $this->Application->Memcached->get('master:configs_parsed'))) { $data = $conn->GetOne('SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"'); } if ($data) { $cache = unserialize($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->RewriteListeners = $cache['Application.RewriteListeners']; $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 (isset($this->Application->Memcached)) { $this->Application->Memcached->delete('master:configs_parsed'); } if ($include_sections) { $conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"'); if (isset($this->Application->Memcached)) { $this->Application->Memcached->delete('master: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, $level = 0) { /*if ($level == 0) { if ($this->Application->isDebugMode()) { $start_time = getmicrotime(); $this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . $folderPath . '")'); $this->Application->Debugger->appendTrace(); } }*/ // 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 $base_folder = FULL_PATH . $folderPath . DIRECTORY_SEPARATOR; $sub_folders = glob($base_folder . '*', GLOB_ONLYDIR); if (!$sub_folders) { return ; } if ($level == 0) { // don't scan Front-End themes because of extensive directory structure $sub_folders = array_diff($sub_folders, Array ($base_folder . 'themes', $base_folder . 'tools')); } foreach ($sub_folders as $full_path) { $sub_folder = substr($full_path, strlen($base_folder)); if (in_array($sub_folder, $this->_skipFolders)) { continue; } if (preg_match('/^\./', $sub_folder)) { // don't scan ".folders" continue; } $config_name = $this->getConfigName($folderPath . DIRECTORY_SEPARATOR . $sub_folder); if (file_exists(FULL_PATH . $config_name)) { $this->configFiles[] = $config_name; } $this->findConfigFiles($full_path, $level + 1); } /*if ($level == 0) { if ($this->Application->isDebugMode()) { $this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . FULL_PATH . $folderPath . '"): ' . (getmicrotime() - $start_time)); } }*/ } function includeConfigFiles($folderPath, $cache = true) { $this->Application->refreshModuleInfo(); $conn =& $this->Application->GetADODBConnection(); if (!isset($this->Application->Memcached) || !($data = $this->Application->Memcached->get('master:config_files'))) { $data = $conn->GetOne('SELECT Data FROM ' . TABLE_PREFIX . 'Cache WHERE VarName = "config_files"'); } if ($cache && $data) { $this->configFiles = unserialize($data); shuffle($this->configFiles); } 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() { // 1. process normal configs and their dependencies $prioritized_configs = array(); foreach ($this->configData as $prefix => $config) { if (isset($config['ConfigPriority'])) { $prioritized_configs[$prefix] = $config['ConfigPriority']; continue; } $this->parseConfig($prefix); } foreach ($this->configData as $prefix => $config) { $this->ProcessDependencies($prefix); $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix'); } // 2. process prioritized configs and their dependencies asort($prioritized_configs); foreach ($prioritized_configs as $prefix => $priority) { $this->parseConfig($prefix); } foreach ($prioritized_configs as $prefix => $priority) { $this->ProcessDependencies($prefix); } } function AfterConfigRead($store_cache = null) { // 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 (!isset($store_cache)) { // store cache not overrided -> use global setting $store_cache = $this->StoreCache; } if ($store_cache || (defined('IS_INSTALL') && IS_INSTALL)) { // cache is not stored during install, but dynamic clones should be processed in any case $this->processDynamicClones(); $this->retrieveCollections(); } if ($store_cache) { $this->_sortRewriteListeners(); $this->CacheParsedData(); if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) { // validate configs here to have changes from OnAfterConfigRead hooks to prefixes foreach ($this->configData as $prefix => $config) { if (!isset($config['TableName'])) continue; $this->ValidateConfig($prefix); } } $after_event = new kEvent('adm:OnAfterCacheRebuild'); $this->Application->HandleEvent($after_event); } } /** * Sort rewrite listeners according to RewritePriority (non-prioritized listeners goes first) * */ function _sortRewriteListeners() { $listeners = Array (); $prioritized_listeners = Array (); // process non-prioritized listeners foreach ($this->Application->RewriteListeners as $prefix => $listener_data) { if ($listener_data['priority'] === false) { $listeners[$prefix] = $listener_data; } else { $prioritized_listeners[$prefix] = $listener_data['priority']; } } // process prioritized listeners - asort($prioritized_listeners); + asort($prioritized_listeners, SORT_NUMERIC); foreach ($prioritized_listeners as $prefix => $priority) { $listeners[$prefix] = $this->Application->RewriteListeners[$prefix]; } $this->Application->RewriteListeners = $listeners; } /** * Re-reads all configs * */ function ReReadConfigs() { // clear restored cache (not in db) $this->Application->Factory->Files = Array (); $this->Application->Factory->realClasses = Array (); $this->Application->Factory->Dependencies = Array (); $this->Application->EventManager->beforeRegularEvents = Array (); $this->Application->EventManager->afterRegularEvents = Array (); $this->Application->EventManager->beforeHooks = Array (); $this->Application->EventManager->afterHooks = Array (); // otherwise ModulesHelper indirectly used from includeConfigFiles won't work $this->Application->RegisterDefaultClasses(); // parse all configs $this->ProcessAllConfigs = true; $this->includeConfigFiles(MODULES_PATH, false); $this->ParseConfigs(); $this->AfterConfigRead(false); $this->processDynamicClones(); $this->retrieveCollections(); } /** * Process clones, that were defined via OnAfterConfigRead event * */ function processDynamicClones() { $new_clones = Array(); foreach ($this->configData as $prefix => $config) { $clones = $this->postProcessConfig($prefix, 'Clones', 'prefix'); if ($clones) { $new_clones = array_merge($new_clones, $clones); } } // call OnAfterConfigRead for cloned configs $new_clones = array_unique($new_clones); foreach ($new_clones as $prefix) { if (in_array($prefix, $this->AfterConfigProcessed)) { continue; } $this->Application->HandleEvent( new kEvent($prefix.':OnAfterConfigRead') ); $this->AfterConfigProcessed[] = $prefix; } } /** * Process all collectable unit config options here to also catch ones, defined from OnAfterConfigRead events * */ function retrieveCollections() { foreach ($this->configData as $prefix => $config) { // collect replacement templates if (array_key_exists('ReplacementTemplates', $config) && $config['ReplacementTemplates']) { $this->Application->ReplacementTemplates = array_merge($this->Application->ReplacementTemplates, $config['ReplacementTemplates']); } // collect rewrite listeners if (array_key_exists('RewriteListener', $config) && $config['RewriteListener']) { $rewrite_listener = $config['RewriteListener']; if (strpos($rewrite_listener, ':') === false) { $rewrite_listener = $prefix . '_EventHandler:' . $rewrite_listener; } $rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false; $this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listener, 'priority' => $rewrite_priority); } } } /** * 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'); /* @var $event_manager kEventManager */ $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'] . DIRECTORY_SEPARATOR . $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_status = array_key_exists('Status', $regular_event_info) ? $regular_event_info['Status'] : STATUS_ACTIVE; $event_manager->registerRegularEvent( $short_name, $config['Prefix'].':'.$regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'], $event_status); } } $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: <b>'.$config['Prefix'].'</b>; do_prefix: <b>'.$hook['DoPrefix'].'</b>] use <b>#PARENT#</b> as <b>HookToPrefix</b> 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: <b>'.$config['Prefix'].'</b>; AggregateTo: <b>'.$aggregate_tag['AggregateTo'].'</b>] use <b>#PARENT#</b> as <b>AggregateTo</b> 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); } } } function ValidateConfig($prefix) { global $debugger; $config =& $this->configData[$prefix]; $tablename = $config['TableName']; $float_types = Array ('float', 'double', 'numeric'); $conn =& $this->Application->GetADODBConnection(); $table_found = $conn->Query('SHOW TABLES LIKE "'.$tablename.'"'); if (!$table_found) { // config present, but table missing, strange $debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Table <strong>$tablename</strong> missing, but prefix <b>".$config['Prefix']."</b> requires it!"); safeDefine('DBG_RAISE_ON_WARNINGS', 1); return ; } $res = $conn->Query('DESCRIBE '.$tablename); $config_link = $debugger->getFileLink(FULL_PATH.$this->prefixFiles[$config['Prefix']], 1, $config['Prefix']); $error_messages = Array ( 'field_not_found' => 'Field <strong>%s</strong> exists in the database, but <strong>is not defined</strong> in config', 'default_missing' => 'Default value for field <strong>%s</strong> not set in config', 'not_null_error1' => 'Field <strong>%s</strong> is NOT NULL in the database, but is not configured as not_null', // or required', 'not_null_error2' => 'Field <strong>%s</strong> is described as NOT NULL in config, but <strong>does not have DEFAULT value</strong>', 'not_null_error3' => 'Field <strong>%s</strong> is described as <strong>NOT NULL in config</strong>, but is <strong>NULL in db</strong>', 'invalid_default' => '<strong>Default value</strong> for field %s<strong>%s</strong> not sync. to db (in config = %s, in db = %s)', 'type_missing' => '<strong>Type definition</strong> for field <strong>%s</strong> missing in config', ); $config_errors = Array (); $tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix foreach ($res as $field) { $f_name = $field['Field']; if (getArrayValue($config, 'Fields')) { if (preg_match('/l[\d]+_[\w]/', $f_name)) { // skip multilingual fields continue; } if (!array_key_exists ($f_name, $config['Fields'])) { $config_errors[] = sprintf($error_messages['field_not_found'], $f_name); } else { if (is_numeric($field['Default'])) { $field['Default'] = preg_match('/[\.,]/', $field['Default']) ? (float)$field['Default'] : (int)$field['Default']; } $options = $config['Fields'][$f_name]; $default_missing = false; if (!array_key_exists('default', $options)) { $config_errors[] = sprintf($error_messages['default_missing'], $f_name); $default_missing = true; } if ($field['Null'] != 'YES') { // field is NOT NULL in database (MySQL5 for null returns "NO", but MySQL4 returns "") if ( $f_name != $config['IDField'] && !isset($options['not_null']) /*&& !isset($options['required'])*/ ) { $config_errors[] = sprintf($error_messages['not_null_error1'], $f_name); } if (isset($options['not_null']) && $options['not_null'] && !isset($options['default']) ) { $config_errors[] = sprintf($error_messages['not_null_error2'], $f_name); } } else { if (isset($options['not_null']) && $options['not_null']) { $config_errors[] = sprintf($error_messages['not_null_error3'], $f_name); } } if (!array_key_exists('type', $options)) { $config_errors[] = sprintf($error_messages['type_missing'], $f_name); } if (!$default_missing) { if ($f_name == $config['IDField'] && $options['type'] != 'string' && $options['default'] !== 0) { $config_errors[] = sprintf($error_messages['invalid_default'], '<span class="debug_error">IDField</span> ', $f_name, $this->varDump($options['default']), $this->varDump($field['Default'])); } else if ($options['default'] != '#NOW#' && $field['Default'] !== $options['default'] && !in_array($options['type'], $float_types)) { $config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($field['Default'])); } } } } } if ($config_errors) { $error_prefix = '<strong class="debug_error">Config Error'.(count($config_errors) > 1 ? 's' : '').': </strong> for prefix <strong>'.$config_link.'</strong> ('.$tablename.') in unit config:<br />'; $config_errors = $error_prefix.' '.implode('<br /> ', $config_errors); $debugger->appendHTML($config_errors); safeDefine('DBG_RAISE_ON_WARNINGS', 1); } } function varDump($value) { return '<strong>'.var_export($value, true).'</strong> of '.gettype($value); } 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 = isset($main_config[$config_key]) && $main_config[$config_key] ? $main_config[$config_key] : false; // 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 && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES) { if ( in_array($filename, get_required_files()) ) { return; } global $debugger; if ($config_found) { $file = FULL_PATH . $filename; $file_crc = crc32($file); $debugger->ProfileStart('inc_' . $file_crc, $file); include_once($file); $debugger->ProfileFinish('inc_' . $file_crc); $debugger->profilerAddTotal('includes', 'inc_' . $file_crc); } } elseif ($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 = array_key_exists('Prefix', $config) ? $config['Prefix'] : ''; preg_match('#' . $this->_directorySeparator . '(.*)' . $this->_directorySeparator . '#U', $filename, $rets); $config['ModuleFolder'] = $rets[1]; $config['BasePath'] = dirname(FULL_PATH . $filename); if (array_key_exists('AdminTemplatePath', $config)) { // append template base folder for admin templates path of this prefix $module_templates = $rets[1] == 'core' ? '' : $rets[1] . '/'; $config['AdminTemplatePath'] = $module_templates . $config['AdminTemplatePath']; } if (array_key_exists($prefix, $this->prefixFiles) && ($this->prefixFiles[$prefix] != $filename)) { trigger_error( 'Single unit config prefix "<strong>' . $prefix . '</strong>" ' . 'is used in multiple unit config files: ' . '"<strong>' . $this->prefixFiles[$prefix] . '</strong>", "<strong>' . $filename . '</strong>"', E_USER_WARNING ); } $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 <b>'.$prefix.'</b> 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 . DIRECTORY_SEPARATOR . basename($folderPath) . '_config.php'; } /** * 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; } if (preg_match('#' . $this->_directorySeparator . 'plugins' . $this->_directorySeparator . '|' . $this->_directorySeparator . 'core#', $config_path)) { // always allow to include configs from core and plugins folder return true; } $module_found = false; if (!$this->Application->ModuleInfo) { return false; } foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $module_path = DIRECTORY_SEPARATOR . trim($module_info['Path'], '/') . DIRECTORY_SEPARATOR; // config file path starts with module folder path if (substr($config_path, 0, strlen($module_path)) == $module_path) { // if (preg_match('#^' . preg_quote($module_path, '/') . '#', $config_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; } /** * Returns config file for given prefix * * @param string $prefix * @return string */ function getPrefixFile($prefix) { return array_key_exists($prefix, $this->prefixFiles) ? $this->prefixFiles[$prefix] : false; } function iterateConfigs($callback_function, $params) { $this->includeConfigFiles(MODULES_PATH); //make sure to re-read all configs $this->AfterConfigRead(); foreach ($this->configData as $prefix => $config_data) { $callback_function[0]->$callback_function[1]($prefix, $config_data, $params); } } } \ No newline at end of file Index: branches/5.0.x/core/kernel/application.php =================================================================== --- branches/5.0.x/core/kernel/application.php (revision 13241) +++ branches/5.0.x/core/kernel/application.php (revision 13242) @@ -1,3012 +1,3012 @@ <?php /** * @version $Id$ * @package In-Portal * @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved. * @license GNU/GPL * In-Portal is Open Source software. * This means that this software may have been modified pursuant * the GNU General Public License, and as distributed it includes * or is derivative of works licensed under the GNU General Public License * or other free or open source software licenses. * See http://www.in-portal.org/license for copyright notices and details. */ /** * Basic class for Kernel4-based Application * * This class is a Facade for any other class which needs to deal with Kernel4 framework.<br> * The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br> * <br> * The class is a singleton, which means that there could be only one instance of kApplication in the script.<br> * This could be guranteed by NOT calling the class constuctor directly, but rather calling kApplication::Instance() method, * which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br> * See singleton pattern by GOF. * @package kernel4 */ defined('FULL_PATH') or die('restricted access!'); class kApplication { /** * Is true, when Init method was called already, prevents double initialization * * @var bool */ var $InitDone = false; /** * Holds internal NParser object * @access private * @var NParser */ var $Parser; /** * Holds parser output buffer * @access private * @var string */ var $HTML; /** * Prevents request from beeing proceeded twice in case if application init is called mere then one time * * @var bool * @todo This is not good anyway (by Alex) */ var $RequestProcessed = false; /** * The main Factory used to create * almost any class of kernel and * modules * * @access private * @var kFactory */ var $Factory; /** * All ConfigurationValues table content (hash) here * * @var Array * @access private */ var $ConfigHash = Array(); /** * Ids of config variables used in current run (for caching) * * @var Array * @access private */ var $ConfigCacheIds = array(); /** * Template names, that will be used instead of regular templates * * @var Array */ var $ReplacementTemplates = Array (); /** * Mod-Rewrite listeners used during url building and parsing * * @var Array */ var $RewriteListeners = Array (); /** * Reference to debugger * * @var Debugger */ var $Debugger = null; /** * Holds all phrases used * in code and template * * @var PhrasesCache */ var $Phrases; /** * Modules table content, key - module name * * @var Array */ var $ModuleInfo = Array(); /** * Holds DBConnection * * @var kDBConnection */ var $Conn = null; /** * Maintains list of user-defined error handlers * * @var Array */ var $errorHandlers = Array(); // performance needs: /** * Holds a refererence to httpquery * * @var kHttpQuery */ var $HttpQuery = null; /** * Holds a reference to UnitConfigReader * * @var kUnitConfigReader */ var $UnitConfigReader = null; /** * Holds a reference to Session * * @var Session */ var $Session = null; /** * Holds a ref to kEventManager * * @var kEventManager */ var $EventManager = null; /** * Ref to itself, needed because everybody used to write $this->Application, even inside kApplication * * @var kApplication */ var $Application = null; /** * Ref for TemplatesChache * * @var TemplatesCache */ var $TemplatesCache = null; /** * Physical template name mapping to their template names based on structure * * @var Array */ var $structureTemplateMapping = Array (); var $CompilationCache = array(); //used when compiling templates var $CachedProcessors = array(); //used when running compiled templates var $LambdaElements = 1; // for autonumbering unnamed RenderElements [any better place for this prop? KT] /** * Holds current NParser tag while parsing, can be used in error messages to display template file and line * * @var _BlockTag */ var $CurrentNTag = null; /** * Memcache object pointer * * @var Memcache */ var $Memcached = null; /** * Tells, that administrator has authentificated in administrative console * Should be used to manipulate data change OR data restrictioning! * * @var bool */ var $isAdminUser = false; /** * Tells, that admin version of "index.php" was used, nothing more! * Should be used to manipulate data display! * * @var bool */ var $isAdmin = false; /** * Returns kApplication instance anywhere in the script. * * This method should be used to get single kApplication object instance anywhere in the * Kernel-based application. The method is guranteed to return the SAME instance of kApplication. * Anywhere in the script you could write: * <code> * $application =& kApplication::Instance(); * </code> * or in an object: * <code> * $this->Application =& kApplication::Instance(); * </code> * to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class. * To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant * BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would * create and return default KernelApplication instance. * @static * @access public * @return kApplication */ function &Instance() { static $instance = false; if (!$instance) { $class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication'; $instance = new $class(); $instance->Application =& $instance; } return $instance; } function InitMemcached() { return ; $memcached_servers = 'localhost:11211'; // $this->Application->ConfigValue('MemcachedServers'); if ($memcached_servers && class_exists('Memcache')) { $this->Memcached = new Memcache(); $servers = explode(';', $memcached_servers); foreach ($servers as $server) { list ($server, $port) = strpos($server, ':') !== false ? explode(':', $server, 2) : Array ($server, 11211); $this->Memcached->addServer($server, $port); } } //try to set something to cache, if not working - set $this->Memcached to null } function CacheSet($name, $value, $expiration) { if (isset($this->Memcached)) { return $this->Memcached->set($name, $value, 0, $expiration); } return false; } function CacheGet($name) { if (isset($this->Memcached)) { return $this->Memcached->get($name); } return false; } /** * Initializes the Application * * @access public * @see kHTTPQuery * @see Session * @see TemplatesCache * @return bool Was Init actually made now or before */ function Init() { if($this->InitDone) { return false; } $this->isAdmin = constOn('ADMIN'); $this->InitMemcached(); if (!constOn('SKIP_OUT_COMPRESSION')) { ob_start(); // collect any output from method (other then tags) into buffer } if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Init:'); } if (!$this->isDebugMode() && !constOn('DBG_ZEND_PRESENT')) { error_reporting(0); ini_set('display_errors', 0); } if (!constOn('DBG_ZEND_PRESENT')) { $error_handler = set_error_handler( Array (&$this, 'handleError') ); if ($error_handler) { // wrap around previous error handler, if any was set $this->errorHandlers[] = $error_handler; } } $this->Conn = new kDBConnection(SQL_TYPE, Array(&$this, 'handleSQLError') ); $this->Conn->debugMode = $this->isDebugMode(); $this->Conn->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB); $this->Factory = new kFactory(); $this->registerDefaultClasses(); $this->Phrases = new PhrasesCache(); $this->EventManager =& $this->Factory->makeClass('EventManager'); $this->Factory->Storage['EventManager'] =& $this->EventManager; $this->RegisterDefaultBuildEvents(); $this->SetDefaultConstants(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Before UnitConfigReader'); } $this->UnitConfigReader =& $this->recallObject('kUnitConfigReader'); $this->UnitConfigReader->scanModules(MODULES_PATH); $this->registerModuleConstants(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('After UnitConfigReader'); } define('MOD_REWRITE', $this->ConfigValue('UseModRewrite') && !$this->isAdmin ? 1 : 0); $this->HttpQuery =& $this->recallObject('HTTPQuery'); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed HTTPQuery initial'); } $this->Session =& $this->recallObject('Session'); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed Session'); } if (!$this->RecallVar('UserGroups')) { $user_groups = trim($this->Session->GetField('GroupList'), ','); if (!$user_groups) { $user_groups = $this->ConfigValue('User_GuestGroup'); } $this->Session->SetField('GroupList', $user_groups); $this->StoreVar('UserGroups', $user_groups, true); // true for optional } $this->LoadStructureTemplateMapping(); $this->HttpQuery->AfterInit(); $this->Session->ValidateExpired(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); } $this->LoadCache(); $this->InitConfig(); $this->Phrases->Init('phrases'); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Loaded cache and phrases'); } $this->ValidateLogin(); $this->UnitConfigReader->AfterConfigRead(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed AfterConfigRead'); } /*// Module items are recalled during url parsing & PhrasesCache is needed already there, // because it's used in their build events. That's why phrases cache initialization is // called from kHTTPQuery in case when mod_rewrite is used if (!$this->RewriteURLs()) { $this->Phrases = new PhrasesCache(); }*/ if ($this->GetVar('m_cat_id') === false) $this->SetVar('m_cat_id', 0); if (!$this->RecallVar('curr_iso')) { $this->StoreVar('curr_iso', $this->GetPrimaryCurrency(), true); // true for optional } $this->SetVar('visits_id', $this->RecallVar('visit_id') ); $language =& $this->recallObject( 'lang.current', null, Array('live_table' => true) ); if (preg_match('/utf-8/', $language->GetDBField('Charset'))) { setlocale(LC_ALL, 'en_US.UTF-8'); mb_internal_encoding('UTF-8'); } if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->profileFinish('kernel4_startup'); } $this->InitDone = true; $this->HandleEvent( new kEvent('adm:OnStartup') ); return true; } /** * Returns module information. Searches module by requested field * * @param string $field * @param mixed $value * @param string field value to returns, if not specified, then return all fields * @param string field to return * @return Array */ function findModule($field, $value, $return_field = null) { $found = false; foreach ($this->ModuleInfo as $module_name => $module_info) { if (strtolower($module_info[$field]) == strtolower($value)) { $found = true; break; } } if ($found) { return isset($return_field) ? $module_info[$return_field] : $module_info; } return false; } function refreshModuleInfo() { if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules')) { $this->registerModuleConstants(); return false; } $modules_helper =& $this->recallObject('ModulesHelper'); /* @var $modules_helper kModulesHelper */ $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'Modules WHERE Loaded = 1 ORDER BY LoadOrder'; $this->ModuleInfo = $this->Conn->Query($sql, 'Name'); $sql = 'SELECT * FROM '.TABLE_PREFIX.'Modules WHERE '.$modules_helper->getWhereClause().' ORDER BY LoadOrder'; $this->ModuleInfo = $this->Conn->Query($sql, 'Name'); $this->registerModuleConstants(); } /** * Checks if passed language id if valid and sets it to primary otherwise * */ function VerifyLanguageId() { $language_id = $this->GetVar('m_lang'); if (!$language_id) { $language_id = 'default'; } $this->SetVar('lang.current_id', $language_id ); $this->SetVar('m_lang', $language_id ); $lang_mode = $this->GetVar('lang_mode'); $this->SetVar('lang_mode', ''); $lang =& $this->recallObject('lang.current'); /* @var $lang kDBItem */ if (!$lang->isLoaded() || (!$this->isAdmin && !$lang->GetDBField('Enabled'))) { if (!defined('IS_INSTALL')) { $this->ApplicationDie('Unknown or disabled language'); } } $this->SetVar('lang_mode',$lang_mode); } /** * Checks if passed theme id if valid and sets it to primary otherwise * */ function VerifyThemeId() { if ($this->isAdmin) { safeDefine('THEMES_PATH', '/core/admin_templates'); return; } $path = $this->GetFrontThemePath(); if ($path === false) { $this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled'); } safeDefine('THEMES_PATH', $path); /*$theme_id = $this->GetVar('m_theme'); if (!$theme_id) { $theme_id = $this->GetDefaultThemeId(); if (!$theme_id) { if (!defined('IS_INSTALL')) $this->ApplicationDie('No Primary Theme Selected'); } } $this->SetVar('m_theme', $theme_id); $this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId $theme =& $this->recallObject('theme.current'); if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) { if (!defined('IS_INSTALL')) $this->ApplicationDie('Unknown or disabled theme'); } safeDefine('THEMES_PATH', '/themes/'.$theme->GetDBField('Name'));*/ } function GetFrontThemePath($force=0) { static $path=null; if (!$force && isset($path)) return $path; $theme_id = $this->GetVar('m_theme'); if (!$theme_id) { // $theme_id = $this->GetDefaultThemeId(1); //1 to force front-end mode! $theme_id = 'default'; } $this->SetVar('m_theme', $theme_id); $this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId $theme =& $this->recallObject('theme.current'); if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) { return false; } $path = '/themes/'.$theme->GetDBField('Name'); return $path; } function GetDefaultLanguageId($init = false) { static $language_info = null; if (!isset($language_info)) { // cache primary language info first $table = $this->getUnitOption('lang', 'TableName'); $id_field = $this->getUnitOption('lang', 'IDField'); $sql = 'SELECT ' . $id_field . ', IF(AdminInterfaceLang, "Admin", "Front") AS LanguageKey FROM ' . $table . ' WHERE (AdminInterfaceLang = 1 OR PrimaryLang = 1) AND (Enabled = 1)'; $language_info = $this->Conn->GetCol($sql, 'LanguageKey'); } $language_key = ($this->isAdmin && $init) || count($language_info) == 1 ? 'Admin' : 'Front'; if (array_key_exists($language_key, $language_info) && $language_info[$language_key] > 0) { // get from cache return $language_info[$language_key]; } $language_id = $language_info && array_key_exists($language_key, $language_info) ? $language_info[$language_key] : false; if (!$language_id && defined('IS_INSTALL') && IS_INSTALL) { $language_id = 1; } return $language_id; } function GetDefaultThemeId($force_front=0) { static $theme_id = 0; if ($theme_id > 0) { return $theme_id; } if (constOn('DBG_FORCE_THEME')) { $theme_id = DBG_FORCE_THEME; } elseif (!$force_front && $this->isAdmin) { $theme_id = 999; } else { $table = $this->getUnitOption('theme','TableName'); $id_field = $this->getUnitOption('theme','IDField'); $sql = 'SELECT '.$id_field.' FROM '.$table.' WHERE (PrimaryTheme = 1) AND (Enabled = 1)'; $theme_id = $this->Conn->GetOne($sql); } return $theme_id; } function GetPrimaryCurrency() { if ($this->isModuleEnabled('In-Commerce')) { $table = $this->getUnitOption('curr', 'TableName'); return $this->Conn->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 1'); } else { return 'USD'; } } /** * Registers default classes such as ItemController, GridController and LoginController * * Called automatically while initializing Application * @access private * @return void */ function RegisterDefaultClasses() { $this->registerClass('kTempTablesHandler', KERNEL_PATH . '/utility/temp_handler.php'); $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager'); $this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php'); $this->registerClass('kArray', KERNEL_PATH . '/utility/params.php'); $this->registerClass('Params', KERNEL_PATH . '/utility/params.php'); $this->registerClass('Params', KERNEL_PATH . '/utility/params.php', 'kActions'); $this->registerClass('kCache', KERNEL_PATH . '/utility/cache.php', 'Cache', 'Params'); $this->registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery', 'Params'); $this->registerClass('kHelper', KERNEL_PATH . '/kbase.php'); $this->registerClass('kMultipleFilter', KERNEL_PATH . '/utility/filters.php'); $this->registerClass('Session', KERNEL_PATH . '/session/session.php'); $this->registerClass('SessionStorage', KERNEL_PATH . '/session/session.php'); $this->registerClass('InpSession', KERNEL_PATH . '/session/inp_session.php', 'Session'); $this->registerClass('InpSessionStorage', KERNEL_PATH . '/session/inp_session.php', 'SessionStorage'); $this->registerClass('kTagProcessor', KERNEL_PATH . '/processors/tag_processor.php'); $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php','m_TagProcessor', 'kTagProcessor'); $this->registerClass('kDBList', KERNEL_PATH . '/db/dblist.php'); $this->registerClass('kDBItem', KERNEL_PATH . '/db/dbitem.php'); $this->registerClass('kDBEventHandler', KERNEL_PATH . '/db/db_event_handler.php'); $this->registerClass('kDBTagProcessor', KERNEL_PATH . '/db/db_tag_processor.php', null, 'kTagProcessor'); $this->registerClass('kCatDBItem', KERNEL_PATH . '/db/cat_dbitem.php'); $this->registerClass('kCatDBList', KERNEL_PATH . '/db/cat_dblist.php'); $this->registerClass('kCatDBEventHandler', KERNEL_PATH . '/db/cat_event_handler.php'); $this->registerClass('kCatDBTagProcessor', KERNEL_PATH . '/db/cat_tag_processor.php'); $this->registerClass('NParser', KERNEL_PATH . '/nparser/nparser.php'); $this->registerClass('TemplatesCache', KERNEL_PATH . '/nparser/template_cache.php', null, Array ('kHelper', 'kDBTagProcessor')); $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender', 'kHelper'); $this->registerClass('kSocket', KERNEL_PATH . '/utility/socket.php', 'Socket'); if (file_exists(MODULES_PATH . '/in-commerce/units/currencies/currency_rates.php')) { $this->registerClass('kCurrencyRates', MODULES_PATH . '/in-commerce/units/currencies/currency_rates.php'); } // do not move to config - this helper is used before configs are read $this->registerClass('kModulesHelper', KERNEL_PATH . '/../units/helpers/modules_helper.php', 'ModulesHelper'); } function RegisterDefaultBuildEvents() { $event_manager =& $this->recallObject('EventManager'); $event_manager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild'); } /** * Returns item's filename that corresponds id passed. If possible, then get it from cache * * @param string $prefix * @param int $id * @return string */ function getFilename($prefix, $id, $category_id=null) { $filename = $this->getCache('filenames', $prefix.'_'.$id); if ($filename === false) { $table = $this->getUnitOption($prefix, 'TableName'); $id_field = $this->getUnitOption($prefix, 'IDField'); if ($prefix == 'c') { if(!$id) { $this->setCache('filenames', $prefix.'_'.$id, ''); return ''; } // this allows to save 2 sql queries for each category $sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight FROM '.$table.' WHERE '.$id_field.' = '.$this->Conn->qstr($id); $category_data = $this->Conn->GetRow($sql); // only direct links to category pages work (symlinks, container pages and so on won't work) $filename = $category_data['NamedParentPath']; $this->setCache('category_templates', $id, $filename); $this->setCache('category_designs', $id, ltrim($category_data['CachedTemplate'], '/')); $this->setCache('category_tree', $id, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']); } else { $sql = 'SELECT ResourceId FROM ' . $table . ' WHERE ' . $id_field . ' = ' . $this->Conn->qstr($id); $resource_id = $this->Conn->GetOne($sql); if (is_null($category_id)) { $category_id = $this->GetVar('m_cat_id'); } $sql = 'SELECT Filename FROM ' . TABLE_PREFIX . 'CategoryItems WHERE (ItemResourceId = ' . $resource_id . ') AND (CategoryId = ' . (int)$category_id . ')'; $filename = $this->Conn->GetOne($sql); /*if (!$filename) { $sql = 'SELECT Filename FROM ' . TABLE_PREFIX . 'CategoryItems WHERE ItemResourceId = ' . $resource_id . ' AND PrimaryCat = 1'; $filename = $this->Conn->GetOne($sql); } $sql = 'SELECT Filename FROM ' . $table . ' WHERE ' . $id_field . ' = ' . $this->Conn->qstr($id); $filename = $this->Conn->GetOne($sql);*/ } $this->setCache('filenames', $prefix.'_'.$id, $filename); } return $filename; } /** * Adds new value to cache $cache_name and identified by key $key * * @param string $cache_name cache name * @param int $key key name to add to cache * @param mixed $value value of chached record */ function setCache($cache_name, $key, $value, $expiration=3600) { $cache =& $this->recallObject('Cache'); /* @var $cache kCache */ return $cache->setCache($cache_name, $key, $value, $expiration); } /** * Returns cached $key value from cache named $cache_name * * @param string $cache_name cache name * @param int $key key name from cache * @return mixed */ function getCache($cache_name, $key) { $cache =& $this->recallObject('Cache'); return $cache->getCache($cache_name, $key); } /** * Defines default constants if it's not defined before - in config.php * * @access private */ function SetDefaultConstants() // it's defined in startup.php - can be removed?? { safeDefine('SERVER_NAME', $_SERVER['HTTP_HOST']); } /** * Registers each module specific constants if any found * */ function registerModuleConstants() { if (file_exists(KERNEL_PATH.'/constants.php')) { k4_include_once(KERNEL_PATH.'/constants.php'); } if (!$this->ModuleInfo) return false; foreach($this->ModuleInfo as $module_name => $module_info) { $module_path = '/'.$module_info['Path']; $contants_file = FULL_PATH.$module_path.'constants.php'; if( file_exists($contants_file) ) k4_include_once($contants_file); } return true; } function ProcessRequest() { $event_manager =& $this->recallObject('EventManager'); /* @var $event_manager kEventManager */ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_SHOW_HTTPQUERY')) { $this->Debugger->appendHTML('HTTPQuery:'); $this->Debugger->dumpVars($this->HttpQuery->_Params); } $event_manager->ProcessRequest(); $event_manager->RunRegularEvents(reBEFORE); $this->RequestProcessed = true; } /** * Actually runs the parser against current template and stores parsing result * * This method gets t variable passed to the script, loads the template given in t variable and * parses it. The result is store in {@link $this->HTML} property. * @access public * @return void */ function Run() { if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Run:'); } if ($this->isAdminUser) { // for permission checking in events & templates $this->LinkVar('module'); // for common configuration templates $this->LinkVar('module_key'); // for common search templates $this->LinkVar('section'); // for common configuration templates if ($this->GetVar('m_opener') == 'p') { $this->LinkVar('main_prefix'); // window prefix, that opened selector $this->LinkVar('dst_field'); // field to set value choosed in selector } if ($this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax')) { // hide debug output from ajax requests automatically define('DBG_SKIP_REPORTING', 1); } } elseif ($this->GetVar('admin')) { // viewing front-end through admin's frame $admin_session =& $this->Application->recallObject('Session.admin'); $user = (int)$admin_session->RecallVar('user_id'); // in case, when no valid admin session found $perm_helper =& $this->recallObject('PermissionsHelper'); /* @var $perm_helper kPermissionsHelper */ if ($perm_helper->CheckUserPermission($user, 'CATEGORY.MODIFY', 0, $this->ModuleInfo['Core']['RootCat'])) { // user can edit cms blocks $editing_mode = $this->GetVar('editing_mode'); define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE); $this->Phrases->setPhraseEditing(); } } safeDefine('EDITING_MODE', ''); // user can't edit anything if (!$this->RequestProcessed) $this->ProcessRequest(); $this->InitParser(); $t = $this->GetVar('t'); if (!$this->TemplatesCache->TemplateExists($t) && !$this->isAdmin) { $cms_handler =& $this->recallObject('st_EventHandler'); /* @var $cms_handler CategoriesEventHandler */ $t = ltrim($cms_handler->GetDesignTemplate(), '/'); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendHTML('<strong>Design Template</strong>: ' . $t . '; <strong>CategoryID</strong>: ' . $this->GetVar('m_cat_id')); } } /*else { $cms_handler->SetCatByTemplate(); }*/ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Parsing:'); } $this->HTML = $this->Parser->Run($t); if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application after Parsing:'); } } function InitParser($theme_name = false) { if( !is_object($this->Parser) ) { $this->Parser =& $this->recallObject('NParser'); $this->TemplatesCache =& $this->recallObject('TemplatesCache'); } $this->TemplatesCache->forceThemeName = $theme_name; } /** * Send the parser results to browser * * Actually send everything stored in {@link $this->HTML}, to the browser by echoing it. * @access public * @return void */ function Done() { $this->HandleEvent( new kEvent('adm:OnBeforeShutdown') ); if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Done:'); } if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->EventManager->RunRegularEvents(reAFTER); $this->Session->SaveData(); if (constOn('DBG_CACHE')) { $cache =& $this->recallObject('Cache'); $cache->printStatistics(); } $this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true); } else { $this->HTML = ob_get_clean().$this->HTML; } if ($this->UseOutputCompression()) { header('Content-Encoding: gzip'); $compression_level = $this->ConfigValue('OutputCompressionLevel'); if ($compression_level < 0 || $compression_level > 9) $compression_level = 7; echo gzencode($this->HTML, $compression_level); } else { echo $this->HTML; } $this->UpdateCache(); flush(); if (!$this->isDebugMode()) { $this->EventManager->RunRegularEvents(reAFTER); $this->Session->SaveData(); } if (defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->isAdmin) { $this->_storeStatistics(); } } /** * Stores script execution statistics to database * */ function _storeStatistics() { global $start; $script_time = getmicrotime() - $start; $query_statistics = $this->Conn->getQueryStatistics(); // time & count $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'StatisticsCapture WHERE TemplateName = ' . $this->Conn->qstr( $this->GetVar('t') ); $data = $this->Conn->GetRow($sql); if ($data) { $this->_updateAverageStatistics($data, 'ScriptTime', $script_time); $this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']); $this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']); $data['Hits']++; $data['LastHit'] = adodb_mktime(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']); } else { $data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time; $data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time']; $data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count']; $data['TemplateName'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = adodb_mktime(); $this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture'); } } /** * Calculates average time for statistics * * @param Array $data * @param string $field_prefix * @param float $current_value */ function _updateAverageStatistics(&$data, $field_prefix, $current_value) { $data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1); if ($current_value < $data[$field_prefix . 'Min']) { $data[$field_prefix . 'Min'] = $current_value; } if ($current_value > $data[$field_prefix . 'Max']) { $data[$field_prefix . 'Max'] = $current_value; } } function logSlowQuery($slow_sql, $time) { $query_crc = crc32($slow_sql); $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SlowSqlCapture WHERE QueryCrc = ' . $query_crc; $data = $this->Conn->Query($sql, null, true); if ($data) { $this->_updateAverageStatistics($data, 'Time', $time); $template_names = explode(',', $data['TemplateNames']); array_push($template_names, $this->GetVar('t')); $data['TemplateNames'] = implode(',', array_unique($template_names)); $data['Hits']++; $data['LastHit'] = adodb_mktime(); $this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']); } else { $data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time; $data['SqlQuery'] = $slow_sql; $data['QueryCrc'] = $query_crc; $data['TemplateNames'] = $this->GetVar('t'); $data['Hits'] = 1; $data['LastHit'] = adodb_mktime(); $this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture'); } } /** * Checks if output compression options is available * * @return string */ function UseOutputCompression() { if (constOn('IS_INSTALL') || constOn('DBG_ZEND_PRESENT') || constOn('SKIP_OUT_COMPRESSION')) return false; return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip'); } // Facade /** * Returns current session id (SID) * @access public * @return longint */ function GetSID() { $session =& $this->recallObject('Session'); return $session->GetID(); } function DestroySession() { $session =& $this->recallObject('Session'); $session->Destroy(); } /** * Returns variable passed to the script as GET/POST/COOKIE * * @access public * @param string $name Name of variable to retrieve * @param int $default default value returned in case if varible not present * @return mixed */ function GetVar($name, $default = false) { return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default; } /** * Returns ALL variables passed to the script as GET/POST/COOKIE * * @access public * @return array */ function GetVars() { return $this->HttpQuery->GetParams(); } /** * Set the variable 'as it was passed to the script through GET/POST/COOKIE' * * This could be useful to set the variable when you know that * other objects would relay on variable passed from GET/POST/COOKIE * or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br> * * This method is formerly known as $this->Session->SetProperty. * @param string $var Variable name to set * @param mixed $val Variable value * @access public * @return void */ function SetVar($var,$val) { return $this->HttpQuery->Set($var, $val); } /** * Deletes kHTTPQuery variable * * @param string $var * @todo think about method name */ function DeleteVar($var) { return $this->HttpQuery->Remove($var); } /** * Deletes Session variable * * @param string $var */ function RemoveVar($var) { return $this->Session->RemoveVar($var); } function RemovePersistentVar($var) { return $this->Session->RemovePersistentVar($var); } /** * Restores Session variable to it's db version * * @param string $var */ function RestoreVar($var) { return $this->Session->RestoreVar($var); } /** * Returns session variable value * * Return value of $var variable stored in Session. An optional default value could be passed as second parameter. * * @see SimpleSession * @access public * @param string $var Variable name * @param mixed $default Default value to return if no $var variable found in session * @return mixed */ function RecallVar($var,$default=false) { return $this->Session->RecallVar($var,$default); } function RecallPersistentVar($var, $default = false) { return $this->Session->RecallPersistentVar($var, $default); } /** * Stores variable $val in session under name $var * * Use this method to store variable in session. Later this variable could be recalled. * @see RecallVar * @access public * @param string $var Variable name * @param mixed $val Variable value */ function StoreVar($var, $val, $optional = false) { $session =& $this->recallObject('Session'); $this->Session->StoreVar($var, $val, $optional); } function StorePersistentVar($var, $val) { $this->Session->StorePersistentVar($var, $val); } function StoreVarDefault($var, $val, $optional=false) { $session =& $this->recallObject('Session'); $this->Session->StoreVarDefault($var, $val, $optional); } /** * Links HTTP Query variable with session variable * * If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session. * This method could be used for making sure that GetVar will return query or session value for given * variable, when query variable should overwrite session (and be stored there for later use).<br> * This could be used for passing item's ID into popup with multiple tab - * in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id'). * After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session * @access public * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value */ function LinkVar($var, $ses_var = null, $default = '', $optional = false) { if (!isset($ses_var)) $ses_var = $var; if ($this->GetVar($var) !== false) { $this->StoreVar($ses_var, $this->GetVar($var), $optional); } else { $this->SetVar($var, $this->RecallVar($ses_var, $default)); } } /** * Returns variable from HTTP Query, or from session if not passed in HTTP Query * * The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed. * Returns the default value if variable does not exist in session and was not passed in HTTP Query * * @see LinkVar * @access public * @param string $var HTTP Query (GPC) variable name * @param mixed $ses_var Session variable name * @param mixed $default Default variable value * @return mixed */ function GetLinkedVar($var, $ses_var = null, $default = '') { $this->LinkVar($var, $ses_var, $default); return $this->GetVar($var); } function AddBlock($name, $tpl) { $this->cache[$name] = $tpl; } function ProcessParsedTag($prefix, $tag, $params) { $processor = $this->Parser->GetProcessor($prefix); return $processor->ProcessParsedTag($tag, $params, $prefix); } /** * Return ADODB Connection object * * Returns ADODB Connection object already connected to the project database, configurable in config.php * @access public * @return kDBConnection */ function &GetADODBConnection() { return $this->Conn; } /** * Allows to parse given block name or include template * * @param Array $params Parameters to pass to block. Reserved parameter "name" used to specify block name. * @param Array $pass_params Forces to pass current parser params to this block/template. Use with cauntion, because you can accidently pass "block_no_data" parameter. * @param bool $as_template * @return string */ function ParseBlock($params, $pass_params = 0, $as_template = false) { if (substr($params['name'], 0, 5) == 'html:') { return substr($params['name'], 6); } return $this->Parser->ParseBlock($params, $pass_params, $as_template); } /** * Allows to include template with a given name and given parameters * * @param Array $params Parameters to pass to template. Reserved parameter "name" used to specify template name. * @return string */ function IncludeTemplate($params) { return $this->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0); } /** * Returns index file, that could be passed as parameter to method, as parameter to tag and as constant or not passed at all * * @param string $prefix * @param string $index_file * @param Array $params * @return string */ function getIndexFile($prefix, $index_file, &$params) { if (isset($params['index_file'])) { $index_file = $params['index_file']; unset($params['index_file']); return $index_file; } if (isset($index_file)) { return $index_file; } if (defined('INDEX_FILE')) { return INDEX_FILE; } $cut_prefix = trim(BASE_PATH, '/').'/'.trim($prefix, '/'); return trim(preg_replace('/'.preg_quote($cut_prefix, '/').'(.*)/', '\\1', $_SERVER['PHP_SELF']), '/'); } /** * Return href for template * * @access public * @param string $t Template path * @var string $prefix index.php prefix - could be blank, 'admin' */ function HREF($t, $prefix = '', $params = null, $index_file = null) { static $theme_id = null; if (!isset($theme_id)) { $theme_id = $this->GetVar('m_theme'); } if (!$t) { // when template not specified, use current $t = $this->GetVar('t'); } $t = preg_replace('/^Content\//i', '', $t); if (substr($t, -4) == '.tpl') { // cut template extension (deprecated link format) $t = substr($t, 0, strlen($t) - 4); } if (substr($t, 0, 3) == 'id:') { // link to structure page using it's id $params['m_cat_id'] = substr($t, 3); $t = $this->structureTemplateMapping[$t]; } if (array_key_exists('use_section', $params)) { $use_section = $params['use_section']; unset($params['use_section']); } if (isset($use_section) && $use_section && array_key_exists($t . ':' . $theme_id, $this->structureTemplateMapping)) { // structure template corresponding to given physical template $t = $this->structureTemplateMapping[$t . ':' . $theme_id]; unset($params['use_section']); } if (preg_match('/external:(.*)/', $t, $rets)) { // external url return $rets[1]; } if ($this->isAdmin && $prefix == '') $prefix = ADMIN_DIRECTORY; if ($this->isAdmin && $prefix == '_FRONT_END_') $prefix = ''; $index_file = $this->getIndexFile($prefix, $index_file, $params); if (isset($params['_auto_prefix_'])) { unset($params['_auto_prefix_']); // this is parser-related param, do not need to pass it here } $ssl = isset($params['__SSL__']) ? $params['__SSL__'] : null; if ($ssl !== null) { $session =& $this->recallObject('Session'); $cookie_url = trim($session->CookieDomain.$session->CookiePath, '/.'); if ($ssl) { $target_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false; if (!$target_url) { $target_url = $this->ConfigValue('SSL_URL'); } } else { $target_url = 'http://'.DOMAIN.$this->ConfigValue('Site_Path'); } if (!preg_match('#'.preg_quote($cookie_url).'#', $target_url)) { $session->SetMode(smGET_ONLY); } } if (isset($params['opener']) && $params['opener'] == 'u') { $wid = $this->Application->GetVar('m_wid'); $stack_name = rtrim('opener_stack_'.$wid, '_'); $opener_stack = $this->RecallVar($stack_name); if ($opener_stack && $opener_stack != serialize(Array())) { $opener_stack = unserialize($opener_stack); list($index_file, $env) = explode('|', $opener_stack[count($opener_stack) - 1]); $ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.ENV_VAR_NAME.'='.$env; if ( getArrayValue($params,'escape') ) $ret = addslashes($ret); if (isset($params['m_opener']) && $params['m_opener'] == 'u') { array_pop($opener_stack); if (!$opener_stack) { $this->RemoveVar($stack_name); // remove popups last templates, because popup is closing now $this->RemoveVar('last_template_'.$wid); $this->RemoveVar('last_template_popup_'.$wid); // don't save popups last templates again :) $this->SetVar('skip_last_template', 1); } else { $this->StoreVar($stack_name, serialize($opener_stack)); } /*// store window relations $window_relations = $this->Application->RecallVar('window_relations'); $window_relations = $window_relations ? unserialize($window_relations) : Array (); if (array_key_exists($wid, $window_relations)) { unset($window_relations[$wid]); $this->Application->StoreVar('window_relations', serialize($window_relations)); }*/ } return $ret; } else { //define('DBG_REDIRECT', 1); $t = $this->GetVar('t'); } } $pass = isset($params['pass']) ? $params['pass'] : ''; // pass events with url $pass_events = false; if( isset($params['pass_events']) ) { $pass_events = $params['pass_events']; unset($params['pass_events']); } $map_link = ''; if( isset($params['anchor']) ) { $map_link = '#'.$params['anchor']; unset($params['anchor']); } if ( isset($params['no_amp']) ) { $params['__URLENCODE__'] = $params['no_amp']; unset($params['no_amp']); } $no_rewrite = false; if( isset($params['__NO_REWRITE__']) ) { $no_rewrite = true; unset($params['__NO_REWRITE__']); } $force_rewrite = false; if( isset($params['__MOD_REWRITE__']) ) { $force_rewrite = true; unset($params['__MOD_REWRITE__']); } $force_no_sid = false; if( isset($params['__NO_SID__']) ) { $force_no_sid = true; unset($params['__NO_SID__']); } // append pass through variables to each link to be build // $params = array_merge_recursive2($this->getPassThroughVariables($params), $params); $params = array_merge($this->getPassThroughVariables($params), $params); if ($force_rewrite || ($this->RewriteURLs($ssl) && !$no_rewrite)) { static $rewrite_listeners_done = false; if (!$rewrite_listeners_done) { $mod_rewrite_helper =& $this->recallObject('ModRewriteHelper'); /* @var $mod_rewrite_helper kModRewriteHelper */ $mod_rewrite_helper->initRewriteListeners(); $rewrite_listeners_done = true; } $session =& $this->recallObject('Session'); if ($session->NeedQueryString() && !$force_no_sid) { $params['sid'] = $this->GetSID(); } $url = $this->BuildEnv_NEW($t, $params, $pass, $pass_events); $ret = $this->BaseURL($prefix, $ssl).$url.$map_link; } else { unset($params['pass_category']); // we don't need to pass it when mod_rewrite is off $env = $this->BuildEnv($t, $params, $pass, $pass_events); $ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env.$map_link; } return $ret; } /** * Returns variables with values that should be passed throught with this link + variable list * * @param Array $params * @return Array */ function getPassThroughVariables(&$params) { static $cached_pass_through = null; if (isset($params['no_pass_through']) && $params['no_pass_through']) { unset($params['no_pass_through']); return Array(); } // because pass through is not changed during script run, then we can cache it if (is_null($cached_pass_through)) { $cached_pass_through = Array(); $pass_through = $this->Application->GetVar('pass_through'); if ($pass_through) { // names of variables to pass to each link $cached_pass_through['pass_through'] = $pass_through; $pass_through = explode(',', $pass_through); foreach ($pass_through as $pass_through_var) { $cached_pass_through[$pass_through_var] = $this->Application->GetVar($pass_through_var); } } } return $cached_pass_through; } /** * Returns sorted array of passed prefixes (to build url from) * * @param string $pass * @return Array */ function getPassInfo($pass = 'all') { if (!$pass) $pass = 'all'; $pass = trim( preg_replace( '/(?<=,|\\A)all(?=,|\\z)/', trim($this->GetVar('passed'), ','), trim($pass, ',') ), ','); if (!$pass) { return Array(); } $pass_info = array_unique( explode(',', $pass) ); // array( prefix[.special], prefix[.special] ... // we need to keep that sorting despite the sorting below, because this sorts prefixes with same priority by name sort($pass_info, SORT_STRING); // to be prefix1,prefix1.special1,prefix1.special2,prefix3.specialX foreach ($pass_info as $prefix) { - list($prefix_only) = explode('.', $prefix, 1); + list ($prefix_only, ) = explode('.', $prefix, 2); $sorted[$prefix] = $this->getUnitOption($prefix_only, 'RewritePriority', 0); } - arsort($sorted); + asort($sorted, SORT_NUMERIC); $pass_info = array_keys($sorted); // ensure that "m" prefix is at the beginning $main_index = array_search('m', $pass_info); if ($main_index !== false) { unset($pass_info[$main_index]); array_unshift($pass_info, 'm'); } return $pass_info; } function BuildEnv_NEW($t, $params, $pass='all', $pass_events = false) { // $session =& $this->recallObject('Session'); $force_admin = getArrayValue($params,'admin') || $this->GetVar('admin'); // if($force_admin) $sid = $this->GetSID(); $ret = ''; $env = ''; $encode = false; if (isset($params['__URLENCODE__'])) { $encode = $params['__URLENCODE__']; unset($params['__URLENCODE__']); } if (isset($params['__SSL__'])) { unset($params['__SSL__']); } $catalog_item_found = false; $pass_info = $this->getPassInfo($pass); if ($pass_info) { if ($pass_info[0] == 'm') { array_shift($pass_info); } $inject_parts = Array (); // url parts for beginning of url $params['t'] = $t; // make template available for rewrite listeners $params['pass_template'] = true; // by default we keep given template in resulting url if (!array_key_exists('pass_category', $params)) { $params['pass_category'] = false; // by default we don't keep categories in url } foreach ($pass_info as $pass_index => $pass_element) { list ($prefix) = explode('.', $pass_element); $catalog_item = $this->findModule('Var', $prefix) && $this->getUnitOption($prefix, 'CatalogItem'); if (array_key_exists($prefix, $this->RewriteListeners)) { // if next prefix is same as current, but with special => exclude current prefix from url $next_prefix = array_key_exists($pass_index + 1, $pass_info) ? $pass_info[$pass_index + 1] : false; if ($next_prefix) { $next_prefix = substr($next_prefix, 0, strlen($prefix) + 1); if ($prefix . '.' == $next_prefix) { continue; } } // rewrited url part $url_part = $this->BuildModuleEnv_NEW($pass_element, $params, $pass_events); if (is_string($url_part) && $url_part) { $ret .= $url_part . '/'; if ($catalog_item) { // pass category later only for catalog items $catalog_item_found = true; } } elseif (is_array($url_part)) { // rewrite listener want to insert something at the beginning of url too if ($url_part[0]) { $inject_parts[] = $url_part[0]; } if ($url_part[1]) { $ret .= $url_part[1] . '/'; } if ($catalog_item) { // pass category later only for catalog items $catalog_item_found = true; } } elseif ($url_part === false) { // rewrite listener decided not to rewrite given $pass_element $env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events); } } else { $env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events); } } if ($catalog_item_found || preg_match('/c\.[-\d]*/', implode(',', $pass_info))) { // "c" prefix is present -> keep category $params['pass_category'] = true; } $params['inject_parts'] = $inject_parts; $ret = $this->BuildModuleEnv_NEW('m', $params, $pass_events) . '/' . $ret; $cat_processed = array_key_exists('category_processed', $params) && $params['category_processed']; // remove tempporary parameters used by listeners unset($params['t'], $params['inject_parts'], $params['pass_template'], $params['pass_category'], $params['category_processed']); if ($catalog_item_found || !$cat_processed || !defined('EXP_DIR_URLS')) { // this catalog item detail page OR there is no category given $ret = trim($ret, '/') . '.html'; } else { // url ends with "/" and not with ".html" $ret = trim($ret, '/') . '/'; } if ($env) { $params[ENV_VAR_NAME] = ltrim($env, ':'); } } unset($params['pass'], $params['opener'], $params['m_event']); if ($force_admin) { $params['admin'] = 1; } if (array_key_exists('escape', $params) && $params['escape']) { $ret = addslashes($ret); unset($params['escape']); } $ret = str_replace('%2F', '/', urlencode($ret)); $params_str = ''; $join_string = $encode ? '&' : '&'; foreach ($params as $param => $value) { $params_str .= $join_string . $param . '=' . $value; } if ($params_str) { $ret .= '?' . substr($params_str, strlen($join_string)); } if ($encode) { $ret = str_replace('\\', '%5C', $ret); } return $ret; } function BuildModuleEnv_NEW($prefix_special, &$params, $keep_events = false) { list ($prefix) = explode('.', $prefix_special); $url_parts = Array (); $listener = $this->RewriteListeners[$prefix]; $ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $keep_events); return $ret; } /** * Builds env part that corresponds prefix passed * * @param string $prefix_special item's prefix & [special] * @param Array $params url params * @param bool $pass_events */ function BuildModuleEnv($prefix_special, &$params, $pass_events = false) { list($prefix) = explode('.', $prefix_special); $query_vars = $this->getUnitOption($prefix, 'QueryString'); //if pass events is off and event is not implicity passed if( !$pass_events && !isset($params[$prefix_special.'_event']) ) { $params[$prefix_special.'_event'] = ''; // remove event from url if requested //otherwise it will use value from get_var } if(!$query_vars) return ''; $tmp_string = Array(0 => $prefix_special); foreach($query_vars as $index => $var_name) { //if value passed in params use it, otherwise use current from application $var_name = $prefix_special.'_'.$var_name; $tmp_string[$index] = isset( $params[$var_name] ) ? $params[$var_name] : $this->GetVar($var_name); if ( isset($params[$var_name]) ) unset( $params[$var_name] ); } $escaped = array(); foreach ($tmp_string as $tmp_val) { $escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val); } $ret = implode('-', $escaped); if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true) { $ret = preg_replace('/^([a-zA-Z]+)-([0-9]+)-(.*)/','\\1\\2-\\3', $ret); } return $ret; } function BuildEnv($t, $params, $pass='all', $pass_events = false, $env_var = true) { $session =& $this->recallObject('Session'); $ssl = isset($params['__SSL__']) ? $params['__SSL__'] : 0; $sid = $session->NeedQueryString() && !$this->RewriteURLs($ssl) ? $this->GetSID() : ''; // if (getArrayValue($params,'admin') == 1) $sid = $this->GetSID(); $ret = ''; if ($env_var) { $ret = ENV_VAR_NAME.'='; } $ret .= $sid . '-'; // SID-TEMPLATE $encode = false; if (isset($params['__URLENCODE__'])) { $encode = $params['__URLENCODE__']; unset($params['__URLENCODE__']); } if (isset($params['__SSL__'])) { unset($params['__SSL__']); } $env_string = ''; $category_id = isset($params['m_cat_id']) ? $params['m_cat_id'] : $this->GetVar('m_cat_id'); $item_id = false; $pass_info = $this->getPassInfo($pass); if ($pass_info) { if ($pass_info[0] == 'm') array_shift($pass_info); foreach ($pass_info as $pass_element) { list($prefix) = explode('.', $pass_element); $require_rewrite = $this->findModule('Var', $prefix); if ($require_rewrite) { $item_id = isset($params[$pass_element.'_id']) ? $params[$pass_element.'_id'] : $this->GetVar($pass_element.'_id'); } $env_string .= ':'.$this->BuildModuleEnv($pass_element, $params, $pass_events); } } if (strtolower($t) == '__default__') { // to put category & item templates into cache $filename = $this->getFilename('c', $category_id); if (is_numeric($item_id)) { $mod_rw_helper =& $this->Application->recallObject('ModRewriteHelper'); /* @var $mod_rw_helper kModRewriteHelper */ $t = $mod_rw_helper->GetItemTemplate($category_id, $pass_element); // $pass_element should be the last processed element // $t = $this->getCache('item_templates', $category_id); } elseif ($category_id) { $t = strtolower( preg_replace('/^Content\//i', '', $this->getCache('category_templates', $category_id)) ); } else { $t = 'index'; } } $ret .= $t.':'.$this->BuildModuleEnv('m', $params, $pass_events).$env_string; unset($params['pass'], $params['opener'], $params['m_event']); if ($this->GetVar('admin') && !isset($params['admin'])) { $params['admin'] = 1; if (!array_key_exists('editing_mode', $params)) { $params['editing_mode'] = EDITING_MODE; } } if (array_key_exists('escape', $params) && $params['escape']) { $ret = addslashes($ret); unset($params['escape']); } $join_string = $encode ? '&' : '&'; $params_str = ''; foreach ($params as $param => $value) { $params_str .= $join_string.$param.'='.$value; } $ret .= $params_str; if ($encode) { $ret = str_replace('\\', '%5C', $ret); } return $ret; } function BaseURL($prefix='', $ssl=null) { if ($ssl === null) { return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').$prefix.'/'; } else { if ($ssl) { $base_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false; if (!$base_url) { $base_url = $this->ConfigValue('SSL_URL'); } return rtrim($base_url, '/').$prefix.'/'; } else { return 'http://'.DOMAIN.(defined('PORT')?':'.PORT : '').rtrim( $this->ConfigValue('Site_Path'), '/').$prefix.'/'; } } } function Redirect($t='', $params=null, $prefix='', $index_file=null) { $js_redirect = getArrayValue($params, 'js_redirect'); if ($t == '' || $t === true) { $t = $this->GetVar('t'); } // pass prefixes and special from previous url if (array_key_exists('js_redirect', $params)) { unset($params['js_redirect']); } if (!array_key_exists('pass', $params)) { $params['pass'] = 'all'; } if ($this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t')) { // redirects to the same template as current $params['ajax'] = 'yes'; } $params['__URLENCODE__'] = 1; $location = $this->HREF($t, $prefix, $params, $index_file); $a_location = $location; $location = "Location: $location"; if ($this->isDebugMode() && constOn('DBG_REDIRECT')) { $this->Debugger->appendTrace(); echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>"; } else { if ($js_redirect) { $this->SetVar('t', 'redirect'); $this->SetVar('redirect_to_js', addslashes($a_location) ); $this->SetVar('redirect_to', $a_location); return true; } else { if ($this->GetVar('ajax') == 'yes' && $t != $this->GetVar('t')) { // redirection to other then current template during ajax request echo '#redirect#'.$a_location; } elseif (headers_sent() != '') { // some output occured -> redirect using javascript echo '<script type="text/javascript">window.location.href = \''.$a_location.'\';</script>'; } else { // no output before -> redirect using HTTP header // header('HTTP/1.1 302 Found'); header("$location"); } } } ob_end_flush(); // session expiration is called from session initialization, // that's why $this->Session may be not defined here $session =& $this->Application->recallObject('Session'); /* @var $session Session */ $this->HandleEvent( new kEvent('adm:OnBeforeShutdown') ); $session->SaveData(); exit; } function Phrase($label, $allow_editing = true, $use_admin = false) { return $this->Phrases->GetPhrase($label, $allow_editing, $use_admin); } /** * Replace language tags in exclamation marks found in text * * @param string $text * @param bool $force_escape force escaping, not escaping of resulting string * @return string * @access public */ function ReplaceLanguageTags($text, $force_escape=null) { // !!!!!!!! // if( !is_object($this->Phrases) ) $this->Debugger->appendTrace(); return $this->Phrases->ReplaceLanguageTags($text,$force_escape); } /** * Checks if user is logged in, and creates * user object if so. User object can be recalled * later using "u.current" prefix_special. Also you may * get user id by getting "u.current_id" variable. * * @access private */ function ValidateLogin() { $session =& $this->recallObject('Session'); $user_id = $session->GetField('PortalUserId'); if (!$user_id && $user_id != -1) { $user_id = -2; } $this->SetVar('u.current_id', $user_id); if (!$this->isAdmin) { // needed for "profile edit", "registration" forms ON FRONT ONLY $this->SetVar('u_id', $user_id); } $this->StoreVar('user_id', $user_id, $user_id == -2); // storing Guest user_id (-2) is optional $this->isAdminUser = $this->isAdmin && $this->LoggedIn(); if ($this->GetVar('expired') == 1) { // this parameter is set only from admin $user =& $this->recallObject('u.current'); $user->SetError('ValidateLogin', 'session_expired', 'la_text_sess_expired'); } if (($user_id != -2) && constOn('DBG_REQUREST_LOG') ) { $http_query =& $this->recallObject('HTTPQuery'); $http_query->writeRequestLog(DBG_REQUREST_LOG); } if ($user_id != -2) { // normal users + root $this->LoadPersistentVars(); } } /** * Loads current user persistent session data * */ function LoadPersistentVars() { $this->Session->LoadPersistentVars(); } function LoadCache() { $cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->isAdmin; $query = sprintf("SELECT PhraseList, ConfigVariables FROM %s WHERE Template = %s", TABLE_PREFIX.'PhraseCache', $this->Conn->qstr(md5($cache_key))); $res = $this->Conn->GetRow($query); if ($res) { $this->Caches['PhraseList'] = $res['PhraseList'] ? explode(',', $res['PhraseList']) : array(); $config_ids = $res['ConfigVariables'] ? explode(',', $res['ConfigVariables']) : array(); if (isset($this->Caches['ConfigVariables'])) { $config_ids = array_diff($config_ids, $this->Caches['ConfigVariables']); } } else { $config_ids = array(); } $this->Caches['ConfigVariables'] = $config_ids; $this->ConfigCacheIds = $config_ids; } function LoadStructureTemplateMapping() { // get template mapping $sql = 'SELECT Data FROM ' . TABLE_PREFIX . 'Cache WHERE VarName = "template_mapping"'; $template_mapping = $this->Conn->GetOne($sql); if (!$this->isAdmin && $template_mapping) { // template mappings only for Front-End $this->structureTemplateMapping = unserialize($template_mapping); } } function UpdateCache() { $update = false; //something changed $update = $update || $this->Phrases->NeedsCacheUpdate(); $update = $update || (count($this->ConfigCacheIds) && $this->ConfigCacheIds != $this->Caches['ConfigVariables']); if ($update) { $cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->isAdmin; $query = sprintf("REPLACE %s (PhraseList, CacheDate, Template, ConfigVariables) VALUES (%s, %s, %s, %s)", TABLE_PREFIX.'PhraseCache', $this->Conn->Qstr(join(',', $this->Phrases->Ids)), adodb_mktime(), $this->Conn->Qstr(md5($cache_key)), $this->Conn->qstr(implode(',', array_unique($this->ConfigCacheIds)))); $this->Conn->Query($query); } } function InitConfig() { if (isset($this->Caches['ConfigVariables']) && count($this->Caches['ConfigVariables']) > 0) { $this->ConfigHash = array_merge($this->ConfigHash, $this->Conn->GetCol( 'SELECT VariableValue, VariableName FROM '.TABLE_PREFIX.'ConfigurationValues WHERE VariableId IN ('.implode(',', $this->Caches['ConfigVariables']).')', 'VariableName')); } } /** * Returns configuration option value by name * * @param string $name * @return string */ function ConfigValue($name) { $res = array_key_exists($name, $this->ConfigHash) ? $this->ConfigHash[$name] : false; if ($res !== false) { return $res; } if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('ConfigurationValues')) { return false; } $sql = 'SELECT VariableId, VariableValue FROM '.TABLE_PREFIX.'ConfigurationValues WHERE VariableName = '.$this->Conn->qstr($name); $res = $this->Conn->GetRow($sql); if ($res !== false) { $this->ConfigHash[$name] = $res['VariableValue']; $this->ConfigCacheIds[] = $res['VariableId']; return $res['VariableValue']; } return false; } function UpdateConfigCache() { if ($this->ConfigCacheIds) { } } /** * Allows to process any type of event * * @param kEvent $event * @access public * @author Alex */ function HandleEvent(&$event, $params=null, $specificParams=null) { if ( isset($params) ) { $event = new kEvent( $params, $specificParams ); } if (!isset($this->EventManager)) { $this->EventManager =& $this->recallObject('EventManager'); } $this->EventManager->HandleEvent($event); } /** * Registers new class in the factory * * @param string $real_class Real name of class as in class declaration * @param string $file Filename in what $real_class is declared * @param string $pseudo_class Name under this class object will be accessed using getObject method * @param Array $dependecies List of classes required for this class functioning * @access public * @author Alex */ function registerClass($real_class, $file, $pseudo_class = null, $dependecies = Array() ) { $this->Factory->registerClass($real_class, $file, $pseudo_class, $dependecies); } /** * Add $class_name to required classes list for $depended_class class. * All required class files are included before $depended_class file is included * * @param string $depended_class * @param string $class_name * @author Alex */ function registerDependency($depended_class, $class_name) { $this->Factory->registerDependency($depended_class, $class_name); } /** * Registers Hook from subprefix event to master prefix event * * @param string $hookto_prefix * @param string $hookto_special * @param string $hookto_event * @param string $mode * @param string $do_prefix * @param string $do_special * @param string $do_event * @param string $conditional * @access public * @todo take care of a lot parameters passed * @author Kostja */ function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional) { $event_manager =& $this->recallObject('EventManager'); $event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional); } /** * Allows one TagProcessor tag act as other TagProcessor tag * * @param Array $tag_info * @author Kostja */ function registerAggregateTag($tag_info) { $aggregator =& $this->recallObject('TagsAggregator', 'kArray'); $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial'))); } /** * Returns object using params specified, * creates it if is required * * @param string $name * @param string $pseudo_class * @param Array $event_params * @return Object * @author Alex */ function &recallObject($name,$pseudo_class=null,$event_params=Array()) { $result =& $this->Factory->getObject($name, $pseudo_class, $event_params); return $result; } /** * Returns object using Variable number of params, * all params starting with 4th are passed to object consturctor * * @param string $name * @param string $pseudo_class * @param Array $event_params * @return Object * @author Alex */ function &recallObjectP($name,$pseudo_class=null,$event_params=Array()) { $func_args = func_get_args(); $result =& ref_call_user_func_array( Array(&$this->Factory, 'getObjectP'), $func_args ); return $result; } /** * Returns tag processor for prefix specified * * @param string $prefix * @return kDBTagProcessor */ function &recallTagProcessor($prefix) { $this->InitParser(); // because kDBTagProcesor is in NParser dependencies $result =& $this->recallObject($prefix . '_TagProcessor'); return $result; } /** * Checks if object with prefix passes was already created in factory * * @param string $name object presudo_class, prefix * @return bool * @author Kostja */ function hasObject($name) { return isset($this->Factory->Storage[$name]); } /** * Removes object from storage by given name * * @param string $name Object's name in the Storage * @author Kostja */ function removeObject($name) { $this->Factory->DestroyObject($name); } /** * Get's real class name for pseudo class, * includes class file and creates class * instance * * @param string $pseudo_class * @return Object * @access public * @author Alex */ function &makeClass($pseudo_class) { $func_args = func_get_args(); $result =& ref_call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args); return $result; } /** * Checks if application is in debug mode * * @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant * @return bool * @author Alex * @access public */ function isDebugMode($check_debugger = true) { $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; if ($check_debugger) { $debug_mode = $debug_mode && is_object($this->Debugger); } return $debug_mode; } /** * Apply url rewriting used by mod_rewrite or not * * @param bool $ssl Force ssl link to be build * @return bool */ function RewriteURLs($ssl = false) { // case #1,#4: // we want to create https link from http mode // we want to create https link from https mode // conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL') // case #2,#3: // we want to create http link from https mode // we want to create http link from http mode // conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://') $allow_rewriting = (!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http || // or allow rewriting for redirect TO httpS or when already in httpS (($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config! return constOn('MOD_REWRITE') && $allow_rewriting; } /** * Reads unit (specified by $prefix) * option specified by $option * * @param string $prefix * @param string $option * @param mixed $default * @return string * @access public * @author Alex */ function getUnitOption($prefix, $option, $default = false) { /*if (!isset($this->UnitConfigReader)) { $this->UnitConfigReader =& $this->recallObject('kUnitConfigReader'); }*/ return $this->UnitConfigReader->getUnitOption($prefix, $option, $default); } /** * Set's new unit option value * * @param string $prefix * @param string $name * @param string $value * @author Alex * @access public */ function setUnitOption($prefix, $option, $value) { // $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $this->UnitConfigReader->setUnitOption($prefix,$option,$value); } /** * Read all unit with $prefix options * * @param string $prefix * @return Array * @access public * @author Alex */ function getUnitOptions($prefix) { // $unit_config_reader =& $this->recallObject('kUnitConfigReader'); return $this->UnitConfigReader->getUnitOptions($prefix); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ function prefixRegistred($prefix) { /*if (!isset($this->UnitConfigReader)) { $this->UnitConfigReader =& $this->recallObject('kUnitConfigReader'); }*/ return $this->UnitConfigReader->prefixRegistred($prefix); } /** * Splits any mixing of prefix and * special into correct ones * * @param string $prefix_special * @return Array * @access public * @author Alex */ function processPrefix($prefix_special) { return $this->Factory->processPrefix($prefix_special); } /** * Set's new event for $prefix_special * passed * * @param string $prefix_special * @param string $event_name * @access public */ function setEvent($prefix_special,$event_name) { $event_manager =& $this->recallObject('EventManager'); $event_manager->setEvent($prefix_special,$event_name); } /** * SQL Error Handler * * @param int $code * @param string $msg * @param string $sql * @return bool * @access private * @author Alex */ function handleSQLError($code, $msg, $sql) { if ( isset($this->Debugger) ) { $errorLevel = constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ? E_USER_ERROR : E_USER_WARNING; $this->Debugger->appendTrace(); $error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:$Debugger.SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$this->Debugger->formatSQL($sql); $long_id = $this->Debugger->mapLongError($error_msg); trigger_error( mb_substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel); return true; } else { //$errorLevel = constOn('IS_INSTALL') ? E_USER_WARNING : E_USER_ERROR; $errorLevel = E_USER_WARNING; trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel); /*echo '<b>xProcessing SQL</b>: '.$sql.'<br>'; echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/ return $errorLevel == E_USER_ERROR ? false : true; } } /** * Default error handler * * @param int $errno * @param string $errstr * @param string $errfile * @param int $errline * @param Array $errcontext */ function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '') { if (defined('SILENT_LOG') && SILENT_LOG) { if ( !(defined('DBG_IGNORE_STRICT_ERRORS') && DBG_IGNORE_STRICT_ERRORS && defined('E_STRICT') && ($errno == E_STRICT)) ) { $fp = fopen(FULL_PATH.'/silent_log.txt','a'); $time = adodb_date('d/m/Y H:i:s'); fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n"); fclose($fp); } } $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; $skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING; if (!$this->errorHandlers || ($debug_mode && $skip_reporting)) { // when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request) $ignore_fatal_errors = defined('DBG_IGNORE_FATAL_ERRORS') && DBG_IGNORE_FATAL_ERRORS; if (($errno == E_USER_ERROR) && !$ignore_fatal_errors) { echo (' <div style="background-color: #FEFFBF; margin: auto; padding: 10px; border: 2px solid red; text-align: center"> <strong>Fatal Error: </strong>'."$errstr in $errfile on line $errline".' </div>'); exit; } if (!$this->errorHandlers) { return true; } } $res = false; $i = 0; // while (not foreach) because it is array of references in some cases $eh_count = count($this->errorHandlers); while ($i < $eh_count) { if ( is_array($this->errorHandlers[$i]) ) { $object =& $this->errorHandlers[$i][0]; $method = $this->errorHandlers[$i][1]; $res = $object->$method($errno, $errstr, $errfile, $errline, $errcontext); } else { $function = $this->errorHandlers[$i]; $res = $function($errno, $errstr, $errfile, $errline, $errcontext); } $i++; } return $res; } /** * Returns & blocks next ResourceId available in system * * @return int * @access public * @author Alex */ function NextResourceId() { $table_name = TABLE_PREFIX.'IdGenerator'; $this->Conn->Query('LOCK TABLES '.$table_name.' WRITE'); $this->Conn->Query('UPDATE '.$table_name.' SET lastid = lastid + 1'); $id = $this->Conn->GetOne('SELECT lastid FROM '.$table_name); if($id === false) { $this->Conn->Query('INSERT INTO '.$table_name.' (lastid) VALUES (2)'); $id = 2; } $this->Conn->Query('UNLOCK TABLES'); return $id - 1; } /** * Returns genealogical main prefix for subtable prefix passes * OR prefix, that has been found in REQUEST and some how is parent of passed subtable prefix * * @param string $current_prefix * @param string $real_top if set to true will return real topmost prefix, regardless of its id is passed or not * @return string * @access public * @author Kostja / Alex */ function GetTopmostPrefix($current_prefix, $real_top = false) { // 1. get genealogical tree of $current_prefix $prefixes = Array ($current_prefix); while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) { if (!$this->prefixRegistred($parent_prefix)) { // stop searching, when parent prefix is not registered break; } $current_prefix = $parent_prefix; array_unshift($prefixes, $current_prefix); } if ($real_top) { return $current_prefix; } // 2. find what if parent is passed $passed = explode(',', $this->GetVar('all_passed')); foreach ($prefixes as $a_prefix) { if (in_array($a_prefix, $passed)) { return $a_prefix; } } return $current_prefix; } /** * Triggers email event of type Admin * * @param string $email_event_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return unknown */ function &EmailEventAdmin($email_event_name, $to_user_id = null, $send_params = false) { $event =& $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params); return $event; } /** * Triggers email event of type User * * @param string $email_event_name * @param int $to_user_id * @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text * @return unknown */ function &EmailEventUser($email_event_name, $to_user_id = null, $send_params = false) { $event =& $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params); return $event; } /** * Triggers general email event * * @param string $email_event_name * @param int $email_event_type ( 0 for User, 1 for Admin) * @param int $to_user_id * @param array $send_params associative array of direct send params, * possible keys: to_email, to_name, from_email, from_name, message, message_text * @return unknown */ function &EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false) { $params = array( 'EmailEventName' => $email_event_name, 'EmailEventToUserId' => $to_user_id, 'EmailEventType' => $email_event_type, ); if ($send_params) { $params['DirectSendParams'] = $send_params; } $event_str = isset($send_params['use_special']) ? 'emailevents.'.$send_params['use_special'].':OnEmailEvent' : 'emailevents:OnEmailEvent'; $this->HandleEvent($event, $event_str, $params); return $event; } /** * Allows to check if user in this session is logged in or not * * @return bool */ function LoggedIn() { // no session during expiration process return is_null($this->Session) ? false : $this->Session->LoggedIn(); } /** * Check current user permissions based on it's group permissions in specified category * * @param string $name permission name * @param int $cat_id category id, current used if not specified * @param int $type permission type {1 - system, 0 - per category} * @return int */ function CheckPermission($name, $type = 1, $cat_id = null) { $perm_helper =& $this->recallObject('PermissionsHelper'); return $perm_helper->CheckPermission($name, $type, $cat_id); } /** * Set's any field of current visit * * @param string $field * @param mixed $value */ function setVisitField($field, $value) { if ($this->isAdmin || !$this->ConfigValue('UseVisitorTracking')) { // admin logins are not registred in visits list return ; } $visit =& $this->recallObject('visits', null, Array ('raise_warnings' => 0)); /* @var $visit kDBItem */ if ($visit->isLoaded()) { $visit->SetDBField($field, $value); $visit->Update(); } } /** * Allows to check if in-portal is installed * * @return bool */ function isInstalled() { return $this->InitDone && (count($this->ModuleInfo) > 0); } /** * Allows to determine if module is installed & enabled * * @param string $module_name * @return bool */ function isModuleEnabled($module_name) { return $this->findModule('Name', $module_name) !== false; } function reportError($class, $method) { $this->Debugger->appendTrace(); trigger_error('depricated method <b>'.$class.'->'.$method.'(...)</b>', E_USER_ERROR); } /** * Returns Window ID of passed prefix main prefix (in edit mode) * * @param string $prefix * @return mixed */ function GetTopmostWid($prefix) { $top_prefix = $this->GetTopmostPrefix($prefix); $mode = $this->GetVar($top_prefix.'_mode'); return $mode != '' ? substr($mode, 1) : ''; } /** * Get temp table name * * @param string $table * @param mixed $wid * @return string */ function GetTempName($table, $wid = '') { if (preg_match('/prefix:(.*)/', $wid, $regs)) { $wid = $this->GetTopmostWid($regs[1]); } return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_'.$table; } function GetTempTablePrefix($wid = '') { if (preg_match('/prefix:(.*)/', $wid, $regs)) { $wid = $this->GetTopmostWid($regs[1]); } return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_'; } function IsTempTable($table) { return preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$table); } /** * Checks, that given prefix is in temp mode * * @param string $prefix * @return bool */ function IsTempMode($prefix, $special = '') { $top_prefix = $this->Application->GetTopmostPrefix($prefix); $var_names = Array ( $top_prefix, rtrim($top_prefix . '_' . $special, '_'), // from post rtrim($top_prefix . '.' . $special, '.'), // assembled locally ); $var_names = array_unique($var_names); $temp_mode = false; foreach ($var_names as $var_name) { $value = $this->Application->GetVar($var_name . '_mode'); if ($value && (substr($value, 0, 1) == 't')) { $temp_mode = true; break; } } return $temp_mode; } /** * Return live table name based on temp table name * * @param string $temp_table * @return string */ function GetLiveName($temp_table) { if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$temp_table, $rets) ) { // cut wid from table end if any return $rets[2]; } else { return $temp_table; } } function CheckProcessors($processors) { foreach ($processors as $a_processor) { if (!isset($this->CachedProcessors[$a_processor])) { $this->CachedProcessors[$a_processor] =& $this->recallObject($a_processor.'_TagProcessor'); } } } function TimeZoneAdjustment($time_zone = null) { if ($time_zone == 'GMT') { return (-1) * adodb_date('Z'); } $target_zone = isset($time_zone) ? $time_zone : $this->ConfigValue('Config_Site_Time'); return 3600 * ($target_zone - $this->ConfigValue('Config_Server_Time')); } function ApplicationDie($message = '') { $message = ob_get_clean().$message; if ($this->isDebugMode()) { $message .= $this->Debugger->printReport(true); } echo $this->UseOutputCompression() ? gzencode($message, DBG_COMPRESSION_LEVEL) : $message; exit; } /* moved from MyApplication */ function getUserGroups($user_id) { switch ($user_id) { case -1: $user_groups = $this->ConfigValue('User_LoggedInGroup'); break; case -2: $user_groups = $this->ConfigValue('User_LoggedInGroup') . ',' . $this->ConfigValue('User_GuestGroup'); break; default: $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroup WHERE PortalUserId = ' . (int)$user_id; $res = $this->Conn->GetCol($sql); $user_groups = Array( $this->ConfigValue('User_LoggedInGroup') ); if ($res) { $user_groups = array_merge($user_groups, $res); } $user_groups = implode(',', $user_groups); } return $user_groups; } /** * Allows to detect if page is browsed by spider (293 agents supported) * * @return bool */ function IsSpider() { static $is_spider = null; if (!isset($is_spider)) { $user_agent = trim($_SERVER['HTTP_USER_AGENT']); $robots = file(FULL_PATH.'/core/robots_list.txt'); foreach ($robots as $robot_info) { $robot_info = explode("\t", $robot_info, 3); if ($user_agent == trim($robot_info[2])) { $is_spider = true; break; } } } return $is_spider; } /** * Allows to detect table's presense in database * * @param string $table_name * @return bool */ function TableFound($table_name) { return $this->Conn->TableFound($table_name); } /** * Returns counter value * * @param string $name counter name * @param Array $params counter parameters * @param string $query_name specify query name directly (don't generate from parmeters) * @param bool $multiple_results * @return mixed */ function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false) { $count_helper =& $this->Application->recallObject('CountHelper'); /* @var $count_helper kCountHelper */ return $count_helper->getCounter($name, $params, $query_name, $multiple_results); } /** * Resets counter, whitch are affected by one of specified tables * * @param string $tables comma separated tables list used in counting sqls */ function resetCounters($tables) { if (constOn('IS_INSTALL')) { return ; } $count_helper =& $this->Application->recallObject('CountHelper'); /* @var $count_helper kCountHelper */ return $count_helper->resetCounters($tables); } /** * Sends XML header + optionally displays xml heading * * @param string $xml_version * @return string * @author Alex */ function XMLHeader($xml_version = false) { $lang =& $this->recallObject('lang.current'); header('Content-type: text/xml; charset='.$lang->GetDBField('Charset')); return $xml_version ? '<?xml version="'.$xml_version.'" encoding="'.$lang->GetDBField('Charset').'"?>' : ''; } /** * Returns category tree * * @param int $category_id * @return Array */ function getTreeIndex($category_id) { $category_template = $this->getFilename('c', $category_id); // to rebuild "category_tree" cache $tree_index = $this->getCache('category_tree', $category_id); if ($tree_index) { $ret = Array (); list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index); return $ret; } return false; } } \ No newline at end of file