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

Count coloured cells on Google Sheets with reference

In a spreadsheet if you need to count cells based on their background you can use this code in Google…

May 22, 2020

WP doesn’t send email? try this

Snippets for sending emails with Wordpress

February 8, 2020

Two post types share the same taxonomy in WordPress

Sharing a WordPress taxonomy between two post types is useful especially if you want to create a relation between different…

November 14, 2019

MYSQL add counter in a query

Use mysql variables to create a counter in SQL, PHP code to use an SQL counter and what does the i mean in mysqli?

November 9, 2019

Modify the language attribute based on category in WordPress

How to modify the language attribute in your Wordpress theme using a specific value

November 7, 2019