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…

Dicembre 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, https://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

PHP expert. Wordpress plugin and theme developer. Father, Maker, Arduino and ESP8266 enthusiast.

Comments on “PHP Session class with crypted cookies.”

9 thoughts

  1. JasonDavis ha detto:

    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 ha detto:

    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 ha detto:

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

  4. kevin ha detto:

    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 ha detto:

    very good. thanks!

  6. Neotropic ha detto:

    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 ha detto:

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

  8. Andrew ha detto:

    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 ha detto:

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

Comments are closed

Recommended

The Quantcast CMP broke my sites

A javascript error in CMP blocks my site.

Maggio 19, 2023

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.…

Marzo 1, 2010

WP Gutenberg notes

Collection of notes and thoughts on Wordpress Gutenberg blocks development.

Gennaio 9, 2023

Optimizing LCP, Largest Contentful Paint result

Notes about Core Web Vitals optimization challenge

Gennaio 4, 2023

Find values recursively inside complex json objects in PHP

A PHP function to to quickly search complex, nested php structures for specific values.

Dicembre 18, 2022