Inplement a own HttpSession class to use stored producures

Hello,

I am trying to implement my own Http Session class but I cannot get it right. The browser only waiting for data for some time and then after some time, it returns “The page cannot be found” as result :( If I am go back to CHttpSession everything works fine.

I am using the following code and would be glad if someone could help me.





class DbHttpSession extends CHttpSession

{

	public $ext_options = array();

	

	public function init()

	{

		foreach($this->ext_options as $key => $value)

		{

			$opt = 'session.'.$key;

			ini_set($opt,$value);

		}

		parent::init(); 

	}

	

	public function close()

	{

		if(!Yii::app()->user->isGuest)

		{

			$this->regenerateID(true);

		}

		parent::close();

	}

	

	public function getUseCustomStorage()

	{

		return true;

	}


	public function regenerateID($deleteOldSession=false)

	{

	    $oldID = session_id();;

	    parent::regenerateID(false);

	    $newID = session_id();

	    $db = $this->getDbConnection();

	

	    $sql="CALL session_set_id(unhex('$oldID'),unhex('$newID'))";

        $row = $db->createCommand($sql)->execute();

		return ($row > 0);

	}

	

	protected function getDbConnection()

	{

		return Yii::app()->db;

	}

	

	public function openSession($savePath,$sessionName)

	{

		return true;

	}

	

	public function closeSession()

	{

		return true;

	}

	

	public function readSession($id)

	{

		

		try

		{

			$timeout = (int)$this->getTimeout();

			

			$sql = "CALL session_read(unhex('$id'), $timeout)";

			

		    $data = $this->getDbConnection()->createCommand($sql)->queryScalar();

		    

		    return $data === false ? '' : $data;

		}

		catch(Exception $exp)

		{

			return '';	

		}

	}

	

	public function writeSession($id,$data)

	{

		if(strlen($data) === 0)

		{

			return true;

		}

		

		try

	    {

	    	$db=$this->getDbConnection();

			

			$sql = "call session_write(unhex(:id), :data)";

			$command = $connection->createCommand($sql);

			$command->bindParam(":id",$id,PDO::PARAM_STR);

			$command->bindParam(":data",$data,PDO::PARAM_STR);

			

			return $this->getDbConnection()->createCommand($sql)->execute() !== 0;

	    }

	    catch(Exception $e)

	    {

			if(YII_DEBUG)

			{

				echo $e->getMessage();

				// it is too late to log an error message here

			}

			return false;

		}

	}

	

	public function destroySession($id)

	{

		$sql="CALL session_destroy(unhex('$id'))";

	    return ($this->getDbConnection()->createCommand($sql)->execute() !== 0);

	}

	

	

	public function gcSession($maxLifetime)

	{

		$sql="CALL session_gc('$maxLifetime')";

		$this->getDbConnection()->createCommand($sql)->execute();

		return true;

	}

}



I fixed it now, after some sleeping :slight_smile: Here is my code, if someone is interested. I also added a security method: abnormalBehaviour() which can be used to check if someone is trying to hijack the session. I will when I got the time ask for improvements in a new thread for it, but for now, here is my code.




class DbHttpSession extends CHttpSession

{

	public $ext_options = array();

	

	private $_db = null;

	

	public function init()

	{

		foreach($this->ext_options as $key => $value)

		{

			$opt = 'session.'.$key;

			ini_set($opt,$value);

		}

		parent::init(); 

	}

	

	public function abnormalBehaviour()

    {

    	$request = Yii::app()->getComponent('request',true);

        // check the users user agent activity and the user ip address. If it suddenly changes should

        //this method return true

        $user_agent = $request->getUserAgent();

		$user_host_address = $request->getUserHostAddress();

		if($user_agent == null)

		{

			$user_agent = 'null';

		}

        $keyprefix = 'DbHttpSession.HijackCheck';   

		$init = $this->get($keyprefix.'initialized');

        if($init == null || $init !== true)

        {

        	//first run, set start variables

        	

			$this->add($keyprefix.'user_agents', array($user_agent => 1));

			$this->add($keyprefix.'user_host_addresses', array($user_host_address => 0));

			

        	$this->add($keyprefix.'initialized', true);

		}

		else

		{

			$user_agents = $this->get($keyprefix.'user_agents');

			if(!isset($user_agents[$user_agent]))

			{

				$user_agents[$user_agent] = 0;

			}

			++$user_agents[$user_agent];

			

			$total_sum = (float)array_sum($user_agents);

			$part_sum =  (float)$user_agents[$user_agent];

			if($part_sum/$total_sum < 0.07)

			{

				//we believe one session hijack attempt is catch here.

				return true;

			}

			if(count($user_agents) > 50)

			{

				//remove the front element, just save the last 50 recently used user agents.

				unshift($user_agents);

			}

			

			

			//do the same check but for ip addresses

			$user_host_addresses = $this->get($keyprefix.'user_host_address');

			if(!isset($user_host_addresses[$user_host_address]))

			{

				$user_host_addresses[$user_host_address] = 0;

			}

			++$user_host_addresses[$user_host_address];

			

			$total_sum = (float)array_sum($user_host_addresses);

			$part_sum =  (float)$user_host_addresses[$user_host_address];

			if($part_sum/$total_sum < 0.07)

			{

				//we believe one session hijack attempt is catch here.

				return true;

			}

			//we could also do loose check, if all ip addresses is in same group and suddenly changes

			//to another upper group should we assume hijack attempt, implement it in the future.

			

			

			if(count($user_host_addresses) > 50)

			{

				//remove the front element, just save the last 50 recently used user agents.

				unshift($user_host_addresses);

			}

		}

		return false;

    }


	public function getUseCustomStorage()

	{

		return true;

	}

	

	public function regenerateID($deleteOldSession=false)

	{

		$oldID = session_id();;

	    parent::regenerateID(false);

	    $newID = session_id();

	    $db = $this->getDbConnection();

	

	    $sql="CALL session_set_id(unhex(:old),unhex(:new))";

		$command = $db->createCommand($sql);

		$command->bindParam(":old", $oldID, PDO::PARAM_STR);

		$command->bindParam(":new", $newID, PDO::PARAM_STR);

		return ($command->execute() !== 0);

	}

	

	protected function getDbConnection()

	{

		if($this->_db !== null)

		{

			return $this->_db;

		}

		$this->_db = Yii::app()->getComponent('db',true);

		

		return $this->_db;

	}

	

	public function openSession($savePath,$sessionName)

	{

		return true;

	}

	

	public function closeSession()

	{

		return true;

	}

	

	public function readSession($id)

	{

		$timeout = (int)$this->getTimeout();

		$db = $this->getDbConnection();

		$sql = "CALL session_read(unhex(:id), :timeout)";

		

		$command = $db->createCommand($sql);

		$command->bindParam(":id",$id,PDO::PARAM_STR);

		$command->bindParam(":timeout",$timeout,PDO::PARAM_INT);

		$data = $command->queryScalar();

		return ($data === false) ? '' : $data;

	}


	public function writeSession($id,$data)

	{

		if($data == NULL || strlen($data) == 0)

		{

			return true;

		}

		

		try

	    {

	    	$db = $this->getDbConnection();

			

			$sql = "CALL session_write(unhex(:id), :data)";

			$command = $db->createCommand($sql);

			$command->bindParam(":id",$id,PDO::PARAM_STR);

			$command->bindParam(":data",$data,PDO::PARAM_STR);

			return $command->execute() !== 0;

	    }

	    catch(Exception $e)

	    {

			if(YII_DEBUG)

			{

				echo $e->getMessage();

				// it is too late to log an error message here

			}

			return false;

		}

	}

	

	public function destroySession($id)

	{

		$sql="CALL session_destroy(unhex(:id))";

		$db = $this->getDbConnection();

		$command = $db->createCommand($sql);

		$command->bindParam(":id",$id,PDO::PARAM_STR);

		return ($command->execute() !== 0);

	}


	public function gcSession($maxLifetime)

	{

		$sql="CALL session_gc(:timeout)";

		$this->getDbConnection()->createCommand($sql)->bindParam(":timeout",$maxLifetime,PDO::PARAM_INT)->execute();

		return true;

	}

}