#native_company# #native_desc#
#native_cta#

SimpleSession – a powerful URL-based session handler class

By Joseph Ostor
on May 11, 2001

Version: 1.0

Type: Class

Category: HTTP

License: GNU General Public License

Description: 4 Files:
ses.php – main file, contains server-side PHP code.
ses.js – contains some client-side JavaScript routines.
ses1.php – sample file, demonstrates features, loads ses2.php
ses2.php – sample file, demonstrates features, loads ses1.php
Installation:
– split the text into 4 files
– copy all the files into a test dir, and diplay ses1.php or ses2.php in your browser.

Description:
– Feature-rich session managing class for PHP 4.0.x.
– Never uses cookies, so always working on the same way for every browser. Transmits the session ID through URLs, keeps track name-value pairs in files. Supports expiration, various URL handling features, etc.

Version information:
1.0 (2001-may-12) – Initial release.
– Independent of PHP’s own session handling code
– Transmits session id through URL
– Stores variable names and values in plain text files.
– Supplies URL managing functions for seamless web-page integration
– Contains session handling examples for links, GET forms, POST forms, self-calling JavaScript drop-down lists
– Tunable automatic expiration settings on a per-session basis.
– Performs regular, tunable garbage collection of expired server-side session files.
– as does not use cookies, it is nothing to with headers, and the session handling code may be placed anywhere on the PHP page
– MD5-based session ID generation
– Session config parameters used from php.conf:
— session.name
— session.save_path
— session.gc_maxlifetime
— session.gc_probability

======================== START OF ses_readme.txt FILE ======================== 
//---------------------------------------------------------------------------
// SimpleSession - a powerful URL-based session handler for PHP4.
//---------------------------------------------------------------------------
// Author:       Joseph Ostor ([email protected])
// Version:      1.0 (2001-may-12)
// Requirements: PHP >= 4.0.x
// License:      GPL
// Files: 
//    ses.php  - this file, contains server-side PHP code.
//    ses.js   - contains some client-side JavaScript routines.
//    ses1.php - sample file, demonstrates features, loads ses2.php
//    ses2.php - sample file, demonstrates features, loads ses1.php
// Installation: copy all the files into a test dir, and diplay
//               ses1.php or ses2.php in your browser.
//
// Description:
//    Feature-rich session managing class for PHP 4.0.x.
//    Never uses cookies, so always working on the same way for every
//    browser. Transmits the session ID through URLs, keeps track 
//    name-value pairs in files. Supports expiration, various URL
//    handling features, etc.
//
// Version information:
//    1.0 (2001-may-12) - Initial release.
//       - Independent of PHP's own session handling code
//       - Transmits session id through URL
//       - Stores variable names and values in plain text files.
//       - Supplies URL managing functions for seamless web-page 
//         integration
//       - Contains session handling examples for links, GET forms, 
//         POST forms, self-calling JavaScript drop-down lists
//       - Tunable automatic expiration settings on a per-session 
//         basis.
//       - Performs regular, tunable garbage collection of expired 
//         server-side session files.
//       - as does not use cookies, it is nothing to with headers, 
//         and the session handling code may be placed anywhere on
//         the PHP page
//       - MD5-based session ID generation
//       - Session config parameters used from php.conf:
//         session.name           = name of the request variable in the URL
//         session.save_path      = OS file path to save session data files.
//         session.gc_maxlifetime = after these seconds elapsed, session 
//                                  file will be removed by the garbage 
//                                  collector
//         session.gc_probability = percentual probability of the garbage 
//                                  collector to start on session start
//---------------------------------------------------------------------------

======================== END OF ses_readme.txt FILE ======================== 

======================== START OF ses.js FILE ======================== 
//------------------

// SimpleSession - a powerful URL-based session handler

// ses.js - contains some client-side JavaScript routines.
//------------------

// Author:  Joseph Ostor ([email protected])

// Version: 1.0 (2001-may-12)

//------------------

