<?PHP
/*
 * Session Management for PHP3
 *
 * Copyright (c) 1998-2000 NetUSE AG
 *                    Boris Erdmann, Kristian Koehntopp
 *
 * $Id: session.inc,v 1.2 2004/10/18 16:36:24 Eppi Exp $
 *
 */

class Session {
	var $classname = 'Session';	// Needed for object serialization.

	// Define the parameters of your session by either overwriting
	// these values or by subclassing session (recommended).
	var $magic = '';		// Some string you should change.
	var $mode = 'cookie';		// We propagate session IDs with cookies
	var $fallback_mode;		// If this doesn't work, fall back...
	var $lifetime = 0;		// 0 = do session cookies, else minutes
	var $cookie_domain = '';	// If set, the domain for which the session cookie is set.
	var $gc_time = 1440;		// Purge all session data older than 1440 minutes.
	var $gc_probability = 5;	// Garbage collect probability in percent
	var $auto_init = '';		// Name of the autoinit-File, if any.
	var $secure_auto_init = 1;	// Set to 0 only, if all pages call page_close() guaranteed.
	var $allowcache = 'no';		// "passive", "no", "private" or "public"
	var $allowcache_expire = 1440;	// If you allowcache, data expires in this many minutes.
	var $that_class = '';		// Name of data storage container

	var $name;			// Session name
	var $id;			// Unique Session ID
	var $that;
	var $pt = array();		// This Array contains the registered things
	var $in = 0;			// Marker: Did we already include the autoinit file?

	// Variablen in der Session speichern
	function register($things) {
		$things = explode(',', $things);
		reset($things);
		while (list(,$thing) = each($things)) {
			$thing = trim($thing);
			if (isset($thing)) $this->pt[$thing] = true;
		}
	}

	// ist Variable registriert?
	function is_registered($name) {
		if (isset($this->pt[$name]) && $this->pt[$name] == true) return true;
		return false;
	}

	// Variable aus Session entfernen
	function unregister($things) {
		$things = explode(',', $things);
		reset($things);
		while (list(,$thing) = each($things)) {
			$thing = trim($thing);
			if (isset($thing)) unset($this->pt[$thing]);
		}
	}

	// Session generieren - verl&auml;ngern
	function get_id($id = '') {
		$newid = true;
		$this->name = ($this->cookiename == '') ? $this->classname : $this->cookiename;
		if (empty($id)) {
			$newid = false;
			switch ($this->mode) {
				case 'get':
					$id = isset($_GET[$this->name]) ? $_GET[$this->name] : (isset($_POST[$this->name]) ? $_POST[$this->name] : '');
					break;
				case 'cookie':
					$id = isset($_COOKIE[$this->name]) ? $_COOKIE[$this->name] : '';
					break;
				}
		}
		if (empty($id)) {
			$newid=true;
			if(!empty($this->id)) $id = $this->id;
			else $id = $this->that->ac_newid(md5(uniqid($this->magic)), $this->name);
		}
		switch ($this->mode) {
			case 'cookie':
				if ($newid && ($this->lifetime == 0)) {
                                 	SetCookie($this->name, $id, 0, '/', $this->cookie_domain);
                                 }
				if ($this->lifetime > 0) {
                                 	SetCookie($this->name, $id, time()+$this->lifetime*60, '/', $this->cookie_domain);
                                 }

				// Sessionvariable entfernen
				if (isset($_SERVER['QUERY_STRING']) && ('' != $_SERVER['QUERY_STRING'])) {
					$_SERVER['QUERY_STRING'] = ereg_replace("(^|&)".quotemeta(urlencode($this->name)).'='.$id."(&|$)",
								     "\\1", $_SERVER['QUERY_STRING']);
				}
				break;
			case 'get':
				if (isset($_SERVER['QUERY_STRING']) && (!empty($_SERVER['QUERY_STRING']))) {
					$_SERVER['QUERY_STRING'] = ereg_replace("(^|&)".quotemeta(urlencode($this->name)).'='.$id."(&|$)",
	                                 			     "\\1", $_SERVER['QUERY_STRING']);
				}
				break;
		}
		$this->id = $id;
	}

