<?php


Class Install{
	var $path;

	var $DatabaseName = "logaholic";	# Default database name
	var $databasedriver = "mysql";		# For now we only support mysql as database driver. (this used to be an array) 
	var $mysqlserver = "127.0.0.1";		# Default Mysql server
	var $mysqluname = "";				# Mysql user
	var $mysqlpw = "";					# Mysql user password
	var $mysqlprefix = "";				# The Logaholic tables prefix
	var $mysqltmp = "";					# Location to the Temporary mysql directory
	var $datadir = "";					# Location to the /data/ directory

	var $adminUser = "";				# The admin user that is to be inserted to the users table
	var $adminName = "";				# The admin name that is to be inserted to the users table
	var $adminEmail = "";				# The admin email that is to be inserted to the users table
	var $adminUserPass = "";			# Password of the admin user
	var $adminNeeded = true;			# Does the Installation already has an admin user or does it needs a new user?

	var $warning_level = 2;				# tell the install what output to give ( 0 = no output - 1 = warnings only - 2 = all output )

	var $db;							# This is the database object
	var $connected = false;				# This variable is set to true if the db object is set and connected to a database
	var $php_version = "5.3.0"; 		# The minimum php version recommended
	var $errors = 0;					# If there is something wrong then this variable gets a +1
	var $global_file;					# Location to the global.php file
	var $langs = array(					# All available languages
		"dutch"
		,"english"
		,"french"
		,"german"
		,"italian"
		,"portuguese"
		,"spanish"
	); 								

	/*
	**	In the constructor we set the paths to the Logaholic directory
	*/
	function __CONSTRUCT($path = ""){
		if(empty($path)){
			$this->path = $this->LogaPath();
		} else {
			$this->path = $path;
		}

		$this->SetPathVars();
	}

	/*
	**	set the path to the Logaholic dirs
	*/
	function SetPathVars(){
		$this->mysqltmp = $this->path ."/data/";
		$this->datadir = $this->path ."/data/";
		$this->global_file = $this->path."/files/global.php";
	}

	/*
	**	Get the path to the Logaholic root folder
	*/
	function LogaPath(){
		$real_path = realpath("index.php");
		$path = dirname($real_path);
		return str_replace ("\\", "/", $path);
	}

	/*
	**	Check if the correct php version is used by your system
	*/
	function CheckPhpVersion(){
		$version = phpversion();
		$number = (int)str_replace(".", "", $version);
		$number = substr($number,0,3);
		$rec_number = (int)str_replace(".", "", $this->php_version);

		if($number > $rec_number){
			$this->echoValid("PHP ". _VERSION ." = $version");
		} else if($number < 520){
			$this->echoInvalid(_PHP_OUTDATED . " ($version).", str_replace("%X%",
                                                                           "https://php.net/downloads.php", _WE_RECOMMEND_PHP_VERSION) . " >= {$this->php_version}</a>");
		} else {
			$this->echoNotice("PHP ". _VERSION ." = $version", str_replace("%X%",
                                                                           "https://php.net/downloads.php", _WE_RECOMMEND_PHP_VERSION) . " >= {$this->php_version}</a>");
		}
	}

	/*
	**	Check the php ini settings and check if some classes are available
	*/
	function PhpSettings(){
		# check php settings
		$this->CheckPhpVersion();

		# Check allow_url_fopen
		$urlfopen = (int)ini_get("allow_url_fopen");
		if($urlfopen === 1){
			$this->echoValid("allow_url_fopen = ". $urlfopen);
		} else {
			$msg = str_replace("%K%","allow_url_fopen",_PLEASE_SET_K_TO_V);
			$msg = str_replace("%V%"," 1",$msg);
			$this->echoInvalid(
                "allow_url_fopen = ". $urlfopen
				,
                "{$msg} - <a href='https:///www.logaholic.com/manual/installation/php-settings/' target='_blank'>" . _HELP ."</a>"
			);
		}
		

		# Check the output_buffering
		$buffering = ini_get("output_buffering");
		if( empty($buffering) || $buffering == "off"){
			$this->echoValid("output_buffering = ". $buffering);
		} else {
			$msg = str_replace("%K%","output_buffering",_PLEASE_SET_K_TO_V);
			$msg = str_replace("%V%","off",$msg);
			$this->echoNotice(
                "output_buffering = ". $buffering
				, "{$msg} - <a href='https:///www.logaholic.com/manual/installation/php-settings/' target='_blank'>" . _HELP ."</a>"
			);
		}

		# Check the open_basedir setting
		$basedir = ini_get("open_basedir");
		if( empty($basedir) ){
			$this->echoValid("open_basedir = ". $basedir);
		} else {
			$this->echoNotice(
				"open_basedir = ". $basedir
				, _CHECK_LOG_DIR_ACCESS . " - <a href='https:///www.logaholic.com/manual/installation/php-settings/' target='_blank'>" . _HELP ."</a>"
			);
		}

		# Check if the user user suhosin
		if(file_exists("reports/reports.phar.gz")){
			# Check if we have the phar method
			$phar_check = $this->CheckPhar();

			if($phar_check && extension_loaded('suhosin')){				
				$this->echoNotice("You have enabled suhosin as well, If you do not change this it is possible that a white screen will be displayed. Please add: suhosin.executor.include.whitelist=\"phar\"<br/><br/>
					to \"/etc/php5/conf.d/suhosin.ini\" file or your \"php.ini\" file.",
                                  "<a href='https:///suhosin.org/stories/configuration.html#suhosin-executor-include-whitelist' target='_blank'>" . _HELP ."</a>");
			}
		}

		# check optional classes
		if(class_exists("ZipArchive")){ 
			$this->echoValid( str_replace("%X%","ZipArchive",_X_METHOD_AVAILABLE) );
		} else {
			$this->echoNotice(
				str_replace("%X%","ZipArchive",_X_METHOD_NOT_AVAILABLE)
				,_ZIPARCHIVE_NOT_AVAILABLE_DESC
			);
		}

		# Check cUrl
		if (extension_loaded("curl")){
		    $this->echoValid(_CURL_LOADED);
		} else {
		    $this->echoNotice(_CURL_NOT_LOADED, "<a href='https:///www.php.net//manual/en/curl.installation.php' target='_blank'>" . _HELP . "</a>");
		}

		if(class_exists("DateTime")){ 
			$this->echoValid( str_replace("%X%","DateTime",_X_METHOD_AVAILABLE) );
		} else {
			$this->echoNotice(
				str_replace("%X%","DateTime",_X_METHOD_NOT_AVAILABLE)
				,_PLEASE_INSTALL_RECENT_PHP
			);
		}
	}

	function CheckPhar(){
		# check Phar class
		if(class_exists("Phar")){ 
			$this->echoValid( str_replace("%X%","Phar",_X_METHOD_AVAILABLE) );
			return true;
		} else {
			$this->echoInvalid( 
				str_replace("%X%","Phar",_X_METHOD_NOT_AVAILABLE)
				, str_replace("%X%", "https://php.net/downloads.php", _INSTALL_PHP_VERSION) . " >= {$this->php_version}</a>"
			);
			return false;
		}
	}

	/*
	**	Check if the /files/ dir is writable
	*/
	function CheckFilesDir(){

	    if(!is_dir($this->path ."/files/")){
            mkdir($this->path . '/files/');
        }

		if (is_writable($this->path ."/files/")) {
			$this->echoValid( str_replace("%X%","/files/", _X_DIR_IS_WRITEABLE) );
		} else {
			$this->echoInvalid(
                str_replace("%X%","/files/", _X_DIR_IS_NOT_WRITEABLE)
				,
                "<a href='https:///www.logaholic.com/manual/installation/file-permissions/' target='_blank'>" . _HELP ."</a>"
			);
		}
	}

	/*
	**	Check if the /data/ dir is writable
	*/
	function CheckDataDir(){
		if (is_writable($this->datadir)) {
			$this->echoValid( str_replace("%X%",$this->datadir, _X_DIR_IS_WRITEABLE) );
		} else {
			$this->echoInvalid(
                str_replace("%X%",$this->datadir, _X_DIR_IS_NOT_WRITEABLE)
				,
                "<a href='https:///www.logaholic.com/manual/installation/file-permissions/' target='_blank'>" . _HELP ."</a>"
			);
		}
	}

	/*
	**	Check if the mysqltmp directory is writable
	*/
	function CheckMysqlTmp(){
		if (is_writable($this->mysqltmp)) {
			return true;
		} else {
			return false;
		}
	}

	/*
	**	Check if the GeoLite2-City.mmdb is present. If not give information on how to get it.
	*/
	function CheckGeoLiteCity(){
		if(file_exists("components/geoip/GeoLite2-City.mmdb")){
			$this->echoValid(_GEOLITE_FOUND);
		} else {
			$this->echoNotice(
				_GEOLITE_NOT_FOUND."<br><br>"._GEOLITE_NOT_FOUND_DESC
			);
		}
	}

	/*
	**	Create a mesage box
	*/
	function Message($string = "", $class = "", $icon = ""){
		return "<div class='alert alert-{$class}'><i class='fa {$icon}'></i>$string</div>";
	}

	/*
	**	print a mesage box to the UI
	*/
	function echoMessage($string){
		echo $this->Message($string);
	}

	/*
	**	print a mesage box to the UI with the green box styling
	*/
	function echoValid($string, $recommendation = ""){
		# check if the warning level permits it..
		if($this->warning_level < 2){
			return;
		}

		if(!empty($recommendation)){
			$string .= "<span style='float:right;'>{$recommendation}<span>"; 
		}
		echo $this->Message($string,"success", "fa-check");
	}

	/*
	**	print a mesage box to the UI with the yellow box styling
	*/
	function echoNotice($string, $recommendation = ""){
		# check if the warning level permits it..
		if($this->warning_level < 2){
			return;
		}

		if(!empty($recommendation)){
			$string .= "<span style='float:right;'>{$recommendation}<span>"; 
		}
		echo $this->Message($string,"warning", "fa-warning");
	}

	/*
	**	print a mesage box to the UI with the red box styling
	*/
	function echoInvalid($string, $recommendation = ""){
		# check if the warning level permits it..
		if($this->warning_level < 1){
			return;
		}

		if(!empty($recommendation)){
			$string .= "<span style='float:right;'>{$recommendation}<span>"; 
		}
		echo $this->Message($string,"danger", "fa-exclamation");
		$this->errors ++;
	}

	/*
	**	Load the global file and and update the class variables.
	**	Also load the labels for the Logaholic Tables
	*/
	function ShowGlobalData(){
		global $DatabaseName,$mysqlserver,$mysqluname,$mysqlpw,$mysqlprefix,$mysqltmp;

		# inlcude global and set class variables
		include_once($this->path."/files/global.php");

		$this->DatabaseName = $DatabaseName;

		$this->mysqlserver = $mysqlserver;

		$this->mysqluname = $mysqluname;

		$this->mysqlpw = $mysqlpw;

		$this->mysqlprefix = $mysqlprefix;

		$this->mysqltmp = $mysqltmp;

		include_once($this->path."/includes/table_definitions.php");
	}

	/*
	**	Create the database object for this class
	*/
	function GetDbObject(){	
		if (function_exists("mysqli_connect")) {			
			$this->db = ADONewConnection("mysqli");	
		} else {
            if (function_exists("mysql_connect")) {
			    $this->db = ADONewConnection("mysql");
            } else {
                $this->echoInvalid(_WRONG_PHP_VERSION);
                return false;
            }
		}
		return $this->db;
	}

	/*
	** Secure the input of a password
	*/
	function SecurePassword($value){
		if(empty($value)){
			return "";
		}
		return $value;
	}

	/*
	** Create some strict individual checks for some fields
	*/ 
	function PostPreChecks($data, $print = true){
		if(strrpos($data['DatabaseName'], ".") !== false){
			if($print){ $this->echoInvalid(_DOT_IN_DB_NAME); } else { $this->errors ++; }
		}	
		if(empty($data['mysqluname'])){
			if($print){ $this->echoInvalid(_FIELD_MYSQLUSER_EMPTY); } else { $this->errors ++; }
		}	
		if(empty($data['mysqlpw'])){
			if($print){ $this->echoNotice(_FIELD_MYSQLPASS_EMPTY); }
		}	
		
		if(empty($data['datadir'])){
			if($print){ $this->echoInvalid(_FIELD_DATADIR_EMPTY); } else { $this->errors ++; }
		}	
		if(empty($data['mysqltmp'])){
			if($print){ $this->echoInvalid(_FIELD_MYSQLTMP_EMPTY); } else { $this->errors ++; }
		}

		if(empty($_SESSION['username'])){
			if(empty($data['adminUser'])){
				if($print){ $this->echoInvalid(_FIELD_ADMINUSER_EMPTY); } else { $this->errors ++; }
			}

			if(empty($data['adminName'])){
				if($print){ $this->echoInvalid("Administrator Name field is Empty"); } else { $this->errors ++; }
			}

			if (empty($data['adminEmail']) || !filter_var($data['adminEmail'], FILTER_VALIDATE_EMAIL)) {
				if($print){ $this->echoInvalid(_INVALID_EMAIL); } else { $this->errors ++; }
			}

			if(empty($data['adminUserPass'])){
				if($print){ $this->echoNotice(_FIELD_ADMINPASS_EMPTY); }
			}
		}
	}

	/*
	** A security check for all file and folder permissions + geoip
	*/
	function FilePermissionsChecks(){
		# Check Files dir
		$this->CheckFilesDir();		

		# Check Data dir
		$this->CheckDataDir();		
		
		# check the geoip file
		$this->CheckGeoLiteCity();
	}


	/*
	** A security check for all input fields. Check for strange characters
	*/
	function SecureInput($value){
		if(empty($value)){
			return "";
		}

		$regex = "^[a-zA-Z0-9\/\:\_\.\ \-\\\]+";
		preg_match("/$regex/", $value, $matches);

		if($matches[0] == $value){
			return $value;
		} else {
			$this->echoInvalid("Invalid Input ({$matches[0]})");
			return "";
		}
	}

	/*
	** If the database form is posted check the input and setup a db connection
	*/
	function FormDataChecks(){
        //echo(var_dump($_POST));

        if( isset($_POST['DatabaseName'])
			&& isset($_POST['PrevDatabaseName']) 
			&& isset($_POST['mysqlserver']) 
			&& isset($_POST['mysqluname']) 
			&& isset($_POST['mysqlpw']) 
			&& isset($_POST['PrevPrefix']) 
			&& isset($_POST['mysqlprefix']) 
			&& isset($_POST['mysqltmp']) 
			&& isset($_POST['datadir'])

		){
			# check some individual fields
			$this->PostPreChecks($_POST);

			# set it to the globals in the install object
			$this->SetNewConnection($_POST);
			
			# Now set it to the temp SESSION	
			$this->SetGlobalTmpSession();

			if($this->errors == 0){

				# Reconnect if needed
				$this->db = NULL;
				if($this->ConnectionCheck()){

					# second check if we need to create new tables or not
					$prevprefix = $this->SecureInput($_POST['PrevPrefix']);

					if ($this->CheckIfTableExists($prevprefix ."_logaholic_GlobalSettings")) {
						$this->RenameLogaholicTables($prevprefix);


					} else {

						# Create all the main database tables
						$this->CreateLogaholicTables();
					}
					$this->echoValid(_TABLES_FOUND);
				} else {
					# Empty session		
					$_SESSION['TmpGlobal'] = [];
				}
			}
		} else if(file_exists($this->global_file)){
			$this->ShowGlobalData();
			$this->ConnectDb();
		}
	}

	/*
	**	Add the global data to the session
	*/
	function SetGlobalTmpSession(){
		$_SESSION['TmpGlobal'] = array(
			"DatabaseName" => $this->DatabaseName
			,"mysqlserver" => $this->mysqlserver
			,"mysqluname" => $this->mysqluname
			,"mysqlpw" => $this->mysqlpw
			,"mysqlprefix" => $this->mysqlprefix
			,"mysqltmp" => $this->mysqltmp
			,"datadir" => $this->datadir
			,"adminUser" => $this->adminUser
			,"adminName" => $this->adminName
			,"adminEmail" => $this->adminEmail
			,"adminUserPass" => $this->adminUserPass
		);
	}

	/*
	**	Secure the input of the data and set the global variables
	*/
	function SetNewConnection($data){

		$this->DatabaseName = $this->SecureInput($data['DatabaseName']);
		$this->mysqlserver = $this->SecureInput($data['mysqlserver']);
		$this->mysqluname = $this->SecureInput($data['mysqluname']); 
		$this->mysqlpw = $this->SecurePassword($data['mysqlpw']);
		$this->mysqlprefix = $this->SecureInput($data['mysqlprefix']); 
		$this->mysqltmp = $this->SecureInput($data['mysqltmp']);
		$this->datadir = $this->SecureInput($data['datadir']);
		
		# New user
		if(!empty($data['adminUser'])){
			$this->adminUser = $this->SecureInput($data['adminUser']);
		}
		if(!empty($data['adminUser'])){
			$this->adminName = $data['adminName'];
		}
		if(!empty($data['adminUser'])){
			$this->adminEmail = $data['adminEmail'];
		}
		if(!empty($data['adminUserPass'])){
			$this->adminUserPass = $this->SecurePassword($data['adminUserPass']);
		}

		# mysql prefix myst also be global for table definitions
		$mysqlprefix = $this->mysqlprefix;
		include_once($this->path."/includes/table_definitions.php");
	}

	/*
	**	Connect to the database
	*/
	function ConnectDb(){	
		if(!empty($this->db)){
			$this->connected = true;
			return $this->db;
		}

		$this->db = $this->GetDbObject();
		if($this->db === false){
            $_SESSION['TmpGlobal'] = [];
			return false;
		}

		//TODO: FIX THIS BETTER IN FUTURE! Sorry!
		error_reporting(0);
        $conn = new mysqli($this->mysqlserver, $this->mysqluname, $this->mysqlpw);
        if ($conn->connect_error) {
            $_SESSION['TmpGlobal'] = [];
            echo("Connection failed: " . $conn->connect_error);
        } else {
            $this->db->Connect($this->mysqlserver,$this->mysqluname,$this->mysqlpw);
        }
        error_reporting(1);

		if (!$this->db->IsConnected()) {
            $_SESSION['TmpGlobal'] = [];
			return false;

			# Empty session		

		} else {
			if ($sel = @$this->db->SelectDB($this->DatabaseName)) {
				$this->connected = true;
				return $this->db;
			} else {
                $_SESSION['TmpGlobal'] = [];
				return false;
							}
		}
	}

	/*
	**	If the user changes the prefix then rename the main tables
	*/
	function RenameLogaholicTables($previous_prefix){
		# No need to rename if the tables already exists.
		if($this->CheckIfTableExists($this->mysqlprefix ."_logaholic_GlobalSettings")) {
			return false;
		}

		$tables = array(
			"_logaholic_GlobalSettings"
			,"_logaholic_users"
			,"_logaholic_Profiles"
			,"_logaholic_goals"
			,"lgstatus"
			,"notes"
			,"_logaholic_Traffic_Sources"
			,"_report_usage"
			,"_logaholic_Profile_URL_Params"
		);

		$queries = [];
		foreach ($tables as $table) {
			$queries[] = $previous_prefix . $table ." TO ". $this->mysqlprefix . $table;
		}

		$q = "RENAME TABLE ". implode(",",$queries);
		$this->db->Execute($q);

		# rewrite global if needed
		if(file_exists($this->global_file)){
			$this->WriteGlobal();
		}
	}

	/*
	**	Create the main tables and add default content
	*/
	function CreateLogaholicTables(){
		# Create TBL_GLOBAL_SETTINGS
		$this->CreateGlobalsTable();
		# Insert/Update Data Dir
		$this->InsertDataDir();
		# Create TBL_PROFILES
		$this->CreateProfilesTable();
		# Create TBL_USERS
		$this->CreateUsersTable();
		# Create TBL_GOALS
		$this->CreateGoalsTable();
		# Create TBL_LGSTATUS
		$this->CreateStatusTable();
		# Create TBL_NOTES
		$this->CreateNotesTable();
		# Create TBL_REPORT_USAGE
		$this->CreateReportUsageTable();
		# Create TBL_TRAFFIC_SOURCES
		$this->CreateTrafficSrcTable();
		# Create TBL_IMPORTANT_URL_PARAMS
		$this->CreateUrlParamsTable();
		# Create the url parsing function
		$this->CreateUrlParseFunc();
	}

	/*
	**	Check if the table actually exists or not
	*/
	function CheckIfTableExists($table){
		if(empty($this->db)){
			return false;
		}
        $R = $this->db->getRow("SELECT COUNT(*) FROM information_schema.TABLES  WHERE TABLE_SCHEMA ='" . $this->db->database . "' AND TABLE_NAME ='" . $table . "'");

		if( $R[0] != 0 ){
            return true;
        } else {
            return false;
        }
	}

	/*
	** Check if we need to add a new admin or if it already exists
	*/
	function AdminsCheck(){

		if (!defined('TBL_USERS') || !$this->CheckIfTableExists(TBL_USERS)) {
			return false;
		}


		$q = $this->db->Execute("select count(*) as c from ". TBL_USERS ." where isAdmin = 1");
		$r = $q->FetchRow();
		$count = (int)$r['c'];

		if($count > 0){
			$this->adminNeeded = false;
			return true;
		}
	}

	/*
	**	Add a user and flag him as admin
	*/
	function AddAdmin(){
		$this->db->Execute("INSERT IGNORE INTO ". TBL_USERS ." (`username`,`password`,`isAdmin`,`created`, `name`, `email`, `metadata`) VALUES (?,?,'1',?,?,?,'{}')",array( $this->adminUser, md5($this->adminUserPass), time(), $this->adminName, $this->adminEmail ));
	}

	/*
	**	Create the _logaholic_GlobalSettings table
	*/
	function CreateGlobalsTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_GLOBAL_SETTINGS ."` (
			  `Name` varchar(255) NOT NULL,
			  `Profile` varchar(50) DEFAULT NULL,
			  `Value` mediumtext,
			  PRIMARY KEY (`Name`),
			  KEY `_logaholic_GlobalSettings_Profile` (`Profile`,`Name`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);

		# Insert default global settings
		$this->InsertStartupSettings();
	}

	/*
	**	add datamanager settings to the _logaholic_GlobalSettings table
	*/
	function InsertDataDir(){
		$save = array(
			"datamanagerDirectory"
			,$this->datadir
			,$this->datadir
		);
		$this->db->Execute("INSERT INTO ". TBL_GLOBAL_SETTINGS ." (`Name`,`Profile`,`Value`) VALUES (?,'',?) ON DUPLICATE KEY UPDATE `Value` = ?",$save);
	}

	/*
	**	insert into _logaholic_GlobalSettings table
	*/
	function InsertGlobalSetting($name,$profile,$value){
		$this->db->Execute("INSERT IGNORE INTO ". TBL_GLOBAL_SETTINGS ." (`Name`,`Profile`,`Value`) VALUES (?,?,?) ON DUPLICATE KEY UPDATE `Value` = ?", array($name,$profile,$value,$value) );
	}

	/*
	**	add settings to the _logaholic_GlobalSettings table
	*/
	function InsertStartupSettings(){
		$this->InsertGlobalSetting('DB_MetadataVersion','','2.47');			
		$this->InsertGlobalSetting('DB_UserDataVersion','','2.21');
		$this->InsertGlobalSetting('UserAuthenticationType','','logaholic');

		$this->InsertGlobalSetting('datamanagersettings','','0');
		$this->InsertGlobalSetting('datamanagerStorageSize','','5000');

		$format = array('format1' => 'd', 'seperator1' => ' ', 'format2' => 'M', 'seperator2' => ' ', 'format3' => 'Y', 'seperator3' => ' ', 'format4' => '');
		$this->InsertGlobalSetting('profileDateFormat','', json_encode($format));
	}

	/*
	**	Create the _logaholic_Profiles table
	*/
	function CreateProfilesTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_PROFILES ."` (
			  `profileid` int(11) NOT NULL AUTO_INCREMENT,
			  `profilename` varchar(255) DEFAULT NULL,
			  `confdomain` varchar(255) DEFAULT NULL,
			  `equivdomains` text,
			  `tablename` varchar(64) DEFAULT NULL,
			  `defaultfile` varchar(128) DEFAULT NULL,
			  `logfilefullpath` text,
			  `splitlogs` tinyint(4) DEFAULT '0',
			  `splitfilter` varchar(100) DEFAULT NULL,
			  `trackermode` tinyint(4) DEFAULT '0',
			  `visitoridentmethod` tinyint(4) DEFAULT NULL,
			  `skipips` text,
			  `skipfiles` text,
			  `targetfiles` mediumtext,
			  `othersettings` text,
			  `structure_version` float DEFAULT NULL,
			  `animate` int(1) DEFAULT '1',
			  `timezonecorrection` varchar(5) DEFAULT '0',
			  `recursive` int(1) DEFAULT '0',
			  `ftpserver` varchar(150) DEFAULT NULL,
			  `ftpuser` varchar(50) DEFAULT NULL,
			  `ftppasswd` varchar(50) DEFAULT NULL,
			  `ftpfullpath` text,
			  `visittimeout` int(2) DEFAULT '20',
			  `urlparamfilter` varchar(255) DEFAULT '',
			  `urlparamfiltermode` varchar(20) DEFAULT 'Exclude',
			  `splitfilternegative` varchar(100) DEFAULT NULL,
			  `feedurl` varchar(100) DEFAULT '',
			  `feedburneruri` varchar(100) DEFAULT '',
			  `timezone` varchar(50) DEFAULT '',
			  `googleparams` varchar(255) DEFAULT 'q, start, gclid, as_q, as_epq, as_oq, as _eq, as_sitesearch, as_rq, as_lq',
			  `lastused` int(11) DEFAULT '0',
			  `sessioncounter` int(11) NOT NULL DEFAULT '0',
			  `stats` text,
			  `update_status` char(7) NOT NULL DEFAULT 'ready',
			  `dashboards` longtext,
			  `other_settings` longtext,
			  `filehistory` longtext,
			  `activated` tinyint(1) NOT NULL DEFAULT '1',
			  PRIMARY KEY (`profileid`),
			  UNIQUE KEY `_logaholic_Profiles_profilename` (`profilename`),
			  UNIQUE KEY `_logaholic_Profiles_tablename` (`tablename`),
			  KEY `lastused` (`lastused`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}

	/*
	**	Create the _logaholic_users table
	*/
	function CreateUsersTable(){
            $query = "CREATE TABLE  IF NOT EXISTS`". TBL_USERS ."` (
			  `userid` int(11) NOT NULL AUTO_INCREMENT,
			  `username` varchar(100) NOT NULL,
			  `name` varchar(100) DEFAULT NULL,
			  `password` varchar(100) DEFAULT NULL,
			  `email` varchar(100) DEFAULT NULL,
			  `profiles` text,
			  `foreignkey` varchar(100) DEFAULT NULL,
			  `created` int(11) NOT NULL,
			  `isAdmin` int(4) NOT NULL DEFAULT '0',
			  `active` tinyint(1) DEFAULT '1',
			  `accessUpdateLogs` tinyint(4) NOT NULL DEFAULT '1',
			  `accessAddProfile` tinyint(4) NOT NULL DEFAULT '1',
			  `usersessionid` varchar(32) DEFAULT NULL,
			  `lastlogin` int(11) NOT NULL DEFAULT '0',
			  `accessEditProfile` tinyint(4) NOT NULL DEFAULT '1',
			  `expires` int(11) NOT NULL DEFAULT '0',
			  `metadata` text,
			  `subscriptionid` int(11) DEFAULT NULL,
			  PRIMARY KEY (`userid`),
			  UNIQUE KEY `_logaholic_users_username` (`username`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
            $this->db->Execute($query);



	}

	/*
	**	Create the _logaholic_goals table
	*/
	function CreateGoalsTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_GOALS ."` (
			  `goalID` int(11) NOT NULL AUTO_INCREMENT,
			  `goalName` varchar(100) DEFAULT NULL,
			  `timeunit` varchar(100) DEFAULT NULL,
			  `targetValue` varchar(11) DEFAULT NULL,
			  `metric` varchar(50) DEFAULT NULL,
			  `conditions` text,
			  `graphType` varchar(50) DEFAULT 'speed',
			  `profileID` int(11) DEFAULT NULL,
			  `inverse` int(1) DEFAULT NULL,
			  `kpi` varchar(100) DEFAULT NULL,
			  PRIMARY KEY (`goalID`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}

	/*
	**	Create the lgstatus table
	*/
	function CreateStatusTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_LGSTATUS ."` (
		  `id` int(10) NOT NULL AUTO_INCREMENT,
		  `code` int(5) NOT NULL DEFAULT '0',
		  `descr` varchar(100) NOT NULL DEFAULT '0',
		  PRIMARY KEY (`id`),
		  UNIQUE KEY `code` (`code`)
		) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);

		# Insert Statusses to TBL_LGSTATUS
		$this->FillStatusTable();
	}

	/*
	**	Create the notes table
	*/
	function CreateNotesTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_NOTES ."` (
			  `id` int(10) NOT NULL AUTO_INCREMENT,
			  `profile` varchar(75) NOT NULL DEFAULT '0',
			  `timestamp` int(11) NOT NULL DEFAULT '0',
			  `note` varchar(255) NOT NULL DEFAULT '0',
			  PRIMARY KEY (`id`),
			  KEY `timestamp` (`timestamp`),
			  KEY `profile` (`profile`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}

	/*
	**	Create the _report_usage table
	*/
	function CreateReportUsageTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_REPORT_USAGE ."` (
			  `profilename` varchar(255) NOT NULL,
			  `reporturl` text NOT NULL,
			  `hits` int(11) NOT NULL,
			  `month` int(6) NOT NULL,
			  `reporturl_hash` varchar(32) DEFAULT NULL,
			  UNIQUE KEY `usagekey` (`profilename`,`month`,`reporturl_hash`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}

	/*
	**	Create the _logaholic_Traffic_Sources table
	*/
	function CreateTrafficSrcTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_TRAFFIC_SOURCES ."` (
			  `id` int(11) NOT NULL AUTO_INCREMENT,
			  `profileid` int(11) NOT NULL,
			  `sourcename` varchar(128) NOT NULL,
			  `sourcecondition` text,
			  `category` varchar(255) DEFAULT NULL,
			  `userid` int(11) default 0,
			  PRIMARY KEY (`id`),
			  KEY `_logaholic_Traffic_Sources_sourcename` (`sourcename`),
			  KEY `_logaholic_Traffic_Sources_profileid` (`profileid`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}

	/*
	**	Create the _logaholic_Profile_URL_Params table
	*/
	function CreateUrlParamsTable(){
		$query = "CREATE OR REPLACE TABLE  `". TBL_IMPORTANT_URL_PARAMS ."` (
			  `paramid` int(11) NOT NULL AUTO_INCREMENT,
			  `profileid` int(11) NOT NULL,
			  `filename` varchar(128) NOT NULL,
			  `nameisregex` tinyint(1) DEFAULT '0',
			  `importantparams` text,
			  PRIMARY KEY (`paramid`),
			  KEY `profileid` (`profileid`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8
		";
		$this->db->Execute($query);
	}


	function CreateUrlParseFunc() {		
		$f="CREATE FUNCTION `lg_getparam`(param varchar(55), url varchar(2048)) RETURNS varchar(2048) CHARACTER SET utf8 COLLATE utf8_unicode_ci
			BEGIN 
			declare val varchar(2048);
			declare _param varchar(60) DEFAULT CONCAT(param,'=');
			 
			select SUBSTRING_INDEX(SUBSTRING_INDEX(url,_param,-1), '&', 1)
			into val;
			 
			RETURN val;

			END";		
		$this->db->Execute($f);
	}

	/*
	**	fill the lgstatus table with statuses
	*/
	function FillStatusTable(){
		# list from http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('100', 'Continue')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('101', 'Switching Protocols')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('102', 'Processing')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('200', 'OK')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('201', 'Created')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('202', 'Accepted')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('203', 'Non-Authoritative Information')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('204', 'No Content')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('205', 'Reset Content')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('206', 'Partial Content')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('207', 'Multi-Status')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('300', 'Multiple Choices')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('301', 'Moved Permanently (redirect)')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('302', 'Moved Temporarily (redirect)')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('303', 'See Other')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('304', 'Not Modified')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('305', 'Use Proxy')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('307', 'Temporary Redirect')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('400', 'Bad Request')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('401', 'Authorization Required')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('402', 'Payment Required')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('403', 'Forbidden')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('404', 'Not Found')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('405', 'Method Not Allowed')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('406', 'Not Acceptable')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('407', 'Proxy Authentication Required')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('408', 'Request Time-out')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('409', 'Conflict')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('410', 'Gone')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('411', 'Length Required')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('412', 'Precondition Failed')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('413', 'Request Entity Too Large')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('414', 'Request-URI Too Large')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('415', 'Unsupported Media Type')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('416', 'Requested Range Not Satisfiable')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('417', 'Expectation Failed')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('422', 'Unprocessable Entity')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('423', 'Locked')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('424', 'Failed Dependency')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('425', 'No code')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('426', 'Upgrade Required')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('500', 'Internal Server Error')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('501', 'Method Not Implemented')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('502', 'Bad Gateway')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('503', 'Service Temporarily Unavailable')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('504', 'Gateway Time-out')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('505', 'HTTP Version Not Supported')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('506', 'Variant Also Negotiates')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('507', 'Insufficient Storage')");
		$this->db->Execute("insert ignore into ".TBL_LGSTATUS." (code, descr) values ('510', 'Not Extended')");
	}

	/*
	** Create the global file
	*/
	function WriteGlobal(){
		$gfile = $this->path ."/files/global.php";

		$fp = fopen ($gfile,"w+");
		fwrite ($fp, "<?php \$DatabaseName=\"".$this->DatabaseName."\";\n");
		fwrite ($fp, "\$databasedriver=\"".$this->databasedriver."\";\n");
		fwrite ($fp, "\$mysqlserver=\"".$this->mysqlserver."\";\n");
		fwrite ($fp, "\$mysqluname=\"".$this->mysqluname."\";\n");
		fwrite ($fp, "\$mysqlpw=\"".$this->mysqlpw."\";\n");
		fwrite ($fp, "\$mysqlprefix=\"".$this->mysqlprefix."\";\n");
		fwrite ($fp, "\$mysqltmp=\"".$this->mysqltmp."\";\n");
		fwrite ($fp, "?>");
		fclose ($fp);
		@chmod($gfile, 0666);
	}

	/*
	**	Check if we are already connected to a database
	**	- If not setup a connection.
	**	- create the database if it does not exist 
	*/
	function ConnectionCheck(){

		$this->db = $this->GetDbObject();
		if($this->db === false){
			return false;
		}

        error_reporting(0);
        $conn = new mysqli($this->mysqlserver, $this->mysqluname, $this->mysqlpw);
        if ($conn->connect_error) {
            return false;
        } else {
            $this->db->Connect($this->mysqlserver,$this->mysqluname,$this->mysqlpw);
        }
        error_reporting(1);


		$this->db->Connect($this->mysqlserver,$this->mysqluname,$this->mysqlpw);

		if (!$this->db->IsConnected()) {
			$this->echoInvalid(_NO_DB_CONNECT.".<br>".$this->db->ErrorMsg());
			return false;
		} else {
			$this->echoValid(_OK_DB_CONNECT." <b>{$this->mysqlserver}</b>");

            $this->db->Execute("create database if not exists {$this->DatabaseName} CHARACTER SET = utf8 COLLATE = utf8_general_ci;") or $this->echoInvalid($this->db->ErrorMsg());
            $this->db->SelectDB($this->DatabaseName);
			/*if ($sel) {
				$this->echoValid(_OK_DB." <b>{$this->DatabaseName}</b> "._FOUND);
			} else {
				@$this->db->Execute("create database if not exists {$this->DatabaseName} CHARACTER SET = utf8 COLLATE = utf8_general_ci;") or $this->echoInvalid($this->db->ErrorMsg());
				if (@$sel = @$this->db->SelectDB(@$this->DatabaseName)) {
					# it worked
				} else {
					$this->echoInvalid("<font color=red>"._DB_CREATE_FAILED." {$this->DatabaseName}</font></br>"._CREATE_DB_MANUAL." {$this->DatabaseName}</font>");
					return false;
				}
			}*/
			$ServerInfo = $this->db->ServerInfo();
			$this->echoValid(_DB_DRIVER.": {$this->databasedriver}<br>"._DB_TYPE.": " . $ServerInfo["description"] . "<br>"._DB_VERSION.": ".$ServerInfo["version"]);

			$this->connected = true;
			return true;
		}
	}

	/*
	** Get the current Mysql timezone settings
	*/
	function GetCurrentTimeZone(){
		# Get the current setting
		$current_zone = "";
		$r = $this->db->Execute("SELECT @@session.time_zone;"); 
	    if ($row = $r->FetchRow()) {
	    	$current_zone = $row[0];
		}
		return $current_zone;
	}

	function CheckMysqli(){
		if (function_exists("mysqli_connect")) {			
			# ok
		} else {
            if (function_exists("mysql_connect")) {
            	# ok
            } else {
                $this->echoInvalid(_WRONG_PHP_VERSION);
            }
		}
	}  

	/*
	**	Check if Mysql has the timezone description tables.
	**	- here we try to set the timezone to Europe/Amsterdam
	**	- when we get the timezone and it does not returns the same as we tried to set then the tables are not loaded
	**	- return the setting to what it was.
	*/
	function CheckMysqlTimeZoneTables(){
        error_reporting(0);
        # return this variable as boolean
		$result = false;

		# Get the current setting for reverting
		$current_zone = $this->GetCurrentTimeZone();

		# try settings a named zone
		$test_zone ="Europe/Amsterdam";
		$q = "set time_zone = '".$test_zone."'";
		@$this->db->Execute($q);
		# Now get what is set and check if it is the same as the test setting
		$z = $this->GetCurrentTimeZone();
		if($z == $test_zone){
			$result = true; # It worked !
		}

		# revert to original setting
		$q = "set time_zone = '".$current_zone."'";
		@$this->db->Execute($q);
        error_reporting(1);
        return $result;
	}

	/*
	**	Create a dummy file and try to use the mysql Load data infile method
	**	on error return an invalid message with details on how to correct this
	*/
	function CheckLoadDataInfile(){
        error_reporting(0);
		$test_table = $this->mysqlprefix ."notes";
		if ($this->CheckIfTableExists($test_table) !== true) {
			$this->echoInvalid(_TABLES_NOT_FOUND);
			return false;
		}

		$test_file = $this->mysqltmp . "/load_data_test.txt";
		$fp = fopen($test_file, "w+");
		fwrite($fp, "0|test|0|Test Note  \n");
		fclose($fp);
		@chmod($test_file, 0777);

		$q = "LOAD DATA LOCAL INFILE '{$test_file}' INTO TABLE `". $test_table ."` FIELDS TERMINATED BY '|' ESCAPED BY '' LINES TERMINATED BY '\n'";
		$r = @$this->db->Execute($q);
		if(!$r){
			$q2 = "LOAD DATA LOCAL INFILE '{$test_file}' INTO TABLE `". $test_table ."` FIELDS TERMINATED BY '|' ESCAPED BY '' LINES TERMINATED BY '\n'";
			$r2 = @$this->db->Execute($q2);
			if(!$r2){
				$this->echoNotice(
                    _LOAD_DATA_INFILE_FAILED . $this->db->ErrorMsg()
					,
                    "<a target='_blank' href='https:///www.logaholic.com/manual/installation/load-data-infile/'>" . _HELP ."</a>"
				);
			} else {
				$this->echoValid(_LOAD_DATA_INFILE_WORKS);
			}
		} else {
			$this->echoValid(_LOAD_DATA_INFILE_WORKS);
		}

		# remove the test file
		unlink($test_file);

		# Delete the test records
		$this->db->Execute("DELETE FROM `". $test_table ."` WHERE timestamp = 0");
        error_reporting(1);
	}
}
?>