function getformopt(formname,selectname)
{
   var sel  = 'document.'+formname+'.'+selectname+'.';
   var expr = sel+'options['+sel+'selectedIndex].value';
   var val  = parseFloat(eval(expr));
   if( isNaN(val) ) return 0;
   return val;
}
function splitURL()
{
   var i,url = new Array();

   var reqpos = location.href.indexOf('?');
   if( reqpos>0 )
   {
      url[0] = location.href.substring(0,reqpos);
      var qstr = location.href.substr(reqpos+1);
      var qarr = qstr.split("&");
      for(i=0; i<qarr.length; i++)
      {
         var qvar = qarr[i].split("=");
         if( qvar.length==2 )
            url[url.length] = qvar;
      }
   }
   else
      url[0] = location.href;
   
   return url;
}
function assembleURL(urlarr)
{
   if( urlarr.length<1 ) return '';
   var url = urlarr[0];
   if( urlarr.length<2 ) return url;
   url += '?';
   for(i=1; i<urlarr.length; i++)
   {
      if( i>1 ) url += '&';
      url += urlarr[i][0] + '=' + urlarr[i][1];
   }
   return url;
}
function removeElement(arr,idx)
{
  var tmp = new Array();
  var i1,i2;
  for(i1=0,i2=0; i1<arr.length; i1++)
  {
     if( i1!=idx )
     {
        tmp[i2]=arr[i1];
        i2++;
     }
  }
  
  return tmp;
}
======================== END OF ses.js FILE ======================== 

======================== START OF ses.php FILE ======================== 
<?
//---------------------------------------------------------------------------
// SimpleSession - a powerful URL-based session handler for PHP4.
//---------------------------------------------------------------------------
// Author:       Joseph Ostor ([email protected])
// Version:      1.0 (2001-may-12)
// Requirements: PHP 4.0.x
//
// See 'ses_readme.txt' for details.
//---------------------------------------------------------------------------
class SimpleSession
{
   var $id,$name,$lifetime,$gc_probability;
   var $vars;
   var $rqm;
   //---------------------

   function SimpleSession($autostart=true)
   {
      $cache_expire = (int)get_cfg_var('session.gc_maxlifetime');
      if( $cache_expire<100 ) 
         $cache_expire = 1440; //seconds

      $gc_prob = (int)get_cfg_var('session.gc_probability');
      if( $gc_prob>100 || $gc_prob<1 )
         $gc_prob = 1;

      $sessionname = get_cfg_var('session.name');
      if( !$sessionname )
         $sessionname = 'SIMPSESSID';

      $this->id       = '';
      $this->name     = $sessionname;   //PHP built-in function.
      $this->lifetime = $cache_expire;  //seconds.
      $this->gc_probability = $gc_prob; //percentage
      $this->vars     = array();
      $this->active   = false;
      $this->rqm      = new ReqManager();

      if( $autostart ) $this->session_start();
   }

   function Save()
   {
      if( $this->active ) 
      {
         dbg("Save started");
         $this->session_save_internal();
      }
   }
   
   //removeoldreqs: removes additional GET variables from the URL.
   function Req($startchar='?',$removeoldreqs=true) 
   {
      if( $removeoldreqs ) 
         $this->rqm->clear();

      if( $this->active )
         $this->rqm->add($this->name,$this->id);

      return $this->rqm->request($startchar);
   }

   function session_name(){return $this->name;}
   function session_id()  {return $this->id;}
   function SID()         {return "{$this->name}={$this->id}";}
   function FormSID()     {return "<input type="hidden" name="{$this->name}" value="{$this->id}">n";}
   
   function read($nam,$defval=false)
   {
      if( !isset($this->vars[$nam]) ) return $defval;
      return $this->vars[$nam];
   }

   function is_registered($nam){return isset($this->vars[$nam]);}
   function register($nam) //storing a new session variable.
   {
      if( !$this->active ) $this->session_start();
      if( !$this->active ) return false; //could not start session.
      
      if( !isset($GLOBALS[$nam]) )
      {
         warn("Warning: register: registered variable ($nam) has not assigned a value - set to true.");
         $GLOBALS[$nam] = true;
      }
      $this->vars[$nam] = &$GLOBALS[$nam];
   }
   function register_from_GET($nam,$defval=false) //storing a new session variable from Query string.
   {
    global $HTTP_GET_VARS;
    
      if( isset($HTTP_GET_VARS[$nam]) )
      {
         $GLOBALS[$nam] = $HTTP_GET_VARS[$nam];
         $this->register($nam);
         dbg("register_from_GET: $nam found in the reqest string, value: {$HTTP_GET_VARS[$nam]}");
         return true;
      }
      elseif( $this->is_registered($nam) )
      {
         dbg("register_from_GET: $nam NOT found in the reqest string, but registered, value: ".$this->read($nam));
         return true;
      }
      
      if( (!isset($GLOBALS[$nam])) ) 
      {
         $GLOBALS[$nam] = $defval;
         dbg("register_from_GET: $nam NOT found in the reqest string, NOT registered, created from default value $defval");
      }
      else
         dbg("register_from_GET: $nam NOT found in the reqest string, NOT registered, leaved as undefined (defval=$defval)");
      
      return false;
   }
   function register_from_POST($nam,$defval=false) //storing a new session variable from POSTed variable.
   {
    global $HTTP_POST_VARS;
    
      if( isset($HTTP_POST_VARS[$nam]) )
      {
         $GLOBALS[$nam] = $HTTP_POST_VARS[$nam];
         $this->register($nam);
         return true;
      }
      elseif( $this->is_registered($nam) )
         return true;
         
      if( !isset($GLOBALS[$nam]) && isset($defval) && $defval!='nodefault' ) $GLOBALS[$nam] = $defval;
      return false;
   }

