<?php
/**
 * AgileBill - Open Billing Software
 *
 * This body of work is free software; you can redistribute it and/or
 * modify it under the terms of the Open AgileBill License
 * License as published at http://www.agileco.com/agilebill/license1-4.txt
 *
 * Originally authored by Tony Landis, AgileBill LLC
 *
 * Recent modifications by Deon George
 *
 * @author Deon George <deonATleenooksDOTnet>
 * @copyright 2009 Deon George
 * @link http://osb.leenooks.net
 *
 * @link http://www.agileco.com/
 * @copyright 2004-2008 Agileco, LLC.
 * @license http://www.agileco.com/agilebill/license1-4.txt
 * @author Tony Landis <tony@agileco.com>
 * @package AgileBill
 * @subpackage Core:Session
 */

/**
 * The main AgileBill Session Class
 *
 * @package AgileBill
 * @subpackage Core:Session
 */
class CORE_session {
	# Our session ID
	private $id = '';
	# The time our session expires
	private $sess_date_expire = 0;

	public function __construct() {
		global $C_debug,$VAR;

		$session_arr = array();

		# Get our SESSION ID, either as a GET/POST or COOKIE
		if (isset($_GET['s']) && trim($_GET['s']))
			array_push($session_arr,$_GET['s']);

		elseif (isset($_POST['s']) && trim($_POST['s']))
			array_push($session_arr,$_POST['s']);

		elseif(isset($_COOKIE[COOKIE_NAME]) && trim($_COOKIE[COOKIE_NAME])) {
			array_push($session_arr,$_COOKIE[COOKIE_NAME]);

			# Clear the cookie, as we'll validate it
			$this->id = $_COOKIE[COOKIE_NAME];
			$this->setcookies(true);
			$this->id = '';
		}

		foreach ($session_arr as $s)
			if ($validate = $this->validate($s))
				$this->id = $s;

		$this->sess_date_expire = time()+(SESSION_EXPIRE*60);

		if (! $this->id) {
			$this->tid = empty($VAR['tid']) ? DEFAULT_THEME : $VAR['tid'];
			$this->lid = empty($VAR['lid']) ? DEFAULT_LANGUAGE : $VAR['lid'];
			$this->cid = empty($VAR['cid']) ? DEFAULT_COUNTRY : $VAR['cid'];
			$this->cyid = empty($VAR['cyid']) ? DEFAULT_CURRENCY : $this->get_currency($VAR['cyid']);
			$this->wid = empty($VAR['wid']) ? DEFAULT_WEIGHT : $VAR['wid'];
			$this->rid = empty($VAR['rid']) ? null : $VAR['rid'];
			$this->aid = $this->get_session_link(0,'affiliate');
			$this->caid = $this->get_session_link(0,'campaign');
			$this->sess_logged = false;
			$this->sess_account_id = false;
			$this->session();

		} else {
			$this->tid = empty($VAR['tid']) ? $validate['theme_id'] : $VAR['tid'];
			$this->lid = empty($VAR['lid']) ? $validate['language_id'] : $VAR['lid'];
			$this->cid = empty($VAR['cid']) ? $validate['country_id'] : $VAR['cid'];
			$this->cyid = empty($VAR['cyid']) ? $validate['currency_id'] : $this->get_currency($VAR['cyid']);
			$this->wid = empty($VAR['wid']) ? $validate['weight_id'] : $VAR['wid'];
			$this->rid = empty($VAR['rid']) ? $validate['reseller_id'] : $VAR['rid'];
			$this->aid = empty($VAR['aid']) ? $validate['affiliate_id'] : $this->get_session_link($validate['affiliate_id'],'affiliate');
			$this->caid = empty($VAR['caid']) ? $validate['campaign_id'] : $this->get_session_link($validate['campaign_id'],'campaign');
			$this->sess_logged = $validate['logged'];
			$this->sess_account_id = $validate['account_id'];

			$db = &DB();

			# Only update the session (every 5 mins) if we are logged in
			if ($validate['logged'] && $this->sess_date_expire+60*5 < time())
				$db->Execute(
					sqlUpdate($db,'session',array(
						'date_last'=>time(),
						'date_expire'=>$this->sess_date_expire,
						'ip'=>USER_IP,
						'theme_id'=>$this->tid,
						'country_id'=>$this->cid,
						'language_id'=>$this->lid,
						'currency_id'=>$this->cyid,
						'weight_id'=>$this->wid,
						'reseller_id'=>$this->rid,
						'affiliate_id'=>$this->aid,
						'campaign_id'=>$this->caid,
					),array('id'=>$this->id)));
		}

		if (! defined('SESS'))
			define('SESS',$this->id);

		$this->setcookies();
	}

