Index: branches/5.2.x/core/kernel/application.php =================================================================== --- branches/5.2.x/core/kernel/application.php (revision 14183) +++ branches/5.2.x/core/kernel/application.php (revision 14184) @@ -1,3332 +1,2523 @@ <?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!'); /** * 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. */ class kApplication implements kiCacheable { /** * 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(); /** * Maintains list of user-defined exception handlers * * @var Array */ var $exceptionHandlers = 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 for TemplatesChache + * Holds a ref to kUrlManager * - * @var TemplatesCache + * @var kUrlManager + * @access protected */ - var $TemplatesCache = null; + protected $UrlManager = null; /** - * Physical template name mapping to their template names based on structure + * Ref for TemplatesChache * - * @var Array + * @var TemplatesCache */ - var $structureTemplateMapping = Array (); + var $TemplatesCache = null; 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; /** - * Object of memory caching class + * Object of unit caching class * - * @var kCache + * @var kCacheManager */ - var $memoryCache = null; + var $cacheManager = 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; /** * Instance of site domain object * * @var kDBItem */ var $siteDomain = null; /** * Prevent kApplication class to be created directly, only via Instance method * */ protected function __construct() { } /** * 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 */ public static function &Instance() { static $instance = false; if (!$instance) { $class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication'; $instance = new $class(); $instance->Application =& $instance; } return $instance; } /** * Initializes the Application * * @access public * @see kHTTPQuery * @see Session * @see TemplatesCache * @return bool Was Init actually made now or before */ public function Init() { if($this->InitDone) { return false; } $this->isAdmin = kUtil::constOn('ADMIN'); if ( !kUtil::constOn('SKIP_OUT_COMPRESSION') ) { ob_start(); // collect any output from method (other then tags) into buffer } if (defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Init:'); } if (!$this->isDebugMode() && !kUtil::constOn('DBG_ZEND_PRESENT')) { error_reporting(0); ini_set('display_errors', 0); } if (!kUtil::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; } $exception_handler = set_exception_handler( Array (&$this, 'handleException') ); if ($exception_handler) { // wrap around previous exception handler, if any was set $this->exceptionHandlers[] = $exception_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->memoryCache =& $this->Factory->makeClass('Cache'); - $this->EventManager =& $this->Factory->makeClass('EventManager'); + + $this->cacheManager =& $this->makeClass('kCacheManager'); + $this->cacheManager->InitCache(); + + $this->UrlManager =& $this->makeClass('kUrlManager'); + $this->EventManager =& $this->makeClass('EventManager'); $this->Factory->Storage['EventManager'] =& $this->EventManager; $this->RegisterDefaultBuildEvents(); 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->UrlManager->LoadStructureTemplateMapping(); $this->HttpQuery->AfterInit(); $this->Session->ValidateExpired(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); } - $this->LoadCache(); - $this->InitConfig(); + $this->cacheManager->LoadApplicationCache(); $site_timezone = $this->ConfigValue('Config_Site_Time'); if ($site_timezone) { putenv('TZ=' . $site_timezone); } if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Loaded cache and phrases'); } $this->ValidateLogin(); // must be called before AfterConfigRead, because current user should be available there $this->UnitConfigReader->AfterConfigRead(); if (defined('DEBUG_MODE') && $this->isDebugMode()) { $this->Debugger->appendTimestamp('Processed AfterConfigRead'); } 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 } $visit_id = $this->RecallVar('visit_id'); if ($visit_id !== false) { $this->SetVar('visits_id', $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 */ $this->Conn->nextQueryCachable = true; $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) { kUtil::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'); } kUtil::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'); - } - - kUtil::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) { $cache_key = 'primary_language_info[%LangSerial%]'; $language_info = $this->getCache($cache_key); if ($language_info === false) { // cache primary language info first $table = $this->getUnitOption('lang', 'TableName'); $id_field = $this->getUnitOption('lang', 'IDField'); $this->Conn->nextQueryCachable = true; $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'); if ($language_info !== false) { $this->setCache($cache_key, $language_info); } } $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 (kUtil::constOn('DBG_FORCE_THEME')) { $theme_id = DBG_FORCE_THEME; } elseif (!$force_front && $this->isAdmin) { $theme_id = 999; } else { $cache_key = 'primary_theme[%ThemeSerial%]'; $theme_id = $this->getCache($cache_key); if ($theme_id === false) { $this->Conn->nextQueryCachable = true; $sql = 'SELECT ' . $this->getUnitOption('theme', 'IDField') . ' FROM ' . $this->getUnitOption('theme', 'TableName') . ' WHERE (PrimaryTheme = 1) AND (Enabled = 1)'; $theme_id = $this->Conn->GetOne($sql); if ($theme_id !== false) { $this->setCache($cache_key, $theme_id); } } } return $theme_id; } /** * Returns site primary currency ISO code * * @return string */ function GetPrimaryCurrency() { $cache_key = 'primary_currency[%CurrSerial%][%SiteDomainSerial%]:' . $this->siteDomainField('DomainId'); $currency_iso = $this->getCache($cache_key); if ($currency_iso === false) { if ($this->isModuleEnabled('In-Commerce')) { $this->Conn->nextQueryCachable = true; $currency_id = $this->siteDomainField('PrimaryCurrencyId'); $sql = 'SELECT ISO FROM ' . $this->getUnitOption('curr', 'TableName') . ' WHERE ' . ($currency_id > 0 ? 'CurrencyId = ' . $currency_id : 'IsPrimary = 1'); $currency_iso = $this->Conn->GetOne($sql); } else { $currency_iso = 'USD'; } $this->setCache($cache_key, $currency_iso); } return $currency_iso; } /** * Returns site domain field. When none of site domains are found false is returned. * * @param string $field * @param bool $formatted * @param string $format */ function siteDomainField($field, $formatted = false, $format = null) { if ($this->isAdmin) { // don't apply any filtering in administrative console return false; } if (!$this->siteDomain) { $this->siteDomain =& $this->recallObject('site-domain.current'); /* @var $site_domain kDBItem */ } if ($this->siteDomain->isLoaded()) { return $formatted ? $this->siteDomain->GetField($field, $format) : $this->siteDomain->GetDBField($field); } return false; } /** * Registers default classes such as ItemController, GridController and LoginController * * Called automatically while initializing Application * @access private * @return void */ function RegisterDefaultClasses() { $this->registerClass('kiCacheable', KERNEL_PATH . '/interfaces/cacheable.php', 'kiCacheable'); $this->registerClass('kTempTablesHandler', KERNEL_PATH . '/utility/temp_handler.php'); $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager', 'kiCacheable'); - $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php', 'kHookManager', 'kiCacheable'); - $this->registerClass('kAgentManager', KERNEL_PATH . '/managers/agent_manager.php', 'kAgentManager', 'kiCacheable'); - $this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php', 'kRequestManager'); + $this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php', null, 'kiCacheable'); + $this->registerClass('kAgentManager', KERNEL_PATH . '/managers/agent_manager.php', null, 'kiCacheable'); + $this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php'); + $this->registerClass('kUrlManager', KERNEL_PATH . '/managers/url_manager.php'); + $this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php', null, 'kiCacheable'); $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('kCache', KERNEL_PATH . '/utility/cache.php', 'kCache', '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_storage.php'); $this->registerClass('InpSession', KERNEL_PATH . '/session/inp_session.php', 'Session'); $this->registerClass('InpSessionStorage', KERNEL_PATH . '/session/inp_session_storage.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')) { + 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() { $this->EventManager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild'); } /** * Returns cached category informaton by given cache name. All given category * information is recached, when at least one of 4 caches is missing. * * @param int $category_id * @param string $name cache name = {filenames, category_designs, category_tree} * @return string + * @access public */ - function getCategoryCache($category_id, $name) - { - $serial_name = '[%CIDSerial:' . $category_id . '%]'; - $cache_key = $name . $serial_name; - $ret = $this->getCache($cache_key); - - if ($ret === false) { - if (!$category_id) { - // don't query database for "Home" category (ID = 0), because it doesn't exist in database - return false; - } - - // this allows to save 2 sql queries for each category - $this->Conn->nextQueryCachable = true; - $sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight - FROM ' . TABLE_PREFIX . 'Category - WHERE CategoryId = ' . (int)$category_id; - $category_data = $this->Conn->GetRow($sql); - - if ($category_data !== false) { - // only direct links to category pages work (symlinks, container pages and so on won't work) - $this->setCache('filenames' . $serial_name, $category_data['NamedParentPath']); - $this->setCache('category_designs' . $serial_name, ltrim($category_data['CachedTemplate'], '/')); - $this->setCache('category_tree' . $serial_name, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']); - } - } - - return $this->getCache($cache_key); - } - - /** - * Returns item's filename that corresponds id passed. If possible, then get it from cache - * - * @param string $prefix - * @param int $id - * @param int $category_id - * @return string - */ - function getFilename($prefix, $id, $category_id = null) + public function getCategoryCache($category_id, $name) { - if ($prefix == 'c') { - throw new Exception('Method "<strong>' . __FUNCTION__ . '</strong>" no longer work with "<strong>c</strong>" prefix. Please use "<strong>getCategoryCache</strong>" method instead'); - - return false; - } - - $category_id = isset($category_id) ? $category_id : $this->GetVar('m_cat_id'); - - $cache_key = 'filenames[%' . $this->incrementCacheSerial($prefix, $id, false) . '%]:' . (int)$category_id; - $filename = $this->getCache($cache_key); - - if ($filename === false) { - $this->Conn->nextQueryCachable = true; - $sql = 'SELECT ResourceId - FROM ' . $this->getUnitOption($prefix, 'TableName') . ' - WHERE ' . $this->getUnitOption($prefix, 'IDField') . ' = ' . $this->Conn->qstr($id); - $resource_id = $this->Conn->GetOne($sql); - - $this->Conn->nextQueryCachable = true; - $sql = 'SELECT Filename - FROM ' . TABLE_PREFIX . 'CategoryItems - WHERE (ItemResourceId = ' . $resource_id . ') AND (CategoryId = ' . (int)$category_id . ')'; - $filename = $this->Conn->GetOne($sql); - - if ($filename !== false) { - $this->setCache($cache_key, $filename); - } - } - - return $filename; + return $this->cacheManager->getCategoryCache($category_id, $name); } /** * Returns caching type (none, memory, temporary) * * @return int + * @access public */ - function isCachingType($caching_type) + public function isCachingType($caching_type) { - return $this->memoryCache->getCachingType() == $caching_type; + return $this->cacheManager->isCachingType($caching_type); } /** * Increments serial based on prefix and it's ID (optional) * * @param string $prefix * @param int $id ID (value of IDField) or ForeignKeyField:ID * @param bool $increment + * @access public */ - function incrementCacheSerial($prefix, $id = null, $increment = true) + public function incrementCacheSerial($prefix, $id = null, $increment = true) { - $pascal_case_prefix = implode('', array_map('ucfirst', explode('-', $prefix))); - $serial_name = $pascal_case_prefix . (isset($id) ? 'IDSerial:' . $id : 'Serial'); - - if ($increment) { - if (defined('DEBUG_MODE') && DEBUG_MODE && $this->isDebugMode()) { - $this->Debugger->appendHTML('Incrementing serial: <strong>' . $serial_name . '</strong>.'); - } - - $this->setCache($serial_name, (int)$this->getCache($serial_name) + 1); - - if (!defined('IS_INSTALL') || !IS_INSTALL) { - // delete cached mod-rewrite urls related to given prefix and id - $delete_clause = isset($id) ? $prefix . ':' . $id : $prefix; - - $sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls - WHERE Prefixes LIKE ' . $this->Conn->qstr('%|' . $delete_clause . '|%'); - $this->Conn->Query($sql); - } - } + return $this->cacheManager->incrementCacheSerial($prefix, $id, $increment); + } - return $serial_name; + /** + * Returns cached $key value from cache named $cache_name + * + * @param int $key key name from cache + * @param bool $store_locally store data locally after retrieved + * @return mixed + * @access public + */ + public function getCache($key, $store_locally = true) + { + return $this->cacheManager->getCache($key, $store_locally); } /** * Adds new value to cache $cache_name and identified by key $key * * @param int $key key name to add to cache * @param mixed $value value of chached record * @param int $expiration when value expires (0 - doesn't expire) + * @access public */ - function setCache($key, $value, $expiration = 0) + public function setCache($key, $value, $expiration = 0) { - return $this->memoryCache->setCache($key, $value, $expiration); + return $this->cacheManager->setCache($key, $value, $expiration); } /** - * Sets value to database cache + * Deletes key from cache * - * @param string $name - * @param mixed $value - * @param int $expiration + * @param string $key + * @access public */ - function setDBCache($name, $value, $expiration = false) + public function deleteCache($key) { - if ((int)$expiration <= 0) { - $expiration = -1; - } - - $fields_hash = Array ( - 'VarName' => $name, - 'Data' => &$value, - 'Cached' => adodb_mktime(), - 'LifeTime' => (int)$expiration, - ); - - $this->Conn->nextQueryCachable = true; - $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache', 'REPLACE'); + $this->cacheManager->deleteCache($key); } /** - * Returns cached $key value from cache named $cache_name + * Reset's all memory cache at once * - * @param int $key key name from cache - * @param bool $store_locally store data locally after retrieved - * @return mixed + * @access public */ - function getCache($key, $store_locally = true) + public function resetCache() { - return $this->memoryCache->getCache($key, $store_locally); + $this->cacheManager->resetCache(); } /** * Returns value from database cache * * @param string $name key name * @return mixed + * @access public */ - function getDBCache($name) + public function getDBCache($name) { - $this->Conn->nextQueryCachable = true; - - $sql = 'SELECT Data, Cached, LifeTime - FROM ' . TABLE_PREFIX . 'Cache - WHERE VarName = ' . $this->Conn->qstr($name); - $data = $this->Conn->GetRow($sql); - - if ($data) { - $lifetime = (int)$data['LifeTime']; // in seconds - if (($lifetime > 0) && ($data['Cached'] + $lifetime < adodb_mktime())) { - // delete expired - $this->Conn->nextQueryCachable = true; - - $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache - WHERE VarName = ' . $this->Conn->qstr($name); - $this->Conn->Query($sql); - - return false; - } - - return $data['Data']; - } - - return false; + return $this->cacheManager->getDBCache($name); } /** - * Deletes key from cache + * Sets value to database cache * - * @param string $key + * @param string $name + * @param mixed $value + * @param int $expiration + * @access public */ - function deleteCache($key) + public function setDBCache($name, $value, $expiration = false) { - $this->memoryCache->delete($key); + $this->cacheManager->setDBCache($name, $value, $expiration); } /** * Deletes key from database cache * * @param string $name + * @access public */ - function deleteDBCache($name) + public function deleteDBCache($name) { - $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache - WHERE VarName = ' . $this->Conn->qstr($name); - $this->Conn->Query($sql); + $this->cacheManager->deleteDBCache($name); } /** * Registers each module specific constants if any found * */ function registerModuleConstants() { if (file_exists(KERNEL_PATH.'/constants.php')) { kUtil::includeOnce(KERNEL_PATH.'/constants.php'); } if (!$this->ModuleInfo) { return false; } foreach ($this->ModuleInfo as $module_name => $module_info) { $contants_file = FULL_PATH . '/' . $module_info['Path'] . 'constants.php'; if (file_exists($contants_file)) { kUtil::includeOnce($contants_file); } } return true; } function ProcessRequest() { if ( defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::constOn('DBG_SHOW_HTTPQUERY') ) { $this->Debugger->appendHTML('HTTPQuery:'); $this->Debugger->dumpVars($this->HttpQuery->_Params); } $this->EventManager->ProcessRequest(); $this->EventManager->runAgents(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() && kUtil::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->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->getBaseCategory())) { // user can edit cms blocks $editing_mode = $this->GetVar('editing_mode'); define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE); } } kUtil::safeDefine('EDITING_MODE', ''); // user can't edit anything $this->Phrases->setPhraseEditing(); 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() && kUtil::constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Parsing:'); } $this->HTML = $this->Parser->Run($t); if (defined('DEBUG_MODE') && $this->isDebugMode() && kUtil::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') ); $debug_mode = defined('DEBUG_MODE') && $this->isDebugMode(); if ($debug_mode && kUtil::constOn('DBG_PROFILE_MEMORY')) { $this->Debugger->appendMemoryUsage('Application before Done:'); } if ($debug_mode) { $this->EventManager->runAgents(reAFTER); $this->Session->SaveData(); if (kUtil::constOn('DBG_CACHE')) { - $this->memoryCache->printStatistics(); + $this->cacheManager->printStatistics(); } $this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true); } else { // send "Set-Cookie" header before any output is made $this->Session->SetSession(); $this->HTML = ob_get_clean() . $this->HTML; } if ($this->UseOutputCompression()) { $compression_level = $this->ConfigValue('OutputCompressionLevel'); if ($compression_level < 0 || $compression_level > 9) { $compression_level = 7; } header('Content-Encoding: gzip'); echo gzencode($this->HTML, $compression_level); } else { echo $this->HTML; } - $this->UpdateCache(); + $this->cacheManager->UpdateApplicationCache(); flush(); if (!$debug_mode) { $this->EventManager->runAgents(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 = microtime(true) - $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 (kUtil::constOn('IS_INSTALL') || kUtil::constOn('DBG_ZEND_PRESENT') || kUtil::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, $optional = false) { $this->Session->StorePersistentVar($var, $val, $optional); } 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); } /** * Checks, that we have given block defined * * @param string $name * @return bool */ function ParserBlockFound($name) { return $this->Parser->blockFound($name); } /** * 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) + public 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'); - /* @var $session Session */ - - $target_url = rtrim($this->BaseURL('', $ssl, false), '/'); - $cookie_url = trim($session->CookieDomain . $session->CookiePath, '/.'); - - // set session to GET_ONLY, to pass sid only if sid is REAL AND session is set - if (!preg_match('#' . preg_quote($cookie_url) . '#', $target_url) && $session->SessionSet) { - // when SSL<->NON-SSL redirect to different domain pass SID in url - $session->SetMode(Session::smGET_ONLY); - } - } - - if (isset($params['opener']) && $params['opener'] == 'u') { - $wid = $this->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->RecallVar('window_relations'); - $window_relations = $window_relations ? unserialize($window_relations) : Array (); - if (array_key_exists($wid, $window_relations)) { - unset($window_relations[$wid]); - $this->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($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 $this->UrlManager->HREF($t, $prefix, $params, $index_file); + } - return $ret; + function getPhysicalTemplate($template) + { + return $this->UrlManager->getPhysicalTemplate($template); } /** * 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->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->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, 2); - $sorted[$prefix] = $this->getUnitOption($prefix_only, 'RewritePriority', 0); - } - - 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) - { - if ($this->GetVar('admin') || (array_key_exists('admin', $params) && $params['admin'])) { - $params['admin'] = 1; - - if (!array_key_exists('editing_mode', $params)) { - $params['editing_mode'] = EDITING_MODE; - } - } - - $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 (array_key_exists('url_ending', $params)) { - $ret = trim($ret, '/') . $params['url_ending']; - unset($params['url_ending']); - } - else { - $ret = trim($ret, '/') . MOD_REWRITE_URL_ENDING; - } - - if ($env) { - $params[ENV_VAR_NAME] = ltrim($env, ':'); - } - } - - unset($params['pass'], $params['opener'], $params['m_event']); - - 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][0]; - - $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; + return $this->UrlManager->getPassThroughVariables($params); } function BuildEnv($t, $params, $pass='all', $pass_events = false, $env_var = true) { - if ($this->GetVar('admin') || (array_key_exists('admin', $params) && $params['admin'])) { - $params['admin'] = 1; - - if (!array_key_exists('editing_mode', $params)) { - $params['editing_mode'] = EDITING_MODE; - } - } - - $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__') { - if (is_numeric($item_id)) { - $mod_rw_helper =& $this->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->getCategoryCache($category_id, 'item_templates'); - } - elseif ($category_id) { - $t = strtolower(preg_replace('/^Content\//i', '', $this->getCategoryCache($category_id, 'filenames') )); - } - else { - $t = 'index'; - } - } - - $ret .= $t.':'.$this->BuildModuleEnv('m', $params, $pass_events).$env_string; - - unset($params['pass'], $params['opener'], $params['m_event']); - - 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; + return $this->UrlManager->BuildEnv($t, $params, $pass, $pass_events, $env_var); } function BaseURL($prefix = '', $ssl = null, $add_port = true) { if ($ssl === null) { // stay on same encryption level return PROTOCOL . SERVER_NAME . ($add_port && defined('PORT') ? ':' . PORT : '') . rtrim(BASE_PATH, '/') . $prefix . '/'; } if ($ssl) { // going from http:// to https:// $base_url = $this->isAdmin ? $this->ConfigValue('AdminSSL_URL') : false; if (!$base_url) { $ssl_url = $this->siteDomainField('SSLUrl'); $base_url = $ssl_url !== false ? $ssl_url : $this->ConfigValue('SSL_URL'); } return rtrim($base_url, '/') . $prefix . '/'; } // going from https:// to http:// $domain = $this->siteDomainField('DomainName'); if ($domain === false) { $domain = DOMAIN; } return 'http://' . $domain . ($add_port && defined('PORT') ? ':' . PORT : '') . rtrim($this->ConfigValue('Site_Path'), '/') . $prefix . '/'; } function Redirect($t = '', $params = Array(), $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']); } // allows to send custom responce code along with redirect header if (array_key_exists('response_code', $params)) { $response_code = (int)$params['response_code']; unset($params['response_code']); } else { $response_code = 302; // Found } 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); if ($this->isDebugMode() && (kUtil::constOn('DBG_REDIRECT') || (kUtil::constOn('DBG_RAISE_ON_WARNINGS') && $this->Debugger->WarningCount))) { $this->Debugger->appendTrace(); echo '<strong>Debug output above !!!</strong><br/>' . "\n"; if ( array_key_exists('HTTP_REFERER', $_SERVER) ) { echo 'Referer: <strong>' . $_SERVER['HTTP_REFERER'] . '</strong><br/>' . "\n"; } echo "Proceed to redirect: <a href=\"{$location}\">{$location}</a><br/>\n"; } else { if ($js_redirect) { // show "redirect" template instead of redirecting, // because "Set-Cookie" header won't work, when "Location" // header is used later $this->SetVar('t', 'redirect'); $this->SetVar('redirect_to', $location); // make all additional parameters available on "redirect" template too foreach ($params as $name => $value) { $this->SetVar($name, $value); } return true; } else { if ($this->GetVar('ajax') == 'yes' && $t != $this->GetVar('t')) { // redirection to other then current template during ajax request echo '#redirect#' . $location; } elseif (headers_sent() != '') { // some output occured -> redirect using javascript echo '<script type="text/javascript">window.location.href = \'' . $location . '\';</script>'; } else { // no output before -> redirect using HTTP header // header('HTTP/1.1 302 Found'); header('Location: ' . $location, true, $response_code); } } } ob_end_flush(); // session expiration is called from session initialization, // that's why $this->Session may be not defined here $session =& $this->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) { 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 != USER_ROOT) { $user_id = USER_GUEST; } $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 == USER_GUEST); // 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 != USER_GUEST) && kUtil::constOn('DBG_REQUREST_LOG') ) { $http_query =& $this->recallObject('HTTPQuery'); $http_query->writeRequestLog(DBG_REQUREST_LOG); } if ($user_id != USER_GUEST) { // normal users + root $this->LoadPersistentVars(); } } /** * Loads current user persistent session data * */ function LoadPersistentVars() { $this->Session->LoadPersistentVars(); } - function LoadCache() - { - // TODO: maybe language part isn't required, since same phrase from different languages have one ID now - $cache_key = $this->GetVar('t') . $this->GetVar('m_theme') . $this->GetVar('m_lang') . $this->isAdmin; - - $sql = 'SELECT PhraseList, ConfigVariables - FROM ' . TABLE_PREFIX . 'PhraseCache - WHERE Template = ' . $this->Conn->qstr( md5($cache_key) ); - $res = $this->Conn->GetRow($sql); - - 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->Phrases->Init('phrases'); - $this->Caches['ConfigVariables'] = $config_ids; - $this->ConfigCacheIds = $config_ids; - } - - /** - * Loads template mapping for Front-End - * - */ - function LoadStructureTemplateMapping() - { - if (!$this->isAdmin) { - $category_helper =& $this->recallObject('CategoryHelper'); - /* @var $category_helper CategoryHelper */ - - $this->structureTemplateMapping = $category_helper->getTemplateMapping(); - } - } - - 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) { - $sql = 'SELECT VariableValue, VariableName - FROM ' . TABLE_PREFIX . 'ConfigurationValues - WHERE VariableId IN (' . implode(',', $this->Caches['ConfigVariables']) . ')'; - $this->ConfigHash = array_merge($this->ConfigHash, $this->Conn->GetCol($sql, 'VariableName')); - } - } - /** * Returns configuration option value by name * * @param string $name * @return string */ function ConfigValue($name) { - if ($name == 'Smtp_AdminMailFrom') { - $res = $this->siteDomainField('AdminEmail'); - - if ($res) { - return $res; - } - } - - $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; - } - - $this->Conn->nextQueryCachable = true; - $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) { - - } + return $this->cacheManager->ConfigValue($name); } /** * Allows to process any type of event * * @param kEvent $event * @param Array $params * @param Array $specific_params * @access public * @author Alex */ function HandleEvent(&$event, $params = null, $specific_params = null) { if ( isset($params) ) { $event = new kEvent($params, $specific_params); } 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); } /** * Unregisters existing class from factory * * @param string $real_class Real name of class as in class declaration * @param string $pseudo_class Name under this class object is accessed using getObject method */ function unregisterClass($real_class, $pseudo_class = null) { $this->Factory->unregisterClass($real_class, $pseudo_class); } /** * 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 $hook_event * @param string $do_event * @param int $mode * @param bool $conditional * @access public */ public function registerHook($hook_event, $do_event, $mode = hAFTER, $conditional = false) { $this->EventManager->registerHook($hook_event, $do_event, $mode, $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 * @param Array $arguments * @return kBase */ - function &recallObject($name, $pseudo_class = null, $event_params = Array(), $arguments = Array ()) + public function &recallObject($name, $pseudo_class = null, $event_params = Array(), $arguments = Array ()) { $result =& $this->Factory->getObject($name, $pseudo_class, $event_params, $arguments); 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) + public 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 * @param Array $arguments * @return kBase * @access public */ - function &makeClass($pseudo_class, $arguments = Array ()) + public function &makeClass($pseudo_class, $arguments = Array ()) { $result =& $this->Factory->makeClass($pseudo_class, $arguments); 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) + 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 kUtil::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) + public 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) + 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) + public 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) + public 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) + public 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) { $this->EventManager->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) ) { $long_error_msg = '<span class="debug_error">' . $msg . ' (' . $code . ')</span><br/><a href="javascript:$Debugger.SetClipboard(\'' . htmlspecialchars($sql) . '\');"><strong>SQL</strong></a>: ' . $this->Debugger->formatSQL($sql); $long_id = $this->Debugger->mapLongError($long_error_msg); $error_msg = mb_substr($msg . ' (' . $code . ') [' . $sql . ']', 0, 1000) . ' #' . $long_id; if ( kUtil::constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ) { throw new Exception($error_msg); } else { $this->Debugger->appendTrace(); } } else { // when not debug mode, then fatal database query won't break anything $error_msg = '<strong>SQL Error</strong> in sql: ' . $sql . ', code <strong>' . $code . '</strong> (' . $msg . ')'; } trigger_error($error_msg, E_USER_WARNING); return 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 = '') { $this->errorLogSilent($errno, $errstr, $errfile, $errline); $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) if ($errno == E_USER_ERROR) { $this->errorDisplayFatal('<strong>Fatal Error: </strong>' . "{$errstr} in {$errfile} on line {$errline}"); } if (!$this->errorHandlers) { return true; } } $res = false; foreach ($this->errorHandlers as $handler) { if ( is_array($handler) ) { $object =& $handler[0]; $method = $handler[1]; $res = $object->$method($errno, $errstr, $errfile, $errline, $errcontext); } else { $res = $handler($errno, $errstr, $errfile, $errline, $errcontext); } } return $res; } /** * Handles exception * * @param Exception $exception */ function handleException($exception) { // transform exception to regular error (no need to rewrite existing error handlers) $errno = $exception->getCode(); $errstr = $exception->getMessage(); $errfile = $exception->getFile(); $errline = $exception->getLine(); $this->errorLogSilent($errno, $errstr, $errfile, $errline); $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; $skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING; if (!$this->exceptionHandlers || ($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) $this->errorDisplayFatal('<strong>' . get_class($exception) . ': </strong>' . "{$errstr} in {$errfile} on line {$errline}"); if (!$this->exceptionHandlers) { return true; } } $res = false; foreach ($this->exceptionHandlers as $handler) { if ( is_array($handler) ) { $object =& $handler[0]; $method = $handler[1]; $res = $object->$method($exception); } else { $res = $handler($exception); } } return $res; } protected function errorLogSilent($errno, $errstr = '', $errfile = '', $errline = '') { if (!defined('SILENT_LOG') || !SILENT_LOG) { return ; } if ( !(defined('DBG_IGNORE_STRICT_ERRORS') && DBG_IGNORE_STRICT_ERRORS && defined('E_STRICT') && ($errno == E_STRICT)) ) { $time = adodb_date('d/m/Y H:i:s'); $fp = fopen(FULL_PATH . '/silent_log.txt', 'a'); fwrite($fp, '[' . $time . '] #' . $errno . ': ' . strip_tags($errstr) . ' in [' . $errfile . '] on line ' . $errline . "\n"); fclose($fp); } } protected function errorDisplayFatal($msg) { $margin = $this->isAdmin ? '8px' : 'auto'; echo '<div style="background-color: #FEFFBF; margin: ' . $margin . '; padding: 10px; border: 2px solid red; text-align: center">' . $msg . '</div>'; exit; } /** * 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 kEvent */ function &EmailEventAdmin($email_event_name, $to_user_id = null, $send_params = Array ()) { $event =& $this->EmailEvent($email_event_name, EmailEvent::EVENT_TYPE_ADMIN, $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 kEvent */ function &EmailEventUser($email_event_name, $to_user_id = null, $send_params = Array ()) { $event =& $this->EmailEvent($email_event_name, EmailEvent::EVENT_TYPE_FRONTEND, $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 kEvent */ function &EmailEvent($email_event_name, $email_event_type, $to_user_id = null, $send_params = Array ()) { $params = Array ( 'EmailEventName' => $email_event_name, 'EmailEventToUserId' => $to_user_id, 'EmailEventType' => $email_event_type, 'DirectSendParams' => $send_params, ); if (array_key_exists('use_special', $send_params)) { $event_str = 'emailevents.' . $send_params['use_special'] . ':OnEmailEvent'; } else { $event_str = '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'); + /* @var $perm_helper kPermissionsHelper */ + 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; - } /** * 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 = '') { return $this->GetTempTablePrefix($wid) . $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) { static $cache = Array (); if ( !array_key_exists($table, $cache) ) { $cache[$table] = preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$table); } return (bool)$cache[$table]; } /** * Checks, that given prefix is in temp mode * * @param string $prefix * @return bool */ function IsTempMode($prefix, $special = '') { $top_prefix = $this->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->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 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 USER_ROOT: $user_groups = $this->ConfigValue('User_LoggedInGroup'); break; case USER_GUEST: $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->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 (kUtil::constOn('IS_INSTALL')) { return ; } $count_helper =& $this->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) { $tree_index = $this->getCategoryCache($category_id, 'category_tree'); if ($tree_index) { $ret = Array (); list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index); return $ret; } return false; } /** * Base category of all categories * Usually replaced category, with ID = 0 in category-related operations. * * @return int */ function getBaseCategory() { // same, what $this->findModule('Name', 'Core', 'RootCat') does // don't cache while IS_INSTALL, because of kInstallToolkit::createModuleCategory and upgrade return $this->ModuleInfo['Core']['RootCat']; } + function DeleteUnitCache($include_sections = false) + { + $this->cacheManager->DeleteUnitCache($include_sections); + } + /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { - $this->ConfigHash = $data['Application.ConfigHash']; - - $this->Caches['ConfigVariables'] = $data['Application.ConfigCacheIds']; // undefined attribute - $this->ConfigCacheIds = $data['Application.ConfigCacheIds']; - $this->ReplacementTemplates = $data['Application.ReplacementTemplates']; $this->RewriteListeners = $data['Application.RewriteListeners']; - $this->ModuleInfo = $data['Application.ModuleInfo']; } /** * Gets object data for caching * The following caches should be reset based on admin interaction (adjusting config, enabling modules etc) * * @access public * @return Array */ public function getToCache() { - return Array ( - 'Application.ConfigHash' => $this->ConfigHash, - - 'Application.Caches.ConfigVariables' => $this->Caches['ConfigVariables'], // undefined attribute - 'Application.ConfigCacheIds' => $this->ConfigCacheIds, - - 'Application.ReplacementTemplates' => $this->ReplacementTemplates, - 'Application.RewriteListeners' => $this->RewriteListeners, - - 'Application.ModuleInfo' => $this->ModuleInfo, - ); + return Array ( + 'Application.ReplacementTemplates' => $this->ReplacementTemplates, + 'Application.RewriteListeners' => $this->RewriteListeners, + 'Application.ModuleInfo' => $this->ModuleInfo, + ); } - } \ No newline at end of file Index: branches/5.2.x/core/kernel/managers/url_manager.php =================================================================== --- branches/5.2.x/core/kernel/managers/url_manager.php (nonexistent) +++ branches/5.2.x/core/kernel/managers/url_manager.php (revision 14184) @@ -0,0 +1,631 @@ +<?php +/** +* @version $Id$ +* @package In-Portal +* @copyright Copyright (C) 1997 - 2010 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 kUrlManager extends kBase { + + /** + * Physical template name mapping to their template names based on structure + * + * @var Array + */ + protected $structureTemplateMapping = Array (); + + /** + * Return href for template + * + * @access public + * @param string $t Template path + * @var string $prefix index.php prefix - could be blank, 'admin' + */ + public function HREF($t, $prefix = '', $params = null, $index_file = null) + { + static $theme_id = null; + + if (!isset($theme_id)) { + $theme_id = $this->Application->GetVar('m_theme'); + } + + if (!$t) { + // when template not specified, use current + $t = $this->Application->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->Application->isAdmin && $prefix == '') $prefix = ADMIN_DIRECTORY; + if ($this->Application->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->Application->recallObject('Session'); + /* @var $session Session */ + + $target_url = rtrim($this->Application->BaseURL('', $ssl, false), '/'); + $cookie_url = trim($session->CookieDomain . $session->CookiePath, '/.'); + + // set session to GET_ONLY, to pass sid only if sid is REAL AND session is set + if (!preg_match('#' . preg_quote($cookie_url) . '#', $target_url) && $session->SessionSet) { + // when SSL<->NON-SSL redirect to different domain pass SID in url + $session->SetMode(Session::smGET_ONLY); + } + } + + if (isset($params['opener']) && $params['opener'] == 'u') { + $wid = $this->Application->GetVar('m_wid'); + $stack_name = rtrim('opener_stack_'.$wid, '_'); + $opener_stack = $this->Application->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->Application->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->Application->RemoveVar($stack_name); + // remove popups last templates, because popup is closing now + $this->Application->RemoveVar('last_template_'.$wid); + $this->Application->RemoveVar('last_template_popup_'.$wid); + + // don't save popups last templates again :) + $this->Application->SetVar('skip_last_template', 1); + } + else { + $this->Application->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->Application->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($this->getPassThroughVariables($params), $params); + + if ($force_rewrite || ($this->Application->RewriteURLs($ssl) && !$no_rewrite)) { + static $rewrite_listeners_done = false; + + if (!$rewrite_listeners_done) { + $mod_rewrite_helper =& $this->Application->recallObject('ModRewriteHelper'); + /* @var $mod_rewrite_helper kModRewriteHelper */ + + $mod_rewrite_helper->initRewriteListeners(); + + $rewrite_listeners_done = true; + } + + $session =& $this->Application->recallObject('Session'); + + if ($session->NeedQueryString() && !$force_no_sid) { + $params['sid'] = $this->Application->GetSID(); + } + + $url = $this->BuildEnv_NEW($t, $params, $pass, $pass_events); + $ret = $this->Application->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->Application->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; + } + + function BuildEnv($t, $params, $pass='all', $pass_events = false, $env_var = true) + { + if ($this->Application->GetVar('admin') || (array_key_exists('admin', $params) && $params['admin'])) { + $params['admin'] = 1; + + if (!array_key_exists('editing_mode', $params)) { + $params['editing_mode'] = EDITING_MODE; + } + } + + $session =& $this->Application->recallObject('Session'); + $ssl = isset($params['__SSL__']) ? $params['__SSL__'] : 0; + $sid = $session->NeedQueryString() && !$this->Application->RewriteURLs($ssl) ? $this->Application->GetSID() : ''; +// if (getArrayValue($params,'admin') == 1) $sid = $this->Application->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->Application->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->Application->findModule('Var', $prefix); + if ($require_rewrite) { + $item_id = isset($params[$pass_element.'_id']) ? $params[$pass_element.'_id'] : $this->Application->GetVar($pass_element.'_id'); + } + $env_string .= ':'.$this->BuildModuleEnv($pass_element, $params, $pass_events); + } + } + + if (strtolower($t) == '__default__') { + 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->Application->getCategoryCache($category_id, 'item_templates'); + } + elseif ($category_id) { + $t = strtolower(preg_replace('/^Content\//i', '', $this->Application->getCategoryCache($category_id, 'filenames') )); + } + else { + $t = 'index'; + } + } + + $ret .= $t.':'.$this->BuildModuleEnv('m', $params, $pass_events).$env_string; + + unset($params['pass'], $params['opener'], $params['m_event']); + + if (array_key_exists('escape', $params) && $params['escape']) { + $ret = addslashes($ret); + unset($params['escape']); + } + + if ($params) { + $params_str = ''; + $join_string = $encode ? '&' : '&'; + + foreach ($params as $param => $value) { + $params_str .= $join_string . $param . '=' . $value; + } + + $ret .= $params_str; + } + + if ($encode) { + $ret = str_replace('\\', '%5C', $ret); + } + + return $ret; + } + + function BuildEnv_NEW($t, $params, $pass='all', $pass_events = false) + { + if ($this->Application->GetVar('admin') || (array_key_exists('admin', $params) && $params['admin'])) { + $params['admin'] = 1; + + if (!array_key_exists('editing_mode', $params)) { + $params['editing_mode'] = EDITING_MODE; + } + } + + $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->Application->findModule('Var', $prefix) && $this->Application->getUnitOption($prefix, 'CatalogItem'); + + if (array_key_exists($prefix, $this->Application->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 (array_key_exists('url_ending', $params)) { + $ret = trim($ret, '/') . $params['url_ending']; + unset($params['url_ending']); + } + else { + $ret = trim($ret, '/') . MOD_REWRITE_URL_ENDING; + } + + if ($env) { + $params[ENV_VAR_NAME] = ltrim($env, ':'); + } + } + + unset($params['pass'], $params['opener'], $params['m_event']); + + if (array_key_exists('escape', $params) && $params['escape']) { + $ret = addslashes($ret); + unset($params['escape']); + } + + $ret = str_replace('%2F', '/', urlencode($ret)); + + if ($params) { + $params_str = ''; + $join_string = $encode ? '&' : '&'; + + foreach ($params as $param => $value) { + $params_str .= $join_string . $param . '=' . $value; + } + + $ret .= '?' . substr($params_str, strlen($join_string)); + } + + if ($encode) { + $ret = str_replace('\\', '%5C', $ret); + } + + 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->Application->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->Application->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->Application->getUnitOption($prefix, 'PortalStyleEnv') == true) + { + $ret = preg_replace('/^([a-zA-Z]+)-([0-9]+)-(.*)/','\\1\\2-\\3', $ret); + } + return $ret; + } + + function BuildModuleEnv_NEW($prefix_special, &$params, $keep_events = false) + { + list ($prefix) = explode('.', $prefix_special); + + $url_parts = Array (); + $listener = $this->Application->RewriteListeners[$prefix][0]; + + $ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $keep_events); + + return $ret; + } + + /** + * 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->Application->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, 2); + $sorted[$prefix] = $this->Application->getUnitOption($prefix_only, 'RewritePriority', 0); + } + + 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; + } + + /** + * 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']), '/'); + } + + function getPhysicalTemplate($template) + { + return array_search($template, $this->structureTemplateMapping); + } + + /** + * Loads template mapping for Front-End + * + */ + function LoadStructureTemplateMapping() + { + if (!$this->Application->isAdmin) { + $category_helper =& $this->Application->recallObject('CategoryHelper'); + /* @var $category_helper CategoryHelper */ + + $this->structureTemplateMapping = $category_helper->getTemplateMapping(); + } + } +} \ No newline at end of file Index: branches/5.2.x/core/kernel/managers/cache_manager.php =================================================================== --- branches/5.2.x/core/kernel/managers/cache_manager.php (nonexistent) +++ branches/5.2.x/core/kernel/managers/cache_manager.php (revision 14184) @@ -0,0 +1,574 @@ +<?php +/** +* @version $Id$ +* @package In-Portal +* @copyright Copyright (C) 1997 - 2011 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 kCacheManager extends kBase implements kiCacheable { + + /** + * Used variables from ConfigurationValues table + * + * @var Array + * @access protected + */ + protected $configVariables = Array(); + + /** + * IDs of config variables used in current run (for caching) + * + * @var Array + * @access protected + */ + protected $configIDs = Array (); + + /** + * IDs of config variables retirieved from cache + * + * @var Array + * @access protected + */ + protected $originalConfigIDs = Array (); + + /** + * Object of memory caching class + * + * @var kCache + * @access protected + */ + protected $cacheHandler = null; + + /** + * Creates caching manager instance + * + * @access public + */ + public function InitCache() + { + $this->cacheHandler =& $this->Application->makeClass('kCache'); + } + + /** + * Returns cache key, used to cache phrase and configuration variable IDs used on current page + * + * @return string + * @access protected + */ + protected function getCacheKey() + { + // TODO: maybe language part isn't required, since same phrase from different languages have one ID now + return $this->Application->GetVar('t') . $this->Application->GetVar('m_theme') . $this->Application->GetVar('m_lang') . $this->Application->isAdmin; + } + + /** + * Loads phrases and configuration variables, that were used on this template last time + * + * @access public + */ + public function LoadApplicationCache() + { + $phrase_ids = $config_ids = Array (); + + $sql = 'SELECT PhraseList, ConfigVariables + FROM ' . TABLE_PREFIX . 'PhraseCache + WHERE Template = ' . $this->Conn->qstr( md5($this->getCacheKey()) ); + $res = $this->Conn->GetRow($sql); + + if ($res) { + if ( $res['PhraseList'] ) { + $phrase_ids = explode(',', $res['PhraseList']); + } + + if ( $res['ConfigVariables'] ) { + $config_ids = array_diff( explode(',', $res['ConfigVariables']), $this->originalConfigIDs); + } + } + + $this->Application->Phrases->Init('phrases', '', null, $phrase_ids); + $this->configIDs = $this->originalConfigIDs = $config_ids; + + $this->InitConfig(); + } + + /** + * Updates phrases and configuration variables, that were used on this template + * + * @access public + */ + public function UpdateApplicationCache() + { + $update = false; + + //something changed + $update = $update || $this->Application->Phrases->NeedsCacheUpdate(); + $update = $update || (count($this->configIDs) && $this->configIDs != $this->originalConfigIDs); + + if ($update) { + $fields_hash = Array ( + 'PhraseList' => implode(',', $this->Application->Phrases->Ids), + 'CacheDate' => adodb_mktime(), + 'Template' => md5( $this->getCacheKey() ), + 'ConfigVariables' => implode(',', array_unique($this->configIDs)), + ); + + $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'PhraseCache', 'REPLACE'); + } + } + + /** + * Loads configuration variables, that were used on this template last time + * + * @access protected + */ + protected function InitConfig() + { + if (!$this->originalConfigIDs) { + return ; + } + + $sql = 'SELECT VariableValue, VariableName + FROM ' . TABLE_PREFIX . 'ConfigurationValues + WHERE VariableId IN (' . implode(',', $this->originalConfigIDs) . ')'; + $config_variables = $this->Conn->GetCol($sql, 'VariableName'); + + $this->configVariables = array_merge($this->configVariables, $config_variables); + } + + /** + * Returns configuration option value by name + * + * @param string $name + * @return string + * @access public + */ + public function ConfigValue($name) + { + if ($name == 'Smtp_AdminMailFrom') { + $res = $this->Application->siteDomainField('AdminEmail'); + + if ($res) { + return $res; + } + } + + if ( array_key_exists($name, $this->configVariables) ) { + return $this->configVariables[$name]; + } + + if ( defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound('ConfigurationValues') ) { + return false; + } + + $this->Conn->nextQueryCachable = true; + $sql = 'SELECT VariableId, VariableValue + FROM ' . TABLE_PREFIX . 'ConfigurationValues + WHERE VariableName = ' . $this->Conn->qstr($name); + $res = $this->Conn->GetRow($sql); + + if ($res !== false) { + $this->configIDs[] = $res['VariableId']; + $this->configVariables[$name] = $res['VariableValue']; + + return $res['VariableValue']; + } + + return false; + } + + /** + * Loads data, that was cached during unit config parsing + * + * @return bool + * @access public + */ + public function LoadUnitCache() + { + if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + $data = $this->Application->getCache('master:configs_parsed', false); + } + else { + $data = $this->Application->getDBCache('configs_parsed'); + } + + if ($data) { + $cache = unserialize($data); // 126 KB all modules + unset($data); + + $this->Application->Factory->setFromCache($cache); + $this->Application->UnitConfigReader->setFromCache($cache); + $this->Application->EventManager->setFromCache($cache); + + $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); + /* @var $aggregator kArray */ + + $aggregator->setFromCache($cache); + $this->setFromCache($cache); + $this->Application->setFromCache($cache); + unset($cache); + + return true; + + } + + return false; + } + + /** + * Updates data, that was parsed from unit configs this time + * + * @access public + */ + public function UpdateUnitCache() + { + $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); + /* @var $aggregator kArray */ + + $this->preloadConfigVars(); // preloading will put to cache + + $cache = array_merge( + $this->Application->Factory->getToCache(), + $this->Application->UnitConfigReader->getToCache(), + $this->Application->EventManager->getToCache(), + $aggregator->getToCache(), + $this->getToCache(), + $this->Application->getToCache() + ); + + $cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s'); + + if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + $this->Application->setCache('master:configs_parsed', serialize($cache)); + $this->Application->setCache('master:last_cache_rebuild', $cache_rebuild_by); + } + else { + $this->Application->setDBCache('configs_parsed', serialize($cache)); + $this->Application->setDBCache('last_cache_rebuild', $cache_rebuild_by); + } + } + + /** + * Deletes all data, that was cached during unit config parsing (including unit config locations) + * + * @param bool $include_sections + * @access public + */ + public function DeleteUnitCache($include_sections = false) + { + if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + $this->Application->deleteCache('master:configs_parsed'); + } + else { + $this->Application->deleteDBCache('configs_parsed'); + } + + if ($include_sections) { + if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + $this->Application->deleteCache('master:sections_parsed'); + } + else { + $this->Application->deleteDBCache('sections_parsed'); + } + } + } + + /** + * Preloads widely used configuration variables, so they will get to cache for sure + * + * @access protected + */ + protected function preloadConfigVars() + { + $config_vars = Array ( + // session related + 'SessionTimeout', + 'SessionCookieName', + 'SessionCookieDomains', + 'SessionBrowserSignatureCheck', + 'SessionIPAddressCheck', + 'CookieSessions', + 'KeepSessionOnBrowserClose', + 'User_GuestGroup', + 'User_LoggedInGroup', + + // output related + 'UseModRewrite', + 'UseContentLanguageNegotiation', + 'UseOutputCompression', + 'OutputCompressionLevel', + 'Config_Site_Time', + 'SystemTagCache', + + // tracking related + 'UseChangeLog', + 'UseVisitorTracking', + 'ModRewriteUrlEnding', + 'ForceModRewriteUrlEnding', + 'UseCronForRegularEvent', + ); + + $escaped_config_vars = array_map(Array (&$this->Conn, 'qstr'), $config_vars); + + $sql = 'SELECT VariableId, VariableName, VariableValue + FROM ' . TABLE_PREFIX . 'ConfigurationValues + WHERE VariableName IN (' . implode(',', $escaped_config_vars) . ')'; + $data = $this->Conn->Query($sql, 'VariableId'); + + foreach ($data as $variable_id => $variable_info) { + $this->configIDs[] = $variable_id; + $this->configVariables[ $variable_info['VariableName'] ] = $variable_info['VariableValue']; + } + } + + /** + * Sets data from cache to object + * + * @param Array $data + * @access public + */ + public function setFromCache(&$data) + { + $this->configVariables = $data['Application.ConfigHash']; + $this->configIDs = $this->originalConfigIDs = $data['Application.ConfigCacheIds']; + } + + /** + * Gets object data for caching + * The following caches should be reset based on admin interaction (adjusting config, enabling modules etc) + * + * @access public + * @return Array + */ + public function getToCache() + { + return Array ( + 'Application.ConfigHash' => $this->configVariables, + 'Application.ConfigCacheIds' => $this->configIDs, + + // not in use, since it only represents template specific values, not global ones + // 'Application.Caches.ConfigVariables' => $this->originalConfigIDs, + ); + } + + /** + * Returns caching type (none, memory, temporary) + * + * @return int + * @access public + */ + public function isCachingType($caching_type) + { + return $this->cacheHandler->getCachingType() == $caching_type; + } + + /** + * Prints caching statistics + * + * @access public + */ + public function printStatistics() + { + $this->cacheHandler->printStatistics(); + } + + /** + * Returns cached $key value from cache named $cache_name + * + * @param int $key key name from cache + * @param bool $store_locally store data locally after retrieved + * @return mixed + * @access public + */ + public function getCache($key, $store_locally = true) + { + return $this->cacheHandler->getCache($key, $store_locally); + } + + /** + * Adds new value to cache $cache_name and identified by key $key + * + * @param int $key key name to add to cache + * @param mixed $value value of chached record + * @param int $expiration when value expires (0 - doesn't expire) + * @access public + */ + public function setCache($key, $value, $expiration = 0) + { + return $this->cacheHandler->setCache($key, $value, $expiration); + } + + /** + * Deletes key from cache + * + * @param string $key + * @access public + */ + public function deleteCache($key) + { + $this->cacheHandler->delete($key); + } + + /** + * Reset's all memory cache at once + * + * @access public + */ + public function resetCache() + { + $this->cacheHandler->reset(); + } + + /** + * Returns value from database cache + * + * @param string $name key name + * @return mixed + * @access public + */ + public function getDBCache($name) + { + $this->Conn->nextQueryCachable = true; + + $sql = 'SELECT Data, Cached, LifeTime + FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = ' . $this->Conn->qstr($name); + $data = $this->Conn->GetRow($sql); + + if ($data) { + $lifetime = (int)$data['LifeTime']; // in seconds + if (($lifetime > 0) && ($data['Cached'] + $lifetime < adodb_mktime())) { + // delete expired + $this->Conn->nextQueryCachable = true; + + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = ' . $this->Conn->qstr($name); + $this->Conn->Query($sql); + + return false; + } + + return $data['Data']; + } + + return false; + } + + /** + * Sets value to database cache + * + * @param string $name + * @param mixed $value + * @param int $expiration + * @access public + */ + public function setDBCache($name, $value, $expiration = false) + { + if ((int)$expiration <= 0) { + $expiration = -1; + } + + $fields_hash = Array ( + 'VarName' => $name, + 'Data' => &$value, + 'Cached' => adodb_mktime(), + 'LifeTime' => (int)$expiration, + ); + + $this->Conn->nextQueryCachable = true; + $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache', 'REPLACE'); + } + + /** + * Deletes key from database cache + * + * @param string $name + * @access public + */ + public function deleteDBCache($name) + { + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache + WHERE VarName = ' . $this->Conn->qstr($name); + $this->Conn->Query($sql); + } + + /** + * Increments serial based on prefix and it's ID (optional) + * + * @param string $prefix + * @param int $id ID (value of IDField) or ForeignKeyField:ID + * @param bool $increment + * @access public + */ + public function incrementCacheSerial($prefix, $id = null, $increment = true) + { + $pascal_case_prefix = implode('', array_map('ucfirst', explode('-', $prefix))); + $serial_name = $pascal_case_prefix . (isset($id) ? 'IDSerial:' . $id : 'Serial'); + + if ($increment) { + if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) { + $this->Application->Debugger->appendHTML('Incrementing serial: <strong>' . $serial_name . '</strong>.'); + } + + $this->setCache($serial_name, (int)$this->getCache($serial_name) + 1); + + if (!defined('IS_INSTALL') || !IS_INSTALL) { + // delete cached mod-rewrite urls related to given prefix and id + $delete_clause = isset($id) ? $prefix . ':' . $id : $prefix; + + $sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls + WHERE Prefixes LIKE ' . $this->Conn->qstr('%|' . $delete_clause . '|%'); + $this->Conn->Query($sql); + } + } + + return $serial_name; + } + + /** + * Returns cached category informaton by given cache name. All given category + * information is recached, when at least one of 4 caches is missing. + * + * @param int $category_id + * @param string $name cache name = {filenames, category_designs, category_tree} + * @return string + * @access public + */ + public function getCategoryCache($category_id, $name) + { + $serial_name = '[%CIDSerial:' . $category_id . '%]'; + $cache_key = $name . $serial_name; + $ret = $this->getCache($cache_key); + + if ($ret === false) { + if (!$category_id) { + // don't query database for "Home" category (ID = 0), because it doesn't exist in database + return false; + } + + // this allows to save 2 sql queries for each category + $this->Conn->nextQueryCachable = true; + $sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight + FROM ' . TABLE_PREFIX . 'Category + WHERE CategoryId = ' . (int)$category_id; + $category_data = $this->Conn->GetRow($sql); + + if ($category_data !== false) { + // only direct links to category pages work (symlinks, container pages and so on won't work) + $this->setCache('filenames' . $serial_name, $category_data['NamedParentPath']); + $this->setCache('category_designs' . $serial_name, ltrim($category_data['CachedTemplate'], '/')); + $this->setCache('category_tree' . $serial_name, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']); + } + } + + return $this->getCache($cache_key); + } +} \ No newline at end of file Index: branches/5.2.x/core/kernel/utility/formatters/password_formatter.php =================================================================== --- branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 14183) +++ branches/5.2.x/core/kernel/utility/formatters/password_formatter.php (revision 14184) @@ -1,143 +1,145 @@ <?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. */ class kPasswordFormatter extends kFormatter { /** * The method is supposed to alter config options or cofigure object in some way based on its usage of formatters * The methods is called for every field with formatter defined when configuring item. * Could be used for adding additional VirtualFields to an object required by some special Formatter * * @param string $field_name * @param array $field_options * @param kDBBase $object */ function PrepareOptions($field_name, &$field_options, &$object) { if ( isset( $field_options['verify_field'] ) ) { $add_fields = Array (); $options = Array ('master_field' => $field_name, 'formatter' => 'kPasswordFormatter'); $copy_options = Array ('encryption_method', 'salt', 'required', 'skip_empty'); foreach ($copy_options as $copy_option) { if (array_key_exists($copy_option, $field_options)) { $options[$copy_option] = $field_options[$copy_option]; } } $add_fields[ $field_options['verify_field'] ] = $options; $add_fields[$field_name.'_plain'] = Array('type'=>'string', 'error_field'=>$field_name); $add_fields[ $field_options['verify_field'].'_plain' ] = Array('type'=>'string', 'error_field'=>$field_options['verify_field'] ); $virtual_fields = $object->getVirtualFields(); $add_fields = kUtil::array_merge_recursive($add_fields, $virtual_fields); $object->setVirtualFields($add_fields); } } function Format($value, $field_name, &$object, $format=null) { return $value; } /** * Performs password & verify password field validation * * @param mixed $value * @param string $field_name * @param kDBItem $object * @return string */ function Parse($value, $field_name, &$object) { $options = $object->GetFieldOptions($field_name); $flip_count = 0; $fields_set = true; $fields = Array ('master_field', 'verify_field'); // 1. collect values from both Password and VerifyPassword fields while ($flip_count < 2) { if ( getArrayValue($options, $fields[0]) ) { $tmp_field = $options[ $fields[0] ]; $object->SetDBField($field_name.'_plain', $value); if ( !$object->GetFieldOption($tmp_field, $fields[1].'_set') ) { $object->SetFieldOption($tmp_field, $fields[1].'_set', true); } $password_field = $options[ $fields[0] ]; $verify_field = $field_name; } $fields = array_reverse($fields); $flip_count++; } $salt = $object->GetFieldOption($password_field, 'salt', false, ''); if ($object->GetFieldOption($password_field, 'verify_field_set') && $object->GetFieldOption($verify_field, 'master_field_set')) { $new_password = $object->GetDBField($password_field . '_plain'); $verify_password = $object->GetDBField($verify_field . '_plain'); if ($new_password == '' && $verify_password == '') { // both passwords are empty -> keep old password if ($object->GetDBField($password_field) != $this->EncryptPassword('', $salt)) { if ($options['encryption_method'] == 'plain') { return $value; } return $this->EncryptPassword($value); } else { return $value; } } // determine admin or front $phrase_error_prefix = $this->Application->isAdmin ? 'la' : 'lu'; if ($new_password != $verify_password) { // passwords don't match (no matter what is their length) $object->SetError($verify_field, 'passwords_do_not_match', $phrase_error_prefix.'_passwords_do_not_match'); } $min_length = $this->Application->ConfigValue('Min_Password'); // for error message too + $min_length = $object->GetFieldOption($password_field, 'min_length', false, $min_length); + if (mb_strlen($new_password) < $min_length) { $error_msg = '+' . sprintf($this->Application->Phrase($phrase_error_prefix.'_passwords_too_short'), $min_length); // + -> not phrase $object->SetError($password_field, 'passwords_min_length', $error_msg); } } if ($value == '') { return $object->GetDBField($field_name); } if ($options['encryption_method'] == 'plain') { return $value; } return $this->EncryptPassword($value, $salt); } function EncryptPassword($value, $salt=null) { if (!isset($salt) || !$salt) { // if empty salt, assume, that it's not passed at all return md5($value); } return md5(md5($value).$salt); } } \ No newline at end of file Index: branches/5.2.x/core/kernel/utility/unit_config_reader.php =================================================================== --- branches/5.2.x/core/kernel/utility/unit_config_reader.php (revision 14183) +++ branches/5.2.x/core/kernel/utility/unit_config_reader.php (revision 14184) @@ -1,1147 +1,1046 @@ <?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 implements kiCacheable { /** * 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 = ''; /** * Regular expression for detecting module folder * * @var string */ var $_moduleFolderRegExp = ''; /** * Folders to skip during unit config search * * @var Array */ var $_skipFolders = Array ('CVS', '.svn', 'admin_templates', 'libchart'); /** * Creates instance of unit config reader * */ public function __construct() { parent::__construct(); $this->_directorySeparator = preg_quote(DIRECTORY_SEPARATOR); $editor_path = explode('/', trim(EDITOR_PATH, '/')); $this->_skipFolders[] = array_pop($editor_path); // last of cmseditor folders $this->_moduleFolderRegExp = '#' . $this->_directorySeparator . '(core|modules' . $this->_directorySeparator . '.*?)' . $this->_directorySeparator . '#'; } /** * Sets data from cache to object * * @param Array $data * @access public */ public function setFromCache(&$data) { $this->prefixFiles = $data['ConfigReader.prefixFiles']; } /** * Gets object data for caching * * @access public * @return Array */ public function getToCache() { return Array ( 'ConfigReader.prefixFiles' => $this->prefixFiles, ); } - function CacheParsedData() - { - $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); - /* @var $aggregator kArray */ - - $this->preloadConfigVars(); // preloading will put to cache - - $cache = array_merge( - $this->Application->Factory->getToCache(), - $this->getToCache(), - $this->Application->EventManager->getToCache(), - $aggregator->getToCache(), - $this->Application->getToCache() - ); - - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $this->Application->setCache('master:configs_parsed', serialize($cache)); - $this->Application->setCache('master:config_files', serialize($this->configFiles)); - } - else { - $this->Application->setDBCache('configs_parsed', serialize($cache)); - $this->Application->setDBCache('config_files', serialize($this->configFiles)); - } - - $cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s'); - $this->Application->setDBCache('last_cache_rebuild', $cache_rebuild_by); - - unset($this->configFiles); - } - - function preloadConfigVars() - { - $config_vars = Array ( - // session related - 'SessionTimeout', - 'SessionCookieName', - 'SessionCookieDomains', - 'SessionBrowserSignatureCheck', - 'SessionIPAddressCheck', - 'CookieSessions', - 'KeepSessionOnBrowserClose', - 'User_GuestGroup', - 'User_LoggedInGroup', - - // output related - 'UseModRewrite', - 'UseContentLanguageNegotiation', - 'UseOutputCompression', - 'OutputCompressionLevel', - 'Config_Site_Time', - 'SystemTagCache', - - // tracking related - 'UseChangeLog', - 'UseVisitorTracking', - 'ModRewriteUrlEnding', - 'ForceModRewriteUrlEnding', - 'UseCronForRegularEvent', - ); - - foreach ($config_vars as $var) { - $this->Application->ConfigValue($var); - } - } - - function RestoreParsedData() - { - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $data = $this->Application->getCache('master:configs_parsed', false); - } - else { - $data = $this->Application->getDBCache('configs_parsed'); - } - - if ($data) { - $cache = unserialize($data); // 126 KB all modules - unset($data); - - $this->Application->Factory->setFromCache($cache); - $this->setFromCache($cache); - $this->Application->EventManager->setFromCache($cache); - - $aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray'); - /* @var $aggregator kArray */ - - $aggregator->setFromCache($cache); - $this->Application->setFromCache($cache); - unset($cache); - - return true; - - } - - return false; - } - - function ResetParsedData($include_sections = false) - { - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $this->Application->deleteCache('master:configs_parsed'); - } - else { - $this->Application->deleteDBCache('configs_parsed'); - } - - if ($include_sections) { - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $this->Application->deleteCache('master:sections_parsed'); - } - else { - $this->Application->deleteDBCache('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(); + $restored = $this->Application->cacheManager->LoadUnitCache(); + if ($restored) { if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) { $this->Application->Debugger->appendHTML('UnitConfigReader: Restoring Cache'); } return; } } if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) { $this->Application->Debugger->appendHTML('UnitConfigReader: Generating Cache'); } $this->ProcessAllConfigs = true; $this->includeConfigFiles($folderPath, $cache); $this->ParseConfigs(); // tell AfterConfigRead to store cache if needed // can't store it here beacuse AfterConfigRead needs ability to change config data $this->StoreCache = $cache; } function findConfigFiles($folderPath, $level = 0) { // 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); } } function includeConfigFiles($folderPath, $cache = true) { $this->Application->refreshModuleInfo(); if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->getCache('master:config_files', false); } else { $data = $this->Application->getDBCache('config_files'); } - if ($cache && $data) { + if ($data) { $this->configFiles = unserialize($data); if ( !defined('DBG_VALIDATE_CONFIGS') && !DBG_VALIDATE_CONFIGS ) { shuffle($this->configFiles); } } else { $this->findConfigFiles(FULL_PATH . DIRECTORY_SEPARATOR . 'core'); // search from core directory $this->findConfigFiles($folderPath); // search from modules directory + + if ($cache) { + if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { + $this->Application->setCache('master:config_files', serialize($this->configFiles)); + } + else { + $this->Application->setDBCache('config_files', serialize($this->configFiles)); + } + } } foreach ($this->configFiles as $filename) { $prefix = $this->PreloadConfigFile($filename); if (!$prefix) { throw new Exception('Prefix not defined in config file <strong>' . $filename . '</strong>'); } } + + if ($cache) { + unset($this->configFiles); + } } /** * 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) { $this->runAfterConfigRead($prefix); } - if (!isset($store_cache)) { + 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(); $after_event = new kEvent('adm:OnAfterCacheRebuild'); $this->Application->HandleEvent($after_event); - $this->CacheParsedData(); + $this->Application->cacheManager->UpdateUnitCache(); 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); } } } } /** * 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, 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->AfterConfigProcessed = Array (); $this->includeConfigFiles(MODULES_PATH, false); $this->ParseConfigs(); $this->AfterConfigRead(false); $this->processDynamicClones(); // don't call kUnitConfigReader::retrieveCollections since it // will overwrite what we already have in kApplication class instance } /** * 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) { $this->runAfterConfigRead($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_listeners = $config['RewriteListener']; if (!is_array($rewrite_listeners)) { // when one method is used to build and parse url $rewrite_listeners = Array ($rewrite_listeners, $rewrite_listeners); } foreach ($rewrite_listeners as $index => $rewrite_listener) { if (strpos($rewrite_listener, ':') === false) { $rewrite_listeners[$index] = $prefix . '_EventHandler:' . $rewrite_listener; } } $rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false; $this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listeners, 'priority' => $rewrite_priority); } } } /** * Register nessasary classes * This method should only process the data which is cached! * * @param string $prefix * @access private */ function parseConfig($prefix) { $this->parseClasses($prefix); $this->parseAgents($prefix); $this->parseHooks($prefix); $this->parseAggregatedTags($prefix); } protected function parseClasses($prefix) { $config =& $this->configData[$prefix]; $register_classes = $this->getClasses($prefix); foreach ($register_classes as $class_info) { // remember class dependencies $class_name = $class_info['class']; $require_classes = isset($class_info['require_classes']) ? $class_info['require_classes'] : Array (); if ($require_classes) { $require_classes = (array)$require_classes; if ( !isset($config['_Dependencies'][$class_name]) ) { $config['_Dependencies'][$class_name] = Array (); } $config['_Dependencies'][$class_name] = array_merge($config['_Dependencies'][$class_name], $require_classes); } // register class $this->Application->registerClass( $class_name, $config['BasePath'] . DIRECTORY_SEPARATOR . $class_info['file'], $class_info['pseudo'] ); if ( isset($class_info['build_event']) && $class_info['build_event'] ) { $this->Application->EventManager->registerBuildEvent($class_info['pseudo'], $class_info['build_event']); } } } protected function parseAgents($prefix) { $config =& $this->configData[$prefix]; if ( !isset($config['RegularEvents']) || !$config['RegularEvents'] ) { return ; } $regular_events = $config['RegularEvents']; foreach ($regular_events as $short_name => $regular_event_info) { $event_status = array_key_exists('Status', $regular_event_info) ? $regular_event_info['Status'] : STATUS_ACTIVE; $this->Application->EventManager->registerAgent( $short_name, $config['Prefix'] . ':' . $regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'], $event_status ); } } protected function parseHooks($prefix) { $config =& $this->configData[$prefix]; if ( !isset($config['Hooks']) || !$config['Hooks'] ) { return ; } $hooks = $config['Hooks']; foreach ($hooks as $hook) { if ( isset($config['ParentPrefix']) && ($hook['HookToPrefix'] == $config['ParentPrefix']) ) { trigger_error('Depricated Hook Usage [prefix: <strong>' . $config['Prefix'] . '</strong>; do_prefix: <strong>' . $hook['DoPrefix'] . '</strong>] use <strong>#PARENT#</strong> as <strong>HookToPrefix</strong> value, where HookToPrefix is same as ParentPrefix', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_NOTICE); } if ($hook['HookToPrefix'] == '') { // new: set hooktoprefix to current prefix if not set $hook['HookToPrefix'] = $config['Prefix']; } 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#') { // we need parent prefix but it's not set ! continue; } $hook_events = (array)$hook['HookToEvent']; $do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix']; foreach ($hook_events as $hook_event) { $hook_event = $hook['HookToPrefix'] . '.' . $hook['HookToSpecial'] . ':' . $hook_event; $do_event = $do_prefix . '.' . $hook['DoSpecial'] . ':' . $hook['DoEvent']; $this->Application->registerHook($hook_event, $do_event, $hook['Mode'], $hook['Conditional']); } } } protected function parseAggregatedTags($prefix) { $config =& $this->configData[$prefix]; $aggregated_tags = isset($config['AggregateTags']) ? $config['AggregateTags'] : Array (); foreach ($aggregated_tags 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', defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : 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'); $table_found = $this->Conn->Query('SHOW TABLES LIKE "'.$tablename.'"'); if (!$table_found) { // config present, but table missing, strange kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1); $debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Table <strong>$tablename</strong> missing, but prefix <b>".$config['Prefix']."</b> requires it!"); $debugger->WarningCount++; return ; } $res = $this->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)', 'date_column_not_null_error' => 'Field <strong>%s</strong> must be NULL in config and database, since it contains date', 'user_column_default_error' => 'Field <strong>%s</strong> must be have NULL as default value, since it holds user id', 'type_missing' => '<strong>Type definition</strong> for field <strong>%s</strong> missing in config', 'virtual_type_missing' => '<strong>Type definition</strong> for virtual field <strong>%s</strong> missing in config', 'virtual_default_missing' => 'Default value for virtual field <strong>%s</strong> not set in config', 'virtual_not_null_error' => 'Virtual field <strong>%s</strong> cannot be not null, since it doesn\'t exist in database', 'invalid_calculated_field' => 'Calculated field <strong>%s</strong> is missing corresponding virtual field', ); $config_errors = Array (); $tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix // validate unit config field declaration in relation to database table structure 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 { $db_default = $field['Default']; if (is_numeric($db_default)) { $db_default = preg_match('/[\.,]/', $db_default) ? (float)$db_default : (int)$db_default; } $default_missing = false; $options = $config['Fields'][$f_name]; $not_null = isset($options['not_null']) && $options['not_null']; $formatter = array_key_exists('formatter', $options) ? $options['formatter'] : 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 ($not_null && !isset($options['default']) ) { $config_errors[] = sprintf($error_messages['not_null_error2'], $f_name); } } elseif ($not_null) { $config_errors[] = sprintf($error_messages['not_null_error3'], $f_name); } if (($formatter == 'kDateFormatter') && $not_null) { $config_errors[] = sprintf($error_messages['date_column_not_null_error'], $f_name); } // columns, holding userid should have NULL as default value if (array_key_exists('type', $options) && !$default_missing) { // both type and default value set if (preg_match('/ById$/', $f_name) && $options['default'] !== null) { $config_errors[] = sprintf($error_messages['user_column_default_error'], $f_name); } } if (!array_key_exists('type', $options)) { $config_errors[] = sprintf($error_messages['type_missing'], $f_name); } if (!$default_missing && ($field['Type'] != 'text')) { if ( is_null($db_default) && $not_null ) { $db_default = $options['type'] == 'string' ? '' : 0; } 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 (((string)$options['default'] != '#NOW#') && ($db_default !== $options['default']) && !in_array($options['type'], $float_types)) { $config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($db_default)); } } } } } // validate virtual fields if ( array_key_exists('VirtualFields', $config) ) { foreach ($config['VirtualFields'] as $f_name => $options) { if (!array_key_exists('type', $options)) { $config_errors[] = sprintf($error_messages['virtual_type_missing'], $f_name); } if (array_key_exists('not_null', $options)) { $config_errors[] = sprintf($error_messages['virtual_not_null_error'], $f_name); } if (!array_key_exists('default', $options)) { $config_errors[] = sprintf($error_messages['virtual_default_missing'], $f_name); } } } // validate calculated fields if ( array_key_exists('CalculatedFields', $config) ) { foreach ($config['CalculatedFields'] as $special => $calculated_fields) { foreach ($calculated_fields as $calculated_field => $calculated_field_expr) { if ( !isset($config['VirtualFields'][$calculated_field]) ) { $config_errors[] = sprintf($error_messages['invalid_calculated_field'], $calculated_field); } } } $config_errors = array_unique($config_errors); } 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); kUtil::safeDefine('DBG_RAISE_ON_WARNINGS', 1); $debugger->appendHTML($config_errors); $debugger->WarningCount++; } } function varDump($value) { return '<strong>'.var_export($value, true).'</strong> of '.gettype($value); } protected 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] = kUtil::array_merge_recursive($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->_moduleFolderRegExp, $filename, $rets); $config['ModuleFolder'] = str_replace(DIRECTORY_SEPARATOR, '/', $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' ? '' : substr($rets[1], 8) . '/'; $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]) ) { throw new Exception('Configuration file for prefix <strong>' . $prefix . '</strong> is unknown'); return ; } $file = $this->prefixFiles[$prefix]; $prefix = $this->PreloadConfigFile($file); if ($this->FinalStage) { // run prefix OnAfterConfigRead so all // hooks to it can define their clonses $this->runAfterConfigRead($prefix); } $clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix'); $clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones); if ($this->FinalStage) { $clones = array_unique($clones); foreach ($clones as $a_prefix) { $this->runAfterConfigRead($a_prefix); } } } function runAfterConfigRead($prefix) { if (in_array($prefix, $this->AfterConfigProcessed)) { return ; } $this->Application->HandleEvent( new kEvent($prefix . ':OnAfterConfigRead') ); if (!(defined('IS_INSTALL') && IS_INSTALL)) { // allow to call OnAfterConfigRead multiple times during install array_push($this->AfterConfigProcessed, $prefix); } } /** * 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; } } protected function getClasses($prefix) { $config =& $this->configData[$prefix]; $class_params = Array ('ItemClass', 'ListClass', 'EventHandlerClass', 'TagProcessorClass'); $register_classes = isset($config['RegisterClasses']) ? $config['RegisterClasses'] : Array (); foreach ($class_params as $param_name) { if ( !isset($config[$param_name]) ) { continue; } $config[$param_name]['pseudo'] = $this->getPseudoByOptionName($param_name, $prefix); $register_classes[] = $config[$param_name]; } return $register_classes; } protected function getPseudoByOptionName($option_name, $prefix) { $pseudo_class_map = Array ( 'ItemClass' => '%s', 'ListClass' => '%s_List', 'EventHandlerClass' => '%s_EventHandler', 'TagProcessorClass' => '%s_TagProcessor' ); return sprintf($pseudo_class_map[$option_name], $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) { static $module_paths = null; 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 . 'core#', $config_path)) { // always allow to include configs from "core" module's folder return true; } if (!$this->Application->ModuleInfo) { return false; } if (!isset($module_paths)) { $module_paths = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $module_paths[] = str_replace('/', DIRECTORY_SEPARATOR, rtrim($module_info['Path'], '/')); } $module_paths = array_unique($module_paths); } preg_match($this->_moduleFolderRegExp, $config_path, $rets); // config file path starts with module folder path return in_array($rets[1], $module_paths); } /** * 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.2.x/core/kernel/languages/phrases_cache.php =================================================================== --- branches/5.2.x/core/kernel/languages/phrases_cache.php (revision 14183) +++ branches/5.2.x/core/kernel/languages/phrases_cache.php (revision 14184) @@ -1,383 +1,341 @@ <?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 PhrasesCache extends kBase { var $Phrases = Array(); var $Ids = Array(); var $OriginalIds = Array(); //for comparing cache var $LanguageId = null; /** * Administrator's language, when visiting site (from frame) * * @var int */ var $AdminLanguageId = null; var $fromTag = false; /** * Allows to edit existing phrases * * @var bool */ var $_editExisting = false; /** * Allows to edit missing phrases * * @var bool */ var $_editMissing = false; /** * Template, used for phrase adding/editing * * @var string */ var $_phraseEditTemplate = 'languages/phrase_edit'; /** * Use simplified form for phrase editing * * @var bool */ var $_simpleEditingMode = false; /** * HTML tag used to translate phrases * * @var string */ var $_translateHtmlTag = 'a'; /** * Phrases, that are in cache, but are not in database * * @var Array */ var $_missingPhrases = Array (); /** * Mask for editing link * * @var string */ var $_editLinkMask = ''; /** * Escape phrase name, before placing it in javascript translation link * @var bool */ var $_escapePhraseName = true; /** * Sets phrase editing mode, that corresponds current editing mode * */ function setPhraseEditing() { if (!$this->Application->isAdmin && (EDITING_MODE == EDITING_MODE_CONTENT)) { // front-end viewed in content mode $this->_editExisting = true; $this->_editMissing = true; $this->_simpleEditingMode = true; $this->_translateHtmlTag = 'span'; } $this->_editLinkMask = 'javascript:translate_phrase(\'#LABEL#\', \'' . $this->_phraseEditTemplate . '\', {event: \'OnPreparePhrase\', simple_mode: ' . ($this->_simpleEditingMode ? 'true' : 'false') . '});'; if (defined('DEBUG_MODE') && DEBUG_MODE && !$this->Application->GetVar('admin')) { // admin and front-end while not viewed using content mode (via admin) $this->_editMissing = defined('DBG_PHRASES') && DBG_PHRASES; if (!$this->Application->isAdmin) { $this->_phraseEditTemplate = 'phrases_edit'; $url_params = Array ( 'm_opener' => 'd', 'phrases_label' => '#LABEL#', 'phrases_event' => 'OnPreparePhrase', 'pass' => 'm,phrases' ); $this->_escapePhraseName = false; $this->_editLinkMask = $this->Application->HREF($this->_phraseEditTemplate, '', $url_params); } } } /** * Loads phrases from current language * Method is called manually (not from kFactory class) too * * @param string $prefix * @param string $special + * @param int $language_id + * @param Array $phrase_ids */ - public function Init($prefix, $special = '') + public function Init($prefix, $special = '', $language_id = null, $phrase_ids = null) { parent::Init($prefix, $special); if (kUtil::constOn('IS_INSTALL')) { $this->LanguageId = 1; } else { - if ($this->Application->isAdmin) { - $this->LanguageId = $this->Application->Session->GetField('Language'); - } - else { - $this->LanguageId = $this->Application->GetVar('m_lang'); - - if ($this->Application->GetVar('admin')) { - $admin_session =& $this->Application->recallObject('Session.admin'); - /* @var $admin_session Session */ - - $this->AdminLanguageId = $admin_session->GetField('Language'); + if ( !isset($language_id) ) { + if ($this->Application->isAdmin) { + $language_id = $this->Application->Session->GetField('Language'); + } + else { + $language_id = $this->Application->GetVar('m_lang'); } } - } - if (isset($this->Application->Caches['PhraseList'])) { - $this->LoadPhrases( $this->Application->Caches['PhraseList'] ); - } - } + $this->LanguageId = $language_id; - function GetCachedIds() - { - $cache_key = md5($this->Application->GetVar('t') . $this->Application->GetVar('m_theme') . $this->Application->GetVar('m_lang')); - - $sql = 'SELECT PhraseList, ConfigVariables - FROM ' . TABLE_PREFIX . 'PhraseCache - WHERE Template = ' . $this->Conn->qstr($cache_key); - $res = $this->Conn->GetRow($sql); + if (!$this->Application->isAdmin && $this->Application->GetVar('admin')) { + $admin_session =& $this->Application->recallObject('Session.admin'); + /* @var $admin_session Session */ - if ($res && $res['ConfigVariables']) { - $this->Application->OriginalConfigCacheIds = explode(',', $res['ConfigVariables']); - $this->Application->ConfigCacheIds = $this->Application->OriginalConfigCacheIds; + $this->AdminLanguageId = $admin_session->GetField('Language'); + } } - return ($res === false) ? Array() : explode(',', $res['PhraseList']); + $this->LoadPhrases($phrase_ids); } function LoadPhrases($ids) { if ( !is_array($ids) || !implode('', $ids) ) { - return; + return ; } $sql = 'SELECT l' . $this->LanguageId . '_Translation, PhraseKey FROM ' . TABLE_PREFIX . 'Phrase WHERE PhraseId IN (' . implode(',', $ids) . ') AND l' . $this->LanguageId . '_Translation IS NOT NULL'; $this->Phrases = $this->Conn->GetCol($sql, 'PhraseKey'); - /*foreach($phrases as $phrase => $tanslation) - { - $this->AddCachedPhrase(mb_strtoupper($phrase), $tanslation); - }*/ - - $this->Ids = $ids; - $this->OriginalIds = $ids; + $this->Ids = $this->OriginalIds = $ids; } function AddCachedPhrase($label, $value, $allow_editing = true) { // uppercase phrase name for cases, when this method is called outside this class $cache_key = ($allow_editing ? '' : 'NE:') . mb_strtoupper($label); $this->Phrases[$cache_key] = $value; } function NeedsCacheUpdate() { return is_array($this->Ids) && count($this->Ids) > 0 && $this->Ids != $this->OriginalIds; } - /** - * Copy from Application->UpdateCache method - * - * @deprecated - */ - function UpdateCache() - { - $update = false; - //something changed - $update = $update || (is_array($this->Ids) && count($this->Ids) > 0 && $this->Ids != $this->OriginalIds); - $update = $update || (count($this->Application->ConfigCacheIds) && $this->Application->ConfigCacheIds != $this->Application->OriginalConfigCacheIds); - if ($update) { - $query = sprintf("REPLACE %s (PhraseList, CacheDate, Template, ConfigVariables) - VALUES (%s, %s, %s, %s)", - TABLE_PREFIX.'PhraseCache', - $this->Conn->Qstr(join(',', $this->Ids)), - adodb_mktime(), - $this->Conn->Qstr(md5($this->Application->GetVar('t').$this->Application->GetVar('m_theme').$this->Application->GetVar('m_lang'))), - $this->Conn->qstr(implode(',', array_unique($this->Application->ConfigCacheIds)))); - $this->Conn->Query($query); - } - } - function GetPhrase($label, $allow_editing = true, $use_admin = false) { if (!isset($this->LanguageId)) { //actually possible when custom field contains references to language labels and its being rebuilt in OnAfterConfigRead //which is triggered by Sections rebuild, which in turn read all the configs and all of that happens BEFORE seeting the language... return 'impossible case'; } // cut exclamation marks - depricated form of passing phrase name from templates $label = preg_replace('/^!(.*)!$/', '\\1', $label); if (strlen($label) == 0) { return ''; } $original_label = $this->_escapePhraseName ? addslashes($label) : $label; $label = mb_strtoupper($label); $cache_key = ($allow_editing ? '' : 'NE:') . $label; if (array_key_exists($cache_key, $this->Phrases)) { $translated_label = $this->Phrases[$cache_key]; if ($this->_editExisting && $allow_editing && !array_key_exists($label, $this->_missingPhrases)) { // option to change translation for Labels $edit_url = 'javascript:translate_phrase(\'' . $original_label . '\', \'' . $this->_phraseEditTemplate . '\', {event: \'OnPreparePhrase\', simple_mode: ' . ($this->_simpleEditingMode ? 'true' : 'false') . '});'; $translated_label = '<' . $this->_translateHtmlTag . ' href="' . $edit_url . '" name="cms-translate-phrase" title="Edit translation">' . $translated_label . '</' . $this->_translateHtmlTag . '>'; if ($this->fromTag) { $translated_label = $this->escapeTagReserved($translated_label); } } return $translated_label; } $this->LoadPhraseByLabel($label, $original_label, $allow_editing, $use_admin); return $this->GetPhrase($label, $allow_editing); } function LoadPhraseByLabel($label, $original_label, $allow_editing = true, $use_admin = false) { if (!$allow_editing && !$use_admin && !array_key_exists($label, $this->_missingPhrases) && array_key_exists($label, $this->Phrases)) { // label is aready translated, but it's version without on the fly translation code is requested $this->Phrases['NE:' . $label] = $this->Phrases[$label]; return true; } $language_id = $use_admin ? $this->AdminLanguageId : $this->LanguageId; $sql = 'SELECT PhraseId, l' . $language_id . '_Translation FROM ' . TABLE_PREFIX . 'Phrase WHERE (PhraseKey = ' . $this->Conn->qstr($label) . ') AND (l' . $language_id . '_Translation IS NOT NULL)'; $res = $this->Conn->GetRow($sql); if ($res === false || count($res) == 0) { $translation = '!' . $label . '!'; if ($this->_editMissing && $allow_editing) { $edit_url = str_replace('#LABEL#', $original_label, $this->_editLinkMask); $translation = '<' . $this->_translateHtmlTag . ' href="' . $edit_url . '" name="cms-translate-phrase" title="Translate">!' . $label . '!</' . $this->_translateHtmlTag . '>'; if ($this->fromTag) { $translation = $this->escapeTagReserved($translation); } $this->_missingPhrases[$label] = true; // add as key for faster accessing } // add it as already cached, as long as we dont need to cache not found phrase $this->AddCachedPhrase($label, $translation, $allow_editing); return false; } $cache_key = ($allow_editing ? '' : 'NE:') . $label; $this->Phrases[$cache_key] = $res['l' . $language_id . '_Translation']; array_push($this->Ids, $res['PhraseId']); $this->Ids = array_unique($this->Ids); // just to make sure return true; } /** * Sort params by name and then by length * * @param string $a * @param string $b * @return int * @access private */ function CmpParams($a, $b) { $a_len = mb_strlen($a); $b_len = mb_strlen($b); if ($a_len == $b_len) return 0; return $a_len > $b_len ? -1 : 1; } /** * 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, $forse_escaping = null) { $this->fromTag = true; if( isset($forse_escaping) ) { $this->fromTag = $forse_escaping; } preg_match_all("(!(la|lu)[^!]+!)", $text, $res, PREG_PATTERN_ORDER); $language_tags = $res[0]; uasort($language_tags, Array(&$this, 'CmpParams')); $i = 0; $values = Array(); foreach ($language_tags as $label) { array_push($values, $this->GetPhrase($label) ); //array_push($values, $this->Application->Phrase($label) ); $language_tags[$i] = '/' . $language_tags[$i] . '/'; $i++; } $this->fromTag = false; return preg_replace($language_tags, $values, $text); } /** * Escape chars in phrase translation, that could harm parser to process tag * * @param string $text * @return string * @access private */ function escapeTagReserved($text) { $reserved = Array('"',"'"); // = $replacement = Array('\"',"\'"); // \= return str_replace($reserved,$replacement,$text); } } \ No newline at end of file Index: branches/5.2.x/core/kernel/globals.php =================================================================== --- branches/5.2.x/core/kernel/globals.php (revision 14183) +++ branches/5.2.x/core/kernel/globals.php (revision 14184) @@ -1,717 +1,717 @@ <?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 kUtil { // const KG_TO_POUND = 2.20462262; const POUND_TO_KG = 0.45359237; /** * Similar to array_merge_recursive but keyed-valued are always overwritten. * Priority goes to the 2nd array. * * @param $paArray1 array * @param $paArray2 array * @return array * @access public */ public static function array_merge_recursive($paArray1, $paArray2) { if (!is_array($paArray1) or !is_array($paArray2)) { return $paArray2; } foreach ($paArray2 AS $sKey2 => $sValue2) { $paArray1[$sKey2] = isset($paArray1[$sKey2]) ? self::array_merge_recursive($paArray1[$sKey2], $sValue2) : $sValue2; } return $paArray1; } /** * Prepend a reference to an element to the beginning of an array. * Renumbers numeric keys, so $value is always inserted to $array[0] * * @param $array array * @param $value mixed * @return int * @access public */ public static function array_unshift_ref(&$array, &$value) { $return = array_unshift($array,''); $array[0] =& $value; return $return; } /** * Rename key in associative array, maintaining keys order * * @param Array $array Associative Array * @param mixed $old Old key name * @param mixed $new New key name * @access public */ public static function array_rename_key(&$array, $old, $new) { $new_array = Array (); foreach ($array as $key => $val) { $new_array[ $key == $old ? $new : $key] = $val; } $array = $new_array; } /** * Same as print_r, but outputs result on screen or in debugger report (when in debug mode) * * @param Array $data * @param string $label * @param bool $on_screen * @access public */ public static function print_r($data, $label = '', $on_screen = false) { $is_debug = false; if (class_exists('kApplication') && !$on_screen) { $application =& kApplication::Instance(); $is_debug = $application->isDebugMode(); } if ($is_debug) { if ($label) { $application->Debugger->appendHTML('<strong>' . $label . '</strong>'); } $application->Debugger->dumpVars($data); } else { if ($label) { echo '<strong>' . $label . '</strong><br/>'; } echo '<pre>', print_r($data, true), '</pre>'; } } /** * Define constant if it was not already defined before * * @param string $const_name * @param string $const_value * @access public */ public static function safeDefine($const_name, $const_value) { if ( !defined($const_name) ) { define($const_name, $const_value); } } /** * Parses "/system/config.php" file and returns the result * * @param bool $parse_section * @return Array * @access public */ public static function parseConfig($parse_section = false) { $file = FULL_PATH . DIRECTORY_SEPARATOR . 'system' . DIRECTORY_SEPARATOR . 'config.php'; if (!file_exists($file)) { return Array (); } if (file_exists($file) && !is_readable($file)) { die('Could Not Open Ini File'); } $contents = file($file); if ($contents && $contents[0] == '<' . '?' . 'php die() ?' . ">\n") { // format of "config.php" file before 5.1.0 version array_shift($contents); return parse_ini_string(implode('', $contents), $parse_section); } $_CONFIG = Array (); require($file); if ($parse_section) { return $_CONFIG; } $ret = Array (); foreach ($_CONFIG as $section => $section_variables) { $ret = array_merge($ret, $section_variables); } return $ret; } /** * Returns parsed variables from "config.php" file * * @return Array * @access public */ public static function getConfigVars() { static $vars = null; if ( !isset($vars) ) { $vars = self::parseConfig(); } return $vars; } /** * Same as "include_once", but also profiles file includes in debug mode and DBG_PROFILE_INCLUDES constant is set * * @param string $file * @access public */ public static function includeOnce($file) { global $debugger; if ( defined('DEBUG_MODE') && DEBUG_MODE && isset($debugger) && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES ) { if ( in_array($file, get_required_files()) ) { return ; } global $debugger; /*$debugger->IncludeLevel++; $before_mem = memory_get_usage();*/ $debugger->ProfileStart('inc_'.crc32($file), $file); include_once($file); $debugger->ProfileFinish('inc_'.crc32($file)); $debugger->profilerAddTotal('includes', 'inc_'.crc32($file)); /*$used_mem = memory_get_usage() - $before_mem; $debugger->IncludeLevel--; $debugger->IncludesData['file'][] = str_replace(FULL_PATH, '', $file); $debugger->IncludesData['mem'][] = $used_mem; $debugger->IncludesData['time'][] = $used_time; $debugger->IncludesData['level'][] = $debugger->IncludeLevel;*/ } else { include_once($file); } } /** * Checks if given string is a serialized array * * @param string $string * @return bool * @access public */ public static function IsSerialized($string) { if ( is_array($string) ) { return false; } return preg_match('/a:([\d]+):{/', $string); } /** * Generates password of given length * * @param int $length * @return string * @access public */ public static function generatePassword($length = 10) { $pass_length = $length; $p1 = Array ('b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z'); $p2 = Array ('a','e','i','o','u'); $p3 = Array ('1','2','3','4','5','6','7','8','9'); $p4 = Array ('(','&',')',';','%'); // if you need real strong stuff // how much elements in the array // can be done with a array count but counting once here is faster $s1 = 21;// this is the count of $p1 $s2 = 5; // this is the count of $p2 $s3 = 9; // this is the count of $p3 $s4 = 5; // this is the count of $p4 // possible readable combinations $c1 = '121'; // will be like 'bab' $c2 = '212'; // will be like 'aba' $c3 = '12'; // will be like 'ab' $c4 = '3'; // will be just a number '1 to 9' if you dont like number delete the 3 //$c5 = '4'; // uncomment to active the strong stuff $comb = '4'; // the amount of combinations you made above (and did not comment out) for ($p = 0; $p < $pass_length;) { mt_srand((double)microtime() * 1000000); $strpart = mt_rand(1, $comb); // checking if the stringpart is not the same as the previous one if ($strpart != $previous) { $pass_structure .= ${'c' . $strpart}; // shortcutting the loop a bit $p = $p + mb_strlen(${'c' . $strpart}); } $previous = $strpart; } // generating the password from the structure defined in $pass_structure for ($g = 0; $g < mb_strlen($pass_structure); $g++) { mt_srand((double)microtime() * 1000000); $sel = mb_substr($pass_structure, $g, 1); $pass .= ${'p' . $sel}[ mt_rand(0,-1+${'s'.$sel}) ]; } return $pass; } /** * Reverts effects of "htmlspecialchars" function * * @param string $string * @return string * @access public */ public static function unhtmlentities($string) { - $trans_tbl = get_html_translation_table(HTML_ENTITIES); + $trans_tbl = get_html_translation_table(HTML_ENTITIES); // from PHP 5.3.4: , ENT_COMPAT, 'utf-8'); $trans_tbl = array_flip ($trans_tbl); return strtr($string, $trans_tbl); } /** * submits $url with $post as POST * * @param string $url * @param mixed $data * @return string * @access public * @deprecated */ public static function curl_post($url, $data, $headers = null, $request_type = 'POST', $curl_options = null) { $application =& kApplication::Instance(); $curl_helper =& $application->recallObject('CurlHelper'); /* @var $curl_helper kCurlHelper */ if ($request_type == 'POST') { $curl_helper->SetRequestMethod(kCurlHelper::REQUEST_METHOD_POST); } $curl_helper->SetRequestData($data); if (!is_null($headers)) { // not an associative array, so don't use kCurlHelper::SetHeaders method $curl_helper->setOptions( Array (CURLOPT_HTTPHEADER => $headers) ); } if (is_array($curl_options)) { $curl_helper->setOptions($curl_options); } $curl_helper->followLocation = false; $ret = $curl_helper->Send($url); $GLOBALS['curl_errorno'] = $curl_helper->lastErrorCode; $GLOBALS['curl_error'] = $curl_helper->lastErrorMsg; return $ret; } /** * Checks if constant is defined and has positive value * * @param string $const_name * @return bool * @access public */ public static function constOn($const_name) { return defined($const_name) && constant($const_name); } /** * Converts KG to Pounds * * @param float $kg * @param bool $pounds_only * @return float * @access public */ public static function Kg2Pounds($kg, $pounds_only = false) { $major = floor( round($kg / self::POUND_TO_KG, 3) ); $minor = abs(round(($kg - $major * self::POUND_TO_KG) / self::POUND_TO_KG * 16, 2)); if ($pounds_only) { $major += round($minor * 0.0625, 2); $minor = 0; } return array($major, $minor); } /** * Converts Pounds to KG * * @param float $pounds * @param float $ounces * @return float * @access public */ public static function Pounds2Kg($pounds, $ounces=0) { return round(($pounds + ($ounces / 16)) * self::POUND_TO_KG, 5); } /** * Formats file/memory size in nice way * * @param int $bytes * @return string * @access public */ public static function formatSize($bytes) { if ($bytes >= 1099511627776) { $return = round($bytes / 1024 / 1024 / 1024 / 1024, 2); $suffix = "TB"; } elseif ($bytes >= 1073741824) { $return = round($bytes / 1024 / 1024 / 1024, 2); $suffix = "GB"; } elseif ($bytes >= 1048576) { $return = round($bytes / 1024 / 1024, 2); $suffix = "MB"; } elseif ($bytes >= 1024) { $return = round($bytes / 1024, 2); $suffix = "KB"; } else { $return = $bytes; $suffix = "Byte"; } $return .= ' '.$suffix; return $return; } /** * Enter description here... * * @param resource $filePointer the file resource to write to * @param Array $data the data to write out * @param string $delimiter the field separator * @param string $enclosure symbol to enclose field data to * @param string $recordSeparator symbols to separate records with * @access public */ public static function fputcsv($filePointer, $data, $delimiter = ',', $enclosure = '"', $recordSeparator = "\r\n") { foreach($data as $field_index => $field_value) { // replaces an enclosure with two enclosures $data[$field_index] = str_replace($enclosure, $enclosure.$enclosure, $field_value); } $line = $enclosure.implode($enclosure.$delimiter.$enclosure, $data).$enclosure.$recordSeparator; $line = preg_replace('/'.preg_quote($enclosure, '/').'([0-9\.]+)'.preg_quote($enclosure, '/').'/', '$1', $line); fwrite($filePointer, $line); } /** * Enter description here... * * @param resource $filePointer the file resource to write to * @param Array $data the data to write out * @param string $delimiter the field separator * @param string $enclosure symbol to enclose field data to * @param string $recordSeparator symbols to separate records with * @access public */ public static function getcsvline($data, $delimiter = ',', $enclosure = '"', $recordSeparator = "\r\n") { foreach($data as $field_index => $field_value) { // replaces an enclosure with two enclosures $data[$field_index] = str_replace($enclosure, $enclosure.$enclosure, $field_value); } $line = $enclosure.implode($enclosure.$delimiter.$enclosure, $data).$enclosure.$recordSeparator; $line = preg_replace('/'.preg_quote($enclosure, '/').'([0-9\.]+)'.preg_quote($enclosure, '/').'/', '$1', $line); return $line; } /** * Allows to replace #section# within any string with current section * * @param string $string * @return string * @access public */ public static function replaceModuleSection($string) { $application =& kApplication::Instance(); $module_section = $application->RecallVar('section'); if ($module_section) { // substitute section instead of #section# parameter in title preset name $module_section = explode(':', $module_section); $section = preg_replace('/(configuration|configure)_(.*)/i', '\\2', $module_section[count($module_section) == 2 ? 1 : 0]); $string = str_replace('#section#', mb_strtolower($section), $string); } return $string; } /** * Checks, that user IP address is within allowed range * * @param string $ip_list semi-column (by default) separated ip address list * @param string $separator ip address separator (default ";") * * @return bool * @access public */ public static function ipMatch($ip_list, $separator = ';') { if ( !isset($_SERVER['REMOTE_ADDR']) ) { // PHP CLI used -> never match return false; } $ip_match = false; $ip_addresses = $ip_list ? explode($separator, $ip_list) : Array (); foreach ($ip_addresses as $ip_address) { if (self::netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) { $ip_match = true; break; } } return $ip_match; } /** * Checks, that given ip belongs to given subnet * * @param string $network * @param string $ip * @return bool * @access public */ public static function netMatch($network, $ip) { $network = trim($network); $ip = trim($ip); if ($network == $ip) { // comparing two ip addresses directly return true; } $d = strpos($network, '-'); if ($d !== false) { // ip address range specified $from = ip2long(trim(substr($network, 0, $d))); $to = ip2long(trim(substr($network, $d + 1))); $ip = ip2long($ip); return ($ip >= $from && $ip <= $to); } elseif (strpos($network, '/') !== false) { // sigle subnet specified $ip_arr = explode('/', $network); if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) { $ip_arr[0] .= '.0'; // Alternate form 194.1.4/24 } $network_long = ip2long($ip_arr[0]); $x = ip2long($ip_arr[1]); $mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1])); $ip_long = ip2long($ip); return ($ip_long & $mask) == ($network_long & $mask); } return false; } } /** * Returns array value if key exists * Accepts infinite number of parameters * * @param Array $array searchable array * @param int $key array key * @return string */ function getArrayValue(&$array, $key) { $ret = isset($array[$key]) ? $array[$key] : false; if ($ret && func_num_args() > 2) { for ($i = 2; $i < func_num_args(); $i++) { $cur_key = func_get_arg($i); $ret = getArrayValue( $ret, $cur_key ); if ($ret === false) { break; } } } return $ret; } if ( !function_exists('parse_ini_string') ) { /** * Equivalent for "parse_ini_string" function available since PHP 5.3.0 * * @param string $ini * @param bool $process_sections * @param int $scanner_mode * @return Array */ function parse_ini_string($ini, $process_sections = false, $scanner_mode = null) { # Generate a temporary file. $tempname = tempnam('/tmp', 'ini'); $fp = fopen($tempname, 'w'); fwrite($fp, $ini); $ini = parse_ini_file($tempname, !empty($process_sections)); fclose($fp); @unlink($tempname); return $ini; } } if ( !function_exists('memory_get_usage') ) { // PHP 4.x and compiled without --enable-memory-limit option function memory_get_usage() { return -1; } } if ( !function_exists('imagecreatefrombmp') ) { // just in case if GD will add this function in future function imagecreatefrombmp($filename) { //Ouverture du fichier en mode binaire if (! $f1 = fopen($filename,"rb")) return FALSE; //1 : Chargement des ent�tes FICHIER $FILE = unpack("vfile_type/Vfile_size/Vreserved/Vbitmap_offset", fread($f1,14)); if ($FILE['file_type'] != 19778) return FALSE; //2 : Chargement des ent�tes BMP $BMP = unpack('Vheader_size/Vwidth/Vheight/vplanes/vbits_per_pixel'. '/Vcompression/Vsize_bitmap/Vhoriz_resolution'. '/Vvert_resolution/Vcolors_used/Vcolors_important', fread($f1,40)); $BMP['colors'] = pow(2,$BMP['bits_per_pixel']); if ($BMP['size_bitmap'] == 0) $BMP['size_bitmap'] = $FILE['file_size'] - $FILE['bitmap_offset']; $BMP['bytes_per_pixel'] = $BMP['bits_per_pixel']/8; $BMP['bytes_per_pixel2'] = ceil($BMP['bytes_per_pixel']); $BMP['decal'] = ($BMP['width']*$BMP['bytes_per_pixel']/4); $BMP['decal'] -= floor($BMP['width']*$BMP['bytes_per_pixel']/4); $BMP['decal'] = 4-(4*$BMP['decal']); if ($BMP['decal'] == 4) $BMP['decal'] = 0; //3 : Chargement des couleurs de la palette $PALETTE = array(); if ($BMP['colors'] < 16777216) { $PALETTE = unpack('V'.$BMP['colors'], fread($f1,$BMP['colors']*4)); } //4 : Cr�ation de l'image $IMG = fread($f1,$BMP['size_bitmap']); $VIDE = chr(0); $res = imagecreatetruecolor($BMP['width'],$BMP['height']); $P = 0; $Y = $BMP['height']-1; while ($Y >= 0) { $X=0; while ($X < $BMP['width']) { if ($BMP['bits_per_pixel'] == 24) $COLOR = unpack("V",substr($IMG,$P,3).$VIDE); elseif ($BMP['bits_per_pixel'] == 16) { $COLOR = unpack("n",substr($IMG,$P,2)); $COLOR[1] = $PALETTE[$COLOR[1]+1]; } elseif ($BMP['bits_per_pixel'] == 8) { $COLOR = unpack("n",$VIDE.substr($IMG,$P,1)); $COLOR[1] = $PALETTE[$COLOR[1]+1]; } elseif ($BMP['bits_per_pixel'] == 4) { $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1)); if (($P*2)%2 == 0) $COLOR[1] = ($COLOR[1] >> 4) ; else $COLOR[1] = ($COLOR[1] & 0x0F); $COLOR[1] = $PALETTE[$COLOR[1]+1]; } elseif ($BMP['bits_per_pixel'] == 1) { $COLOR = unpack("n",$VIDE.substr($IMG,floor($P),1)); if (($P*8)%8 == 0) $COLOR[1] = $COLOR[1] >>7; elseif (($P*8)%8 == 1) $COLOR[1] = ($COLOR[1] & 0x40)>>6; elseif (($P*8)%8 == 2) $COLOR[1] = ($COLOR[1] & 0x20)>>5; elseif (($P*8)%8 == 3) $COLOR[1] = ($COLOR[1] & 0x10)>>4; elseif (($P*8)%8 == 4) $COLOR[1] = ($COLOR[1] & 0x8)>>3; elseif (($P*8)%8 == 5) $COLOR[1] = ($COLOR[1] & 0x4)>>2; elseif (($P*8)%8 == 6) $COLOR[1] = ($COLOR[1] & 0x2)>>1; elseif (($P*8)%8 == 7) $COLOR[1] = ($COLOR[1] & 0x1); $COLOR[1] = $PALETTE[$COLOR[1]+1]; } else return FALSE; imagesetpixel($res,$X,$Y,$COLOR[1]); $X++; $P += $BMP['bytes_per_pixel']; } $Y--; $P+=$BMP['decal']; } //Fermeture du fichier fclose($f1); return $res; } } \ No newline at end of file Index: branches/5.2.x/core/units/users/users_event_handler.php =================================================================== --- branches/5.2.x/core/units/users/users_event_handler.php (revision 14183) +++ branches/5.2.x/core/units/users/users_event_handler.php (revision 14184) @@ -1,1661 +1,1663 @@ <?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 UsersEventHandler extends kDBEventHandler { /** * Allows to override standart permission mapping * */ function mapPermissions() { parent::mapPermissions(); $permissions = Array ( // admin 'OnSetPersistantVariable' => Array('self' => 'view'), // because setting to logged in user only 'OnUpdateRootPassword' => Array('self' => true), 'OnUpdatePassword' => Array('self' => true), // front 'OnRefreshForm' => Array('self' => true), 'OnForgotPassword' => Array('self' => true), 'OnResetPassword' => Array('self' => true), 'OnResetPasswordConfirmed' => Array('self' => true), 'OnSubscribeQuery' => Array('self' => true), 'OnSubscribeUser' => Array('self' => true), 'OnRecommend' => Array('self' => true), 'OnItemBuild' => Array('self' => true), 'OnMassResetSettings' => Array('self' => 'edit'), 'OnMassCloneUsers' => Array('self' => 'add'), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Shows only admins when required * * @param kEvent $event */ function SetCustomQuery(&$event) { $object =& $event->getObject(); /* @var $object kDBList */ if ($event->Special == 'admins') { $object->addFilter('primary_filter', 'ug.GroupId = 11'); } if ($event->Special == 'regular') { $object->addFilter('primary_filter', 'ug.GroupId <> 11 OR ug.GroupId IS NULL'); } if (!$this->Application->isAdminUser) { $object->addFilter('status_filter', '%1$s.Status = '.STATUS_ACTIVE); } if ($event->Special == 'online') { $object->addFilter('online_users_filter', 's.PortalUserId IS NOT NULL'); } if ($event->Special == 'group') { $group_id = $this->Application->GetVar('g_id'); if ($group_id !== false) { // show only users, that user doesn't belong to current group $table_name = $this->Application->GetTempName(TABLE_PREFIX.'UserGroup', 'prefix:g'); $sql = 'SELECT PortalUserId FROM ' . $table_name . ' WHERE GroupId = ' . (int)$group_id; $user_ids = $this->Conn->GetCol($sql); // array_push($user_ids); // Guest & Everyone groups are set dynamically if ($user_ids) { $object->addFilter('already_member_filter', '%1$s.PortalUserId NOT IN ('.implode(',', $user_ids).')'); } } } } /** * Checks permissions of user * * @param kEvent $event */ function CheckPermission(&$event) { if ($event->Name == 'OnLogin' || $event->Name == 'OnLogout') { // permission is checked in OnLogin event directly return true; } if (!$this->Application->isAdminUser) { $user_id = $this->Application->RecallVar('user_id'); $items_info = $this->Application->GetVar($event->getPrefixSpecial(true)); if ($event->Name == 'OnCreate' && $user_id == USER_GUEST) { // "Guest" can create new users return true; } if ($event->Name == 'OnUpdate' && $user_id > 0) { $user_dummy =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true)); foreach ($items_info as $id => $field_values) { if ($id != $user_id) { // registered users can update their record only return false; } $user_dummy->Load($id); $status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField')); if ($user_dummy->GetDBField($status_field) != STATUS_ACTIVE) { // not active user is not allowed to update his record (he could not activate himself manually) return false; } if (isset($field_values[$status_field]) && $user_dummy->GetDBField($status_field) != $field_values[$status_field]) { // user can't change status by himself return false; } } return true; } if ($event->Name == 'OnUpdate' && $user_id <= 0) { // guests are not allowed to update their record, because they don't have it :) return false; } } return parent::CheckPermission($event); } /** * Handles session expiration (redirects to valid template) * * @param kEvent $event */ function OnSessionExpire(&$event) { $this->Application->resetCounters('UserSession'); // place 2 of 2 (also in kHTTPQuery::getRedirectParams) $admin_url_params = Array ( 'm_cat_id' => 0, // category means nothing on admin login screen 'm_wid' => '', // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for <a> targets) 'pass' => 'm', // don't pass any other (except "m") prefixes to admin session expiration template 'expired' => 1, // expiration mark to show special error on login screen 'no_pass_through' => 1, // this way kApplication::HREF won't add them again ); if ($this->Application->isAdmin) { $this->Application->Redirect('index', $admin_url_params, '', 'index.php'); } if ($this->Application->GetVar('admin') == 1) { // Front-End showed in admin's right frame $session_admin =& $this->Application->recallObject('Session.admin'); /* @var $session_admin Session */ if (!$session_admin->LoggedIn()) { // front-end session created from admin session & both expired $this->Application->DeleteVar('admin'); $this->Application->Redirect('index', $admin_url_params, '', 'admin/index.php'); } } // Front-End session expiration $get = $this->Application->HttpQuery->getRedirectParams(); $t = $this->Application->GetVar('t'); $get['js_redirect'] = $this->Application->ConfigValue('UseJSRedirect'); $this->Application->Redirect($t ? $t : 'index', $get); } /** * [AGENT] Deletes expired sessions * * @param kEvent $event */ function OnDeleteExpiredSessions(&$event) { if (defined('IS_INSTALL') && IS_INSTALL) { return ; } $this->Application->Session->DeleteExpired(); } /** * Checks user data and logs it in if allowed * * @param kEvent $event */ function OnLogin(&$event) { $email_as_login = $this->Application->ConfigValue('Email_As_Login'); $username = $this->Application->GetVar($email_as_login && !$this->Application->isAdmin ? 'email' : 'login'); $password = $this->Application->GetVar('password'); $rember_login = $this->Application->GetVar('cb_remember_login') == 1; $user_helper =& $this->Application->recallObject('UserHelper'); /* @var $user_helper UserHelper */ $user_helper->event =& $event; $result = $user_helper->loginUser($username, $password, false, $rember_login); if ($result != LoginResult::OK) { $object =& $user_helper->getUserObject(); if ($result == LoginResult::NO_PERMISSION) { $object->SetError('ValidateLogin', 'no_permission', 'la_no_permissions'); } else { $object->SetID(USER_GUEST); $object->SetError('ValidateLogin', 'invalid_password', 'la_invalid_password'); } $event->status = kEvent::erFAIL; } } /** * [HOOK] Auto-Logins Front-End user when "Remember Login" cookie is found * * @param kEvent $event */ function OnAutoLoginUser(&$event) { $remember_login_cookie = $this->Application->GetVar('remember_login'); if (!$remember_login_cookie || $this->Application->isAdmin || $this->Application->LoggedIn()) { return ; } $user_helper =& $this->Application->recallObject('UserHelper'); /* @var $user_helper UserHelper */ $user_helper->loginUser('', '', false, false, $remember_login_cookie); } /** * Called when user logs in using old in-portal * * @param kEvent $event */ function OnInpLogin(&$event) { $sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize')); $sync_manager->performAction('LoginUser', $event->getEventParam('user'), $event->getEventParam('pass') ); if ($event->redirect && is_string($event->redirect)) { // some real template specified instead of true $this->Application->Redirect($event->redirect, $event->getRedirectParams()); } } /** * Called when user logs in using old in-portal * * @param kEvent $event */ function OnInpLogout(&$event) { $sync_manager =& $this->Application->recallObject('UsersSyncronizeManager', null, Array(), Array ('InPortalSyncronize')); $sync_manager->performAction('LogoutUser'); } function OnLogout(&$event) { $user_helper =& $this->Application->recallObject('UserHelper'); /* @var $user_helper UserHelper */ $user_helper->event =& $event; $user_helper->logoutUser(); } /** * Redirects user after succesfull registration to confirmation template (on Front only) * * @param kEvent $event */ function OnAfterItemCreate(&$event) { $this->saveUserImages($event); if ($this->Application->GetVar('skip_set_primary')) return; $is_subscriber = $this->Application->GetVar('IsSubscriber'); if(!$is_subscriber) { $object =& $event->getObject(); $ug_table = TABLE_PREFIX.'UserGroup'; if ($object->IsTempTable()) { $ug_table = $this->Application->GetTempName($ug_table, 'prefix:'.$event->Prefix); } $sql = 'UPDATE '.$ug_table.' SET PrimaryGroup = 0 WHERE PortalUserId = '.$object->GetDBField('PortalUserId'); $this->Conn->Query($sql); // set primary group to user if ($this->Application->isAdminUser && $this->Application->GetVar('user_group')) { // while in admin you can set any group for new users $group_id = $this->Application->GetVar('user_group'); } else { $group_id = $object->GetDBField('UserGroup'); if ($group_id) { // check, that group is allowed for Front-End $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'PortalGroup WHERE GroupId = ' . (int)$group_id . ' AND FrontRegistration = 1'; $group_id = $this->Conn->GetOne($sql); } if (!$group_id) { // when group not selected -> use default group $group_id = $this->Application->ConfigValue('User_NewGroup'); } } $sql = 'REPLACE INTO '.$ug_table.'(PortalUserId,GroupId,PrimaryGroup) VALUES (%s,%s,1)'; $this->Conn->Query( sprintf($sql, $object->GetID(), $group_id) ); } } /** * Login user if possible, if not then redirect to corresponding template * * @param kEvent $event */ function autoLoginUser(&$event) { $object =& $event->getObject(); $this->Application->SetVar('u.current_id', $object->GetID()); if ($object->GetDBField('Status') == STATUS_ACTIVE && !$this->Application->ConfigValue('User_Password_Auto')) { $user_helper =& $this->Application->recallObject('UserHelper'); /* @var $user_helper UserHelper */ $user_helper->loginUser($object->GetDBField('Login'), $object->GetDBField('Password_plain')); } } /** * When creating user & user with such email exists then force to use OnUpdate insted of ? * * @param kEvent $event */ function OnSubstituteSubscriber(&$event) { $ret = false; $object =& $event->getObject( Array('skip_autoload' => true) ); $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); if($items_info) { list($id, $field_values) = each($items_info); $user_email = isset($field_values['Email']) ? $field_values['Email'] : false; if($user_email) { // check if is subscriber $verify_user =& $this->Application->recallObject('u.verify', null, Array('skip_autoload' => true) ); $verify_user->Load($user_email, 'Email'); if( $verify_user->isLoaded() && $verify_user->isSubscriberOnly() ) { $items_info = Array( $verify_user->GetDBField('PortalUserId') => $field_values ); $this->Application->SetVar($event->getPrefixSpecial(true), $items_info); $ret = true; } } } if( isset($event->MasterEvent) ) { $event->MasterEvent->setEventParam('is_subscriber_only', $ret); } else { $event->setEventParam('is_subscriber_only', $ret); } } /** * Enter description here... * * @param kEvent $event * @param bool $dry_run * @return bool */ function isSubscriberOnly(&$event, $dry_run = false) { $event->CallSubEvent('OnSubstituteSubscriber'); $is_subscriber = $event->getEventParam('is_subscriber_only'); if ($dry_run) { return $is_subscriber; } if ($is_subscriber) { $object =& $event->getObject( Array('skip_autoload' => true) ); $this->OnUpdate($event); if ($event->status == kEvent::erSUCCESS) { $this->OnAfterItemCreate($event); $object->SendEmailEvents(); if (!$this->Application->isAdmin && $event->redirect) { $this->autoLoginUser($event); } } } return $is_subscriber; } /** * Creates new user * * @param kEvent $event */ function OnCreate(&$event) { if (!$this->Application->isAdminUser) { $this->setUserStatus($event); } if (!$this->isSubscriberOnly($event)) { $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ if ($this->Application->ConfigValue('User_Password_Auto')) { $pass = kUtil::generatePassword(rand(5,8)); $object->SetField('Password', $pass); $object->SetField('VerifyPassword', $pass); $this->Application->SetVar('user_password',$pass); } parent::OnCreate($event); $this->Application->SetVar('u.current_id', $object->getID() ); // for affil:OnRegisterAffiliate after hook $this->setNextTemplate($event); if (!$this->Application->isAdmin && ($event->status == kEvent::erSUCCESS) && $event->redirect) { $object->SendEmailEvents(); $this->autoLoginUser($event); } } } /** * Set's new user status based on config options * * @param kEvent $event */ function setUserStatus(&$event) { $object =& $event->getObject( Array('skip_autoload' => true) ); $new_users_allowed = $this->Application->ConfigValue('User_Allow_New'); switch ($new_users_allowed) { case 1: // Immediate $object->SetDBField('Status', STATUS_ACTIVE); $next_template = $this->Application->GetVar('registration_confirm_template'); if ($next_template) { $event->redirect = $next_template; } break; case 3: // Upon Approval case 4: // Email Activation $next_template = $this->Application->GetVar('registration_confirm_pending_template'); if ($next_template) { $event->redirect = $next_template; } $object->SetDBField('Status', STATUS_PENDING); break; case 2: // Not Allowed $object->SetDBField('Status', STATUS_DISABLED); break; } } /** * Set's new unique resource id to user * * @param kEvent $event */ function OnBeforeItemCreate(&$event) { parent::OnBeforeItemCreate($event); $cs_helper =& $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ if (!$this->isSubscriberOnly($event, true)) { $cs_helper->CheckStateField($event, 'State', 'Country'); } $this->_makePasswordRequired($event); $cs_helper->PopulateStates($event, 'State', 'Country'); $object =& $event->getObject(); /* @var $object kDBItem */ if ( $this->Application->ConfigValue('Email_As_Login') ) { $field_options = $object->GetFieldOptions('Email'); $field_options['error_msgs']['unique'] = $this->Application->Phrase('lu_user_and_email_already_exist'); $object->SetFieldOptions('Email', $field_options); } $object->setLogin(); $user_helper =& $this->Application->recallObject('UserHelper'); /* @var $user_helper UserHelper */ if (!$user_helper->checkBanRules($object)) { $event->status = kEvent::erFAIL; return ; } } /** * Set's new unique resource id to user * * @param kEvent $event */ function OnAfterItemValidate(&$event) { $object =& $event->getObject(); $resource_id = $object->GetDBField('ResourceId'); if (!$resource_id) { $object->SetDBField('ResourceId', $this->Application->NextResourceId() ); } } /** * Enter description here... * * @param kEvent $event */ function OnRecommend(&$event) { $friend_email = $this->Application->GetVar('friend_email'); $friend_name = $this->Application->GetVar('friend_email'); // used for error reporting only -> rewrite code + theme (by Alex) $object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too /* @var $object UsersItem */ if (preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $friend_email)) { /*$cutoff = adodb_mktime() + (int)$this->Application->ConfigValue('Suggest_MinInterval'); $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'SuggestMail WHERE email = ' . $this->Conn->qstr($friend_email) . ' AND sent < ' . $cutoff; if ($this->Conn->GetRow($sql) !== false) { $object->SetError('Email', 'send_error', 'lu_email_already_suggested'); $event->status = kEvent::erFAIL; return ; }*/ $send_params = Array (); $send_params['to_email'] = $friend_email; $send_params['to_name'] = $friend_name; $user_id = $this->Application->RecallVar('user_id'); $email_event =& $this->Application->EmailEventUser('USER.SUGGEST', $user_id, $send_params); $email_event =& $this->Application->EmailEventAdmin('USER.SUGGEST'); if ($email_event->status == kEvent::erSUCCESS){ /*$fields_hash = Array ( 'email' => $friend_email, 'sent' => adodb_mktime(), ); $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'SuggestMail');*/ $event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'), true); $event->redirect = $this->Application->GetVar('template_success'); } else { // $event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'), true); // $event->redirect = $this->Application->GetVar('template_fail'); $object->SetError('Email', 'send_error', 'lu_email_send_error'); $event->status = kEvent::erFAIL; } } else { $object->SetError('Email', 'invalid_email', 'lu_InvalidEmail'); $event->status = kEvent::erFAIL; } } /** * Saves address changes and mades no redirect * * @param kEvent $event */ function OnUpdateAddress(&$event) { $object =& $event->getObject( Array('skip_autoload' => true) ); $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); if ($items_info) { list ($id, $field_values) = each($items_info); if ($id > 0) { $object->Load($id); } $object->SetFieldsFromHash($field_values); $object->setID($id); $object->Validate(); } $cs_helper =& $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ $cs_helper->PopulateStates($event, 'State', 'Country'); $event->redirect = false; } /** * Validate subscriber's email & store it to session -> redirect to confirmation template * * @param kEvent $event */ function OnSubscribeQuery(&$event) { $user_email = $this->Application->GetVar('subscriber_email'); if (preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $user_email)) { $object =& $this->Application->recallObject($this->Prefix.'.subscriber', null, Array('skip_autoload' => true)); /* @var $object UsersItem */ $this->Application->StoreVar('SubscriberEmail', $user_email); $object->Load($user_email, 'Email'); if ($object->isLoaded()) { $group_info = $this->GetGroupInfo($object->GetID()); $event->redirect = $this->Application->GetVar($group_info ? 'unsubscribe_template' : 'subscribe_template'); } else { $event->redirect = $this->Application->GetVar('subscribe_template'); $this->Application->StoreVar('SubscriberEmail', $user_email); } } else { // used for error reporting only -> rewrite code + theme (by Alex) $object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too /* @var $object UsersItem */ $object->SetError('SubscribeEmail', 'invalid_email', 'lu_InvalidEmail'); $event->status = kEvent::erFAIL; } } /** * Subscribe/Unsubscribe user based on email stored in previous step * * @param kEvent $event */ function OnSubscribeUser(&$event) { $object = &$this->Application->recallObject($this->Prefix.'.subscriber', null, Array('skip_autoload' => true)); /* @var $object UsersItem */ $user_email = $this->Application->RecallVar('SubscriberEmail'); if (preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $user_email)) { $this->RemoveRequiredFields($object); $object->Load($user_email, 'Email'); if ($object->isLoaded()) { $group_info = $this->GetGroupInfo($object->GetID()); if ($group_info){ if ($event->getEventParam('no_unsubscribe')) return; if ($group_info['PrimaryGroup']){ // delete user $object->Delete(); } else { $this->RemoveSubscriberGroup($object->GetID()); } $event->redirect = $this->Application->GetVar('unsubscribe_ok_template'); } else { $this->AddSubscriberGroup($object->GetID(), 0); $event->redirect = $this->Application->GetVar('subscribe_ok_template'); } } else { $object->SetField('Email', $user_email); $object->SetField('Login', $user_email); $object->SetDBField('dob', 1); $object->SetDBField('dob_date', 1); $object->SetDBField('dob_time', 1); $object->SetDBField('Status', STATUS_ACTIVE); // make user subscriber Active by default $ip = getenv('HTTP_X_FORWARDED_FOR')?getenv('HTTP_X_FORWARDED_FOR'):getenv('REMOTE_ADDR'); $object->SetDBField('ip', $ip); $this->Application->SetVar('IsSubscriber', 1); if ($object->Create()) { $this->AddSubscriberGroup($object->GetID(), 1); $event->redirect = $this->Application->GetVar('subscribe_ok_template'); } $this->Application->SetVar('IsSubscriber', 0); } } } function AddSubscriberGroup($user_id, $is_primary) { $group_id = $this->Application->ConfigValue('User_SubscriberGroup'); $sql = 'INSERT INTO ' . TABLE_PREFIX . 'UserGroup (PortalUserId, GroupId, PrimaryGroup) VALUES (%s, %s, ' . $is_primary . ')'; $this->Conn->Query( sprintf($sql, $user_id, $group_id) ); $this->Application->EmailEventAdmin('USER.SUBSCRIBE'); $this->Application->EmailEventUser('USER.SUBSCRIBE', $user_id); } function RemoveSubscriberGroup($user_id) { $group_id = $this->Application->ConfigValue('User_SubscriberGroup'); $sql = 'DELETE FROM ' . TABLE_PREFIX . 'UserGroup WHERE PortalUserId = ' . $user_id . ' AND GroupId = ' . $this->Application->ConfigValue('User_SubscriberGroup'); $this->Conn->Query($sql); $this->Application->EmailEventAdmin('USER.UNSUBSCRIBE'); $this->Application->EmailEventUser('USER.UNSUBSCRIBE', $user_id); } /** * Allows to detect user subscription status (subscribed or not) * * @param int $user_id * @return bool */ function GetGroupInfo($user_id) { $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'UserGroup WHERE (PortalUserId = ' . $user_id . ') AND (GroupId = ' . $this->Application->ConfigValue('User_SubscriberGroup') . ')'; return $this->Conn->GetRow($sql); } function OnForgotPassword(&$event) { $user_object =& $this->Application->recallObject('u.forgot', null, Array('skip_autoload' => true)); /* @var $user_object UsersItem */ // used for error reporting only -> rewrite code + theme (by Alex) $user_current_object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too /* @var $user_current_object UsersItem */ $username = $this->Application->GetVar('username'); $email = $this->Application->GetVar('email'); $found = false; $allow_reset = true; if (strlen($username)) { $user_object->Load($username, 'Login'); if ($user_object->isLoaded()) { $found = ($user_object->GetDBField("Login")==$username && $user_object->GetDBField("Status")==1) && strlen($user_object->GetDBField("Password")); } } else if(strlen($email)) { $user_object->Load($email, 'Email'); if ($user_object->isLoaded()) { $found = ($user_object->GetDBField("Email")==$email && $user_object->GetDBField("Status")==1) && strlen($user_object->GetDBField("Password")); } } if ($user_object->isLoaded()) { $PwResetConfirm = $user_object->GetDBField('PwResetConfirm'); $PwRequestTime = $user_object->GetDBField('PwRequestTime'); $PassResetTime = $user_object->GetDBField('PassResetTime'); //$MinPwResetDelay = $user_object->GetDBField('MinPwResetDelay'); $MinPwResetDelay = $this->Application->ConfigValue('Users_AllowReset'); $allow_reset = (strlen($PwResetConfirm) ? adodb_mktime() > $PwRequestTime + $MinPwResetDelay : adodb_mktime() > $PassResetTime + $MinPwResetDelay); } if ($found && $allow_reset) { $this->Application->StoreVar('tmp_user_id', $user_object->GetDBField("PortalUserId")); $this->Application->StoreVar('tmp_email', $user_object->GetDBField("Email")); $confirm_template = $this->Application->GetVar('reset_confirm_template'); if (!$confirm_template) { $this->Application->SetVar('reset_confirm_template', 'platform/login/forgotpass_reset'); } $this->Application->EmailEventUser('USER.PSWDC', $user_object->GetDBField('PortalUserId')); $event->redirect = $this->Application->GetVar('template_success'); } else { if (!strlen($username) && !strlen($email)) { $user_current_object->SetError('Login', 'forgotpw_nodata', 'lu_ferror_forgotpw_nodata'); $user_current_object->SetError('Email', 'forgotpw_nodata', 'lu_ferror_forgotpw_nodata'); } else { if ($allow_reset) { if (strlen($username)) { $user_current_object->SetError('Login', 'unknown_username', 'lu_ferror_unknown_username'); } if (strlen($email)) { $user_current_object->SetError('Email', 'unknown_email', 'lu_ferror_unknown_email'); } } else { if (strlen($username)) { $user_current_object->SetError('Login', 'reset_denied', 'lu_ferror_reset_denied'); } if (strlen($email)) { $user_current_object->SetError('Email', 'reset_denied', 'lu_ferror_reset_denied'); } } } if ( $user_current_object->HasErrors() ) { $event->redirect = false; } } } /** * Enter description here... * * @param kEvent $event */ function OnResetPassword(&$event) { $user_object =& $this->Application->recallObject('u.forgot'); if($user_object->Load($this->Application->RecallVar('tmp_user_id'))){ $this->Application->EmailEventUser('USER.PSWDC', $user_object->GetDBField("PortalUserId")); $event->redirect = $this->Application->GetVar('template_success'); $m_cat_id = $this->Application->findModule('Name', 'In-Commerce', 'RootCat'); $this->Application->SetVar('m_cat_id', $m_cat_id); $event->SetRedirectParam('pass', 'm'); } } function OnResetPasswordConfirmed(&$event) { // used for error reporting only -> rewrite code + theme (by Alex) $user_current_object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true));// TODO: change theme too /* @var $user_current_object UsersItem */ $passed_key = trim($this->Application->GetVar('user_key')); if (!$passed_key) { $event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'), true); $event->redirect = false; $user_current_object->SetError('PwResetConfirm', 'code_is_not_valid', 'lu_code_is_not_valid'); } $user_object =& $this->Application->recallObject('u.forgot', null, Array('skip_autoload' => true)); /* @var $user_object UsersItem */ $user_object->Load($passed_key, 'PwResetConfirm'); if ($user_object->isLoaded()) { $exp_time = $user_object->GetDBField('PwRequestTime') + 3600; $user_object->SetDBField('PwResetConfirm', ''); $user_object->SetDBField('PwRequestTime', 0); if ($exp_time > adodb_mktime()) { $newpw = kUtil::generatePassword(); $this->Application->StoreVar('password', $newpw); $user_object->SetField('Password', $newpw); $user_object->SetField('VerifyPassword', $newpw); $user_object->SetDBField('PassResetTime', adodb_mktime()); $user_object->SetDBField('PwResetConfirm', ''); $user_object->SetDBField('PwRequestTime', 0); $user_object->Update(); $this->Application->SetVar('ForgottenPassword', $newpw); $email_event_user =& $this->Application->EmailEventUser('USER.PSWD', $user_object->GetDBField('PortalUserId')); $email_event_admin =& $this->Application->EmailEventAdmin('USER.PSWD'); $this->Application->DeleteVar('ForgottenPassword'); if ($email_event_user->status == kEvent::erSUCCESS) { $event->setRedirectParams(array('opener' => 's', 'pass' => 'all'), true); $event->redirect = $this->Application->GetVar('template_success'); } } else { $user_current_object->SetError('PwResetConfirm', 'code_expired', 'lu_code_expired'); $event->redirect = false; } } else { $user_current_object->SetError('PwResetConfirm', 'code_is_not_valid', 'lu_code_is_not_valid'); $event->redirect = false; } } function OnUpdate(&$event) { parent::OnUpdate($event); $this->setNextTemplate($event); } /** * Checks state against country * * @param kEvent $event */ function OnBeforeItemUpdate(&$event) { parent::OnBeforeItemUpdate($event); $cs_helper =& $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ $cs_helper->CheckStateField($event, 'State', 'Country'); $cs_helper->PopulateStates($event, 'State', 'Country'); $object =& $event->getObject(); /* @var $object UsersItem */ $object->setLogin(); } /** * Enter description here... * * @param kEvent $event */ function setNextTemplate(&$event) { if ($this->Application->isAdmin) { return ; } $event->SetRedirectParam('opener', 's'); $object =& $event->getObject(); if ($object->GetDBField('Status') == STATUS_ACTIVE) { $next_template = $this->Application->GetVar('next_template'); if ($next_template) { $event->redirect = $next_template; } } } /** * Delete users from groups if their membership is expired * * @param kEvent $event */ function OnCheckExpiredMembership(&$event) { // send pre-expiration reminders: begin $pre_expiration = adodb_mktime() + $this->Application->ConfigValue('User_MembershipExpirationReminder') * 3600 * 24; $sql = 'SELECT PortalUserId, GroupId FROM '.TABLE_PREFIX.'UserGroup WHERE (MembershipExpires IS NOT NULL) AND (ExpirationReminderSent = 0) AND (MembershipExpires < '.$pre_expiration.')'; $skip_clause = $event->getEventParam('skip_clause'); if ($skip_clause) { $sql .= ' AND !('.implode(') AND !(', $skip_clause).')'; } $records = $this->Conn->Query($sql); if ($records) { $conditions = Array(); foreach ($records as $record) { $email_event_user =& $this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRATION.NOTICE', $record['PortalUserId']); $email_event_admin =& $this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRATION.NOTICE'); $conditions[] = '(PortalUserId = '.$record['PortalUserId'].' AND GroupId = '.$record['GroupId'].')'; } $sql = 'UPDATE '.TABLE_PREFIX.'UserGroup SET ExpirationReminderSent = 1 WHERE '.implode(' OR ', $conditions); $this->Conn->Query($sql); } // send pre-expiration reminders: end // remove users from groups with expired membership: begin $sql = 'SELECT PortalUserId FROM '.TABLE_PREFIX.'UserGroup WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')'; $user_ids = $this->Conn->GetCol($sql); if ($user_ids) { foreach ($user_ids as $id) { $email_event_user =& $this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRED', $id); $email_event_admin =& $this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRED'); } } $sql = 'DELETE FROM '.TABLE_PREFIX.'UserGroup WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')'; $this->Conn->Query($sql); // remove users from groups with expired membership: end } /** * Enter description here... * * @param kEvent $event */ function OnRefreshForm(&$event) { $event->redirect = false; $item_info = $this->Application->GetVar($event->getPrefixSpecial()); list($id, $fields) = each($item_info); $object =& $event->getObject( Array('skip_autoload' => true) ); $object->setID($id); $object->IgnoreValidation = true; $object->SetFieldsFromHash($fields); } /** * Sets persistant variable * * @param kEvent $event */ function OnSetPersistantVariable(&$event) { $field = $this->Application->GetVar('field'); $value = $this->Application->GetVar('value'); $this->Application->StorePersistentVar($field, $value); $force_tab = $this->Application->GetVar('SetTab'); if ($force_tab) { $this->Application->StoreVar('force_tab', $force_tab); } } /** * Overwritten to return user from order by special .ord * * @param kEvent $event */ function getPassedID(&$event) { switch ($event->Special) { case 'ord': $order =& $this->Application->recallObject('ord'); /* @var $order OrdersItem */ $id = $order->GetDBField('PortalUserId'); break; case 'profile': $id = $this->Application->GetVar('user_id'); if (!$id) { // if none user_id given use current user id $id = $this->Application->RecallVar('user_id'); } break; default: $id = parent::getPassedID($event); break; } return $id; } /** * Allows to change root password * * @param kEvent $event */ function OnUpdateRootPassword(&$event) { return $this->OnUpdatePassword($event); } /** * Allows to change root password * * @param kEvent $event */ function OnUpdatePassword(&$event) { $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); if (!$items_info) return ; list ($id, $field_values) = each($items_info); $user_id = $this->Application->RecallVar('user_id'); if ($id == $user_id && ($user_id > 0 || $user_id == USER_ROOT)) { $user_dummy =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true)); /* @var $user_dummy kDBItem */ $user_dummy->Load($id); $status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField')); if ($user_dummy->GetDBField($status_field) != STATUS_ACTIVE) { // not active user is not allowed to update his record (he could not activate himself manually) return false; } } if ($user_id == USER_ROOT) { $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object UsersItem */ // put salt to user's config $field_options = $object->GetFieldOptions('RootPassword'); $field_options['salt'] = 'b38'; - $object->SetFieldOptions('RootPassword', $field_options); - $verify_options = $object->GetFieldOptions('VerifyRootPassword'); - $verify_options['salt'] = 'b38'; - $object->SetFieldOptions('VerifyRootPassword', $verify_options); // this is internal hack to allow root/root passwords for dev if ($this->Application->isDebugMode() && $field_values['RootPassword'] == 'root') { - $this->Application->ConfigHash['Min_Password'] = 4; + $field_options['min_length'] = 4; } + $object->SetFieldOptions('RootPassword', $field_options); + + $verify_options = $object->GetFieldOptions('VerifyRootPassword'); + $verify_options['salt'] = 'b38'; + $object->SetFieldOptions('VerifyRootPassword', $verify_options); + $this->RemoveRequiredFields($object); $object->SetDBField('RootPassword', $this->Application->ConfigValue('RootPass')); $object->SetFieldsFromHash($field_values); $object->setID(-1); $status = $object->Validate(); if ($status) { // validation on, password match too $fields_hash = Array ( 'VariableValue' => $object->GetDBField('RootPassword') ); $conf_table = $this->Application->getUnitOption('conf', 'TableName'); $this->Conn->doUpdate($fields_hash, $conf_table, 'VariableName = "RootPass"'); $event->SetRedirectParam('opener', 'u'); } else { $event->status = kEvent::erFAIL; $event->redirect = false; return; } } else { $object =& $event->getObject(); $object->SetFieldsFromHash($field_values); if (!$object->Update()) { $event->status = kEvent::erFAIL; $event->redirect = false; } } $event->SetRedirectParam('opener', 'u'); $event->redirect == true; } /** * Apply custom processing to item * * @param kEvent $event */ function customProcessing(&$event, $type) { if ($event->Name == 'OnCreate' && $type == 'before') { $object =& $event->getObject(); /* @var $object kDBItem */ // if auto password has not been set already - store real one - to be used in email events if (!$this->Application->GetVar('user_password')) { $this->Application->SetVar('user_password', $object->GetDirtyField('Password')); $object->SetDBField('Password_plain', $object->GetDirtyField('Password')); } // validate here, because subscribing procedure should not validate captcha code if ($this->Application->ConfigValue('RegistrationCaptcha')) { $captcha_helper =& $this->Application->recallObject('CaptchaHelper'); /* @var $captcha_helper kCaptchaHelper */ $captcha_helper->validateCode($event, false); } } } function OnMassResetSettings(&$event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = kEvent::erFAIL; return; } $ids = $this->StoreSelectedIDs($event); $default_user_id = $this->Application->ConfigValue('DefaultSettingsUserId'); if (in_array($default_user_id, $ids)) { array_splice($ids, array_search($default_user_id, $ids), 1); } if ($ids) { $q = 'DELETE FROM '.TABLE_PREFIX.'PersistantSessionData WHERE PortalUserId IN ('.join(',', $ids).') AND (VariableName LIKE "%_columns_%" OR VariableName LIKE "%_filter%" OR VariableName LIKE "%_PerPage%")'; $this->Conn->Query($q); } $this->clearSelectedIDs($event); } /** * Checks, that currently loaded item is allowed for viewing (non permission-based) * * @param kEvent $event * @return bool */ function checkItemStatus(&$event) { $object =& $event->getObject(); if (!$object->isLoaded()) { return true; } $virtual_users = Array (USER_ROOT, USER_GUEST); return ($object->GetDBField('Status') == STATUS_ACTIVE) || in_array($object->GetID(), $virtual_users); } /** * Sends approved/declined email event on user status change * * @param kEvent $event */ function OnAfterItemUpdate(&$event) { $this->saveUserImages($event); $object =& $event->getObject(); /* @var $object UsersItem */ if (!$this->Application->isAdmin || $object->IsTempTable()) { return ; } $this->sendStatusChangeEvent($object->GetID(), $object->GetOriginalField('Status'), $object->GetDBField('Status')); } /** * Stores user's original Status before overwriting with data from temp table * * @param kEvent $event */ function OnBeforeDeleteFromLive(&$event) { $user_status = $this->Application->GetVar('user_status'); if (!$user_status) { $user_status = Array (); } $user_id = $event->getEventParam('id'); if ($user_id > 0) { $user_status[$user_id] = $this->getUserStatus($user_id); $this->Application->SetVar('user_status', $user_status); } } /** * Sends approved/declined email event on user status change (in temp tables during editing) * * @param kEvent $event */ function OnAfterCopyToLive(&$event) { $temp_id = $event->getEventParam('temp_id'); if ($temp_id == 0) { // this is new user create, don't send email events return ; } $new_status = $this->getUserStatus($temp_id); $user_status = $this->Application->GetVar('user_status'); $this->sendStatusChangeEvent($temp_id, $user_status[$temp_id], $new_status); } /** * Returns user status (active, pending, disabled) based on ID and temp mode setting * * @param int $user_id * @return int */ function getUserStatus($user_id) { $id_field = $this->Application->getUnitOption($this->Prefix, 'IDField'); $table_name = $this->Application->getUnitOption($this->Prefix, 'TableName'); $sql = 'SELECT Status FROM '.$table_name.' WHERE '.$id_field.' = '.$user_id; return $this->Conn->GetOne($sql); } /** * Sends approved/declined email event on user status change * * @param int $user_id * @param int $prev_status * @param int $new_status */ function sendStatusChangeEvent($user_id, $prev_status, $new_status) { $status_events = Array ( STATUS_ACTIVE => 'USER.APPROVE', STATUS_DISABLED => 'USER.DENY', ); $email_event = isset($status_events[$new_status]) ? $status_events[$new_status] : false; if (($prev_status != $new_status) && $email_event) { $this->Application->EmailEventUser($email_event, $user_id); $this->Application->EmailEventAdmin($email_event); } // deletes sessions from users, that are no longer active if (($prev_status != $new_status) && ($new_status != STATUS_ACTIVE)) { $sql = 'SELECT SessionKey FROM ' . TABLE_PREFIX . 'UserSession WHERE PortalUserId = ' . $user_id; $session_ids = $this->Conn->GetCol($sql); $this->Application->Session->DeleteSessions($session_ids); } } /** * OnAfterConfigRead for users * * @param kEvent $event */ function OnAfterConfigRead(&$event) { parent::OnAfterConfigRead($event); // 1. arrange user registration countries $site_helper =& $this->Application->recallObject('SiteHelper'); /* @var $site_helper SiteHelper */ $first_country = $site_helper->getDefaultCountry('', false); if ($first_country === false) { $first_country = $this->Application->ConfigValue('User_Default_Registration_Country'); } if ($first_country) { // update user country dropdown sql $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); $fields['Country']['options_sql'] = preg_replace('/ORDER BY (.*)/', 'ORDER BY IF (CountryStateId = '.$first_country.', 1, 0) DESC, \\1', $fields['Country']['options_sql']); $this->Application->setUnitOption($event->Prefix, 'Fields', $fields); } // 2. set default user registration group $virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields'); $virtual_fields['UserGroup']['default'] = $this->Application->ConfigValue('User_NewGroup'); $this->Application->setUnitOption($event->Prefix, 'VirtualFields', $virtual_fields); // 3. allow avatar upload on Front-End $file_helper =& $this->Application->recallObject('FileHelper'); /* @var $file_helper FileHelper */ $file_helper->createItemFiles($event->Prefix, true); // create image fields if ($this->Application->isAdminUser) { // 4. when in administrative console, then create all users with Active status $fields = $this->Application->getUnitOption($event->Prefix, 'Fields'); // $fields['Password']['required'] = 1; // set password required (will broke approve/decline buttons) $fields['Status']['default'] = STATUS_ACTIVE; $this->Application->setUnitOption($event->Prefix, 'Fields', $fields); // 5. remove groups tab on editing forms when AdvancedUserManagement config variable not set if (!$this->Application->ConfigValue('AdvancedUserManagement')) { $edit_tab_presets = $this->Application->getUnitOption($event->Prefix, 'EditTabPresets'); foreach ($edit_tab_presets as $preset_name => $preset_tabs) { if (array_key_exists('groups', $preset_tabs)) { unset($edit_tab_presets[$preset_name]['groups']); if (count($edit_tab_presets[$preset_name]) == 1) { // only 1 tab left -> remove it too $edit_tab_presets[$preset_name] = Array (); } } } $this->Application->setUnitOption($event->Prefix, 'EditTabPresets', $edit_tab_presets); } } } /** * OnMassCloneUsers * * @param kEvent $event */ function OnMassCloneUsers(&$event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = kEvent::erFAIL; return; } $event->status=kEvent::erSUCCESS; $ids = $this->StoreSelectedIDs($event); $this->Application->SetVar('skip_set_primary', 1); // otherwise it will default primary group, search for skip_set_primary above $temp_handler =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler'); /* @var $temp_handler kTempTablesHandler */ $cloned_users = $temp_handler->CloneItems($event->Prefix, '', $ids); $this->clearSelectedIDs($event); } /** * When cloning users, reset password (set random) * * @param kEvent $event */ function OnBeforeClone(&$event) { $object =& $event->getObject(); /* @var $object kDBItem */ $object->setRequired('Password', 0); $object->setRequired('VerifyPassword', 0); $object->SetDBField('Password', rand(100000000, 999999999)); $object->SetDBField('CreatedOn', adodb_mktime()); $object->SetDBField('ResourceId', false); // this will reset it // change email cause it should be unique $object->NameCopy(array(), $object->GetID(), 'Email', 'copy%1$s.%2$s'); $object->UpdateFormattersSubFields(); } /** * Copy user groups after copying user * * @param kEvent $event */ function OnAfterClone(&$event) { $id = $event->getEventParam('id'); $original_id = $event->getEventParam('original_id'); $sql = 'INSERT '.TABLE_PREFIX."UserGroup SELECT $id, GroupId, MembershipExpires, PrimaryGroup, 0 FROM ".TABLE_PREFIX."UserGroup WHERE PortalUserId = $original_id"; $this->Conn->Query($sql); } /** * Saves selected ids to session * * @param kEvent $event */ function OnSaveSelected(&$event) { $this->StoreSelectedIDs($event); // remove current ID, otherwise group selector will use it in filters $this->Application->DeleteVar($event->getPrefixSpecial(true).'_id'); } /** * Adds selected link to listing * * @param kEvent $event */ function OnProcessSelected(&$event) { $event->SetRedirectParam('opener', 'u'); $user_ids = $this->getSelectedIDs($event, true); $this->clearSelectedIDs($event); $dst_field = $this->Application->RecallVar('dst_field'); if ($dst_field != 'PrimaryGroupId') { return ; } $group_ids = $this->Application->GetVar('g'); $primary_group_id = $group_ids ? array_shift( array_keys($group_ids) ) : false; if (!$user_ids || !$primary_group_id) { return ; } $table_name = $this->Application->getUnitOption('ug', 'TableName'); $sql = 'SELECT PortalUserId FROM '.$table_name.' WHERE (GroupId = '.$primary_group_id.') AND (PortalUserId IN ('.implode(',', $user_ids).'))'; $existing_members = $this->Conn->GetCol($sql); // 1. reset primary group mark $sql = 'UPDATE '.$table_name.' SET PrimaryGroup = 0 WHERE PortalUserId IN ('.implode(',', $user_ids).')'; $this->Conn->Query($sql); foreach ($user_ids as $user_id) { if (in_array($user_id, $existing_members)) { // 2. already member of that group -> just make primary $sql = 'UPDATE '.$table_name.' SET PrimaryGroup = 1 WHERE (PortalUserId = '.$user_id.') AND (GroupId = '.$primary_group_id.')'; $this->Conn->Query($sql); } else { // 3. not member of that group -> make member & make primary $fields_hash = Array ( 'GroupId' => $primary_group_id, 'PortalUserId' => $user_id, 'PrimaryGroup' => 1, ); $this->Conn->doInsert($fields_hash, $table_name); } } } /** * Loads user images * * @param kEvent $event */ function OnAfterItemLoad(&$event) { parent::OnAfterItemLoad($event); // linking existing images for item with virtual fields $image_helper =& $this->Application->recallObject('ImageHelper'); /* @var $image_helper ImageHelper */ $object =& $event->getObject(); /* @var $object kDBItem */ $image_helper->LoadItemImages($object); $cs_helper =& $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ $cs_helper->PopulateStates($event, 'State', 'Country'); } /** * Save user images * * @param kEvent $event */ function saveUserImages(&$event) { if (!$this->Application->isAdmin) { $image_helper =& $this->Application->recallObject('ImageHelper'); /* @var $image_helper ImageHelper */ $object =& $event->getObject(); /* @var $object kDBItem */ // process image upload in virtual fields $image_helper->SaveItemImages($object); } } /** * Makes password required for new users * * @param kEvent $event */ function OnPreCreate(&$event) { parent::OnPreCreate($event); if ($event->status == kEvent::erSUCCESS) { $this->_makePasswordRequired($event); } } /** * Makes password required for new users * * @param kEvent $event */ function OnNew(&$event) { parent::OnNew($event); if ($event->status == kEvent::erSUCCESS) { $this->_makePasswordRequired($event); } } /** * Makes password required for new users * * @param kEvent $event */ function _makePasswordRequired(&$event) { $object =& $event->getObject(); /* @var $object kDBItem */ $required_fields = Array ('Password', 'Password_plain', 'VerifyPassword', 'VerifyPassword_plain'); foreach ($required_fields as $required_field) { $object->setRequired($required_field); } } /** * Load item if id is available * * @param kEvent $event */ function LoadItem(&$event) { $id = $this->getPassedID($event); if ($id < 0) { // when root, guest and so on $object =& $event->getObject(); /* @var $object kDBItem */ $object->Clear($id); return ; } parent::LoadItem($event); } } Index: branches/5.2.x/core/units/helpers/category_helper.php =================================================================== --- branches/5.2.x/core/units/helpers/category_helper.php (revision 14183) +++ branches/5.2.x/core/units/helpers/category_helper.php (revision 14184) @@ -1,599 +1,599 @@ <?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 CategoryHelper extends kHelper { /** * Structure tree for ParentId field in category or category items * * @var Array */ var $_structureTree = null; /** * ID of primary language (only for caching) * * @var int */ var $_primaryLanguageId = false; /** * Prints category path using given blocks. Also supports used defined path elements at the end. * * @param Array $params * @return string */ function NavigationBar($params) { $params['is_first'] = 1; $main_category_id = isset($params['cat_id']) ? $params['cat_id'] : $this->Application->GetVar('m_cat_id'); if (array_key_exists('shift', $params) && $params['shift']) { $home_element = ''; $params['shift']--; } else { $home_element = $this->getHomeCategoryPath($params, $main_category_id); unset($params['is_first']); } if (!getArrayValue($params, 'titles') && !getArrayValue($params, 'templates')) { // no static templates given, show only category path return $home_element . $this->getCategoryPath($main_category_id, $params); } $navigation_parts = $this->getNavigationParts($params['titles'], $params['templates']); $ret = ''; $block_params = Array (); //$params; // sort of TagProcessor:prepareTagParams $block_params['no_editing'] = 1; $block_params['category'] = 0; $block_params['separator'] = $params['separator']; $show_category = getArrayValue($params, 'show_category'); $current_template = $this->Application->GetVar('t'); - $physical_template = array_search($current_template, $this->Application->structureTemplateMapping); + $physical_template = $this->Application->getPhysicalTemplate($current_template); if ($physical_template !== false) { // replace menu template name with it's actual template name on disk list ($current_template) = explode(':', $physical_template, 2); } foreach ($navigation_parts as $template => $title) { $block_params['template'] = $template; if ($title == '__item__') { if ($show_category) { $ret .= $this->getCategoryPath($main_category_id, $params); $show_category = false; } $category_path = $this->getCategoryParentPath($main_category_id); $module_info = $this->getCategoryModule($params, array_keys($category_path)); if (!$module_info) { continue; } $module_prefix = $module_info['Var']; $object =& $this->Application->recallObject($module_prefix); /* @var $object kCatDBItem */ $title_field = $this->Application->getUnitOption($module_prefix, 'TitleField'); $block_params['title'] = $object->GetField($title_field); $block_params['prefix'] = $module_prefix; $block_params['current'] = 0; $block_params['name'] = $this->SelectParam($params, 'module_item_render_as,render_as'); } else { $block_params['current'] = ($template == $current_template); $block_params['title'] = $this->Application->Phrase($title); $block_params['name'] = $template == $current_template ? $params['current_render_as'] : $params['render_as']; } $ret .= $this->Application->ParseBlock($block_params); } if ($show_category) { $params['no_current'] = true; return $home_element . ($show_category ? $this->getCategoryPath($main_category_id, $params) : '') . $ret; } return $home_element . $ret; } /** * Get navigation parts * * @param Array $titles * @param Array $templates * @return Array */ function getNavigationParts($titles, $templates) { $titles = explode(',', $titles); $templates = explode(',', $templates); $ret = Array (); foreach ($templates as $template_pos => $template) { $ret[$template] = $titles[$template_pos]; } return $ret; } /** * Renders path to given category using given blocks. * * @param int $main_category_id * @param Array $params * @return string */ function getCategoryPath($main_category_id, $params) { $category_path = $this->getCategoryParentPath($main_category_id); if (!$category_path) { // in "Home" category return ''; } if (array_key_exists('shift', $params) && $params['shift']) { array_splice($category_path, 0, $params['shift']); } $module_info = $this->getCategoryModule($params, array_keys($category_path)); $module_category_id = $module_info['RootCat']; $module_item_id = $this->Application->GetVar($module_info['Var'].'_id'); $ret = ''; $block_params['category'] = 1; $block_params['no_editing'] = 1; if (array_key_exists('is_first', $params)) { $block_params['is_first'] = $params['is_first']; } $block_params['separator'] = $params['separator']; $no_current = isset($params['no_current']) && $params['no_current']; $backup_category_id = $this->Application->GetVar('c_id'); foreach ($category_path as $category_id => $category_name) { $block_params['cat_id'] = $category_id; $block_params['cat_name'] = $block_params['title'] = $category_name; if ($no_current) { $block_params['current'] = 0; } else { $block_params['current'] = ($main_category_id == $category_id) && !$module_item_id ? 1 : 0; } $block_params['is_module_root'] = $category_id == $module_category_id ? 1 : 0; $block_params['name'] = $this->SelectParam($params, 'render_as,block'); // which block to parse as current ? if ($block_params['is_module_root']) { $block_params['name'] = $this->SelectParam($params, 'module_root_render_as,render_as'); $block_params['module_index'] = $module_info['TemplatePath'].'index'; } if ($block_params['current']) { $block_params['name'] = $this->SelectParam($params, 'current_render_as,render_as'); } $this->Application->SetVar('c_id', $category_id); $ret .= $this->Application->ParseBlock($block_params); if (array_key_exists('is_first', $block_params)) { unset($block_params['is_first']); } } $this->Application->SetVar('c_id', $backup_category_id); return $ret; } /** * Returns module information based on given module name or current category (relative to module root categories) * * @param Array $params * @param Array $category_ids category parent path (already as array) * @return Array */ function getCategoryModule($params, $category_ids) { if (isset($params['module'])) { // get module by name specified $module_info = $this->Application->findModule('Name', $params['module']); } elseif ($category_ids) { // get module by category path $module_root_categories = $this->getModuleRootCategories(); $common_categories = array_intersect($category_ids, $module_root_categories); $module_category_id = array_shift($common_categories); // get 1st common category $module_info = $this->Application->findModule('RootCat', $module_category_id); } return $module_info; } /** * Renders path to top catalog category * * @param Array $params * @param int $current_category * @return string */ function getHomeCategoryPath($params, $current_category) { $block_params['cat_id'] = $this->Application->getBaseCategory(); $block_params['no_editing'] = 1; $block_params['current'] = $current_category == $block_params['cat_id'] ? 1 : 0; $block_params['separator'] = $params['separator']; $block_params['is_first'] = $params['is_first']; $block_params['cat_name'] = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name'); $block_params['name'] = $this->SelectParam($params, 'root_cat_render_as,render_as'); return $this->Application->ParseBlock($block_params); } /** * Returns root categories from all modules * * @return Array */ function getModuleRootCategories() { static $root_categories = null; if (!isset($root_categories)) { $root_categories = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { array_push($root_categories, $module_info['RootCat']); } $root_categories = array_unique($root_categories); } return $root_categories; } /** * Returns given category's parent path as array of id=>name elements * * @param int $main_category_id * @return Array */ function getCategoryParentPath($main_category_id) { if ($main_category_id == 0) { // don't query path for "Home" category return Array (); } $cache_key = 'parent_paths_named[%CIDSerial:' . $main_category_id . '%]'; $cached_path = $this->Application->getCache($cache_key); if ($cached_path === false) { $ml_formatter =& $this->Application->recallObject('kMultiLanguage'); $navbar_field = $ml_formatter->LangFieldName('CachedNavBar'); $id_field = $this->Application->getUnitOption('c', 'IDField'); $table_name = $this->Application->getUnitOption('c', 'TableName'); $this->Conn->nextQueryCachable = true; $sql = 'SELECT '.$navbar_field.', ParentPath FROM '.$table_name.' WHERE '.$id_field.' = '.$main_category_id; $category_data = $this->Conn->GetRow($sql); $cached_path = Array (); $skip_category = $this->Application->getBaseCategory(); if ($category_data) { $category_names = explode('&|&', $category_data[$navbar_field]); $category_ids = explode('|', substr($category_data['ParentPath'], 1, -1)); foreach ($category_ids as $category_index => $category_id) { if ($category_id == $skip_category) { continue; } $cached_path[$category_id] = $category_names[$category_index]; } } $this->Application->setCache($cache_key, $cached_path); } return $cached_path; } /** * Not tag, method for parameter * selection from list in this TagProcessor * * @param Array $params * @param string $possible_names * @return string * @access public */ function SelectParam($params, $possible_names) { if (!is_array($params)) return; if (!is_array($possible_names)) $possible_names = explode(',', $possible_names); foreach ($possible_names as $name) { if( isset($params[$name]) ) return $params[$name]; } return false; } /** * Converts multi-dimensional category structure in one-dimensional option array (category_id=>category_name) * * @param Array $data * @param int $parent_category_id * @param int_type $language_id * @param int $theme_id * @param int $level * @return Array */ function _printChildren(&$data, $parent_category_id, $language_id, $theme_id, $level = 0) { if ($data['ThemeId'] != $theme_id && $data['ThemeId'] != 0) { // don't show system templates from different themes return Array (); } $category_language = $data['l' . $language_id . '_Name'] ? $language_id : $this->_primaryLanguageId; $ret = Array($parent_category_id => str_repeat('-', $level).' '.$data['l' . $category_language . '_Name']); if ($data['children']) { $level++; foreach ($data['children'] as $category_id => $category_data) { // numeric keys $ret = kUtil::array_merge_recursive($ret, $this->_printChildren($data['children'][$category_id], $category_id, $language_id, $theme_id, $level)); } } return $ret; } /** * Returns information about children under parent path (recursive) * * @param int $parent_category_id * @param Array $languages * @return Array */ function _getChildren($parent_category_id, $languages) { static $items_by_parent = null, $parent_mapping = null; if ( !isset($items_by_parent) ) { $fields = $items_by_parent = Array (); foreach ($languages as $language_id) { $fields[] = 'l' . $language_id . '_Name'; } $sql = 'SELECT CategoryId AS id, ' . implode(', ', $fields) . ', ParentId, ThemeId FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' ORDER BY Priority DESC'; $items = $this->Conn->Query($sql, 'id'); foreach ($items as $item_id => $item_data) { $item_parent_id = $item_data['ParentId']; unset($item_data['ParentId']); if ( !array_key_exists($item_parent_id, $items_by_parent) ) { $items_by_parent[$item_parent_id] = Array (); } $item_data['children'] = false; $parent_mapping[$item_id] = $item_parent_id; $items_by_parent[$item_parent_id][$item_id] = $item_data; } } $data = $items_by_parent[ $parent_mapping[$parent_category_id] ][$parent_category_id]; $categories = array_key_exists($parent_category_id, $items_by_parent) ? $items_by_parent[$parent_category_id] : Array (); foreach ($categories as $category_id => $category_data) { if ($category_id == $parent_category_id) { // don't process myself - prevents recursion continue; } $data['children'][$category_id] = $this->_getChildren($category_id, $languages); } return $data; } /** * Generates OR retrieves from cache structure tree * * @return Array */ function &_getStructureTree() { // get cached version of structure tree if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->getCache('master:StructureTree', false); } else { $data = $this->Application->getDBCache('StructureTree'); } if ($data) { $data = unserialize($data); return $data; } // generate structure tree from scratch $ml_helper =& $this->Application->recallObject('kMultiLanguageHelper'); /* @var $ml_helper kMultiLanguageHelper */ $languages = $ml_helper->getLanguages(); $root_category = $this->Application->getBaseCategory(); $data = $this->_getChildren($root_category, $languages); if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $this->Application->setCache('master:StructureTree', serialize($data)); } else { $this->Application->setDBCache('StructureTree', serialize($data)); } return $data; } function getTemplateMapping() { if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->getCache('master:template_mapping', false); } else { $data = $this->Application->getDBCache('template_mapping'); } if ($data) { return unserialize($data); } $sql = 'SELECT IF(c.`Type` = ' . PAGE_TYPE_TEMPLATE . ', CONCAT(c.Template, ":", c.ThemeId), CONCAT("id:", c.CategoryId)) AS SrcTemplate, LOWER( IF( c.SymLinkCategoryId IS NOT NULL, (SELECT cc.NamedParentPath FROM ' . TABLE_PREFIX . 'Category AS cc WHERE cc.CategoryId = c.SymLinkCategoryId), c.NamedParentPath ) ) AS DstTemplate, c.UseExternalUrl, c.ExternalUrl FROM ' . TABLE_PREFIX . 'Category AS c WHERE c.Status = ' . STATUS_ACTIVE; $pages = $this->Conn->Query($sql, 'SrcTemplate'); $mapping = Array (); $base_url = $this->Application->BaseURL(); foreach ($pages as $src_template => $page) { // process external url, before placing in cache if ($page['UseExternalUrl']) { $external_url = $page['ExternalUrl']; if (!preg_match('/^(.*?):\/\/(.*)$/', $external_url)) { // url without protocol will be relative url to our site $external_url = $base_url . $external_url; } $dst_template = 'external:' . $external_url; } else { $dst_template = preg_replace('/^Content\//i', '', $page['DstTemplate']); } $mapping[$src_template] = $dst_template; } if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $data = $this->Application->setCache('master:template_mapping', serialize($mapping)); } else { $this->Application->setDBCache('template_mapping', serialize($mapping)); } return $mapping; } /** * Returns category structure as field option list * * @return Array */ function getStructureTreeAsOptions() { if ((defined('IS_INSTALL') && IS_INSTALL) || !$this->Application->isAdmin) { // no need to create category structure during install // OR on Front-End, because it's not used there return Array (); } if (isset($this->_structureTree)) { return $this->_structureTree; } $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $data = $this->_getStructureTree(); $theme_id = (int)$themes_helper->getCurrentThemeId(); $root_category = $this->Application->getBaseCategory(); $this->_primaryLanguageId = $this->Application->GetDefaultLanguageId(); $this->_structureTree = $this->_printChildren($data, $root_category, $this->Application->GetVar('m_lang'), $theme_id); return $this->_structureTree; } /** * Replace links like "@@ID@@" to actual template names in given text * * @param string $text * @return string */ function replacePageIds($text) { if (!preg_match_all('/@@(\\d+)@@/', $text, $regs)) { return $text; } $page_ids = $regs[1]; $sql = 'SELECT NamedParentPath, CategoryId FROM ' . TABLE_PREFIX . 'Category WHERE CategoryId IN (' . implode(',', $page_ids) . ')'; $templates = $this->Conn->GetCol($sql, 'CategoryId'); foreach ($page_ids as $page_id) { if (!array_key_exists($page_id, $templates)) { // internal page was deleted, but link to it was found in given content block data continue; } $url_params = Array ('m_cat_id' => $page_id, 'pass' => 'm'); $page_url = $this->Application->HREF(strtolower($templates[$page_id]), '', $url_params); /*if ($this->Application->isAdmin) { $page_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $page_url); }*/ $text = str_replace('@@' . $page_id . '@@', $page_url, $text); } return $text; } } \ No newline at end of file Index: branches/5.2.x/core/units/helpers/mod_rewrite_helper.php =================================================================== --- branches/5.2.x/core/units/helpers/mod_rewrite_helper.php (revision 14183) +++ branches/5.2.x/core/units/helpers/mod_rewrite_helper.php (revision 14184) @@ -1,1145 +1,1189 @@ <?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 kModRewriteHelper extends kHelper { /** * Holds a refererence to httpquery * * @var kHttpQuery */ var $HTTPQuery = null; /** * Parts found during url parsing * * @var Array */ var $_partsFound = Array (); /** * Category item prefix, that was found * * @var string */ var $_modulePrefix = false; /** * Template aliases for current theme * * @var Array */ var $_templateAliases = null; /** * Domain-based primary language id * * @var int */ var $primaryLanguageId = false; /** * Domain-based primary theme id * * @var int */ var $primaryThemeId = false; /** * Possible url endings from ModRewriteUrlEnding configuration variable * * @var Array */ var $_urlEndings = Array ('.html', '/', ''); /** * Constructor of kModRewriteHelper class * * @return kModRewriteHelper */ public function __construct() { parent::__construct(); $this->HTTPQuery =& $this->Application->recallObject('HTTPQuery'); // domain based primary language $this->primaryLanguageId = $this->Application->siteDomainField('PrimaryLanguageId'); // domain based primary theme $this->primaryThemeId = $this->Application->siteDomainField('PrimaryThemeId'); } function processRewriteURL() { $passed = Array (); $url = $this->HTTPQuery->Get('_mod_rw_url_'); if ($url) { foreach ($this->_urlEndings as $url_ending) { if (substr($url, strlen($url) - strlen($url_ending)) == $url_ending) { $url = substr($url, 0, strlen($url) - strlen($url_ending)); $default_ending = $this->Application->ConfigValue('ModRewriteUrlEnding'); // user manually typed url with different url ending -> redirect to same url with default url ending if (($url_ending != $default_ending) && $this->Application->ConfigValue('ForceModRewriteUrlEnding')) { $target_url = $this->Application->BaseURL() . $url . $default_ending; $this->Application->Redirect('external:' . $target_url, Array ('response_code' => 301)); } break; } } } $restored = false; $cached = $this->_getCachedUrl($url); if ($cached !== false) { $vars = $cached['vars']; $passed = $cached['passed']; $restored = true; } else { $vars = $this->parseRewriteURL($url); $passed = $vars['pass']; // also used in bottom of this method unset($vars['pass']); $this->_setCachedUrl($url, Array ('vars' => $vars, 'passed' => $passed)); if (array_key_exists('t', $this->HTTPQuery->Post) && $this->HTTPQuery->Post['t']) { // template from POST overrides template from URL. $vars['t'] = $this->HTTPQuery->Post['t']; if (isset($vars['is_virtual']) && $vars['is_virtual']) { $vars['m_cat_id'] = 0; // this is virtual template category (for Proj-CMS) } } unset($vars['is_virtual']); } foreach ($vars as $name => $value) { $this->HTTPQuery->Set($name, $value); } $this->InitAll(); // also will use parsed language to load phrases from it $this->HTTPQuery->finalizeParsing($passed); } function _getCachedUrl($url) { if (!$url) { return false; } $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'CachedUrls WHERE Hash = ' . crc32($url) . ' AND DomainId = ' . (int)$this->Application->siteDomainField('DomainId'); $data = $this->Conn->GetRow($sql); if ($data) { $lifetime = (int)$data['LifeTime']; // in seconds if (($lifetime > 0) && ($data['Cached'] + $lifetime < adodb_mktime())) { // delete expired $sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls WHERE UrlId = ' . $data['UrlId']; $this->Conn->Query($sql); return false; } return unserialize($data['ParsedVars']); } return false; } function _setCachedUrl($url, $data) { if (!$url) { return ; } $vars = $data['vars']; $passed = $data['passed']; sort($passed); // get expiration if ($vars['m_cat_id'] > 0) { $sql = 'SELECT PageExpiration FROM ' . TABLE_PREFIX . 'Category WHERE CategoryId = ' . $vars['m_cat_id']; $expiration = $this->Conn->GetOne($sql); } // get prefixes $prefixes = Array (); $m_index = array_search('m', $passed); if ($m_index !== false) { unset($passed[$m_index]); if ($vars['m_cat_id'] > 0) { $prefixes[] = 'c:' . $vars['m_cat_id']; } $prefixes[] = 'lang:' . $vars['m_lang']; $prefixes[] = 'theme:' . $vars['m_theme']; } foreach ($passed as $prefix) { if (array_key_exists($prefix . '_id', $vars) && is_numeric($vars[$prefix . '_id'])) { $prefixes[] = $prefix . ':' . $vars[$prefix . '_id']; } else { $prefixes[] = $prefix; } } $fields_hash = Array ( 'Url' => $url, 'Hash' => crc32($url), 'DomainId' => (int)$this->Application->siteDomainField('DomainId'), 'Prefixes' => $prefixes ? '|' . implode('|', $prefixes) . '|' : '', 'ParsedVars' => serialize($data), 'Cached' => adodb_mktime(), 'LifeTime' => isset($expiration) && is_numeric($expiration) ? $expiration : -1 ); $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'CachedUrls'); } function parseRewriteURL($url) { $vars = Array ('pass' => Array ('m')); $url_parts = $url ? explode('/', trim(mb_strtolower($url, 'UTF-8'), '/')) : Array (); if (($this->HTTPQuery->Get('rewrite') == 'on') || !$url_parts) { $this->_setDefaultValues($vars); } if (!$url_parts) { $this->InitAll(); $vars['t'] = $this->HTTPQuery->getDefaultTemplate(''); return $vars; } else { $vars['t'] = ''; } $this->_parseLanguage($url_parts, $vars); $this->_parseTheme($url_parts, $vars); // http://site-url/<language>/<theme>/<category>[_<category_page>]/<template>/<module_page> // http://site-url/<language>/<theme>/<category>[_<category_page>]/<module_page> (category-based section template) // http://site-url/<language>/<theme>/<category>[_<category_page>]/<template>/<module_item> // http://site-url/<language>/<theme>/<category>[_<category_page>]/<module_item> (category-based detail template) // http://site-url/<language>/<theme>/<rl_injections>/<category>[_<category_page>]/<rl_part> (customized url) if ( $this->processRewriteListeners($url_parts, $vars) ) { return $vars; } if ($this->_parsePhisycalTemplate($url_parts, $vars)) { $this->_partsFound[] = 'parsePhisycalTemplate'; } if (($this->_modulePrefix === false) && in_array('parseCategory', $this->_partsFound)) { // no item found, but category found -> module index page /*foreach ($this->Application->RewriteListeners as $prefix => $listener) { // no idea what module we are talking about, so pass info form all modules $vars['pass'][] = $prefix; }*/ return $vars; } if (!$this->_partsFound) { $not_found = $this->Application->ConfigValue('ErrorTemplate'); $vars['t'] = $not_found ? $not_found : 'error_notfound'; $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $vars['m_cat_id'] = $themes_helper->getPageByTemplate($vars['t'], $vars['m_theme']); header('HTTP/1.0 404 Not Found'); } return $vars; } function InitAll() { $this->Application->VerifyThemeId(); $this->Application->VerifyLanguageId(); - $this->Application->Phrases->Init('phrases'); + + // no need, since we don't have any cached phrase IDs + nobody will use PhrasesCache::LanguageId soon + // $this->Application->Phrases->Init('phrases'); } /** * Processes url using rewrite listeners * * @param Array $url_parts * @param Array $vars * @return bool */ function processRewriteListeners(&$url_parts, &$vars) { $this->initRewriteListeners(); $page_number = $this->_parsePage($url_parts, $vars); if ($page_number) { $this->_partsFound[] = 'parsePage'; } foreach ($this->Application->RewriteListeners as $prefix => $listeners) { // set default page // $vars[$prefix . '_Page'] = 1; // will override page in session in case, when none is given in url if ($page_number) { // page given in url - use it $vars[$prefix . '_id'] = 0; $vars[$prefix . '_Page'] = $page_number; } // $listeners[1] - listener, used for parsing $listener_result = $listeners[1][0]->$listeners[1][1](REWRITE_MODE_PARSE, $prefix, $vars, $url_parts); if ($listener_result === false) { // will not proceed to other methods return true; } } // will proceed to other methods return false; } /** * Parses real template name from url * * @param Array $url_parts * @param Array $vars * @return bool */ function _parsePhisycalTemplate($url_parts, &$vars) { if (!$url_parts) { return false; } do { $template_path = implode('/', $url_parts); - $physical_template = array_search($template_path, $this->Application->structureTemplateMapping); + $physical_template = $this->Application->getPhysicalTemplate($template_path); if (($physical_template !== false) && (substr($physical_template, 0, 3) != 'id:')) { // replace menu template name with it's actual template name on disk list ($template_path) = explode(':', $physical_template, 2); } $t_parts['path'] = dirname($template_path) == '.' ? '' : '/' . dirname($template_path); $t_parts['file'] = basename($template_path); $sql = 'SELECT FileId FROM ' . TABLE_PREFIX . 'ThemeFiles WHERE (ThemeId = ' . $vars['m_theme'] . ') AND (FilePath = ' . $this->Conn->qstr($t_parts['path']) . ') AND (FileName = ' . $this->Conn->qstr($t_parts['file'] . '.tpl') . ')'; $template_found = $this->Conn->GetOne($sql); if (!$template_found) { array_shift($url_parts); } } while (!$template_found && $url_parts); if ($template_found) { $vars['t'] = $template_path; // 1. will damage actual category during category item review add process // 2. will use "use_section" parameter of "m_Link" tag to gain same effect // $themes_helper =& $this->Application->recallObject('ThemesHelper'); // /* @var $themes_helper kThemesHelper */ // // $vars['m_cat_id'] = $themes_helper->getPageByTemplate($template_path, $vars['m_theme']); return true; } return false; } /** * Parses category part of url, build main part of url * * @param int $rewrite_mode Mode in what rewrite listener was called. Possbile two modes: REWRITE_MODE_BUILD, REWRITE_MODE_PARSE. * @param string $prefix Prefix, that listener uses for system integration * @param Array $params Params, that are used for url building or created during url parsing. * @param Array $url_parts Url parts to parse (only for parsing). * @param bool $keep_events Keep event names in resulting url (only for building). * @return bool|string|Array Return true to continue to next listener; return false (when building) not to rewrite given prefix; return false (when parsing) to stop processing at this listener. */ function MainRewriteListener($rewrite_mode = REWRITE_MODE_BUILD, $prefix, &$params, &$url_parts, $keep_events = false) { if ($rewrite_mode == REWRITE_MODE_BUILD) { return $this->_buildMainUrl($prefix, $params, $keep_events); } if ( $this->_parseFriendlyUrl($url_parts, $params) ) { // friendly urls work like exact match only! return false; } if ($this->_parseCategory($url_parts, $params)) { $this->_partsFound[] = 'parseCategory'; } return true; } /** * Build main part of every url * * @param string $prefix_special * @param Array $params * @param bool $keep_events * @return string */ function _buildMainUrl($prefix_special, &$params, $keep_events) { $ret = ''; list ($prefix) = explode('.', $prefix_special); $processed_params = $this->getProcessedParams($prefix_special, $params, $keep_events); if ($processed_params === false) { return ''; } // add language if (!$this->primaryLanguageId) { // when domain-based language not found -> use site-wide language $this->primaryLanguageId = $this->Application->GetDefaultLanguageId(); } if ($processed_params['m_lang'] && ($processed_params['m_lang'] != $this->primaryLanguageId)) { $language_name = $this->Application->getCache('language_names[%LangIDSerial:' . $processed_params['m_lang'] . '%]'); if ($language_name === false) { $sql = 'SELECT PackName FROM ' . TABLE_PREFIX . 'Language WHERE LanguageId = ' . $processed_params['m_lang']; $language_name = $this->Conn->GetOne($sql); $this->Application->setCache('language_names[%LangIDSerial:' . $processed_params['m_lang'] . '%]', $language_name); } $ret .= $language_name . '/'; } // add theme if (!$this->primaryThemeId) { // when domain-based theme not found -> use site-wide theme $this->primaryThemeId = $this->Application->GetDefaultThemeId(true); } if ($processed_params['m_theme'] && ($processed_params['m_theme'] != $this->primaryThemeId)) { $theme_name = $this->Application->getCache('theme_names[%ThemeIDSerial:' . $processed_params['m_theme'] . '%]'); if ($theme_name === false) { $sql = 'SELECT Name FROM ' . TABLE_PREFIX . 'Theme WHERE ThemeId = ' . $processed_params['m_theme']; $theme_name = $this->Conn->GetOne($sql); $this->Application->setCache('theme_names[%ThemeIDSerial:' . $processed_params['m_theme'] . '%]', $theme_name); } $ret .= $theme_name . '/'; } // inject custom url parts made by other rewrite listeners just after language/theme url parts if ($params['inject_parts']) { $ret .= implode('/', $params['inject_parts']) . '/'; } // add category if ($processed_params['m_cat_id'] > 0 && $params['pass_category']) { $category_filename = $this->Application->getCategoryCache($processed_params['m_cat_id'], 'filenames'); preg_match('/^Content\/(.*)/i', $category_filename, $regs); if ($regs) { $template = array_key_exists('t', $params) ? $params['t'] : false; if (strtolower($regs[1]) == strtolower($template)) { // we could have category path like "Content/<template_path>" in this case remove template $params['pass_template'] = false; } $ret .= $regs[1] . '/'; } $params['category_processed'] = true; } // reset category page $force_page_adding = false; if (array_key_exists('reset', $params) && $params['reset']) { unset($params['reset']); if ($processed_params['m_cat_id']) { $processed_params['m_cat_page'] = 1; $force_page_adding = true; } } if ((array_key_exists('category_processed', $params) && $params['category_processed'] && ($processed_params['m_cat_page'] > 1)) || $force_page_adding) { // category name was added before AND category page number found $ret = rtrim($ret, '/') . '_' . $processed_params['m_cat_page'] . '/'; } $template = array_key_exists('t', $params) ? $params['t'] : false; $category_template = ($processed_params['m_cat_id'] > 0) && $params['pass_category'] ? $this->Application->getCategoryCache($processed_params['m_cat_id'], 'category_designs') : ''; if ((strtolower($template) == '__default__') && ($processed_params['m_cat_id'] == 0)) { // for "Home" category set template to index when not set $template = 'index'; } // remove template from url if it is category index cached template if (($template == $category_template) || (mb_strtolower($template) == '__default__')) { // given template is also default template for this category or '__default__' given $params['pass_template'] = false; } if ($template && $params['pass_template']) { $ret .= $template . '/'; } return mb_strtolower( rtrim($ret, '/') ); } /** * Gets language part from url * * @param Array $url_parts * @param Array $vars * @return bool */ function _parseLanguage(&$url_parts, &$vars) { if (!$url_parts) { return false; } $url_part = reset($url_parts); $sql = 'SELECT LanguageId, IF(LOWER(PackName) = ' . $this->Conn->qstr($url_part) . ', 2, PrimaryLang) AS SortKey FROM ' . TABLE_PREFIX . 'Language WHERE Enabled = 1 ORDER BY SortKey DESC'; $language_info = $this->Conn->GetRow($sql); if ($language_info && $language_info['LanguageId'] && $language_info['SortKey']) { // primary language will be selected in case, when $url_part doesn't match to other's language pack name // don't use next enabled language, when primary language is disabled $vars['m_lang'] = $language_info['LanguageId']; if ($language_info['SortKey'] == 2) { // language was found by pack name array_shift($url_parts); } elseif ($this->primaryLanguageId) { // use domain-based primary language instead of site-wide primary language $vars['m_lang'] = $this->primaryLanguageId; } return true; } return false; } /** * Gets theme part from url * * @param Array $url_parts * @param Array $vars * @return bool */ function _parseTheme(&$url_parts, &$vars) { if (!$url_parts) { return false; } $url_part = reset($url_parts); $sql = 'SELECT ThemeId, IF(LOWER(Name) = ' . $this->Conn->qstr($url_part) . ', 2, PrimaryTheme) AS SortKey, TemplateAliases FROM ' . TABLE_PREFIX . 'Theme WHERE Enabled = 1 ORDER BY SortKey DESC'; $theme_info = $this->Conn->GetRow($sql); if ($theme_info && $theme_info['ThemeId'] && $theme_info['SortKey']) { // primary theme will be selected in case, when $url_part doesn't match to other's theme name // don't use next enabled theme, when primary theme is disabled $vars['m_theme'] = $theme_info['ThemeId']; if ($theme_info['TemplateAliases']) { $this->_templateAliases = unserialize($theme_info['TemplateAliases']); } else { $this->_templateAliases = Array (); } if ($theme_info['SortKey'] == 2) { // theme was found by name array_shift($url_parts); } elseif ($this->primaryThemeId) { // use domain-based primary theme instead of site-wide primary theme $vars['m_theme'] = $this->primaryThemeId; } return true; } $vars['m_theme'] = 0; // required, because used later for category/template detection return false; } /** * Checks if whole url_parts matches a whole In-CMS page * * @param array $url_parts * @return boolean */ function _parseFriendlyUrl($url_parts, &$vars) { if (!$url_parts) { return false; } $sql = 'SELECT CategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Category WHERE FriendlyURL = ' . $this->Conn->qstr(implode('/', $url_parts)); $friendly = $this->Conn->GetRow($sql); if ($friendly) { $vars['m_cat_id'] = $friendly['CategoryId']; $vars['t'] = preg_replace('/^Content\//i', '', $friendly['NamedParentPath']); return true; } return false; } /** * Set's page (when found) to all modules * * @param Array $url_parts * @param Array $vars * @return string * * @todo Should find a way, how to determine what rewrite listerner page is it */ function _parsePage(&$url_parts, &$vars) { if (!$url_parts) { return false; } $page_number = end($url_parts); if (!is_numeric($page_number)) { return false; } array_pop($url_parts); return $page_number; } /** * Remove page numbers for all rewrite listeners * * @todo Should find a way, how to determine what rewrite listerner page is it */ function removePages() { /*foreach ($this->Application->RewriteListeners as $prefix => $listener) { $this->Application->DeleteVar($prefix . '_Page'); }*/ } /** * Extracts category part from url * * @param Array $url_parts * @param Array $vars * @return bool */ function _parseCategory($url_parts, &$vars) { if (!$url_parts) { return false; } $res = false; $url_part = array_shift($url_parts); $category_id = 0; $last_category_info = false; $category_path = $url_part == 'content' ? '' : 'content'; do { $category_path = trim($category_path . '/' . $url_part, '/'); // bb_<topic_id> -> forums/bb_2 if ( !preg_match('/^bb_[\d]+$/', $url_part) && preg_match('/(.*)_([\d]+)$/', $category_path, $rets) ) { $category_path = $rets[1]; $vars['m_cat_page'] = $rets[2]; } $sql = 'SELECT CategoryId, SymLinkCategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Category WHERE Status IN (1,4) AND (LOWER(NamedParentPath) = ' . $this->Conn->qstr($category_path) . ') AND (ThemeId = ' . $vars['m_theme'] . ' OR ThemeId = 0)'; $category_info = $this->Conn->GetRow($sql); if ($category_info !== false) { $last_category_info = $category_info; $url_part = array_shift($url_parts); $res = true; } } while ($category_info !== false && $url_part); if ($last_category_info) { // this category is symlink to other category, so use it's url instead // (used in case if url prior to symlink adding was indexed by spider or was bookmarked) if ($last_category_info['SymLinkCategoryId']) { $sql = 'SELECT CategoryId, NamedParentPath FROM ' . TABLE_PREFIX . 'Category WHERE (CategoryId = ' . $last_category_info['SymLinkCategoryId'] . ')'; $category_info = $this->Conn->GetRow($sql); if ($category_info) { // web symlinked category was found use it // TODO: maybe 302 redirect should be made to symlinked category url (all other url parts should stay) $last_category_info = $category_info; } } // 1. Set virtual page as template, this will be replaced to physical template later in kApplication::Run. // 2. Don't set CachedTemplate field as template here, because we will loose original page associated with it's cms blocks! $vars['t'] = mb_strtolower( preg_replace('/^Content\//i', '', $last_category_info['NamedParentPath']), 'UTF-8' ); $vars['m_cat_id'] = $last_category_info['CategoryId']; $vars['is_virtual'] = true; // for template from POST, strange code there! } else { $vars['m_cat_id'] = 0; } return $res; } /** * Builds/parses category item part of url * * @param int $rewrite_mode Mode in what rewrite listener was called. Possbile two modes: REWRITE_MODE_BUILD, REWRITE_MODE_PARSE. * @param string $prefix Prefix, that listener uses for system integration * @param Array $params Params, that are used for url building or created during url parsing. * @param Array $url_parts Url parts to parse (only for parsing). * @param bool $keep_events Keep event names in resulting url (only for building). * @return bool Return true to continue to next listener; return false (when building) not to rewrite given prefix; return false (when parsing) to stop processing at this listener. */ function CategoryItemRewriteListener($rewrite_mode = REWRITE_MODE_BUILD, $prefix, &$params, &$url_parts, $keep_events = false) { static $parsed = false; if ($rewrite_mode == REWRITE_MODE_BUILD) { return $this->_buildCategoryItemUrl($prefix, $params, $keep_events); } if (!$parsed) { $this->_modulePrefix = $this->_parseCategoryItemUrl($url_parts, $params); if ($this->_modulePrefix !== false) { $params['pass'][] = $this->_modulePrefix; $this->_partsFound[] = 'parseCategoryItemUrl'; } $parsed = true; } return true; } /** * Build category teim part of url * * @param string $prefix_special * @param Array $params * @param bool $keep_events * @return string */ function _buildCategoryItemUrl($prefix_special, &$params, $keep_events) { static $default_per_page = Array (); $ret = ''; list ($prefix) = explode('.', $prefix_special); $processed_params = $this->getProcessedParams($prefix_special, $params, $keep_events); if ($processed_params === false) { return ''; } if (!array_key_exists($prefix, $default_per_page)) { $list_helper =& $this->Application->recallObject('ListHelper'); /* @var $list_helper ListHelper */ $default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix); } if ($processed_params[$prefix_special . '_id']) { $category_id = array_key_exists('m_cat_id', $params) ? $params['m_cat_id'] : $this->Application->GetVar('m_cat_id'); // if template is also item template of category, then remove template $template = array_key_exists('t', $params) ? $params['t'] : false; $item_template = $this->GetItemTemplate($category_id, $prefix); if ($template == $item_template || strtolower($template) == '__default__') { // given template is also default template for this category item or '__default__' given $params['pass_template'] = false; } // get item's filename if ($prefix == 'bb') { $ret .= 'bb_' . $processed_params[$prefix_special . '_id'] . '/'; } else { - $filename = $this->Application->getFilename($prefix, $processed_params[$prefix_special . '_id'], $category_id); + $filename = $this->getFilename($prefix, $processed_params[$prefix_special . '_id'], $category_id); if ($filename !== false) { $ret .= $filename . '/'; } } } else { if ($processed_params[$prefix_special . '_Page'] == 1) { // when printing category items and we are on the 1st page -> there is no information about // category item prefix and $params['pass_category'] will not be added automatically $params['pass_category'] = true; } elseif ($processed_params[$prefix_special . '_Page'] > 1) { // $ret .= $processed_params[$prefix_special . '_Page'] . '/'; $params['page'] = $processed_params[$prefix_special . '_Page']; } $per_page = $processed_params[$prefix_special . '_PerPage']; if ($per_page && ($per_page != $default_per_page[$prefix])) { $params['per_page'] = $processed_params[$prefix_special . '_PerPage']; } } return mb_strtolower( rtrim($ret, '/') ); } /** + * Returns item's filename that corresponds id passed. If possible, then get it from cache + * + * @param string $prefix + * @param int $id + * @param int $category_id + * @return string + */ + function getFilename($prefix, $id, $category_id = null) + { + if ($prefix == 'c') { + throw new Exception('Method "<strong>' . __FUNCTION__ . '</strong>" no longer work with "<strong>c</strong>" prefix. Please use "<strong>getCategoryCache</strong>" method instead'); + + return false; + } + + $category_id = isset($category_id) ? $category_id : $this->Application->GetVar('m_cat_id'); + + $cache_key = 'filenames[%' . $this->Application->incrementCacheSerial($prefix, $id, false) . '%]:' . (int)$category_id; + $filename = $this->Application->getCache($cache_key); + + if ($filename === false) { + $this->Conn->nextQueryCachable = true; + $sql = 'SELECT ResourceId + FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . ' + WHERE ' . $this->Application->getUnitOption($prefix, 'IDField') . ' = ' . $this->Conn->qstr($id); + $resource_id = $this->Conn->GetOne($sql); + + $this->Conn->nextQueryCachable = true; + $sql = 'SELECT Filename + FROM ' . TABLE_PREFIX . 'CategoryItems + WHERE (ItemResourceId = ' . $resource_id . ') AND (CategoryId = ' . (int)$category_id . ')'; + $filename = $this->Conn->GetOne($sql); + + if ($filename !== false) { + $this->Application->setCache($cache_key, $filename); + } + } + + return $filename; + } + + /** * Sets template and id, corresponding to category item given in url * * @param Array $url_parts * @param Array $vars * @return bool|string */ function _parseCategoryItemUrl(&$url_parts, &$vars) { if (!$url_parts) { return false; } $item_filename = end($url_parts); if (is_numeric($item_filename)) { // this page, don't process here return false; } if (preg_match('/^bb_([\d]+)/', $item_filename, $regs)) { // process topics separatly, because they don't use item filenames array_pop($url_parts); return $this->_parseTopicUrl($regs[1], $vars); } // locating the item in CategoryItems by filename to detect its ItemPrefix and its category ParentPath $sql = 'SELECT ci.ItemResourceId, ci.ItemPrefix, c.ParentPath, ci.CategoryId FROM ' . TABLE_PREFIX . 'CategoryItems AS ci LEFT JOIN ' . TABLE_PREFIX . 'Category AS c ON c.CategoryId = ci.CategoryId WHERE (ci.CategoryId = ' . (int)$vars['m_cat_id'] . ') AND (ci.Filename = ' . $this->Conn->qstr($item_filename) . ')'; $cat_item = $this->Conn->GetRow($sql); if ($cat_item !== false) { // item found $module_prefix = $cat_item['ItemPrefix']; $item_template = $this->GetItemTemplate($cat_item, $module_prefix); // converting ResourceId to correpsonding Item id $module_config = $this->Application->getUnitOptions($module_prefix); $sql = 'SELECT ' . $module_config['IDField'] . ' FROM ' . $module_config['TableName'] . ' WHERE ResourceId = ' . $cat_item['ItemResourceId']; $item_id = $this->Conn->GetOne($sql); array_pop($url_parts); if ($item_id) { if ($item_template) { // when template is found in category -> set it $vars['t'] = $item_template; } // we have category item id $vars[$module_prefix . '_id'] = $item_id; return $module_prefix; } } return false; } /** * Set's template and topic id corresponding to topic given in url * * @param int $topic_id * @param Array $vars * @return string */ function _parseTopicUrl($topic_id, &$vars) { $sql = 'SELECT c.ParentPath, c.CategoryId FROM ' . TABLE_PREFIX . 'Category AS c WHERE c.CategoryId = ' . (int)$vars['m_cat_id']; $cat_item = $this->Conn->GetRow($sql); $item_template = $this->GetItemTemplate($cat_item, 'bb'); if ($item_template) { $vars['t'] = $item_template; } $vars['bb_id'] = $topic_id; return 'bb'; } /** * Returns enviroment variable values for given prefix (uses directly given params, when available) * * @param string $prefix_special * @param Array $params * @param bool $keep_events * @return Array */ function getProcessedParams($prefix_special, &$params, $keep_events) { list ($prefix) = explode('.', $prefix_special); $query_vars = $this->Application->getUnitOption($prefix, 'QueryString'); if (!$query_vars) { // given prefix doesn't use "env" variable to pass it's data return false; } $event_key = array_search('event', $query_vars); if ($event_key) { // pass through event of this prefix unset($query_vars[$event_key]); } if (array_key_exists($prefix_special . '_event', $params) && !$params[$prefix_special . '_event']) { // if empty event, then remove it from url unset( $params[$prefix_special . '_event'] ); } // if pass events is off and event is not implicity passed if (!$keep_events && !array_key_exists($prefix_special . '_event', $params)) { unset($params[$prefix_special . '_event']); // remove event from url if requested //otherwise it will use value from get_var } $processed_params = Array (); 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; $processed_params[$var_name] = array_key_exists($var_name, $params) ? $params[$var_name] : $this->Application->GetVar($var_name); if (array_key_exists($var_name, $params)) { unset($params[$var_name]); } } return $processed_params; } /** * Returns module item details template specified in given category custom field for given module prefix * * @param int|Array $category * @param string $module_prefix * @return string */ function GetItemTemplate($category, $module_prefix) { $category_id = is_array($category) ? $category['CategoryId'] : $category; $cache_key = __CLASS__ . '::' . __FUNCTION__ . '[%CIDSerial:' . $category_id . '%]:' . $module_prefix; $cached_value = $this->Application->getCache($cache_key); if ($cached_value !== false) { return $cached_value; } if (!is_array($category)) { if ($category == 0) { $category = $this->Application->findModule('Var', $module_prefix, 'RootCat'); } $sql = 'SELECT c.ParentPath, c.CategoryId FROM ' . TABLE_PREFIX . 'Category AS c WHERE c.CategoryId = ' . $category; $category = $this->Conn->GetRow($sql); } $parent_path = implode(',',explode('|', substr($category['ParentPath'], 1, -1))); // item template is stored in module' system custom field - need to get that field Id $primary_lang = $this->Application->GetDefaultLanguageId(); $item_template_field_id = $this->getItemTemplateCustomField($module_prefix); // looking for item template through cats hierarchy sorted by parent path $query = ' SELECT ccd.l' . $primary_lang . '_cust_' . $item_template_field_id . ', FIND_IN_SET(c.CategoryId, ' . $this->Conn->qstr($parent_path) . ') AS Ord1, c.CategoryId, c.Name, ccd.l' . $primary_lang . '_cust_' . $item_template_field_id . ' FROM ' . TABLE_PREFIX . 'Category AS c LEFT JOIN ' . TABLE_PREFIX . 'CategoryCustomData AS ccd ON ccd.ResourceId = c.ResourceId WHERE c.CategoryId IN (' . $parent_path . ') AND ccd.l' . $primary_lang . '_cust_' . $item_template_field_id . ' != \'\' ORDER BY FIND_IN_SET(c.CategoryId, ' . $this->Conn->qstr($parent_path) . ') DESC'; $item_template = $this->Conn->GetOne($query); if (!isset($this->_templateAliases)) { // when empty url OR mod-rewrite disabled $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $sql = 'SELECT TemplateAliases FROM ' . TABLE_PREFIX . 'Theme WHERE ThemeId = ' . (int)$themes_helper->getCurrentThemeId(); $template_aliases = $this->Conn->GetOne($sql); $this->_templateAliases = $template_aliases ? unserialize($template_aliases) : Array (); } if ($item_template && array_key_exists($item_template, $this->_templateAliases)) { $item_template = $this->_templateAliases[$item_template]; } $this->Application->setCache($cache_key, $item_template); return $item_template; } /** * Loads all registered rewrite listeners, so they could be quickly accessed later * */ function initRewriteListeners() { static $init_done = false; if ($init_done || count($this->Application->RewriteListeners) == 0) { // not inited OR mod-rewrite url with missing config cache return ; } foreach ($this->Application->RewriteListeners as $prefix => $listener_data) { foreach ($listener_data['listener'] as $index => $rewrite_listener) { list ($listener_prefix, $listener_method) = explode(':', $rewrite_listener); $listener =& $this->Application->recallObject($listener_prefix); $this->Application->RewriteListeners[$prefix][$index] = Array (&$listener, $listener_method); } } define('MOD_REWRITE_URL_ENDING', $this->Application->ConfigValue('ModRewriteUrlEnding')); $init_done = true; } /** * Returns category custom field id, where given module prefix item template name is stored * * @param string $module_prefix * @return int */ function getItemTemplateCustomField($module_prefix) { $cache_key = __CLASS__ . '::' . __FUNCTION__ . '[%CfSerial%]:' . $module_prefix; $cached_value = $this->Application->getCache($cache_key); if ($cached_value !== false) { return $cached_value; } $sql = 'SELECT CustomFieldId FROM ' . TABLE_PREFIX . 'CustomField WHERE FieldName = ' . $this->Conn->qstr($module_prefix . '_ItemTemplate'); $item_template_field_id = $this->Conn->GetOne($sql); $this->Application->setCache($cache_key, $item_template_field_id); return $item_template_field_id; } /** * Sets default parsed values before actual url parsing (only, for empty url) * * @param Array $vars */ function _setDefaultValues(&$vars) { $defaults = Array ( 'm_cat_id' => 0, // no category 'm_cat_page' => 1, // first category page 'm_opener' => 's', // stay on same page 't' => 'index' // main site page ); if ($this->primaryLanguageId) { // domain-based primary language $defaults['m_lang'] = $this->primaryLanguageId; } if ($this->primaryThemeId) { // domain-based primary theme $defaults['m_theme'] = $this->primaryThemeId; } foreach ($defaults as $default_key => $default_value) { if ($this->HTTPQuery->Get($default_key) === false) { $vars[$default_key] = $default_value; } } } } Index: branches/5.2.x/core/units/configuration/configuration_event_handler.php =================================================================== --- branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 14183) +++ branches/5.2.x/core/units/configuration/configuration_event_handler.php (revision 14184) @@ -1,291 +1,291 @@ <?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 ConfigurationEventHandler extends kDBEventHandler { /** * Changes permission section to one from REQUEST, not from config * * @param kEvent $event */ function CheckPermission(&$event) { $event->setEventParam('PermSection', $this->Application->GetVar('section')); return parent::CheckPermission($event); } /** * Apply any custom changes to list's sql query * * @param kEvent $event * @access protected * @see OnListBuild */ function SetCustomQuery(&$event) { $object =& $event->getObject(); /* @var $object kDBList */ $module = $this->Application->GetVar('module'); $section = $this->Application->GetVar('section'); $object->addFilter('module_filter', '%1$s.ModuleOwner = '.$this->Conn->qstr($module)); $object->addFilter('section_filter', '%1$s.Section = '.$this->Conn->qstr($section)); if (!$this->Application->ConfigValue('AllowAdminConsoleInterfaceChange')) { $object->addFilter('interface_change_filter', '%1$s.VariableName <> "AdminConsoleInterface"'); } if (defined('IS_INSTALL') && IS_INSTALL) { $object->addFilter('install_filter', '%1$s.Install = 1'); } $object->addFilter('visible_filter', '%1$s.Heading <> ""'); } /** * Enter description here... * * @param kEvent $event */ function OnBeforeItemUpdate(&$event) { static $default_field_options = null; $object =& $event->getObject(); /* @var $object kDBItem */ // ability to validate each configuration variable separately if (!isset($default_field_options)) { $default_field_options = $object->GetFieldOptions('VariableValue'); } $new_field_options = $default_field_options; $validation = $object->GetDBField('Validation'); if ($validation) { $new_field_options = array_merge($new_field_options, unserialize($validation)); } $object->SetFieldOptions('VariableValue', $new_field_options); // if password field is empty, then don't update if ($object->GetDBField('ElementType') == 'password') { if (trim($object->GetDBField('VariableValue')) == '') { $field_options = $object->GetFieldOptions('VariableValue'); $field_options['skip_empty'] = 1; $object->SetFieldOptions('VariableValue', $field_options); }else { $password_formatter =& $this->Application->recallObject('kPasswordFormatter'); $object->SetDBField('VariableValue', $password_formatter->EncryptPassword($object->GetDBField('VariableValue'), 'b38')); } } $field_values = $this->Application->GetVar( $event->getPrefixSpecial(true) ); $state_country_hash = Array ( 'Comm_State' => 'Comm_Country', 'Comm_Shipping_State' => 'Comm_Shipping_Country' ); $field_name = $object->GetDBField('VariableName'); if (array_key_exists($field_name, $state_country_hash)) { // if this is state field $sql = 'SELECT VariableId FROM ' . $this->Application->getUnitOption('conf', 'TableName') . ' WHERE VariableName = "' . $state_country_hash[$field_name] . '"'; $country_variable_id = $this->Conn->GetOne($sql); $check_state = $object->GetDBField('VariableValue'); $check_country = $field_values[$country_variable_id]['VariableValue']; if (!$check_country || !$check_state) { return true; } $cs_helper =& $this->Application->recallObject('CountryStatesHelper'); /* @var $cs_helper kCountryStatesHelper */ $state_iso = $cs_helper->getStateIso($check_state, $check_country); if ($state_iso !== false) { $object->SetDBField('VariableValue', $state_iso); } else { // selected state doesn't belong to selected country $object->SetError('VariableValue', 'invalid_state', 'la_InvalidState'); } } if ($object->GetDBField('VariableName') == 'AdminConsoleInterface') { $can_change = $this->Application->ConfigValue('AllowAdminConsoleInterfaceChange'); if (($object->GetDBField('VariableValue') != $object->GetOriginalField('VariableValue')) && !$can_change) { $object->SetError('VariableValue', 'not_allowed', 'la_error_NotAllowed'); } } } /** * Enter description here... * * @param kEvent $event */ function OnAfterItemUpdate(&$event) { $object =& $event->getObject(); /* @var $object kDBItem */ if ($object->GetDBField('ElementType') == 'password') { if (trim($object->GetDBField('VariableValue')) == '') { $field_options = $object->GetFieldOptions('VariableValue'); unset($field_options['skip_empty']); $object->SetFieldOptions('VariableValue', $field_options); } } // allows to check if variable's value was changed now $variable_name = $object->GetDBField('VariableName'); $variable_value = $object->GetDBField('VariableValue'); $watch_variables = Array ( 'Require_AdminSSL', 'AdminSSL_URL', 'AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface' ); if (in_array($variable_name, $watch_variables)) { $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); if ($variable_value != $object->GetOriginalField('VariableValue')) { $changed[] = $variable_name; $this->Application->SetVar($event->getPrefixSpecial() . '_changed', $changed); } switch ($variable_name) { case 'Require_AdminSSL': case 'AdminSSL_URL': static $skin_deleted = false; if (in_array($variable_name, $changed) && !$skin_deleted) { // when administrative console is moved to SSL mode, then delete skin $skin_helper =& $this->Application->recallObject('SkinHelper'); /* @var $skin_helper SkinHelper */ $skin_file = $skin_helper->getSkinPath(); if (file_exists($skin_file)) { unlink($skin_file); } $skin_deleted = true; } break; } } } /** * Enter description here... * * @param kEvent $event */ function OnUpdate(&$event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = kEvent::erFAIL; return ; } $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); // 1. save user selected module root category $new_category_id = getArrayValue($items_info, 'ModuleRootCategory', 'VariableValue'); if ($new_category_id !== false) { unset($items_info['ModuleRootCategory']); } $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ if ($items_info) { $has_error = false; foreach ($items_info as $id => $field_values) { $object->Clear(); // clear validation errors from previous variable $object->Load($id); $object->SetFieldsFromHash($field_values); if (!$object->Update($id)) { // don't stop when error found ! $has_error = true; } } $event->status = $has_error ? kEvent::erFAIL : kEvent::erSUCCESS; } if ($event->status == kEvent::erSUCCESS) { if ($new_category_id !== false) { // root category was submitted $module = $this->Application->GetVar('module'); $root_category_id = $this->Application->findModule('Name', $module, 'RootCat'); if ($root_category_id != $new_category_id) { // root category differs from one in db $fields_hash = Array('RootCat' => $new_category_id); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'Modules', 'Name = '.$this->Conn->qstr($module)); } } // reset cache $changed = $this->Application->GetVar($event->getPrefixSpecial() . '_changed', Array ()); $require_refresh = Array ( 'AdvancedUserManagement', 'Site_Name', 'AdminConsoleInterface' ); $refresh_sections = array_intersect($require_refresh, $changed); $require_full_refresh = Array ('Site_Name', 'AdminConsoleInterface'); if (array_intersect($require_full_refresh, $changed)) { $event->SetRedirectParam('refresh_all', 1); } elseif ($refresh_sections) { // reset sections too, because of AdvancedUserManagement $event->SetRedirectParam('refresh_tree', 1); } - $this->Application->UnitConfigReader->ResetParsedData($refresh_sections ? true : false); + $this->Application->DeleteUnitCache($refresh_sections ? true : false); } elseif ($this->Application->GetVar('errors_' . $event->getPrefixSpecial())) { // because we have list out there, and this is item $this->Application->removeObject( $event->getPrefixSpecial() ); } // keeps module and section in REQUEST to ensure, that last admin template will work $event->SetRedirectParam('module', $this->Application->GetVar('module')); $event->SetRedirectParam('section', $this->Application->GetVar('section')); } /** * Process items from selector (selected_ids var, key - prefix, value - comma separated ids) * * @param kEvent $event */ function OnProcessSelected(&$event) { $selected_ids = $this->Application->GetVar('selected_ids'); $this->Application->StoreVar('ModuleRootCategory', $selected_ids['c']); $event->SetRedirectParam('opener', 'u'); } } \ No newline at end of file Index: branches/5.2.x/core/units/modules/modules_event_handler.php =================================================================== --- branches/5.2.x/core/units/modules/modules_event_handler.php (revision 14183) +++ branches/5.2.x/core/units/modules/modules_event_handler.php (revision 14184) @@ -1,196 +1,196 @@ <?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 ModulesEventHandler extends kDBEventHandler { /** * Builds item * * @param kEvent $event * @access protected */ function OnItemBuild(&$event) { $this->Application->SetVar($event->getPrefixSpecial(true).'_id', $event->Special); parent::OnItemBuild($event); } /** * List with one record if special passed * * @param kEvent $event */ function SetCustomQuery(&$event) { $object =& $event->getObject(); if ($event->Special) { $object->addFilter('current_module', 'Name = '.$event->Special); } $object->addFilter('not_core', '%1$s.Name <> "Core"'); } function mapEvents() { parent::mapEvents(); $this->eventMethods['OnMassApprove'] = 'moduleAction'; $this->eventMethods['OnMassDecline'] = 'moduleAction'; } /** * Disabled modules, but not In-Portal * * @param kEvent $event */ function moduleAction(&$event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = kEvent::erFAIL; return ; } $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ $ids = $this->StoreSelectedIDs($event); if (!$ids) { return ; } $updated = 0; $status_field = $this->Application->getUnitOption($event->Prefix, 'StatusField'); $status_field = array_shift($status_field); foreach ($ids as $id) { $object->Load($id); if (in_array($id, Array ('In-Portal', 'Core')) || !$object->isLoaded()) { // don't allow any kind of manupulations with kernel // approve/decline on not installed module continue; } $enabled = $event->Name == 'OnMassApprove' ? 1 : 0; $object->SetDBField($status_field, $enabled); if (!$object->GetChangedFields()) { // no changes -> skip continue; } if ($object->Update()) { $updated++; $sql = 'UPDATE ' . TABLE_PREFIX . 'ImportScripts SET Status = ' . $enabled . ' WHERE Module = "' . $object->GetDBField('Name') . '"'; $this->Conn->Query($sql); } else { $event->status = kEvent::erFAIL; $event->redirect = false; break; } } if ($updated) { $event->status = kEvent::erSUCCESS; $event->setRedirectParams(Array ('opener' => 's'), true); - $this->Application->UnitConfigReader->ResetParsedData(true); //true to reset sections cache also + $this->Application->DeleteUnitCache(true); //true to reset sections cache also $event->SetRedirectParam('RefreshTree', 1); } } /** * Occures after list is queried * * @param kEvent $event */ function OnAfterListQuery(&$event) { parent::OnAfterListQuery($event); $new_modules = $this->_getNewModules(); if (!$new_modules || $this->Application->RecallVar('user_id') != USER_ROOT) { return ; } require_once FULL_PATH . '/core/install/install_toolkit.php'; $toolkit = new kInstallToolkit(); $object =& $event->getObject(); /* @var $object kDBList */ foreach ($new_modules as $module) { $module_record = Array ( 'Name' => $toolkit->getModuleName($module), 'Path' => 'modules/' . $module . '/', 'Version' => $toolkit->GetMaxModuleVersion('modules/' . $module . '/'), 'Loaded' => 0, 'BuildDate' => null, ); $object->addRecord($module_record); } } /** * Returns list of modules, that are not installed, but available in file system * * @return Array */ function _getNewModules() { $modules_helper =& $this->Application->recallObject('ModulesHelper'); /* @var $modules_helper kModulesHelper */ $modules = Array (); if ($dir = @opendir(MODULES_PATH)) { while (($file = readdir($dir)) !== false) { if ($file != '.' && $file != '..') { $module_folder = MODULES_PATH . '/' . $file; if (is_dir($module_folder) && $this->_isModule($module_folder)) { // this is module -> check if it's installed already if (!$modules_helper->moduleInstalled($file)) { $install_order = trim( file_get_contents($module_folder . '/install/install_order.txt') ); $modules[$install_order] = $file; } } } } closedir($dir); } // allows to control module install order ksort($modules, SORT_NUMERIC); return $modules; } /** * Checks, that given folder is module root folder * * @param string $folder * @return bool */ function _isModule($folder) { return file_exists($folder . '/install.php') && file_exists($folder . '/install/install_schema.sql'); } } \ No newline at end of file Index: branches/5.2.x/core/units/admin/admin_events_handler.php =================================================================== --- branches/5.2.x/core/units/admin/admin_events_handler.php (revision 14183) +++ branches/5.2.x/core/units/admin/admin_events_handler.php (revision 14184) @@ -1,1377 +1,1380 @@ <?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 AdminEventsHandler extends kDBEventHandler { function mapPermissions() { parent::mapPermissions(); $permissions = Array( 'OnSaveColumns' => array('self' => true), 'OnClosePopup' => array('self' => true), 'OnSaveSetting' => array('self' => true), // export/import permissions is checked within events 'OnExportCSV' => Array('self' => true), 'OnGetCSV' => Array('self' => true), 'OnCSVImportBegin' => Array('self' => true), 'OnCSVImportStep' => Array('self' => true), 'OnDropTempTablesByWID' => Array('self' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Checks permissions of user * * @param kEvent $event */ function CheckPermission(&$event) { $perm_value = null; $system_events = Array ( 'OnResetModRwCache', 'OnResetSections', 'OnResetConfigsCache', 'OnResetParsedData', 'OnResetMemcache', 'OnDeleteCompiledTemplates', 'OnCompileTemplates', 'OnGenerateTableStructure', 'OnRebuildThemes', 'OnCheckPrefixConfig', 'OnMemoryCacheGet', 'OnMemoryCacheSet' ); if (in_array($event->Name, $system_events)) { // events from "Tools -> System Tools" section are controlled via that section "edit" permission $perm_value = /*$this->Application->isDebugMode() ||*/ $this->Application->CheckPermission($event->getSection() . '.edit'); } $tools_events = Array ( 'OnBackup' => 'in-portal:backup.view', 'OnBackupProgress' => 'in-portal:backup.view', 'OnDeleteBackup' => 'in-portal:backup.view', 'OnBackupCancel' => 'in-portal:backup.view', 'OnRestore' => 'in-portal:restore.view', 'OnRestoreProgress' => 'in-portal:restore.view', 'OnRestoreCancel' => 'in-portal:backup.view', 'OnSqlQuery' => 'in-portal:sql_query.view', ); if (array_key_exists($event->Name, $tools_events)) { $perm_value = $this->Application->CheckPermission($tools_events[$event->Name]); } if ($event->Name == 'OnSaveMenuFrameWidth') { $perm_value = $this->Application->isAdminUser; } if (isset($perm_value)) { $perm_helper =& $this->Application->recallObject('PermissionsHelper'); /* @var $perm_helper kPermissionsHelper */ return $perm_helper->finalizePermissionCheck($event, $perm_value); } return parent::CheckPermission($event); } /** * Enter description here... * * @param kEvent $event */ function OnResetModRwCache(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } $this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls'); } function OnResetSections(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $this->Application->deleteCache('master:sections_parsed'); } else { $this->Application->deleteDBCache('sections_parsed'); } $event->SetRedirectParam('refresh_tree', 1); } function OnResetConfigsCache(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { $this->Application->deleteCache('master:config_files'); } else { $this->Application->deleteDBCache('config_files'); } $this->OnResetParsedData($event); $skin_helper =& $this->Application->recallObject('SkinHelper'); /* @var $skin_helper SkinHelper */ $skin_helper->deleteCompiled(); } /** * Resets parsed data from unit configs * * @param kEvent $event */ function OnResetParsedData(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = erSTOP; } - $this->Application->UnitConfigReader->ResetParsedData(); + $this->Application->DeleteUnitCache(); if ( $this->Application->GetVar('validate_configs') ) { $event->SetRedirectParam('validate_configs', 1); } } function OnResetMemcache(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } - if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) { - $this->Application->memoryCache->reset(); - } + $this->Application->resetCache(); } function OnCompileTemplates(&$event) { $compiler =& $this->Application->recallObject('NParserCompiler'); /* @var $compiler NParserCompiler */ $compiler->CompileTemplatesStep(); $event->status = kEvent::erSTOP; } /** * Deletes all compiled templates * * @param kEvent $event */ function OnDeleteCompiledTemplates(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } $base_path = WRITEABLE . DIRECTORY_SEPARATOR . 'cache'; // delete debugger reports $debugger_reports = glob($base_path . '/debug_@*@.txt'); foreach ($debugger_reports as $debugger_report) { unlink($debugger_report); } $this->_deleteCompiledTemplates($base_path); } function _deleteCompiledTemplates($folder, $unlink_folder = false) { $sub_folders = glob($folder . '/*', GLOB_ONLYDIR); foreach ($sub_folders as $sub_folder) { $this->_deleteCompiledTemplates($sub_folder, true); } $files = glob($folder . '/*.php'); foreach ($files as $file) { unlink($file); } if ($unlink_folder) { rmdir($folder); } } /** * Generates sturcture for specified table * * @param kEvent $event * @author Alex */ function OnGenerateTableStructure(&$event) { $types_hash = Array( 'string' => 'varchar|text|mediumtext|longtext|date|datetime|time|timestamp|char|year|enum|set', 'int' => 'smallint|mediumint|int|bigint|tinyint', 'float' => 'float|double|decimal', ); $table_name = $this->Application->GetVar('table_name'); if (!$table_name) { echo 'error: no table name specified'; return ; } if (TABLE_PREFIX && !preg_match('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', $table_name) && (strtolower($table_name) != $table_name)) { // table name without prefix, then add it (don't affect K3 tables named in lowercase) $table_name = TABLE_PREFIX.$table_name; } if (!$this->Conn->TableFound($table_name)) { // table with prefix doesn't exist, assume that just config prefix passed -> resolve table name from it $prefix = preg_replace('/^' . preg_quote(TABLE_PREFIX, '/') . '/', '', $table_name); if ($this->Application->prefixRegistred($prefix)) { // when prefix is found -> use it's table (don't affect K3 tables named in lowecase) $table_name = $this->Application->getUnitOption($prefix, 'TableName'); } } $table_info = $this->Conn->Query('DESCRIBE '.$table_name); // 1. prepare config keys $grids = Array ( 'Default' => Array ( 'Icons' => Array ('default' => 'icon16_item.png'), 'Fields' => Array (), ) ); $grid_fields = Array(); $id_field = ''; $fields = Array(); $float_types = Array ('float', 'double', 'numeric'); foreach ($table_info as $field_info) { if (preg_match('/l[\d]+_.*/', $field_info['Field'])) { // don't put multilingual fields in config continue; } $field_options = Array (); $grid_col_options = Array( 'title' => 'la_col_' . $field_info['Field'], 'filter_block' => 'grid_like_filter', ); // 1. get php field type by mysql field type foreach ($types_hash as $php_type => $db_types) { if (preg_match('/'.$db_types.'/', $field_info['Type'])) { $field_options['type'] = $php_type; break; } } // 2. get field default value $default_value = $field_info['Default']; $not_null = $field_info['Null'] != 'YES'; if (is_numeric($default_value)) { $default_value = preg_match('/[\.,]/', $default_value) ? (float)$default_value : (int)$default_value; } if ( is_null($default_value) && $not_null ) { $default_value = $field_options['type'] == 'string' ? '' : 0; } if ( in_array($php_type, $float_types) ) { // this is float number if (preg_match('/'.$db_types.'\([\d]+,([\d]+)\)/i', $field_info['Type'], $regs)) { // size is described in structure -> add formatter $field_options['formatter'] = 'kFormatter'; $field_options['format'] = '%01.'.$regs[1].'f'; if ($not_null) { // null fields, will most likely have NULL as default value $default_value = 0; } } elseif ($not_null) { // no size information, just convert to float // null fields, will most likely have NULL as default value $default_value = (float)$default_value; } } if (preg_match('/varchar\(([\d]+)\)/i', $field_info['Type'], $regs)) { $field_options['max_len'] = (int)$regs[1]; } if (preg_match('/tinyint\([\d]+\)/i', $field_info['Type'])) { $field_options['formatter'] = 'kOptionsFormatter'; $field_options['options'] = Array (1 => 'la_Yes', 0 => 'la_No'); $field_options['use_phrases'] = 1; $grid_col_options['filter_block'] = 'grid_options_filter'; } if ($not_null) { $field_options['not_null'] = 1; } if ($field_info['Key'] == 'PRI') { $default_value = 0; $id_field = $field_info['Field']; } if ($php_type == 'int' && !$not_null) { // numeric null field if (preg_match('/(On|Date)$/', $field_info['Field']) || $field_info['Field'] == 'Modified') { $field_options['formatter'] = 'kDateFormatter'; $grid_col_options['filter_block'] = 'grid_date_rage_filter'; } } if ($php_type == 'int' && ($not_null || is_numeric($default_value))) { // is integer field AND not null $field_options['default'] = (int)$default_value; } else { $field_options['default'] = $default_value; } $fields[ $field_info['Field'] ] = $field_options; $grids_fields[ $field_info['Field'] ] = $grid_col_options; } $grids['Default']['Fields'] = $grids_fields; $ret = Array ( 'IDField' => $id_field, 'Fields' => $fields, 'Grids' => $grids, ); $decorator = new UnitConfigDecorator(); $ret = $decorator->decorate($ret); $this->Application->InitParser(); ob_start(); echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"')); ?> <script type="text/javascript"> set_window_title('Table "<?php echo $table_name; ?>" Structure'); </script> <a href="javascript:window_close();">Close Window</a><br /><br /> <?php echo $GLOBALS['debugger']->highlightString($ret); ?> <br /><br /><a href="javascript:window_close();">Close Window</a><br /> <?php echo $this->Application->ParseBlock(Array('name' => 'incs/footer')); echo ob_get_clean(); $event->status = kEvent::erSTOP; } /** * Refreshes ThemeFiles & Theme tables by actual content on HDD * * @param kEvent $event */ function OnRebuildThemes(&$event) { if ($this->Application->GetVar('ajax') == 'yes') { $event->status = kEvent::erSTOP; } $themes_helper =& $this->Application->recallObject('ThemesHelper'); /* @var $themes_helper kThemesHelper */ $themes_helper->refreshThemes(); } function OnSaveColumns(&$event) { $picker_helper =& $this->Application->recallObject('ColumnPickerHelper'); /* @var $picker_helper kColumnPickerHelper */ $picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name')); $picked = trim($this->Application->GetVar('picked_str'), '|'); $hidden = trim($this->Application->GetVar('hidden_str'), '|'); $main_prefix = $this->Application->GetVar('main_prefix'); $picker_helper->SaveColumns($main_prefix, $picked, $hidden); $this->finalizePopup($event); } /** * Saves various admin settings via ajax * * @param kEvent $event */ function OnSaveSetting(&$event) { if ($this->Application->GetVar('ajax') != 'yes') { return ; } $var_name = $this->Application->GetVar('var_name'); $var_value = $this->Application->GetVar('var_value'); $this->Application->StorePersistentVar($var_name, $var_value); $event->status = kEvent::erSTOP; } /** * Just closes popup & deletes last_template & opener_stack if popup, that is closing * * @param kEvent $event */ function OnClosePopup(&$event) { $event->SetRedirectParam('opener', 'u'); } /** * Occurs right after initialization of the kernel, used mainly as hook-to event * * @param kEvent $event */ function OnStartup(&$event) { } /** * Occurs right before echoing the output, in Done method of application, used mainly as hook-to event * * @param kEvent $event */ function OnBeforeShutdown(&$event) { } /** * Is called after tree was build (when not from cache) * * @param kEvent $event */ function OnAfterBuildTree(&$event) { } /** * Called by AJAX to perform CSV export * * @param kEvent $event */ function OnExportCSV(&$event) { $export_helper =& $this->Application->recallObject('CSVHelper'); /* @var $export_helper kCSVHelper */ $prefix_special = $this->Application->GetVar('PrefixSpecial'); if(!$prefix_special) { $prefix_special = $export_helper->ExportData('prefix'); } $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) { $event->status = kEvent::erPERM_FAIL; return ; } $export_helper->PrefixSpecial = $prefix_special; $export_helper->grid = $this->Application->GetVar('grid'); $export_helper->ExportStep(); $event->status = kEvent::erSTOP; } /** * Returning created by AJAX CSV file * * @param kEvent $event */ function OnGetCSV(&$event) { $export_helper =& $this->Application->recallObject('CSVHelper'); /* @var $export_helper kCSVHelper */ $prefix_special = $export_helper->ExportData('prefix'); $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) { $event->status = kEvent::erPERM_FAIL; return ; } $export_helper->GetCSV(); } /** * Enter description here... * * @param kEvent $event */ function OnCSVImportBegin(&$event) { $prefix_special = $this->Application->GetVar('PrefixSpecial'); $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) { $event->status = kEvent::erPERM_FAIL; return ; } $object =& $event->getObject( Array('skip_autoload' => true) ); /* @var $object kDBItem */ $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); $field_values = array_shift($items_info); $object->SetFieldsFromHash($field_values); $event->redirect = false; $result = 'required'; if($object->GetDBField('ImportFile')) { $import_helper =& $this->Application->recallObject('CSVHelper'); /* @var $import_helper kCSVHelper */ $import_helper->PrefixSpecial = $this->Application->GetVar('PrefixSpecial'); $import_helper->grid = $this->Application->GetVar('grid'); $result = $import_helper->ImportStart( $object->GetField('ImportFile', 'file_paths') ); if($result === true) { $event->redirect = $this->Application->GetVar('next_template'); $event->SetRedirectParam('PrefixSpecial', $this->Application->GetVar('PrefixSpecial')); $event->SetRedirectParam('grid', $this->Application->GetVar('grid')); } } if($event->redirect === false) { $object->SetError('ImportFile', $result); $event->status = kEvent::erFAIL; } } /** * Enter description here... * * @param kEvent $event */ function OnCSVImportStep(&$event) { $import_helper =& $this->Application->recallObject('CSVHelper'); /* @var $export_helper kCSVHelper */ $prefix_special = $import_helper->ImportData('prefix'); $prefix_elems = split('\.|_', $prefix_special, 2); $perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection'); if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) { $event->status = kEvent::erPERM_FAIL; return ; } $import_helper->ImportStep(); $event->status = kEvent::erSTOP; } /** * Shows unit config filename, where requested prefix is defined * * @param kEvent $event */ function OnCheckPrefixConfig(&$event) { $prefix = $this->Application->GetVar('config_prefix'); $config_file = $this->Application->UnitConfigReader->prefixFiles[$prefix]; $this->Application->InitParser(); ob_start(); echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"')); ?> <script type="text/javascript"> set_window_title('Unit Config of "<?php echo $prefix; ?>" prefix'); </script> <a href="javascript:window_close();">Close Window</a><br /><br /> <strong>Prefix:</strong> <?php echo $prefix; ?><br /> <strong>Unit Config:</strong> <?php echo $GLOBALS['debugger']->highlightString($config_file); ?><br /> <br /><a href="javascript:window_close();">Close Window</a><br /> <?php echo $this->Application->ParseBlock(Array('name' => 'incs/footer')); echo ob_get_clean(); $event->status = kEvent::erSTOP; } function OnDropTempTablesByWID(&$event) { $sid = $this->Application->GetSID(); $wid = $this->Application->GetVar('m_wid'); $tables = $this->Conn->GetCol('SHOW TABLES'); $mask_edit_table = '/'.TABLE_PREFIX.'ses_'.$sid.'_'.$wid.'_edit_(.*)$/'; foreach($tables as $table) { if( preg_match($mask_edit_table,$table,$rets) ) { $this->Conn->Query('DROP TABLE IF EXISTS '.$table); } } echo 'OK'; $event->status = kEvent::erSTOP; return ; } /** * Backup all data * * @param kEvent $event */ function OnBackup(&$event) { $backup_path = $this->Application->ConfigValue('Backup_Path'); $file_helper =& $this->Application->recallObject('FileHelper'); /* @var $file_helper FileHelper */ if (!$file_helper->CheckFolder($backup_path) || !is_writable($backup_path)) { $event->status = kEvent::erFAIL; $this->Application->SetVar('error_msg', $this->Application->Phrase('la_Text_backup_access')); return ; } $a_tables = $this->Conn->GetCol('SHOW TABLES'); // array_keys($tables); $TableNames = Array(); for($x=0;$x<count($a_tables);$x++) { if(substr($a_tables[$x],0,strlen(TABLE_PREFIX))==TABLE_PREFIX) { if (!strstr($a_tables[$x], 'ses_')) { $TableNames[] = $a_tables[$x]; } } } $backupProgress = Array ( 'table_num' => 0, 'table_names' => $TableNames, 'table_count' => count($TableNames), 'record_count' => 0, 'file_name' => $backup_path."/dump".adodb_mktime().".txt", ); $this->Application->RemoveVar('adm.backupcomplete_filename'); $this->Application->RemoveVar('adm.backupcomplete_filesize'); $out = array(); for($x=0;$x<count($TableNames);$x++) { if (!strstr($TableNames[$x], 'ses_')) { $out[] = $this->GetTableCreate($TableNames[$x]); } } $fp = fopen($backupProgress['file_name'], 'a'); $sql = "SELECT Name, Version FROM ".TABLE_PREFIX."Modules"; $r = $this->Conn->Query($sql); foreach ($r AS $a_module) { $version = $a_module['Version']; fwrite($fp, "# ".$a_module['Name']." Version: $version;\n"); } fwrite($fp, "#------------------------------------------\n\n"); fwrite($fp,implode("\n",$out)); fwrite($fp,"\n"); fclose($fp); $this->Application->StoreVar('adm.backup_status', serialize($backupProgress)); $event->redirect = 'tools/backup2'; } /** * Perform next backup step * * @param kEvent $event */ function OnBackupProgress(&$event) { $done_percent = $this->performBackup(); if ($done_percent == 100) { $event->redirect = 'tools/backup3'; return ; } echo $done_percent; $event->status = kEvent::erSTOP; } /** * Stops Backup & redirect to Backup template * * @param kEvent $event */ function OnBackupCancel(&$event) { $event->redirect = 'tools/backup1'; } /** * Stops Restore & redirect to Restore template * * @param kEvent $event */ function OnRestoreCancel(&$event) { $event->redirect = 'tools/restore1'; } function performBackup() { $backupProgress = unserialize($this->Application->RecallVar('adm.backup_status')); // echo "<pre>"; print_r($backupProgress); echo "</pre>"; // exit; $CurrentTable = $backupProgress['table_names'][$backupProgress['table_num']]; // get records $a_records = $this->insert_data($CurrentTable,$backupProgress['record_count'],50,""); // echo "<pre>"; print_r($a_records); echo "</pre>"; // exit; if ($a_records['num'] < 50) { $backupProgress['table_num']++; // if ($backupProgress['table_names'][$backupProgress['table_num']] == TABLE_PREFIX.'Cache') { // $backupProgress['table_num']++; // } $backupProgress['record_count'] = 0; } else { $backupProgress['record_count']+=50; } if ($a_records['sql']) { $fp = fopen($backupProgress['file_name'], 'a'); fwrite($fp, $a_records['sql']); fclose($fp); } $percent = ($backupProgress['table_num'] / $backupProgress['table_count']) * 100; if ($percent >= 100) { $percent = 100; $this->Application->StoreVar('adm.backupcomplete_filename', $backupProgress['file_name']); $this->Application->StoreVar('adm.backupcomplete_filesize', round(filesize($backupProgress['file_name'])/1024/1024, 2)); // Mbytes } else { $this->Application->StoreVar('adm.backup_status', serialize($backupProgress)); } return round($percent); } //extracts the rows of data from tables using limits function insert_data($table, $start, $limit, $mywhere) { // global $out; if ($mywhere !="") { $whereclause= " WHERE ".$mywhere." "; } else { $whereclause = ""; } $a_data = $this->Conn->Query("SELECT * from $table $whereclause LIMIT $start, $limit"); // echo "SELECT * from $table $whereclause LIMIT $start, $limit"; // echo "<pre>"; print_r($a_records); echo "</pre>"; // exit; if (!$a_data) { return Array( 'num' => 0, 'sql' => '', ); } // $prefix = GetTablePrefix(); $rowcount = 0; $a_fields = array_keys($a_data[0]); $fields_sql = ''; foreach ($a_fields AS $field_name) { $fields_sql .= '`'.$field_name.'`,'; } $fields_sql = substr($fields_sql, 0, -1); $temp = ''; foreach ($a_data AS $a_row) { $values_sql = ''; foreach ($a_row as $field_name => $field_value) { $values_sql .= $this->Conn->qstr($field_value).','; } $values_sql = substr($values_sql, 0, -1); $sql = 'INSERT INTO '.$table.' ('.$fields_sql.') VALUES ('.$values_sql.');'; $sql = str_replace("\n", "\\n", $sql); $sql = str_replace("\r", "\\r", $sql); $temp .= $sql."\n"; } if(strlen(TABLE_PREFIX)) { $temp = str_replace("INSERT INTO ".TABLE_PREFIX, "INSERT INTO ", $temp); } return Array( 'num' => count($a_data), 'sql' => $temp, ); } function GetTableCreate($table, $crlf="\n") { $schema_create = 'DROP TABLE IF EXISTS ' . $table . ';' . $crlf; $schema_create .="# --------------------------------------------------------".$crlf; $this->Conn->Query("SET SQL_QUOTE_SHOW_CREATE = 0"); $tmpres = $this->Conn->Query("SHOW CREATE TABLE $table"); // echo "<pre>"; print_r($tmpres); echo "</pre>"; // exit; if(is_array($tmpres) && isset($tmpres[0])) { $tmpres = $tmpres[0]; $pos = strpos($tmpres["Create Table"], ' ('); $pos2 = strpos($tmpres["Create Table"], '('); if ($pos2 != $pos + 1) { $pos = $pos2; $tmpres["Create Table"] = str_replace(",", ",\n ", $tmpres["Create Table"]); } $tmpres["Create Table"] = substr($tmpres["Create Table"], 0, 13) . (($use_backquotes) ? $tmpres["Table"] : $tmpres["Table"]) . substr($tmpres["Create Table"], $pos); $tmpres["Create Table"] = str_replace("\n", $crlf, $tmpres["Create Table"]); if (preg_match_all('((,\r?\n[\s]*(CONSTRAINT|FOREIGN[\s]*KEY)[^\r\n,]+)+)', $tmpres["Create Table"], $regs)) { if (!isset($sql_constraints)) { if (isset($GLOBALS['no_constraints_comments'])) { $sql_constraints = ''; } else { $sql_constraints = $crlf . '#' . $crlf . '# ' . $GLOBALS['strConstraintsForDumped'] . $crlf . '#' . $crlf; } } if (!isset($GLOBALS['no_constraints_comments'])) { $sql_constraints .= $crlf .'#' . $crlf .'# ' . $GLOBALS['strConstraintsForTable'] . ' ' . $table . $crlf . '#' . $crlf; } $sql_constraints .= 'ALTER TABLE $table $crlf ' . preg_replace('/(,\r?\n|^)([\s]*)(CONSTRAINT|FOREIGN[\s]*KEY)/', '\1\2ADD \3', substr($regs[0][0], 2)) . ";\n"; $tmpres["Create Table"] = preg_replace('((,\r?\n[\s]*(CONSTRAINT|FOREIGN[\s]*KEY)[^\r\n,]+)+)', '', $tmpres["Create Table"]); } $schema_create .= $tmpres["Create Table"]; } if(strlen($schema_create)) { $schema_create = str_replace("DROP TABLE IF EXISTS ".TABLE_PREFIX,"DROP TABLE ",$schema_create); $schema_create = str_replace("CREATE TABLE ".TABLE_PREFIX,"CREATE TABLE ",$schema_create); while(strlen($schema_create && substr($schema_create,-1)!=")")) { $schema_create = substr($schema_create,0,-1); } } $schema_create .= "\n# --------------------------------------------------------\n"; return $schema_create; } /** * Deletes one backup file * * @param kEvent $event */ function OnDeleteBackup(&$event) { @unlink($this->get_backup_file()); } function get_backup_file() { return $this->Application->ConfigValue('Backup_Path').'/dump'.$this->Application->GetVar('backupdate').'.txt'; } /** * Starts restore process * * @param kEvent $event */ function OnRestore(&$event) { $file = $this->get_backup_file(); $restoreProgress = Array ( 'file_pos' => 0, 'file_name' => $file, 'file_size' => filesize($file), ); $this->Application->RemoveVar('adm.restore_success'); $this->Application->StoreVar('adm.restore_status', serialize($restoreProgress)); $event->redirect = 'tools/restore3'; } function OnRestoreProgress(&$event) { $done_percent = $this->performRestore(); if ($done_percent == -3) { $event->redirect = 'tools/restore4'; return ; } if ($done_percent < 0) { $this->Application->StoreVar('adm.restore_error', 'File read error'); $event->redirect = 'tools/restore4'; return ; } if ($done_percent == 100) { $this->replaceRestoredFiles(); $this->Application->StoreVar('adm.restore_success', 1); $event->redirect = 'tools/restore4'; return ; } echo $done_percent; $event->status = kEvent::erSTOP; } function replaceRestoredFiles() { // gather restored table names $tables = $this->Conn->GetCol('SHOW TABLES'); $mask_restore_table = '/^restore'.TABLE_PREFIX.'(.*)$/'; foreach($tables as $table) { if( preg_match($mask_restore_table,$table,$rets) ) { $old_table = substr($table, 7); $this->Conn->Query('DROP TABLE IF EXISTS '.$old_table); $this->Conn->Query('CREATE TABLE '.$old_table.' LIKE '.$table); $this->Conn->Query('INSERT INTO '.$old_table.' SELECT * FROM '.$table); $this->Conn->Query('DROP TABLE '.$table); } } } function performRestore() { $restoreProgress = unserialize($this->Application->RecallVar('adm.restore_status')); $filename = $restoreProgress['file_name']; $FileOffset = $restoreProgress['file_pos']; $MaxLines = 200; $size = filesize($filename); if($FileOffset > $size) { return -2; } $fp = fopen($filename,"r"); if(!$fp) { return -1; } if($FileOffset>0) { fseek($fp,$FileOffset); } else { $EndOfSQL = FALSE; $sql = ""; while(!feof($fp) && !$EndOfSQL) { $l = fgets($fp); if(substr($l,0,11)=="INSERT INTO") { $EndOfSQL = TRUE; } else { $sql .= $l; $FileOffset = ftell($fp) - strlen($l); } } if(strlen($sql)) { $error = $this->runSchemaText($sql); if ($error != '') { $this->Application->StoreVar('adm.restore_error', $error); return -3; } } fseek($fp,$FileOffset); } $LinesRead = 0; $sql = ""; $AllSql = array(); while($LinesRead < $MaxLines && !feof($fp)) { $sql = fgets($fp); if(strlen($sql)) { $AllSql[] = $sql; $LinesRead++; } } if(!feof($fp)) { $FileOffset = ftell($fp); } else { $FileOffset = $size; } fclose($fp); if(count($AllSql)>0) { $error = $this->runSQLText($AllSql); if ($error != '') { $this->Application->StoreVar('adm.restore_error', $error); return -3; } } $restoreProgress['file_pos'] = $FileOffset; $this->Application->StoreVar('adm.restore_status', serialize($restoreProgress)); return round($FileOffset/$size * 100); // $this->Application->StoreVar('adm.restore_error', 'lalalal'); // $event->redirect = 'tools/restore4'; } function runSchemaText($sql) { $table_prefix = 'restore'.TABLE_PREFIX; // $table_prefix = TABLE_PREFIX; if (strlen($table_prefix) > 0) { $replacements = Array ('INSERT INTO ', 'UPDATE ', 'ALTER TABLE ', 'DELETE FROM ', 'REPLACE INTO '); foreach ($replacements as $replacement) { $sql = str_replace($replacement, $replacement . $table_prefix, $sql); } } $sql = str_replace('CREATE TABLE ', 'CREATE TABLE IF NOT EXISTS ' . $table_prefix, $sql); $sql = str_replace('DROP TABLE ', 'DROP TABLE IF EXISTS ' . $table_prefix, $sql); $commands = explode("# --------------------------------------------------------",$sql); if(count($commands)>0) { // $query_func = getConnectionInterface('query',$dbo_type); // $errorno_func = getConnectionInterface('errorno',$dbo_type); // $errormsg_func = getConnectionInterface('errormsg',$dbo_type); for($i = 0; $i < count($commands); $i++) { $cmd = $commands[$i]; $cmd = trim($cmd); if(strlen($cmd)>0) { $this->Conn->Query($cmd); if($this->Conn->errorCode != 0) { return $this->Conn->errorMessage." COMMAND:<PRE>$cmd</PRE>"; } } } } } function runSQLText($allsql) { $line = 0; // $query_func = getConnectionInterface('query',$dbo_type); // $errorno_func = getConnectionInterface('errorno',$dbo_type); // $errormsg_func = getConnectionInterface('errormsg',$dbo_type); while($line<count($allsql)) { $sql = $allsql[$line]; if(strlen(trim($sql))>0 && substr($sql,0,1)!="#") { $table_prefix = 'restore'.TABLE_PREFIX; if (strlen($table_prefix) > 0) { $replacements = Array ('INSERT INTO ', 'UPDATE ', 'ALTER TABLE ', 'DELETE FROM ', 'REPLACE INTO '); foreach ($replacements as $replacement) { $sql = str_replace($replacement, $replacement . $table_prefix, $sql); } } $sql = str_replace('CREATE TABLE ', 'CREATE TABLE IF NOT EXISTS ' . $table_prefix, $sql); $sql = str_replace('DROP TABLE ', 'DROP TABLE IF EXISTS ' . $table_prefix, $sql); $sql = trim($sql); if(strlen($sql)>0) { $this->Conn->Query($sql); if($this->Conn->errorCode != 0) { return $this->Conn->errorMessage." COMMAND:<PRE>$sql</PRE>"; } } } $line++; } } /** * Starts restore process * * @param kEvent $event */ function OnSqlQuery(&$event) { $sql = $this->Application->GetVar('sql'); if ($sql) { $start = $this->getMoment(); $result = $this->Conn->Query($sql); $this->Application->SetVar('sql_time', round($this->getMoment() - $start, 7)); if ($result) { if (is_array($result)) { $this->Application->SetVar('sql_has_rows', 1); $this->Application->SetVar('sql_rows', serialize($result)); } } $check_sql = trim(strtolower($sql)); if ( (substr($check_sql, 0, 6) == 'insert') || (substr($check_sql, 0, 6) == 'update') || (substr($check_sql, 0, 7) == 'replace') || (substr($check_sql, 0, 6) == 'delete') ) { $this->Application->SetVar('sql_has_affected', 1); $this->Application->SetVar('sql_affected', $this->Conn->getAffectedRows()); } } $this->Application->SetVar('query_status', 1); $event->status = kEvent::erFAIL; } function getMoment() { list($usec, $sec) = explode(' ', microtime()); return ((float)$usec + (float)$sec); } /** * Occurs after unit config cache was successfully rebuilt * * @param kEvent $event */ function OnAfterCacheRebuild(&$event) { } /** * Removes "Community -> Groups" section when it is not allowed * * @param kEvent $event */ function OnAfterConfigRead(&$event) { parent::OnAfterConfigRead($event); + $section_ajustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments'); + if (!$this->Application->ConfigValue('AdvancedUserManagement')) { - $section_ajustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments'); if (!$section_ajustments) { $section_ajustments = Array (); } $section_ajustments['in-portal:user_groups'] = 'remove'; - - $this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_ajustments); } + + $section_ajustments['in-portal:root'] = Array ( + 'label' => $this->Application->ConfigValue('Site_Name') + ); + + $this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_ajustments); } /** * Saves menu (tree) frame width * * @param kEvent $event */ function OnSaveMenuFrameWidth(&$event) { $event->status = kEvent::erSTOP; if (!$this->Application->ConfigValue('ResizableFrames')) { return ; } $sql = 'UPDATE ' . $this->Application->getUnitOption('conf', 'TableName') . ' SET VariableValue = ' . (int)$this->Application->GetVar('width') . ' WHERE VariableName = "MenuFrameWidth"'; $this->Conn->Query($sql); if ($this->Conn->getAffectedRows()) { - $this->Application->UnitConfigReader->ResetParsedData(false); + $this->Application->DeleteUnitCache(false); } } /** * Retrieves data from memory cache * * @param kEvent $event */ function OnMemoryCacheGet(&$event) { $event->status = kEvent::erSTOP; $ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error $key = $this->Application->GetVar('key'); if (!$key) { $ret['code'] = 1; $ret['message'] = 'Key name missing'; } else { $value = $this->Application->getCache($key); $ret['value'] =& $value; $ret['size'] = is_string($value) ? kUtil::formatSize( strlen($value) ) : '?'; $ret['type'] = gettype($value); if (kUtil::IsSerialized($value)) { $value = unserialize($value); } if (is_array($value)) { $ret['value'] = print_r($value, true); } if ($ret['value'] === false) { $ret['code'] = 2; $ret['message'] = 'Key "' . $key . '" doesn\'t exist'; } } $json_helper =& $this->Application->recallObject('JSONHelper'); /* @var $json_helper JSONHelper */ echo $json_helper->encode($ret); } /** * Retrieves data from memory cache * * @param kEvent $event */ function OnMemoryCacheSet(&$event) { $event->status = kEvent::erSTOP; $ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error $key = $this->Application->GetVar('key'); if (!$key) { $ret['code'] = 1; $ret['message'] = 'Key name missing'; } else { $value = $this->Application->GetVar('value'); $res = $this->Application->setCache($key, $value); $ret['result'] = $res ? 'OK' : 'FAILED'; } $json_helper =& $this->Application->recallObject('JSONHelper'); /* @var $json_helper JSONHelper */ echo $json_helper->encode($ret); } } class UnitConfigDecorator { var $parentPath = Array (); function decorate($var, $level = 0) { $ret = ''; $deep_level = count($this->parentPath); if ($deep_level && ($this->parentPath[0] == 'Fields')) { $expand = $level < 2; } elseif ($deep_level && ($this->parentPath[0] == 'Grids')) { if ($deep_level == 3 && $this->parentPath[2] == 'Icons') { $expand = false; } else { $expand = $level < 4; } } else { $expand = $level == 0; } if (is_array($var)) { $ret .= 'Array ('; $prepend = $expand ? "\n" . str_repeat("\t", $level + 1) : ''; foreach ($var as $key => $value) { array_push($this->parentPath, $key); $ret .= $prepend . (is_string($key) ? "'" . $key . "'" : $key) . ' => ' . $this->decorate($value, $level + 1) . ', '; array_pop($this->parentPath); } $prepend = $expand ? "\n" . str_repeat("\t", $level) : ''; $ret = rtrim($ret, ', ') . $prepend . ')'; } else { if (is_null($var)) { $ret = 'NULL'; } elseif (is_string($var)) { $ret = "'" . $var . "'"; } else { $ret = $var; } } return $ret; } } \ No newline at end of file Index: branches/5.2.x/core/units/admin/admin_config.php =================================================================== --- branches/5.2.x/core/units/admin/admin_config.php (revision 14183) +++ branches/5.2.x/core/units/admin/admin_config.php (revision 14184) @@ -1,99 +1,99 @@ <?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!'); $config = Array ( 'Prefix' => 'adm', 'ItemClass' => Array ('class' => 'kDBItem','file'=>'','build_event'=>'OnItemBuild'), 'EventHandlerClass' => Array ('class' => 'AdminEventsHandler', 'file' => 'admin_events_handler.php', 'build_event' => 'OnBuild'), 'TagProcessorClass' => Array ('class' => 'AdminTagProcessor', 'file' => 'admin_tag_processor.php', 'build_event' => 'OnBuild'), 'QueryString' => Array ( 1 => 'event', ), 'TitlePresets' => Array ( 'tree_root' => Array ('format' => '!la_section_overview!'), 'tree_reports' => Array ('format' => '!la_section_overview!'), 'tree_system' => Array ('format' => '!la_section_overview!'), 'tree_tools' => Array ('format' => '!la_section_overview!'), 'system_tools' => Array ('format' => '!la_title_SystemTools!'), 'backup' => Array ('format' => '!la_performing_backup! - !la_Step! <span id="step_number"></span>'), 'import' => Array ('format' => '!la_performing_import! - !la_Step! <span id="step_number"></span>'), 'restore' => Array ('format' => '!la_performing_restore! - !la_Step! <span id="step_number"></span>'), 'server_info' => Array ('format' => '!la_tab_ServerInfo!'), 'sql_query' => Array ('format' => '!la_tab_QueryDB!'), 'no_permissions' => Array ('format' => '!la_title_NoPermissions!'), 'column_picker' => Array ('format' => '!la_title_ColumnPicker!'), 'csv_export' => Array ('format' => '!la_title_CSVExport!'), 'csv_import' => Array ('format' => '!la_title_CSVImport!'), ), 'PermSection' => Array ('main' => 'in-portal:service'), 'Sections' => Array ( 'in-portal:root' => Array ( 'parent' => null, 'icon' => 'site', - 'label' => $this->Application->ConfigValue('Site_Name'), + 'label' => 'SITE_NAME', 'url' => Array ('t' => 'index', 'pass' => 'm', 'pass_section' => true, 'no_amp' => 1), 'permissions' => Array (), 'priority' => 0, 'container' => true, 'type' => stTREE, 'icon_module' => 'core', ), 'in-portal:service' => Array ( 'parent' => 'in-portal:tools', 'icon' => 'service', 'label' => 'la_tab_Service', 'url' => Array ('t' => 'tools/system_tools', 'pass' => 'm'), 'permissions' => Array ('view', 'edit'), 'priority' => 6, 'type' => stTREE, ), ), 'ListSQLs' => Array ( '' => '', // to prevent warning ), 'Fields' => Array (), // we need empty array because kernel doesn't use virtual fields else 'VirtualFields' => Array ( 'ImportFile' => Array ( 'type' => 'string', 'formatter' => 'kUploadFormatter', 'max_size' => MAX_UPLOAD_SIZE, // in Bytes ! 'error_msgs' => Array ( 'cant_open_file' => '!la_error_CantOpenFile!', 'no_matching_columns' => '!la_error_NoMatchingColumns!', ), 'file_types' => '*.csv', 'files_description' => '!la_hint_CSVFiles!', 'upload_dir' => '/system/import/', // relative to project's home 'multiple' => false, 'direct_links' => false, 'default' => null, ), 'Content' => Array ('type' => 'string', 'default' => ''), ), ); Index: branches/5.2.x/core/units/admin/admin_tag_processor.php =================================================================== --- branches/5.2.x/core/units/admin/admin_tag_processor.php (revision 14183) +++ branches/5.2.x/core/units/admin/admin_tag_processor.php (revision 14184) @@ -1,1131 +1,1128 @@ <?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 AdminTagProcessor extends kDBTagProcessor { /** * Allows to execute js script after the page is fully loaded * * @param Array $params * @return string */ function AfterScript($params) { $after_script = $this->Application->GetVar('after_script'); if ($after_script) { return '<script type="text/javascript">'.$after_script.'</script>'; } return ''; } /** * Returns section title with #section# keyword replaced with current section * * @param Array $params * @return string */ function GetSectionTitle($params) { if (array_key_exists('default', $params)) { return $params['default']; } return $this->Application->Phrase( kUtil::replaceModuleSection($params['phrase']) ); } /** * Returns section icon with #section# keyword replaced with current section * * @param Array $params * @return string */ function GetSectionIcon($params) { return kUtil::replaceModuleSection($params['icon']); } /** * Returns version of module by name * * @param Array $params * @return string */ function ModuleVersion($params) { return $this->Application->findModule('Name', $params['module'], 'Version'); } /** * Used in table form section drawing * * @param Array $params * @return string */ function DrawTree($params) { static $deep_level = 0; // when processings, then sort children by priority (key of children array) $ret = ''; $section_name = $params['section_name']; $params['name'] = $this->SelectParam($params, 'name,render_as,block'); $sections_helper =& $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ $section_data =& $sections_helper->getSectionData($section_name); $params['children_count'] = isset($section_data['children']) ? count($section_data['children']) : 0; $params['deep_level'] = $deep_level++; $template = $section_data['url']['t']; unset($section_data['url']['t']); $section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']); $ret .= $this->Application->ParseBlock( array_merge($params, $section_data) ); if (!isset($section_data['children'])) { return $ret; } ksort($section_data['children'], SORT_NUMERIC); foreach ($section_data['children'] as $section_name) { if (!$sections_helper->sectionVisible($section_name)) { continue; } $params['section_name'] = $section_name; $ret .= $this->DrawTree($params); $deep_level--; } return $ret; } function SectionInfo($params) { $section = $params['section']; if ($section == '#session#') { $section = $this->Application->RecallVar('section'); } $sections_helper =& $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ $section_data =& $sections_helper->getSectionData($section); if (!$section_data) { throw new Exception('Use of undefined section "<strong>' . $section . '</strong>" in "<strong>' . __METHOD__ . '</strong>"'); return ''; } if (array_key_exists('parent', $params) && $params['parent']) { do { $section = $section_data['parent']; $section_data =& $sections_helper->getSectionData($section); } while (array_key_exists('use_parent_header', $section_data) && $section_data['use_parent_header']); } $info = $params['info']; switch ($info) { case 'module_path': if (isset($params['module']) && $params['module']) { $module = $params['module']; } elseif (isset($section_data['icon_module'])) { $module = $section_data['icon_module']; } else { $module = '#session#'; } $res = $this->ModulePath(array('module' => $module)); break; case 'perm_section': $res = $sections_helper->getPermSection($section); break; case 'label': if ($section && ($section != 'in-portal:root')) { // don't translate label for top section, because it's already translated $no_editing = array_key_exists('no_editing', $params) ? $params['no_editing'] : false; $res = $this->Application->Phrase($section_data['label'], !$no_editing); } else { $res = ''; } break; default: $res = $section_data[$info]; break; } if (array_key_exists('as_label', $params) && $params['as_label']) { $res = $this->Application->Phrase($res); } return $res; } function PrintSection($params) { $section_name = $params['section_name']; if ($section_name == '#session#') { $section_name = $this->Application->RecallVar('section'); } $sections_helper =& $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ if (isset($params['use_first_child']) && $params['use_first_child']) { $section_name = $sections_helper->getFirstChild($section_name, true); } $section_data =& $sections_helper->getSectionData($section_name); $params['name'] = $this->SelectParam($params, 'name,render_as,block'); $params['section_name'] = $section_name; $template = $section_data['url']['t']; unset($section_data['url']['t']); $section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']); $ret = $this->Application->ParseBlock( array_merge($params, $section_data) ); return $ret; } /** * Used in XML drawing for tree * * @param Array $params * @return string */ function PrintSections($params) { // when processings, then sort children by priority (key of children array) $ret = ''; $section_name = $params['section_name']; if ($section_name == '#session#') { $section_name = $this->Application->RecallVar('section'); } $sections_helper =& $this->Application->recallObject('SectionsHelper'); /* @var $sections_helper kSectionsHelper */ $section_data =& $sections_helper->getSectionData($section_name); $params['name'] = $this->SelectParam($params, 'name,render_as,block'); if (!isset($section_data['children'])) { return ''; } ksort($section_data['children'], SORT_NUMERIC); foreach ($section_data['children'] as $section_name) { $params['section_name'] = $section_name; $section_data =& $sections_helper->getSectionData($section_name); if (!$sections_helper->sectionVisible($section_name)) { continue; } else { $show_mode = $section_data['show_mode']; $section_data['debug_only'] = ($show_mode == smDEBUG) || ($show_mode == smSUPER_ADMIN) ? 1 : 0; } if (isset($section_data['tabs_only']) && $section_data['tabs_only']) { $perm_status = false; $folder_label = $section_data['label']; ksort($section_data['children'], SORT_NUMERIC); foreach ($section_data['children'] as $priority => $section_name) { // if only tabs in this section & none of them have permission, then skip section too $section_name = $sections_helper->getPermSection($section_name); $perm_status = $this->Application->CheckPermission($section_name.'.view', 1); if ($perm_status) { break; } } if (!$perm_status) { // no permission for all tabs -> don't display tree node either continue; } $params['section_name'] = $section_name; $section_data =& $sections_helper->getSectionData($section_name); $section_data['label'] = $folder_label; // use folder label in tree $section_data['is_tab'] = 1; } else { $section_name = $sections_helper->getPermSection($section_name); if (!$this->Application->CheckPermission($section_name.'.view', 1)) continue; } $params['children_count'] = isset($section_data['children']) ? count($section_data['children']) : 0; // remove template, so it doesn't appear as additional parameter in url $template = $section_data['url']['t']; unset($section_data['url']['t']); $section_data['section_url'] = $this->Application->HREF($template, '', $section_data['url']); $late_load = getArrayValue($section_data, 'late_load'); if ($late_load) { $t = $late_load['t']; unset($late_load['t']); $section_data['late_load'] = $this->Application->HREF($t, '', $late_load); $params['children_count'] = 99; } else { $section_data['late_load'] = ''; } // restore template $section_data['url']['t'] = $template; $ret .= $this->Application->ParseBlock( array_merge($params, $section_data) ); $params['section_name'] = $section_name; } return preg_replace("/\r\n|\n/", '', $ret); } function ListSectionPermissions($params) { $section_name = isset($params['section_name']) ? $params['section_name'] : $this->Application->GetVar('section_name'); $sections_helper =& $this->Application->recallObject('SectionsHelper'); $section_data =& $sections_helper->getSectionData($section_name); $block_params = array_merge($section_data, Array('name' => $params['render_as'], 'section_name' => $section_name)); $ret = ''; foreach ($section_data['permissions'] as $perm_name) { if (preg_match('/^advanced:(.*)/', $perm_name) != $params['type']) continue; $block_params['perm_name'] = $perm_name; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } function ModuleInclude($params) { foreach ($params as $param_name => $param_value) { $params[$param_name] = kUtil::replaceModuleSection($param_value); } $m =& $this->Application->recallObject('m_TagProcessor'); return $m->ModuleInclude($params); } function TodayDate($params) { return date($params['format']); } function TreeEditWarrning($params) { $ret = $this->Application->Phrase($params['label']); $ret = str_replace(Array('<', '>', 'br/', 'br /', "\n", "\r"), Array('<', '>', 'br', 'br', '', ''), $ret); if (getArrayValue($params, 'escape')) { $ret = addslashes($ret); } $ret = str_replace('<br>', '\n', $ret); return $ret; } /** * Draws section tabs using block name passed * * @param Array $params */ function ListTabs($params) { $sections_helper =& $this->Application->recallObject('SectionsHelper'); $section_data =& $sections_helper->getSectionData($params['section_name']); $ret = ''; $block_params = Array('name' => $params['render_as']); ksort($section_data['children'], SORT_NUMERIC); foreach ($section_data['children'] as $priority => $section_name) { if (!$this->Application->CheckPermission($section_name.'.view', 1)) continue; $tab_data =& $sections_helper->getSectionData($section_name); $block_params['t'] = $tab_data['url']['t']; $block_params['title'] = $tab_data['label']; $block_params['main_prefix'] = $section_data['SectionPrefix']; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Returns list of module item tabs that have view permission in current category * * @param Array $params */ function ListCatalogTabs($params) { $ret = ''; $special = isset($params['special']) ? $params['special'] : ''; $replace_main = isset($params['replace_m']) && $params['replace_m']; $skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array(); $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; foreach ($this->Application->ModuleInfo as $module_name => $module_info) { $prefix = $module_info['Var']; if ($prefix == 'm' && $replace_main) { $prefix = 'c'; } if (in_array($prefix, $skip_prefixes) || !$this->Application->prefixRegistred($prefix) || !$this->Application->getUnitOption($prefix, 'CatalogItem')) { continue; } $icon = $this->Application->getUnitOption($prefix, 'CatalogTabIcon'); if (strpos($icon, ':') !== false) { list ($icon_module, $icon) = explode(':', $icon, 2); } else { $icon_module = 'core'; } $label = $this->Application->getUnitOption($prefix, $params['title_property']); $block_params['title'] = $label; $block_params['prefix'] = $prefix; $block_params['icon_module'] = $icon_module; $block_params['icon'] = $icon; $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Renders inividual catalog tab based on prefix and title_property given * * @param Array $params * @return string */ function CatalogTab($params) { $icon = $this->Application->getUnitOption($params['prefix'], 'CatalogTabIcon'); if (strpos($icon, ':') !== false) { list ($icon_module, $icon) = explode(':', $icon, 2); } else { $icon_module = 'core'; } $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; $block_params['icon_module'] = $icon_module; $block_params['icon'] = $icon; $block_params['title'] = $this->Application->getUnitOption($params['prefix'], $params['title_property']); return $this->Application->ParseBlock($block_params); } /** * Allows to construct link for opening any type of catalog item selector * * @param Array $params * @return string */ function SelectorLink($params) { $mode = 'catalog'; if (isset($params['mode'])) { // {catalog, advanced_view} $mode = $params['mode']; unset($params['mode']); } $params['t'] = 'catalog/item_selector/item_selector_'.$mode; $params['m_cat_id'] = $this->Application->getBaseCategory(); $default_params = Array('no_amp' => 1, 'pass' => 'all,'.$params['prefix']); unset($params['prefix']); $pass_through = Array(); if (isset($params['tabs_dependant'])) { // {yes, no} $pass_through['td'] = $params['tabs_dependant']; unset($params['tabs_dependant']); } if (isset($params['selection_mode'])) { // {single, multi} $pass_through['tm'] = $params['selection_mode']; unset($params['selection_mode']); } if (isset($params['tab_prefixes'])) { // {all, none, <comma separated prefix list>} $pass_through['tp'] = $params['tab_prefixes']; unset($params['tab_prefixes']); } if ($pass_through) { // add pass_through to selector url if any $params['pass_through'] = implode(',', array_keys($pass_through)); $params = array_merge($params, $pass_through); } // user can override default parameters (except pass_through of course) $params = array_merge($default_params, $params); $main_processor =& $this->Application->recallObject('m_TagProcessor'); return $main_processor->T($params); } function TimeFrame($params) { $w = adodb_date('w'); $m = adodb_date('m'); $y = adodb_date('Y'); //FirstDayOfWeek is 0 for Sunday and 1 for Monday $fdow = $this->Application->ConfigValue('FirstDayOfWeek'); if ($fdow && $w == 0) $w = 7; $today_start = adodb_mktime(0,0,0,adodb_date('m'),adodb_date('d'),$y); $first_day_of_this_week = $today_start - ($w - $fdow)*86400; $first_day_of_this_month = adodb_mktime(0,0,0,$m,1,$y); $this_quater = ceil($m/3); $this_quater_start = adodb_mktime(0,0,0,$this_quater*3-2,1,$y); switch ($params['type']) { case 'last_week_start': $timestamp = $first_day_of_this_week - 86400*7; break; case 'last_week_end': $timestamp = $first_day_of_this_week - 1; break; case 'last_month_start': $timestamp = $m == 1 ? adodb_mktime(0,0,0,12,1,$y-1) : adodb_mktime(0,0,0,$m-1,1,$y); break; case 'last_month_end': $timestamp = $first_day_of_this_month = adodb_mktime(0,0,0,$m,1,$y) - 1; break; case 'last_quater_start': $timestamp = $this_quater == 1 ? adodb_mktime(0,0,0,10,1,$y-1) : adodb_mktime(0,0,0,($this_quater-1)*3-2,1,$y); break; case 'last_quater_end': $timestamp = $this_quater_start - 1; break; case 'last_6_months_start': $timestamp = $m <= 6 ? adodb_mktime(0,0,0,$m+6,1,$y-1) : adodb_mktime(0,0,0,$m-6,1,$y); break; case 'last_year_start': $timestamp = adodb_mktime(0,0,0,1,1,$y-1); break; case 'last_year_end': $timestamp = adodb_mktime(23,59,59,12,31,$y-1); break; } if (isset($params['format'])) { $format = $params['format']; if(preg_match("/_regional_(.*)/", $format, $regs)) { $lang =& $this->Application->recallObject('lang.current'); $format = $lang->GetDBField($regs[1]); } return adodb_date($format, $timestamp); } return $timestamp; } /** * Redirect to cache rebuild template, when required by installator * * @param Array $params */ function CheckPermCache($params) { // we have separate session between install wizard and admin console, so store in cache $global_mark = $this->Application->getDBCache('ForcePermCacheUpdate'); $local_mark = $this->Application->RecallVar('PermCache_UpdateRequired'); if ($global_mark || $local_mark) { $this->Application->RemoveVar('PermCache_UpdateRequired'); if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild')) { $updater =& $this->Application->makeClass('kPermCacheUpdater'); /* @var $updater kPermCacheUpdater */ $updater->OneStepRun(); } else { // update with progress bar return true; } } return false; } /** * Checks if current protocol is SSL * * @param Array $params * @return int */ function IsSSL($params) { return (PROTOCOL == 'https://')? 1 : 0; } function PrintColumns($params) { $picker_helper =& $this->Application->RecallObject('ColumnPickerHelper'); $picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name')); /* @var $picker_helper kColumnPickerHelper */ $main_prefix = $this->Application->RecallVar('main_prefix'); $cols = $picker_helper->LoadColumns($main_prefix); $this->Application->Phrases->AddCachedPhrase('__FREEZER__', '-------------'); $o = ''; if (isset($params['hidden']) && $params['hidden']) { foreach ($cols['hidden_fields'] as $col) { $title = $this->Application->Phrase($cols['titles'][$col]); $o .= "<option value='$col'>".$title; } } else { foreach ($cols['order'] as $col) { if (in_array($col, $cols['hidden_fields'])) continue; $title = $this->Application->Phrase($cols['titles'][$col]); $o .= "<option value='$col'>".$title; } } return $o; } /** * Allows to set popup size (key - current template name) * * @param Array $params */ function SetPopupSize($params) { $width = $params['width']; $height = $params['height']; if ($this->Application->GetVar('ajax') == 'yes') { // during AJAX request just output size die($width.'x'.$height); } if (!$this->UsePopups($params)) { return ; } $t = $this->Application->GetVar('t'); $sql = 'SELECT * FROM '.TABLE_PREFIX.'PopupSizes WHERE TemplateName = '.$this->Conn->qstr($t); $popup_info = $this->Conn->GetRow($sql); if (!$popup_info) { // create new popup size record $fields_hash = Array ( 'TemplateName' => $t, 'PopupWidth' => $width, 'PopupHeight' => $height, ); $this->Conn->doInsert($fields_hash, TABLE_PREFIX.'PopupSizes'); } elseif ($popup_info['PopupWidth'] != $width || $popup_info['PopupHeight'] != $height) { // popup found and size in tag differs from one in db -> update in db $fields_hash = Array ( 'PopupWidth' => $width, 'PopupHeight' => $height, ); $this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'PopupSizes', 'PopupId = '.$popup_info['PopupId']); } } /** * Returns popup size (by template), if not cached, then parse template to get value * * @param Array $params * @return string */ function GetPopupSize($params) { $t = $this->Application->GetVar('template_name'); $sql = 'SELECT * FROM '.TABLE_PREFIX.'PopupSizes WHERE TemplateName = '.$this->Conn->qstr($t); $popup_info = $this->Conn->GetRow($sql); if (!$popup_info) { $this->Application->InitParser(); $this->Application->ParseBlock(array('name' => $t)); // dies when SetPopupSize tag found & in ajax requrest return '750x400'; // tag SetPopupSize not found in template -> use default size } return $popup_info['PopupWidth'].'x'.$popup_info['PopupHeight']; } /** * Allows to check if popups are generally enabled OR to check for "popup" or "modal" mode is enabled * * @param Array $params * @return bool */ function UsePopups($params) { if ($this->Application->GetVar('_force_popup')) { return true; } $use_popups = (int)$this->Application->ConfigValue('UsePopups'); if (array_key_exists('mode', $params)) { $mode_mapping = Array ('popup' => 1, 'modal' => 2); return $use_popups == $mode_mapping[ $params['mode'] ]; } return $use_popups; } function UseToolbarLabels($params) { return (int)$this->Application->ConfigValue('UseToolbarLabels'); } /** * Checks if debug mode enabled (optionally) and specified constant is on * * @param Array $params * @return bool * @todo Could be a duplicate of kMainTagProcessor::ConstOn */ function ConstOn($params) { $constant_name = $this->SelectParam($params, 'name,const'); $debug_mode = isset($params['debug_mode']) && $params['debug_mode'] ? $this->Application->isDebugMode() : true; return $debug_mode && kUtil::constOn($constant_name); } /** * Builds link to last template in main frame of admin * * @param Array $params * @return string */ function MainFrameLink($params) { $persistent = isset($params['persistent']) && $params['persistent']; if ($persistent && $this->Application->ConfigValue('RememberLastAdminTemplate')) { // check last_template in persistent session $last_template = $this->Application->RecallPersistentVar('last_template_popup'); } else { // check last_template in session $last_template = $this->Application->RecallVar('last_template_popup'); // because of m_opener=s there } if (!$last_template) { $params['persistent'] = 1; return $persistent ? false : $this->MainFrameLink($params); } list($index_file, $env) = explode('|', $last_template); $vars = $this->Application->HttpQuery->processQueryString($env, 'pass'); $recursion_templates = Array ('login', 'index', 'no_permission'); if (isset($vars['admin']) && $vars['admin'] == 1) { // index template doesn't begin recursion on front-end (in admin frame) $vars['m_theme'] = ''; if (isset($params['m_opener']) && $params['m_opener'] == 'r') { // front-end link for highlighting purposes $vars['t'] = 'index'; $vars['m_cat_id'] = $this->Application->getBaseCategory(); } unset($recursion_templates[ array_search('index', $recursion_templates)]); } if (in_array($vars['t'], $recursion_templates)) { // prevents redirect recursion OR old in-portal pages $params['persistent'] = 1; return $persistent ? false : $this->MainFrameLink($params); } $vars = array_merge($vars, $params); $t = $vars['t']; unset($vars['t'], $vars['persistent']); // substitute language in link to current (link will work, even when language will be changed) $vars['m_lang'] = $this->Application->GetVar('m_lang'); return $this->Application->HREF($t, '', $vars, $index_file); } /** * Returns menu frame width or 200 in case, when invalid width specified in config * * @param Array $params * @return string */ function MenuFrameWidth($params) { $width = (int)$this->Application->ConfigValue('MenuFrameWidth'); return $width > 0 ? $width : 200; } function AdminSkin($params) { $skin_helper =& $this->Application->recallObject('SkinHelper'); /* @var $skin_helper SkinHelper */ return $skin_helper->AdminSkinTag($params); } function PrintCompileErrors($params) { $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; $errors = $this->Application->RecallVar('compile_errors'); if (!$errors) { return ; } $ret = ''; $errors = unserialize($errors); foreach ($errors as $an_error) { $block_params['file'] = str_replace(FULL_PATH, '', $an_error['file']); $block_params['line'] = $an_error['line']; $block_params['message'] = $an_error['msg']; $ret .= $this->Application->ParseBlock($block_params); } $this->Application->RemoveVar('compile_errors'); return $ret; } function CompileErrorCount($params) { $errors = $this->Application->RecallVar('compile_errors'); if (!$errors) { return 0; } return count( unserialize($errors) ); } function ExportData($params) { $export_helper =& $this->Application->recallObject('CSVHelper'); /* @var $export_helper kCSVHelper */ $result = $export_helper->ExportData( $this->SelectParam($params, 'var,name,field') ); return ($result === false) ? '' : $result; } function ImportData($params) { $import_helper =& $this->Application->recallObject('CSVHelper'); /* @var $import_helper kCSVHelper */ $result = $import_helper->ImportData( $this->SelectParam($params, 'var,name,field') ); return ($result === false) ? '' : $result; } function PrintCSVNotImportedLines($params) { $import_helper =& $this->Application->recallObject('CSVHelper'); /* @var $import_helper kCSVHelper */ return $import_helper->GetNotImportedLines(); } /** * Returns input field name to * be placed on form (for correct * event processing) * * @param Array $params * @return string * @access public */ function InputName($params) { list($id, $field) = $this->prepareInputName($params); $ret = $this->getPrefixSpecial().'[0]['.$field.']'; // 0 always, as has no idfield if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/'); return $ret; } /** * Returns list of all backup file dates formatted * in passed block * * @param Array $params * @return string * @access public */ function PrintBackupDates($params) { $datearray = $this->getDirList($this->Application->ConfigValue('Backup_Path')); $ret = ''; foreach($datearray as $key => $value) { $params['backuptimestamp'] = $value['filedate']; $params['backuptime'] = date('F j, Y, g:i a', $value['filedate']); $params['backupsize'] = round($value['filesize']/1024/1024, 2); // MBytes $ret .= $this->Application->ParseBlock($params); } return $ret; } function getDirList ($dirName) { $file_helper =& $this->Application->recallObject('FileHelper'); /* @var $file_helper FileHelper */ $file_helper->CheckFolder($dirName); $fileinfo = array(); $d = dir($dirName); while($entry = $d->read()) { if ($entry != "." && $entry != "..") { if (!is_dir($dirName."/".$entry) && strpos($entry, 'dump') !== false) { $fileinfo[]= Array('filedate' => $this->chopchop($entry), 'filesize' => filesize($dirName. '/'. $entry) ); } } } $d->close(); rsort($fileinfo); return $fileinfo; } function chopchop ($filename) { $p = pathinfo($filename); $ext = '.'.$p['extension']; $filename; $filename = str_replace('dump', '',$filename); $filename = str_replace($ext, '', $filename); return $filename; } /** * Returns phpinfo() output * * @param Array $params * @return string */ function PrintPHPinfo($params) { ob_start(); phpinfo(); return ob_get_clean(); } function PrintSqlCols($params) { $a_data = unserialize($this->Application->GetVar('sql_rows')); $ret = ''; $block = $params['render_as']; foreach ($a_data AS $a_row) { foreach ($a_row AS $col => $value) { $ret .= $this->Application->ParseBlock(Array('name'=>$block, 'value'=>$col)); } break; } return $ret; } function PrintSqlRows($params) { $a_data = unserialize($this->Application->GetVar('sql_rows')); $ret = ''; $block = $params['render_as']; foreach ($a_data AS $a_row) { $cells = ''; foreach ($a_row AS $col => $value) { $cells .= '<td>'.$value.'</td>'; } $ret .= $this->Application->ParseBlock(Array('name'=>$block, 'cells'=>$cells)); } return $ret; } /** * Prints available and enabled import sources using given block * * @param Array $params * @return string */ function PrintImportSources($params) { $sql = 'SELECT * FROM ' . TABLE_PREFIX . 'ImportScripts WHERE (Status = ' . STATUS_ACTIVE . ') AND (Type = "CSV")'; $import_sources = $this->Conn->Query($sql); $block_params = $this->prepareTagParams($params); $block_params['name'] = $params['render_as']; $ret = ''; foreach ($import_sources as $import_source) { $block_params['script_id'] = $import_source['ImportId']; $block_params['script_module'] = mb_strtolower($import_source['Module']); $block_params['script_name'] = $import_source['Name']; $block_params['script_prefix'] = $import_source['Prefix']; $block_params['module_path'] = $this->Application->findModule('Name', $import_source['Module'], 'Path'); $ret .= $this->Application->ParseBlock($block_params); } return $ret; } /** * Checks, that new window should be opened in "incs/close_popup" template instead of refreshing parent window * * @param Array $params * @return bool */ function OpenNewWindow($params) { if (!$this->UsePopups($params)) { return false; } $diff = array_key_exists('diff', $params) ? $params['diff'] : 0; $wid = $this->Application->GetVar('m_wid'); $stack_name = rtrim('opener_stack_' . $wid, '_'); $opener_stack = $this->Application->RecallVar($stack_name); $opener_stack = $opener_stack ? unserialize($opener_stack) : Array (); return count($opener_stack) >= 2 - $diff; } /** * Allows to dynamically change current language in template * * @param Array $params */ function SetLanguage($params) { $this->Application->SetVar('m_lang', $params['language_id']); - $this->Application->Phrases->Init(''); - - $this->Application->Phrases->LanguageId = $params['language_id']; - $this->Application->Phrases->LoadPhrases( $this->Application->Caches['PhraseList'] ); + $this->Application->Phrases->Init('phrases', '', $params['language_id']); } /** * Performs HTTP Authentification for administrative console * * @param Array $params */ function HTTPAuth($params) { if (!$this->Application->ConfigValue('UseHTTPAuth')) { // http authentification not required return true; } $super_admin_ips = defined('SA_IP') ? SA_IP : false; $auth_bypass_ips = $this->Application->ConfigValue('HTTPAuthBypassIPs'); if (($auth_bypass_ips && kUtil::ipMatch($auth_bypass_ips)) || ($super_admin_ips && kUtil::ipMatch($super_admin_ips))) { // user ip is in ip bypass list return true; } if (!array_key_exists('PHP_AUTH_USER', $_SERVER)) { // ask user to authentificate, when not authentificated before return $this->_httpAuthentificate(); } else { // validate user credentials (browsers remembers user/password // and sends them each time page is visited, so no need to save // authentification result in session) if ($this->Application->ConfigValue('HTTPAuthUsername') != $_SERVER['PHP_AUTH_USER']) { // incorrect username return $this->_httpAuthentificate(); } $password_formatter =& $this->Application->recallObject('kPasswordFormatter'); /* @var $password_formatter kPasswordFormatter */ $password = $password_formatter->EncryptPassword($_SERVER['PHP_AUTH_PW'], 'b38'); if ($this->Application->ConfigValue('HTTPAuthPassword') != $password) { // incorrect password return $this->_httpAuthentificate(); } } return true; } /** * Ask user to authentificate * * @return false */ function _httpAuthentificate() { $realm = strip_tags( $this->Application->ConfigValue('Site_Name') ); header('WWW-Authenticate: Basic realm="' . $realm . '"'); header('HTTP/1.0 401 Unauthorized'); return false; } /** * Checks, that we are using memory cache * * @param Array $params * @return bool */ function MemoryCacheEnabled($params) { return $this->Application->isCachingType(CACHING_TYPE_MEMORY); } } \ No newline at end of file