Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1051390
session_storage.php
No One
Temporary
Actions
Download 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
Thu, Jul 3, 11:10 PM
Size
15 KB
Mime Type
text/x-php
Expires
Sat, Jul 5, 11:10 PM (1 d, 4 h)
Engine
blob
Format
Raw Data
Handle
679262
Attached To
rINP In-Portal
session_storage.php
View Options
<?php
/**
* @version $Id: session_storage.php 16813 2024-10-28 11:20:55Z alex $
* @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!'
);
/**
* Implements Session Store in the Database
*
*/
class
SessionStorage
extends
kDBBase
{
/**
* Reference to session
*
* @var Session
* @access protected
*/
protected
$Session
=
null
;
var
$Expiration
;
var
$SessionTimeout
=
0
;
var
$DirectVars
=
Array
();
var
$ChangedDirectVars
=
Array
();
var
$PersistentVars
=
Array
();
/**
* Default persistent vars
*
* @var array
*/
protected
$defaultPersistentVars
=
array
();
var
$OriginalData
=
Array
();
/**
* Session key field.
*
* @var string
*/
protected
$sessionKeyField
;
var
$TimestampField
;
var
$SessionDataTable
;
var
$DataValueField
;
var
$DataVarField
;
public
function
Init
(
$prefix
,
$special
)
{
parent
::
Init
(
$prefix
,
$special
);
$this
->
TableName
=
'sessions'
;
$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
*/
public
function
setSession
(&
$session
)
{
$this
->
Session
=&
$session
;
$this
->
SessionTimeout
=
$session
->
SessionTimeout
;
}
/**
* Calculates browser signature
*
* @return string
*/
function
_getBrowserSignature
()
{
$signature_parts
=
Array
(
'HTTP_USER_AGENT'
,
'SERVER_PROTOCOL'
,
'HTTP_ACCEPT_CHARSET'
,
'HTTP_ACCEPT_ENCODING'
,
'HTTP_ACCEPT_LANGUAGE'
);
$ret
=
''
;
foreach
(
$signature_parts
as
$signature_part
)
{
if
(
array_key_exists
(
$signature_part
,
$_SERVER
))
{
$ret
.=
'&|&'
.
$_SERVER
[
$signature_part
];
}
}
return
md5
(
substr
(
$ret
,
3
)
);
}
function
GetSessionDefaults
()
{
$fields_hash
=
Array
(
$this
->
IDField
=>
null
,
$this
->
sessionKeyField
=>
$this
->
Session
->
GetID
(
Session
::
PURPOSE_STORAGE
),
$this
->
TimestampField
=>
$this
->
Session
->
Expiration
,
);
if
(!
defined
(
'IS_INSTALL'
)
||
!
IS_INSTALL
)
{
// this column was added only in 5.0.1 version,
// so accessing it while database is not upgraded
// will result in admin's inability to login inside
// installator
$fields_hash
[
'BrowserSignature'
]
=
$this
->
_getBrowserSignature
();
}
// default values + values set during this script run
return
array_merge
(
$fields_hash
,
$this
->
DirectVars
);
}
/**
* Stores session to database
*
* @param bool $to_database
*
* @return void
* @access public
*/
public
function
StoreSession
(
$to_database
=
true
)
{
if
(
defined
(
'IS_INSTALL'
)
&&
IS_INSTALL
&&
$to_database
&&
!
$this
->
Application
->
TableFound
(
$this
->
TableName
,
true
)
)
{
return
;
}
$fields_hash
=
$this
->
GetSessionDefaults
();
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
)
{
$this
->
SetField
(
$field_name
,
$field_value
);
}
// Reset change flags, because session is already saved to the database.
$this
->
ChangedDirectVars
=
array
();
// ensure user groups are stored in a way, that kPermissionsHelper::CheckUserPermission can understand
$this
->
Session
->
StoreVar
(
'UserGroups'
,
$this
->
GetField
(
'GroupList'
),
!
$to_database
);
}
function
DeleteSession
()
{
try
{
$this
->
DeleteSessions
(
array
(
$this
->
GetID
()),
SESSION_LOG_LOGGED_OUT
);
}
catch
(
RuntimeException
$e
)
{
// Session is deleted from the database already by the time we attempt to delete it.
}
$this
->
DirectVars
=
$this
->
ChangedDirectVars
=
$this
->
OriginalData
=
Array
();
}
function
UpdateSession
(
$timeout
=
0
)
{
$this
->
SetField
(
$this
->
TimestampField
,
$this
->
Session
->
Expiration
);
$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
->
sessionKeyField
.
' = '
.
$this
->
Conn
->
qstr
(
$this
->
createSignatureFromSID
(
$sid
));
$result
=
$this
->
Conn
->
GetRow
(
$sql
);
if
(
$result
===
false
)
{
return
false
;
}
// perform security checks to ensure, that session is used by it's creator
if
(
$this
->
Application
->
ConfigValue
(
'SessionBrowserSignatureCheck'
)
&&
(
$result
[
'BrowserSignature'
]
!=
$this
->
_getBrowserSignature
())
&&
$this
->
Application
->
GetVar
(
'flashsid'
)
===
false
)
{
return
false
;
}
if
(
$this
->
Application
->
ConfigValue
(
'SessionIPAddressCheck'
)
&&
(
$result
[
'IpAddress'
]
!=
$this
->
Application
->
getClientIp
()))
{
// most secure, except for cases where NAT (Network Address Translation)
// is used and two or more computers can have same IP address
return
false
;
}
$this
->
DirectVars
=
$result
;
$this
->
Expiration
=
$result
[
$this
->
TimestampField
];
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
()
{
$sql
=
'SELECT '
.
$this
->
DataValueField
.
','
.
$this
->
DataVarField
.
'
FROM '
.
$this
->
SessionDataTable
.
'
WHERE '
.
$this
->
IDField
.
' = '
.
$this
->
GetID
();
$this
->
OriginalData
=
$this
->
Conn
->
GetCol
(
$sql
,
$this
->
DataVarField
);
return
$this
->
OriginalData
;
}
/**
* Enter description here...
*
* @param string $var_name
* @param mixed $default
* @return mixed
*/
function
GetField
(
$var_name
,
$default
=
false
)
{
return
array_key_exists
(
$var_name
,
$this
->
DirectVars
)
?
$this
->
DirectVars
[
$var_name
]
:
$default
;
}
function
SetField
(
$var_name
,
$value
)
{
$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
);
}
}
/**
* Saves changes in session to database using single REPLACE query
*
* @return void
* @access public
*/
public
function
SaveData
()
{
$session_id
=
$this
->
GetID
();
if
(
!
$session_id
)
{
// Can't save without sid.
return
;
}
$replace
=
''
;
$ses_data
=
$this
->
Session
->
Data
->
GetParams
();
foreach
(
$ses_data
as
$key
=>
$value
)
{
if
(
isset
(
$this
->
OriginalData
[
$key
])
&&
$this
->
OriginalData
[
$key
]
==
$value
)
{
continue
;
//skip unchanged session data
}
else
{
$replace
.=
sprintf
(
'(%s, %s, %s),'
,
$session_id
,
$this
->
Conn
->
qstr
(
$key
),
$this
->
Conn
->
qstr
(
$value
));
}
}
$replace
=
rtrim
(
$replace
,
','
);
if
(
$replace
!=
''
)
{
$query
=
' REPLACE INTO '
.
$this
->
SessionDataTable
.
' ('
.
$this
->
IDField
.
', '
.
$this
->
DataVarField
.
', '
.
$this
->
DataValueField
.
') VALUES '
.
$replace
;
$this
->
Conn
->
Query
(
$query
);
$this
->
OriginalData
=
$ses_data
;
}
if
(
$this
->
ChangedDirectVars
)
{
$changes
=
Array
();
foreach
(
$this
->
ChangedDirectVars
as
$var
)
{
$changes
[]
=
$var
.
' = '
.
$this
->
Conn
->
qstr
(
$this
->
DirectVars
[
$var
]);
}
$query
=
' UPDATE '
.
$this
->
TableName
.
'
SET '
.
implode
(
','
,
$changes
)
.
'
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.
$where_clause
=
array
(
$this
->
IDField
.
' = '
.
$this
->
GetID
(),
$this
->
DataVarField
.
' = '
.
$this
->
Conn
->
qstr
(
$var
),
);
$sql
=
'DELETE FROM '
.
$this
->
SessionDataTable
.
'
WHERE ('
.
implode
(
') AND ('
,
$where_clause
)
.
')'
;
$this
->
Conn
->
Query
(
$sql
);
}
unset
(
$this
->
OriginalData
[
$var
]);
}
function
GetFromData
(
$var
,
$default
=
false
)
{
return
array_key_exists
(
$var
,
$this
->
OriginalData
)
?
$this
->
OriginalData
[
$var
]
:
$default
;
}
function
GetExpiredSIDs
()
{
$sql
=
'SELECT '
.
$this
->
IDField
.
'
FROM '
.
$this
->
TableName
.
'
WHERE '
.
$this
->
TimestampField
.
' > '
.
adodb_mktime
();
return
$this
->
Conn
->
GetCol
(
$sql
);
}
function
DeleteExpired
()
{
$expired_sids
=
$this
->
GetExpiredSIDs
();
$this
->
DeleteSessions
(
$expired_sids
);
return
$expired_sids
;
}
function
DeleteSessions
(
$session_ids
,
$delete_reason
=
SESSION_LOG_EXPIRED
)
{
if
(!
$session_ids
)
{
return
;
}
$log_table
=
$this
->
Application
->
getUnitOption
(
'session-log'
,
'TableName'
);
if
(
$log_table
)
{
// mark session with proper status
$sub_sql
=
'SELECT '
.
$this
->
TimestampField
.
' - '
.
$this
->
SessionTimeout
.
'
FROM '
.
$this
->
TableName
.
'
WHERE '
.
$this
->
IDField
.
' = '
.
$log_table
.
'.SessionId'
;
$sql
=
'UPDATE '
.
$log_table
.
'
SET Status = '
.
$delete_reason
.
', SessionEnd = ('
.
$sub_sql
.
')
WHERE Status = '
.
SESSION_LOG_ACTIVE
.
' AND SessionId IN ('
.
implode
(
','
,
$session_ids
)
.
')'
;
$this
->
Conn
->
Query
(
$sql
);
}
$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 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
);
}
}
}
function
LoadPersistentVars
()
{
$user_id
=
$this
->
Session
->
RecallVar
(
'user_id'
);
if
(
$user_id
!=
USER_GUEST
)
{
// Root & normal users.
$this
->
PersistentVars
=
$this
->
getPersistentVars
(
$user_id
);
}
else
{
$this
->
PersistentVars
=
Array
();
}
$default_user_id
=
(
int
)
$this
->
Application
->
ConfigValue
(
'DefaultSettingsUserId'
);
if
(
!
$default_user_id
)
{
$default_user_id
=
USER_ROOT
;
}
if
(
$user_id
!=
$default_user_id
)
{
$this
->
defaultPersistentVars
=
$this
->
getPersistentVars
(
$default_user_id
);
}
}
/**
* Get persistent vars
*
* @param integer $user_id User Id.
*
* @return array
*/
protected
function
getPersistentVars
(
$user_id
)
{
$sql
=
'SELECT VariableValue, VariableName
FROM '
.
TABLE_PREFIX
.
'UserPersistentSessionData
WHERE PortalUserId = '
.
$user_id
;
return
$this
->
Conn
->
GetCol
(
$sql
,
'VariableName'
);
}
/**
* Stores variable to persistent session
*
* @param string $var_name
* @param mixed $var_value
* @param bool $optional
* @return void
* @access public
*/
public
function
StorePersistentVar
(
$var_name
,
$var_value
,
$optional
=
false
)
{
$user_id
=
$this
->
Session
->
RecallVar
(
'user_id'
);
if
(
$user_id
==
USER_GUEST
||
$user_id
===
false
)
{
// -2 (when not logged in), false (when after u:OnLogout event)
$this
->
Session
->
StoreVar
(
$var_name
,
$var_value
,
$optional
);
return
;
}
$this
->
PersistentVars
[
$var_name
]
=
$var_value
;
$key_clause
=
'PortalUserId = '
.
$user_id
.
' AND VariableName = '
.
$this
->
Conn
->
qstr
(
$var_name
);
$sql
=
'SELECT VariableName
FROM '
.
TABLE_PREFIX
.
'UserPersistentSessionData
WHERE '
.
$key_clause
;
$record_found
=
$this
->
Conn
->
GetOne
(
$sql
);
$fields_hash
=
Array
(
'PortalUserId'
=>
$user_id
,
'VariableName'
=>
$var_name
,
'VariableValue'
=>
$var_value
,
);
if
(
$record_found
)
{
$this
->
Conn
->
doUpdate
(
$fields_hash
,
TABLE_PREFIX
.
'UserPersistentSessionData'
,
$key_clause
);
}
else
{
$this
->
Conn
->
doInsert
(
$fields_hash
,
TABLE_PREFIX
.
'UserPersistentSessionData'
);
}
}
/**
* Gets persistent variable
*
* @param string $var_name
* @param mixed $default
* @return mixed
* @access public
*/
public
function
RecallPersistentVar
(
$var_name
,
$default
=
false
)
{
if
(
$this
->
Session
->
RecallVar
(
'user_id'
)
==
USER_GUEST
)
{
if
(
$default
==
ALLOW_DEFAULT_SETTINGS
)
{
$default
=
null
;
}
return
$this
->
Session
->
RecallVar
(
$var_name
,
$default
);
}
if
(
array_key_exists
(
$var_name
,
$this
->
PersistentVars
)
)
{
return
$this
->
PersistentVars
[
$var_name
];
}
elseif
(
$default
==
ALLOW_DEFAULT_SETTINGS
)
{
if
(
isset
(
$this
->
defaultPersistentVars
[
$var_name
])
)
{
$value
=
$this
->
defaultPersistentVars
[
$var_name
];
$this
->
StorePersistentVar
(
$var_name
,
$value
);
return
$value
;
}
$this
->
PersistentVars
[
$var_name
]
=
false
;
return
false
;
}
return
$default
;
}
/**
* Removes variable from persistent session
*
* @param string $var_name
* @return void
* @access public
*/
function
RemovePersistentVar
(
$var_name
)
{
unset
(
$this
->
PersistentVars
[
$var_name
]);
$user_id
=
$this
->
Session
->
RecallVar
(
'user_id'
);
if
(
$user_id
==
USER_GUEST
||
$user_id
===
false
)
{
// -2 (when not logged in), false (when after u:OnLogout event)
$this
->
Session
->
RemoveVar
(
$var_name
);
}
else
{
$sql
=
'DELETE FROM '
.
TABLE_PREFIX
.
'UserPersistentSessionData
WHERE PortalUserId = '
.
$user_id
.
' AND VariableName = '
.
$this
->
Conn
->
qstr
(
$var_name
);
$this
->
Conn
->
Query
(
$sql
);
}
}
/**
* Checks of object has given field
*
* @param string $name
*
* @return bool
* @access public
* @throws BadMethodCallException Always.
*/
public
function
HasField
(
$name
)
{
throw
new
BadMethodCallException
(
'Unsupported'
);
}
/**
* Returns field values
*
* @return Array
* @access public
* @throws BadMethodCallException Always.
*/
public
function
GetFieldValues
()
{
throw
new
BadMethodCallException
(
'Unsupported'
);
}
/**
* Returns unformatted field value
*
* @param string $field
*
* @return string
* @access public
* @throws BadMethodCallException Always.
*/
public
function
GetDBField
(
$field
)
{
throw
new
BadMethodCallException
(
'Unsupported'
);
}
/**
* Returns true, when list/item was queried/loaded
*
* @return bool
* @access public
* @throws BadMethodCallException Always.
*/
public
function
isLoaded
()
{
throw
new
BadMethodCallException
(
'Unsupported'
);
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
*
* @return Array
* @access public
* @throws BadMethodCallException Always.
*/
public
function
GetCol
(
$field
)
{
throw
new
BadMethodCallException
(
'Unsupported'
);
}
}
Event Timeline
Log In to Comment