Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F726625
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jan 5, 9:14 PM
Size
64 KB
Mime Type
text/x-diff
Expires
Tue, Jan 7, 9:14 PM (1 d, 7 h ago)
Engine
blob
Format
Raw Data
Handle
536731
Attached To
rINP In-Portal
in-portal
View Options
Index: branches/5.2.x/core/kernel/managers/cache_manager.php
===================================================================
--- branches/5.2.x/core/kernel/managers/cache_manager.php (revision 16663)
+++ branches/5.2.x/core/kernel/managers/cache_manager.php (revision 16664)
@@ -1,853 +1,870 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kCacheManager extends kBase implements kiCacheable {
/**
* Used variables from SystemSettings table
*
* @var Array
* @access protected
*/
protected $configVariables = Array();
/**
* Used variables from SystemSettings table retrieved from unit cache
*
* @var Array
* @access protected
*/
protected $originalConfigVariables = Array ();
/**
* IDs of config variables used in current run (for caching)
*
* @var Array
* @access protected
*/
protected $configIDs = Array ();
/**
* IDs of config variables retrieved from unit cache
*
* @var Array
* @access protected
*/
protected $originalConfigIDs = Array ();
/**
* Object of memory caching class
*
* @var kCache
* @access protected
*/
protected $cacheHandler = null;
protected $temporaryCache = Array (
'registerAggregateTag' => Array (),
'registerScheduledTask' => Array (),
'registerHook' => Array (),
'registerBuildEvent' => Array (),
'registerAggregateTag' => Array (),
);
/**
* Name of database table, where configuration settings are stored
*
* @var string
* @access protected
*/
protected $settingTableName = '';
/**
* Set's references to kApplication and DBConnection interface class instances
*
* @access public
*/
public function __construct()
{
parent::__construct();
$this->settingTableName = TABLE_PREFIX . 'SystemSettings';
if ( defined('IS_INSTALL') && IS_INSTALL ) {
// table substitution required, so "root" can perform login to upgrade to 5.2.0, where setting table was renamed
if ( !$this->Application->TableFound(TABLE_PREFIX . 'SystemSettings') ) {
$this->settingTableName = TABLE_PREFIX . 'ConfigurationValues';
}
}
}
/**
* Creates caching manager instance
*
* @access public
*/
public function InitCache()
{
$this->cacheHandler = $this->Application->makeClass('kCache');
}
/**
* Returns cache key, used to cache phrase and configuration variable IDs used on current page
*
* @return string
* @access protected
*/
protected function getCacheKey()
{
// TODO: maybe language part isn't required, since same phrase from different languages have one ID now
return $this->Application->GetVar('t') . $this->Application->GetVar('m_theme') . $this->Application->GetVar('m_lang') . $this->Application->isAdmin;
}
/**
* Loads phrases and configuration variables, that were used on this template last time
*
* @access public
*/
public function LoadApplicationCache()
{
$phrase_ids = $config_ids = Array ();
$sql = 'SELECT PhraseList, ConfigVariables
FROM ' . TABLE_PREFIX . 'PhraseCache
WHERE Template = ' . $this->Conn->qstr( md5($this->getCacheKey()) );
$res = $this->Conn->GetRow($sql);
if ($res) {
if ( $res['PhraseList'] ) {
$phrase_ids = explode(',', $res['PhraseList']);
}
if ( $res['ConfigVariables'] ) {
$config_ids = array_diff( explode(',', $res['ConfigVariables']), $this->originalConfigIDs);
}
}
$this->Application->Phrases->Init('phrases', '', null, $phrase_ids);
$this->configIDs = $this->originalConfigIDs = $config_ids;
$this->InitConfig();
}
/**
* Updates phrases and configuration variables, that were used on this template
*
* @access public
*/
public function UpdateApplicationCache()
{
$update = false;
//something changed
$update = $update || $this->Application->Phrases->NeedsCacheUpdate();
$update = $update || (count($this->configIDs) && $this->configIDs != $this->originalConfigIDs);
if ($update) {
$fields_hash = Array (
'PhraseList' => implode(',', $this->Application->Phrases->Ids),
'CacheDate' => adodb_mktime(),
'Template' => md5( $this->getCacheKey() ),
'ConfigVariables' => implode(',', array_unique($this->configIDs)),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'PhraseCache', 'REPLACE');
}
}
/**
* Loads configuration variables, that were used on this template last time
*
* @access protected
*/
protected function InitConfig()
{
if (!$this->originalConfigIDs) {
return ;
}
$sql = 'SELECT VariableValue, VariableName
FROM ' . $this->settingTableName . '
WHERE VariableId IN (' . implode(',', $this->originalConfigIDs) . ')';
$config_variables = $this->Conn->GetCol($sql, 'VariableName');
$this->configVariables = array_merge($this->configVariables, $config_variables);
}
/**
* Returns configuration option value by name
*
* @param string $name
* @return string
* @access public
*/
public function ConfigValue($name)
{
$site_domain_override = Array (
'DefaultEmailSender' => 'AdminEmail',
'DefaultEmailRecipients' => 'DefaultEmailRecipients',
);
if ( isset($site_domain_override[$name]) ) {
$res = $this->Application->siteDomainField($site_domain_override[$name]);
if ( $res ) {
return $res;
}
}
if ( array_key_exists($name, $this->configVariables) ) {
return $this->configVariables[$name];
}
if ( defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound($this->settingTableName, true) ) {
return false;
}
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT VariableId, VariableValue
FROM ' . $this->settingTableName . '
WHERE VariableName = ' . $this->Conn->qstr($name);
$res = $this->Conn->GetRow($sql);
if ( $res !== false ) {
$this->configIDs[] = $res['VariableId'];
$this->configVariables[$name] = $res['VariableValue'];
return $res['VariableValue'];
}
trigger_error('Usage of undefined configuration variable "<strong>' . $name . '</strong>"', E_USER_NOTICE);
return false;
}
/**
* 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)
{
$this->configVariables[$name] = $value;
if ( $local_cache_only ) {
return;
}
$fields_hash = Array ('VariableValue' => $value);
$this->Conn->doUpdate($fields_hash, $this->settingTableName, 'VariableName = ' . $this->Conn->qstr($name));
if ( array_key_exists($name, $this->originalConfigVariables) && $value != $this->originalConfigVariables[$name] ) {
$this->DeleteUnitCache();
}
}
/**
* Loads data, that was cached during unit config parsing
*
* @return bool
* @access public
*/
public function LoadUnitCache()
{
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$data = $this->Application->getCache('master:configs_parsed', false, CacheSettings::$unitCacheRebuildTime);
}
else {
$data = $this->Application->getDBCache('configs_parsed', CacheSettings::$unitCacheRebuildTime);
}
if ( $data ) {
$cache = unserialize($data); // 126 KB all modules
unset($data);
$this->Application->InitManagers();
$this->Application->setFromCache($cache);
/** @var kArray $aggregator */
$aggregator = $this->Application->recallObject('TagsAggregator', 'kArray');
$aggregator->setFromCache($cache);
$this->setFromCache($cache);
unset($cache);
return true;
}
return false;
}
/**
* Empties factory and event manager cache (without storing changes)
*/
public function EmptyUnitCache()
{
// maybe discover keys automatically from corresponding classes
$cache_keys = Array (
'Factory.Files', 'Factory.realClasses',
'ConfigReader.prefixFiles',
'EventManager.beforeHooks', 'EventManager.afterHooks', 'EventManager.scheduledTasks', 'EventManager.buildEvents',
'Application.ReplacementTemplates', 'Application.RewriteListeners', 'Application.ModuleInfo',
'Application.ConfigHash', 'Application.ConfigCacheIds',
);
$empty_cache = Array ();
foreach ($cache_keys as $cache_key) {
$empty_cache[$cache_key] = Array ();
}
$this->Application->setFromCache($empty_cache);
$this->setFromCache($empty_cache);
// otherwise ModulesHelper indirectly used from includeConfigFiles won't work
$this->Application->RegisterDefaultClasses();
$this->Application->RegisterDefaultBuildEvents();
}
/**
* Updates data, that was parsed from unit configs this time
*
* @access public
*/
public function UpdateUnitCache()
{
/** @var kArray $aggregator */
$aggregator = $this->Application->recallObject('TagsAggregator', 'kArray');
$this->preloadConfigVars(); // preloading will put to cache
$cache = array_merge(
$this->Application->getToCache(),
$aggregator->getToCache(),
$this->getToCache()
);
$cache_rebuild_by = SERVER_NAME . ' (' . $this->Application->getClientIp() . ') - ' . adodb_date('d/m/Y H:i:s');
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$this->Application->setCache('master:configs_parsed', serialize($cache));
$this->Application->setCache('master:last_cache_rebuild', $cache_rebuild_by);
}
else {
$this->Application->setDBCache('configs_parsed', serialize($cache));
$this->Application->setDBCache('last_cache_rebuild', $cache_rebuild_by);
}
}
public function delayUnitProcessing($method, $params)
{
if ($this->Application->InitDone) {
// init already done -> call immediately (happens during installation)
$function = Array (&$this->Application, $method);
call_user_func_array($function, $params);
return ;
}
$this->temporaryCache[$method][] = $params;
}
public function applyDelayedUnitProcessing()
{
foreach ($this->temporaryCache as $method => $method_calls) {
$function = Array (&$this->Application, $method);
foreach ($method_calls as $method_call) {
call_user_func_array($function, $method_call);
}
$this->temporaryCache[$method] = Array ();
}
}
/**
* 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)
{
if ( isset($config_variables) && !array_intersect(array_keys($this->originalConfigVariables), $config_variables) ) {
// prevent cache reset, when given config variables are not in unit cache
return;
}
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->rebuildDBCache('configs_parsed', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
}
/**
* Deletes cached section tree, used during permission checking and admin console tree display
*
* @return void
* @access public
*/
public function DeleteSectionCache()
{
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
else {
$this->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
}
/**
* Preloads 21 widely used configuration variables, so they will get to cache for sure
*
* @access protected
*/
protected function preloadConfigVars()
{
$config_vars = Array (
// session related
'SessionTimeout', 'SessionCookieName', 'SessionCookieDomains', 'SessionBrowserSignatureCheck',
'SessionIPAddressCheck', 'CookieSessions', 'KeepSessionOnBrowserClose', 'User_GuestGroup',
'User_LoggedInGroup', 'RegistrationUsernameRequired',
// output related
'UseModRewrite', 'UseContentLanguageNegotiation', 'UseOutputCompression', 'OutputCompressionLevel',
'Config_Site_Time', 'SystemTagCache', 'DefaultGridPerPage',
// tracking related
'UseChangeLog', 'UseVisitorTracking', 'ModRewriteUrlEnding', 'ForceModRewriteUrlEnding',
'RunScheduledTasksFromCron',
);
$escaped_config_vars = $this->Conn->qstrArray($config_vars);
$sql = 'SELECT VariableId, VariableName, VariableValue
FROM ' . $this->settingTableName . '
WHERE VariableName IN (' . implode(',', $escaped_config_vars) . ')';
$data = $this->Conn->Query($sql, 'VariableId');
foreach ($data as $variable_id => $variable_info) {
$this->configIDs[] = $variable_id;
$this->configVariables[ $variable_info['VariableName'] ] = $variable_info['VariableValue'];
}
}
/**
* Sets data from cache to object
*
* Used for cases, when ConfigValue is called before LoadApplicationCache method (e.g. session init, url engine init)
*
* @param Array $data
* @access public
*/
public function setFromCache(&$data)
{
$this->configVariables = $this->originalConfigVariables = $data['Application.ConfigHash'];
$this->configIDs = $this->originalConfigIDs = $data['Application.ConfigCacheIds'];
}
/**
* Gets object data for caching
* The following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
*
* @access public
* @return Array
*/
public function getToCache()
{
return Array (
'Application.ConfigHash' => $this->configVariables,
'Application.ConfigCacheIds' => $this->configIDs,
// not in use, since it only represents template specific values, not global ones
// 'Application.Caches.ConfigVariables' => $this->originalConfigIDs,
);
}
/**
* Returns caching type (none, memory, temporary)
*
* @param int $caching_type
* @return bool
* @access public
*/
public function isCachingType($caching_type)
{
return $this->cacheHandler->getCachingType() == $caching_type;
}
/**
* 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->cacheHandler->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->cacheHandler->setCache($key, $value, $expiration);
}
/**
* Stores new $value in cache with $key name (only if not there already)
*
* @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->cacheHandler->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->cacheHandler->rebuildCache($name, $mode, $max_rebuilding_time);
}
/**
* Deletes key from cache
*
* @param string $key
* @return void
* @access public
*/
public function deleteCache($key)
{
$this->cacheHandler->delete($key);
}
/**
* Reset's all memory cache at once
*
* @return void
* @access public
*/
public function resetCache()
{
$this->cacheHandler->reset();
}
/**
* 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)
{
// no serials in cache key OR cache is outdated
$rebuilding = false;
$wait_seconds = $max_rebuild_seconds;
while (true) {
$cached_data = $this->_getDBCache(Array ($name, $name . '_rebuilding', $name . '_rebuild'));
if ( $cached_data[$name . '_rebuild'] ) {
// cache rebuild requested -> rebuild now
$this->deleteDBCache($name . '_rebuild');
if ( $this->rebuildDBCache($name, kCache::REBUILD_NOW, $max_rebuild_seconds, '[M1]') ) {
return false;
}
}
$cache = $cached_data[$name];
$rebuilding = $cached_data[$name . '_rebuilding'];
if ( ($cache === false) && (!$rebuilding || $wait_seconds == 0) ) {
// cache missing and nobody rebuilding it -> rebuild; enough waiting for cache to be ready
$this->rebuildDBCache($name, kCache::REBUILD_NOW, $max_rebuild_seconds, '[M2' . ($rebuilding ? 'R' : '!R') . ',WS=' . $wait_seconds . ']');
return false;
}
elseif ( $cache !== false ) {
// cache present -> return it
$this->cacheHandler->storeStatistics($name, $rebuilding ? 'h' : 'H');
return $cache;
}
$wait_seconds -= kCache::WAIT_STEP;
sleep(kCache::WAIT_STEP);
}
$this->rebuildDBCache($name, kCache::REBUILD_NOW, $max_rebuild_seconds, '[M3' . ($rebuilding ? 'R' : '!R') . ',WS=' . $wait_seconds . ']');
return false;
}
/**
* Returns value from database cache
*
* @param string|Array $names key name
* @return mixed
* @access protected
*/
protected function _getDBCache($names)
{
$res = Array ();
$names = (array)$names;
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT Data, Cached, LifeTime, VarName
FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName IN (' . implode(',', $this->Conn->qstrArray($names)) . ')';
$cached_data = $this->Conn->Query($sql, 'VarName');
foreach ($names as $name) {
if ( !isset($cached_data[$name]) ) {
$res[$name] = false;
continue;
}
$lifetime = (int)$cached_data[$name]['LifeTime']; // in seconds
if ( ($lifetime > 0) && ($cached_data[$name]['Cached'] + $lifetime < adodb_mktime()) ) {
// delete expired
$this->Conn->nextQueryCachable = true;
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName = ' . $this->Conn->qstr($name);
$this->Conn->Query($sql);
$res[$name] = false;
continue;
}
$res[$name] = $cached_data[$name]['Data'];
}
return count($res) == 1 ? array_pop($res) : $res;
}
/**
* 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->cacheHandler->storeStatistics($name, 'WU');
$this->deleteDBCache($name . '_rebuilding');
$this->_setDBCache($name, $value, $expiration);
}
/**
* Sets value to database cache
*
* @param string $name
* @param mixed $value
* @param int|bool $expiration
* @param string $insert_type
* @return bool
* @access protected
*/
protected function _setDBCache($name, $value, $expiration = false, $insert_type = 'REPLACE')
{
if ( (int)$expiration <= 0 ) {
$expiration = -1;
}
$fields_hash = Array (
'VarName' => $name,
'Data' => &$value,
'Cached' => adodb_mktime(),
'LifeTime' => (int)$expiration,
);
$this->Conn->nextQueryCachable = true;
return $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'SystemCache', $insert_type);
}
/**
* Sets value to database cache
*
* @param string $name
* @param mixed $value
* @param int|bool $expiration
* @return bool
* @access protected
*/
protected function _addDBCache($name, $value, $expiration = false)
{
return $this->_setDBCache($name, $value, $expiration, 'INSERT');
}
/**
* Sets rebuilding mode for given cache
*
* @param string $name
* @param int $mode
* @param int $max_rebuilding_time
* @param string $miss_type
* @return bool
* @access public
*/
public function rebuildDBCache($name, $mode = null, $max_rebuilding_time = 0, $miss_type = 'M')
{
if ( !isset($mode) || $mode == kCache::REBUILD_NOW ) {
$this->cacheHandler->storeStatistics($name, $miss_type);
if ( !$max_rebuilding_time ) {
return true;
}
if ( !$this->_addDBCache($name . '_rebuilding', 1, $max_rebuilding_time) ) {
$this->cacheHandler->storeStatistics($name, 'l');
return false;
}
$this->deleteDBCache($name . '_rebuild');
$this->cacheHandler->storeStatistics($name, 'L');
}
elseif ( $mode == kCache::REBUILD_LATER ) {
$this->_setDBCache($name . '_rebuild', 1, 0);
$this->deleteDBCache($name . '_rebuilding');
}
return true;
}
/**
* Deletes key from database cache
*
* @param string $name
* @return void
* @access public
*/
public function deleteDBCache($name)
{
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemCache
WHERE VarName = ' . $this->Conn->qstr($name);
$this->Conn->Query($sql);
}
/**
* Increments serial based on prefix and it's ID (optional)
*
* @param string $prefix
* @param int $id ID (value of IDField) or ForeignKeyField:ID
* @param bool $increment
* @return string
* @access public
*/
public function incrementCacheSerial($prefix, $id = null, $increment = true)
{
$pascal_case_prefix = implode('', array_map('ucfirst', explode('-', $prefix)));
$serial_name = $pascal_case_prefix . (isset($id) ? 'IDSerial:' . $id : 'Serial');
if ($increment) {
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Incrementing serial: <strong>' . $serial_name . '</strong>.');
}
$this->setCache($serial_name, (int)$this->getCache($serial_name) + 1);
if (!defined('IS_INSTALL') || !IS_INSTALL) {
- // delete cached mod-rewrite urls related to given prefix and id
- $delete_clause = isset($id) ? $prefix . ':' . $id : $prefix;
+ if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
+ $prefixes = $this->Application->getCache('cached_urls_unit_prefixes');
+ }
+ else {
+ $prefixes = $this->Application->getDBCache('cached_urls_unit_prefixes');
- $sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls
- WHERE Prefixes LIKE ' . $this->Conn->qstr('%|' . $delete_clause . '|%');
- $this->Conn->Query($sql);
+ if ( $prefixes !== false ) {
+ $prefixes = unserialize($prefixes);
+ }
+ }
+
+ if ( !$prefixes ) {
+ $prefixes = array('c', 'lang', 'theme');
+ }
+
+ if ( in_array($prefix, $prefixes) ) {
+ // delete cached mod-rewrite urls related to given prefix and id
+ $delete_clause = isset($id) ? $prefix . ':' . $id : $prefix;
+
+ $sql = 'DELETE FROM ' . TABLE_PREFIX . 'CachedUrls
+ WHERE Prefixes LIKE ' . $this->Conn->qstr('%|' . $delete_clause . '|%');
+ $this->Conn->Query($sql);
+ }
}
}
return $serial_name;
}
/**
* Returns cached category informaton by given cache name. All given category
* information is recached, when at least one of 4 caches is missing.
*
* @param int $category_id
* @param string $name cache name = {filenames, category_designs, category_tree}
* @return string
* @access public
*/
public function getCategoryCache($category_id, $name)
{
$serial_name = '[%CIDSerial:' . $category_id . '%]';
$cache_key = $name . $serial_name;
$ret = $this->getCache($cache_key);
if ($ret === false) {
if (!$category_id) {
// don't query database for "Home" category (ID = 0), because it doesn't exist in database
return false;
}
// this allows to save 2 sql queries for each category
$this->Conn->nextQueryCachable = true;
$sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight
FROM ' . TABLE_PREFIX . 'Categories
WHERE CategoryId = ' . (int)$category_id;
$category_data = $this->Conn->GetRow($sql);
if ($category_data !== false) {
// only direct links to category pages work (symlinks, container pages and so on won't work)
$this->setCache('filenames' . $serial_name, $category_data['NamedParentPath']);
$this->setCache('category_designs' . $serial_name, ltrim($category_data['CachedTemplate'], '/'));
$this->setCache('category_tree' . $serial_name, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']);
}
}
return $this->getCache($cache_key);
}
}
Index: branches/5.2.x/core/units/admin/admin_events_handler.php
===================================================================
--- branches/5.2.x/core/units/admin/admin_events_handler.php (revision 16663)
+++ branches/5.2.x/core/units/admin/admin_events_handler.php (revision 16664)
@@ -1,1305 +1,1336 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class AdminEventsHandler extends kDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
'OnSaveColumns' => Array ('self' => true),
'OnGetPopupSize' => Array ('self' => true),
'OnClosePopup' => Array ('self' => true),
'OnSaveSetting' => Array ('self' => true),
'OnDropTempTablesByWID' => Array ('self' => true),
'OnProcessSelected' => Array ('self' => true), // allow CSV import file upload
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks user permission to execute given $event
*
* @param kEvent $event
* @return bool
* @access public
*/
public function CheckPermission(kEvent $event)
{
$perm_value = null;
$system_events = array(
'OnResetModRwCache', 'OnResetSections', 'OnResetConfigsCache', 'OnResetParsedData', 'OnResetMemcache',
'OnDeleteCompiledTemplates', 'OnCompileTemplates', 'OnGenerateTableStructure', 'OnSynchronizeDBRevisions',
'OnDeploy', 'OnRebuildThemes', 'OnDumpAssets', 'OnCheckPrefixConfig', 'OnMemoryCacheGet',
'OnMemoryCacheSet',
);
if ( in_array($event->Name, $system_events) ) {
// events from "Tools -> System Tools" section are controlled via that section "edit" permission
$perm_value = /*$this->Application->isDebugMode() ||*/ $this->Application->CheckPermission($event->getSection() . '.edit');
}
$tools_events = Array (
'OnBackup' => 'in-portal:backup.view',
'OnBackupProgress' => 'in-portal:backup.view',
'OnDeleteBackup' => 'in-portal:backup.view',
'OnBackupCancel' => 'in-portal:backup.view',
'OnRestore' => 'in-portal:restore.view',
'OnRestoreProgress' => 'in-portal:restore.view',
'OnRestoreCancel' => 'in-portal:backup.view',
'OnSqlQuery' => 'in-portal:sql_query.view',
);
if ( array_key_exists($event->Name, $tools_events) ) {
$perm_value = $this->Application->CheckPermission($tools_events[$event->Name]);
}
if ( $event->Name == 'OnSaveMenuFrameWidth' ) {
$perm_value = $this->Application->isAdminUser;
}
/** @var kPermissionsHelper $perm_helper */
$perm_helper = $this->Application->recallObject('PermissionsHelper');
$csv_events = Array ('OnCSVImportBegin', 'OnCSVImportStep', 'OnExportCSV', 'OnGetCSV');
if ( in_array($event->Name, $csv_events) ) {
/** @var kCSVHelper $csv_helper */
$csv_helper = $this->Application->recallObject('CSVHelper');
$prefix = $csv_helper->getPrefix(stripos($event->Name, 'import') !== false);
$perm_mapping = Array (
'OnCSVImportBegin' => 'OnProcessSelected',
'OnCSVImportStep' => 'OnProcessSelected',
'OnExportCSV' => 'OnLoad',
'OnGetCSV' => 'OnLoad',
);
$tmp_event = new kEvent($prefix . ':' . $perm_mapping[$event->Name] );
$perm_value = $perm_helper->CheckEventPermission($tmp_event, $this->permMapping);
}
if ( isset($perm_value) ) {
return $perm_helper->finalizePermissionCheck($event, $perm_value);
}
return parent::CheckPermission($event);
}
/**
* Reset mod-rewrite url cache
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnResetModRwCache(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls');
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets tree section cache and refreshes admin section tree
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnResetSections(kEvent $event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
if ($this->Application->isCachingType(CACHING_TYPE_MEMORY)) {
$this->Application->rebuildCache('master:sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
else {
$this->Application->rebuildDBCache('sections_parsed', kCache::REBUILD_LATER, CacheSettings::$sectionsParsedRebuildTime);
}
$event->SetRedirectParam('refresh_tree', 1);
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets unit config cache
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnResetConfigsCache(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
$this->Application->rebuildCache('master:config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
else {
$this->Application->rebuildDBCache('config_files', kCache::REBUILD_LATER, CacheSettings::$unitCacheRebuildTime);
}
$this->OnResetParsedData($event);
/** @var SkinHelper $skin_helper */
$skin_helper = $this->Application->recallObject('SkinHelper');
$skin_helper->deleteCompiled();
}
/**
* Resets parsed data from unit configs
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnResetParsedData(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$this->Application->DeleteUnitCache();
if ( $this->Application->GetVar('validate_configs') ) {
$event->SetRedirectParam('validate_configs', 1);
}
$event->SetRedirectParam('action_completed', 1);
}
/**
* Resets memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnResetMemcache(kEvent $event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = kEvent::erSTOP;
}
$this->Application->resetCache();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Compiles all templates (with a progress bar)
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCompileTemplates(kEvent $event)
{
/** @var NParserCompiler $compiler */
$compiler = $this->Application->recallObject('NParserCompiler');
$compiler->CompileTemplatesStep();
$event->status = kEvent::erSTOP;
}
/**
* Deletes all compiled templates
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnDeleteCompiledTemplates(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
$base_path = WRITEABLE . DIRECTORY_SEPARATOR . 'cache';
// delete debugger reports
$debugger_reports = glob(RESTRICTED . '/debug_@*@.txt');
if ( $debugger_reports ) {
foreach ($debugger_reports as $debugger_report) {
unlink($debugger_report);
}
}
$this->_deleteCompiledTemplates($base_path);
$event->SetRedirectParam('action_completed', 1);
}
/**
* Deletes compiled templates in a given folder
*
* @param string $folder
* @param bool $unlink_folder
* @return void
* @access protected
*/
protected function _deleteCompiledTemplates($folder, $unlink_folder = false)
{
$sub_folders = glob($folder . '/*', GLOB_ONLYDIR);
if ( is_array($sub_folders) ) {
foreach ($sub_folders as $sub_folder) {
$this->_deleteCompiledTemplates($sub_folder, true);
}
}
$files = glob($folder . '/*.php');
if ( is_array($files) ) {
foreach ($files as $file) {
unlink($file);
}
}
if ( $unlink_folder ) {
rmdir($folder);
}
}
/**
* Generates structure for specified table
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnGenerateTableStructure(kEvent $event)
{
$types_hash = Array (
'string' => 'varchar|text|mediumtext|longtext|date|datetime|time|timestamp|char|year|enum|set',
'int' => 'smallint|mediumint|int|bigint|tinyint',
'float' => 'float|double|decimal',
);
$table_name = $this->Application->GetVar('table_name');
if ( !$table_name ) {
echo 'error: no table name specified';
return;
}
if ( TABLE_PREFIX && !preg_match('/^' . preg_quote(TABLE_PREFIX, '/') . '(.*)/', $table_name) && (strtolower($table_name) != $table_name) ) {
// table name without prefix, then add it (don't affect K3 tables named in lowercase)
$table_name = TABLE_PREFIX . $table_name;
}
if ( !$this->Conn->TableFound($table_name) ) {
// table with prefix doesn't exist, assume that just config prefix passed -> resolve table name from it
$prefix = preg_replace('/^' . preg_quote(TABLE_PREFIX, '/') . '/', '', $table_name);
if ( $this->Application->prefixRegistred($prefix) ) {
// when prefix is found -> use it's table (don't affect K3 tables named in lowecase)
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
}
}
$table_info = $this->Conn->Query('DESCRIBE '.$table_name);
// 1. prepare config keys
$grids = Array (
'Default' => Array (
'Icons' => Array ('default' => 'icon16_item.png'),
'Fields' => Array (),
)
);
$grids_fields = Array();
$id_field = '';
$fields = Array ();
$float_types = Array ('float', 'double', 'numeric');
foreach ($table_info as $field_info) {
if ( preg_match('/l[\d]+_.*/', $field_info['Field']) ) {
// don't put multilingual fields in config
continue;
}
$field_options = Array ();
if ( $field_info['Key'] == 'PRI' ) {
if ( $field_info['Field'] == 'Id' ) {
$grid_col_options = Array ('filter_block' => 'grid_range_filter', 'width' => 80);
}
else {
$grid_col_options = Array ('title' => 'column:la_fld_Id', 'filter_block' => 'grid_range_filter', 'width' => 80);
}
}
else {
$grid_col_options = Array ('filter_block' => 'grid_like_filter');
}
// 1. get php field type by mysql field type
foreach ($types_hash as $php_type => $db_types) {
if ( preg_match('/' . $db_types . '/', $field_info['Type']) ) {
$field_options['type'] = $php_type;
break;
}
}
// 2. get field default value
$default_value = $field_info['Default'];
$not_null = $field_info['Null'] != 'YES';
if ( is_numeric($default_value) ) {
$default_value = preg_match('/[\.,]/', $default_value) ? (float)$default_value : (int)$default_value;
}
if ( is_null($default_value) && $not_null ) {
$default_value = $field_options['type'] == 'string' ? '' : 0;
}
if ( in_array($php_type, $float_types) ) {
// this is float number
if ( preg_match('/' . $db_types . '\([\d]+,([\d]+)\)/i', $field_info['Type'], $regs) ) {
// size is described in structure -> add formatter
$field_options['formatter'] = 'kFormatter';
$field_options['format'] = '%01.' . $regs[1] . 'f';
if ( $not_null ) {
// null fields, will most likely have NULL as default value
$default_value = 0;
}
}
elseif ( $not_null ) {
// no size information, just convert to float
// null fields, will most likely have NULL as default value
$default_value = (float)$default_value;
}
}
if ( preg_match('/varchar\(([\d]+)\)/i', $field_info['Type'], $regs) ) {
$field_options['max_len'] = (int)$regs[1];
}
if ( preg_match('/tinyint\([\d]+\)/i', $field_info['Type']) ) {
$field_options['formatter'] = 'kOptionsFormatter';
$field_options['options'] = Array (1 => 'la_Yes', 0 => 'la_No');
$field_options['use_phrases'] = 1;
$grid_col_options['filter_block'] = 'grid_options_filter';
}
if ( $not_null ) {
$field_options['not_null'] = 1;
}
if ( $field_info['Key'] == 'PRI' ) {
$default_value = 0;
$id_field = $field_info['Field'];
}
if ( $php_type == 'int' && !$not_null ) {
// numeric null field
if ( preg_match('/(On|Date)$/', $field_info['Field']) || $field_info['Field'] == 'Modified' ) {
$field_options['formatter'] = 'kDateFormatter';
$grid_col_options['filter_block'] = 'grid_date_range_filter';
$grid_col_options['width'] = 120;
}
else {
$grid_col_options['filter_block'] = 'grid_range_filter';
$grid_col_options['width'] = 80;
}
}
if ( $php_type == 'int' && ($not_null || is_numeric($default_value)) ) {
// is integer field AND not null
$field_options['default'] = (int)$default_value;
}
else {
$field_options['default'] = $default_value;
}
$fields[$field_info['Field']] = $field_options;
$grids_fields[$field_info['Field']] = $grid_col_options;
}
$grids['Default']['Fields'] = $grids_fields;
$ret = Array (
'IDField' => $id_field,
'Fields' => $fields,
'Grids' => $grids,
);
$decorator = new UnitConfigDecorator();
$ret = $decorator->decorate($ret);
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Table "<?php echo $table_name; ?>" Structure');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<?php echo $GLOBALS['debugger']->highlightString($ret); ?>
<br /><br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = kEvent::erSTOP;
}
/**
* Refreshes ThemeFiles & Themes tables by actual content on HDD
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnRebuildThemes(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
/** @var kThemesHelper $themes_helper */
$themes_helper = $this->Application->recallObject('ThemesHelper');
$themes_helper->refreshThemes();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Dumps assets
*
* @param kEvent $event Event.
*
* @return void
*/
protected function OnDumpAssets(kEvent $event)
{
if ( $this->Application->GetVar('ajax') == 'yes' ) {
$event->status = kEvent::erSTOP;
}
/** @var MinifyHelper $minify_helper */
$minify_helper = $this->Application->recallObject('MinifyHelper');
$minify_helper->delete();
$minify_helper->dump();
$event->SetRedirectParam('action_completed', 1);
}
/**
* Saves grid column widths after their resize by user
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSaveColumns(kEvent $event)
{
$picker_helper = new kColumnPickerHelper(
$this->Application->GetVar('main_prefix'),
$this->Application->GetLinkedVar('grid_name')
);
$picked = trim($this->Application->GetVar('picked_str'), '|');
$hidden = trim($this->Application->GetVar('hidden_str'), '|');
$picker_helper->saveColumns($picked, $hidden);
$this->finalizePopup($event);
}
/**
* Saves various admin settings via ajax
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSaveSetting(kEvent $event)
{
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return;
}
$var_name = $this->Application->GetVar('var_name');
$var_value = $this->Application->GetVar('var_value');
$this->Application->StorePersistentVar($var_name, $var_value);
$event->status = kEvent::erSTOP;
}
/**
* Just closes popup & deletes last_template & opener_stack if popup, that is closing
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnClosePopup(kEvent $event)
{
$event->SetRedirectParam('opener', 'u');
}
/**
* Occurs right after initialization of the kernel, used mainly as hook-to event
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnStartup(kEvent $event)
{
if ( $this->Application->isAdmin ) {
return;
}
$base_url = preg_quote($this->Application->BaseURL(), '/');
$referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
if ( $referrer && !preg_match('/^' . $base_url . '/', $referrer) ) {
$this->Application->Session->SetCookie('original_referrer', $referrer);
$this->Application->SetVar('original_referrer', $referrer);
}
}
/**
* Occurs right before echoing the output, in Done method of application, used mainly as hook-to event
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeShutdown(kEvent $event)
{
}
/**
* Is called after tree was build (when not from cache)
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterBuildTree(kEvent $event)
{
}
/**
* Called by AJAX to perform CSV export
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnExportCSV(kEvent $event)
{
/** @var kCSVHelper $csv_helper */
$csv_helper = $this->Application->recallObject('CSVHelper');
$csv_helper->PrefixSpecial = $csv_helper->getPrefix(false);
$csv_helper->grid = $this->Application->GetVar('grid');
$csv_helper->ExportStep();
$event->status = kEvent::erSTOP;
}
/**
* Returning created by AJAX CSV file
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnGetCSV(kEvent $event)
{
/** @var kCSVHelper $csv_helper */
$csv_helper = $this->Application->recallObject('CSVHelper');
$csv_helper->GetCSV();
}
/**
* Start CSV import
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCSVImportBegin(kEvent $event)
{
/** @var kDBItem $object */
$object = $event->getObject(Array ('skip_autoload' => true));
$object->setID(0);
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values);
$event->setEventParam('form_data', $field_values);
$event->redirect = false;
$result = 'required';
if ( $object->GetDBField('ImportFile') ) {
/** @var kCSVHelper $csv_helper */
$csv_helper = $this->Application->recallObject('CSVHelper');
$csv_helper->PrefixSpecial = $csv_helper->getPrefix(true);
$csv_helper->grid = $this->Application->GetVar('grid');
$result = $csv_helper->ImportStart($object->GetField('ImportFile', 'file_paths'));
if ( $result === true ) {
$event->redirect = $this->Application->GetVar('next_template');
$event->SetRedirectParam('PrefixSpecial', $this->Application->GetVar('PrefixSpecial'));
$event->SetRedirectParam('grid', $this->Application->GetVar('grid'));
}
}
if ( $event->redirect === false ) {
$object->SetError('ImportFile', $result);
$event->status = kEvent::erFAIL;
}
}
/**
* Performs one CSV import step
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCSVImportStep(kEvent $event)
{
/** @var kCSVHelper $import_helper */
$import_helper = $this->Application->recallObject('CSVHelper');
$import_helper->ImportStep();
$event->status = kEvent::erSTOP;
}
/**
* Shows unit config filename, where requested prefix is defined
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCheckPrefixConfig(kEvent $event)
{
$prefix = $this->Application->GetVar('config_prefix');
$config_file = $this->Application->UnitConfigReader->prefixFiles[$prefix];
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Unit Config of "<?php echo $prefix; ?>" prefix');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<strong>Prefix:</strong> <?php echo $prefix; ?><br />
<strong>Unit Config:</strong> <?php echo $GLOBALS['debugger']->highlightString($config_file); ?><br />
<br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array ('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = kEvent::erSTOP;
}
/**
* Deletes temp tables, when user closes window using "x" button in top right corner
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnDropTempTablesByWID(kEvent $event)
{
$sid = $this->Application->GetSID();
$wid = $this->Application->GetVar('m_wid');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . TABLE_PREFIX . 'ses_' . $sid . '_' . $wid . '_edit_(.*)$/';
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) ) {
$this->Conn->Query('DROP TABLE IF EXISTS ' . $table);
}
}
echo 'OK';
$event->status = kEvent::erSTOP;
}
/**
* Backup all data
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBackup(kEvent $event)
{
/** @var BackupHelper $backup_helper */
$backup_helper = $this->Application->recallObject('BackupHelper');
if ( !$backup_helper->initBackup() ) {
$event->status = kEvent::erFAIL;
}
$event->redirect = 'tools/backup2';
}
/**
* Perform next backup step
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBackupProgress(kEvent $event)
{
/** @var BackupHelper $backup_helper */
$backup_helper = $this->Application->recallObject('BackupHelper');
$done_percent = $backup_helper->performBackup();
if ( $done_percent == 100 ) {
$event->redirect = 'tools/backup3';
return;
}
$event->status = kEvent::erSTOP;
echo $done_percent;
}
/**
* Stops Backup & redirect to Backup template
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBackupCancel(kEvent $event)
{
$event->redirect = 'tools/backup1';
}
/**
* Starts restore process
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnRestore(kEvent $event)
{
/** @var BackupHelper $backup_helper */
$backup_helper = $this->Application->recallObject('BackupHelper');
$backup_helper->initRestore();
$event->redirect = 'tools/restore3';
}
/**
* Performs next restore step
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnRestoreProgress(kEvent $event)
{
/** @var BackupHelper $backup_helper */
$backup_helper = $this->Application->recallObject('BackupHelper');
$done_percent = $backup_helper->performRestore();
if ( $done_percent == BackupHelper::SQL_ERROR_DURING_RESTORE ) {
$event->redirect = 'tools/restore4';
}
elseif ( $done_percent == BackupHelper::FAILED_READING_BACKUP_FILE ) {
$this->Application->StoreVar('adm.restore_error', 'File read error');
$event->redirect = 'tools/restore4';
}
elseif ( $done_percent == 100 ) {
$backup_helper->replaceRestoredFiles();
$this->Application->StoreVar('adm.restore_success', 1);
$event->redirect = 'tools/restore4';
}
else {
$event->status = kEvent::erSTOP;
echo $done_percent;
}
}
/**
* Stops Restore & redirect to Restore template
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnRestoreCancel(kEvent $event)
{
$event->redirect = 'tools/restore1';
}
/**
* Deletes one backup file
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnDeleteBackup(kEvent $event)
{
/** @var BackupHelper $backup_helper */
$backup_helper = $this->Application->recallObject('BackupHelper');
$backup_helper->delete();
}
/**
* Starts restore process
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSqlQuery(kEvent $event)
{
$sql = $this->Application->GetVar('sql');
if ( $sql ) {
$start = microtime(true);
$result = $this->Conn->Query($sql);
$this->Application->SetVar('sql_time', round(microtime(true) - $start, 7));
if ( $result && is_array($result) ) {
$this->Application->SetVar('sql_has_rows', 1);
$this->Application->SetVar('sql_rows', serialize($result));
}
$check_sql = trim(strtolower($sql));
if ( preg_match('/^(insert|update|replace|delete)/', $check_sql) ) {
$this->Application->SetVar('sql_has_affected', 1);
$this->Application->SetVar('sql_affected', $this->Conn->getAffectedRows());
}
}
$this->Application->SetVar('query_status', 1);
$event->status = kEvent::erFAIL;
}
/**
* Occurs after unit config cache was successfully rebuilt
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterCacheRebuild(kEvent $event)
{
}
/**
* Removes "Community -> Groups" section when it is not allowed
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
$section_adjustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments', Array());
if ( !$this->Application->ConfigValue('AdvancedUserManagement') ) {
$section_adjustments['in-portal:user_groups'] = 'remove';
}
$section_adjustments['in-portal:root'] = Array (
'label' => $this->Application->ConfigValue('Site_Name')
);
$this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_adjustments);
}
/**
* Saves menu (tree) frame width
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSaveMenuFrameWidth(kEvent $event)
{
$event->status = kEvent::erSTOP;
if ( !$this->Application->ConfigValue('ResizableFrames') ) {
return;
}
$this->Application->StorePersistentVar('MenuFrameWidth', (int)$this->Application->GetVar('width'));
}
/**
* Retrieves data from memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnMemoryCacheGet(kEvent $event)
{
$event->status = kEvent::erSTOP;
$ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error
$key = $this->Application->GetVar('key');
if ( !$key ) {
$ret['code'] = 1;
$ret['message'] = 'Key name missing';
}
else {
$value = $this->Application->getCache($key);
$ret['value'] =& $value;
$ret['size'] = is_string($value) ? kUtil::formatSize(strlen($value)) : '?';
$ret['type'] = gettype($value);
if ( kUtil::IsSerialized($value) ) {
$value = unserialize($value);
}
if ( is_array($value) ) {
$ret['value'] = print_r($value, true);
}
if ( $ret['value'] === false ) {
$ret['code'] = 2;
$ret['message'] = 'Key "' . $key . '" doesn\'t exist';
}
}
/** @var JSONHelper $json_helper */
$json_helper = $this->Application->recallObject('JSONHelper');
echo $json_helper->encode($ret);
}
/**
* Retrieves data from memory cache
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnMemoryCacheSet(kEvent $event)
{
$event->status = kEvent::erSTOP;
$ret = Array ('message' => '', 'code' => 0); // 0 - ok, > 0 - error
$key = $this->Application->GetVar('key');
if ( !$key ) {
$ret['code'] = 1;
$ret['message'] = 'Key name missing';
}
else {
$value = $this->Application->GetVar('value');
$res = $this->Application->setCache($key, $value);
$ret['result'] = $res ? 'OK' : 'FAILED';
}
/** @var JSONHelper $json_helper */
$json_helper = $this->Application->recallObject('JSONHelper');
echo $json_helper->encode($ret);
}
/**
* Deploy changes
*
* Usage: "php tools/run_event.php adm:OnDeploy b674006f3edb1d9cd4d838c150b0567d"
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnDeploy(kEvent $event)
{
$this->_deploymentAction($event);
}
/**
* Synchronizes database revisions from "project_upgrades.sql" file
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSynchronizeDBRevisions(kEvent $event)
{
$this->_deploymentAction($event, true);
}
/**
* Common code to invoke deployment helper
*
* @param kEvent $event
* @param bool $dry_run
* @return void
* @access protected
*/
protected function _deploymentAction(kEvent $event, $dry_run = false)
{
/** @var DeploymentHelper $deployment_helper */
$deployment_helper = $this->Application->recallObject('DeploymentHelper');
$deployment_helper->setEvent($event);
if ( $deployment_helper->deployAll($dry_run) ) {
$event->SetRedirectParam('action_completed', 1);
if ( !$deployment_helper->isCommandLine ) {
// browser invocation -> don't perform redirect
$event->redirect = false;
// no redirect, but deployment succeeded - set redirect params directly
foreach ($event->getRedirectParams() as $param_name => $param_value) {
$this->Application->SetVar($param_name, $param_value);
}
}
}
else {
$event->status = kEvent::erFAIL;
}
}
/**
* [SCHEDULED TASK]
* 1. Delete all Debug files from system/.restricted folder (format debug_@977827436@.txt)
* 2. Run MySQL OPTIMIZE SQL one by one on all In-Portal tables (found by prefix).
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnOptimizePerformance(kEvent $event)
{
$start_time = adodb_mktime();
$sql = 'SELECT SessionKey
FROM ' . TABLE_PREFIX . 'UserSessions
WHERE LastAccessed > ' . $start_time;
$active_sessions = array_flip($this->Conn->GetCol($sql));
$files = scandir(RESTRICTED);
$file_path = RESTRICTED . '/';
foreach ($files AS $file_name) {
if ( !preg_match('#^debug_@([0-9]{9})@.txt$#', $file_name, $matches) ) {
// not debug file
continue;
}
$sid = $matches[1];
if ( isset($active_sessions[$sid]) || (filemtime($file_path . $file_name) > $start_time) ) {
// debug file belongs to an active session
// debug file is recently created (after sessions snapshot)
continue;
}
unlink($file_path . $file_name);
}
$system_tables = $this->Conn->GetCol('SHOW TABLES LIKE "' . TABLE_PREFIX . '%"');
foreach ($system_tables AS $table_name) {
$this->Conn->Query('OPTIMIZE TABLE ' . $table_name);
}
}
/**
* Returns popup size (by template), if not cached, then parse template to get value
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnGetPopupSize(kEvent $event)
{
$event->status = kEvent::erSTOP;
if ( $this->Application->GetVar('ajax') != 'yes' ) {
return;
}
$t = $this->Application->GetVar('template_name');
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'PopupSizes
WHERE TemplateName = ' . $this->Conn->qstr($t);
$popup_info = $this->Conn->GetRow($sql);
$this->Application->setContentType('text/plain');
if ( !$popup_info ) {
// dies when SetPopupSize tag found & in ajax request
$this->Application->InitParser();
$this->Application->ParseBlock(Array ('name' => $t));
// tag SetPopupSize not found in template -> use default size
echo '750x400';
}
else {
echo $popup_info['PopupWidth'] . 'x' . $popup_info['PopupHeight'];
}
}
/**
* Writes HTTP request to System Log
*
* @param kEvent $event
* @return void
* @access public
*/
public function OnLogHttpRequest(kEvent $event)
{
if ( defined('DBG_REQUEST_LOG') && DBG_REQUEST_LOG && $this->Application->LoggedIn() ) {
$log = $this->Application->log('HTTP_REQUEST')->addRequestData();
if ( !$log->write() ) {
trigger_error('Unable to log Http Request due disabled "System Log"', E_USER_WARNING);
}
}
}
/**
* Purges expired database cache entries.
*
* @param kEvent $event Event.
*
* @return void
*/
protected function OnPurgeExpiredDatabaseCacheScheduledTask(kEvent $event)
{
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'SystemCache
WHERE LifeTime > 0 AND Cached + LifeTime < ' . time();
$this->Conn->Query($sql);
}
+ /**
+ * Populates URL unit cache
+ *
+ * @param kEvent $event Event.
+ *
+ * @return void
+ */
+ protected function OnPopulateUrlUnitCacheScheduledTask(kEvent $event)
+ {
+ $sql = 'SELECT DISTINCT Prefixes
+ FROM ' . TABLE_PREFIX . 'CachedUrls';
+ $urls = $this->Conn->GetColIterator($sql);
+ $prefixes = array();
+
+ foreach ( $urls as $url_prefixes ) {
+ $url_prefixes = explode('|', trim($url_prefixes, '|'));
+
+ foreach ( $url_prefixes as $url_prefix ) {
+ $url_prefix = explode(':', $url_prefix);
+ $prefixes[$url_prefix[0]] = 1;
+ }
+ }
+
+ if ( $this->Application->isCachingType(CACHING_TYPE_MEMORY) ) {
+ $this->Application->setCache('cached_urls_unit_prefixes', array_keys($prefixes), 3600);
+ }
+ else {
+ $this->Application->setDBCache('cached_urls_unit_prefixes', serialize(array_keys($prefixes)), 3600);
+ }
+ }
+
}
class UnitConfigDecorator {
var $parentPath = Array ();
/**
* Decorates given array
*
* @param Array $var
* @param int $level
* @return string
*/
public function decorate($var, $level = 0)
{
$ret = '';
$deep_level = count($this->parentPath);
if ( $deep_level && ($this->parentPath[0] == 'Fields') ) {
$expand = $level < 2;
}
elseif ( $deep_level && ($this->parentPath[0] == 'Grids') ) {
if ( $deep_level == 3 && $this->parentPath[2] == 'Icons' ) {
$expand = false;
}
else {
$expand = $level < 4;
}
}
else {
$expand = $level == 0;
}
if ( is_array($var) ) {
$ret .= 'array(';
$prepend = $expand ? "\n" . str_repeat("\t", $level + 1) : '';
foreach ($var as $key => $value) {
array_push($this->parentPath, $key);
$ret .= $prepend . (is_string($key) ? "'" . $key . "'" : $key) . ' => ' . $this->decorate($value, $level + 1);
$ret .= ',' . ($expand ? '' : ' ');
array_pop($this->parentPath);
}
$prepend = $expand ? "\n" . str_repeat("\t", $level) : '';
if ( !$expand ) {
$ret = rtrim($ret, ', ');
}
$ret .= $prepend . ')';
}
else {
if ( is_null($var) ) {
$ret = 'null';
}
elseif ( is_string($var) ) {
$ret = "'" . $var . "'";
}
else {
$ret = $var;
}
}
return $ret;
}
}
Index: branches/5.2.x/core/units/admin/admin_config.php
===================================================================
--- branches/5.2.x/core/units/admin/admin_config.php (revision 16663)
+++ branches/5.2.x/core/units/admin/admin_config.php (revision 16664)
@@ -1,103 +1,104 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
$config = Array (
'Prefix' => 'adm',
'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
'EventHandlerClass' => Array ('class' => 'AdminEventsHandler', 'file' => 'admin_events_handler.php', 'build_event' => 'OnBuild'),
'TagProcessorClass' => Array ('class' => 'AdminTagProcessor', 'file' => 'admin_tag_processor.php', 'build_event' => 'OnBuild'),
'RegisterClasses' => Array (
Array ('pseudo' => 'UnitConfigDecorator', 'class' => 'UnitConfigDecorator', 'file' => 'admin_events_handler.php', 'build_event' => ''),
),
'QueryString' => Array (
1 => 'event',
),
'ScheduledTasks' => Array (
'optimize_performance' => Array ('EventName' => 'OnOptimizePerformance', 'RunSchedule' => '0 0 * * *'),
'purge_expired_database_cache' => Array ('EventName' => 'OnPurgeExpiredDatabaseCacheScheduledTask', 'RunSchedule' => '0 0,12 * * *'),
+ 'populate_url_unit_cache' => array('EventName' => 'OnPopulateUrlUnitCacheScheduledTask', 'RunSchedule' => '0 * * * *'),
),
'TitlePresets' => Array (
'tree_root' => Array ('format' => '!la_section_overview!'),
'tree_reports' => Array ('format' => '!la_section_overview!'),
'tree_system' => Array ('format' => '!la_section_overview!'),
'tree_tools' => Array ('format' => '!la_section_overview!'),
'system_tools' => Array ('format' => '!la_title_SystemTools!'),
'backup' => Array ('format' => '!la_performing_backup! - !la_Step! <span id="step_number"></span>'),
'import' => Array ('format' => '!la_performing_import! - !la_Step! <span id="step_number"></span>'),
'restore' => Array ('format' => '!la_performing_restore! - !la_Step! <span id="step_number"></span>'),
'server_info' => Array ('format' => '!la_tab_ServerInfo!'),
'sql_query' => Array ('format' => '!la_tab_QueryDB!'),
'no_permissions' => Array ('format' => '!la_title_NoPermissions!'),
'column_picker' => Array ('format' => '!la_title_ColumnPicker!'),
'csv_export' => Array ('format' => '!la_title_CSVExport!'),
'csv_import' => Array ('format' => '!la_title_CSVImport!'),
),
'PermSection' => Array ('main' => 'in-portal:service'),
'Sections' => Array (
'in-portal:root' => Array (
'parent' => null,
'icon' => 'site',
'label' => 'SITE_NAME',
'url' => Array ('t' => 'index', 'pass' => 'm'),
'permissions' => Array ('view'),
'priority' => 0,
'container' => true,
'type' => stTREE,
'icon_module' => 'core',
),
'in-portal:service' => Array (
'parent' => 'in-portal:tools',
'icon' => 'service',
'label' => 'la_tab_Service',
'url' => Array ('t' => 'tools/system_tools', 'pass' => 'm'),
'permissions' => Array ('view', 'edit'),
'priority' => 6,
'type' => stTREE,
),
),
'ListSQLs' => Array (
'' => '', // to prevent warning
),
'Fields' => Array (), // we need empty array because kernel doesn't use virtual fields else
'VirtualFields' => Array (
'ImportFile' => Array (
'type' => 'string',
'formatter' => 'kUploadFormatter', 'max_size' => MAX_UPLOAD_SIZE, // in Bytes !
'error_msgs' => Array (
'cant_open_file' => '!la_error_CantOpenFile!',
'no_matching_columns' => '!la_error_NoMatchingColumns!',
),
'file_types' => '*.csv', 'files_description' => '!la_hint_CSVFiles!',
'upload_dir' => '/system/import/', // relative to project's home
'multiple' => false, 'direct_links' => false,
'default' => null,
),
'Content' => Array ('type' => 'string', 'default' => ''),
),
);
Event Timeline
Log In to Comment