	private function validate($session_id) {
		global $C_debug;

		$db = &DB();

		$q = str_replace('{p}',AGILE_DB_PREFIX,str_replace('{s}',DEFAULT_SITE,sprintf(
			'SELECT A.*,B.id AS acct_id,B.status,B.date_expire AS account_date_expire,C.date_expire AS sess_auth_date_expire,C.group_arr,C.module_arr
			FROM {p}session AS A
			LEFT JOIN {p}account AS B ON B.id=A.account_id LEFT JOIN {p}session_auth_cache AS C ON A.id=C.session_id
			WHERE A.id=%s AND A.site_id={s} AND ((B.site_id={s} AND A.account_id IS NOT NULL) OR (B.site_id IS NULL AND A.account_id IS NULL)) AND C.site_id={s}',$db->qstr($session_id)
		)));

		$rs = $db->Execute($q);
		if (! $rs) {
			$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
			printf('Unable to start session: Database Error: %s',$db->ErrorMsg());

			return false;

		} elseif ($rs->RecordCount() == 0) {
			return false;
		}

		# Set the auth caching for use in the auth module to save a query there:
		$this->auth_cache['date_expire'] = $rs->fields['sess_auth_date_expire'];
		$this->auth_cache['group_arr'] = $rs->fields['group_arr'];
		$this->auth_cache['module_arr'] = $rs->fields['module_arr'];

		if ($rs->fields['logged'] == 1) {
			if ($rs->fields['status'] != 1)
					return false;

			elseif (! empty($rs->fields['account_date_expire']) && $rs->fields['account_date_expire'] < time())
					return false;

			elseif (SESSION_EXPIRE != 0 && $rs->fields['date_expire'] <= time()) {
				$this->logout($session_id);
				return false;
			}
		}

		if (SESSION_IP_MATCH && ($rs->fields['ip'] != USER_IP)) {
			$this->delete($session_id);
			return false;
		}

		return $rs->fields;
	}

	/**
	 * Set or expire cookies
	 */
	private function setcookies($expire=false) {
		if (defined('AGILE_COOKIE') && AGILE_COOKIE != '') {
			$domain = AGILE_COOKIE;

		} else {
			global $_SERVER;

			if (isset($_SERVER['HTTP_HOST'])) {
				$domain = $_SERVER['HTTP_HOST'];
			} elseif (isset($_SERVER['SERVER_NAME'])) {
				$domain = $_SERVER['SERVER_NAME'];
			} elseif (function_exists('getallheaders')) {
				$server = getallheaders();
				$domain = $server['Host'];
			} else {
				echo '<PRE>';print_r($_SERVER);echo '</PRE>';
				echo 'ERROR: Cant work out our domain?';
				die();
			}

			$domain = '.'.preg_replace('/^www./','',$domain);
		}

		if ($expire)
			$cookie_expire = 0;
		elseif (COOKIE_EXPIRE == 0)
			$cookie_expire = (time()+86400*365);
		else
			$cookie_expire = (time()+(COOKIE_EXPIRE*60));

		if (empty($domain) || preg_match('/localhost/',$domain))
			setcookie(COOKIE_NAME,$this->id,$cookie_expire,'/');
		else
			setcookie(COOKIE_NAME,$this->id,$cookie_expire,'/',$domain);

		# Affiliate Cookie
		if (! empty($this->aid)) {
			$aid_cookie_name = COOKIE_NAME.'aid';
			if ($expire)
				$aid_expire = 0;
			else
				$aid_expire = time()+86400*720;

			if (empty($domain) || preg_match('/localhost/',$domain))
				setcookie($aid_cookie_name,$this->aid,$aid_expire,'/');
			else
				setcookie($aid_cookie_name,$this->aid,$aid_expire,'/',$domain);
		}

		# Campaign Cookie
		if (! empty($this->caid)) {
			$cid_cookie_name = COOKIE_NAME.'caid';
			if ($expire)
				$cid_expire = 0;
			else
				$cid_expire = time()+86400*720;

			if (empty($domain) || preg_match('/localhost/',$domain))
				setcookie($cid_cookie_name,$this->caid,$cid_expire,'/');
			else
				setcookie($cid_cookie_name,$this->caid,$cid_expire,'/',$domain);
		}
	}

