Compressed Sessions with CDbHttpSession

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 :D