   function unregister($nam) //storing a new session variable.
   {
      if( isset($this->vars[$nam]) ) {unset($this->vars[$nam]);}
   }

   function get($nam)  //returning current value of the session variable.
   {
      if( !isset($this->vars[$nam]) ) return '';
      return $this->vars[$nam];
   }
 
   function get_sessionfile_name_internal()
   {
      if( !$this->id ) return '';
      return session_save_path()."/sse_{$this->id}";
   }

   function garbage_collection_internal()
   {
      //limit garbage collection resource usage.
      if( rand(1, 100) > $this->gc_probability ) 
         return false; 

      dbg("garbage_collection_internal started");
      $dir = dir(session_save_path());
      while($entry = $dir->read()) 
      {
        if( strncmp($entry, 'sse_', 4)==0 )
        {
           $fnam = session_save_path()."/$entry";
           $f  = fopen($fnam, 'r');
           if( $f ) 
           {
              $l1 = fgets($f, 100);
              $l2 = fgets($f, 100);
              fclose($f);
              $this->check_expire_and_delete($l1,$l2,$fnam);
           }
        }
      }//for each file in the dir.
      $dir->close();
   }
   
   function delete_sessionfile_internal($fnam='')
   {
      if( !$fnam ) $fnam=$this->get_sessionfile_name_internal();
      if( !$fnam ) return false;
      dbg("delete_sessionfile_internal(fnam=$fnam)");
      return unlink($fnam);
   }
   
   function check_expire_and_delete($line1,$line2,$filename)
   {
      if( $line1!="expirationn" ) return false;
      $expire = (int)($line2); //first 2 values: expiration name and value
      if( $expire < time() ) //this session has been expired.
      {
         dbg("session expired and now will be deleted(filename=$filename)");
         $this->delete_sessionfile_internal($filename);
         return false;
      }
      
      return true;
   }

   function session_load_internal($newsesid)
   {
      dbg("session_load_internal started");
      $this->active = false;
      $this->vars = array();
      
      //---getting session file name---
      $this->id = $newsesid;
      $fnam = $this->get_sessionfile_name_internal();
      if( !$fnam || !file_exists($fnam) ) 
      {
         $this->id = '';
         return false;
      }
      
      //---reading session file content---
      $lines = file($fnam);
      if( !is_array($lines) || count($lines)<2 )
      {
         $this->id = '';
         return false;
      }

      //---checking session data expiration---
      if( !$this->check_expire_and_delete($lines[0],$lines[1],$fnam) )
      {
         $this->id = '';
         return false;
      }
         
      //---reading back session variables---
      $n=count($lines);
      for($i=2; $i<$n; $i+=2)
      {
         $varnam = rtrim($lines[$i]);
         if( $varnam )
         {
            $varval = unserialize($lines[$i+1]);
            $GLOBALS[$varnam] = $varval;
            $this->vars[$varnam] = &$GLOBALS[$varnam];
            dbg("session var retrieved: {$varnam}={$this->vars[$varnam]}");
         }
      }//for each line.

      dbg("session_load_internal succeed");
      $this->active = true;
   }
   
   function session_save_internal()
   {
      $fnam = '';
      $fnam = $this->get_sessionfile_name_internal();
      $f = fopen($fnam,'w');
      dbg("session_save_internal: file overwritten=$fnam");
      if( !$f )
      {
         err("Error: could not create session file '$fnam' - giving up (SimpleSession::session_save_internal)");
         return false;
      }
      
      $expiration = time()+$this->lifetime;
      fwrite($f,"expirationn$expirationn");
      while( list($k,$v) = each($this->vars))
      {
         if( isset($v) ) //global variable possibly destroyed by the user using unset().
         {
            $v = serialize($v);
            fwrite($f,"$kn$vn");
            dbg("session_save_internal: written: varname=$k, value=$v");
         }
      }
      fclose($f);
      return true;
   }

