Helpdesk da PluGzOne, baseado no osTicket
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

345 lines
9.8 KiB

<?php
/*********************************************************************
class.ostsession.php
Custom osTicket session handler.
Peter Rotich <peter@osticket.com>
Copyright (c) 2006-2013 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
class osTicketSession {
static $backends = array(
'db' => 'DbSessionBackend',
'memcache' => 'MemcacheSessionBackend',
'system' => 'FallbackSessionBackend',
);
var $ttl = SESSION_TTL;
var $data = '';
var $data_hash = '';
var $id = '';
var $backend;
function __construct($ttl=0){
$this->ttl = $ttl ?: ini_get('session.gc_maxlifetime') ?: SESSION_TTL;
// Set osTicket specific session name.
session_name('OSTSESSID');
// Forced cleanup on shutdown
register_shutdown_function('session_write_close');
// Set session cleanup time to match TTL
ini_set('session.gc_maxlifetime', $ttl);
if (OsticketConfig::getDBVersion())
return session_start();
# Cookies
// Avoid setting a cookie domain without a dot, thanks
// http://stackoverflow.com/a/1188145
$domain = null;
if (isset($_SERVER['HTTP_HOST'])
&& strpos($_SERVER['HTTP_HOST'], '.') !== false
&& !Validator::is_ip($_SERVER['HTTP_HOST']))
// Remote port specification, as it will make an invalid domain
list($domain) = explode(':', $_SERVER['HTTP_HOST']);
session_set_cookie_params($ttl, ROOT_PATH, $domain,
osTicket::is_https(), true);
if (!defined('SESSION_BACKEND'))
define('SESSION_BACKEND', 'db');
try {
$bk = SESSION_BACKEND;
if (!class_exists(self::$backends[$bk]))
$bk = 'db';
$this->backend = new self::$backends[$bk]($this->ttl);
}
catch (Exception $x) {
// Use the database for sessions
trigger_error($x->getMessage(), E_USER_WARNING);
$this->backend = new self::$backends['db']($this->ttl);
}
if ($this->backend instanceof SessionBackend) {
// Set handlers.
session_set_save_handler(
array($this->backend, 'open'),
array($this->backend, 'close'),
array($this->backend, 'read'),
array($this->backend, 'write'),
array($this->backend, 'destroy'),
array($this->backend, 'gc')
);
}
// Start the session.
session_start();
}
function regenerate_id(){
$oldId = session_id();
session_regenerate_id();
$this->backend->destroy($oldId);
}
static function destroyCookie() {
setcookie(session_name(), 'deleted', 1,
ini_get('session.cookie_path'),
ini_get('session.cookie_domain'),
ini_get('session.cookie_secure'),
ini_get('session.cookie_httponly'));
}
static function renewCookie($baseTime=false, $window=false) {
setcookie(session_name(), session_id(),
($baseTime ?: time()) + ($window ?: SESSION_TTL),
ini_get('session.cookie_path'),
ini_get('session.cookie_domain'),
ini_get('session.cookie_secure'),
ini_get('session.cookie_httponly'));
}
/* helper functions */
function get_online_users($sec=0){
$sql='SELECT user_id FROM '.SESSION_TABLE.' WHERE user_id>0 AND session_expire>NOW()';
if($sec)
$sql.=" AND TIME_TO_SEC(TIMEDIFF(NOW(),session_updated))<$sec";
$users=array();
if(($res=db_query($sql)) && db_num_rows($res)) {
while(list($uid)=db_fetch_row($res))
$users[] = $uid;
}
return $users;
}
/* ---------- static function ---------- */
static function start($ttl=0) {
return new static($ttl);
}
}
abstract class SessionBackend {
var $isnew = false;
var $ttl;
function __construct($ttl=SESSION_TTL) {
$this->ttl = $ttl;
}
function open($save_path, $session_name) {
return true;
}
function close() {
return true;
}
function getTTL() {
return $this->ttl;
}
function write($id, $data) {
// Last chance session update
$i = new ArrayObject(array('touched' => false));
Signal::send('session.close', null, $i);
return $this->update($id, $i['touched'] ? session_encode() : $data);
}
function cleanup() {
$this->gc(0);
}
abstract function read($id);
abstract function update($id, $data);
abstract function destroy($id);
abstract function gc($maxlife);
}
class SessionData
extends VerySimpleModel {
static $meta = array(
'table' => SESSION_TABLE,
'pk' => array('session_id'),
);
}
class DbSessionBackend
extends SessionBackend {
var $data = null;
function read($id) {
try {
$this->data = SessionData::objects()
->filter(['session_id' => $id])
->annotate(array('is_expired' =>
new SqlExpr(new Q(array('session_expire__lt' => SqlFunction::NOW())))))
->one();
if ($this->data->is_expired > 0) {
// session_expire is in the past. Pretend it is expired and
// reset the data. This will assist with CSRF issues
$this->data->session_data='';
}
$this->id = $id;
}
catch (DoesNotExist $e) {
$this->data = new SessionData(['session_id' => $id, 'session_data' => '']);
}
catch (OrmException $e) {
return false;
}
return $this->data->session_data;
}
function update($id, $data){
global $thisstaff;
if (defined('DISABLE_SESSION') && $this->data->__new__)
return true;
$ttl = $this && method_exists($this, 'getTTL')
? $this->getTTL() : SESSION_TTL;
// Create a session data obj if not loaded.
if (!isset($this->data))
$this->data = new SessionData(['session_id' => $id]);
$this->data->session_data = $data;
$this->data->session_expire =
SqlFunction::NOW()->plus(SqlInterval::SECOND($ttl));
$this->data->user_id = $thisstaff ? $thisstaff->getId() : 0;
$this->data->user_ip = $_SERVER['REMOTE_ADDR'];
$this->data->user_agent = $_SERVER['HTTP_USER_AGENT'];
return $this->data->save();
}
function destroy($id){
return SessionData::objects()->filter(['session_id' => $id])->delete() ? true : false;
}
function cleanup() {
self::gc(0);
}
function gc($maxlife){
SessionData::objects()->filter([
'session_expire__lte' => SqlFunction::NOW()
])->delete();
}
}
class MemcacheSessionBackend
extends SessionBackend {
var $memcache;
var $servers = array();
function __construct($ttl) {
parent::__construct($ttl);
if (!extension_loaded('memcache'))
throw new Exception('Memcached extension is missing');
if (!defined('MEMCACHE_SERVERS'))
throw new Exception('MEMCACHE_SERVERS must be defined');
$servers = explode(',', MEMCACHE_SERVERS);
$this->memcache = new Memcache();
foreach ($servers as $S) {
@list($host, $port) = explode(':', $S);
if (strpos($host, '/') !== false)
// Use port '0' for unix sockets
$port = 0;
else
$port = $port ?: ini_get('memcache.default_port') ?: 11211;
$this->servers[] = array(trim($host), (int) trim($port));
// FIXME: Crash or warn if invalid $host or $port
}
}
function getKey($id) {
return sha1($id.SECRET_SALT);
}
function read($id) {
$key = $this->getKey($id);
// Try distributed read first
foreach ($this->servers as $S) {
list($host, $port) = $S;
$this->memcache->addServer($host, $port);
}
$data = $this->memcache->get($key);
// Read from other servers on failure
if ($data === false && count($this->servers) > 1) {
foreach ($this->servers as $S) {
list($host, $port) = $S;
$this->memcache->pconnect($host, $port);
if ($data = $this->memcache->get($key))
break;
}
}
// No session data on record -- new session
$this->isnew = $data === false;
return $data ?: '';
}
function update($id, $data) {
if (defined('DISABLE_SESSION') && $this->isnew)
return true;
$key = $this->getKey($id);
foreach ($this->servers as $S) {
list($host, $port) = $S;
$this->memcache->pconnect($host, $port);
if (!$this->memcache->replace($key, $data, 0, $this->getTTL()));
$this->memcache->set($key, $data, 0, $this->getTTL());
}
return true;
}
function destroy($id) {
$key = $this->getKey($id);
foreach ($this->servers as $S) {
list($host, $port) = $S;
$this->memcache->pconnect($host, $port);
$this->memcache->replace($key, '', 0, 1);
$this->memcache->delete($key, 0);
}
return true;
}
function gc($maxlife) {
// Memcache does this automatically
}
}
class FallbackSessionBackend {
// Use default PHP settings, with some edits for best experience
function __construct() {
// FIXME: Consider extra possible security tweaks such as adjusting
// the session.save_path
}
}
?>