PHP File Session reader

Updated digital-ether 2 Tallied Votes 1K Views Share

The above classes provide an interface for reading the PHP session data.

PHP alone only gives you access to the current users session. This class allows you to read all session files, and thus allow you to read session data across different users.

This may be useful if you want to copy, backups session data, or transfer to a different format/handler etc..

At the moment it only reads file based session handling, with PHP doing the serializing and handling (the default setting). It does not support other session handlers or serializers.

You can extend the base abstract class for different handlers and serializations.

Example usage:

require 'FileSessionData.php';

// instantiate the file session reader
$FileSession = FileSessionData::singleton();

// get all saved session ids
$sess_ids = $FileSession->getIds();

// loop through each session id on the server and show session data
foreach($sess_ids as $id) 
{
  // get the session data
  if ($data = $FileSession->get($id))
  {
    // dump session array
    dumper($data);
    // dump serialized session
    dumper(FileSessionData::encode($data));

    exit; // lets limit to just one for testing
  }
}




/**
 * Dump utility
 * @param Object
 */
function dumper($data)
{
  echo '<pre>' . print_r($data, true) . '</pre>';
}
/**
 * Class for retrieving session data when save handler is files
 * 
 * Features:
 * Retrieving of all session data saved by PHP, not just the current user
 * Encoding and decoding in PHP session format (not serialize|unserialize)
 * 
 * @author gabe@fijiwebdesign.com
 * @link http://www.fijiwebdesign.com/
 * 
 */
class FileSessionData extends AbstractSessionData
{
  
  /**
   * @var array Sesssion Files
   */
  static $sess_files;
  /**
   * @var array Session Ids
   */
  static $sess_ids;
  
  /**
   * Do not call constructor, use FileSessionData::singleton();
   */
  protected function __construct()
  {
    // configs
    $this->handler = ini_get('session.save_handler');
    $this->save_path = ini_get('session.save_path');
    
    // make sure session is using files
    if ( $this->handler !== 'files') 
    {
      throw new Exception('This class (' . __CLASS__ .') only works for file based session handling.');
    }
    
    // start session (it may already be started so suppress errors)
    @session_start();
  }
  
  /**
   * Retrieve a single instance of this class
   * 
   * @usage 
   * 
   * $SessionData = FileSessionData::singleton();
   * 
   */
  public static function singleton(array $args = array())
  {
    return parent::singleton(__CLASS__, $args);
  }
  
  /**
   * Get the session Object for a session id
   * 
   * @param string Session ID
   * 
   * @return array|bool
   */
  public function get($sess_id)
  {
    $data = $this->read($sess_id);
    if ($data)
    {
      return self::decode($data);
    }
    return false;
  }
  
  /**
   * Save the session Object for a session id
   * 
   * @param string Session ID
   * @param array Session Object
   * 
   * @return Bool
   */
  public function set($sess_id, array $sess)
  {
    $data = self::encode($sess);
    return $this->write($sess_id, $data);
  }
  
  /**
   * Unset a session
   * 
   * @param string Session ID
   * 
   * @return Bool
   */
  public function un_set($sess_id)
  {
    return unlink($this->getPath($sess_id));
  }
  
  /**
   * Returns if a session exists given it's ID
   * 
   * @param string Session ID
   * 
   * @return Bool
   */
  public function is_set($sess_id)
  {
    return file_exists($this->getPath($sess_id));
  }
  
  /**
   * Write raw session data to a session
   * 
   * @param string Session Id
   * @param string Session encoded data
   * 
   * @return Bool Write result
   */
  public function write($sess_id, $data)
  {
    return file_put_contents($this->getPath($sess_id), $data);
  }
  
  /**
   * Read raw session data from a session
   * 
   * @param string Session Id
   * 
   * @return string Session Data
   */
  public function read($sess_id)
  {
    return file_get_contents($this->getPath($sess_id));
  }
  
  /**
   * Retrieve all session Ids
   * 
   * @return array
   */
  public function getIds()
  {
    
    if (!self::$sess_ids) 
    {
      
      $files = $this->getFiles();
      
      self::$sess_ids = array();
      foreach($files as $file) {
        // @todo use substr ? 
        $parts = explode('_', $file);
        self::$sess_ids[] = array_pop($parts);
      }
    }
    
    return self::$sess_ids;
    
  }
  
  /**
   * Retrieve the file to the session given its id
   * 
   * @param string Session ID
   * 
   * @return string Session Path (Path may not exist)
   */
  private function getPath($sess_id)
  {
    return $this->save_path . '/sess_' . $sess_id;
  }
  
