Skip to content

Commit

Permalink
Fixed issue #14700: DbHttpSession broke (mariadb) with data too long
Browse files Browse the repository at this point in the history
Fixed issue #13950: (MS)SQL Error when saving getting a session token via API
Dev: update data transparently (reset after allow usage after) 
Dev: usage of iSessionExpirationTime
  • Loading branch information
Shnoulle committed Apr 26, 2019
2 parents 9dcffbb + ac95cfc commit 1a28a46
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 63 deletions.
2 changes: 1 addition & 1 deletion application/config/version.php
Expand Up @@ -13,7 +13,7 @@


$config['versionnumber'] = '3.17.2';
$config['dbversionnumber'] = 357;
$config['dbversionnumber'] = 358;
$config['buildnumber'] = '';
$config['updatable'] = true;
$config['assetsversionnumber'] = '30083';
Expand Down
5 changes: 3 additions & 2 deletions application/controllers/survey/index.php
Expand Up @@ -32,8 +32,9 @@ public function action()

// only attempt to change session lifetime if using a DB backend
// with file based sessions, it's up to the admin to configure maxlifetime
if (isset(Yii::app()->session->connectionID)) {
@ini_set('session.gc_maxlifetime', Yii::app()->getConfig('iSessionExpirationTime'));
if (isset(Yii::app()->session->connectionID) && (int)Yii::app()->getConfig('iSessionExpirationTime') ) {
/* Use Yii CHttpSession to freeze/unfreeze session @see CHttpSession::freeze */
Yii::app()->session->setTimeout((int) Yii::app()->getConfig('iSessionExpirationTime'));
}

$this->_loadRequiredHelpersAndLibraries();
Expand Down
2 changes: 0 additions & 2 deletions application/core/db/MssqlSchema.php
Expand Up @@ -23,8 +23,6 @@ public function __construct($conn)
$this->columnTypes['autoincrement'] = 'integer NOT NULL IDENTITY (1,1)';

$this->columnTypes['longbinary'] = 'varbinary(max)';

$this->columnTypes['binary'] = 'varbinary(max)';
}


