PHP Session class with crypted cookies.

This class was built to handle session variables, I made this class because once I had to use session variables for a project, but than I had to change the behaviour to use cookies… and last, I had to hide some important ids in cookies and I don’t want cookie injection.

So I’ve made this class that can use normal session variables, or cookies. This class can use cookies in two ways: store a single variable in each cookie, or pack many variables, encrypt, and store them into cookies.

Now I always use this class when I have to use session/cookies and when I know that I have not to put too many bytes in cookies (since cookie size is limited).

<?php
/////////////////////////////////////////////////////
// this class was build
// to handle sessions with cookie or not
// if you choose "zipcook" value the cookies
// are crypted and packed to hide data to malicious
// users.
//
// $use_cookie parameter values:
// no --------> use session
// yes -------> use cookie, one cookie for each variable
// zipcook ---> encrypted cookies
//
// by Giulio Pons, http://www.barattalo.it
//
/////////////////////////////////////////////////////

class Session
{
	private $use_cookie;
	private $preStr;
	private $maxCookie;
	private $cookieLenght;
	private $stringone;
	private $duratacookie;
	private $secret;

	public function __construct ($cook = "zipcook") {

		$this->use_cookie = $cook;	//choose mode
		$this->preStr= "_KK_";		//prefix for cookies
		$this->maxCookie=20;		//since cookie lenght is limited, I've limited the number of cookies
		$this->cookieLenght=3096;	//max cookie length (it depends on browser)
		$this->duratacookie=3600*24;//cookie life time
		$this->secred="secret";		//secret keyword to crypt/decrypt, change this to customize encryption
		if ($this->use_cookie=="yes") {
		} elseif ($this->use_cookie=="zipcook") {
			$this->stringone = $this->prelevaStringaTotale();
		} else {
			ini_set("session.gc_maxlifetime","432000");
			ini_set("url_rewriter.tags","");
			ini_set("session.use_trans_sid", false);
			session_start();
		}
	}

	/* ------------------------------------------- */
	/* pack variables for parse_str                */
	/* ------------------------------------------- */
	private function build_str($ar) {
		$qs = array();
		foreach ($ar as $k => $v) { $qs[] = $k.'='.$v; }
		return join('&', $qs);
	}

	/* ------------------------------------------- */
	/* get the list of variables from the crypted  */
	/* cookies                                     */
	/* ------------------------------------------- */
	private function prelevaStringaTotale() {
		$cookiesSet = array_keys($_COOKIE);
		$out = "";
		for ($x=0;$x<count($cookiesSet);$x++) {
			if (strpos(" ".$cookiesSet[$x],$this->preStr)==1)
				$out.=$_COOKIE[$cookiesSet[$x]];
		}
		return $this->decrypta($out);
	}

	public function debug() {
		// for debug
		return $this->prelevaStringaTotale();
	}

	/* ------------------------------------------- */
	/* determine available cookies                 */
	/* ------------------------------------------- */
	private function calcolaCookieLiberi() {
		$cookiesSet = array_keys($_COOKIE);
		$c=0;
		for ($x=0;$x<count($cookiesSet);$x++) {
			if (strpos(" ".$cookiesSet[$x],$this->preStr)==1)
				$c+=1;
		}
		return $this->maxCookie - count($cookiesSet) + $c;
	}

	/* ------------------------------------------- */
	/* split the string in blocks to store cookies */
	/* ------------------------------------------- */
	private function my_str_split($s,$len) {
		$output = array();
		if (strlen($s)<=$len) {
			$output[0] = $s;
			return $output;
		}
		$i = 0;
		while (strlen($s)>0) {
			$s = substr($s,0,$len);
			$output[$i]=$s;
			$s = substr($s,$len);
			$i++;
		}
		return $output;
	}

	/* ------------------------------------------- */
	/* save vars in cookies or session             */
	/* ------------------------------------------- */
	public function register($var,$value) {
		$this->set($var,$value);
	}
	public function set($var,$value) {
		if ($this->use_cookie=="yes") {
			setcookie($var,$this->crypta($value),time()+$this->duratacookie,"/", $_SERVER['HTTP_HOST'] );
		} elseif ($this->use_cookie=="zipcook") {
			if ($this->stringone!="") {
				parse_str($this->stringone, $vars);
			} else {
				$vars=array();
			}
			$vars[$var] = $value;	//aggiungo-modifico valore
			$str = $this->crypta($this->build_str($vars));
			$arr = $this->my_str_split($str,$this->cookieLenght);
			$cLiberi = $this->calcolaCookieLiberi();
			if (count($arr) < $cLiberi) {
				// c'ho spazio, posso registrare
				$this->stringone = $this->build_str($vars);
				for ($i=0;$i<count($arr);$i++) {
					setcookie($this->preStr.$i,$arr[$i],time()+$this->duratacookie,"/", $_SERVER['HTTP_HOST'] );
				}
			} else {
				//cookie overflow
				return "errore cookie overflow";
			}
		} else {
			//session_register($var);
			$_SESSION[$var]=$value;
		}
	}