  /**
   * Retrieve the list of session files
   * 
   * @return array
   */
  private function getFiles()
  {
    if (!self::$sess_files) 
    {
      self::$sess_files = glob($this->save_path . '/sess_*');
    }

    return self::$sess_files;
  }
  
   /**
   * Decode/Unserialize encoded session data string
   * 
   * @param string Session encoded data
   * 
   * @return string Session Object
   */
  public static function decode($data) 
  {
    return parent::decode($data);
    
  }
  
  /**
   * Encode/Serialize Object in session format
   * 
   * @param array Session Object
   * 
   * @return string Session encoded data
   */
  public static function encode(array $sess) 
  {
    return parent::encode($sess);
  }
  
  /**
   * Maps isset() and unset()
   */
  public function __call($method, $args)
  {
    if ($method == 'isset')
    {
      return call_user_func_array(array($this, 'is_set'), $args);
    }
    else if ($method == 'unset')
    {
      return call_user_func_array(array($this, 'un_set'), $args);
    }
    else 
      {
        throw new Exception('Call to non-existant method ' . htmlentities($method) . ' of class ' . htmlentities(__CLASS__));
      }
  }
  
}

/**
 * Class for retrieving session data
 * 
 * Features:
 * Retrieving of all session data saved by PHP, not just the current user
 * Encoding and decoding in PHP session format (not serialize|unserialize)
 * 
 * @author gabe@fijiwebdesign.com
 * @link http://www.fijiwebdesign.com/
 * 
 * This class must be implemented for each Session Handler as retrieving session data will be different for each
 * 
 */
abstract class AbstractSessionData
{
  
  /**
   * Retrieve a single instance of this class
   * 
   * @usage 
   * 
   * $SessionData = AbstractSessionData::singleton('FileSessionData');
   * 
   */
  public static function singleton($classname, array $args)
  {
    static $instance = array();
    if (!isset($instance[$classname])) 
    {
      $instance[$classname] = new $classname;
    }
    
    return $instance[$classname];
  }
  
  /**
   * Get the session Object for a session id
   * 
   * @param string Session ID
   * 
   * @return array|Bool
   */
  abstract public function get($sess_id);
  
  /**
   * Save the session Object for a session id
   * 
   * @param string Session ID
   * @param array Session Object
   * 
   * @return Bool
   */
  abstract public function set($sess_id, array $sess);
  
  /**
   * Unset a session
   * 
   * @param string Session ID
   * 
   * @return Bool
   */
  abstract public function un_set($sess_id);
  
  /**
   * Returns if a session exists given it's ID
   * 
   * @param string Session ID
   * 
   * @return Bool
   */
  abstract public function is_set($sess_id);
  /**
   * Write raw session data to a session
   * 
   * @param string Session Id
   * @param string Session encoded data
   * 
   * @return Bool Write result
   */
  abstract public function write($sess_id, $data);
  
  /**
   * Read raw session data from a session
   * 
   * @param string Session Id
   * 
   * @return string Session Data
   */
  abstract public function read($sess_id);
  
  /**
   * Retrieve all session Ids
   * 
   * @return array
   */
  abstract public function getIds();
  
  
  /**
   * Decode/Unserialize encoded session data string
   * 
   * @param string Session encoded data
   * 
   * @return string Session Object
   */
  public static function decode($data) 
  {
    // save current session var and empty it
    $sess_orig = $_SESSION;
    $_SESSION = array();
    
    // decode session data to $_SESSION
    session_decode($data);
    
    // restore original session
    $sess = $_SESSION;
    $_SESSION = $sess_orig; 
    
    return $sess;
    
  }
  
  /**
   * Encode/Serialize Object in session format
   * 
   * @param array Session Object
   * 
   * @return string Session encoded data
   */
  public static function encode(array $sess) 
  {
    // save current session var
    $sess_orig = $_SESSION;
    $_SESSION = $sess;
    
    // decode session data in $_SESSION
    $data = session_encode();
    
    // restore original session
    $_SESSION = $sess_orig; 
    
    return $data;
    
  }
  
}
Member Avatar for P0lT10n
P0lT10n

Very well coded, thanks for this !

digital-ether 399 Nearly a Posting Virtuoso Team Colleague

Thanks. I added un_set() and is_set() methods which can also be called using isset() and unset().

mschroeder 251 Bestower of Knowledge Team Colleague

What was the reasoning for it to be designed as a singleton?

digital-ether 399 Nearly a Posting Virtuoso Team Colleague

Because it doesn't make sense to have two instances. For other session handlers such as DB, Memcached etc. you don't want to have multiple connections.

It also will want to cache a bunch of stuff like session Ids etc. You don't want multiple caches, and can just implement those as properties and know it won't be duplicated - static or not.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.