Expand Down
8 changes: 4 additions & 4 deletions application/core/db/PgsqlSchema.php
Expand Up @@ -22,16 +22,16 @@ public function __construct($conn)
public function getColumnType($type)
{
if (isset($this->columnTypes[$type])) {
// Direct : get it
// Direct : get it
$sResult = $this->columnTypes[$type];
} elseif (preg_match('/^([a-zA-Z ]+)\((.+?)\)(.*)$/', $type, $matches)) {
// With params : some test to do
// With params : some test to do
$baseType = parent::getColumnType($matches[1]);
if (preg_match('/^([a-zA-Z ]+)\((.+?)\)(.*)$/', $baseType, $baseMatches)) {
// Replace the default Yii param
// Replace the default Yii param
$sResult = preg_replace('/\(.+\)/', "(".$matches[2].")", parent::getColumnType($matches[1]." ".$matches[3]));
} else {
// Get the base type and join
// Get the base type and join
$sResult = join(" ", array($baseType, "(".$matches[2].")", $matches[3]));
}
} else {
Expand Down
47 changes: 8 additions & 39 deletions application/core/web/DbHttpSession.php
@@ -1,47 +1,16 @@
<?php

/**
* @inheritdoc
* Leave it for compatibility of old config.php file
*/
class DbHttpSession extends \CDbHttpSession
{

/**
* Session write handler.
* Do not call this method directly.
* @param string $id session ID
* @param string $data session data
* @return boolean whether session write is successful
* @inheritdoc
* Usage of config
*/
public function writeSession($id, $data)
public function getTimeout()
{
// exception must be caught in session write handler
// http://us.php.net/manual/en/function.session-set-save-handler.php
try {
$expire = time() + $this->getTimeout();
$db = $this->getDbConnection();
if ($db->getDriverName() == 'pgsql') {
$data = new CDbExpression($db->quoteValueExtended($data, PDO::PARAM_LOB)."::bytea");
}
if ($db->getDriverName() == 'sqlsrv' || $db->getDriverName() == 'mssql' || $db->getDriverName() == 'dblib') {
$data = new CDbExpression('CONVERT(VARBINARY(MAX), '.$db->quoteValue($data).')');
}
if ($db->createCommand()->select('id')->from($this->sessionTableName)->where('id=:id', array(':id'=>$id))->queryScalar() === false) {
$db->createCommand()->insert($this->sessionTableName, array(
'id'=>$id,
'data'=>$data,
'expire'=>$expire,
));
} else {
$db->createCommand()->update($this->sessionTableName, array(
'data'=>$data,
'expire'=>$expire
), 'id=:id', array(':id'=>$id));
}
} catch (Exception $e) {
if (YII_DEBUG) {
echo $e->getMessage();
}
// it is too late to log an error message here
return false;
}
return true;
return (int)Yii::app()->getConfig('iSessionExpirationTime',ini_get('session.gc_maxlifetime'));
}
}
4 changes: 1 addition & 3 deletions application/helpers/remotecontrol/remotecontrol_handle.php
Expand Up @@ -48,14 +48,12 @@ public function get_session_key($username, $password, $plugin = 'Authdb')
if ($loginResult === true) {
$this->_jumpStartSession($username);
$sSessionKey = Yii::app()->securityManager->generateRandomString(32);
$sDatabasetype = Yii::app()->db->getDriverName();
$session = new Session;
$session->id = $sSessionKey;
$session->expire = time() + Yii::app()->getConfig('iSessionExpirationTime');
$session->expire = time() + (int) Yii::app()->getConfig('iSessionExpirationTime',ini_get('session.gc_maxlifetime'));
$session->data = $username;
$session->save();
return $sSessionKey;

}
if (is_string($loginResult)) {
return array('status' => $loginResult);
Expand Down
11 changes: 10 additions & 1 deletion application/helpers/update/updatedb_helper.php
Expand Up @@ -2380,12 +2380,20 @@ function db_upgrade_all($iOldDBVersion, $bSilent = false)

if ($iOldDBVersion < 357) {
$oTransaction = $oDB->beginTransaction();
//// IKI
//// IKI
$oDB->createCommand()->renameColumn('{{surveys_groups}}','owner_uid','owner_id');
$oDB->createCommand()->update('{{settings_global}}', ['stg_value'=>357], "stg_name='DBVersion'");
$oTransaction->commit();
}

if ($iOldDBVersion < 358) {
$oTransaction = $oDB->beginTransaction();
dropColumn('{{sessions}}','data');
addColumn('{{sessions}}','data','longbinary');
$oDB->createCommand()->update('{{settings_global}}', ['stg_value'=>358], "stg_name='DBVersion'");
$oTransaction->commit();
}

} catch (Exception $e) {
Yii::app()->setConfig('Updating', false);
$oTransaction->rollback();
Expand Down Expand Up @@ -2456,6 +2464,7 @@ function db_upgrade_all($iOldDBVersion, $bSilent = false)
Yii::app()->setConfig('Updating', false);
return true;
}

/**
* @param CDbConnection $oDB
*
Expand Down
55 changes: 45 additions & 10 deletions application/models/Session.php
Expand Up @@ -17,13 +17,26 @@

/**
* Class Session
*
* Extend CActiveRecord and not LSActiveRecord to disable plugin event (session can be used a lot)
*
* @property string $id Primary Key
* @property integer $expire
* @property string $data
*/
class Session extends CActiveRecord
{

/** @var mixed $dataBackup to reset $data after save */
private $dataBackup = null;

/**
* @inheritdoc
*/
public function init()
{
$this->attachEventHandler("onBeforeSave", array($this, 'fixDataType'));
$this->attachEventHandler("onAfterSave", array($this, 'resetDataType'));
}
/**
* @inheritdoc
* @return Session
Expand Down Expand Up @@ -51,24 +64,46 @@ public function primaryKey()
public function afterFind()
{
$sDatabasetype = Yii::app()->db->getDriverName();
// MSSQL delivers hex data (except for dblib driver)
if ($sDatabasetype == 'sqlsrv' || $sDatabasetype == 'mssql') {
$this->data = $this->hexToStr($this->data);
}
// Postgres delivers a stream pointer
if (gettype($this->data) == 'resource') {
$this->data = stream_get_contents($this->data, -1, 0);
}
return parent::afterFind();
}

private function hexToStr($hex)
/**
* Update data before saving
* @see \CDbHttpSession
* @return void
*/
public function fixDataType()
{
$string = '';
for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
$string .= chr(hexdec($hex[$i].$hex[$i + 1]));
$this->dataBackup = $this->data;
$db = $this->getDbConnection();
$dbType = $db->getDriverName();
switch($dbType) {
case 'sqlsrv':
case 'mssql':
case 'dblib':
$this->data=new CDbExpression('CONVERT(VARBINARY(MAX), '.$db->quoteValue($this->data).')');
break;
case 'pgsql':
$this->data=new CDbExpression($db->quoteValueWithType($this->data, PDO::PARAM_LOB)."::bytea");
break;
case 'mysql':
// Don't seems to need something
default:
// No update
}
return $string;
}

/**
* Reset data after saving
* @return void
*/
public function resetDataType()
{
$this->data = $this->dataBackup;
$this->dataBackup = null;
}
}
2 changes: 1 addition & 1 deletion installer/create-database.php
Expand Up @@ -396,7 +396,7 @@ function createDatabase($oDB){
$oDB->createCommand()->createTable('{{sessions}}', array(
'id' => "string(32) NOT NULL",
'expire' => "integer NULL",
'data' => "binary",
'data' => "longbinary",
));

$oDB->createCommand()->addPrimaryKey('{{sessions_pk}}', '{{sessions}}', 'id');
Expand Down

0 comments on commit 1a28a46

Please sign in to comment.