	/* ------------------------------------------- */
	/* get variables back from cookies crypted or  */
	/* not, or directly from session               */
	/* ------------------------------------------- */
	public function get($var) {
		if ($this->use_cookie=="yes") {
			global $_COOKIE;
			return $this->decrypta($_COOKIE[$var]);
		} elseif ($this->use_cookie=="zipcook") {
			if ($this->stringone!="") {
				parse_str($this->stringone, $vars);
			} else {
				return "";
			}
			if(!isset($vars[$var])) {
				return "";
			}
			return $vars[$var];
		} else {
			return isset($_SESSION[$var]) ? $_SESSION[$var] : "";
			//if ($this->is_registered($var)) {
			//	$this->$var=$GLOBALS[$var];
			//} else
			//	if(isset($GLOBALS[$var]))
			//		$this->$var = $GLOBALS[$var];
			//	else
			//			$this->$var="";
			//return($this->$var);
		}
	}

	/* ------------------------------------------- */
	/* empty session or cookis                     */
	/* ------------------------------------------- */
	public function finish() {
		if ($this->use_cookie=="yes") {
			$cookiesSet = array_keys($_COOKIE);
			for ($x=0;$x<count($cookiesSet);$x++) {
				//echo $cookiesSet[$x]."<br/>";
				setcookie($cookiesSet[$x],"",time()-3600*24,"/", $_SERVER['HTTP_HOST'] );	//faccio scadere il cookie
			}

		} elseif ($this->use_cookie=="zipcook") {
			$cookiesSet = array_keys($_COOKIE);
			for ($x=0;$x<count($cookiesSet);$x++) {
				if (strpos(" ".$cookiesSet[$x],$this->preStr)==1)
					setcookie($cookiesSet[$x],"",time()-3600*24,"/",$_SERVER['HTTP_HOST']);
				$this->stringone="";
			}
		} else {
			session_destroy();
			$_SESSION = array();
		}
	}

	/* crypt */
	private function crypta($t){
		if ($t=="") return $t;
		$r = md5(10); $c=0; $v="";
		for ($i=0;$i<strlen($t);$i++){
			if ($c==strlen($r)) $c=0;
			$v.= substr($r,$c,1) . (substr($t,$i,1) ^ substr($r,$c,1));
			$c++;
		}
		return (base64_encode($this->ed($v)));
	}
	/* decrypt */
	private function decrypta($t) {
		if ($t=="") return $t;
		$t = $this->ed(base64_decode(($t)));
		$v = "";
		for ($i=0;$i<strlen($t);$i++){
			$md5 = substr($t,$i,1);
			$i++;
			$v.= (substr($t,$i,1) ^ $md5);
		}
		return $v;
	}

	/* used to crypt/decrypt */
	private function ed($t) {
		$r = md5($this->secret); $c=0; $v="";
		for ($i=0;$i<strlen($t);$i++) {
			if ($c==strlen($r)) $c=0;
			$v.= substr($t,$i,1) ^ substr($r,$c,1);
			$c++;
		}
		return $v;
	}

}
?>

To use the class, in every file include at the beginning the class and instantiate the class:

<?
//test1.php
include("session.class.php");
$s = new Session();
$s->set("userid","27");
?>
<?
//test2.php
include("session.class.php");
$s = new Session();
echo $s->get("userid"); //27
?>

If you try to see the cookie content you will find unreadable data:

2009-12-21_230527

This will prevent stealing data from cookies.

Download session.class.php

No related posts.

9 comments

  1. JasonDavis

    Hello I tried your example code class and the example to set and show but I get errors from running. Warning: Cannot modify header information – headers already sent by (output started at C:\webserver\htdocs\friendproject2\labs\sessions\index.php:5) in C:\webserver\htdocs\friendproject2\labs\sessions\cookiesession.class.php on line 130

    When I look at line 130, it is the line that sets the cookie

  2. admin

    Sure. I didn’t write it: since cookies are sent with headers you need to use the class at the beginning of your files. When you instantiate the session object you must have not written anything on the page. Before any output instantiate the class and set variables. You can read variables wherever you want.

  3. kevin

    Hi, I am having trouble using your cookie class with your zipcook encryption. I do

    $cookie = new Session();
    $cookie->set(“loginCookie”, “myvalue”); //load page 1st time
    //I can see the cookie named _KK_0;
    //I delete the above code and RELOAD the page 2nd time
    $cookie = new Session();
    if($cookie->get(“loginCookie”) { //or get(“_KK_0″)
    echo “Got the Cookie”;
    }
    //This does not work, but If I do the same with $cookie = new Session(“yes”); the following line works $cookie->get(“loginCookie”);

  4. Neotropic

    Nice error checking. Nice to loose all that one writes.

    Any ways….

    Line 160…?
    Take a closer look, calling a function that does not exist.
    ‘if ($this->is_registered($var)) {‘

    Also….
    Change: __construct ($cook = “zipcook”)
    To: __construct ($cook)

    Defaults to zipcook of you just do: new Session(); even though people may not.

    Either set a sess value, or explain to set it as new Session(”); if wanting to use sessions. Or hell… new Session(‘I CAN PUT ANYTHING HERE’); to tell it to use sessions. But do other people, new people know?

    Aside from that a great script!

  5. Andrew

    Hi,
    Thanks for your class.
    Would you mind to tell me what is supposed to be is_registered function ?
    When I want to use only session configuration, this bug stops all. Then your class becomes useless :-(
    Regards,
    Andrew.

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>