Index: branches/5.2.x/core/units/logs/session_logs/session_log_eh.php =================================================================== diff -u -r16513 -r16797 --- branches/5.2.x/core/units/logs/session_logs/session_log_eh.php (.../session_log_eh.php) (revision 16513) +++ branches/5.2.x/core/units/logs/session_logs/session_log_eh.php (.../session_log_eh.php) (revision 16797) @@ -1,6 +1,6 @@ Application->ConfigValue('UseChangeLog')) { - // don't use session log when change log is disabled - return ; + if ( (defined('IS_INSTALL') && IS_INSTALL) + || !$this->Application->ConfigValue('UseChangeLog') + ) { + // Don't use session log when installing OR change log is disabled. + return; } /** @var kDBItem $object */ @@ -35,7 +37,8 @@ 'SessionStart' => adodb_mktime(), 'IP' => $this->Application->getClientIp(), 'PortalUserId' => $this->Application->RecallVar('user_id'), - 'SessionId' => $this->Application->GetSID(), + 'SessionId' => $this->Application->GetSID(Session::PURPOSE_REFERENCE), + 'SessionKey' => $this->Application->GetSID(Session::PURPOSE_STORAGE), 'Status' => SESSION_LOG_ACTIVE, ); @@ -127,4 +130,4 @@ } } - } \ No newline at end of file + } Index: branches/5.2.x/core/units/users/users_event_handler.php =================================================================== diff -u -r16774 -r16797 --- branches/5.2.x/core/units/users/users_event_handler.php (.../users_event_handler.php) (revision 16774) +++ branches/5.2.x/core/units/users/users_event_handler.php (.../users_event_handler.php) (revision 16797) @@ -1,6 +1,6 @@ Conn->GetCol($sql); Index: branches/5.2.x/core/kernel/db/db_load_balancer.php =================================================================== diff -u -r16710 -r16797 --- branches/5.2.x/core/kernel/db/db_load_balancer.php (.../db_load_balancer.php) (revision 16710) +++ branches/5.2.x/core/kernel/db/db_load_balancer.php (.../db_load_balancer.php) (revision 16797) @@ -1,6 +1,6 @@ getMasterIndex(); } else { - $sid = isset($this->Application->Session) ? $this->Application->GetSID() : '9999999999999999999999'; - - if ( preg_match('/(^[ \t\r\n]*(ALTER|CREATE|DROP|RENAME|DELETE|DO|INSERT|LOAD|REPLACE|TRUNCATE|UPDATE))|ses_' . $sid . '/', $sql) ) { + if ( preg_match('/(^[ \t\r\n]*(ALTER|CREATE|DROP|RENAME|DELETE|DO|INSERT|LOAD|REPLACE|TRUNCATE|UPDATE))|ses_[\d]+/', $sql) ) { $index = $this->getMasterIndex(); } else { Index: branches/5.2.x/core/install.php =================================================================== diff -u -r16796 -r16797 --- branches/5.2.x/core/install.php (.../install.php) (revision 16796) +++ branches/5.2.x/core/install.php (.../install.php) (revision 16797) @@ -1,6 +1,6 @@ Conn->Query('RENAME TABLE ' . TABLE_PREFIX . 'SessionData TO ' . TABLE_PREFIX . 'UserSessionData'); } + $sessions_table_structure = $this->Conn->Query('DESCRIBE ' . TABLE_PREFIX . 'UserSessions', 'Field'); + + if ( !array_key_exists('SessionId', $sessions_table_structure) ) { + // Update to 5.2.2-B3 -> add missing columns before creating sessions. + $this->Conn->Query('ALTER TABLE ' . TABLE_PREFIX . 'UserSessions DROP INDEX `PRIMARY`'); + $this->Conn->Query( + 'ALTER TABLE ' . TABLE_PREFIX . 'UserSessions + ADD `SessionId` int NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST' + ); + $this->Conn->Query( + 'ALTER TABLE ' . TABLE_PREFIX . 'UserSessions + CHANGE `SessionKey` `SessionKey` char(64) NOT NULL DEFAULT ""' + ); + $this->Conn->Query( + 'ALTER TABLE ' . TABLE_PREFIX . 'UserSessions + ADD UNIQUE INDEX `SessionKey` (`SessionKey`) USING BTREE' + ); + $this->Conn->Query( + 'ALTER TABLE ' . TABLE_PREFIX . 'UserSessionData + CHANGE `SessionKey` `SessionId` int unsigned NOT NULL DEFAULT "0"' + ); + } + $next_preset = $this->Application->GetVar('next_preset'); if ($next_preset !== false) { /** @var UserHelper $user_helper */ Index: branches/5.2.x/core/kernel/utility/logger.php =================================================================== diff -u -r16754 -r16797 --- branches/5.2.x/core/kernel/utility/logger.php (.../logger.php) (revision 16754) +++ branches/5.2.x/core/kernel/utility/logger.php (.../logger.php) (revision 16797) @@ -1,6 +1,6 @@ php_sapi_name() == 'cli' ? implode(' ', $GLOBALS['argv']) : $_SERVER['REQUEST_URI'], 'LogUserId' => USER_GUEST, 'IpAddress' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', - 'LogSessionKey' => 0, + 'LogSessionKey' => '', 'LogProcessId' => getmypid(), 'LogUserData' => '', 'LogNotificationStatus' => self::LNS_DISABLED, @@ -352,7 +352,7 @@ if ( $this->Application->InitDone ) { $this->_logRecord['LogUserId'] = $this->Application->RecallVar('user_id'); - $this->_logRecord['LogSessionKey'] = $this->Application->GetSID(); + $this->_logRecord['LogSessionKey'] = $this->Application->GetSID(Session::PURPOSE_STORAGE); $this->_logRecord['IpAddress'] = $this->Application->getClientIp(); } Index: branches/5.2.x/core/units/logs/system_logs/system_logs_config.php =================================================================== diff -u -r16754 -r16797 --- branches/5.2.x/core/units/logs/system_logs/system_logs_config.php (.../system_logs_config.php) (revision 16754) +++ branches/5.2.x/core/units/logs/system_logs/system_logs_config.php (.../system_logs_config.php) (revision 16797) @@ -1,6 +1,6 @@ 1, 'default' => 0 ), 'IpAddress' => Array ('type' => 'string', 'max_len' => 15, 'not_null' => 1, 'default' => ''), - 'LogSessionKey' => Array ('type' => 'int', 'default' => NULL), + 'LogSessionKey' => Array ('type' => 'string', 'max_len' => 64, 'not_null' => 1, 'default' => ''), 'LogSessionData' => Array ('type' => 'string', 'default' => NULL), 'LogBacktrace' => Array ('type' => 'string', 'default' => NULL), 'LogSourceFilename' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''), Index: branches/5.2.x/core/kernel/db/db_event_handler.php =================================================================== diff -u -r16781 -r16797 --- branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 16781) +++ branches/5.2.x/core/kernel/db/db_event_handler.php (.../db_event_handler.php) (revision 16797) @@ -1,6 +1,6 @@ getObject(); - $edit_mark = rtrim($this->Application->GetSID() . '_' . $this->Application->GetTopmostWid($event->Prefix), '_'); + if ( $object->IsTempTable() ) { + $session_id = $this->Application->GetSID(Session::PURPOSE_REFERENCE); + $edit_mark = rtrim($session_id . '_' . $this->Application->GetTopmostWid($event->Prefix), '_'); + } + else { + $edit_mark = ''; + } // add search filter $filter_data = $this->Application->RecallVar($event->getPrefixSpecial() . '_search_filter'); Index: branches/5.2.x/core/kernel/session/session.php =================================================================== diff -u -r16788 -r16797 --- branches/5.2.x/core/kernel/session/session.php (.../session.php) (revision 16788) +++ branches/5.2.x/core/kernel/session/session.php (.../session.php) (revision 16797) @@ -1,6 +1,6 @@ SID; + if ( $purpose === self::PURPOSE_TRANSPORT ) { + return $this->SID; + } + + if ( $purpose === self::PURPOSE_STORAGE ) { + return $this->Storage->createSignatureFromSID($this->SID); + } + + if ( $purpose === self::PURPOSE_REFERENCE ) { + return $this->Storage->GetID(); + } + + throw new RuntimeException('The "' . $purpose . '" purpose is not supported.'); } /** * Generates new session id * - * @return int - * @access private + * @return string */ - function GenerateSID() + protected function GenerateSID() { - $this->setSID( - SecurityGenerator::generateNumber(100000000, 999999999) - ->resolveForPersisting(TABLE_PREFIX . 'UserSessions', 'SessionKey') - ); + $promise = SecurityGenerator::generateBytes(16); + $promise->asSignature()->resolveForPersisting(TABLE_PREFIX . 'UserSessions', 'SessionKey'); + $new_sid = $promise->asValue()->resolve(); + $this->setSID($new_sid); + return $this->SID; } Index: branches/5.2.x/core/units/helpers/search_helper.php =================================================================== diff -u -r16692 -r16797 --- branches/5.2.x/core/units/helpers/search_helper.php (.../search_helper.php) (revision 16692) +++ branches/5.2.x/core/units/helpers/search_helper.php (.../search_helper.php) (revision 16797) @@ -1,6 +1,6 @@ Application->GetSID().'(_[\d]+){0,1}_edit_(.*)/', $table_name, $regs); - if ($is_temp_table) { - $table_name = $regs[1].TABLE_PREFIX.'ses_'.EDIT_MARK.'_edit_'.$regs[3]; // edit_mark will be replaced with sid[_main_wid] in AddFilters + // Replace wid inside table name to WID_MARK constant value. + $is_temp_table = preg_match( + '/(.*)' . TABLE_PREFIX . 'ses_[\d]+(_[\d]+){0,1}_edit_(.*)/', + $table_name, + $regs + ); + + // The EDIT_MARK will be replaced with sid[_main_wid] in AddFilters. + if ( $is_temp_table ) { + $table_name = $regs[1] . TABLE_PREFIX . 'ses_' . EDIT_MARK . '_edit_' . $regs[3]; } return Array ($field_name, $field_type, $table_name, $sql_filter_type); @@ -855,7 +861,21 @@ */ public function getSearchTable() { - return TABLE_PREFIX . 'ses_' . $this->Application->GetSID() . '_' . TABLE_PREFIX . 'Search'; + try { + $sid = $this->Application->GetSID(Session::PURPOSE_REFERENCE); + } + catch ( RuntimeException $e ) { + // 1. Put some real variable into session, or otherwise it won't even save to the database. + $this->Application->StoreVar('search_made', 'yes'); + + // 2. Create session on they fly to store search results. + $this->Application->Session->SaveData(); + + // 3. Get ID of the created session. + $sid = $this->Application->GetSID(Session::PURPOSE_REFERENCE); + } + + return TABLE_PREFIX . 'ses_' . $sid . '_' . TABLE_PREFIX . 'Search'; } } Index: branches/5.2.x/core/admin_templates/logs/system_logs/system_log_list.tpl =================================================================== diff -u -r15552 -r16797 --- branches/5.2.x/core/admin_templates/logs/system_logs/system_log_list.tpl (.../system_log_list.tpl) (revision 15552) +++ branches/5.2.x/core/admin_templates/logs/system_logs/system_log_list.tpl (.../system_log_list.tpl) (revision 16797) @@ -76,6 +76,10 @@ padding-left: 25px; font-size: 11px; } + + tr.grid-data-row td.LogSessionKey { + text-overflow: ellipsis; + } Index: branches/5.2.x/core/kernel/utility/debugger.php =================================================================== diff -u -r16728 -r16797 --- branches/5.2.x/core/kernel/utility/debugger.php (.../debugger.php) (revision 16728) +++ branches/5.2.x/core/kernel/utility/debugger.php (.../debugger.php) (revision 16797) @@ -1,6 +1,6 @@ rowSeparator = '@' . (/*is_object($application->Factory) &&*/ $application->InitDone ? $application->GetSID() : 0) . '@'; -// $this->rowSeparator = '@' . rand(0, 100000) . '@'; + /* + * Don't use "Session::PURPOSE_REFERENCE" below, because + * until session is saved to the db there is no reference. + */ + if ( $application->InitDone ) { + $this->rowSeparator = '@' . $application->GetSID(Session::PURPOSE_STORAGE) . '@'; + } + else { + $this->rowSeparator = '@0@'; + } // include debugger files from this url $reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/'; Index: branches/5.2.x/core/kernel/application.php =================================================================== diff -u -r16781 -r16797 --- branches/5.2.x/core/kernel/application.php (.../application.php) (revision 16781) +++ branches/5.2.x/core/kernel/application.php (.../application.php) (revision 16797) @@ -1,6 +1,6 @@ recallObject('Session'); - return $session->GetID(); + return $session->GetID($purpose); } /** @@ -2757,17 +2758,17 @@ /** * Builds temporary table prefix based on given window id * - * @param string $wid + * @param string $wid Window ID. + * * @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_'; + return TABLE_PREFIX . 'ses_' . $this->GetSID(Session::PURPOSE_REFERENCE) . ($wid ? '_' . $wid : '') . '_edit_'; } /** @@ -2782,7 +2783,7 @@ static $cache = Array (); if ( !array_key_exists($table, $cache) ) { - $cache[$table] = preg_match('/' . TABLE_PREFIX . 'ses_' . $this->GetSID() . '(_[\d]+){0,1}_edit_(.*)/', $table); + $cache[$table] = $table !== $this->GetLiveName($table); } return (bool)$cache[$table]; @@ -2829,13 +2830,12 @@ */ 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]; + if ( preg_match('/' . TABLE_PREFIX . 'ses_([\d]+)(_[\d]+){0,1}_edit_(.*)/', $temp_table, $rets) ) { + // Cut wid from table end if any. + return $rets[3]; } - else { - return $temp_table; - } + + return $temp_table; } /** Index: branches/5.2.x/core/kernel/session/inp_session_storage.php =================================================================== diff -u -r15569 -r16797 --- branches/5.2.x/core/kernel/session/inp_session_storage.php (.../inp_session_storage.php) (revision 15569) +++ branches/5.2.x/core/kernel/session/inp_session_storage.php (.../inp_session_storage.php) (revision 16797) @@ -1,7 +1,7 @@ TableName = TABLE_PREFIX.'UserSessions'; $this->SessionDataTable = TABLE_PREFIX.'UserSessionData'; - $this->IDField = 'SessionKey'; + $this->IDField = 'SessionId'; + $this->sessionKeyField = 'SessionKey'; $this->TimestampField = 'LastAccessed'; $this->DataValueField = 'VariableValue'; $this->DataVarField = 'VariableName'; @@ -94,4 +95,4 @@ } } } -} \ No newline at end of file +} Index: branches/5.2.x/core/kernel/utility/temp_handler.php =================================================================== diff -u -r16770 -r16797 --- branches/5.2.x/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 16770) +++ branches/5.2.x/core/kernel/utility/temp_handler.php (.../temp_handler.php) (revision 16797) @@ -1,6 +1,6 @@ _getSeparateConnection(); $sleep_count = 0; @@ -1034,7 +1034,7 @@ protected function createSemaphore(IDBConnection $conn, array $master_ids) { $fields_hash = array( - 'SessionKey' => $this->Application->GetSID(), + 'SessionKey' => $this->Application->GetSID(Session::PURPOSE_STORAGE), 'Timestamp' => adodb_mktime(), 'MainPrefix' => $this->Tables['Prefix'], 'MainIDs' => implode(',', $master_ids), @@ -1073,7 +1073,7 @@ $tables = $this->Conn->GetCol('SHOW TABLES'); $mask_edit_table = '/' . TABLE_PREFIX . 'ses_(.*)_edit_' . $this->MasterTable . '$/'; - $my_sid = $this->Application->GetSID(); + $my_sid = $this->Application->GetSID(Session::PURPOSE_REFERENCE); $my_wid = $this->Application->GetVar('m_wid'); $ids = implode(',', isset($ids) ? $ids : $this->Tables['IDs']); $sids = Array (); @@ -1121,7 +1121,7 @@ ), \' IP: \', s.IpAddress, \'\') FROM ' . TABLE_PREFIX . 'UserSessions AS s LEFT JOIN ' . TABLE_PREFIX . 'Users AS u ON u.PortalUserId = s.PortalUserId - WHERE s.SessionKey IN (' . implode(',', $sids) . ')'; + WHERE s.SessionId IN (' . implode(',', $sids) . ')'; $users = $this->Conn->GetCol($sql); if ($users) { Index: branches/5.2.x/core/units/logs/session_logs/session_logs_config.php =================================================================== diff -u -r16388 -r16797 --- branches/5.2.x/core/units/logs/session_logs/session_logs_config.php (.../session_logs_config.php) (revision 16388) +++ branches/5.2.x/core/units/logs/session_logs/session_logs_config.php (.../session_logs_config.php) (revision 16797) @@ -1,6 +1,6 @@ Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'PortalUserId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), 'SessionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0), + 'SessionKey' => Array ('type' => 'string', 'max_len' => 64, 'not_null' => 1, 'default' => ''), 'Status' => Array ( 'type' => 'int', 'formatter' => 'kOptionsFormatter', 'options'=> Array (0 => 'la_opt_Active', 1 => 'la_opt_LoggedOut', 2 => 'la_opt_Expired'), @@ -136,6 +137,7 @@ 'Icons' => Array ('default' => 'icon16_item.png'), 'Fields' => Array ( 'SessionLogId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70, ), + 'SessionKey' => Array ('title' => 'column:la_fld_LogSessionKey', 'filter_block' => 'grid_like_filter', 'width' => 120, ), 'PortalUserId' => Array ('title' => 'la_col_PortalUserId', 'filter_block' => 'grid_range_filter', 'width' => 70, ), 'UserLogin' => Array ('title' => 'column:la_fld_Username', 'filter_block' => 'grid_like_filter', 'width' => 100, ), 'UserFirstName' => Array ('title' => 'column:la_fld_FirstName', 'filter_block' => 'grid_like_filter', 'width' => 120, ), @@ -150,4 +152,4 @@ ), ), ), -); \ No newline at end of file +); Index: branches/5.2.x/admin/system_presets/simple/session_logs_session-log.php =================================================================== diff -u -r15024 -r16797 --- branches/5.2.x/admin/system_presets/simple/session_logs_session-log.php (.../session_logs_session-log.php) (revision 15024) +++ branches/5.2.x/admin/system_presets/simple/session_logs_session-log.php (.../session_logs_session-log.php) (revision 16797) @@ -20,7 +20,7 @@ // fields to hide $hidden_fields = Array ( - /*'SessionLogId', 'PortalUserId', 'SessionId', 'Status', 'SessionStart', 'SessionEnd', 'IP', 'AffectedItems',*/ + /*'SessionLogId', 'PortalUserId', 'SessionKey', 'Status', 'SessionStart', 'SessionEnd', 'IP', 'AffectedItems',*/ ); // virtual fields to hide @@ -30,7 +30,7 @@ // fields to make required $required_fields = Array ( - /*'SessionLogId', 'PortalUserId', 'SessionId', 'Status', 'SessionStart', 'SessionEnd', 'IP', 'AffectedItems',*/ + /*'SessionLogId', 'PortalUserId', 'SessionKey', 'Status', 'SessionStart', 'SessionEnd', 'IP', 'AffectedItems',*/ ); // virtual fields to make required @@ -46,6 +46,6 @@ // hide columns in grids $hide_columns = Array ( // currently not in user - 'Default' => Array (/* 'SessionLogId', 'PortalUserId', 'SessionId', 'Status', 'SessionStart', 'SessionEnd' + 'Default' => Array (/* 'SessionLogId', 'PortalUserId', 'SessionKey', 'Status', 'SessionStart', 'SessionEnd' , 'IP', 'Duration', 'AffectedItems', */), - ); \ No newline at end of file + ); Index: branches/5.2.x/core/units/admin/admin_events_handler.php =================================================================== diff -u -r16770 -r16797 --- branches/5.2.x/core/units/admin/admin_events_handler.php (.../admin_events_handler.php) (revision 16770) +++ branches/5.2.x/core/units/admin/admin_events_handler.php (.../admin_events_handler.php) (revision 16797) @@ -1,6 +1,6 @@ Array ('self' => true), 'OnClosePopup' => Array ('self' => true), 'OnSaveSetting' => Array ('self' => true), - 'OnDropTempTablesByWID' => Array ('self' => true), 'OnProcessSelected' => Array ('self' => true), // allow CSV import file upload ); @@ -79,7 +78,7 @@ $perm_value = $this->Application->CheckPermission($tools_events[$event->Name]); } - if ( $event->Name == 'OnSaveMenuFrameWidth' ) { + if ( $event->Name == 'OnSaveMenuFrameWidth' || $event->Name == 'OnDropTempTablesByWID' ) { $perm_value = $this->Application->isAdminUser; } @@ -753,7 +752,7 @@ */ protected function OnDropTempTablesByWID(kEvent $event) { - $sid = $this->Application->GetSID(); + $sid = $this->Application->GetSID(Session::PURPOSE_REFERENCE); $wid = $this->Application->GetVar('m_wid'); $tables = $this->Conn->GetCol('SHOW TABLES'); $mask_edit_table = '/' . TABLE_PREFIX . 'ses_' . $sid . '_' . $wid . '_edit_(.*)$/'; @@ -1122,7 +1121,7 @@ /** * [SCHEDULED TASK] - * 1. Delete all Debug files from system/.restricted folder (format debug_@977827436@.txt) + * 1. Delete all Debug files from system/.restricted folder (format debug_@f353wfsds43g5...@.txt) * 2. Run MySQL OPTIMIZE SQL one by one on all In-Portal tables (found by prefix). * * @param kEvent $event @@ -1141,9 +1140,9 @@ $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 + foreach ( $files as $file_name ) { + if ( !preg_match('#^debug_@([^@]+)@.txt$#', $file_name, $matches) ) { + // Not debug file. continue; } Index: branches/5.2.x/core/units/helpers/curl_helper.php =================================================================== diff -u -r16790 -r16797 --- branches/5.2.x/core/units/helpers/curl_helper.php (.../curl_helper.php) (revision 16790) +++ branches/5.2.x/core/units/helpers/curl_helper.php (.../curl_helper.php) (revision 16797) @@ -1,6 +1,6 @@ $_SERVER['REQUEST_URI'], 'RequestUrl' => $url, 'PortalUserId' => $this->Application->RecallVar('user_id'), - 'SessionKey' => $this->Application->GetSID(), + 'SessionKey' => $this->Application->GetSID(Session::PURPOSE_STORAGE), 'IsAdmin' => $this->Application->isAdminUser ? 1 : 0, 'PageData' => implode("\n", $page_data), 'RequestData' => $this->requestData, Index: branches/5.2.x/core/install/upgrades.php =================================================================== diff -u -r16779 -r16797 --- branches/5.2.x/core/install/upgrades.php (.../upgrades.php) (revision 16779) +++ branches/5.2.x/core/install/upgrades.php (.../upgrades.php) (revision 16797) @@ -1,6 +1,6 @@ migrateExportUserPresets(); + $this->changeSessionKeyFormat(); } if ( $mode != 'before' ) { @@ -2454,4 +2455,116 @@ $this->Conn->Query($sql); } + /** + * Transforms the way, how "SessionKey" is stored in the database. + * + * @return void + */ + protected function changeSessionKeyFormat() + { + $sql = 'SELECT SessionId, SessionKey + FROM ' . TABLE_PREFIX . 'UserSessions'; + $session_mapping = $this->Conn->GetCol($sql, 'SessionKey'); + + // 1. Replace session key with session id. + foreach ( $session_mapping as $session_key => $session_id ) { + // Ignore already converted data. + if ( !is_numeric($session_key) ) { + continue; + } + + $this->Conn->doUpdate( + array('SessionId' => $session_id), + TABLE_PREFIX . 'UserSessionData', + 'SessionId = ' . $session_key + ); + + $this->Conn->doUpdate( + array('SessionId' => $session_id), + TABLE_PREFIX . 'UserSessionLogs', + 'SessionId = ' . $session_key + ); + } + + // 2. Rename temporary tables. + $tables = $this->Conn->GetCol('SHOW TABLES LIKE "%' . TABLE_PREFIX . 'ses_%"'); + $mask_edit_table = '/' . TABLE_PREFIX . 'ses_(.*)_edit_(.*)/'; + $mask_search_table = '/' . TABLE_PREFIX . 'ses_(.*?)_(.*)/'; + + foreach ( $tables as $table ) { + if ( preg_match($mask_edit_table, $table, $rets) || preg_match($mask_search_table, $table, $rets) ) { + $old_table_name_fragment = $rets[1]; + $new_table_name_fragment = $this->replaceSessionKeyWithSessionId( + $old_table_name_fragment, + $session_mapping + ); + + if ( $old_table_name_fragment === $new_table_name_fragment ) { + continue; + } + + $new_table = str_replace( + '_' . $old_table_name_fragment . '_', + '_' . $new_table_name_fragment . '_', + $table + ); + + $this->Conn->Query('RENAME TABLE `' . $table . '` TO `' . $new_table . '`'); + } + } + + // 3. Replace plain-text session key storage with hashed one. + /** @var SecurityEncrypter $encrypter */ + $encrypter = $this->Application->recallObject('SecurityEncrypter'); + + $tables_with_session_keys = array( + TABLE_PREFIX . 'UserSessions' => array('SessionKey', 'SessionId'), + TABLE_PREFIX . 'Semaphores' => array('SessionKey', 'SemaphoreId'), + TABLE_PREFIX . 'UserSessionLogs' => array('SessionKey', 'SessionLogId'), + TABLE_PREFIX . 'CurlLog' => array('SessionKey', 'LogId'), + TABLE_PREFIX . 'SystemLog' => array('LogSessionKey', 'LogId'), + ); + + foreach ( $tables_with_session_keys as $table => $fields ) { + list($session_key_field, $id_field) = $fields; + + $sql = 'SELECT ' . $session_key_field . ', ' . $id_field . ' + FROM ' . $table; + $table_records = $this->Conn->GetCol($sql, $id_field); + + foreach ( $table_records as $record_id => $session_key ) { + // Ignore already converted data. + if ( !is_numeric($session_key) ) { + continue; + } + + $this->Conn->doUpdate( + array($session_key_field => $encrypter->createSignature($session_key)), + $table, + $id_field . ' = ' . $record_id + ); + } + } + } + + /** + * Replaces session key with session id in the given table name fragment. + * + * @param string $table_name_fragment Table name fragment. + * @param array $session_mapping Session mapping. + * + * @return string + */ + protected function replaceSessionKeyWithSessionId($table_name_fragment, array $session_mapping) + { + $table_name_fragment_parts = explode('_', $table_name_fragment); + $session_key = $table_name_fragment_parts[0]; + + if ( array_key_exists($session_key, $session_mapping) ) { + $table_name_fragment_parts[0] = $session_mapping[$session_key]; + } + + return implode('_', $table_name_fragment_parts); + } + } Index: branches/5.2.x/core/install/upgrades.sql =================================================================== diff -u -r16779 -r16797 --- branches/5.2.x/core/install/upgrades.sql (.../upgrades.sql) (revision 16779) +++ branches/5.2.x/core/install/upgrades.sql (.../upgrades.sql) (revision 16797) @@ -2980,3 +2980,9 @@ PresetData text NULL DEFAULT NULL, PRIMARY KEY (PortalUserId, ItemPrefix, PresetName) ); + +ALTER TABLE Semaphores CHANGE `SessionKey` `SessionKey` char(64) NOT NULL DEFAULT ''; +ALTER TABLE UserSessionLogs ADD COLUMN `SessionKey` char(64) NOT NULL DEFAULT '' AFTER `SessionId`; +UPDATE UserSessionLogs SET SessionKey = SessionId; +ALTER TABLE CurlLog CHANGE `SessionKey` `SessionKey` char(64) NOT NULL DEFAULT ''; +ALTER TABLE SystemLog CHANGE `LogSessionKey` `LogSessionKey` char(64) NOT NULL DEFAULT ''; Index: branches/5.2.x/core/kernel/session/session_storage.php =================================================================== diff -u -r16793 -r16797 --- branches/5.2.x/core/kernel/session/session_storage.php (.../session_storage.php) (revision 16793) +++ branches/5.2.x/core/kernel/session/session_storage.php (.../session_storage.php) (revision 16797) @@ -1,7 +1,7 @@ TableName = 'sessions'; - $this->IDField = 'sid'; + $this->IDField = 'session_id'; + $this->sessionKeyField = 'sid'; $this->TimestampField = 'expire'; $this->SessionDataTable = 'SessionData'; $this->DataValueField = 'value'; $this->DataVarField = 'var'; } /** + * @inheritDoc + * + * @throws RuntimeException When session isn't found in the database. + */ + public function GetID() + { + $session_id = $this->GetField($this->IDField); + + if ( $session_id === null ) { + throw new RuntimeException( + 'Session with "' . $this->Session->GetID(Session::PURPOSE_STORAGE) . '" key not found in the database.' + ); + } + + return $session_id; + } + + /** * Sets reference to session * * @param Session $session @@ -100,7 +126,8 @@ function GetSessionDefaults() { $fields_hash = Array ( - $this->IDField => $this->Session->SID, + $this->IDField => null, + $this->sessionKeyField => $this->Session->GetID(Session::PURPOSE_STORAGE), $this->TimestampField => $this->Session->Expiration, ); @@ -135,6 +162,7 @@ if ( $to_database ) { $this->Conn->doInsert($fields_hash, $this->TableName); + $fields_hash[$this->IDField] = $this->Conn->getInsertID(); } foreach ($fields_hash as $field_name => $field_value) { @@ -150,23 +178,27 @@ function DeleteSession() { - $this->DeleteSessions( Array ($this->Session->SID), SESSION_LOG_LOGGED_OUT ); + $this->DeleteSessions( Array ($this->GetID()), SESSION_LOG_LOGGED_OUT ); $this->DirectVars = $this->ChangedDirectVars = $this->OriginalData = Array(); } function UpdateSession($timeout = 0) { $this->SetField($this->TimestampField, $this->Session->Expiration); - $query = ' UPDATE '.$this->TableName.' SET '.$this->TimestampField.' = '.$this->Session->Expiration.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($this->Session->SID); - $this->Conn->Query($query); + + $this->Conn->doUpdate( + array($this->TimestampField => $this->Session->Expiration), + $this->TableName, + $this->IDField . ' = ' . $this->GetID() + ); } function LocateSession($sid) { $sql = 'SELECT * FROM ' . $this->TableName . ' - WHERE ' . $this->IDField . ' = ' . $this->Conn->qstr($sid); + WHERE ' . $this->sessionKeyField . ' = ' . $this->Conn->qstr($this->createSignatureFromSID($sid)); $result = $this->Conn->GetRow($sql); if ($result === false) { @@ -190,16 +222,33 @@ return true; } + /** + * Creates signature from SID. + * + * @param string $sid SID. + * + * @return string + */ + public function createSignatureFromSID($sid) + { + /** @var SecurityEncrypter $encrypter */ + $encrypter = $this->Application->recallObject('SecurityEncrypter'); + + return $encrypter->createSignature($sid); + } + function GetExpiration() { return $this->Expiration; } function LoadData() { - $query = 'SELECT '.$this->DataValueField.','.$this->DataVarField.' FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($this->Session->SID); + $sql = 'SELECT ' . $this->DataValueField . ',' . $this->DataVarField . ' + FROM ' . $this->SessionDataTable . ' + WHERE ' . $this->IDField . ' = ' . $this->GetID(); + $this->OriginalData = $this->Conn->GetCol($sql, $this->DataVarField); - $this->OriginalData = $this->Conn->GetCol($query, $this->DataVarField); return $this->OriginalData; } @@ -212,19 +261,18 @@ */ function GetField($var_name, $default = false) { - return isset($this->DirectVars[$var_name]) ? $this->DirectVars[$var_name] : $default; - //return $this->Conn->GetOne('SELECT '.$var_name.' FROM '.$this->TableName.' WHERE `'.$this->IDField.'` = '.$this->Conn->qstr($this->Session->GetID()) ); + return array_key_exists($var_name, $this->DirectVars) ? $this->DirectVars[$var_name] : $default; } function SetField($var_name, $value) { - $value_changed = !isset($this->DirectVars[$var_name]) || ($this->DirectVars[$var_name] != $value); - if ($value_changed) { + $value_changed = !array_key_exists($var_name, $this->DirectVars) || ($this->DirectVars[$var_name] != $value); + + if ( $value_changed ) { $this->DirectVars[$var_name] = $value; $this->ChangedDirectVars[] = $var_name; $this->ChangedDirectVars = array_unique($this->ChangedDirectVars); } - //return $this->Conn->Query('UPDATE '.$this->TableName.' SET '.$var_name.' = '.$this->Conn->qstr($value).' WHERE '.$this->IDField.' = '.$this->Conn->qstr($this->Session->GetID()) ); } /** @@ -235,9 +283,11 @@ */ public function SaveData() { - if ( !$this->Session->SID ) { - // can't save without sid - return ; + $session_id = $this->GetID(); + + if ( !$session_id ) { + // Can't save without sid. + return; } $replace = ''; @@ -248,7 +298,7 @@ continue; //skip unchanged session data } else { - $replace .= sprintf("(%s, %s, %s),", $this->Conn->qstr($this->Session->SID), $this->Conn->qstr($key), $this->Conn->qstr($value)); + $replace .= sprintf('(%s, %s, %s),', $session_id, $this->Conn->qstr($key), $this->Conn->qstr($value)); } } @@ -269,18 +319,22 @@ $query = ' UPDATE ' . $this->TableName . ' SET ' . implode(',', $changes) . ' - WHERE ' . $this->IDField . ' = ' . $this->Conn->qstr($this->Session->GetID()); + WHERE ' . $this->IDField . ' = ' . $session_id; $this->Conn->Query($query); $this->ChangedDirectVars = array(); } } function RemoveFromData($var) { - if ($this->Session->SessionSet) { - // only, when session is stored in database + if ( $this->Session->SessionSet ) { + // Only, when session is stored in database. + $where_clause = array( + $this->IDField . ' = ' . $this->GetID(), + $this->DataVarField . ' = ' . $this->Conn->qstr($var), + ); $sql = 'DELETE FROM ' . $this->SessionDataTable . ' - WHERE ' . $this->IDField . ' = ' . $this->Conn->qstr($this->Session->SID) . ' AND ' . $this->DataVarField . ' = ' . $this->Conn->qstr($var); + WHERE (' . implode(') AND (', $where_clause) . ')'; $this->Conn->Query($sql); } @@ -331,18 +385,26 @@ } $where_clause = ' WHERE ' . $this->IDField . ' IN (' . implode(',', $session_ids) . ')'; + + $sql = 'SELECT SessionKey + FROM ' . $this->TableName . + $where_clause; + $session_keys = $this->Conn->GetCol($sql); + $sql = 'DELETE FROM ' . $this->SessionDataTable . $where_clause; $this->Conn->Query($sql); $sql = 'DELETE FROM ' . $this->TableName . $where_clause; $this->Conn->Query($sql); - // delete debugger ouputs left of deleted sessions - foreach ($session_ids as $session_id) { - $debug_file = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/cache') . '/debug_@' . $session_id . '@.txt'; - if (file_exists($debug_file)) { + // Delete debugger outputs left of deleted sessions. + foreach ( $session_keys as $session_key ) { + $debug_file = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/cache'); + $debug_file .= '/debug_@' . $session_key . '@.txt'; + + if ( file_exists($debug_file) ) { @unlink($debug_file); - } + } } } Index: branches/5.2.x/core/admin_templates/logs/session_logs/session_log_list.tpl =================================================================== diff -u -r14244 -r16797 --- branches/5.2.x/core/admin_templates/logs/session_logs/session_log_list.tpl (.../session_log_list.tpl) (revision 14244) +++ branches/5.2.x/core/admin_templates/logs/session_logs/session_log_list.tpl (.../session_log_list.tpl) (revision 16797) @@ -57,6 +57,10 @@ tr.row-expired td { color: #555; } + + tr.grid-data-row td.SessionKey { + text-overflow: ellipsis; + } @@ -83,4 +87,4 @@ Grids['session-log'].SetDependantToolbarButtons( new Array('delete') ); - \ No newline at end of file + Index: branches/5.2.x/core/kernel/utility/debugger/debugger_responce.php =================================================================== diff -u -r15588 -r16797 --- branches/5.2.x/core/kernel/utility/debugger/debugger_responce.php (.../debugger_responce.php) (revision 15588) +++ branches/5.2.x/core/kernel/utility/debugger/debugger_responce.php (.../debugger_responce.php) (revision 16797) @@ -1,6 +1,6 @@