	private function get_session_link($id,$type) {
		global $VAR;

		switch($type) {
			case 'affiliate' : $var = 'aid'; $table = 'affiliate'; break;
			case 'campaign' : $var = 'caid'; $table = 'campaign'; break;
			default:
				return '';
		}

		$cookie_name = sprintf('%s%s',COOKIE_NAME,$var);

		if (isset($VAR[$var]))
			$i = $VAR[$var];
		elseif (isset($_COOKIE[$cookie_name]))
			$i = $_COOKIE[$cookie_name];

		if (empty($i))
			return '';
		elseif ($i == $id)
			return $i;

		# Validate
		else {
			$db = &DB();
			$rs = $db->Execute(sqlSelect($table,'id',array('where'=>array('id'=>$i))));
			if ($rs && $rs->RecordCount())
				return $i;
			else
				return '';
		}
	}

	private function get_currency($id)  {
		$db = &DB();
		$rs = $db->Execute(sqlSelect('currency','status',array('where'=>array('id'=>$id))));
		if ($rs && $rs->RecordCount() && $rs->fields['status'] == 1)
			return $id;

		global $VAR;
		$VAR['cyid'] = DEFAULT_CURRENCY;

		return DEFAULT_CURRENCY;
	}

	/**
	 * Create a session
	 */
	private function session() {
		global $C_debug;
		$db = &DB();

		mt_srand((double)microtime()*1000000);
		$this->id = md5(uniqid(mt_rand(),1));

		$rs = $db->Execute(sqlSelect('session','id',array('where'=>array('id'=>$this->id))));
		if (! $rs) {
			echo 'SESSION FAILED: Unable to connect to database';

			exit;
		}

		if (! $rs->RecordCount()) {
			$rs = $db->Execute(
				sqlInsert($db,'session',array(
					'date_orig'=>time(),
					'date_last'=>time(),
					'date_expire'=>$this->sess_date_expire,
					'affiliate_id'=>$this->aid,
					'reseller_id'=>$this->rid,
					'country_id'=>$this->cid,
					'language_id'=>$this->lid,
					'currency_id'=>$this->cyid,
					'weight_id'=>$this->wid,
					'theme_id'=>$this->tid,
					'campaign_id'=>$this->caid,
					'logged'=>0,
					'ip'=>USER_IP
				),$this->id));

			if (! $rs) {
				$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
				printf('Unable to start session: Db error<br/><br/>%s<br/><br/>%s',$q,$db->ErrorMsg());

				exit;
			}
		}
	}

	private function logout($sess) {
		$db = &DB();

		$rs = $db->Execute(sqlUpdate($db,'session',array('logged'=>0),array('id'=>$sess)));
		if (! $rs) {
			global $C_debug;
			$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());

			return false;
		}

		$db->Execute(sqlDelete($db,'session_auth_cache',array('session_id'=>$sess)));

		define('FORCE_SESS_ACCOUNT',0);
		define('FORCE_SESS_LOGGED',false);

		if (CACHE_SESSIONS == '1') {
			$VAR['_login'] = '1';
			$force = true;
			$C_auth = new CORE_auth($force);

			global $C_auth2;
			$C_auth2 = $C_auth;
		}
	}

	/**
	 * Delete a session
	 */
	private function delete($sess) {
		$db = &DB();

		$rs = $db->Execute(sqlDelete($db,'session',array('id'=>$sess)));
		if (! $rs === false) {
			global $C_debug;
			$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());

			return false;
		}
	}

	/**
	 * Define the session constants
	 */
	public function session_constant() {
		# Define the constants
		define('SESS_THEME',$this->tid);
		define('SESS_LANGUAGE',$this->lid);
		define('SESS_COUNTRY',$this->cid);
		define('SESS_CURRENCY',$this->cyid);
		define('SESS_WEIGHT',$this->wid);
		define('SESS_RESELLER',$this->rid);
		define('SESS_AFFILIATE',$this->aid);
		define('SESS_CAMPAIGN',$this->caid);
	}

	public function session_constant_log() {
		global $VAR;

		if (isset($VAR['_login']) || isset($VAR['_logout'])) {
			$db = &DB();

			$rs = $db->Execute(sqlSelect('session','logged,account_id',array('where'=>array('id'=>$this->id))));

			if (! $rs) {
				global $C_debug;
				$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());

				return;
			}

			if (! defined('SESS_LOGGED'))
				define('SESS_LOGGED',$rs->fields['logged']);
			if (! defined('SESS_ACCOUNT'))
				define('SESS_ACCOUNT',$rs->fields['account_id']);

		} else {
			if (! defined('SESS_LOGGED'))
				define('SESS_LOGGED',$this->sess_logged);
			if (! defined('SESS_ACCOUNT'))
				define('SESS_ACCOUNT',$this->sess_account_id);
		}

		if (SESS_LOGGED)
			define('SESS_EXPIRES',$this->sess_date_expire);
		else
			define('SESS_EXPIRES',0);
	}
}
?>