   function session_start_internal()
   {
      dbg("session_start_internal started");
      $this->active = false;
      for($i=0; $i<100; $i++)
      {
         $this->id = md5(uniqid(rand()).'0123456789');
         $fnam = $this->get_sessionfile_name_internal();
         if( !file_exists($fnam) ) 
         {
            $f = fopen($fnam,'w');
            if( $f ) 
            {
               fclose($f); 
               dbg("empty session file created: $fnam");
               break;
            }
         }
         $this->id = '';
      }
      
      if( !$this->id )
      {
         err("Error: could not create new session id,  '$fnam' - giving up (SimpleSession::session_save_internal)");
         return false;
      }
      
      $this->active = true;
      dbg("session_start_internal succeed");
      return true;
   }
   function session_unset()
   {
      $this->vars = array();
      return true;
   }
   function session_destroy()
   {
      if( $this->active ) //this session has been expired.
         $this->delete_sessionfile_internal();

      $this->session_unset();
      $this->active = false;
      return true;
   }
   
   function session_start()
   {
    global $HTTP_GET_VARS,$HTTP_POST_VARS;
    
      dbg("session_start() started");
      if( $this->active ) return true;
      
      $this->garbage_collection_internal();
      
      if( isset($HTTP_GET_VARS[$this->name]) )
         $this->session_load_internal($HTTP_GET_VARS[$this->name]);
      elseif( isset($HTTP_POST_VARS[$this->name]) )
         $this->session_load_internal($HTTP_POST_VARS[$this->name]);

      if( !$this->active )
         $this->session_start_internal();
         
      return $this->active;
   }
};

function dbg($msg) //for debugging messages.
{
   //echo "$msg<br>n";
}
function warn($msg) //for warning messages.
{
   echo "$msg<br>n";
}
function err($msg) //for error messages.
{
   echo "$msg<br>n";
}

//---------------
// ReqManager
// Request string parser class - for intelligent merging of values
//---------------
class ReqManager 
{
   var $reqvars;
   
   function ReqManager()
   {
      global $HTTP_GET_VARS;
      
      $this->reqvars = $HTTP_GET_VARS;
      while( list($k,$v)=each($HTTP_GET_VARS) )
         $this->reqvars[$k] = urldecode($v);
   }

   function clear()
   {
      $this->reqvars = array();
   }
   
   function request($startchar='?')
   {
      if( count($this->reqvars)<1 ) return '';
      $req = '';
      while( list($k,$v)=each($this->reqvars) )
      {
         if( $req ) $req .= '&';
         $req .= "$k=".urlencode($v);
      }
      return "$startchar$req";
   }
   
   function add($nam,$val)
   {
      $this->reqvars[$nam] = $val;
   }
   
   function remove($nam,$val)
   {
      if( isset($this->reqvars[$nam]) ) 
      {
         unset($this->reqvars[$nam]);
         return true;
      }
      
      return false;
   }
   
   function get($nam,$defval=false)
   {
      if( !isset($this->reqvars[$nam]) ) return $defval;
      return $this->reqvars[$nam];
   }
};
//----------------

?>
======================== END OF ses.php FILE ======================== 

======================== START OF ses1.php FILE ======================== 
<?
include_once('./ses.php');
global $session;
$session = new SimpleSession();
?>
<script language="JavaScript" src="ses.js"></script>
<script language="JavaScript">
function SafeSelfReload(removepg)
{
   var fn = 'OklessForm';
   var st = 'CarBrand';
   var sr = 'CarColor';
   var i,requests = splitURL();
   var typefound=false;
   var recnfound=false;
   var pgidx=-1;
   for(i=1; i<requests.length; i++) //first element is the page address: skip it.
   {
      if( requests[i][0]==st )
      {
         requests[i][1] = getformopt(fn,st);
         typefound=true;
      }
      else
      if( requests[i][0]==sr )
      {
         requests[i][1] = getformopt(fn,sr);
         recnfound=true;
      }
      else
      if( requests[i][0]=='pg' ) //note the position of the pagenum, which will be removed now by some reason.
         pgidx=i;
   }

   if( !typefound ) requests[requests.length] = new Array(st,getformopt(fn,st));
   if( !recnfound ) requests[requests.length] = new Array(sr,getformopt(fn,sr));
   if( removepg ) requests = removeElement(requests,pgidx);
   var newurl = assembleURL(requests);
   location.href=newurl;
}
</script>
<?
if( !isset($myvar) )
{
   global $myvar;
   $myvar = 1;
   $session->register('myvar');
}
if( !isset($origin) )
{
   global $origin;
   $origin = 'unknown';
   $session->register('origin');
}
?>
<h1>First session test page</h1>

