Property changes on: branches/5.2.x/LICENSE
___________________________________________________________________
Modified: svn:mergeinfo
Merged /in-portal/branches/5.3.x/LICENSE:r15957
Property changes on: branches/5.2.x/robots.txt
___________________________________________________________________
Modified: svn:mergeinfo
Merged /in-portal/branches/5.3.x/robots.txt:r15957
Index: branches/5.2.x/core/kernel/application.php
===================================================================
--- branches/5.2.x/core/kernel/application.php (revision 16433)
+++ branches/5.2.x/core/kernel/application.php (revision 16434)
@@ -1,3100 +1,3098 @@
* The class encapsulates the main run-cycle of the script, provide access to all other objects in the framework.
*
* The class is a singleton, which means that there could be only one instance of kApplication in the script.
* 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.
* See singleton pattern by GOF.
*/
class kApplication implements kiCacheable {
/**
* Location of module helper class (used in installator too)
*/
const MODULE_HELPER_PATH = '/../units/helpers/modules_helper.php';
/**
* Is true, when Init method was called already, prevents double initialization
*
* @var bool
*/
public $InitDone = false;
/**
* Holds internal NParser object
*
* @var NParser
* @access public
*/
public $Parser;
/**
* Holds parser output buffer
*
* @var string
* @access protected
*/
protected $HTML = '';
/**
* The main Factory used to create
* almost any class of kernel and
* modules
*
* @var kFactory
* @access protected
*/
protected $Factory;
/**
* Template names, that will be used instead of regular templates
*
* @var Array
* @access public
*/
public $ReplacementTemplates = Array ();
/**
* Mod-Rewrite listeners used during url building and parsing
*
* @var Array
* @access public
*/
public $RewriteListeners = Array ();
/**
* Reference to debugger
*
* @var Debugger
* @access public
*/
public $Debugger = null;
/**
* Holds all phrases used
* in code and template
*
* @var PhrasesCache
* @access public
*/
public $Phrases;
/**
* Modules table content, key - module name
*
* @var Array
* @access public
*/
public $ModuleInfo = Array ();
/**
* Holds DBConnection
*
* @var IDBConnection
* @access public
*/
public $Conn = null;
/**
* Reference to event log
*
* @var Array|kLogger
* @access public
*/
protected $_logger = Array ();
// performance needs:
/**
* Holds a reference to httpquery
*
* @var kHttpQuery
* @access public
*/
public $HttpQuery = null;
/**
* Holds a reference to UnitConfigReader
*
* @var kUnitConfigReader
* @access public
*/
public $UnitConfigReader = null;
/**
* Holds a reference to Session
*
* @var Session
* @access public
*/
public $Session = null;
/**
* Holds a ref to kEventManager
*
* @var kEventManager
* @access public
*/
public $EventManager = null;
/**
* Holds a ref to kUrlManager
*
* @var kUrlManager
* @access public
*/
public $UrlManager = null;
/**
* Ref for TemplatesCache
*
* @var TemplatesCache
* @access public
*/
public $TemplatesCache = null;
/**
* Holds current NParser tag while parsing, can be used in error messages to display template file and line
*
* @var _BlockTag
* @access public
*/
public $CurrentNTag = null;
/**
* Object of unit caching class
*
* @var kCacheManager
* @access public
*/
public $cacheManager = null;
/**
* Tells, that administrator has authenticated in administrative console
* Should be used to manipulate data change OR data restrictions!
*
* @var bool
* @access public
*/
public $isAdminUser = false;
/**
* Tells, that admin version of "index.php" was used, nothing more!
* Should be used to manipulate data display!
*
* @var bool
* @access public
*/
public $isAdmin = false;
/**
* Instance of site domain object
*
* @var kDBItem
* @access public
* @todo move away into separate module
*/
public $siteDomain = null;
/**
* Prevent kApplication class to be created directly, only via Instance method
*
* @access private
*/
private function __construct()
{
}
final private function __clone() {}
/**
* 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:
*
* $application =& kApplication::Instance();
*
* or in an object:
*
* $this->Application =& kApplication::Instance();
*
* 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
* @return kApplication
* @access public
*/
public static function &Instance()
{
static $instance = false;
if ( !$instance ) {
$class = defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication';
$instance = new $class();
}
return $instance;
}
/**
* Initializes the Application
*
* @param string $factory_class
* @return bool Was Init actually made now or before
* @access public
* @see kHTTPQuery
* @see Session
* @see TemplatesCache
*/
public function Init($factory_class = 'kFactory')
{
if ( $this->InitDone ) {
return false;
}
if ( preg_match('/utf-8/i', CHARSET) ) {
setlocale(LC_ALL, 'en_US.UTF-8');
mb_internal_encoding('UTF-8');
}
$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:');
}
$this->_logger = new kLogger($this->_logger);
$this->Factory = new $factory_class();
$this->registerDefaultClasses();
$vars = kUtil::parseConfig(true);
$db_class = isset($vars['Databases']) ? 'kDBLoadBalancer' : ($this->isDebugMode() ? 'kDBConnectionDebug' : 'kDBConnection');
$this->Conn = $this->Factory->makeClass($db_class, Array (SQL_TYPE, Array ($this->_logger, 'handleSQLError')));
$this->Conn->setup($vars);
$this->cacheManager = $this->makeClass('kCacheManager');
$this->cacheManager->InitCache();
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('Before UnitConfigReader');
}
// init config reader and all managers
$this->UnitConfigReader = $this->makeClass('kUnitConfigReader');
$this->UnitConfigReader->scanModules(MODULES_PATH); // will also set RewriteListeners when existing cache is read
$this->registerModuleConstants();
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->appendTimestamp('After UnitConfigReader');
}
define('MOD_REWRITE', $this->ConfigValue('UseModRewrite') && !$this->isAdmin ? 1 : 0);
// start processing request
$this->HttpQuery = $this->recallObject('HTTPQuery');
$this->HttpQuery->process();
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');
}
$this->Session->ValidateExpired(); // needs mod_rewrite url already parsed to keep user at proper template after session expiration
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 ) {
date_default_timezone_set($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(); // will set RewriteListeners when missing cache is built first time
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') && !(defined('IS_INSTALL') && IS_INSTALL) ) {
$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);
}
if ( defined('DEBUG_MODE') && $this->isDebugMode() ) {
$this->Debugger->profileFinish('kernel4_startup');
}
$this->InitDone = true;
if ( PHP_SAPI !== 'cli' && !$this->isAdmin ) {
$this->HandleEvent(new kEvent('adm:OnStartup'));
}
return true;
}
/**
* Performs initialization of manager classes, that can be overridden from unit configs
*
* @return void
* @access public
* @throws Exception
*/
public 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 $return_field field value to returns, if not specified, then return all fields
* @return Array
*/
public function findModule($field, $value, $return_field = null)
{
$found = $module_info = false;
foreach ($this->ModuleInfo as $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', true) ) {
$this->registerModuleConstants();
return;
}
// use makeClass over recallObject, since used before kApplication initialization during installation
$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
*
* @return void
* @access public
*/
public function VerifyLanguageId()
{
/** @var LanguagesItem $lang */
$lang = $this->recallObject('lang.current');
if ( !$lang->isLoaded() || (!$this->isAdmin && !$lang->GetDBField('Enabled')) ) {
if ( !defined('IS_INSTALL') ) {
$this->ApplicationDie('Unknown or disabled language');
}
}
}
/**
* Checks if passed theme id if valid and sets it to primary otherwise
*
* @return void
* @access public
*/
public 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);
}
/**
* Returns relative path to current front-end theme
*
* @param bool $force
* @return string
* @access public
*/
public function GetFrontThemePath($force = false)
{
static $path = null;
if ( !$force && isset($path) ) {
return $path;
}
/** @var ThemeItem $theme */
$theme = $this->recallObject('theme.current');
if ( !$theme->isLoaded() || !$theme->GetDBField('Enabled') ) {
return false;
}
// assign & then return, since it's static variable
$path = '/themes/' . $theme->GetDBField('Name');
return $path;
}
/**
* Returns primary front/admin language id
*
* @param bool $init
* @return int
* @access public
*/
public 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;
}
/**
* Returns front-end primary theme id (even, when called from admin console)
*
* @param bool $force_front
* @return int
* @access public
*/
public function GetDefaultThemeId($force_front = false)
{
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
* @access public
* @todo Move into In-Commerce
*/
public function GetPrimaryCurrency()
{
$cache_key = 'primary_currency[%CurrSerial%][%SiteDomainSerial%]:' . $this->siteDomainField('DomainId');
$currency_iso = $this->getCache($cache_key);
if ( $currency_iso === false ) {
if ( $this->prefixRegistred('curr') ) {
$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
* @return mixed
* @todo Move into separate module
*/
public 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', null, Array ('live_table' => true));
/* @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 kDBEventHandler, kUrlManager
*
* Called automatically while initializing kApplication
*
* @return void
* @access public
*/
public 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');
$this->registerClass('kEventManager', KERNEL_PATH . '/event_manager.php', 'EventManager');
$this->registerClass('kHookManager', KERNEL_PATH . '/managers/hook_manager.php');
$this->registerClass('kScheduledTaskManager', KERNEL_PATH . '/managers/scheduled_task_manager.php');
$this->registerClass('kRequestManager', KERNEL_PATH . '/managers/request_manager.php');
$this->registerClass('kSubscriptionManager', KERNEL_PATH . '/managers/subscription_manager.php');
$this->registerClass('kSubscriptionItem', KERNEL_PATH . '/managers/subscription_manager.php');
$this->registerClass('kUrlManager', KERNEL_PATH . '/managers/url_manager.php');
$this->registerClass('kUrlProcessor', KERNEL_PATH . '/managers/url_processor.php');
$this->registerClass('kPlainUrlProcessor', KERNEL_PATH . '/managers/plain_url_processor.php');
$this->registerClass('kRewriteUrlProcessor', KERNEL_PATH . '/managers/rewrite_url_processor.php');
$this->registerClass('kCacheManager', KERNEL_PATH . '/managers/cache_manager.php');
$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('kOpenerStack', KERNEL_PATH . '/utility/opener_stack.php');
$this->registerClass('kLogger', KERNEL_PATH . '/utility/logger.php');
$this->registerClass('kUnitConfigReader', KERNEL_PATH . '/utility/unit_config_reader.php');
$this->registerClass('PasswordHash', KERNEL_PATH . '/utility/php_pass.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');
// 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');
$this->registerClass('kDBTagProcessor', KERNEL_PATH . '/db/db_tag_processor.php');
$this->registerClass('kCatDBTagProcessor', KERNEL_PATH . '/db/cat_tag_processor.php');
$this->registerClass('NParser', KERNEL_PATH . '/nparser/nparser.php');
$this->registerClass('TemplatesCache', KERNEL_PATH . '/nparser/template_cache.php');
// database
$this->registerClass('kDBConnection', KERNEL_PATH . '/db/db_connection.php');
$this->registerClass('kDBConnectionDebug', KERNEL_PATH . '/db/db_connection.php');
$this->registerClass('kDBLoadBalancer', KERNEL_PATH . '/db/db_load_balancer.php');
$this->registerClass('kDBItem', KERNEL_PATH . '/db/dbitem.php');
$this->registerClass('kCatDBItem', KERNEL_PATH . '/db/cat_dbitem.php');
$this->registerClass('kDBList', KERNEL_PATH . '/db/dblist.php');
$this->registerClass('kCatDBList', KERNEL_PATH . '/db/cat_dblist.php');
$this->registerClass('kDBEventHandler', KERNEL_PATH . '/db/db_event_handler.php');
$this->registerClass('kCatDBEventHandler', KERNEL_PATH . '/db/cat_event_handler.php');
// email sending
$this->registerClass('kEmail', KERNEL_PATH . '/utility/email.php');
$this->registerClass('kEmailSendingHelper', KERNEL_PATH . '/utility/email_send.php', 'EmailSender');
$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 . self::MODULE_HELPER_PATH, 'ModulesHelper');
}
/**
* Registers default build events
*
* @return void
*/
public function RegisterDefaultBuildEvents()
{
$this->EventManager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild');
}
/**
* Returns cached category information 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)
*
* @param int $caching_type
* @return bool
* @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
* @return string
* @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);
}
/**
* Stores new $value in cache with $key name
*
* @param int $key key name to add to cache
* @param mixed $value value of cached record
* @param int $expiration when value expires (0 - doesn't expire)
* @return bool
* @access public
*/
public function setCache($key, $value, $expiration = 0)
{
return $this->cacheManager->setCache($key, $value, $expiration);
}
/**
* Stores new $value in cache with $key name (only if it's not there)
*
* @param int $key key name to add to cache
* @param mixed $value value of cached record
* @param int $expiration when value expires (0 - doesn't expire)
* @return bool
* @access public
*/
public function addCache($key, $value, $expiration = 0)
{
return $this->cacheManager->addCache($key, $value, $expiration);
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @return bool
* @access public
*/
public function rebuildCache($name, $mode = null, $max_rebuilding_time = 0)
{
return $this->cacheManager->rebuildCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from cache
*
* @param string $key
* @return void
* @access public
*/
public function deleteCache($key)
{
$this->cacheManager->deleteCache($key);
}
/**
* Reset's all memory cache at once
*
* @return void
* @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
* @return void
* @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
* @return bool
* @access public
*/
public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0)
{
return $this->cacheManager->rebuildDBCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from database cache
*
* @param string $name
* @return void
* @access public
*/
public function deleteDBCache($name)
{
$this->cacheManager->deleteDBCache($name);
}
/**
* Registers each module specific constants if any found
*
* @return bool
* @access protected
*/
protected 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_info) {
$constants_file = FULL_PATH . '/' . $module_info['Path'] . 'constants.php';
if ( file_exists($constants_file) ) {
kUtil::includeOnce($constants_file);
}
}
return true;
}
/**
* Performs redirect to hard maintenance template
*
* @return void
* @access public
*/
public function redirectToMaintenance()
{
$maintenance_page = WRITEBALE_BASE . '/maintenance.html';
$query_string = ''; // $this->isAdmin ? '' : '?next_template=' . kUtil::escape($_SERVER['REQUEST_URI'], kUtil::ESCAPE_URL);
if ( file_exists(FULL_PATH . $maintenance_page) ) {
header('Location: ' . BASE_PATH . $maintenance_page . $query_string);
exit;
}
}
/**
* 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.
*
* @return void
* @access public
*/
public function Run()
{
// process maintenance mode redirect: begin
$maintenance_mode = $this->getMaintenanceMode();
if ( $maintenance_mode == MaintenanceMode::HARD ) {
$this->redirectToMaintenance();
}
elseif ( $maintenance_mode == MaintenanceMode::SOFT ) {
$maintenance_template = $this->isAdmin ? 'login' : $this->ConfigValue('SoftMaintenanceTemplate');
if ( $this->GetVar('t') != $maintenance_template ) {
$redirect_params = Array ();
if ( !$this->isAdmin ) {
$redirect_params['next_template'] = $_SERVER['REQUEST_URI'];
}
$this->Redirect($maintenance_template, $redirect_params);
}
}
// process maintenance mode redirect: end
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') ) {
$admin_session = $this->recallObject('Session.admin');
/* @var $admin_session Session */
// store Admin Console User's ID to Front-End's session for cross-session permission checks
$this->StoreVar('admin_user_id', (int)$admin_session->RecallVar('user_id'));
if ( $this->CheckAdminPermission('CATEGORY.MODIFY', 0, $this->getBaseCategory()) ) {
// user can edit cms blocks (when viewing front-end through admin's frame)
$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();
$this->EventManager->ProcessRequest();
$this->InitParser();
$t = $this->GetVar('render_template', $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('Design Template: ' . $t . '; CategoryID: ' . $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:');
}
}
/**
* Replaces current rendered template with given one.
*
* @param string|null $template Template.
*
* @return void
*/
public function QuickRun($template)
{
/** @var kThemesHelper $themes_helper */
$themes_helper = $this->recallObject('ThemesHelper');
// Set Web Request variables to affect link building on template itself.
$this->SetVar('t', $template);
$this->SetVar('m_cat_id', $themes_helper->getPageByTemplate($template));
$this->SetVar('passed', 'm');
// Replace current page content with given template.
$this->InitParser();
$this->Parser->Clear();
$this->HTML = $this->Parser->Run($template);
}
/**
* Performs template parser/cache initialization
*
* @param bool|string $theme_name
* @return void
* @access public
*/
public 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.
*
* @return void
* @access public
*/
public function Done()
{
$this->HandleEvent(new kEvent('adm:OnBeforeShutdown'));
$debug_mode = defined('DEBUG_MODE') && $this->isDebugMode();
if ( $debug_mode ) {
if ( kUtil::constOn('DBG_PROFILE_MEMORY') ) {
$this->Debugger->appendMemoryUsage('Application before Done:');
}
$this->Session->SaveData(); // adds session data to debugger report
$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;
}
$this->_outputPage();
$this->cacheManager->UpdateApplicationCache();
if ( !$debug_mode ) {
$this->Session->SaveData();
}
$this->EventManager->runScheduledTasks();
if ( defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->isAdmin ) {
$this->_storeStatistics();
}
}
/**
* Outputs generated page content to end-user
*
* @return void
* @access protected
*/
protected function _outputPage()
{
$this->setContentType();
ob_start();
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 {
// when gzip compression not used connection won't be closed early!
echo $this->HTML;
}
// send headers to tell the browser to close the connection
header('Content-Length: ' . ob_get_length());
header('Connection: close');
// flush all output
ob_end_flush();
if ( ob_get_level() ) {
ob_flush();
}
flush();
// close current session
if ( session_id() ) {
session_write_close();
}
}
/**
* Stores script execution statistics to database
*
* @return void
* @access protected
*/
protected 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
* @return void
* @access protected
*/
protected 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;
}
}
/**
* Remembers slow query SQL and execution time into log
*
* @param string $slow_sql
* @param int $time
* @return void
* @access public
*/
public function logSlowQuery($slow_sql, $time)
{
$query_crc = kUtil::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 bool
* @access protected
*/
protected function UseOutputCompression()
{
if ( kUtil::constOn('IS_INSTALL') || kUtil::constOn('DBG_ZEND_PRESENT') || kUtil::constOn('SKIP_OUT_COMPRESSION') ) {
return false;
}
$accept_encoding = isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : '';
return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($accept_encoding, 'gzip');
}
// Facade
/**
* Returns current session id (SID)
*
* @return int
* @access public
*/
public function GetSID()
{
$session = $this->recallObject('Session');
/* @var $session Session */
return $session->GetID();
}
/**
* Destroys current session
*
* @return void
* @access public
* @see UserHelper::logoutUser()
*/
public 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;
}
/**
* Removes forceful escaping done to the variable upon Front-End submission.
*
* @param string|array $value Value.
*
* @return string|array
* @see kHttpQuery::StripSlashes
* @todo Temporary method for marking problematic places to take care of, when forceful escaping will be removed.
*/
public function unescapeRequestVariable($value)
{
return $this->HttpQuery->unescapeRequestVariable($value);
}
/**
* Returns variable passed to the script as $type
*
* @param string $name Name of variable to retrieve
* @param string $type Get/Post/Cookie
* @param mixed $default default value returned in case if variable not present
* @return mixed
* @access public
*/
public function GetVarDirect($name, $type, $default = false)
{
// $type = ucfirst($type);
$array = $this->HttpQuery->$type;
return isset($array[$name]) ? $array[$name] : $default;
}
/**
* Returns ALL variables passed to the script as GET/POST/COOKIE
*
* @return Array
* @access public
* @deprecated
*/
public 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.
*
* @param string $var Variable name to set
* @param mixed $val Variable value
* @return void
* @access public
*/
public function SetVar($var,$val)
{
$this->HttpQuery->Set($var, $val);
}
/**
* Deletes kHTTPQuery variable
*
* @param string $var
* @return void
* @todo Think about method name
*/
public function DeleteVar($var)
{
$this->HttpQuery->Remove($var);
}
/**
* Deletes Session variable
*
* @param string $var
* @return void
* @access public
*/
public function RemoveVar($var)
{
$this->Session->RemoveVar($var);
}
/**
* Removes variable from persistent session
*
* @param string $var
* @return void
* @access public
*/
public function RemovePersistentVar($var)
{
$this->Session->RemovePersistentVar($var);
}
/**
* Restores Session variable to it's db version
*
* @param string $var
* @return void
* @access public
*/
public function RestoreVar($var)
{
$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.
*
* @param string $var Variable name
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
* @access public
* @see Session::RecallVar()
*/
public function RecallVar($var,$default=false)
{
return $this->Session->RecallVar($var,$default);
}
/**
* Returns variable value from persistent session
*
* @param string $var
* @param mixed $default
* @return mixed
* @access public
* @see Session::RecallPersistentVar()
*/
public 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.
*
* @param string $var Variable name
* @param mixed $val Variable value
* @param bool $optional
* @return void
* @access public
* @see kApplication::RecallVar()
*/
public function StoreVar($var, $val, $optional = false)
{
$session = $this->recallObject('Session');
/* @var $session Session */
$this->Session->StoreVar($var, $val, $optional);
}
/**
* Stores variable to persistent session
*
* @param string $var
* @param mixed $val
* @param bool $optional
* @return void
* @access public
*/
public function StorePersistentVar($var, $val, $optional = false)
{
$this->Session->StorePersistentVar($var, $val, $optional);
}
/**
* Stores default value for session variable
*
* @param string $var
* @param string $val
* @param bool $optional
* @return void
* @access public
* @see Session::RecallVar()
* @see Session::StoreVar()
*/
public function StoreVarDefault($var, $val, $optional = false)
{
$session = $this->recallObject('Session');
/* @var $session 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).
* 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
*
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @param bool $optional
* @return void
* @access public
*/
public 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
*
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @return mixed
* @access public
* @see LinkVar
*/
public function GetLinkedVar($var, $ses_var = null, $default = '')
{
$this->LinkVar($var, $ses_var, $default);
return $this->GetVar($var);
}
/**
* Renders given tag and returns it's output
*
* @param string $prefix
* @param string $tag
* @param Array $params
* @return mixed
* @access public
* @see kApplication::InitParser()
*/
public function ProcessParsedTag($prefix, $tag, $params)
{
$processor = $this->Parser->GetProcessor($prefix);
/* @var $processor kDBTagProcessor */
return $processor->ProcessParsedTag($tag, $params, $prefix);
}
/**
* Return object of IDBConnection interface
*
* Return object of IDBConnection interface already connected to the project database, configurable in config.php
*
* @return IDBConnection
* @access public
*/
public 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 bool $pass_params Forces to pass current parser params to this block/template. Use with caution, because you can accidentally pass "block_no_data" parameter.
* @param bool $as_template
* @return string
* @access public
*/
public function ParseBlock($params, $pass_params = false, $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
* @access public
*/
public 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
* @access public
*/
public function IncludeTemplate($params)
{
return $this->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0);
}
/**
* Return href for template
*
* @param string $t Template path
* @param string $prefix index.php prefix - could be blank, 'admin'
* @param Array $params
* @param string $index_file
* @return string
*/
public function HREF($t, $prefix = '', $params = Array (), $index_file = null)
{
return $this->UrlManager->HREF($t, $prefix, $params, $index_file);
}
/**
* Returns theme template filename and it's corresponding page_id based on given seo template
*
* @param string $seo_template
* @return string
* @access public
*/
public function getPhysicalTemplate($seo_template)
{
return $this->UrlManager->getPhysicalTemplate($seo_template);
}
/**
* Returns template name, that corresponds with given virtual (not physical) page id
*
* @param int $page_id
* @return string|bool
* @access public
*/
public function getVirtualPageTemplate($page_id)
{
return $this->UrlManager->getVirtualPageTemplate($page_id);
}
/**
* Returns section template for given physical/virtual template
*
* @param string $template
* @param int $theme_id
* @return string
* @access public
*/
public function getSectionTemplate($template, $theme_id = null)
{
return $this->UrlManager->getSectionTemplate($template, $theme_id);
}
/**
* Returns variables with values that should be passed through with this link + variable list
*
* @param Array $params
* @return Array
* @access public
*/
public function getPassThroughVariables(&$params)
{
return $this->UrlManager->getPassThroughVariables($params);
}
/**
* Builds url
*
* @param string $t
* @param Array $params
* @param string $pass
* @param bool $pass_events
* @param bool $env_var
* @return string
* @access public
*/
public function BuildEnv($t, $params, $pass = 'all', $pass_events = false, $env_var = true)
{
return $this->UrlManager->plain->build($t, $params, $pass, $pass_events, $env_var);
}
/**
* Process QueryString only, create
* events, ids, based on config
* set template name and sid in
* desired application variables.
*
* @param string $env_var environment string value
* @param string $pass_name
* @return Array
* @access public
*/
public function processQueryString($env_var, $pass_name = 'passed')
{
return $this->UrlManager->plain->parse($env_var, $pass_name);
}
/**
* Parses rewrite url and returns parsed variables
*
* @param string $url
* @param string $pass_name
* @return Array
* @access public
*/
public function parseRewriteUrl($url, $pass_name = 'passed')
{
return $this->UrlManager->rewrite->parse($url, $pass_name);
}
/**
* Returns base part of all urls, build on website
*
* @param string $prefix
* @param bool $ssl
* @param bool $add_port
* @return string
* @access public
*/
public 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 : '') . 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 : '') . BASE_PATH . $prefix . '/';
}
/**
* Redirects user to url, that's build based on given parameters
*
* @param string $t
* @param Array $params
* @param string $prefix
* @param string $index_file
* @return void
* @access public
*/
public 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';
}
$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 'Debug output above !!!
' . "\n";
if ( array_key_exists('HTTP_REFERER', $_SERVER) ) {
echo 'Referer: ' . kUtil::escape($_SERVER['HTTP_REFERER'], kUtil::ESCAPE_HTML) . '
' . "\n";
}
echo "Proceed to redirect: {$location}
\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;
}
else {
if ( $this->GetVar('ajax') == 'yes' && ($t != $this->GetVar('t') || !$this->isSOPSafe($location, $t)) ) {
// redirection to other then current template during ajax request OR SOP violation
kUtil::safeDefine('DBG_SKIP_REPORTING', 1);
echo '#redirect#' . $location;
}
elseif ( headers_sent() != '' ) {
// some output occurred -> redirect using javascript
echo '';
}
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 */
if ( $this->InitDone ) {
// if redirect happened in the middle of application initialization don't call event,
// that presumes that application was successfully initialized
$this->HandleEvent(new kEvent('adm:OnBeforeShutdown'));
}
$session->SaveData();
ob_end_flush();
exit;
}
/**
* Determines if real redirect should be made within AJAX request.
*
* @param string $url Location.
* @param string $template Template.
*
* @return boolean
* @link http://en.wikipedia.org/wiki/Same-origin_policy
*/
protected function isSOPSafe($url, $template)
{
$parsed_url = parse_url($url);
if ( $parsed_url['scheme'] . '://' != PROTOCOL ) {
return false;
}
if ( $parsed_url['host'] != SERVER_NAME ) {
return false;
}
if ( defined('PORT') && isset($parsed_url['port']) && $parsed_url['port'] != PORT ) {
return false;
}
return true;
}
/**
* Returns translation of given label
*
* @param string $label
* @param bool $allow_editing return translation link, when translation is missing on current language
* @param bool $use_admin use current Admin Console language to translate phrase
* @return string
* @access public
*/
public 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
*/
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.
*
* @return void
* @access protected
*/
protected 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.login-admin', null, Array ('form_name' => 'login'));
/* @var $user UsersItem */
$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);
- }
+ $this->HandleEvent(new kEvent('adm:OnLogHttpRequest'));
if ( $user_id != USER_GUEST ) {
// normal users + root
$this->LoadPersistentVars();
}
$user_timezone = $this->Session->GetField('TimeZone');
if ( $user_timezone ) {
date_default_timezone_set($user_timezone);
}
}
/**
* Loads current user persistent session data
*
* @return void
* @access public
*/
public function LoadPersistentVars()
{
$this->Session->LoadPersistentVars();
}
/**
* Returns configuration option value by name
*
* @param string $name
* @return string
* @access public
*/
public function ConfigValue($name)
{
return $this->cacheManager->ConfigValue($name);
}
/**
* Changes value of individual configuration variable (+resets cache, when needed)
*
* @param string $name
* @param string $value
* @param bool $local_cache_only
* @return string
* @access public
*/
public function SetConfigValue($name, $value, $local_cache_only = false)
{
return $this->cacheManager->SetConfigValue($name, $value, $local_cache_only);
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @param Array $params
* @param Array $specific_params
* @return void
* @access public
*/
public function HandleEvent($event, $params = null, $specific_params = null)
{
if ( isset($params) ) {
$event = new kEvent($params, $specific_params);
}
$this->EventManager->HandleEvent($event);
}
/**
* Notifies event subscribers, that event has occured
*
* @param kEvent $event
* @return void
*/
public function notifyEventSubscribers(kEvent $event)
{
$this->EventManager->notifySubscribers($event);
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function eventImplemented(kEvent $event)
{
return $this->EventManager->eventImplemented($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
* @return void
* @access public
*/
public function registerClass($real_class, $file, $pseudo_class = null)
{
$this->Factory->registerClass($real_class, $file, $pseudo_class);
}
/**
* 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
* @return void
* @access public
*/
public function unregisterClass($real_class, $pseudo_class = null)
{
$this->Factory->unregisterClass($real_class, $pseudo_class);
}
/**
* Finds the absolute path to the file where the class is defined.
*
* @param string $class The name of the class.
*
* @return string|false
*/
public function findClassFile($class)
{
return $this->Factory->findClassFile($class);
}
/**
* Add new scheduled task
*
* @param string $short_name name to be used to store last maintenance run info
* @param string $event_string
* @param int $run_schedule run schedule like for Cron
* @param int $status
* @access public
*/
public function registerScheduledTask($short_name, $event_string, $run_schedule, $status = STATUS_ACTIVE)
{
$this->EventManager->registerScheduledTask($short_name, $event_string, $run_schedule, $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
* @return void
* @access public
*/
public 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, array $event_params = array(), array $arguments = array())
{
/*if ( !$this->hasObject($name) && $this->isDebugMode() && ($name == '_prefix_here_') ) {
// first time, when object with "_prefix_here_" prefix is accessed
$this->Debugger->appendTrace();
}*/
return $this->Factory->getObject($name, $pseudo_class, $event_params, $arguments);
}
/**
* Returns tag processor for prefix specified
*
* @param string $prefix
* @return kDBTagProcessor
* @access public
*/
public function recallTagProcessor($prefix)
{
$this->InitParser(); // because kDBTagProcesor is in NParser dependencies
return $this->recallObject($prefix . '_TagProcessor');
}
/**
* Checks if object with prefix passes was already created in factory
*
* @param string $name object pseudo_class, prefix
* @return bool
* @access public
*/
public function hasObject($name)
{
return $this->Factory->hasObject($name);
}
/**
* Removes object from storage by given name
*
* @param string $name Object's name in the Storage
* @return void
* @access public
*/
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, array $arguments = array())
{
return $this->Factory->makeClass($pseudo_class, $arguments);
}
/**
* 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|null $ssl Force ssl link to be build
* @return bool
* @access public
*/
public 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 $option
* @param string $value
* @access public
*/
public function setUnitOption($prefix, $option, $value)
{
$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
* @return void
* @access public
*/
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 public
* @throws Exception
* @deprecated
*/
public function handleSQLError($code, $msg, $sql)
{
return $this->_logger->handleSQLError($code, $msg, $sql);
}
/**
* Returns & blocks next ResourceId available in system
*
* @return int
* @access public
*/
public 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 sub-table prefix passes
* OR prefix, that has been found in REQUEST and some how is parent of passed sub-table prefix
*
* @param string $current_prefix
* @param bool $real_top if set to true will return real topmost prefix, regardless of its id is passed or not
* @return string
* @access public
*/
public 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_template_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
* @access public
*/
public function emailAdmin($email_template_name, $to_user_id = null, $send_params = Array ())
{
return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_ADMIN, $to_user_id, $send_params);
}
/**
* Triggers email event of type User
*
* @param string $email_template_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
* @access public
*/
public function emailUser($email_template_name, $to_user_id = null, $send_params = Array ())
{
return $this->_email($email_template_name, EmailTemplate::TEMPLATE_TYPE_FRONTEND, $to_user_id, $send_params);
}
/**
* Triggers general email event
*
* @param string $email_template_name
* @param int $email_template_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
* @access protected
*/
protected function _email($email_template_name, $email_template_type, $to_user_id = null, $send_params = Array ())
{
$email = $this->makeClass('kEmail');
/* @var $email kEmail */
if ( !$email->findTemplate($email_template_name, $email_template_type) ) {
return false;
}
$email->setParams($send_params);
return $email->send($to_user_id);
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
* @access public
*/
public 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
* @access public
*/
public 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);
}
/**
* Check current admin 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
* @access public
*/
public function CheckAdminPermission($name, $type = 1, $cat_id = null)
{
$perm_helper = $this->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
return $perm_helper->CheckAdminPermission($name, $type, $cat_id);
}
/**
* Set's any field of current visit
*
* @param string $field
* @param mixed $value
* @return void
* @access public
* @todo move to separate module
*/
public function setVisitField($field, $value)
{
if ( $this->isAdmin || !$this->ConfigValue('UseVisitorTracking') ) {
// admin logins are not registered 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
* @access public
*/
public function isInstalled()
{
return $this->InitDone && (count($this->ModuleInfo) > 0);
}
/**
* Allows to determine if module is installed & enabled
*
* @param string $module_name
* @return bool
* @access public
*/
public 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 int
* @access public
*/
public 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
* @access public
*/
public function GetTempName($table, $wid = '')
{
return $this->GetTempTablePrefix($wid) . $table;
}
/**
* Builds temporary table prefix based on given window id
*
* @param string $wid
* @return string
* @access public
*/
public function GetTempTablePrefix($wid = '')
{
if ( preg_match('/prefix:(.*)/', $wid, $regs) ) {
$wid = $this->GetTopmostWid($regs[1]);
}
return TABLE_PREFIX . 'ses_' . $this->GetSID() . ($wid ? '_' . $wid : '') . '_edit_';
}
/**
* Checks if given table is a temporary table
*
* @param string $table
* @return bool
* @access public
*/
public 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
* @param string $special
* @return bool
* @access public
*/
public 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
*/
public 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;
}
}
/**
* Stops processing of user request and displays given message
*
* @param string $message
* @access public
*/
public function ApplicationDie($message = '')
{
while ( ob_get_level() ) {
ob_end_clean();
}
if ( $this->isDebugMode() ) {
$message .= $this->Debugger->printReport(true);
}
$this->HTML = $message;
$this->_outputPage();
}
/**
* Returns comma-separated list of groups from given user
*
* @param int $user_id
* @return string
*/
public 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 . 'UserGroupRelations
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 scheduled_tasks supported)
*
* @return bool
* @access public
*/
/*public 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 presence in database
*
* @param string $table_name
* @param bool $force
* @return bool
* @access public
*/
public function TableFound($table_name, $force = false)
{
return $this->Conn->TableFound($table_name, $force);
}
/**
* 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 parameters)
* @param bool $multiple_results
* @return mixed
* @access public
*/
public 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)
{
$this->setContentType('text/xml');
return $xml_version ? '' : '';
}
/**
* Returns category tree
*
* @param int $category_id
* @return Array
* @access public
*/
public 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
* @access public
*/
public 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'];
}
/**
* Deletes all data, that was cached during unit config parsing (excluding unit config locations)
*
* @param Array $config_variables
* @access public
*/
public function DeleteUnitCache($config_variables = null)
{
$this->cacheManager->DeleteUnitCache($config_variables);
}
/**
* Deletes cached section tree, used during permission checking and admin console tree display
*
* @return void
* @access public
*/
public function DeleteSectionCache()
{
$this->cacheManager->DeleteSectionCache();
}
/**
* Sets data from cache to object
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->Factory->setFromCache($data);
$this->UnitConfigReader->setFromCache($data);
$this->EventManager->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_merge(
$this->Factory->getToCache(),
$this->UnitConfigReader->getToCache(),
$this->EventManager->getToCache(),
Array (
'Application.ReplacementTemplates' => $this->ReplacementTemplates,
'Application.RewriteListeners' => $this->RewriteListeners,
'Application.ModuleInfo' => $this->ModuleInfo,
)
);
}
public function delayUnitProcessing($method, $params)
{
$this->cacheManager->delayUnitProcessing($method, $params);
}
/**
* Returns current maintenance mode state
*
* @param bool $check_ips
* @return int
* @access public
*/
public function getMaintenanceMode($check_ips = true)
{
$exception_ips = defined('MAINTENANCE_MODE_IPS') ? MAINTENANCE_MODE_IPS : '';
$setting_name = $this->isAdmin ? 'MAINTENANCE_MODE_ADMIN' : 'MAINTENANCE_MODE_FRONT';
if ( defined($setting_name) && constant($setting_name) > MaintenanceMode::NONE ) {
$exception_ip = $check_ips ? kUtil::ipMatch($exception_ips) : false;
if ( !$exception_ip ) {
return constant($setting_name);
}
}
return MaintenanceMode::NONE;
}
/**
* Sets content type of the page
*
* @param string $content_type
* @param bool $include_charset
* @return void
* @access public
*/
public function setContentType($content_type = 'text/html', $include_charset = null)
{
static $already_set = false;
if ( $already_set ) {
return;
}
$header = 'Content-type: ' . $content_type;
if ( !isset($include_charset) ) {
$include_charset = $content_type = 'text/html' || $content_type == 'text/plain' || $content_type = 'text/xml';
}
if ( $include_charset ) {
$header .= '; charset=' . CHARSET;
}
$already_set = true;
header($header);
}
/**
* Posts message to event log
*
* @param string $message
* @param int $code
* @param bool $write_now Allows further customization of log record by returning kLog object
* @return bool|int|kLogger
* @access public
*/
public function log($message, $code = null, $write_now = false)
{
$log = $this->_logger->prepare($message, $code)->addSource($this->_logger->createTrace(null, 1));
if ( $write_now ) {
return $log->write();
}
return $log;
}
/**
* Deletes log with given id from database or disk, when database isn't available
*
* @param int $unique_id
* @param int $storage_medium
* @return void
* @access public
* @throws InvalidArgumentException
*/
public function deleteLog($unique_id, $storage_medium = kLogger::LS_AUTOMATIC)
{
$this->_logger->delete($unique_id, $storage_medium);
}
/**
* Returns the client IP address.
*
* @return string The client IP address
* @access public
*/
public function getClientIp()
{
return $this->HttpQuery->getClientIp();
}
}
Index: branches/5.2.x/core/kernel/processors/main_processor.php
===================================================================
--- branches/5.2.x/core/kernel/processors/main_processor.php (revision 16433)
+++ branches/5.2.x/core/kernel/processors/main_processor.php (revision 16434)
@@ -1,1316 +1,1293 @@
Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set('t', $this->Application->GetVar('t'));
$actions->Set('sid', $this->Application->GetSID());
$actions->Set('m_opener', $this->Application->GetVar('m_opener') );
}
/**
* Base folder for all template includes
*
* @param Array $params
* @return string
*/
function TemplatesBase($params)
{
static $cached = Array ();
$cache_key = crc32( serialize($params) );
if (!array_key_exists($cache_key, $cached)) {
$module = array_key_exists('module', $params) ? $params['module'] : 'core';
if ($this->Application->isAdmin) {
if ($module == 'in-portal') {
$module = 'kernel';
}
// remove leading slash + substitute module
$module_path = $this->Application->findModule('Name', $module, 'Path');
if ($module_path !== false) {
$path = $module_path . 'admin_templates';
}
else {
// remove leading slash + substitute module
$path = preg_replace('/\/(.*?)\/(.*)/', $module . '/\\2', THEMES_PATH);
}
}
else {
$path = mb_substr(THEMES_PATH, 1);
if (mb_strtolower($module) == 'in-portal') {
$module_folder = 'platform';
}
else {
$module_folder = $this->Application->findModule('Name', $module, 'TemplatePath');
}
$path .= rtrim('/' . trim($module_folder, '/'), '/') . '/';
}
$cached[$cache_key] = $this->Application->BaseURL() . $path;
}
return $cached[$cache_key];
}
/**
* Creates
";
}
else
echo "Object $name does not exist in the appliaction
";
}*/
/**
* Tag, that always returns true.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function True($params)
{
return true;
}
/**
* Tag, that always returns false.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function False($params)
{
return false;
}
/**
* Returns block parameter by name (used only as "check" parameter value for "m_if" tag!)
*
* @param Array $params
* @return stirng
* @access public
*/
function Param($params)
{
$name = $params['name'];
if (array_key_exists($name, $this->Application->Parser->Captures)) {
$capture_params = $params;
$capture_params['name'] = '__capture_' . $name;
$this->Application->Parser->SetParam($name, $this->Application->ParseBlock($capture_params));
}
$res = $this->Application->Parser->GetParam($name);
if ($res === false) {
$res = '';
}
if (array_key_exists('plus', $params)) {
$res += $params['plus'];
}
return $res;
}
/**
* Compares block parameter with value specified
*
* @param Array $params
* @return bool
* @access public
*/
function ParamEquals($params)
{
$name = $this->SelectParam($params, 'name,var,param');
$value = $params['value'];
return ($this->Application->Parser->GetParam($name) == $value);
}
/*function PHP_Self($params)
{
return $HTTP_SERVER_VARS['PHP_SELF'];
}
*/
/**
* Returns session variable value by name
*
* @param Array $params
* @return string
* @access public
*/
function Recall($params)
{
$var_name = $this->SelectParam($params,'name,var,param');
if (isset($params['persistent']) && $params['persistent']) {
$ret = $this->Application->RecallPersistentVar($var_name);
}
else {
$ret = $this->Application->RecallVar($var_name);
}
$ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) {
$ret = kUtil::escape($ret, kUtil::ESCAPE_HTML);
}
if (getArrayValue($params, 'urlencode')) {
$ret = kUtil::escape($ret, kUtil::ESCAPE_URL);
}
return $ret;
}
function RemoveVar($params)
{
$this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') );
}
// bad style to store something from template to session !!! (by Alex)
// Used here only to test how session works, nothing more
function Store($params)
{
//echo"Store $params[name]
";
$name = $params['name'];
$value = $params['value'];
$this->Application->StoreVar($name,$value);
}
/**
* Links variable from request with variable from session
*
* @param Array $params
* @return string
* @access protected
*/
protected function LinkVar($params)
{
$var_name = $params['name'];
$session_var_name = isset($params['session_name']) ? $params['session_name'] : $var_name;
$default_value = isset($params['default']) ? $params['default'] : '';
$this->Application->LinkVar($var_name, $session_var_name, $default_value);
return '';
}
/**
* Links variable from request with variable from session and returns it's value
*
* @param Array $params
* @return string
* @access protected
*/
protected function GetLinkedVar($params)
{
$this->LinkVar($params);
return $this->Application->GetVar( $params['name'] );
}
/**
* Sets application variable value(-s)
*
* @param Array $params
* @access public
*/
function Set($params)
{
foreach ($params as $param => $value) {
$this->Application->SetVar($param, $value);
}
}
/**
* Increment application variable
* specified by number specified
*
* @param Array $params
* @access public
*/
function Inc($params)
{
$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
}
/**
* Retrieves application variable
* value by name
*
* @param Array $params
* @return string
* @access public
*/
function Get($params)
{
$name = $this->SelectParam($params, 'name,var,param');
if ( strpos($name, '[') !== false ) {
preg_match('/([^\[\]]+)\[(.*)\]/', $name, $regs);
$function_params = explode('][', $regs[2]);
$ret = $this->Application->GetVar($regs[1], array());
kUtil::array_unshift_ref($function_params, $ret);
$ret = call_user_func_array('getArrayValue', $function_params);
}
else {
$ret = $this->Application->GetVar($name, '');
}
if ( array_key_exists('no_html_escape', $params) && $params['no_html_escape'] ) {
return $this->Application->isAdmin ? $ret : kUtil::unescape($ret, kUtil::ESCAPE_HTML);
}
return kUtil::escape($ret, kUtil::ESCAPE_HTML);
}
/**
* Retrieves application constant
* value by name
*
* @param Array $params
* @return string
* @access public
*/
function GetConst($params)
{
$constant_name = $this->SelectParam($params, 'name,const');
return defined($constant_name) ? constant($constant_name) : '';
}
/**
* Retrieves configuration variable value by name
*
* @param Array $params
* @return string
* @access public
*/
function GetConfig($params)
{
$config_name = $this->SelectParam($params, 'name,var');
$ret = $this->Application->ConfigValue($config_name);
if ( isset($params['formatted']) && $params['formatted'] ) {
$sql = 'SELECT ValueList
FROM ' . TABLE_PREFIX . 'SystemSettings
WHERE VariableName = ' . $this->Conn->qstr($config_name) . ' AND ElementType IN ("select", "radio")';
$value_list = $this->Conn->GetOne($sql);
if ( $value_list ) {
$helper = $this->Application->recallObject('InpCustomFieldsHelper');
/* @var $helper InpCustomFieldsHelper */
$options = $helper->GetValuesHash($value_list);
$ret = isset($options[$ret]) ? $options[$ret] : $ret;
}
}
if ( isset($params['as_label']) && $params['as_label'] ) {
$ret = $this->Application->Phrase($ret);
}
return $ret;
}
/**
* Compares configuration variable to a given value
*
* @param Array $params
* @return bool
* @deprecated
* @access protected
*/
protected function ConfigEquals($params)
{
$option = $this->SelectParam($params, 'name,option,var');
return $this->Application->ConfigValue($option) == $params['value'];
}
/**
* Creates all hidden fields
* needed for kernel_form
*
* @param Array $params
* @return string
* @access protected
*/
protected function DumpSystemInfo($params)
{
$actions = $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set('t', $this->Application->GetVar('t'));
$o = '';
$params = $actions->GetParams();
foreach ($params AS $name => $val) {
$o .= "\n";
}
return $o;
}
/**
* Used for search sidebox on front-end only
*
* @param Array $params
* @return string
* @access protected
*/
protected function GetFormHiddens($params)
{
$t = $this->SelectParam($params, 'template,t');
unset($params['template']);
$form_fields = Array ();
if ( $this->Application->RewriteURLs() ) {
$session = $this->Application->recallObject('Session');
/* @var $session Session */
if ( $session->NeedQueryString() ) {
$form_fields['sid'] = $this->Application->GetSID();
}
}
else {
$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', false, false);
}
if ( $this->Application->GetVar('admin') == 1 ) {
$form_fields['admin'] = 1;
}
$ret = '';
$field_tpl = '' . "\n";
foreach ($form_fields as $form_field => $field_value) {
$ret .= sprintf($field_tpl, $form_field, $field_value);
}
return $ret;
}
function Odd_Even($params)
{
$odd = $params['odd'];
$even = $params['even'];
if (!isset($params['var'])) {
$var = 'odd_even';
}
else {
$var = $params['var'];
}
if ($this->Application->GetVar($var) == 'even') {
if (!isset($params['readonly']) || !$params['readonly']) {
$this->Application->SetVar($var, 'odd');
}
return $even;
}
else {
if (!isset($params['readonly']) || !$params['readonly']) {
$this->Application->SetVar($var, 'even');
}
return $odd;
}
}
/**
* Returns phrase translation by name
*
* @param Array $params
* @return string
* @access public
*/
function Phrase($params)
{
$phrase_name = $this->SelectParam($params, 'label,name,title');
$default_translation = $this->SelectParam($params, 'default');
$no_editing = isset($params['no_editing']) && $params['no_editing'];
$translation = $this->Application->Phrase($phrase_name, !$no_editing);
$phrase_key = mb_strtoupper($phrase_name);
if ( $default_translation && strpos($translation, '!' . $phrase_key . '!') !== false ) {
$phrase = $this->Application->recallObject('phrases.autocreate', null, Array ('skip_autoload' => true));
/* @var $phrase kDBItem */
if ( !$phrase->Load($phrase_key, 'PhraseKey') ) {
$phrase->SetDBField('Phrase', $phrase_name);
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$languages = $ml_helper->getLanguages();
foreach ($languages AS $language_id) {
$phrase->SetDBField('l' . $language_id . '_Translation', $default_translation);
}
if ( $phrase->Create() ) {
$translation = $default_translation;
}
}
}
if ( isset($params['escape']) && $params['escape'] ) {
// html escaping here is redundant
$translation = kUtil::escape($translation, kUtil::ESCAPE_JS);
}
return $translation;
}
// for tabs
function is_active($params)
{
$test_templ = $this->SelectParam($params, 'templ,template,t');
if ( !getArrayValue($params, 'allow_empty') ) {
$if_true = getArrayValue($params, 'true') ? $params['true'] : 1;
$if_false = getArrayValue($params, 'false') ? $params['false'] : 0;
}
else {
$if_true = $params['true'];
$if_false = $params['false'];
}
$physical_template = $this->Application->getPhysicalTemplate($this->Application->GetVar('t'));
return preg_match('/^' . str_replace('/', '\/', $test_templ) . '/i', $physical_template) ? $if_true : $if_false;
}
function IsNotActive($params)
{
return !$this->is_active($params);
}
function IsActive($params)
{
return $this->is_active($params);
}
function is_t_active($params)
{
return $this->is_active($params);
}
function CurrentTemplate($params)
{
return $this->is_active($params);
}
/**
* Checks if session variable
* specified by name value match
* value passed as parameter
*
* @param Array $params
* @return string
* @access public
*/
function RecallEquals($params)
{
$name = $this->SelectParam($params, 'name,var');
$value = $params['value'];
if (isset($params['persistent']) && $params['persistent']) {
return $this->Application->RecallPersistentVar($name) == $value;
}
return ($this->Application->RecallVar($name) == $value);
}
/**
* Checks if application variable specified by name value match value passed as parameter
*
* @param Array $params
* @return bool
* @access protected
* @deprecated
*/
protected function GetEquals($params)
{
$name = $this->SelectParam($params, 'var,name,param');
return $this->Application->GetVar($name) == $params['value'];
}
function ModuleInclude($params)
{
$ret = '';
$included = Array ();
$block_params = array_merge($params, Array ('is_silent' => 2)); // don't make fatal errors in case if template is missing
$current_template = $this->Application->GetVar('t');
$replace_main = isset($params['replace_m']) && $params['replace_m'];
$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array ();
$cms_mode = $this->Application->GetVar('admin');
foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
$module_key = mb_strtolower($module_name);
if ( $module_name == 'In-Portal' ) {
if ( !$cms_mode && $this->Application->isAdmin ) {
// don't process In-Portal templates in admin
continue;
}
// Front-End still relies on In-Portal module
$module_prefix = $module_data['TemplatePath'];
}
elseif ( $this->Application->isAdmin && $module_data['Path'] != 'core/' ) {
$module_prefix = $module_key . '/'; // was $module_data['Path'];
}
else {
$module_prefix = $module_data['TemplatePath']; // always have trailing "/"
}
if ( in_array($module_prefix, $included) ) {
// template by this path was already included by other module (e.g. in-portal used core's template)
continue;
}
$block_params['t'] = $module_prefix . $this->SelectParam($params, $module_key . '_template,' . $module_key . '_t,template,t');
$check_prefix = $module_data['Var'];
if ( $check_prefix == 'adm' && $replace_main ) {
$check_prefix = 'c';
}
if ( $block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes) ) {
continue;
}
$no_data = $this->SelectParam($params, $module_key . '_block_no_data,block_no_data');
if ( $no_data ) {
$block_params['block_no_data'] = $module_prefix . '/' . $no_data;
}
$ret .= $this->Application->IncludeTemplate($block_params);
$included[] = $module_prefix;
}
return $ret;
}
function ModuleEnabled($params)
{
return $this->Application->isModuleEnabled( $params['module'] );
}
/**
* Checks if debug mode is on
*
* @param Array $params
* @return bool
* @access public
*/
function IsDebugMode($params)
{
return defined('DEBUG_MODE') && $this->Application->isDebugMode();
}
/*function MassParse($params)
{
$qty = $params['qty'];
$block = $params['block'];
$mode = $params['mode'];
$o = '';
if ($mode == 'func') {
$func = create_function('$params', '
$o = \'
' . implode("\n", $current_params) . ''; } /** * Gets previously defined counter result * * @param Array $params * @return int */ function GetCounter($params) { return $this->Application->getCounter($params['name'], $params); } /** * Increments PageHit counter * * @param Array $params * @return int */ function RegisterPageHit($params) { if ($this->Application->ConfigValue('UsePageHitCounter')) { // get current counte $sql = 'SELECT VariableValue FROM '.TABLE_PREFIX.'SystemSettings WHERE VariableName = "PageHitCounter"'; $page_counter = (int)$this->Conn->GetOne($sql); $sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'SystemSettings SET VariableValue = '.($page_counter + 1).' WHERE VariableName = "PageHitCounter"'; $this->Conn->Query($sql); } } function Timestamp($params) { $format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s'; return adodb_date($format); } function GetUrlHiddenFileds($params) { $vars = Array ('page', 'per_page', 'sort_by'); $ret = ''; if (array_key_exists('skip', $params)) { $vars = array_diff($vars, $params['skip']); } foreach ($vars as $var_name) { $var_value = $this->Application->GetVar($var_name); if ($var_value) { $ret .= ''; } } return $ret; } /** * Returns current Page URL (without re-assembling it). * "skip_query" param is optional and will remove the ?QUERY part from the result. * * @param Array $params * @return string * @access protected */ protected function CurrentPageLink($params) { if ( isset($params['skip_query']) && $params['skip_query'] ) { return preg_replace('/\?' . preg_quote($_SERVER['QUERY_STRING'], '/') . '$/', '', $_SERVER['REQUEST_URI']); } return $_SERVER['REQUEST_URI']; } /** * Returns current maintenance mode state * * @param Array $params * @return int * @access protected */ protected function MaintenanceMode($params) { $check_ips = isset($params['check_ips']) ? $params['check_ips'] : true; return $this->Application->getMaintenanceMode($check_ips); } /** * Checks if element with given name is defined * * @param Array $params * @return int * @access protected */ protected function ElementDefined($params) { return $this->Application->Parser->blockFound($params['name']); } } Index: branches/5.2.x/core/kernel/utility/http_query.php =================================================================== --- branches/5.2.x/core/kernel/utility/http_query.php (revision 16433) +++ branches/5.2.x/core/kernel/utility/http_query.php (revision 16434) @@ -1,818 +1,808 @@ Order = $order; if ( isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { // when AJAX request is made from jQuery, then create ajax variable, // so any logic based in it (like redirects) will not break down $_GET['ajax'] = 'yes'; } $vars = kUtil::getConfigVars(); $this->_trustProxy = isset($vars['TrustProxy']) ? (bool)$vars['TrustProxy'] : false; } /** * Discovers unit form request and returns it's QueryString option on success * * @param string $prefix_special * * @return Array|bool * @access public */ public function discoverUnit($prefix_special) { list($prefix) = explode('.', $prefix_special); $query_string = $this->getQueryString($prefix); if ($query_string) { // only units with QueryString option can be discovered $this->discoveredUnits[$prefix_special] = $query_string; return $query_string; } unset( $this->discoveredUnits[$prefix] ); return false; } /** * Returns units, passed in request * * @param bool $prefix_special_only * @return Array * @access protected */ public function getDiscoveredUnits($prefix_special_only = true) { return $prefix_special_only ? array_keys( $this->discoveredUnits ) : $this->discoveredUnits; } /** * Returns QueryMap for requested unit config. * In case if unit config is a clone, then get parent item's (from prefix) config to create clone * * @param string $prefix * @return Array * @access protected */ protected function getQueryString($prefix) { $ret = $this->Application->getUnitOption($prefix, 'QueryString', Array ()); if ( !$ret && preg_match('/(.*?)-(.*)/', $prefix, $regs) ) { // "#prefix" (new format), "prefix" (old format) return $this->_getQueryString('#' . $regs[2]); } return $ret; } /** * Returns query string (with safety check against missing prefixes) * * @param string $prefix * @return Array */ private function _getQueryString($prefix) { if ( $this->Application->prefixRegistred($prefix) ) { return $this->Application->getUnitOption($prefix, 'QueryString'); } return substr($prefix, 0, 1) == '#' ? $this->_getQueryString( substr($prefix, 1) ) : Array (); } /** * Removes specials from request * * @param Array $array * @return Array * @access protected */ protected function _removeSpecials($array) { $ret = Array (); $removed = false; foreach ($this->specialsToRemove as $prefix_special => $flag) { if ( $flag ) { $removed = true; list ($prefix, $special) = explode('.', $prefix_special, 2); foreach ($array as $key => $val) { $new_key = preg_match("/^" . $prefix . "[._]{1}" . $special . "(.*)/", $key, $regs) ? $prefix . $regs[1] : $key; $ret[$new_key] = is_array($val) ? $this->_removeSpecials($val) : $val; } } } return $removed ? $ret : $array; } public function process() { $this->AddAllVars(); $this->removeSpecials(); ini_set('magic_quotes_gpc', 0); $this->Application->UrlManager->LoadStructureTemplateMapping(); $this->AfterInit(); } /** * All all requested vars to * common storage place * * @return void * @access protected */ protected function AddAllVars() { for ($i = 0; $i < strlen($this->Order); $i++) { switch ($this->Order[$i]) { case 'G': $this->Get = $this->AddVars($_GET); if ( array_key_exists('sid', $_GET) ) { $this->_sidInQueryString = true; } $vars = $this->Application->processQueryString($this->Get(ENV_VAR_NAME)); if ( array_key_exists('sid', $vars) ) { // used by Session::GetPassedSIDValue $this->Get['sid'] = $vars['sid']; } $this->AddParams($vars); break; case 'P': $this->Post = $this->AddVars($_POST); $this->convertPostEvents(); $this->_processPostEnvVariables(); break; case 'C': $this->Cookie = $this->AddVars($_COOKIE); break; /*case 'E'; $this->Env = $this->AddVars($_ENV, false); //do not strip slashes! break; case 'S'; $this->Server = $this->AddVars($_SERVER, false); //do not strip slashes! break;*/ case 'F'; $this->convertFiles(); $this->Files = $this->MergeVars($_FILES); // , false); //do not strip slashes! break; } } } /** * Allow POST variables, that names were transformed by PHP ("." replaced with "_") to * override variables, that were virtually created through environment variable parsing * */ function _processPostEnvVariables() { $passed = $this->Get('passed'); if ( !$passed ) { return; } $passed = explode(',', $passed); foreach ($passed as $prefix_special) { if ( strpos($prefix_special, '.') === false ) { continue; } list ($prefix, $special) = explode('.', $prefix_special); $query_map = $this->getQueryString($prefix); $post_prefix_special = $prefix . '_' . $special; foreach ($query_map as $var_name) { if ( array_key_exists($post_prefix_special . '_' . $var_name, $this->Post) ) { $this->Set($prefix_special . '_' . $var_name, $this->Post[$post_prefix_special . '_' . $var_name]); } } } } /** * Removes requested specials from all request variables * * @return void * @access protected */ protected function removeSpecials() { $this->specialsToRemove = $this->Get('remove_specials'); if ( $this->specialsToRemove ) { foreach ($this->specialsToRemove as $prefix_special => $flag) { if ( $flag && strpos($prefix_special, '.') === false ) { unset($this->specialsToRemove[$prefix_special]); trigger_error('Incorrect usage of "remove_specials[' . $prefix_special . ']" field (no special found)', E_USER_NOTICE); } } $this->_Params = $this->_removeSpecials($this->_Params); } } /** * Finishes initialization of kHTTPQuery class * * @return void * @access protected * @todo: only uses build-in rewrite listeners, when cache is build for the first time */ protected function AfterInit() { $rewrite_url = $this->Get('_mod_rw_url_'); if ( $this->Application->RewriteURLs() || $rewrite_url ) { // maybe call onafterconfigread here $this->Application->UrlManager->initRewrite(); if ( defined('DEBUG_MODE') && $this->Application->isDebugMode() ) { $this->Application->Debugger->profileStart('url_parsing', 'Parsing MOD_REWRITE url'); $this->Application->UrlManager->rewrite->parseRewriteURL(); $description = 'Parsing MOD_REWRITE url (template: ' . $this->Get('t') . ')'; $this->Application->Debugger->profileFinish('url_parsing', $description); } else { $this->Application->UrlManager->rewrite->parseRewriteURL(); } if ( !$rewrite_url && $this->rewriteRedirectRequired() ) { // rewrite url is missing (e.g. not a script from tools folder) $url_params = $this->getRedirectParams(); // no idea about how to check, that given template require category to be passed with it, so pass anyway $url_params['pass_category'] = 1; $url_params['response_code'] = 301; // Moved Permanently trigger_error('Non mod-rewrite url "' . $_SERVER['REQUEST_URI'] . '" used', E_USER_NOTICE); $this->Application->Redirect('', $url_params); } } else { $this->Application->VerifyThemeId(); $this->Application->VerifyLanguageId(); } $virtual_template = $this->Application->getVirtualPageTemplate($this->Get('m_cat_id')); if ( ($virtual_template !== false) && preg_match('/external:(.*)/', $virtual_template) ) { trigger_error('URL of page, that has "External URL" set was accessed: "' . $_SERVER['REQUEST_URI'] . '"', E_USER_NOTICE); $this->Application->Redirect($virtual_template); } } /** * Checks, that non-rewrite url was visited and it's automatic rewrite is required * * @return bool */ function rewriteRedirectRequired() { $redirect_conditions = Array ( !$this->IsHTTPSRedirect(), // not https <-> http redirect !$this->refererIsOurSite(), // referer doesn't match ssl path or non-ssl domain (same for site domains) !defined('GW_NOTIFY'), // not in payment gateway notification script preg_match('/[\/]{0,1}index.php[\/]{0,1}/', $_SERVER['PHP_SELF']), // "index.php" was visited $this->Get('t') != 'index', // not on index page ); $perform_redirect = true; foreach ($redirect_conditions as $redirect_condition) { $perform_redirect = $perform_redirect && $redirect_condition; if (!$perform_redirect) { return false; } } return true; } /** * This is redirect from https to http or via versa * * @return bool */ function IsHTTPSRedirect() { $http_referer = array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : false; return ( ( PROTOCOL == 'https://' && preg_match('#http:\/\/#', $http_referer) ) || ( PROTOCOL == 'http://' && preg_match('#https:\/\/#', $http_referer) ) ); } /** * Checks, that referer is out site * * @return bool */ function refererIsOurSite() { if ( !array_key_exists('HTTP_REFERER', $_SERVER) ) { // no referer -> don't care what happens return false; } $site_helper = $this->Application->recallObject('SiteHelper'); /* @var $site_helper SiteHelper */ $found = false; $http_referer = $_SERVER['HTTP_REFERER']; preg_match('/^(.*?):\/\/(.*?)(\/|$)/', $http_referer, $regs); // 1 - protocol, 2 - domain if ($regs[1] == 'https') { $found = $site_helper->getDomainByName('SSLUrl', $http_referer) > 0; if (!$found) { // check if referer starts with our ssl url $ssl_url = $this->Application->ConfigValue('SSL_URL'); $found = $ssl_url && preg_match('/^' . preg_quote($ssl_url, '/') . '/', $http_referer); } } else { $found = $site_helper->getDomainByName('DomainName', $regs[2]) > 0; if (!$found) { $found = $regs[2] == DOMAIN; } } return $found; } function convertFiles() { if ( !$_FILES ) { return ; } $tmp = Array (); $file_keys = Array ('error', 'name', 'size', 'tmp_name', 'type'); foreach ($_FILES as $file_name => $file_info) { if ( is_array($file_info['error']) ) { $tmp[$file_name] = $this->getArrayLevel($file_info['error'], $file_name); } else { $normal_files[$file_name] = $file_info; } } if ( !$tmp ) { return ; } $files = $_FILES; $_FILES = Array (); foreach ($tmp as $prefix => $prefix_files) { $anchor =& $_FILES; foreach ($prefix_files['keys'] as $key) { $anchor =& $anchor[$key]; } foreach ($prefix_files['value'] as $field_name) { unset($inner_anchor, $copy); $work_copy = $prefix_files['keys']; foreach ($file_keys as $file_key) { $inner_anchor =& $files[$prefix][$file_key]; if ( isset($copy) ) { $work_copy = $copy; } else { $copy = $work_copy; } array_shift($work_copy); foreach ($work_copy as $prefix_file_key) { $inner_anchor =& $inner_anchor[$prefix_file_key]; } $anchor[$field_name][$file_key] = $inner_anchor[$field_name]; } } } // keys: img_temp, 0, values: LocalPath, ThumbPath } function getArrayLevel(&$level, $prefix='') { $ret['keys'] = $prefix ? Array($prefix) : Array(); $ret['value'] = Array(); foreach($level as $level_key => $level_value) { if( is_array($level_value) ) { $ret['keys'][] = $level_key; $tmp = $this->getArrayLevel($level_value); $ret['keys'] = array_merge($ret['keys'], $tmp['keys']); $ret['value'] = array_merge($ret['value'], $tmp['value']); } else { $ret['value'][] = $level_key; } } return $ret; } /** * Overwrites GET events with POST events in case if they are set and not empty * * @return void * @access protected */ protected function convertPostEvents() { $events = $this->Get('events', Array ()); /* @var $events Array */ if ( is_array($events) ) { $events = array_filter($events); foreach ($events as $prefix_special => $event_name) { $this->Set($prefix_special . '_event', $event_name); } } } function finalizeParsing($passed = Array()) { if (!$passed) { return; } foreach ($passed as $passed_prefix) { $this->discoverUnit($passed_prefix); // from mod-rewrite url parsing } $this->Set('passed', implode(',', $this->getDiscoveredUnits())); } /** * Saves variables from array specified * into common variable storage place * * @param Array $array * @param bool $strip_slashes * @return Array * @access private */ function AddVars($array, $strip_slashes = true) { if ( $strip_slashes ) { $array = $this->StripSlashes($array); } foreach ($array as $key => $value) { $this->Set($key, $value); } return $array; } function MergeVars($array, $strip_slashes = true) { if ( $strip_slashes ) { $array = $this->StripSlashes($array); } foreach ($array as $key => $value_array) { // $value_array is an array too $this->_Params = kUtil::array_merge_recursive($this->_Params, Array ($key => $value_array)); } return $array; } function StripSlashes($array) { static $magic_quotes = null; if (!isset($magic_quotes)) { $magic_quotes = get_magic_quotes_gpc(); } foreach ($array as $key => $value) { if (is_array($value)) { $array[$key] = $this->StripSlashes($value); } else { if ($magic_quotes) { $value = stripslashes($value); } if (!$this->Application->isAdmin) { // TODO: always escape output instead of input $value = kUtil::escape($value, kUtil::ESCAPE_HTML); } $array[$key] = $value; } } return $array; } /** * Removes forceful escaping done to the variable upon Front-End submission. * * @param string|array $value Value. * * @return string|array * @see StripSlashes */ public function unescapeRequestVariable($value) { if ( $this->Application->isAdmin ) { return $value; } // This allows to revert kUtil::escape() call for each field submitted on front-end. if ( is_array($value) ) { foreach ( $value as $param_name => $param_value ) { $value[$param_name] = $this->unescapeRequestVariable($param_value); } return $value; } return kUtil::unescape($value, kUtil::ESCAPE_HTML); } /** * Returns all $_GET array excluding system parameters, that are not allowed to be passed through generated urls * * @param bool $access_error Method is called during no_permission, require login, session expiration link preparation * @return Array */ function getRedirectParams($access_error = false) { $vars = $this->Get; $unset_vars = Array (ENV_VAR_NAME, 'rewrite', '_mod_rw_url_', 'Action'); if (!$this->_sidInQueryString) { $unset_vars[] = 'sid'; } // remove system variables foreach ($unset_vars as $var_name) { if (array_key_exists($var_name, $vars)) { unset($vars[$var_name]); } } if ($access_error) { // place 1 of 2 (also in UsersEventHandler::OnSessionExpire) $vars = $this->_removePassThroughVariables($vars); } return $vars; } /** * Removes all pass_though variables from redirect params * * @param Array $url_params * @return Array */ function _removePassThroughVariables($url_params) { $pass_through = array_key_exists('pass_through', $url_params) ? $url_params['pass_through'] : ''; if (!$pass_through) { return $url_params; } $pass_through = explode(',', $pass_through . ',pass_through'); foreach ($pass_through as $pass_through_var) { unset($url_params[$pass_through_var]); } $url_params['no_pass_through'] = 1; // this way kApplication::HREF won't add them again return $url_params; } - function writeRequestLog($filename) - { - $log_file = (defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/' . $filename; - - if ( is_writable(dirname($log_file)) ) { - $fp = fopen($log_file, 'a'); - - if ( $fp ) { - $session = $this->Application->recallObject('Session'); - /* @var $session Session */ - - $user_id = $session->GetField('PortalUserId'); - $admin_mark = $this->Application->isAdmin ? 'ADMIN' : 'FRONT'; - - $data = '[' . date('D M d H:i:s Y') . '] ' . $admin_mark . '; ip: ' . $this->getClientIp() . '; user_id: ' . $user_id . '; sid: ' . $this->Application->GetSID() . '; request: ' . "\n"; - if ( $this->Get ) { - $data .= "_GET:\n" . print_r($this->Get, true); - } - - if ( $this->Post ) { - $data .= "_POST:\n" . print_r($this->Post, true); - } - - if ( $this->Cookie ) { - $data .= "_COOKIE:\n" . print_r($this->Cookie, true); - } - $data .= str_repeat('=', 100) . "\n"; - - fwrite($fp, $data); - fclose($fp); - } - else { - trigger_error('Request Log directory not writable', E_USER_WARNING); - } - } - else { - trigger_error('Request Log directory not writable', E_USER_WARNING); - } - } - /** * Checks, that url is empty * * @return bool * @access public */ public function isEmptyUrl() { if ( $this->Application->RewriteURLs() ) { return !$this->Get('_mod_rw_url_'); } return !count($this->Get); } /** * Returns the client IP address. * * @return string The client IP address * @access public */ public function getClientIp() { if ( $this->_trustProxy ) { if ( array_key_exists('HTTP_CLIENT_IP', $_SERVER) ) { return $_SERVER['HTTP_CLIENT_IP']; } if ( array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) ) { $client_ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); foreach ($client_ip as $ip_address) { $clean_ip_address = trim($ip_address); if ( false !== filter_var($clean_ip_address, FILTER_VALIDATE_IP) ) { return $clean_ip_address; } } return ''; } } return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; } + + /** + * Returns headers + * + * @return array + * @access public + */ + public function getHeaders() + { + if ( function_exists('apache_request_headers') ) { + // If apache_request_headers() exists... + $headers = apache_request_headers(); + + if ( $headers ) { + return $headers; // And works... Use it + } + } + + $headers = array(); + + foreach ( array_keys($_SERVER) as $server_key ) { + if ( substr($server_key, 0, 5) == 'HTTP_' ) { + $header_name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($server_key, 0, 5))))); + $headers[$header_name] = $_SERVER[$server_key]; + } + } + + return $headers; + } + } Index: branches/5.2.x/core/kernel/utility/logger.php =================================================================== --- branches/5.2.x/core/kernel/utility/logger.php (revision 16433) +++ branches/5.2.x/core/kernel/utility/logger.php (revision 16434) @@ -1,1401 +1,1404 @@ _debugMode = $this->Application->isDebugMode(); $this->setState(isset($vars['EnableSystemLog']) ? $vars['EnableSystemLog'] : self::STATE_DISABLED); $this->_maxLogLevel = isset($vars['SystemLogMaxLevel']) ? (int)$vars['SystemLogMaxLevel'] : self::LL_NOTICE; foreach ($methods_to_call as $method_to_call) { call_user_func_array(Array ($this, $method_to_call[0]), $method_to_call[1]); } if ( !kUtil::constOn('DBG_ZEND_PRESENT') && !$this->Application->isDebugMode() ) { // don't report error on screen if debug mode is turned off error_reporting(0); ini_set('display_errors', 0); } register_shutdown_function(Array ($this, 'catchLastError')); } /** * Sets state of the logged (enabled/user-only/disabled) * * @param $new_state * @return void * @access public */ public function setState($new_state = null) { if ( isset($new_state) ) { $this->_state = (int)$new_state; } if ( $this->_state === self::STATE_ENABLED ) { $this->_enableErrorHandling(); } elseif ( $this->_state === self::STATE_DISABLED ) { $this->_disableErrorHandling(); } } /** * Enable error/exception handling capabilities * * @return void * @access protected */ protected function _enableErrorHandling() { $this->_disableErrorHandling(); $this->_handlers[self::LL_ERROR] = new kErrorHandlerStack($this); $this->_handlers[self::LL_CRITICAL] = new kExceptionHandlerStack($this); } /** * Disables error/exception handling capabilities * * @return void * @access protected */ protected function _disableErrorHandling() { foreach ($this->_handlers as $index => $handler) { $this->_handlers[$index]->__destruct(); unset($this->_handlers[$index]); } } /** * Initializes new log record. Use "kLogger::write" to save to db/disk * * @param string $message * @param int $code * @return kLogger * @access public */ public function prepare($message = '', $code = null) { $this->_logRecord = Array ( 'LogUniqueId' => kUtil::generateId(), 'LogMessage' => $message, 'LogLevel' => self::LL_INFO, 'LogCode' => $code, 'LogType' => self::LT_OTHER, 'LogHostname' => $_SERVER['HTTP_HOST'], 'LogRequestSource' => php_sapi_name() == 'cli' ? 2 : 1, 'LogRequestURI' => php_sapi_name() == 'cli' ? implode(' ', $GLOBALS['argv']) : $_SERVER['REQUEST_URI'], 'LogUserId' => USER_GUEST, 'IpAddress' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', 'LogSessionKey' => 0, 'LogProcessId' => getmypid(), 'LogUserData' => '', 'LogNotificationStatus' => self::LNS_DISABLED, ); if ( $this->Application->isAdmin ) { $this->_logRecord['LogInterface'] = defined('CRON') && CRON ? self::LI_CRON_ADMIN : self::LI_ADMIN; } else { $this->_logRecord['LogInterface'] = defined('CRON') && CRON ? self::LI_CRON_FRONT : self::LI_FRONT; } if ( $this->Application->InitDone ) { $this->_logRecord['LogUserId'] = $this->Application->RecallVar('user_id'); $this->_logRecord['LogSessionKey'] = $this->Application->GetSID(); $this->_logRecord['IpAddress'] = $this->Application->getClientIp(); } return $this; } /** * Sets one or more fields of log record * * @param string|Array $field_name * @param string|null $field_value * @return kLogger * @access public * @throws UnexpectedValueException */ public function setLogField($field_name, $field_value = null) { if ( isset($field_value) ) { $this->_logRecord[$field_name] = $field_value; } elseif ( is_array($field_name) ) { $this->_logRecord = array_merge($this->_logRecord, $field_name); } else { throw new UnexpectedValueException('Invalid arguments'); } return $this; } /** * Sets user data * * @param string $data * @param bool $as_array * @return kLogger * @access public */ public function setUserData($data, $as_array = false) { if ( $as_array ) { $data = serialize((array)$data); } return $this->setLogField('LogUserData', $data); } /** * Add user data * * @param string $data * @param bool $as_array * @return kLogger * @access public */ public function addUserData($data, $as_array = false) { $new_data = $this->_logRecord['LogUserData']; if ( $as_array ) { $new_data = $new_data ? unserialize($new_data) : Array (); $new_data[] = $data; $new_data = serialize($new_data); } else { $new_data .= ($new_data ? PHP_EOL : '') . $data; } return $this->setLogField('LogUserData', $new_data); } /** * Adds event to log record * * @param kEvent $event * @return kLogger * @access public */ public function addEvent(kEvent $event) { $this->_logRecord['LogEventName'] = (string)$event; return $this; } /** * Adds log source file & file to log record * * @param string|Array $file_or_trace file path * @param int $line file line * @return kLogger * @access public */ public function addSource($file_or_trace = '', $line = 0) { if ( is_array($file_or_trace) ) { $trace_info = $file_or_trace[0]; $this->_logRecord['LogSourceFilename'] = $trace_info['file']; $this->_logRecord['LogSourceFileLine'] = $trace_info['line']; } else { $this->_logRecord['LogSourceFilename'] = $file_or_trace; $this->_logRecord['LogSourceFileLine'] = $line; } return $this; } /** * Adds session contents to log record * * @param bool $include_optional Include optional session variables * @return kLogger * @access public */ public function addSessionData($include_optional = false) { if ( $this->Application->InitDone ) { $this->_logRecord['LogSessionData'] = serialize($this->Application->Session->getSessionData($include_optional)); } return $this; } /** * Adds user request information to log record * * @return kLogger * @access public */ public function addRequestData() { - $request_data = Array (); - $request_variables = Array ('_GET' => $_GET, '_POST' => $_POST, '_COOKIE' => $_COOKIE); + $request_data = array( + 'Headers' => $this->Application->HttpQuery->getHeaders(), + ); + + $request_variables = Array('_GET' => $_GET, '_POST' => $_POST, '_COOKIE' => $_COOKIE); - foreach ($request_variables as $title => $data) { + foreach ( $request_variables as $title => $data ) { if ( !$data ) { continue; } $request_data[$title] = $data; } $this->_logRecord['LogRequestData'] = serialize($request_data); return $this; } /** * Adds trace to log record * * @param Array $trace * @param int $skip_levels * @param Array $skip_files * @return kLogger * @access public */ public function addTrace($trace = null, $skip_levels = 1, $skip_files = null) { $trace = $this->createTrace($trace, $skip_levels, $skip_files); foreach ($trace as $trace_index => $trace_info) { if ( isset($trace_info['args']) ) { $trace[$trace_index]['args'] = $this->_implodeObjects($trace_info['args']); } } $this->_logRecord['LogBacktrace'] = serialize($this->_removeObjectsFromTrace($trace)); return $this; } /** * Remove objects from trace, since before PHP 5.2.5 there wasn't possible to remove them initially * * @param Array $trace * @return Array * @access protected */ protected function _removeObjectsFromTrace($trace) { if ( version_compare(PHP_VERSION, '5.3', '>=') ) { return $trace; } $trace_indexes = array_keys($trace); foreach ($trace_indexes as $trace_index) { unset($trace[$trace_index]['object']); } return $trace; } /** * Implodes object to prevent memory leaks * * @param Array $array * @return Array * @access protected */ protected function _implodeObjects($array) { $ret = Array (); foreach ($array as $key => $value) { if ( is_array($value) ) { $ret[$key] = $this->_implodeObjects($value); } elseif ( is_object($value) ) { if ( $value instanceof kEvent ) { $ret[$key] = 'Event: ' . (string)$value; } elseif ( $value instanceof kBase ) { $ret[$key] = (string)$value; } else { $ret[$key] = 'Class: ' . get_class($value); } } elseif ( strlen($value) > 200 ) { $ret[$key] = substr($value, 0, 50) . ' ...'; } else { $ret[$key] = $value; } } return $ret; } /** * Removes first N levels from trace * * @param Array $trace * @param int $levels * @param Array $files * @return Array * @access public */ public function createTrace($trace = null, $levels = null, $files = null) { if ( !isset($trace) ) { $trace = debug_backtrace(false); } if ( !$trace ) { // no trace information return $trace; } if ( isset($levels) && is_numeric($levels) ) { for ($i = 0; $i < $levels; $i++) { array_shift($trace); } } if ( isset($files) && is_array($files) ) { while (true) { $trace_info = $trace[0]; $file = isset($trace_info['file']) ? basename($trace_info['file']) : ''; if ( !in_array($file, $files) ) { break; } array_shift($trace); } } return $trace; } /** * Adds PHP error to log record * * @param int $errno * @param string $errstr * @param string $errfile * @param int $errline * @return kLogger * @access public */ public function addError($errno, $errstr, $errfile = null, $errline = null) { $errstr = self::expandMessage($errstr, !$this->_debugMode); $this->_logRecord['LogLevel'] = $this->_getLogLevelByErrorNo($errno); if ( $this->isLogType(self::LT_DATABASE, $errstr) ) { list ($errno, $errstr, $sql) = self::parseDatabaseError($errstr); $this->_logRecord['LogType'] = self::LT_DATABASE; $this->_logRecord['LogUserData'] = $sql; $trace = $this->createTrace(null, 4, $this->_ignoreInTrace); $this->addSource($trace); $this->addTrace($trace, 0); } else { $this->_logRecord['LogType'] = self::LT_PHP; $this->addSource((string)$errfile, $errline); $this->addTrace(null, 4); } $this->_logRecord['LogCode'] = $errno; $this->_logRecord['LogMessage'] = $errstr; return $this; } /** * Adds PHP exception to log record * * @param Exception $exception * @return kLogger * @access public */ public function addException($exception) { $errstr = self::expandMessage($exception->getMessage(), !$this->_debugMode); $this->_logRecord['LogLevel'] = self::LL_CRITICAL; $exception_trace = $exception->getTrace(); array_unshift($exception_trace, array( 'function' => '', 'file' => $exception->getFile() !== null ? $exception->getFile() : 'n/a', 'line' => $exception->getLine() !== null ? $exception->getLine() : 'n/a', 'args' => array(), )); if ( $this->isLogType(self::LT_DATABASE, $errstr) ) { list ($errno, $errstr, $sql) = self::parseDatabaseError($errstr); $this->_logRecord['LogType'] = self::LT_DATABASE; $this->_logRecord['LogUserData'] = $sql; $trace = $this->createTrace($exception_trace, null, $this->_ignoreInTrace); $this->addSource($trace); $this->addTrace($trace, 0); } else { $this->_logRecord['LogType'] = self::LT_PHP; $errno = $exception->getCode(); $this->addSource((string)$exception->getFile(), $exception->getLine()); $this->addTrace($exception_trace, 0); } $this->_logRecord['LogCode'] = $errno; $this->_logRecord['LogMessage'] = $errstr; return $this; } /** * Allows to map PHP error numbers to syslog log level * * @param int $errno * @return int * @access protected */ protected function _getLogLevelByErrorNo($errno) { $error_number_mapping = Array ( self::LL_ERROR => Array (E_RECOVERABLE_ERROR, E_USER_ERROR, E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE), self::LL_WARNING => Array (E_WARNING, E_USER_WARNING, E_CORE_WARNING, E_COMPILE_WARNING), self::LL_NOTICE => Array (E_NOTICE, E_USER_NOTICE, E_STRICT), ); if ( version_compare(PHP_VERSION, '5.3.0', '>=') ) { $error_number_mapping[self::LL_NOTICE][] = E_DEPRECATED; $error_number_mapping[self::LL_NOTICE][] = E_USER_DEPRECATED; } foreach ($error_number_mapping as $log_level => $error_numbers) { if ( in_array($errno, $error_numbers) ) { return $log_level; } } return self::LL_ERROR; } /** * Changes log level of a log record * * @param int $log_level * @return kLogger * @access public */ public function setLogLevel($log_level) { $this->_logRecord['LogLevel'] = $log_level; return $this; } /** * Writes prepared log to database or disk, when database isn't available * * @param int $storage_medium * @return bool|int * @access public * @throws InvalidArgumentException */ public function write($storage_medium = self::LS_AUTOMATIC) { if ( !$this->_logRecord || $this->_logRecord['LogLevel'] > $this->_maxLogLevel || $this->_state == self::STATE_DISABLED ) { // nothing to save OR less detailed logging requested OR disabled - return true; + return false; } $this->_logRecord['LogMemoryUsed'] = memory_get_usage(); $this->_logRecord['LogTimestamp'] = adodb_mktime(); $this->_logRecord['LogDate'] = adodb_date('Y-m-d H:i:s'); if ( $storage_medium == self::LS_AUTOMATIC ) { $storage_medium = $this->Conn->connectionOpened() ? self::LS_DATABASE : self::LS_DISK; } if ( $storage_medium == self::LS_DATABASE ) { $result = $this->Conn->doInsert($this->_logRecord, TABLE_PREFIX . 'SystemLog'); } elseif ( $storage_medium == self::LS_DISK ) { $result = $this->_saveToFile(RESTRICTED . '/system.log'); } else { throw new InvalidArgumentException('Unknown storage medium "' . $storage_medium . '"'); } $unique_id = $this->_logRecord['LogUniqueId']; if ( $this->_logRecord['LogNotificationStatus'] == self::LNS_SENT ) { $this->_sendNotification($unique_id); } $this->_logRecord = Array (); return $result ? $unique_id : false; } /** * Catches last error happened before script ended * * @return void * @access public */ public function catchLastError() { $this->write(); $last_error = error_get_last(); if ( !is_null($last_error) && isset($this->_handlers[self::LL_ERROR]) ) { $handler = $this->_handlers[self::LL_ERROR]; /* @var $handler kErrorHandlerStack */ $handler->handle($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']); } } /** * Deletes log with given id from database or disk, when database isn't available * * @param int $unique_id * @param int $storage_medium * @return void * @access public * @throws InvalidArgumentException */ public function delete($unique_id, $storage_medium = self::LS_AUTOMATIC) { if ( $storage_medium == self::LS_AUTOMATIC ) { $storage_medium = $this->Conn->connectionOpened() ? self::LS_DATABASE : self::LS_DISK; } if ( $storage_medium == self::LS_DATABASE ) { $sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemLog WHERE LogUniqueId = ' . $unique_id; $this->Conn->Query($sql); } elseif ( $storage_medium == self::LS_DISK ) { // TODO: no way to delete a line from a file } else { throw new InvalidArgumentException('Unknown storage medium "' . $storage_medium . '"'); } } /** * Send notification (delayed or instant) about log record to e-mail from configuration * * @param bool $instant * @return kLogger * @access public */ public function notify($instant = false) { $this->_logRecord['LogNotificationStatus'] = $instant ? self::LNS_SENT : self::LNS_PENDING; return $this; } /** * Sends notification e-mail about message with given $unique_id * * @param int $unique_id * @return void * @access protected */ protected function _sendNotification($unique_id) { $notification_email = $this->Application->ConfigValue('SystemLogNotificationEmail'); if ( !$notification_email ) { trigger_error('System Log notification E-mail not specified', E_USER_NOTICE); return; } $send_params = Array ( 'to_name' => $notification_email, 'to_email' => $notification_email, ); // initialize list outside of e-mail event with right settings $this->Application->recallObject('system-log.email', 'system-log_List', Array ('unique_id' => $unique_id)); $this->Application->emailAdmin('SYSTEM.LOG.NOTIFY', null, $send_params); $this->Application->removeObject('system-log.email'); } /** * Adds error/exception handler * * @param string|Array $handler * @param bool $is_exception * @return void * @access public */ public function addErrorHandler($handler, $is_exception = false) { $this->_handlers[$is_exception ? self::LL_CRITICAL : self::LL_ERROR]->add($handler); } /** * SQL Error Handler * * When not debug mode, then fatal database query won't break anything. * * @param int $code * @param string $msg * @param string $sql * @return bool * @access public * @throws RuntimeException */ public function handleSQLError($code, $msg, $sql) { $error_msg = self::shortenMessage(self::DB_ERROR_PREFIX . ' #' . $code . ' - ' . $msg . '. SQL: ' . trim($sql)); if ( isset($this->Application->Debugger) ) { if ( kUtil::constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ) { throw new RuntimeException($error_msg); } else { $this->Application->Debugger->appendTrace(); } } // next line also trigger attached error handlers trigger_error($error_msg, E_USER_WARNING); return true; } /** * Packs information about error into a single line * * @param string $errno * @param bool $strip_tags * @return string * @access public */ public function toString($errno = null, $strip_tags = false) { if ( !isset($errno) ) { $errno = $this->_logRecord['LogCode']; } $errstr = $this->_logRecord['LogMessage']; $errfile = $this->_logRecord['LogSourceFilename']; $errline = $this->_logRecord['LogSourceFileLine']; if ( PHP_SAPI === 'cli' ) { $result = sprintf(' [%s] ' . PHP_EOL . ' %s', $errno, $errstr); if ( $this->_logRecord['LogBacktrace'] ) { $result .= $this->printBacktrace(unserialize($this->_logRecord['LogBacktrace'])); } } else { $result = '' . $errno . ': ' . "{$errstr} in {$errfile} on line {$errline}"; } return $strip_tags ? strip_tags($result) : $result; } /** * Prints backtrace result * * @param array $trace Trace. * * @return string */ protected function printBacktrace(array $trace) { if ( !$trace ) { return ''; } $ret = PHP_EOL . PHP_EOL . PHP_EOL . 'Exception trace:' . PHP_EOL; foreach ( $trace as $trace_info ) { $class = isset($trace_info['class']) ? $trace_info['class'] : ''; $type = isset($trace_info['type']) ? $trace_info['type'] : ''; $function = $trace_info['function']; $args = isset($trace_info['args']) && $trace_info['args'] ? '...' : ''; $file = isset($trace_info['file']) ? $trace_info['file'] : 'n/a'; $line = isset($trace_info['line']) ? $trace_info['line'] : 'n/a'; $ret .= sprintf(' %s%s%s(%s) at %s:%s' . PHP_EOL, $class, $type, $function, $args, $file, $line); } return $ret; } /** * Saves log to file (e.g. when not possible to save into database) * * @param $filename * @return bool * @access protected */ protected function _saveToFile($filename) { $time = adodb_date('Y-m-d H:i:s'); $log_file = new SplFileObject($filename, 'a'); return $log_file->fwrite('[' . $time . '] #' . $this->toString(null, true) . PHP_EOL) > 0; } /** * Checks if log type of current log record matches given one * * @param int $log_type * @param string $log_message * @return bool * @access public */ public function isLogType($log_type, $log_message = null) { if ( $this->_logRecord['LogType'] == $log_type ) { return true; } if ( $log_type == self::LT_DATABASE ) { if ( !isset($log_message) ) { $log_message = $this->_logRecord['LogMessage']; } return strpos($log_message, self::DB_ERROR_PREFIX) !== false; } return false; } /** * Shortens message * * @param string $message * @return string * @access public */ public static function shortenMessage($message) { $max_len = ini_get('log_errors_max_len'); if ( strlen($message) > $max_len ) { $long_key = kUtil::generateId(); self::$_longMessages[$long_key] = $message; return mb_substr($message, 0, $max_len - strlen($long_key) - 2) . ' #' . $long_key; } return $message; } /** * Expands shortened message * * @param string $message * @param bool $clear_cache Allow debugger to expand message after it's been expanded by kLogger * @return string * @access public */ public static function expandMessage($message, $clear_cache = true) { if ( preg_match('/(.*)#([\d]+)$/', $message, $regs) ) { $long_key = $regs[2]; if ( isset(self::$_longMessages[$long_key]) ) { $message = self::$_longMessages[$long_key]; if ( $clear_cache ) { unset(self::$_longMessages[$long_key]); } } } return $message; } /** * Parses database error message into error number, error message and sql that caused that error * * @static * @param string $message * @return Array * @access public */ public static function parseDatabaseError($message) { $regexp = '/' . preg_quote(self::DB_ERROR_PREFIX) . ' #(.*?) - (.*?)\. SQL: (.*?)$/s'; if ( preg_match($regexp, $message, $regs) ) { // errno, errstr, sql return Array ($regs[1], $regs[2], $regs[3]); } return Array (0, $message, ''); } } /** * Base class for error or exception handling */ abstract class kHandlerStack extends kBase { /** * List of added handlers * * @var Array * @access protected */ protected $_handlers = Array (); /** * Reference to event log, which created this object * * @var kLogger * @access protected */ protected $_logger; /** * Remembers if handler is activated * * @var bool * @access protected */ protected $_enabled = false; public function __construct(kLogger $logger) { parent::__construct(); $this->_logger = $logger; if ( !kUtil::constOn('DBG_ZEND_PRESENT') ) { $this->attach(); $this->_enabled = true; } } /** * Detaches from error handling routines on class destruction * * @return void * @access public */ public function __destruct() { if ( !$this->_enabled ) { return; } $this->detach(); $this->_enabled = false; } /** * Attach to error handling routines * * @abstract * @return void * @access protected */ abstract protected function attach(); /** * Detach from error handling routines * * @abstract * @return void * @access protected */ abstract protected function detach(); /** * Adds new handler to the stack * * @param callable $handler * @return void * @access public */ public function add($handler) { $this->_handlers[] = $handler; } protected function _handleFatalError($errno) { $debug_mode = defined('DEBUG_MODE') && DEBUG_MODE; $skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING; if ( !$this->_handlers || ($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 ( $this->_isFatalError($errno) ) { $this->_displayFatalError($errno); } if ( !$this->_handlers ) { return true; } } return null; } /** * Determines if given error is a fatal * * @abstract * @param Exception|int $errno * @return bool */ abstract protected function _isFatalError($errno); /** * Displays div with given error message * * @param string $errno * @return void * @access protected */ protected function _displayFatalError($errno) { $errno = $this->_getFatalErrorTitle($errno); $margin = $this->Application->isAdmin ? '8px' : 'auto'; $error_msg = $this->_logger->toString($errno, PHP_SAPI === 'cli'); if ( PHP_SAPI === 'cli' ) { echo $error_msg; } else { echo '