直接上代码:
代码如下:
class dbsession
{
const type_int = 1;
const type_str = 2;
/**
* database configration
*
* @var array
*/
private $_config = array(
‘host' => '127.0.0.1′,
‘port' => 3306,
‘username' => ‘root',
‘password' => ‘root',
‘dbname' => ‘db_mylab',
‘tablename' => ‘t_sessions',
‘cookie_prefix' => ‘mylab_',
‘cookiepath' => ‘/',
‘cookiedomain' => ”,
‘cookie_timeout' => 900
);
/**
* table fields type array
*
* @var array
*/
private $_db_fields = array(
‘crc32sid' => self::type_int,
‘sessionhash' => self::type_str,
‘idhash' => self::type_str,
‘userid' => self::type_int,
‘ipaddress' => self::type_str,
‘lastactivity' => self::type_str,
‘location' => self::type_str,
‘loggedin' => self::type_int,
‘heartbeat' => self::type_str
);
/**
* db obj
*
* @var mysqli object
*/
private $_mysqli = null;
/**
* weather the session was created or existed previously
*
* @var bool
*/
private $_created = false;
/**
* array of changes.
*
* @var array
*/
private $_changes = array();
/**
* @var bool
*/
private $_db_inited = false;
/**
* session host
*
* @var string
*/
private $_session_host = ”;
/**
* session idhash
*
* @var string
*/
private $_session_idhash = ”;
private $_dbsessionhash = ”;
private $_vars = array();
public function __construct()
{
$this->_dbsessionhash = addslashes($this->get_cookie(‘sessionhash'));
$this->_session_host = substr($_server[‘remote_addr'], 0, 15);
#this should *never* change during a session
$this->_session_idhash = md5($_server[‘http_user_agent'] . self::fetch_substr_ip(self::fetch_alt_ip()) );
$this->_init_config();
$this->init_db();
$gotsession = false;
if ($this->_dbsessionhash)
{
$sql = ‘
select *
from ‘ . $this->_config[‘tablename'] . ‘
where crc32sid = ‘ . sprintf(‘%u', crc32($this->_dbsessionhash)) . ‘
and sessionhash = '‘ . $this->_dbsessionhash . ‘'
and idhash = '‘ . $this->_session_idhash . ‘'
and heartbeat > '‘ . date(‘y-m-d h:i:s' ,timenow – $this->_config[‘cookie_timeout']) . ‘'‘;
//echo $sql;exit;
$result = $this->_mysqli->query($sql);
$session = $result->fetch_array(mysqli_assoc);
if ($session and ($this->fetch_substr_ip($session[‘ipaddress']) == $this->fetch_substr_ip($this->_session_host)))
{
$gotsession = true;
$this->_vars = $session;
$this->_created = false;
}
}
if ($gotsession == false)
{
$this->_vars = $this->fetch_session();
$this->_created = true;
$gotsession = true;
}
if ($this->_created == false)
{
$this->set(‘lastactivity', date(‘y-m-d h:i:s', timenow));
$this->set(‘location', $_server[‘request_uri']);
}
}
/**
* builds an array that can be used to build a query to insert/update the session
*
* @return array array of column name => prepared value
*/
private function _build_query_array()
{
$return = array();
foreach ($this->_db_fields as $fieldname => $cleantype)
{
switch ($cleantype)
{
case self::type_int:
$cleaned = is_numeric($this->_vars[$fieldname]) ? $this->_vars[$fieldname] : intval($this->_vars[$fieldname]);
break;
case self::type_str:
default:
$cleaned = ' . addslashes($this->_vars[$fieldname]) . ';
}
$return[$fieldname] = $cleaned;
}
return $return;
}
/**
* sets a session variable and updates the change list.
*
* @param string name of session variable to update
* @param string value to update it with
*/
public function set($key, $value)
{
if ($this->_vars[$key] != $value)
{
$this->_vars[$key] = $value;
$this->_changes[$key] = true;
}
}
public function get($key)
{
return $this->_vars[$key];
}
public function unsetchangedvar($var)
{
if (isset($this->_changes[$var]))
{
unset($this->_changes[$var]);
}
}
/**
* fetches a valid sessionhash value, not necessarily the one tied to this session.
*
* @return string 32-character sessionhash
*/
static function fetch_sessionhash()
{
return hash(‘md5′ , timenow . rand(1, 100000) . uniqid() );
}
private function _init_config()
{
$registry = zend_registry::getinstance();
$config = $registry->get(‘config');
$this->_config[‘host'] = $config->database->params->host;
$this->_config[‘port'] = $config->database->params->port;
$this->_config[‘username'] = $config->database->params->username;
$this->_config[‘password'] = $config->database->params->password;
$this->_config[‘dbname'] = $config->database->params->dbname;
$this->_config[‘tablename'] = $config->database->session->tablename;
}
/**
* initialize database connection
*/
public function init_db()
{
if ($this->_db_inited)
{
return true;
}
//mysqli_report(mysqli_report_off);
$this->_mysqli = new mysqli(
$this->_config[‘host'],
$this->_config[‘username'],
$this->_config[‘password'],
$this->_config[‘dbname'],
$this->_config[‘port']
);
/* check connection */
if (mysqli_connect_errno())
{
// printf(connect failed: %sn, mysqli_connect_error());
// echo ‘in ‘, __file__, ‘ on line ‘, __line__;
echo { success: false, errors: { reason: ‘ connect failed: . addslashes( mysqli_connect_error() ) . ' }};
exit();
}
$this->_mysqli->query(‘set names latin1′);
$this->_db_inited = true;
return true;
}
/**
* fetches an alternate ip address of the current visitor, attempting to detect proxies etc.
*
* @return string
*/
static function fetch_alt_ip()
{
$alt_ip = $_server[‘remote_addr'];
if (isset($_server[‘http_client_ip']))
{
$alt_ip = $_server[‘http_client_ip'];
}
else if (isset($_server[‘http_from']))
{
$alt_ip = $_server[‘http_from'];
}
return $alt_ip;
}
/**
* returns the ip address with the specified number of octets removed
*
* @param string ip address
*
* @return string truncated ip address
*/
static function fetch_substr_ip($ip, $length = null)
{
return implode(‘.', array_slice(explode(‘.', $ip), 0, 4 – $length));
}
/**
* fetches a default session. used when creating a new session.
*
* @param integer user id the session should be for
*
* @return array array of session variables
*/
public function fetch_session($userid = 0)
{
$sessionhash = self::fetch_sessionhash();
$this->set_cookie(‘sessionhash', $sessionhash);
return array(
‘crc32sid' => sprintf(‘%u', crc32($sessionhash)),
‘sessionhash' => $sessionhash,
‘idhash' => $this->_session_idhash,
‘userid' => $userid,
‘ipaddress' => $this->_session_host,
‘lastactivity' => date(‘y-m-d h:i:s', timenow),
‘location' => $_server[‘request_uri'],
‘loggedin' => $userid ? 1 : 0,
‘heartbeat' => date(‘y-m-d h:i:s', timenow)
);
}
public function get_cookie($cookiename)
{
$full_cookiename = $this->_config[‘cookie_prefix'] . $cookiename;
if (isset($_cookie[$full_cookiename]))
{
return $_cookie[$full_cookiename];
}
else
{
return false;
}
}
public function set_cookie($name, $value = ”, $permanent = 1, $allowsecure = true)
{
if ($permanent)
{
$expire = timenow + 60 * 60 * 24 * 365;
}
else
{
$expire = 0;
}
if ($_server[‘server_port'] == '443′)
{
// we're using ssl
$secure = 1;
}
else
{
$secure = 0;
}
// check for ssl
$secure = ((req_protocol === ‘https' and $allowsecure) ? true : false);
$name = $this->_config[‘cookie_prefix'] . $name;
$filename = ‘n/a';
$linenum = 0;
if (!headers_sent($filename, $linenum))
{ // consider showing an error message if there not sent using above variables?
if ($value == ” and strlen($this->_config[‘cookiepath']) > 1 and strpos($this->_config[‘cookiepath'], ‘/') !== false)
{
// this will attempt to unset the cookie at each directory up the path.
// ie, cookiepath = /test/abc/. these will be unset: /, /test, /test/, /test/abc, /test/abc/
// this should hopefully prevent cookie conflicts when the cookie path is changed.
$dirarray = explode(‘/', preg_replace(‘#/+$#', ”, $this->_config[‘cookiepath']));
$alldirs = ”;
foreach ($dirarray as $thisdir)
{
$alldirs .= $thisdir;
if (!empty($thisdir))
{ // try unsetting without the / at the end
setcookie($name, $value, $expire, $alldirs, $this->_config[‘cookiedomain'], $secure);
}
$alldirs .= /;
setcookie($name, $value, $expire, $alldirs, $this->_config[‘cookiedomain'], $secure);
}
}
else
{
setcookie($name, $value, $expire, $this->_config[‘cookiepath'], $this->_config[‘cookiedomain'], $secure);
}
}
else if (!debug)
{
echo can't set cookies;
}
}
private function _save()
{
$cleaned = $this->_build_query_array();
if ($this->_created)
{
//var_dump($cleaned);
# insert query
$this->_mysqli->query(‘
insert ignore into ‘ . $this->_config[‘tablename'] . ‘
(‘ . implode(‘,', array_keys($cleaned)) . ‘)
values
(‘ . implode(‘,', $cleaned). ‘)
‘);
}
else
{
# update query
$update = array();
foreach ($cleaned as $key => $value)
{
if (!empty($this->_changes[$key]))
{
$update[] = $key = $value;
}
}
if (sizeof($update) > 0)
{
$sql = ‘update ‘ . $this->_config[‘tablename'] . ‘
set ‘ . implode(‘, ‘, $update) . ‘
where crc32sid = ‘ . sprintf(‘%u', crc32($this->_dbsessionhash)) . ‘
and sessionhash = '‘ . $this->_dbsessionhash . ‘'‘;
//echo $sql;
$this->_mysqli->query($sql);
}
}
}
public function getonlineusernum()
{
$sql = ‘
select count(*) as cnt
from ‘ . $this->_config[‘tablename'] . ‘
where loggedin = 1
and heartbeat > '‘ . date(‘y-m-d h:i:s' ,timenow – $this->_config[‘cookie_timeout']) . ‘'‘;
$result = $this->_mysqli->query($sql);
$row = $result->fetch_array(mysqli_assoc);
return $row[‘cnt'];
}
private function _gc()
{
$rand_num = rand(); # randow integer between 0 and getrandmax()
if ($rand_num < 100)
{
$sql = ‘delete from ‘ . $this->_config[‘tablename'] . ‘
where heartbeat < '‘ . date(‘y-m-d h:i:s' ,timenow – $this->_config[‘cookie_timeout']) . ‘'‘;
$this->_mysqli->query($sql);
}
}
public function __destruct()
{
$this->_save();
$this->_gc();
$this->_mysqli->close();
}
}
更多信息请查看IT技术专栏