You are coming from page '<?= $origin ?>'. Welcome!<br>
Number of visited pages in the session: <?=$myvar?><br>
<!--Session ID: '<?=$session->session_id();?>'--><br>
<hr>

1. Transferring session ID with a URL:<br>
Please visit <a href="ses2.php<?=$session->Req();?>">2nd session test page</a>.<br>

<?
$session->register_from_POST('TextValue',   ''); //read posted value and register it.
$session->register_from_GET ('TextValueGet','');
$session->register_from_GET ('CarBrand',    0);
$session->register_from_GET ('CarColor',    0);
?>
<hr>

2. Transferring session ID with a form POST:<br>
<form action="ses2.php?pg=2" method="post">
Fill up this field: <input type="text" name="TextValue" value="<?=$session->read('TextValue')?>">
<input type="submit" value="Go">
<?=$session->FormSID()?>
</form>
<hr>

3. Transferring session ID with a form GET:<br>
<form action="ses2.php<?=$session->Req()?>&pg=1" method="get">
Fill up this field: <input type="text" name="TextValueGet" value="<?=$session->read('TextValueGet')?>">
<input type="submit" value="Go">
<?=$session->FormSID()?>
</form>
<hr>

4. Transferring session ID to itself by client-side JavaScript - retaining other Request values:<br>
<form action="ses1.php" method="POST" name="OklessForm">
Car brand: 
<select name="CarBrand" onChange="javascript:SafeSelfReload(1);return true;">
<option value="0" <?= $CarBrand<1 || $CarBrand>3 ? 'selected':'' ?> >-please select brand-</option>
<option value="1" <?= $CarBrand==1 ? 'selected':'' ?> >Ford T-Modell</option>
<option value="2" <?= $CarBrand==2 ? 'selected':'' ?> >Mitsubishi</option>
<option value="3" <?= $CarBrand==3 ? 'selected':'' ?> >Citroen</option>
</select>
Color: 
<select name="CarColor" onChange="javascript:SafeSelfReload(1);return true;">
<option value="0" <?= $CarColor<1 || $CarColor>4 ? 'selected':'' ?> >-please select color-</option>
<option value="1" <?= $CarColor==1 ? 'selected':'' ?> >black</option>
<option value="2" <?= $CarColor==2 ? 'selected':'' ?> >not painted</option>
<option value="3" <?= $CarColor==3 ? 'selected':'' ?> >pink</option>
<option value="4" <?= $CarColor==4 ? 'selected':'' ?> >yellow</option>
</select>
</form>

<? 
$origin = 'First test page';
$myvar++; 
?>

<? $session->Save(); ?>
======================== END OF ses1.php FILE ======================== 

======================== START OF ses2.php FILE ======================== 
<?
include_once('./ses.php');
global $session;
$session = new SimpleSession();

if( !isset($myvar) )
{
   global $myvar;
   $myvar = 1;
   $session->register('myvar');
}
if( !isset($origin) )
{
   global $origin;
   $origin = 'unknown';
   $session->register('origin');
}
?>
<h1>Second session test page</h1>

You are coming from page '<?= $origin ?>'. Welcome!<br>
Number of visited pages in the session: <?=$myvar?><br>
<!--Session ID: '<?=$session->session_id()?>'--><br>
<hr>

1. Transferring session ID with a URL:<br>
Please visit <a href="ses1.php<?=$session->Req()?>">1st session test page</a>.<br>

<?
$session->register_from_POST('TextValue',   ''); //read posted value and register it.
$session->register_from_GET ('TextValueGet','');
$session->register_from_GET ('CarBrand',    0);
$session->register_from_GET ('CarColor',    0);
?>
<hr>

2. Transferring session ID with a form POST:<br>
<form action="ses1.php" method="post">
Fill up this field: <input type="text" name="TextValue" value="<?=$session->read('TextValue')?>">
<input type="submit" value="Go">
<?=$session->FormSID()?>
</form>
<hr>

3. Transferring session ID with a form GET:<br>
<form action="ses1.php<?=$session->Req()?>" method="get">
Fill up this field: <input type="text" name="TextValueGet" value="<?=$session->read('TextValueGet')?>">
<input type="submit" value="Go">
<?=$session->FormSID()?>
</form>

<? 
$origin = 'Second test page';
$myvar++; 
?>

<? $session->Save(); ?>
======================== END OF ses2.php FILE ======================== 
that's all.