	// Session im Cookie l&ouml;schen
	function put_id() {
		switch ($this->mode) {
			case 'cookie':
				$this->name = ($this->cookiename == '') ? $this->classname : $this->cookiename;
				SetCookie($this->name, '', 0, '/', $this->cookie_domain);
				$_COOKIE[$this->name] = '';
				break;
		}
	}

	// Session entfernen
	function delete() {
		$this->that->ac_delete($this->id, $this->name);
		$this->put_id();
	}

	// Gibt URL mit Session zur&uuml;ck
	function url($url) {
		if (!$this->session_enabled) return $url;

		// Session entfernen
		$url = ereg_replace("([&?])".quotemeta(urlencode($this->name)).'='.$this->id."(&|$)", "\\1", $url);

		// Verbindungszeichen ? oder & entfernen
		$url=ereg_replace("[&?]+$", '', $url);
		switch ($this->mode) {
			case 'get':
				// Anchor-Fragment extrahieren
				$dummy = split('#',$url);
				$url = $dummy[0];
				$url .= (strpos($url, '?') != false ?  '&' : '?').urlencode($this->name).'='.$this->id;
				$url .= isset($dummy[1]) ? '#'.$dummy[1] : '';
				break;
		}

		// Sonderzeichen ersetzen
		$url = str_replace(array('<', '>', ' ', '"', '\''), array("%3C", "%3E", '+', "%22", "%27"), $url);
		return $url;
	}

	// url ausgeben
	function purl($url) {
		echo $this->url($url);
	}

	function self_url() {
		global $idcatside;

		return $this->url($_SERVER['PHP_SELF'].((isset($_SERVER['QUERY_STRING']) && ($_SERVER['QUERY_STRING'] != '')) ? '?'.$_SERVER['QUERY_STRING'] : '?idcatside='. $idcatside));
	}

	function pself_url() {
		echo $this->self_url();
	}

	function hidden_session() {
		printf("<input type=\"hidden\" name=\"%s\" value=\"%s\">\n", $this->name, $this->id);
	}

	function add_query($qarray) {
		$sep_char = ((isset($_SERVER['QUERY_STRING']) && (!empty($_SERVER['QUERY_STRING']))) || ($this->mode == 'get')) ? '&' : '?';
		$qstring = '';
		while (list($k, $v) = each($qarray)) {
			$qstring .= $sep_char.urlencode($k).'='.urlencode($v);
			$sep_char = '&';
		}
		return $qstring;
	}

	function padd_query($qarray) {
		echo $this->add_query($qarray);
	}

	// serialize($var,&$str):
	// appends a serialized representation of $$var
	// at the end of $str.
	// To be able to serialize an object, the object must implement
	// a variable $classname (containing the name of the class as string)
	// and a variable $persistent_slots (containing the names of the slots
	// to be saved as an array of strings).
	function serialize($var, &$str) {
		static $t,$l,$k;

		// Determine the type of $$var
		eval("\$t = gettype(\$$var);");
		switch ($t) {
			case 'array':
				// $$var is an array. Enumerate the elements and serialize them.
				eval("reset(\$$var); \$l = gettype(list(\$k)=each(\$$var));");
				$str .= "\$$var = array(); ";

				// Structural recursion
				while ('array' == $l) {
					$this->serialize($var."['".ereg_replace("([\\'])", "\\\\1", $k)."']", $str);
					eval("\$l = gettype(list(\$k)=each(\$$var));");
				}
				break;
			case 'object':
				// $$var is an object. Enumerate the slots and serialize them.
				eval("\$k = \$${var}->classname; \$l = reset(\$${var}->persistent_slots);");
				$str.="\$$var = new $k; ";

				// Structural recursion.
				while ($l) {
					$this->serialize($var."->".$l, $str);
					eval("\$l = next(\$${var}->persistent_slots);");
				}
				break;
			default:
				// $$var is an atom. Extract it to $l, then generate code.
				eval("\$l = \$$var;");
				$str.="\$$var = '".ereg_replace("([\\'])", "\\\\1", $l)."'; ";
				break;
		}
	}

