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…

December 21, 2009

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

Author

I’m a software engineer, an everyday web developer and a maker. I usually build sites with PHP, within or without WordPress. I build Internet of Things with Arduino and ESP8266. I’m the founder of Rockit.it and Dailybest.it and I’m actually the Chief Technical Officer of Better Days web agency.


Comments on “PHP Session class with crypted cookies.”

9 thoughts

  1. JasonDavis says:

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

    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. Tdude says:

    Hi!
    Thanx for the excellent work. It’s just what I need. You made my day!
    Saluti da Svecia

  4. kevin says:

    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”);

  5. mehrdad says:

    very good. thanks!

  6. Neotropic says:

    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!

  7. Giulio Pons says:

    Yes this version has some errors, I have to upload the fixed version, sorry!

  8. Andrew says:

    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.

  9. Giulio Pons says:

    you’re right. that last “else” part is wrong I’ve just fixed id.

Comments are closed

Recommended

PHP curl bot to update Facebook status

I’ve found this great mini bot from Alste blog, and I’ve decided to add it to the mini bot class.…

March 1, 2010

A new avatar generator for WordPress with get_avatar and Flathash

Brand new avatars for WordPress Gravatar service

April 7, 2017

3 ways to add author’s image in WordPress

Add author's image in WordPress without a plugin

April 5, 2017

Orari trenord, corri solo quando ce n’รจ bisogno

Hai presente quando corri in stazione per prendere il treno al volo e, quando arrivi, ti accorgi che il treno ha 12 minuti di ritardo?

March 30, 2017

Stop sending email to new user in WordPress admin registration

Prevent WordPress to send notification emails when you manually create new users

March 9, 2017

Add Internet Explorer class to body to detect old browser

When you have clients that still uses an old browser, you need to handle it. This javascript function detects the…

February 27, 2017