I’ve been working on an application with session data that were potentially growing rapidly. Since I am storing all sessions in memory, I wanted to ease out things a bit with help of MySQL’s COMPRESS() function. A word of warning: This is a bit wank and will only work for MySQL (AFAIK). A more general approach to session compression might be valuable to Yii in an effort to conserve memory, disk-i/o and/or disk space.
So, here we go: Create a new file CCompressedDbHttpSession in application.components with the following content
<?php
class CCompressedDbHttpSession extends CDbHttpSession
{
/**
* Creates the session DB table.
* @param CDbConnection $db the database connection
* @param string $tableName the name of the table to be created
*/
protected function createSessionTable($db,$tableName)
{
$sql="
CREATE TABLE $tableName
(
id CHAR(32) PRIMARY KEY,
expire INTEGER,
data BLOB
)";
$db->createCommand($sql)->execute();
}
/**
* Session read handler.
* Do not call this method directly.
* @param string $id session ID
* @return string the session data
*/
public function readSession($id)
{
$now=time();
$sql="
SELECT UNCOMPRESS(data) FROM {$this->sessionTableName}
WHERE expire>$now AND id=:id
";
$data=$this->getDbConnection()->createCommand($sql)->bindValue(':id',$id)->queryScalar();
return $data===false?'':$data;
}
/**
* 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
*/
public function writeSession($id,$data)
{
// 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();
$sql="SELECT id FROM {$this->sessionTableName} WHERE id=:id";
if($db->createCommand($sql)->bindValue(':id',$id)->queryScalar()===false)
$sql="INSERT INTO {$this->sessionTableName} (id, data, expire) VALUES (:id, COMPRESS(:data), $expire)";
else
$sql="UPDATE {$this->sessionTableName} SET expire=$expire, data=COMPRESS(:data) WHERE id=:id";
$db->createCommand($sql)->bindValue(':id',$id)->bindValue(':data',$data)->execute();
}
catch(Exception $e)
{
if(YII_DEBUG)
echo $e->getMessage();
// it is too late to log an error message here
return false;
}
return true;
}
}
Use this class in your config instead of CDbHttpSession for holding your sessions. Be aware that you need to change your table schema so that data is a BLOB (You can use VARBINARY for tables stored in memory).
Have fun