	function get_lock() {
		$this->that->ac_get_lock();
	}

	function release_lock() {
		$this->that->ac_release_lock();
	}

	// Session in DB schreiben
	function freeze() {
		$str = '';
		$this->serialize("this->in", $str);
		$this->serialize("this->pt", $str);
		reset($this->pt);
		while (list($thing) = each($this->pt)) {
			$thing=trim($thing);
			if (isset($thing)) $this->serialize("GLOBALS['".$thing."']", $str);
		}
		$r = $this->that->ac_store($this->id, $this->name, $str);
		$this->release_lock();
		if (!$r) $this->that->ac_halt("Session: freeze() failed.");
	}

	// Sessionvariablen aus DB holen
	function thaw() {
		$this->get_lock();
		$vals = $this->that->ac_get_value($this->id, $this->name);
		eval(sprintf(";%s",$vals));
	}

	// All this is support infrastructure for the start() method
	function set_container() {
		$name = $this->that_class;
		$this->that = new $name;
		$this->that->ac_start();
	}

	function set_tokenname() {
		$this->name = $this->cookiename==''?$this->classname:$this->cookiename;
	}

	function release_token($sid = '') {
		if (isset($this->fallback_mode) && ('get' == $this->fallback_mode) && ('cookie' == $this->mode) && (!isset($_COOKIE[$this->name]))) {
			// Looks like no cookie here - check GET/POST params
			if (isset($_GET[$this->name]) || isset($_POST[$this->name])) {
				// Session info passed via GET/POST - go to fallback_mode
				$this->mode = $this->fallback_mode;
			} else {
				// It seems to be the first load of this page -
				// no cookie and no GET/POST params
				// Generate session ID and setup cookie.
				$this->get_id($sid);

				// Next line is to generate correct self_url() later
				$this->mode = $this->fallback_mode;
			}
		}
	}

	function put_headers() {
		switch ($this->allowcache) {
			case 'assive':
				$mod_gmt = gmdate('D, d M Y H:i:s', getlastmod()).' GMT';
				header('Last-Modified: '.$mod_gmt);

				// possibly ie5 needs the pre-check line. This needs testing.
				header('Cache-Control: post-check=0, pre-check=0');
				break;
			case 'public':
				$exp_gmt = gmdate('D, d M Y H:i:s', time() + $this->allowcache_expire * 60).' GMT';
				$mod_gmt = gmdate('D, d M Y H:i:s', getlastmod()).' GMT';
				header('Expires: '.$exp_gmt);
				header('Last-Modified: '.$mod_gmt);
				header('Cache-Control: public');
				header('Cache-Control: max-age='.$this->allowcache_expire * 60);
				break;
			case 'private':
				$mod_gmt = gmdate('D, d M Y H:i:s', getlastmod()).' GMT';
				header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
				header('Last-Modified: '.$mod_gmt);
				header('Cache-Control: private');
				header('Cache-Control: max-age='.$this->allowcache_expire * 60);
				header('Cache-Control: pre-check='.$this->allowcache_expire * 60);
				break;
			default:
				header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
				header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
				header('Cache-Control: no-cache');
				header('Cache-Control: post-check=0, pre-check=0');
				header('Pragma: no-cache');
				break;
		}
	}

	// Destroy all session data older than this
	function gc() {
		srand(time());
		if ((rand()%100) < $this->gc_probability) $this->that->ac_gc($this->gc_time, $this->name);
	}

	// Session Initialisieren
	function start($sid = '') {
		if (!$this -> session_enabled) return false;
		$this->set_container();
		$this->set_tokenname();
		$this->put_headers();
		$this->release_token($sid);
		$this->get_id($sid);
		$this->thaw();
		$this->gc();
	}
}
?>