562 Zeilen
18 KiB
PHP
562 Zeilen
18 KiB
PHP
<?php
|
|
/**
|
|
* ConLite Session Management
|
|
*
|
|
* @package Core
|
|
* @subpackage cSystemClasses
|
|
* @version $Rev$
|
|
* @author Ortwin Pinke <conlite@ortwinpinke.de>
|
|
* @copyright (c) 2014, ConLite Team <www.conlite.org>
|
|
* @link http://conlite.org ConLite Portal
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
/**
|
|
* @package ContenidoBackendArea
|
|
* @version 1.1.1.2
|
|
* @author Boris Erdmann, Kristian Koehntopp
|
|
* @copyright four for business AG <www.4fb.de>
|
|
* @license http://www.contenido.org/license/LIZENZ.txt
|
|
* @link http://www.4fb.de
|
|
* @link http://www.contenido.org
|
|
*/
|
|
|
|
if(!defined('CON_FRAMEWORK')) {die('Illegal call');}
|
|
|
|
/**
|
|
* old session class, now only extends new cSession
|
|
*
|
|
* @deprecated since version 2.0
|
|
*/
|
|
class Session extends cSession {
|
|
|
|
}
|
|
|
|
|
|
class cSession {
|
|
|
|
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
|
|
##
|
|
## End of parameters.
|
|
##
|
|
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?
|
|
var $expires; ## Expire date
|
|
var $_expires;
|
|
|
|
## register($things):
|
|
##
|
|
## call this function to register the things that should become persistent
|
|
|
|
function register($things) {
|
|
$arr_things = explode(",", $things);
|
|
reset($arr_things);
|
|
//while (list(, $thing) = each($arr_things)) {
|
|
foreach($arr_things as $thing) {
|
|
$str_thing = trim($thing);
|
|
if ($str_thing) {
|
|
$this->pt[$str_thing] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function setExpires($time) {
|
|
$this->_expires = $time;
|
|
}
|
|
|
|
function is_registered($name) {
|
|
if (isset($this->pt[$name]) && $this->pt[$name] == true)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
function unregister($things) {
|
|
$things = explode(",", $things);
|
|
reset($things);
|
|
foreach ($things as $thing) {
|
|
$thing = trim($thing);
|
|
if ($thing) {
|
|
unset($this->pt[$thing]);
|
|
}
|
|
}
|
|
}
|
|
|
|
## get_id():
|
|
##
|
|
## Propagate the session id according to mode and lifetime.
|
|
## Will create a new id if necessary. To take over abandoned sessions,
|
|
## one may provide the new session id as a parameter (not recommended).
|
|
|
|
function get_id($id = "") {
|
|
global $_COOKIE, $_GET, $_POST, $QUERY_STRING;
|
|
$newid = true;
|
|
|
|
$this->name = $this->cookiename == "" ? $this->classname : $this->cookiename;
|
|
|
|
if ("" == $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;
|
|
default:
|
|
die("This has not been coded yet.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ("" == $id) {
|
|
$newid = true;
|
|
$id = $this->that->ac_newid(md5(uniqid($this->magic)), $this->name);
|
|
}
|
|
|
|
switch ($this->mode) {
|
|
case "cookie":
|
|
if ($newid && ( 0 == $this->lifetime )) {
|
|
SetCookie($this->name, $id, 0, "/", $this->cookie_domain);
|
|
}
|
|
if (0 < $this->lifetime) {
|
|
SetCookie($this->name, $id, time() + $this->lifetime * 60, "/", $this->cookie_domain);
|
|
}
|
|
|
|
// Remove session ID info from QUERY String - it is in cookie
|
|
if (isset($QUERY_STRING) && ("" != $QUERY_STRING)) {
|
|
$QUERY_STRING = preg_replace(
|
|
"/(^|&)" . quotemeta(urlencode($this->name)) . "=" . $id . "(&|$)/", "\\1", $QUERY_STRING);
|
|
}
|
|
break;
|
|
case "get":
|
|
if (isset($QUERY_STRING) && ("" != $QUERY_STRING)) {
|
|
$QUERY_STRING = preg_replace(
|
|
"/(^|&)" . quotemeta(urlencode($this->name)) . "=" . $id . "(&|$)/", "\\1", $QUERY_STRING);
|
|
}
|
|
break;
|
|
default:
|
|
;
|
|
break;
|
|
}
|
|
$this->id = $id;
|
|
}
|
|
|
|
## put_id():
|
|
##
|
|
## Stop using the current session id (unset cookie, ...) and
|
|
## abandon a session.
|
|
|
|
function put_id() {
|
|
global $_COOKIE;
|
|
|
|
switch ($this->mode) {
|
|
case "cookie":
|
|
$this->name = $this->cookiename == "" ? $this->classname : $this->cookiename;
|
|
SetCookie($this->name, "", 0, "/", $this->cookie_domain);
|
|
$_COOKIE[$this->name] = "";
|
|
break;
|
|
|
|
default:
|
|
// do nothing. We don't need to die for modes other than cookie here.
|
|
break;
|
|
}
|
|
}
|
|
|
|
## delete():
|
|
##
|
|
## Delete the current session record and put the session id.
|
|
|
|
function delete() {
|
|
$this->that->ac_delete($this->id, $this->name);
|
|
$this->put_id();
|
|
}
|
|
|
|
## url($url):
|
|
##
|
|
## Helper function: returns $url concatenated with the current
|
|
## session $id.
|
|
|
|
function url($url) {
|
|
// Remove existing session info from url
|
|
$url = preg_replace(
|
|
"/([&?])" . quotemeta(urlencode($this->name)) . "=" . $this->id . "(&|$)/", "\\1", $url);
|
|
|
|
// Remove trailing ?/& if needed
|
|
$url = preg_replace("/[&?]+$/", "", $url);
|
|
|
|
switch ($this->mode) {
|
|
case "get":
|
|
$url .= ( strpos($url, "?") != false ? "&" : "?" ) .
|
|
urlencode($this->name) . "=" . $this->id;
|
|
break;
|
|
default:
|
|
;
|
|
break;
|
|
}
|
|
|
|
// Encode naughty characters in the URL
|
|
$url = str_replace(array("<", ">", " ", "\"", "'"), array("%3C", "%3E", "+", "%22", "%27"), $url);
|
|
return $url;
|
|
}
|
|
|
|
function purl($url) {
|
|
print $this->url($url);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param array $aParam
|
|
* @return string
|
|
*/
|
|
function self_url($aParam = array()) {
|
|
$sURI = $_SERVER["PHP_SELF"];
|
|
parse_str($_SERVER["QUERY_STRING"], $aQuery);
|
|
$aQuery = array_merge($aQuery, $aParam);
|
|
$sQuery = http_build_query($aQuery,'','&');
|
|
|
|
return $this->url($_SERVER["PHP_SELF"] . "?" . $sQuery);
|
|
}
|
|
|
|
function pself_url() {
|
|
print $this->self_url();
|
|
}
|
|
|
|
function hidden_session($mode = 0) {
|
|
if ($mode) {
|
|
return sprintf("<input type=\"hidden\" name=\"%s\" value=\"%s\">\n", $this->name, $this->id);
|
|
} else {
|
|
printf("<input type=\"hidden\" name=\"%s\" value=\"%s\">\n", $this->name, $this->id);
|
|
}
|
|
}
|
|
|
|
function add_query($qarray) {
|
|
global $PHP_SELF;
|
|
global $QUERY_STRING;
|
|
|
|
if ((isset($QUERY_STRING) && ("" != $QUERY_STRING)) || ($this->mode == "get")) {
|
|
$sep_char = "&";
|
|
} else {
|
|
$sep_char = "?";
|
|
}
|
|
|
|
$qstring = "";
|
|
while (list($k, $v) = each($qarray)) {
|
|
$qstring .= $sep_char . urlencode($k) . "=" . urlencode($v);
|
|
$sep_char = "&";
|
|
}
|
|
|
|
return $qstring;
|
|
}
|
|
|
|
function padd_query($qarray) {
|
|
print $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(); ";
|
|
while ("array" == $l) {
|
|
## Structural recursion
|
|
$this->serialize($var . "['" . preg_replace("/([\\'])/", "\\\\1", $k) . "']", $str);
|
|
eval("\$l = gettype(list(\$k)=each(\$$var));");
|
|
}
|
|
|
|
*/
|
|
// $$var is an array. Enumerate the elements and serialize them.
|
|
$str .= "\$$var = array(); ";
|
|
eval("\$l = array(); foreach(\$$var as \$k => \$v) {\$l[] = array(\$k,gettype(\$k),\$v);}");
|
|
foreach ($l as $item) {
|
|
// Structural recursion
|
|
$this->serialize($var . "['" . preg_replace("/([\\'])/", "\\\\1", $item[0]) . "']", $str);
|
|
}
|
|
|
|
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; ";
|
|
while ($l) {
|
|
## Structural recursion.
|
|
$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 = '" . preg_replace("/([\\'])/", "\\\\1", $l) . "'; ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
function get_lock() {
|
|
$this->that->ac_get_lock();
|
|
}
|
|
|
|
function release_lock() {
|
|
$this->that->ac_release_lock();
|
|
}
|
|
|
|
## freeze():
|
|
##
|
|
## freezes all registered things ( scalar variables, arrays, objects ) into
|
|
## a database table
|
|
|
|
function freeze() {
|
|
$str = "";
|
|
//print "DBG: <pre>"; var_dump($this->pt); print "</pre>\n";
|
|
$this->serialize("this->in", $str);
|
|
$this->serialize("this->pt", $str);
|
|
|
|
reset($this->pt);
|
|
$int_cnt_pt = count($this->pt);
|
|
|
|
for($i=0;$i<$int_cnt_pt;$i++) {
|
|
$thing = trim(key($this->pt));
|
|
if ($thing && isset($GLOBALS[$thing])) {
|
|
$this->serialize("GLOBALS['" . $thing . "']", $str);
|
|
}
|
|
next($this->pt);
|
|
}
|
|
/*
|
|
reset($this->pt); echo "\n";
|
|
while (list($thing) = each($this->pt)) {
|
|
//foreach($this->pt as $thing) {
|
|
echo "\n".$thing = trim($thing);
|
|
if ($thing && isset($GLOBALS[$thing])) {
|
|
$this->serialize("GLOBALS['" . $thing . "']", $str);
|
|
}
|
|
}
|
|
*
|
|
*/
|
|
|
|
//return;
|
|
$r = $this->that->ac_store($this->id, $this->name, $str);
|
|
$this->release_lock();
|
|
|
|
if (!$r)
|
|
$this->that->ac_halt("Session: freeze() failed.");
|
|
}
|
|
|
|
## thaw:
|
|
##
|
|
## Reload frozen variables from the database and microwave them.
|
|
|
|
function thaw() {
|
|
$this->get_lock();
|
|
|
|
$vals = $this->that->ac_get_value($this->id, $this->name);
|
|
eval(sprintf(";%s", $vals));
|
|
}
|
|
|
|
##
|
|
## Variable precedence functions
|
|
##
|
|
|
|
function reimport_get_vars() {
|
|
$this->reimport_any_vars("_GET");
|
|
}
|
|
|
|
function reimport_post_vars() {
|
|
$this->reimport_any_vars("_POST");
|
|
}
|
|
|
|
function reimport_cookie_vars() {
|
|
$this->reimport_any_vars("HTTP_COOKIE_VARS");
|
|
}
|
|
|
|
function reimport_any_vars($arrayname) {
|
|
global $$arrayname;
|
|
|
|
if (!is_array($$arrayname))
|
|
return;
|
|
|
|
reset($$arrayname);
|
|
while (list($key, $val) = each($$arrayname)) {
|
|
$GLOBALS[$key] = $val;
|
|
}
|
|
}
|
|
|
|
##
|
|
## 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 = "") {
|
|
global $_COOKIE, $_POST, $_GET,
|
|
$HTTP_HOST, $HTTPS;
|
|
|
|
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;
|
|
|
|
if (isset($HTTPS) && $HTTPS == 'on') {
|
|
## You will need to fix suexec as well, if you
|
|
## use Apache and CGI PHP
|
|
$PROTOCOL = 'https';
|
|
} else {
|
|
$PROTOCOL = 'http';
|
|
}
|
|
header("Status: 302 Moved Temporarily");
|
|
header("Location: " . $PROTOCOL . "://" . $HTTP_HOST . $this->self_url());
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
function put_headers() {
|
|
# Allowing a limited amount of caching, as suggested by
|
|
# Padraic Renaghan on phplib@lists.netuse.de.
|
|
#
|
|
# Note that in HTTP/1.1 the Cache-Control headers override the Expires
|
|
# headers and HTTP/1.0 ignores headers it does not recognize (e.g,
|
|
# Cache-Control). Mulitple Cache-Control directives are split into
|
|
# mulitple headers to better support MSIE 4.x.
|
|
#
|
|
# Added pre- and post-check for MSIE 5.x as suggested by R.C.Winters,
|
|
# see http://msdn.microsoft.com/workshop/author/perf/perftips.asp#Use%20Cache-Control%20Extensions
|
|
# for details
|
|
switch ($this->allowcache) {
|
|
|
|
case "passive":
|
|
$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:
|
|
$rand = md5(mt_rand());
|
|
$mod_gmt = gmdate("D, d M Y H:i:s", time() - 3600) . " GMT";
|
|
|
|
if ($this->_expires > 0) {
|
|
header("Expires: " . gmdate("D, d M Y H:i:s", $this->_expires) . " GMT");
|
|
} else {
|
|
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-store, no-cache, must-revalidate");
|
|
header("Cache-Control: post-check=0, pre-check=0", false);
|
|
header("Cache-control: private, no-cache");
|
|
header("Pragma: no-cache");
|
|
header("ETag: $rand");
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
##
|
|
## Garbage collection
|
|
##
|
|
## 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);
|
|
}
|
|
}
|
|
|
|
##
|
|
## Initialization
|
|
##
|
|
|
|
function start($sid = "") {
|
|
$this->set_container();
|
|
$this->set_tokenname();
|
|
$this->put_headers();
|
|
$this->release_token($sid);
|
|
$this->get_id($sid);
|
|
$this->thaw();
|
|
$this->gc();
|
|
$this->setExpires(0);
|
|
}
|
|
|
|
}
|