Index: branches/5.2.x/admin/system_presets/simple/users_u.php =================================================================== --- branches/5.2.x/admin/system_presets/simple/users_u.php (revision 14598) +++ branches/5.2.x/admin/system_presets/simple/users_u.php (revision 14599) @@ -1,119 +1,119 @@ <?php defined('FULL_PATH') or die('restricted access!'); // section removal $remove_sections = Array ( // 'in-portal:user_list', // 'in-portal:admins', // 'in-portal:user_setting_folder', // 'in-portal:configure_users', 'in-portal:user_email', 'in-portal:user_custom' ); // sections shown with debug on $debug_only_sections = Array ( // 'in-portal:user_list', // 'in-portal:admins', 'in-portal:user_setting_folder', 'in-portal:configure_users', // 'in-portal:user_email', // 'in-portal:user_custom' ); // toolbar buttons $remove_buttons = Array ( // list of users; section: Users Management -> Users 'users_list' => Array (/*'new_item', 'edit', 'delete', 'approve', 'decline', 'e-mail',*/ 'export', /*'view', 'dbl-click'*/), // "General" tab during user adding/editing // 'users_edit' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'), // "Images" tab during user adding/editing // 'user_edit_images' => Array ('select', 'cancel', 'prev', 'next', 'new_item', 'edit', 'delete', 'move_up', 'move_down', 'setprimary', 'view', 'dbl-click'), // "Groups" tab during user/admin adding/editing // 'user_edit_groups' => Array ('select', 'cancel', 'prev', 'next', 'selec_user', 'edit', 'delete', 'primary_group', 'view', 'dbl-click'), // "Items" tab during user/admin adding/editing // 'user_edit_items' => Array ('select', 'cancel', 'prev', 'next', 'edit', 'delete', 'view', 'dbl-click'), // "Custom" tab during user/admin adding/editing // 'user_edit_custom' => Array ('select', 'cancel', 'prev', 'next'), // list of administrators; section: Users Managements -> Administrators 'admin_list' => Array (/*'new_item', 'edit', 'delete', */'clone', 'refresh',/* 'view', 'dbl-click'*/), // "General" tab during admin adding/editing AND separate password change form for non-"root" users (in top frame) 'admins_edit' => Array (/*'select', 'cancel', */'reset_edit', /*'prev', 'next'*/), // 'regular_users_list' => Array (), // not used // separate password change form for "root" user (in top frame) // 'root_edit' => Array ('select', 'cancel'), // user/admin group membership editing (used on "Groups" tab during user/admin adding/editing) // 'user_edit_group' => Array ('select', 'cancel'), // user image adding/editing (used on "Images" tab during user adding/editing) // 'user_image_edit' => Array ('select', 'cancel', 'prev', 'next'), // user selector // 'user_select' => Array ('select', 'cancel', 'view', 'dbl-click'), // user selector when adding/editing user group // 'group_user_select' => Array ('select', 'cancel', 'view', 'dbl-click'), ); // fields to hide $hidden_fields = Array ( /* 'PortalUserId', 'Login', 'Password', 'FirstName','LastName', 'Company', 'Email', 'CreatedOn', 'Phone', 'Fax', 'Street', 'Street2', 'City', 'State' , 'Zip', 'Country', 'ResourceId', 'Status', 'Modified', 'dob', 'tz', 'ip', 'IsBanned', 'PwResetConfirm', 'PwRequestTime',*/ ); // virtual fields to hide $virtual_hidden_fields = Array ( - /*'ValidateLogin', 'SubscribeEmail', 'PrimaryGroup', 'RootPassword', 'FullName', 'UserGroup'*/ + /*'SubscribeEmail', 'PrimaryGroup', 'RootPassword', 'FullName', 'UserGroup'*/ ); // fields to make required $required_fields = Array ( /*'PortalUserId',*/ 'Login', /*'Password', 'FirstName', 'LastName', 'Company', */'Email', /*'CreatedOn', 'Phone', 'Fax', 'Street', 'Street2', 'City', 'State' , 'Zip', 'Country', 'ResourceId', 'Status', 'Modified', 'dob', 'tz', 'ip', 'IsBanned', 'PwResetConfirm', 'PwRequestTime',*/ ); // virtual fields to make required $virtual_required_fields = Array ( - /*'ValidateLogin', 'SubscribeEmail', 'PrimaryGroup', 'RootPassword', 'FullName', 'UserGroup'*/ + /*'SubscribeEmail', 'PrimaryGroup', 'RootPassword', 'FullName', 'UserGroup'*/ ); // tabs during editing $hide_edit_tabs = Array ( // tabs during user editing, when In-Portal module is enabled 'Default' => Array ('general', 'groups', 'images', 'items', 'custom'), // tabs during user editing, when In-Portal module isn't enabled 'RegularUsers' => Array ('general', 'groups'), // tabs during admin editing 'Admins' => Array ('general', 'groups'), ); // hide columns in grids $hide_columns = Array ( // currently not in user // 'Default' => Array ('Login', 'LastName', 'FirstName', 'Email', 'PrimaryGroup', 'CreatedOn', 'Modified'), // user selector // 'UserSelector' => Array ('Login', 'LastName', 'FirstName', 'Email', 'PrimaryGroup', 'CreatedOn', 'Modified'), // admins list; section: Users Management -> Administrators // 'Admins' => Array ('PortalUserId', 'Login', 'FirstName', 'LastName', 'Email'), // users list; section: Users Management -> Users 'RegularUsers' => Array (/*'PortalUserId', 'Login', 'FirstName', 'LastName', 'Email',*/ 'PrimaryGroup', 'CreatedOn', 'Modified', /* 'Status'*/), ); Index: branches/5.2.x/core/kernel/application.php =================================================================== --- branches/5.2.x/core/kernel/application.php (revision 14598) +++ branches/5.2.x/core/kernel/application.php (revision 14599) @@ -1,2714 +1,2714 @@ <?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 guaranteed by NOT calling the class constructor directly, but rather calling kApplication::Instance() method, * which returns an instance of the application. The method guarantees 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; /** * 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; /** * Holds a ref to kUrlManager * * @var kUrlManager * @access protected */ protected $UrlManager = null; /** * Ref for TemplatesChache * * @var TemplatesCache */ 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 unit caching class * * @var kCacheManager */ var $cacheManager = null; /** * Tells, that administrator has authenticated in administrative console * Should be used to manipulate data change OR data restrictions! * * @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 guaranteed 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 descendant 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. * * Pattern: Singleton * * @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->Factory = new kFactory(); $this->registerDefaultClasses(); $this->Conn =& $this->Factory->makeClass('kDBConnection', Array (SQL_TYPE, Array (&$this, 'handleSQLError'))); $this->Conn->debugMode = $this->isDebugMode(); $this->Conn->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB); $this->cacheManager =& $this->makeClass('kCacheManager'); $this->cacheManager->InitCache(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Before UnitConfigReader'); } $this->UnitConfigReader =& $this->makeClass('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->UrlManager->LoadStructureTemplateMapping(); $this->HttpQuery->AfterInit(); $this->Session->ValidateExpired(); if ( defined('DEBUG_MODE') && $this->isDebugMode() ) { $this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit'); } $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)); /* @var $language LanguagesItem */ 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; } function InitManagers() { if ($this->InitDone) { throw new Exception('Duplicate call of ' . __METHOD__, E_USER_ERROR); return ; } $this->UrlManager =& $this->makeClass('kUrlManager'); $this->EventManager =& $this->makeClass('EventManager'); $this->Phrases =& $this->makeClass('kPhraseCache'); $this->RegisterDefaultBuildEvents(); } /** * 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; } /** * Refreshes information about loaded modules * * @return void * @access public */ public function refreshModuleInfo() { if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules')) { $this->registerModuleConstants(); return ; } $modules_helper =& $this->makeClass('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); } 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'); /* @var $theme ThemeItem */ if ( !$theme->isLoaded() || !$theme->GetDBField('Enabled') ) { return false; } // assign & then return, since it's static variable $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('kHelper', KERNEL_PATH . '/kbase.php'); $this->registerClass('kMultipleFilter', KERNEL_PATH . '/utility/filters.php'); $this->registerClass('kiCacheable', KERNEL_PATH . '/interfaces/cacheable.php', 'kiCacheable'); $this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager', 'kiCacheable'); $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('PhrasesCache', KERNEL_PATH . '/languages/phrases_cache.php', 'kPhraseCache'); $this->registerClass('kTempTablesHandler', KERNEL_PATH . '/utility/temp_handler.php'); $this->registerClass('kValidator', KERNEL_PATH . '/utility/validator.php'); $this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php'); // Params class descendants $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', 'kCache', 'Params'); $this->registerClass('kHTTPQuery', KERNEL_PATH . '/utility/http_query.php', 'HTTPQuery', 'Params'); // session $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'); // template parser $this->registerClass('kTagProcessor', KERNEL_PATH . '/processors/tag_processor.php'); $this->registerClass('kMainTagProcessor', KERNEL_PATH . '/processors/main_processor.php', 'm_TagProcessor', 'kTagProcessor'); $this->registerClass('kDBTagProcessor', KERNEL_PATH . '/db/db_tag_processor.php', null, 'kTagProcessor'); $this->registerClass('kCatDBTagProcessor', KERNEL_PATH . '/db/cat_tag_processor.php', null, 'kDBTagProcessor'); $this->registerClass('NParser', KERNEL_PATH . '/nparser/nparser.php'); $this->registerClass('TemplatesCache', KERNEL_PATH . '/nparser/template_cache.php', null, Array ('kHelper', 'kDBTagProcessor')); // database $this->registerClass('kDBConnection', KERNEL_PATH . '/db/db_connection.php'); $this->registerClass('kDBItem', KERNEL_PATH . '/db/dbitem.php'); $this->registerClass('kCatDBItem', KERNEL_PATH . '/db/cat_dbitem.php', null, 'kDBItem'); $this->registerClass('kDBList', KERNEL_PATH . '/db/dblist.php'); $this->registerClass('kCatDBList', KERNEL_PATH . '/db/cat_dblist.php', null, 'kDBList'); $this->registerClass('kDBEventHandler', KERNEL_PATH . '/db/db_event_handler.php'); $this->registerClass('kCatDBEventHandler', KERNEL_PATH . '/db/cat_event_handler.php', null, 'kDBEventHandler'); // email sending $this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender', 'kHelper'); $this->registerClass('kSocket', KERNEL_PATH . '/utility/socket.php', 'Socket'); // 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 */ public function getCategoryCache($category_id, $name) { return $this->cacheManager->getCategoryCache($category_id, $name); } /** * Returns caching type (none, memory, temporary) * * @return int * @access public */ public function isCachingType($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 */ public function incrementCacheSerial($prefix, $id = null, $increment = true) { return $this->cacheManager->incrementCacheSerial($prefix, $id, $increment); } /** * 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 * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getCache($key, $store_locally = true, $max_rebuild_seconds = 0) { return $this->cacheManager->getCache($key, $store_locally, $max_rebuild_seconds); } /** * 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->cacheManager->setCache($key, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time */ public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0) { $this->cacheManager->rebuildCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from cache * * @param string $key * @access public */ public function deleteCache($key) { $this->cacheManager->deleteCache($key); } /** * Reset's all memory cache at once * * @access public */ public function resetCache() { $this->cacheManager->resetCache(); } /** * Returns value from database cache * * @param string $name key name * @param int $max_rebuild_seconds * @return mixed * @access public */ public function getDBCache($name, $max_rebuild_seconds = 0) { return $this->cacheManager->getDBCache($name, $max_rebuild_seconds); } /** * Sets value to database cache * * @param string $name * @param mixed $value * @param int|bool $expiration * @access public */ public function setDBCache($name, $value, $expiration = false) { $this->cacheManager->setDBCache($name, $value, $expiration); } /** * Sets rebuilding mode for given cache * * @param string $name * @param int $mode * @param int $max_rebuilding_time */ public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0) { $this->cacheManager->rebuildDBCache($name, $mode, $max_rebuilding_time); } /** * Deletes key from database cache * * @param string $name * @access public */ public function deleteDBCache($name) { $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 kUtil::safeDefine('DBG_SKIP_REPORTING', 1); // safeDefine, because debugger also defines it } } elseif ($this->GetVar('admin')) { // viewing front-end through admin's frame $admin_session =& $this->recallObject('Session.admin'); /* @var $admin_session Session */ $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->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 || $compression_level < 0 || $compression_level > 9) { $compression_level = 7; } header('Content-Encoding: gzip'); echo gzencode($this->HTML, $compression_level); } else { echo $this->HTML; } $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 int */ function GetSID() { $session =& $this->recallObject('Session'); /* @var $session Session */ return $session->GetID(); } function DestroySession() { $session =& $this->recallObject('Session'); /* @var $session Session */ $session->Destroy(); } /** * Returns variable passed to the script as GET/POST/COOKIE * * @param string $name Name of variable to retrieve * @param mixed $default default value returned in case if variable not present * * @return mixed * @access public */ public 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 */ public function SetVar($var,$val) { $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 ProcessParsedTag($prefix, $tag, $params) { $processor = $this->Parser->GetProcessor($prefix); /* @var $processor kDBTagProcessor */ 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'], 5); } 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); } /** * 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) { return $this->UrlManager->HREF($t, $prefix, $params, $index_file); } 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) { return $this->UrlManager->getPassThroughVariables($params); } function BuildEnv($t, $params, $pass = 'all', $pass_events = false, $env_var = true) { 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 kUtil::safeDefine('DBG_SKIP_REPORTING', 1); 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); } } } // 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(); ob_end_flush(); 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'); /* @var $session 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 =& $this->recallObject('u.login-admin', null, Array ('form_name' => 'login')); /* @var $user UsersItem */ - $user->SetError('ValidateLogin', 'session_expired', 'la_text_sess_expired'); + $user->SetError('UserLogin', 'session_expired', 'la_text_sess_expired'); } if ( ($user_id != USER_GUEST) && defined('DBG_REQUREST_LOG') && DBG_REQUREST_LOG ) { $this->HttpQuery->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(); } /** * Returns configuration option value by name * * @param string $name * @return string */ function ConfigValue($name) { return $this->cacheManager->ConfigValue($name); } function SetConfigValue($name, $value) { return $this->cacheManager->SetConfigValue($name, $value); } /** * 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); } $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); } /** * Add new agent * * @param string $short_name name to be used to store last maintenace run info * @param string $event_name * @param int $run_interval run interval in seconds * @param int $type before or after agent * @param int $status * @access public */ public function registerAgent($short_name, $event_name, $run_interval, $type = reBEFORE, $status = STATUS_ACTIVE) { $this->EventManager->registerAgent($short_name, $event_name, $run_interval, $type, $status); } /** * Registers Hook from subprefix event to master prefix event * * Pattern: Observer * * @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); } /** * Registers build event for given pseudo class * * @param string $pseudo_class * @param string $event_name * @access public */ public function registerBuildEvent($pseudo_class, $event_name) { $this->EventManager->registerBuildEvent($pseudo_class, $event_name); } /** * Allows one TagProcessor tag act as other TagProcessor tag * * @param Array $tag_info * @author Kostja */ function registerAggregateTag($tag_info) { $aggregator =& $this->recallObject('TagsAggregator', 'kArray'); /* @var $aggregator kArray */ $tag_data = Array( $tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial') ); $aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], $tag_data); } /** * 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 */ 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 */ public function removeObject($name) { $this->Factory->DestroyObject($name); } /** * Get's real class name for pseudo class, includes class file and creates class instance * * Pattern: Factory Method * * @param string $pseudo_class * @param Array $arguments * @return kBase * @access public */ 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 */ 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 */ public function getUnitOption($prefix, $option, $default = false) { return $this->UnitConfigReader->getUnitOption($prefix, $option, $default); } /** * Set's new unit option value * * @param string $prefix * @param string $name * @param string $value * @access public */ public function setUnitOption($prefix, $option, $value) { return $this->UnitConfigReader->setUnitOption($prefix,$option,$value); } /** * Read all unit with $prefix options * * @param string $prefix * @return Array * @access public */ public function getUnitOptions($prefix) { return $this->UnitConfigReader->getUnitOptions($prefix); } /** * Returns true if config exists and is allowed for reading * * @param string $prefix * @return bool */ public function prefixRegistred($prefix) { return $this->UnitConfigReader->prefixRegistred($prefix); } /** * Splits any mixing of prefix and * special into correct ones * * @param string $prefix_special * @return Array * @access public */ 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 * @return bool * @access public */ public function handleError($errno, $errstr, $errfile = null, $errline = null, $errcontext = Array ()) { $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 * @return bool * @access public */ public 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; } /** * Silently saves each given error message to "silent_log.txt" file, when silent log mode is enabled * @param int $errno * @param string $errstr * @param string $errfile * @param int $errline * @return void * @access protected */ protected function errorLogSilent($errno, $errstr = '', $errfile = '', $errline = null) { 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((defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/silent_log.txt', 'a'); fwrite($fp, '[' . $time . '] #' . $errno . ': ' . strip_tags($errstr) . ' in [' . $errfile . '] on line ' . $errline . "\n"); fclose($fp); } } /** * Displays div with given error message * * @param string $msg * @return void * @access protected */ 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; } /** * Prints trace, when debug mode is not available * * @param bool $return_result * @param int $skip_levels * @return string * @access public */ public function printTrace($return_result = false, $skip_levels = 1) { $ret = Array (); $trace = debug_backtrace(false); for ($i = 0; $i < $skip_levels; $i++) { array_shift($trace); } foreach ($trace as $level => $trace_info) { if ( isset($trace_info['class']) ) { $object = $trace_info['class']; } elseif ( isset($trace_info['object']) ) { $object = get_class($trace_info['object']); } else { $object = ''; } $args = ''; $type = isset($trace_info['type']) ? $trace_info['type'] : ''; if ( isset($trace_info['args']) ) { foreach ($trace_info['args'] as $argument) { if ( is_object($argument) ) { $args .= get_class($argument) . ' instance, '; } else { $args .= is_array($argument) ? 'Array' : substr($argument, 0, 10) . ' ..., '; } } $args = substr($args, 0, -2); } $ret[] = '#' . $level . ' ' . $object . $type . $trace_info['function'] . '(' . $args . ') called at [' . $trace_info['file'] . ':' . $trace_info['line'] . ']'; } if ( $return_result ) { return implode("\n", $ret); } echo implode("\n", $ret); return ''; } /** * 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, which are affected by one of specified tables * * @param string $tables comma separated tables list used in counting sqls * @return void * @access public */ public function resetCounters($tables) { if ( kUtil::constOn('IS_INSTALL') ) { return; } $count_helper =& $this->recallObject('CountHelper'); /* @var $count_helper kCountHelper */ $count_helper->resetCounters($tables); } /** * Sends XML header + optionally displays xml heading * * @param string|bool $xml_version * @return string * @access public * @author Alex */ public function XMLHeader($xml_version = false) { $lang =& $this->recallObject('lang.current'); /* @var $lang LanguagesItem */ 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->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.ReplacementTemplates' => $this->ReplacementTemplates, 'Application.RewriteListeners' => $this->RewriteListeners, 'Application.ModuleInfo' => $this->ModuleInfo, ); } public function delayUnitProcessing($method, $params) { $this->cacheManager->delayUnitProcessing($method, $params); } } \ No newline at end of file Index: branches/5.2.x/core/kernel/kbase.php =================================================================== --- branches/5.2.x/core/kernel/kbase.php (revision 14598) +++ branches/5.2.x/core/kernel/kbase.php (revision 14599) @@ -1,1031 +1,1034 @@ <?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!'); /** * Base * */ class kBase { /** * Reference to global kApplication instance * * @var kApplication * @access protected */ protected $Application = null; /** * Connection to database * * @var kDBConnection * @access protected */ protected $Conn = null; /** * Prefix, used during object creation * * @var string * @access public */ public $Prefix = ''; /** * Special, used during object creation * * @var string * @access public */ public $Special = ''; /** * Joined prefix and special, usually taken directly from * tag beeing processed, to use in kApplication::recallObject method * * @var string * @access protected * @see kApplication::recallObject */ protected $prefixSpecial = ''; /** * Set's references to kApplication and kDBConnection class instances * * @return kBase * @access public * @see kApplication * @see kDBConnection */ public function __construct($application = null) { if (!isset($application)) { $this->Application =& kApplication::Instance(); } else { $this->Application =& $application; } $this->Conn =& $this->Application->GetADODBConnection(); } /** * Set's prefix and special * * @param string $prefix * @param string $special * @access public */ public function Init($prefix, $special) { $prefix = explode('_', $prefix, 2); $this->Prefix = $prefix[0]; $this->Special = $special; $this->prefixSpecial = rtrim($this->Prefix . '.' . $this->Special, '.'); } /** * Returns prefix and special (when present) joined by a "." * * @return string * @access public */ public function getPrefixSpecial() { return $this->prefixSpecial; } } class kHelper extends kBase { /** * Performs helper initialization * * @access public */ public function InitHelper() { } /** * Append prefix and special to tag * params (get them from tagname) like * they were really passed as params * * @param string $prefix_special * @param Array $tag_params * @return Array * @access protected */ protected function prepareTagParams($prefix_special, $tag_params = Array()) { $parts = explode('.', $prefix_special); $ret = $tag_params; $ret['Prefix'] = $parts[0]; $ret['Special'] = count($parts) > 1 ? $parts[1] : ''; $ret['PrefixSpecial'] = $prefix_special; return $ret; } } abstract class kDBBase extends kBase { /** * Name of primary key field for the unit * * @var string * @access public * @see kDBBase::TableName */ public $IDField = ''; /** * Unit's database table name * * @var string * @access public */ public $TableName = ''; /** * Form name, used for validation * * @var string */ protected $formName = ''; /** * Final form configuration * * @var Array */ protected $formConfig = Array (); /** * SELECT, FROM, JOIN parts of SELECT query (no filters, no limit, no ordering) * * @var string * @access protected */ protected $SelectClause = ''; /** * Unit fields definitions (fields from database plus virtual fields) * * @var Array * @access protected */ protected $Fields = Array (); /** * Mapping between unit custom field IDs and their names * * @var Array * @access protected */ protected $customFields = Array (); /** * Unit virtual field definitions * * @var Array * @access protected */ protected $VirtualFields = Array (); /** * Fields that need to be queried using custom expression, e.g. IF(...) AS value * * @var Array * @access protected */ protected $CalculatedFields = Array (); /** * Fields that contain aggregated functions, e.g. COUNT, SUM, etc. * * @var Array * @access protected */ protected $AggregatedCalculatedFields = Array (); /** * Tells, that multilingual fields sould not be populated by default. * Can be overriden from kDBBase::Configure method * * @var bool * @access protected */ protected $populateMultiLangFields = false; /** * Set object' TableName to LIVE table, defined in unit config * * @access public */ public function SwitchToLive() { $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName'); } /** * Set object' TableName to TEMP table created based on table, defined in unit config * * @access public */ public function SwitchToTemp() { $table_name = $this->Application->getUnitOption($this->Prefix, 'TableName'); $this->TableName = $this->Application->GetTempName($table_name, 'prefix:' . $this->Prefix); } /** * Checks if object uses temp table * * @return bool * @access public */ public function IsTempTable() { return $this->Application->IsTempTable($this->TableName); } /** * Sets SELECT part of list' query * * @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE * @access public */ public function SetSelectSQL($sql) { $this->SelectClause = $sql; } /** * Returns SELECT part of list' query. * 1. Occurences of "%1$s" and "%s" are replaced to kDBBase::TableName * 2. Occurences of "%3$s" are replaced to temp table prefix (only for table, using TABLE_PREFIX) * * @param string $base_query given base query will override unit default select query * @param bool $replace_table replace all possible occurences * @return string * @access public * @see kDBBase::replaceModePrefix */ public function GetSelectSQL($base_query = null, $replace_table = true) { if (!isset($base_query)) { $base_query = $this->SelectClause; } if (!$replace_table) { return $base_query; } $query = str_replace(Array('%1$s', '%s'), $this->TableName, $base_query); return $this->replaceModePrefix($query); } /** * Allows substables to be in same mode as main item (e.g. LEFT JOINED ones) * * @param string $query * @return string * @access protected */ protected function replaceModePrefix($query) { $live_table = substr($this->Application->GetLiveName($this->TableName), strlen(TABLE_PREFIX)); if (preg_match('/'.preg_quote(TABLE_PREFIX, '/').'(.*)'.preg_quote($live_table, '/').'/', $this->TableName, $rets)) { // will only happen, when table has a prefix (like in K4) return str_replace('%3$s', $rets[1], $query); } // will happen, when K3 table without prefix is used return $query; } /** * Sets calculated fields * * @param Array $fields * @access public */ public function setCalculatedFields($fields) { $this->CalculatedFields = $fields; } /** * Adds calculated field declaration to object. * * @param string $name * @param string $sql_clause * @access public */ public function addCalculatedField($name, $sql_clause) { $this->CalculatedFields[$name] = $sql_clause; } /** * Returns required mixing of aggregated & non-aggregated calculated fields * * @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only * @return Array * @access public */ public function getCalculatedFields($aggregated = 1) { switch ($aggregated) { case 0: $fields = array_merge($this->CalculatedFields, $this->AggregatedCalculatedFields); break; case 1: $fields = $this->CalculatedFields; break; case 2: $fields = $this->AggregatedCalculatedFields; // TODO: never used break; default: $fields = Array(); break; } return $fields; } /** * Checks, that given field is a calculated field * * @param string $field * @return bool * @access public */ public function isCalculatedField($field) { return array_key_exists($field, $this->CalculatedFields); } /** * Insert calculated fields sql into query in place of %2$s, * return processed query. * * @param string $query * @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only * @return string * @access protected */ protected function addCalculatedFields($query, $aggregated = 1) { $fields = $this->getCalculatedFields($aggregated); if ($fields) { $sql = Array (); $fields = str_replace('%2$s', $this->Application->GetVar('m_lang'), $fields); foreach ($fields as $field_name => $field_expression) { $sql[] = '('.$field_expression.') AS `'.$field_name.'`'; } $sql = implode(',',$sql); return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) ); } return str_replace('%2$s', '', $query); } /** * Performs initial object configuration, which includes setting the following: * - primary key and table name * - field definitions (including field modifiers, formatters, default values) * * @param bool $populate_ml_fields create all ml fields from db in config or not * @param string $form_name form name for validation * @access public */ public function Configure($populate_ml_fields = null, $form_name = null) { if ( isset($populate_ml_fields) ) { $this->populateMultiLangFields = $populate_ml_fields; } $this->IDField = $this->Application->getUnitOption($this->Prefix, 'IDField'); $this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName'); $this->initForm($form_name); $this->defineFields(); $this->ApplyFieldModifiers(); // should be called only after all fields definitions been set $this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant! // only set on first call of method if ( isset($populate_ml_fields) ) { $this->SetDefaultValues(); } } /** * Adjusts object accoding to given form name * */ protected function initForm($form_name = null) { $forms = $this->Application->getUnitOption($this->Prefix, 'Forms', Array ()); $this->formName = $form_name; $this->formConfig = isset($forms['default']) ? $forms['default'] : Array (); if ( !$this->formName ) { return ; } if ( !isset($forms[$this->formName]) ) { trigger_error('Form "<strong>' . $this->formName . '</strong>" isn\'t declared in "<strong>' . $this->Prefix . '</strong>" unit config.', E_USER_NOTICE); } else { $this->formConfig = kUtil::array_merge_recursive($this->formConfig, $forms[$this->formName]); } } /** * Add field definitions from all possible sources * Used field sources: database fields, custom fields, virtual fields, calculated fields, aggregated calculated fields * * @access protected */ protected function defineFields() { $this->Fields = $this->getFormOption('Fields', Array ()); $this->customFields = $this->getFormOption('CustomFields', Array()); $this->setVirtualFields( $this->getFormOption('VirtualFields', Array ()) ); $calculated_fields = $this->getFormOption('CalculatedFields', Array()); $this->CalculatedFields = $this->getFieldsBySpecial($calculated_fields); $aggregated_calculated_fields = $this->getFormOption('AggregatedCalculatedFields', Array()); $this->AggregatedCalculatedFields = $this->getFieldsBySpecial($aggregated_calculated_fields); } /** * Returns form name, used for validation * * @return string */ public function getFormName() { return $this->formName; } /** * Reads unit (specified by $prefix) option specified by $option and applies form change to it * * @param string $option * @param mixed $default * @return string * @access public */ public function getFormOption($option, $default = false) { $ret = $this->Application->getUnitOption($this->Prefix, $option, $default); if ( isset($this->formConfig[$option]) ) { $ret = kUtil::array_merge_recursive($ret, $this->formConfig[$option]); } return $ret; } /** * Only exteracts fields, that match current object Special * * @param Array $fields * @return Array * @access protected */ protected function getFieldsBySpecial($fields) { if ( array_key_exists($this->Special, $fields) ) { return $fields[$this->Special]; } return array_key_exists('', $fields) ? $fields[''] : Array(); } /** * Sets aggeregated calculated fields * * @param Array $fields * @access public */ public function setAggregatedCalculatedFields($fields) { $this->AggregatedCalculatedFields = $fields; } /** * Set's field names from table from config * * @param Array $fields * @access public */ public function setCustomFields($fields) { $this->customFields = $fields; } /** * Returns custom fields information from table from config * * @return Array * @access public */ public function getCustomFields() { return $this->customFields; } /** * Set's fields information from table from config * * @param Array $fields * @access public */ public function setFields($fields) { $this->Fields = $fields; } /** * Returns fields information from table from config * * @return Array * @access public */ public function getFields() { return $this->Fields; } /** * Checks, that given field exists * * @param string $field * @return bool * @access public */ public function isField($field) { return array_key_exists($field, $this->Fields); } /** * Override field options with ones defined in submit via "field_modfiers" array (common for all prefixes) * * @param Array $field_modifiers * @return void * @access public * @author Alex */ public function ApplyFieldModifiers($field_modifiers = null) { $allowed_modifiers = Array ('required', 'multiple'); if ( $this->Application->isAdminUser ) { // can change upload dir on the fly (admin only!) $allowed_modifiers[] = 'upload_dir'; } if ( !isset($field_modifiers) ) { $field_modifiers = $this->Application->GetVar('field_modifiers'); if ( !$field_modifiers ) { // no field modifiers return ; } $field_modifiers = getArrayValue($field_modifiers, $this->getPrefixSpecial()); } if ( !$field_modifiers ) { // no field modifiers for current prefix_special return ; } foreach ($field_modifiers as $field => $field_options) { foreach ($field_options as $option_name => $option_value) { if ( !in_array(strtolower($option_name), $allowed_modifiers) ) { continue; } $this->Fields[$field][$option_name] = $option_value; } } } /** * Set fields (+options) for fields that physically doesn't exist in database * * @param Array $fields * @access public */ public function setVirtualFields($fields) { if ($fields) { $this->VirtualFields = $fields; $this->Fields = array_merge($this->VirtualFields, $this->Fields); } } /** * Returns virtual fields * * @return Array * @access public */ public function getVirtualFields() { return $this->VirtualFields; } /** * Checks, that given field is a virtual field * * @param string $field * @return bool * @access public */ public function isVirtualField($field) { return array_key_exists($field, $this->VirtualFields); } /** * Performs additional initialization for field default values * * @access protected */ protected function SetDefaultValues() { foreach ($this->Fields as $field => $options) { if ( array_key_exists('default', $options) && $options['default'] === '#NOW#' ) { $this->Fields[$field]['default'] = adodb_mktime(); } } } /** * Overwrites field definition in unit config * * @param string $field * @param Array $options * @param bool $is_virtual * @access public */ public function SetFieldOptions($field, $options, $is_virtual = false) { if ($is_virtual) { $this->VirtualFields[$field] = $options; $this->Fields = array_merge($this->VirtualFields, $this->Fields); } else { $this->Fields[$field] = $options; } } /** * Changes/sets given option's value in given field definiton * * @param string $field * @param string $option_name * @param mixed $option_value * @param bool $is_virtual * @access public */ public function SetFieldOption($field, $option_name, $option_value, $is_virtual = false) { if ($is_virtual) { $this->VirtualFields[$field][$option_name] = $option_value; } $this->Fields[$field][$option_name] = $option_value; } /** * Returns field definition from unit config. * Also executes sql from "options_sql" field option to form "options" field option * * @param string $field * @param bool $is_virtual * @return Array * @access public */ public function GetFieldOptions($field, $is_virtual = false) { $property_name = $is_virtual ? 'VirtualFields' : 'Fields'; if ( !array_key_exists($field, $this->$property_name) ) { return Array (); } if (!$is_virtual) { if (!array_key_exists('options_prepared', $this->Fields[$field]) || !$this->Fields[$field]['options_prepared']) { // executes "options_sql" from field definition, only when field options are accessed (late binding) $this->PrepareFieldOptions($field); $this->Fields[$field]['options_prepared'] = true; } } return $this->{$property_name}[$field]; } /** * Returns field option * * @param string $field * @param string $option_name * @param string $is_virtual * @param string $default * @return string * @access public */ public function GetFieldOption($field, $option_name, $is_virtual = false, $default = false) { $field_options = $this->GetFieldOptions($field, $is_virtual); - if (!$field_options) { - return $field_options; + if ( !$field_options ) { + $form_name = $this->getFormName(); + trigger_error('Field "<strong>' . $field . '</strong>" is not defined' . ($form_name ? ' on "<strong>' . $this->getFormName() . '</strong>" form' : '') . ' in "<strong>' . $this->Prefix . '</strong>" unit config', E_USER_WARNING); + + return false; } return array_key_exists($option_name, $field_options) ? $field_options[$option_name] : $default; } /** * Returns formatted field value * * @param string $name * @param string $format * * @return string * @access protected */ public function GetField($name, $format = null) { $formatter_class = $this->GetFieldOption($name, 'formatter'); if ( $formatter_class ) { $value = ($formatter_class == 'kMultiLanguage') && !preg_match('/^l[0-9]+_/', $name) ? '' : $this->GetDBField($name); $formatter =& $this->Application->recallObject($formatter_class); /* @var $formatter kFormatter */ return $formatter->Format($value, $name, $this, $format); } return $this->GetDBField($name); } /** * Returns unformatted field value * * @param string $field * @return string * @access protected */ abstract protected function GetDBField($field); /** * Checks of object has given field * * @param string $name * @return bool * @access protected */ abstract protected function HasField($name); /** * Returns field values * * @return Array * @access protected */ abstract protected function GetFieldValues(); /** * Populates values of sub-fields, based on formatters, set to mater fields * * @param Array $fields * @access public * @todo Maybe should not be publicly accessible */ public function UpdateFormattersSubFields($fields = null) { if ( !is_array($fields) ) { $fields = array_keys($this->Fields); } foreach ($fields as $field) { if ( isset($this->Fields[$field]['formatter']) ) { $formatter =& $this->Application->recallObject($this->Fields[$field]['formatter']); /* @var $formatter kFormatter */ $formatter->UpdateSubFields($field, $this->GetDBField($field), $this->Fields[$field], $this); } } } /** * Use formatters, specified in field declarations to perform additional field initialization in unit config * * @access protected */ protected function prepareConfigOptions() { $field_names = array_keys($this->Fields); foreach ($field_names as $field_name) { if ( !array_key_exists('formatter', $this->Fields[$field_name]) ) { continue; } $formatter =& $this->Application->recallObject( $this->Fields[$field_name]['formatter'] ); /* @var $formatter kFormatter */ $formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this); } } /** * Escapes fields only, not expressions * * @param string $field_expr * @return string * @access protected */ protected function escapeField($field_expr) { return preg_match('/[.(]/', $field_expr) ? $field_expr : '`' . $field_expr . '`'; } /** * Replaces current language id in given field options * * @param string $field_name * @param Array $field_option_names * @access protected */ protected function _replaceLanguageId($field_name, $field_option_names) { // don't use GetVar('m_lang') since it's always equals to default language on editing form in admin $current_language_id = $this->Application->Phrases->LanguageId; $primary_language_id = $this->Application->GetDefaultLanguageId(); $field_options =& $this->Fields[$field_name]; foreach ($field_option_names as $option_name) { $field_options[$option_name] = str_replace('%2$s', $current_language_id, $field_options[$option_name]); $field_options[$option_name] = str_replace('%3$s', $primary_language_id, $field_options[$option_name]); } } /** * Transforms "options_sql" field option into valid "options" array for given field * * @param string $field_name * @access protected */ protected function PrepareFieldOptions($field_name) { $field_options =& $this->Fields[$field_name]; if (array_key_exists('options_sql', $field_options) ) { // get options based on given sql $replace_options = Array ('option_title_field', 'option_key_field', 'options_sql'); $this->_replaceLanguageId($field_name, $replace_options); $select_clause = $this->escapeField($field_options['option_title_field']) . ',' . $this->escapeField($field_options['option_key_field']); $sql = sprintf($field_options['options_sql'], $select_clause); if (array_key_exists('serial_name', $field_options)) { // try to cache option sql on serial basis $cache_key = 'sql_' . crc32($sql) . '[%' . $field_options['serial_name'] . '%]'; $dynamic_options = $this->Application->getCache($cache_key); if ($dynamic_options === false) { $this->Conn->nextQueryCachable = true; $dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field'])); $this->Application->setCache($cache_key, $dynamic_options); } } else { // don't cache options sql $dynamic_options = $this->Conn->GetCol($sql, preg_replace('/^.*?\./', '', $field_options['option_key_field'])); } $options_hash = array_key_exists('options', $field_options) ? $field_options['options'] : Array (); $field_options['options'] = kUtil::array_merge_recursive($options_hash, $dynamic_options); // because of numeric keys } } /** * Returns ID of currently processed record * * @return int * @access public */ public function GetID() { return $this->GetDBField($this->IDField); } /** * Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation * * @return bool * @access public */ public function IsNewItem() { return $this->GetID() ? false : true; } /** * Returns parent table information * * @param string $special special of main item * @param bool $guess_special if object retrieved with specified special is not loaded, then try not to use special * @return Array * @access public */ public function getLinkedInfo($special = '', $guess_special = false) { $parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix'); if ($parent_prefix) { // if this is linked table, then set id from main table $table_info = Array ( 'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'), 'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'), 'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'), 'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'), 'ParentPrefix' => $parent_prefix ); if (is_array($table_info['ForeignKey'])) { $table_info['ForeignKey'] = getArrayValue($table_info, 'ForeignKey', $parent_prefix); } if (is_array($table_info['ParentTableKey'])) { $table_info['ParentTableKey'] = getArrayValue($table_info, 'ParentTableKey', $parent_prefix); } $main_object =& $this->Application->recallObject($parent_prefix.'.'.$special, null, Array ('raise_warnings' => 0)); /* @var $main_object kDBItem */ if (!$main_object->isLoaded() && $guess_special) { $main_object =& $this->Application->recallObject($parent_prefix); } return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) ); } return false; } /** * Returns true, when list/item was queried/loaded * * @return bool * @access protected */ abstract protected function isLoaded(); /** * Returns specified field value from all selected rows. * Don't affect current record index * * @param string $field * @return Array * @access protected */ abstract protected function GetCol($field); } \ No newline at end of file