<?php

ini_set('default_charset', 'utf-8');
if (file_exists("revision.txt")) {
    $rev = file_get_contents('revision.txt');
    $rev = substr(str_replace("Exported revision ", "", $rev), 0, -1);
    if (intval($rev) <= 4250) {
        echo "<style>
        body{ font-family: Arial; font-size: 12px; padding: 10px; }
        .warning{ border: 2px solid #ddd; float: left; padding: 10px; }
        </style>";

        $upgradetxt = file_get_contents("UPGRADE Instructions.txt");
        $upgradetxt = str_replace("\n", "<br/>", $upgradetxt);

        die("<div class='warning'>Your current version of Logaholic cannot be upgraded to Logaholic 6.<br/> Please read the following to upgrade your installation:<br/><br/>" . $upgradetxt);
    }
}

# This file creates fallback functions for php versions < 5.2.0
if (!function_exists('json_encode')) {
    include_once("components/json/JSON.php");
}
require_once("includes/fallback_functions.php");

// first of all sanitize any input as a first line of defense
SanitizeInput();

// core util function consolidation; aids in customization
require_once "core_factory.php";


//This file includes the software version and db version numbers
require_once("includes/version.php");

//error reporting
if (LOGAHOLIC_VERSION_STATUS == "release") {
    error_reporting(E_ALL & ~E_NOTICE);
} else {
    error_reporting(E_ALL);
}

ini_set('session.cookie_domain', $_SERVER['HTTP_HOST']);
Logaholic_sessionStart();

//load some option user settings class
if (is_file("user_settings.php")) {
    include_once("user_settings.php");
}

if (!isset($_SESSION['logaholic_dir']) || $_SESSION['logaholic_dir'] !== logaholic_dir()) {
    foreach ($_SESSION as $k => $v) {
        unset($_SESSION[$k]);
    }
}
$_SESSION['logaholic_dir'] = logaholic_dir();

// If the debug parameter was passed in, then set it sticky in the session (either on or off).

if (isset($_GET["debug"])) {
    if ($_GET["debug"] == "off") {
        $_SESSION["debug"] = "";
    } else {
        $_SESSION["debug"] = $_GET["debug"];
    }
}
if (isset($_SESSION["debug"])) {
    $debug = $_SESSION["debug"];
}

/**
 * Default Timezone. We need to set a default or we get warnings
 */
if (function_exists("date_default_timezone_get")) {
    $system_timezone = @date_default_timezone_get();
    if ($system_timezone != "") {
        date_default_timezone_set("$system_timezone");
    }
}

# All database errors will be raised as errors.  No need for special handling.
require_once("vendor/adodb/adodb-php/adodb-errorhandler.inc.php");
# Use adodb for database work.
require_once("vendor/adodb/adodb-php/adodb.inc.php");
$ADODB_QUOTE_FIELDNAMES = 'NATIVE';

require_once("markup.php");
if (!defined('_LOGAHOLIC_EDITION')) {
    if (!empty($edition)) {
        $ed = array_flip($edition);
        define('_LOGAHOLIC_EDITION', $ed[LOGAHOLIC_BASE_EDITION]);
    }
}

// Include siteprofile class
include_once "includes/siteprofile.php";
// Turn on error handling...
@include_once("errorhandling.inc.php");
$errorHandler = @(new clsErrorHandle());


if (!@$running_from_command_line) {
    $ignore_keys = array('saveDashboard', 'serverdata', 'logdata', 'subscriptions', 'reportsdata', 'panea', 'paneb');
    foreach ($_GET as $k => $v) {
        if (!in_array($k, $ignore_keys)) {
            SecurityCheck($v, $k);
        }
    }

    foreach ($_POST as $k => $v) {
        if (!in_array($k, $ignore_keys)) {
            SecurityCheck($v, $k);
        }
    }
}

if (isset($_REQUEST["trafficsource"]) && is_numeric($_REQUEST["trafficsource"])) {
    $_SESSION["trafficsource"] = $_REQUEST["trafficsource"];
}

// Pull in some default values from the URL.
$conf = isset($conf) ? $conf : @$_REQUEST["conf"];
$from = @$_REQUEST["from"];
$to = @$_REQUEST["to"];
$limit = @$_REQUEST["limit"];
$editconf = @$_REQUEST["editconf"];

// Visitor Identification Methods
define("VIDM_IPADDRESS", 1);    // IP Address only
define("VIDM_IPPLUSAGENT", 2);  // IP address + user agent
define("VIDM_COOKIE", 3);  // this used the Logaholic_VID cookie
define("VIDM_CUSTOM_COOKIE", 4);  // this used the Logaholic_VID cookie

# What databases do we support?
$supported_databases = array("mysql" => "MySQL (4.1 or higher recommended)");

$tableheaderfontcolor = "black";  // Temporary (?) to get rid of warnings.

$validUserRequired = false;
$loginSystemExists = false;
$dbid = 0;

# Log in to the database.
if (!isset($mysqlsave)) {
    if (isset($_SESSION['dbid'])) {
        $dbid = $_SESSION['dbid'];
    }
    if (isset($_GET['dbid']) || isset($_POST['dbid'])) {
        $dbid = isset($_GET['dbid']) ? $_GET['dbid'] : $_POST['dbid'];
        if (isset($_SESSION['dbid']) && $_SESSION['dbid'] != $dbid) {
            unset($_SESSION['profilename']);
            unset($_SESSION['profileobject']);
            $_SESSION['dbid'] = 0;
        }
        $_SESSION['dbid'] = $dbid;
    }

    if ($dbid != 0) {
        if (is_int((int)$dbid) && file_exists(logaholic_dir() . "files/global." . $dbid . ".php")) {
            include "files/global." . $dbid . ".php";
        } else {
            if (file_exists(logaholic_dir() . "files/global.php")) {
                include "files/global.php";
            }
        }
    } else {
        if (file_exists(logaholic_dir() . "files/global.php")) {
            include "files/global.php";
        }
    }

    if (!isset($mysqlprefix)) {
        $mysqlprefix = "";
    }

    /**
     * Database Table Constants - these constants
     * hold the names of all the database tables used
     * in the script.
     */
    include_once("includes/table_definitions.php");

    # check if we have variables from global.php
    if (!isset($mysqlserver)) {
        if (_LOGAHOLIC_EDITION == 4 || LOGAHOLIC_BASE_EDITION == "cPanel Edition") {
            die("Global database variables aren't set.  Please contact your hosting provider.");
        } else {
            die("Global database variables aren't set.  Please run <a href=install.php>installation</a>.");
        }
    }

    if (!isset($databasedriver) || (!$databasedriver)) {
        $databasedriver = "mysql";
    }

    if ($databasedriver == "mysql") {
        if (function_exists("mysqli_connect")) {
            $db = ADONewConnection("mysqli");
        } else {
            $db = ADONewConnection("mysql");
        }
    } else {
        if ($databasedriver = "sqlite") {
            if (phpversion() >= "5.0.0") {
                $db = ADONewConnection("pdo_sqlite");
            } else {
                /**
                 * PhpEd needs some help figuring out the class type, since ADONewConnection returns an abstraction.
                 * @var ADOConnection
                 */
                $db = ADONewConnection("sqlite");
            }
        } else {
            die("Database driver: " . $databasedriver . " not supported.");
        }
    }
    $connect_start_time = getmicrotime();
    @$db->Connect($mysqlserver, $mysqluname, $mysqlpw, $DatabaseName);
    if (!$db->IsConnected()) {
        die("Couldn't connect to database " . $db->ErrorMsg());
    } else {
        $db->SetCharSet('utf8');
    }
    $db->query_took = getmicrotime() - $connect_start_time;
    @$db->query_log[] = array("sql" => "connect", "took" => $db->query_took);

    $vnum = $db->ServerInfo();

    $vnumfull = $vnum["version"];
    $vnum = substr($vnum["version"], 0, 3);

    if (($databasedriver == "mysql") && ($vnum < "4.1")) {
        $supports_correlated_subselects = false;
    } else {
        $supports_correlated_subselects = true;
    }

    //$db->Execute("SET sql_mode = ''");
    //$db->Execute("SET global max_allowed_packet=1073741824");

    # Set Lang - previous set above markup for labels there... reverted that to english one
    global $lang;
    $lang_has_changed = Logaholic_hasLangChanged();
    $lang = Logaholic_setLang();


    $vidmethods[VIDM_IPADDRESS] = _IP_ONLY; # "IP Address Only";
    $vidmethods[VIDM_IPPLUSAGENT] = _IP_AND_UA; # "IP Address and User Agent";
    $vidmethods[VIDM_COOKIE] = _COOKIE_BASED; # "Cookie based";
    $vidmethods[VIDM_CUSTOM_COOKIE] = "Use a custom cookie value as tyhe unique identifier"; # "Cookie based";

    # If the user login system exists, then try and access it.   (The @ supressess the error if it doesn't exist).
    if (!@$running_from_command_line) {
        @include_once("user_login/login.inc.php");
        if (!$validUserRequired) {
            $session->isAdminFlag = 1;
        }

        # if we are not an admin, we are not allowed to do debug mode
        if (($validUserRequired) && (!$session->isAdmin())) {
            if (@$debug) {
                $_SESSION["debug"] = "";
                echo "<font color=red>Debug mode is only allowed for admin users!</font>";
                exit();
            }
        }

        // Are we processing a login request?
        if ($validUserRequired) {
            require_once "user_login/process.php";
            /* Initialize process */
            $process = new Process;
        }
    }

    # If the debug parameter was passed in, then set it sticky in the session (either on or off).
    # NOTE ** This session access needs to be *after* the user_login include, because that
    # actually starts the session.

    # Passing debug=0 or debug=off will turn off debug mode.
    if (isset($_SESSION["debug"]) && ($_SESSION["debug"] != 0) && (strtolower($_SESSION["debug"]) != "off")) {
        $debug = $_SESSION["debug"];
        $db->debug = true;
    }


    # Needed for version_check
    if (!isset($_SESSION["cur_dbver"])) {
        $_SESSION["cur_dbver"] = getGlobalSetting("DB_MetadataVersion", 0.00);
    }

    if (!isset($_SESSION["user_dbver"])) {
        $_SESSION["user_dbver"] = getGlobalSetting("DB_UserDataVersion", 0.00);
    }

    $cur_dbver = $_SESSION["cur_dbver"];
    $user_dbver = $_SESSION["user_dbver"];

    $must_load_version_check = false;

    # Check to see the version number of the database schema.  If it needs to be updated then load that file
    if ($cur_dbver < CURRENT_DB_VERSION) {
        $must_load_version_check = true;
        if (@$running_from_command_line) {
            logDebugMessage("Metadata version update needed.  Current: $cur_dbver, Required: " . CURRENT_DB_VERSION);
            # We should update.  For the current build, required and minimum versions are the same - so just *do* the update.
            include_once "version_check.php";
        }
    }

    # Check to see the version number of the user database schema.
    if (($loginSystemExists == true) && ($user_dbver < USER_DB_VERSION)) {
        $must_load_version_check = true;
        if ($running_from_command_line) {
            include_once "version_check.php";
        }
    }

    # Check if we should load IP encoding for privacy
    if (!isset($_SESSION["ipencoding"])) {
        $_SESSION["ipencoding"] = getGlobalSetting("ipencoding", 'false');
        if ($_SESSION["ipencoding"] == 'false') {
            // turn it into bool
            $_SESSION["ipencoding"] = false;
        } else {
            $_SESSION["ipencoding"] = true;
        }
    }
    $ipencoding = $_SESSION["ipencoding"];
}

# FROM HERE WE GOT $db!

# check if we have a software subscription
$ss = false;
if (isset($session->metadata["user_ss"])) {
    // we have a pro software subscription, check if it's of valid form (expire checks are done elsewhere)
    $ss = $session->metadata["user_ss"];
    $ss["type"] = "user";
    foreach ($ss as $v) {
        if (empty($v)) {
            $ss = false;
        }
    }
} else {
    //setGlobalSetting("SoftwareSubscription", false);
    $ss = getGlobalSetting("SoftwareSubscription", false);
    if (!empty($ss)) {
        // we have a pro software subscription, check if it's of valid form (expire checks are done elsewhere)
        $ss = json_decode($ss, true);
        $ss["type"] = "server";
        foreach ($ss as $k => $v) {
            if (empty($v) && $k != "name") {
                $ss = false;
            }
        }
    } else {
        $ss = false;
    }
}

// check if we have a software license
$hl = false;
if (defined('_LOGAHOLIC_EDITION') && _LOGAHOLIC_EDITION != 0) {
    $hl = true;
}
if ($ss) {
    $hl = true;
}

if (LOGAHOLIC_BASE_EDITION != "cPanel Edition") {
    @include_once("user_settings.php");  # This is an optional file that can have several settings in it for user settings.
    # -- Possible user_settings value --
    # $do_today_as_yesterday - set this to true to do the today page as if it was midnight minus 1 second of yesterday.
    # functions: do_extra_visual_mode_url_parse and do_extra_visual_mode_page_parse that are called during visual page mode parsing to help site-specific code
}

# Are we a Cloud Manager?
if ($dbid == 0) {
    $cloudapicall = getGlobalSetting("CloudManagerCall", "");
    $cloudapi = getGlobalSetting("CloudManagerAPI", "");
}
if (empty($cloudapi)) {
    define("REPORTS_FOLDER", logaholic_dir() . "reports");
} else {
    define("REPORTS_FOLDER", $cloudapi . "/reports");
}

$cnames = CountryNames();

require_once "includes/dateselector.php";
logDebugMessage(_LOADING_PAGE . " " . @$_SERVER['SCRIPT_NAME']);

# Setup template
include_once "templates/template.php";
include_once "templates/template_v3.php";
$template = new Template_v3();

if (!empty($conf) && empty($_REQUEST['new'])) {
    if (LoggedIn() == true) {
        #Checks if setted conf exists.
        $checkprofiles = $db->Execute(
            "Select profilename from " . TBL_PROFILES . " WHERE profilename=" . $db->Quote($conf) . ""
        );
        $prof = $checkprofiles->FetchRow();
        if (empty($prof['profilename'])) {
            # If no profile is set, redirect to the profiles page.
            //die('{ "Status" : "Errror" , "Message" : "This profile does not exist!" }');
            header('Location: /index.php');
        }
    }
}

# Do we need to update the profile ?
if (isset($profile)) {
    if ($profile->profileloaded) {
        // make sure the profile is of adequate version to be used.
        if ($profile->structure_version < CURRENT_PROFILE_STRUCTURE_VERSION) {
            $must_load_version_check = true;

            if ($running_from_command_line) {
                include_once "version_check.php";
                updateDataTableForProfile($profile);
                $profile->Load($profile->profilename); // Load the profile again to apply any changes
            }
        }
    }
}

include_once "includes/report.php";

# Include Ecommerce file ?
@include_once "includes/ecommerce.php";

# Include transalarm
@include_once "includes/TransAlarm.php";

if ($lang_has_changed == true) {
    deleteProfileData($conf, $conf . ".cache\_%");
}

if (isset($dont_close_session) == false) {
    if (isset($profile) && $profile->profileloaded && ($profile->structure_version < CURRENT_PROFILE_STRUCTURE_VERSION)) {
        # don't close the session we need to upgrade the profile structure so we need a session
    } else {
        @session_write_close();
    }
}

function getmicrotime()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

function CountryNames()
{
    //set up country names;
    $cnames[_UNKNOWN] = _UNKNOWN;
    $cnames["A1"] = _A1;
    $cnames["A2"] = _A2;
    $cnames["AD"] = _AD;
    $cnames["AE"] = _AE;
    $cnames["AF"] = _AF;
    $cnames["AG"] = _AG;
    $cnames["AI"] = _AI;
    $cnames["AL"] = _AL;
    $cnames["AM"] = _AM;
    $cnames["AN"] = _AN;
    $cnames["AO"] = _AO;
    $cnames["AP"] = _AP;
    $cnames["AQ"] = _AQ;
    $cnames["AR"] = _AR;
    $cnames["AS"] = _AS;
    $cnames["AT"] = _AT;
    $cnames["AU"] = _AU;
    $cnames["AW"] = _AW;
    $cnames["AX"] = _AX;
    $cnames["AZ"] = _AZ;
    $cnames["BA"] = _BA;
    $cnames["BB"] = _BB;
    $cnames["BD"] = _BD;
    $cnames["BE"] = _BE;
    $cnames["BF"] = _BF;
    $cnames["BG"] = _BG;
    $cnames["BH"] = _BH;
    $cnames["BI"] = _BI;
    $cnames["BJ"] = _BJ;
    $cnames["BM"] = _BM;
    $cnames["BN"] = _BN;
    $cnames["BO"] = _BO;
    $cnames["BR"] = _BR;
    $cnames["BS"] = _BS;
    $cnames["BT"] = _BT;
    $cnames["BV"] = _BV;
    $cnames["BW"] = _BW;
    $cnames["BY"] = _BY;
    $cnames["BZ"] = _BZ;
    $cnames["CA"] = _CA;
    $cnames["CC"] = _CC;
    $cnames["CD"] = _CD;
    $cnames["CF"] = _CF;
    $cnames["CG"] = _CG;
    $cnames["CH"] = _CH;
    $cnames["CI"] = _CI;
    $cnames["CK"] = _CK;
    $cnames["CL"] = _CL;
    $cnames["CM"] = _CM;
    $cnames["CN"] = _CN;
    $cnames["CO"] = _CO;
    $cnames["CR"] = _CR;
    $cnames["CU"] = _CU;
    $cnames["CV"] = _CV;
    $cnames["CX"] = _CX;
    $cnames["CY"] = _CY;
    $cnames["CZ"] = _CZ;
    $cnames["DE"] = _DE;
    $cnames["DJ"] = _DJ;
    $cnames["DK"] = _DK;
    $cnames["DM"] = _DM;
    $cnames["DO"] = _DO;
    $cnames["DZ"] = _DZ;
    $cnames["EC"] = _EC;
    $cnames["EE"] = _EE;
    $cnames["EG"] = _EG;
    $cnames["EH"] = _EH;
    $cnames["ER"] = _ER;
    $cnames["ES"] = _ES;
    $cnames["ET"] = _ET;
    $cnames["EU"] = _EU;
    $cnames["FI"] = _FI;
    $cnames["FJ"] = _FJ;
    $cnames["FK"] = _FK;
    $cnames["FM"] = _FM;
    $cnames["FO"] = _FO;
    $cnames["FR"] = _FR;
    $cnames["FX"] = _FX;
    $cnames["GA"] = _GA;
    $cnames["GB"] = _GB;
    $cnames["GD"] = _GD;
    $cnames["GE"] = _GE;
    $cnames["GF"] = _GF;
    $cnames["GH"] = _GH;
    $cnames["GG"] = _GG;
    $cnames["GI"] = _GI;
    $cnames["GL"] = _GL;
    $cnames["GM"] = _GM;
    $cnames["GN"] = _GN;
    $cnames["GP"] = _GP;
    $cnames["GQ"] = _GQ;
    $cnames["GR"] = _GR;
    $cnames["GS"] = _GS;
    $cnames["GT"] = _GT;
    $cnames["GU"] = _GU;
    $cnames["GW"] = _GW;
    $cnames["GY"] = _GY;
    $cnames["HK"] = _HK;
    $cnames["HM"] = _HM;
    $cnames["HN"] = _HN;
    $cnames["HR"] = _HR;
    $cnames["HT"] = _HT;
    $cnames["HU"] = _HU;
    $cnames["ID"] = _ID;
    $cnames["IE"] = _IE;
    $cnames["IL"] = _IL;
    $cnames["IM"] = _IM;
    $cnames["IN"] = _IN;
    $cnames["IO"] = _IO;
    $cnames["IQ"] = _IQ;
    $cnames["IR"] = _IR;
    $cnames["IS"] = _IS;
    $cnames["IT"] = _IT;
    $cnames["JE"] = _JE;
    $cnames["JM"] = _JM;
    $cnames["JO"] = _JO;
    $cnames["JP"] = _JP;
    $cnames["KE"] = _KE;
    $cnames["KG"] = _KG;
    $cnames["KH"] = _KH;
    $cnames["KI"] = _KI;
    $cnames["KM"] = _KM;
    $cnames["KN"] = _KN;
    $cnames["KP"] = _KP;
    $cnames["KR"] = _KR;
    $cnames["KW"] = _KW;
    $cnames["KY"] = _KY;
    $cnames["KZ"] = _KZ;
    $cnames["LA"] = _LA;
    $cnames["LB"] = _LB;
    $cnames["LC"] = _LC;
    $cnames["LI"] = _LI;
    $cnames["LK"] = _LK;
    $cnames["LR"] = _LR;
    $cnames["LS"] = _LS;
    $cnames["LT"] = _LT;
    $cnames["LU"] = _LU;
    $cnames["LV"] = _LV;
    $cnames["LY"] = _LY;
    $cnames["MA"] = _MA;
    $cnames["MC"] = _MC;
    $cnames["MD"] = _MD;
    $cnames["ME"] = _ME;
    $cnames["MG"] = _MG;
    $cnames["MH"] = _MH;
    $cnames["MK"] = _MK;
    $cnames["ML"] = _ML;
    $cnames["MM"] = _MM;
    $cnames["MN"] = _MN;
    $cnames["MO"] = _MO;
    $cnames["MP"] = _MP;
    $cnames["MQ"] = _MQ;
    $cnames["MR"] = _MR;
    $cnames["MS"] = _MS;
    $cnames["MT"] = _MT;
    $cnames["MU"] = _MU;
    $cnames["MV"] = _MV;
    $cnames["MW"] = _MW;
    $cnames["MX"] = _MX;
    $cnames["MY"] = _MY;
    $cnames["MZ"] = _MZ;
    $cnames["NA"] = _NA;
    $cnames["NC"] = _NC;
    $cnames["NE"] = _NE;
    $cnames["NF"] = _NF;
    $cnames["NG"] = _NG;
    $cnames["NI"] = _NI;
    $cnames["NL"] = _NL;
    $cnames["NO"] = _NO;
    $cnames["NP"] = _NP;
    $cnames["NR"] = _NR;
    $cnames["NU"] = _NU;
    $cnames["NZ"] = _NZ;
    $cnames["OM"] = _OM;
    $cnames["PA"] = _PA;
    $cnames["PE"] = _PE;
    $cnames["PF"] = _PF;
    $cnames["PG"] = _PG;
    $cnames["PH"] = _PH;
    $cnames["PK"] = _PK;
    $cnames["PL"] = _PL;
    $cnames["PM"] = _PM;
    $cnames["PN"] = _PN;
    $cnames["PR"] = _PR;
    $cnames["PS"] = _PS;
    $cnames["PT"] = _PT;
    $cnames["PW"] = _PW;
    $cnames["PY"] = _PY;
    $cnames["QA"] = _QA;
    $cnames["RE"] = _RE;
    $cnames["RO"] = _RO;
    $cnames["RS"] = _RS;
    $cnames["RU"] = _RU;
    $cnames["RW"] = _RW;
    $cnames["SA"] = _SA;
    $cnames["SB"] = _SB;
    $cnames["SC"] = _SC;
    $cnames["SD"] = _SD;
    $cnames["SE"] = _SE;
    $cnames["SG"] = _SG;
    $cnames["SH"] = _SH;
    $cnames["SI"] = _SI;
    $cnames["SJ"] = _SJ;
    $cnames["SK"] = _SK;
    $cnames["SL"] = _SL;
    $cnames["SM"] = _SM;
    $cnames["SN"] = _SN;
    $cnames["SO"] = _SO;
    $cnames["SR"] = _SR;
    $cnames["ST"] = _ST;
    $cnames["SV"] = _SV;
    $cnames["SY"] = _SY;
    $cnames["SZ"] = _SZ;
    $cnames["TC"] = _TC;
    $cnames["TD"] = _TD;
    $cnames["TF"] = _TF;
    $cnames["TG"] = _TG;
    $cnames["TH"] = _TH;
    $cnames["TJ"] = _TJ;
    $cnames["TK"] = _TK;
    $cnames["TL"] = _TL;
    $cnames["TM"] = _TM;
    $cnames["TN"] = _TN;
    $cnames["TO"] = _TO;
    $cnames["TR"] = _TR;
    $cnames["TT"] = _TT;
    $cnames["TV"] = _TV;
    $cnames["TW"] = _TW;
    $cnames["TZ"] = _TZ;
    $cnames["UA"] = _UA;
    $cnames["UG"] = _UG;
    $cnames["UM"] = _UM;
    $cnames["US"] = _US;
    $cnames["UY"] = _UY;
    $cnames["UZ"] = _UZ;
    $cnames["VA"] = _VA;
    $cnames["VC"] = _VC;
    $cnames["VE"] = _VE;
    $cnames["VG"] = _VG;
    $cnames["VI"] = _VI;
    $cnames["VN"] = _VN;
    $cnames["VU"] = _VU;
    $cnames["WF"] = _WF;
    $cnames["WS"] = _WS;
    $cnames["YE"] = _YE;
    $cnames["YT"] = _YT;
    $cnames["ZA"] = _ZA;
    $cnames["ZM"] = _ZM;
    $cnames["ZW"] = _ZW;
    $cnames["CW"] = 'Curaçao';
    asort($cnames);
    return $cnames;
}

function LanguageNames()
{
    $lnames = array(
        "af-ZA" => "Afrikaans - South Africa",
        "sq-AL" => "Albanian - Albania",
        "ar-AR" => "Arabic",
        "ar-DZ" => "Arabic - Algeria",
        "ar-BH" => "Arabic - Bahrain",
        "ar-EG" => "Arabic - Egypt",
        "ar-IQ" => "Arabic - Iraq",
        "ar-JO" => "Arabic - Jordan",
        "ar-KW" => "Arabic - Kuwait",
        "ar-LB" => "Arabic - Lebanon",
        "ar-LY" => "Arabic - Libya",
        "ar-MA" => "Arabic - Morocco",
        "ar-OM" => "Arabic - Oman",
        "ar-QA" => "Arabic - Qatar",
        "ar-SA" => "Arabic - Saudi Arabia",
        "ar-SY" => "Arabic - Syria",
        "ar-TN" => "Arabic - Tunisia",
        "ar-AE" => "Arabic - United Arab Emirates",
        "ar-YE" => "Arabic - Yemen",
        "hy-AM" => "Armenian - Armenia",
        "Cy-az-AZ" => "Azeri (Cyrillic) - Azerbaijan",
        "Lt-az-AZ" => "Azeri (Latin) - Azerbaijan",
        "eu-ES" => "Basque - Basque",
        "be-BY" => "Belarusian - Belarus",
        "bg-BG" => "Bulgarian - Bulgaria",
        "ca-ES" => "Catalan - Catalan",
        "zh-CN" => "Chinese - China",
        "zh-HK" => "Chinese - Hong Kong SAR",
        "zh-MO" => "Chinese - Macau SAR",
        "zh-SG" => "Chinese - Singapore",
        "zh-TW" => "Chinese - Taiwan",
        "zh-CHS" => "Chinese (Simplified)",
        "zh-CHT" => "Chinese (Traditional)",
        "hr-HR" => "Croatian - Croatia",
        "cs-CZ" => "Czech - Czech Republic",
        "da-DK" => "Danish - Denmark",
        "div-MV" => "Dhivehi - Maldives",
        "nl-BE" => "Dutch - Belgium",
        "nl-NL" => "Dutch - The Netherlands",
        "en-AU" => "English - Australia",
        "en-BZ" => "English - Belize",
        "en-CA" => "English - Canada",
        "en-CB" => "English - Caribbean",
        "en-IE" => "English - Ireland",
        "en-JM" => "English - Jamaica",
        "en-NZ" => "English - New Zealand",
        "en-PH" => "English - Philippines",
        "en-ZA" => "English - South Africa",
        "en-TT" => "English - Trinidad and Tobago",
        "en-GB" => "English - United Kingdom",
        "en-US" => "English - United States",
        "en-ZW" => "English - Zimbabwe",
        "et-EE" => "Estonian - Estonia",
        "fo-FO" => "Faroese - Faroe Islands",
        "fa-IR" => "Farsi - Iran",
        "fi-FI" => "Finnish - Finland",
        "fr-BE" => "French - Belgium",
        "fr-CA" => "French - Canada",
        "fr-FR" => "French - France",
        "fr-LU" => "French - Luxembourg",
        "fr-MC" => "French - Monaco",
        "fr-CH" => "French - Switzerland",
        "gl-ES" => "Galician - Galician",
        "ka-GE" => "Georgian - Georgia",
        "de-AT" => "German - Austria",
        "de-DE" => "German - Germany",
        "de-LI" => "German - Liechtenstein",
        "de-LU" => "German - Luxembourg",
        "de-CH" => "German - Switzerland",
        "el-GR" => "Greek - Greece",
        "gu-IN" => "Gujarati - India",
        "he-IL" => "Hebrew - Israel",
        "hi-IN" => "Hindi - India",
        "hu-HU" => "Hungarian - Hungary",
        "is-IS" => "Icelandic - Iceland",
        "id-ID" => "Indonesian - Indonesia",
        "it-IT" => "Italian - Italy",
        "it-CH" => "Italian - Switzerland",
        "ja-JP" => "Japanese - Japan",
        "kn-IN" => "Kannada - India",
        "kk-KZ" => "Kazakh - Kazakhstan",
        "kok-IN" => "Konkani - India",
        "ko-KR" => "Korean - Korea",
        "ky-KZ" => "Kyrgyz - Kazakhstan",
        "lv-LV" => "Latvian - Latvia",
        "lt-LT" => "Lithuanian - Lithuania",
        "mk-MK" => "Macedonian (FYROM)",
        "ms-BN" => "Malay - Brunei",
        "ms-MY" => "Malay - Malaysia",
        "mr-IN" => "Marathi - India",
        "mn-MN" => "Mongolian - Mongolia",
        "nb-NO" => "Norwegian (Bokmål) - Norway",
        "nn-NO" => "Norwegian (Nynorsk) - Norway",
        "pl-PL" => "Polish - Poland",
        "pt-BR" => "Portuguese - Brazil",
        "pt-PT" => "Portuguese - Portugal",
        "pa-IN" => "Punjabi - India",
        "ro-RO" => "Romanian - Romania",
        "ru-RU" => "Russian - Russia",
        "sa-IN" => "Sanskrit - India",
        "Cy-sr-SP" => "Serbian (Cyrillic) - Serbia",
        "Lt-sr-SP" => "Serbian (Latin) - Serbia",
        "sk-SK" => "Slovak - Slovakia",
        "sl-SI" => "Slovenian - Slovenia",
        "es-AR" => "Spanish - Argentina",
        "es-BO" => "Spanish - Bolivia",
        "es-CL" => "Spanish - Chile",
        "es-CO" => "Spanish - Colombia",
        "es-CR" => "Spanish - Costa Rica",
        "es-DO" => "Spanish - Dominican Republic",
        "es-EC" => "Spanish - Ecuador",
        "es-SV" => "Spanish - El Salvador",
        "es-GT" => "Spanish - Guatemala",
        "es-HN" => "Spanish - Honduras",
        "es-MX" => "Spanish - Mexico",
        "es-NI" => "Spanish - Nicaragua",
        "es-PA" => "Spanish - Panama",
        "es-PY" => "Spanish - Paraguay",
        "es-PE" => "Spanish - Peru",
        "es-PR" => "Spanish - Puerto Rico",
        "es-ES" => "Spanish - Spain",
        "es-LA" => "Spanish",
        "es-UY" => "Spanish - Uruguay",
        "es-VE" => "Spanish - Venezuela",
        "sw-KE" => "Swahili - Kenya",
        "sv-FI" => "Swedish - Finland",
        "sv-SE" => "Swedish - Sweden",
        "syr-SY" => "Syriac - Syria",
        "ta-IN" => "Tamil - India",
        "tt-RU" => "Tatar - Russia",
        "te-IN" => "Telugu - India",
        "th-TH" => "Thai - Thailand",
        "tr-TR" => "Turkish - Turkey",
        "uk-UA" => "Ukrainian - Ukraine",
        "ur-PK" => "Urdu - Pakistan",
        "Cy-uz-UZ" => "Uzbek (Cyrillic) - Uzbekistan",
        "Lt-uz-UZ" => "Uzbek (Latin) - Uzbekistan",
        "vi-VN" => "Vietnamese - Vietnam"
    );
    asort($lnames);
    return $lnames;
}

function getVersion()
{
    global $databasedriver, $vnumfull;

    return _YOU_ARE_USING_LOGAHOLIC . ' ' . _LOGAHOLIC_PRODUCTNAME . ' ' . _LOGAHOLIC_TRIAL . 'version ' . LOGAHOLIC_VERSION_NUMBER . ' ' . _WITH_PHP_VERSION . ' ' . phpversion(
        ) . ' ' . _AND_DATABASE . ' ' . $databasedriver . ' ' . _VERSION . ' ' . $vnumfull;
}

function printSegmentName()
{
    global $trafficsource;
    if ($trafficsource > 0) {
        $source = getTrafficSourceByID($trafficsource);
        $segmentname = "<i>(" . _FILTERS . ": <b>" . $source["sourcename"] . "</b>)</i>";
    } else {
        $segmentname = "";
    }
    return $segmentname;
}

function UIDIalogButtons($show = [])
{
    $buttons = "<div class='dialog-controls'>";
    if (!empty($show)) {
        foreach ($show as $button) {
            switch ($button) {
                case "close":
                    $buttons .= "<a title='" . _CLOSE_THIS_REPORT . "' href='#' class='close'></a>";
                    break;
                case "minimize":
                    $buttons .= "<a title='" . _MINIMIZE_THIS_REPORT . "' href='#' class='minimize'></a>";
                    break;
                case "reload":
                    $buttons .= "<a title='" . _RELOAD_THIS_REPORT . "' href='#' class='reload'></a>";
                    break;
                case "dialogsettings":
                    $buttons .= "<a title='" . _CHANGE_SETTINGS_THIS_REPORT . "' href='#' class='dialogsettings'></a>";
                    break;
                default;
                    break;
            }
        }
    } else {
        $buttons .= "<a title='" . _CLOSE_THIS_REPORT . "' href='#' class='close'></a> <a title='" . _MINIMIZE_THIS_REPORT . "' href='#' class='minimize'></a> <a title='" . _EXPAND_THIS_REPORT . "' href='#' class='expand_switch expand'></a> <a title='" . _RELOAD_THIS_REPORT . "' href='#' class='reload'></a> <a title='" . _CHANGE_SETTINGS_THIS_REPORT . "' href='#' class='dialogsettings'></a>";
        $buttons .= "";
    }
    $buttons .= "</div>";
    return $buttons;
}

function safeXML($xmlString = "")
{
    $xmlString = iconv('ISO-8859-1', "UTF-8", $xmlString);
    $xmlString = str_replace("&", "&amp;", $xmlString);
    $xmlString = str_replace(">", "&gt;", $xmlString);
    $xmlString = str_replace("<", "&lt;", $xmlString);
    $xmlString = str_replace("'", "&apos;", $xmlString);
    $xmlString = str_replace('"', "&quot;", $xmlString);
    return $xmlString;
}

function CheckNotes($nlimit = 5, $noprint = false)
{
    global $conf, $to, $from, $mysqlprefix, $db;

    if ($from) {
        $q = $db->Execute(
            "select *,FROM_UNIXTIME(timestamp,'%d-%b-%Y %a') as day from " . TBL_NOTES . " where profile=" . $db->Quote(
                $conf
            ) . " and (timestamp >=" . $db->Quote($from) . " and timestamp <=" . $db->Quote(
                $to
            ) . " or timestamp=\"0\") order by timestamp desc limit " . $nlimit
        );

        if ($noprint == false) {
            $i = 0;
            $disp = "";
            while ($data = @$q->FetchRow()) {
                $disp .= "<font color=gray>" . $data["day"] . "</font> - " . $data["note"];
                $disp .= " &nbsp;&nbsp;<a class=graylink href=\"notes.php?conf=$conf&amp;donote=edit&amp;noteid=" . $data["id"] . "\">" . _EDIT . "</a>";
                $disp .= "  <a class=graylink href=\"notes.php?conf=$conf&amp;donote=del&amp;noteid=" . $data["id"] . "\">Del</a><br>";
                $i++;
            }
            $now = time();
            if (!@$disp) {
                echo "<div class=notes><table width=500 cellpadding=3 cellspacing=0 class=small border=0><tr class=small><td class=toplinegray valign=top>";
                echo "<a class=nodec3 href=\"notes.php?conf=$conf&amp;donote=create\"><img src=\"images/icons/note_add.gif\" width=\"14\" height=\"14\" border=\"0\" align=\"left\" alt=\"\"></a> " . _NO_NOTES . ", <a class=nodec3 href=\"notes.php?conf=$conf&amp;donote=create\">" . _NEW_NOTE . "</a></td></tr></table></div>";
            } else {
                echo "<div class=notes><table width=500 cellpadding=3 cellspacing=0 class=small border=0><tr class=small bgcolor=\"#FEFEEA\"><td class=toplineyellow valign=top><img src=\"images/icons/notes.gif\" width=12 height=12 border=0 align=left alt=\"Notes\"></td><td class=toplineyellow valign=top>$disp</td><td valign=top class=toplineyellow>";
                echo "<a class=nodec3 href=\"notes.php?conf=$conf&amp;donote=create\">" . _MORE_NOTES . "</a></td>";
                echo "</tr></table></div>";
            }
        } else {
            $notes = [];
            while ($data = @$q->FetchRow()) {
                $notes[] = $data;
            }

            return $notes;
        }
    }
}

function currentScriptURL($path = false)
{
    /*if ($_SERVER['SERVER_PORT'] == '443') {
		$scriptURL = "https://";
	} else {
		$scriptURL = "http://";
	}*/
    if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") {
        $scriptURL = "https://";
    } else {
        $scriptURL = "https://";
    }

    if ($_SERVER['SERVER_PORT'] != '80' && $_SERVER['SERVER_PORT'] != '443') {
        $port = ':' . $_SERVER['SERVER_PORT'];
    } else {
        $port = '';
    }

    if ($path == true) {
        return $scriptURL . $_SERVER['HTTP_HOST'] . $port . dirname($_SERVER['PHP_SELF']);
    } else {
        return $scriptURL . $_SERVER['HTTP_HOST'] . $port . $_SERVER['PHP_SELF'];
    }
}

function logaholic_url($update = false)
{
    $url = getGlobalSetting("logaholic_url", false);
    if ($url == false || $update == true) {
        if (isset($_SERVER['HTTP_HOST'])) {
            $url = currentScriptURL(true);
            setGlobalSetting("logaholic_url", $url);
        }
    }
    return $url;
}

function in_array_insensitive($needle, $haystack)
{
    foreach ($haystack as $value) {
        if (strcasecmp($value, $needle) == 0) {
            return true;
        }
    }
    return false;
}

function getProfileData($settingname, $profile = 'Profiles', $defaultvalue = "")
{
    global $db;

    $query = "Select Value from " . TBL_GLOBAL_SETTINGS . " where Name = " . $db->Quote(
            $settingname
        ) . " and Profile = " . $db->Quote($profile);
    if (!($result = @$db->GetRow($query))) {
        return $defaultvalue;
    }
    if (count($result) > 0) {
        return $result[0];
    } else {
        return $defaultvalue;
    }
}

function setProfileData($profile, $settingname, $settingvalue)
{
    global $db;
    $query = "REPLACE into " . TBL_GLOBAL_SETTINGS . " (Name, Value, Profile) values (" . $db->Quote(
            $settingname
        ) . ", " . $db->Quote($settingvalue) . ", " . $db->Quote($profile) . ");";
    $db->Execute($query);
}

function deleteProfileData($profile, $settingname = "")
{
    global $db;
    $query = "DELETE from " . TBL_GLOBAL_SETTINGS . " where Profile = " . $db->Quote($profile);
    if (($settingname) || ($settingname === null)) {
        if (strpos($settingname, "%")) {
            $query .= " and Name like " . $db->Quote($settingname);
        } else {
            $query .= " and Name = " . $db->Quote($settingname);
        }
    }
    $db->Execute($query);
}

function getGlobalSetting($settingname, $defaultvalue = "")
{
    return getProfileData($settingname, "", $defaultvalue);
}

function setGlobalSetting($settingname, $settingvalue)
{
    setProfileData("", $settingname, $settingvalue);
}

function logDebugMessage($error_message)
{
    // This writes to a file (or does other things) if the debug flag is turned on...
    global $debug;
    if ($debug == 1) {
        // $_SESSION["debug_log"] .= $error_message . "<br>";
    }
}

function echoConsoleSafe($Message, $LogIfConsole = false)
{
    global $running_from_command_line, $updatelog, $import;

    if (!empty($updatelog) && $LogIfConsole == true) {
        $import->LogProcess("#0|" . strip_tags($Message) . ";");
    } else {
        if (!$running_from_command_line) {
            echo $Message;
        } else {
            if ($LogIfConsole) {
                $stripped = strip_tags($Message);  // Do we need to put a CR/LF on the end?  Maybe...
                echo $stripped;
            }
        }
    }
}

function getTrafficSources()
{
    global $trafficsources, $supports_correlated_subselects, $db, $profile, $session, $running_from_command_line;

    # If we don't support correlated subselects, then we don't support traffic sources.
    if (!$supports_correlated_subselects) {
        return [];
    }

    if ($trafficsources) {
        return $trafficsources;
    }

    $trafficsources = [];

    $db->SetFetchMode(ADODB_FETCH_BOTH);
    $query = "SELECT * from " . TBL_TRAFFIC_SOURCES . " where profileid=" . $db->Quote(
            $profile->profileid
        ) . " or profileid='' order by category, sourcename";
    if ($result = $db->Execute($query)) {
        while ($trafficsource = $result->FetchRow()) {
            if ($running_from_command_line != true) {
                if (!$session->isAdmin()) {
                    # is there a userid set for this record, i.e. a private segment ?
                    if (!empty($trafficsource['userid'])) {
                        # if it is not a source of this user then GTFO!
                        if ($trafficsource['userid'] != $session->userinfo['userid']) {
                            continue;
                        }
                    }
                }
            }
            $trafficsources[] = $trafficsource;
        }
    }
    return $trafficsources;
}

function getTrafficSourceByID($sourceID)
{
    $sources = getTrafficSources();
    foreach ($sources as $source) {
        if ($source["id"] == $sourceID) {
            return $source;
        }
    }
    return null;
}

function printTrafficSourceSelectUI($selsource = 0)
{
    global $supports_correlated_subselects, $conf, $available, $session;
    $sources = getTrafficSources();
    $result = "";
    $filter = "";

    if (count($sources) > 0) {
        $result .= "<select class='isDefault form-control' id='trafficsource' name='trafficsource' ";
        if (@$available == "no") {
            $result .= "onChange=\"alert('" . _FILTER_SYSTEM_NOT_ACTIVE_HERE . "')\"";
        }
        $result .= ">\n";
        $result .= "  <option value='0'" . (($selsource == 0) ? " selected" : "") . ">" . _ALL_TRAFFIC_NO_FILTER . "</option>\n";
        foreach ($sources as $source) {
            $result .= "  <option value='{$source["id"]}'" . (($selsource == $source["id"]) ? " selected" : "") . ">" . $source["sourcename"] . " (" . $source["category"] . ")</option>\n";
            if ($selsource == $source["id"]) {
                $filter = $source["sourcecondition"];
            }
        }
        $result .= "</select>";
        if ($session->canEditProfiles()) {
            $result .= "<a class='optionlink manage_segment_filters' href=\"#\"><i class='fa fa-fw fa-angle-double-right'></i> " . _MANAGE_FILTERS . "</a> ";
        }
    } else {
        if (!$supports_correlated_subselects) {
            $result .= _FILTERS_ONLY_SUPPORTED_BY_MYSQL_41;
        } else {
            $result .= _NO_FILTERS_CREATED_YET_PART1 . "<a class='optionlink open_iframe_window' href=\"filters.php?conf=$conf\">" . _NO_FILTERS_CREATED_YET_PART2 . "</a>";
        }
    }
    return $result;
}

function prepareSegmentQuery($sqlstring)
{
    global $profile;
    $joincond = "";
    $addtables = "";

    if (strpos("  " . $sqlstring, " url ") != false) {
        $sqlstring = str_replace("url =", "u.url=", $sqlstring);
        $sqlstring = str_replace("url !=", "u.url!=", $sqlstring);
        $sqlstring = str_replace("url LIKE", "u.url LIKE", $sqlstring);
        $sqlstring = str_replace("url NOT LIKE", "u.url NOT LIKE", $sqlstring);
        $addtables = ",$profile->tablename_urls as u";
        $joincond = "and a.url=u.id";
    }


    if (strpos("  " . $sqlstring, " params ") != false) {
        if (strpos("  " . $sqlstring, " refparams ") != false) {
            # We do this so it doesn't get mixed up if both url params and ref params are used in the same query
            $sqlstring = str_replace("refparams", "tempfix", $sqlstring);
        }
        $sqlstring = str_replace("params =", " up.params=", $sqlstring);
        $sqlstring = str_replace("params !=", " up.params!=", $sqlstring);
        $sqlstring = str_replace("params LIKE", " up.params LIKE", $sqlstring);
        $sqlstring = str_replace("params NOT LIKE", " up.params NOT LIKE", $sqlstring);
        $addtables .= ",$profile->tablename_urlparams as up";
        $joincond .= " and a.params=up.id";
        if (strpos("  " . $sqlstring, " tempfix ") != false) {
            # Ok, now reset it back to the original
            $sqlstring = str_replace("tempfix", "refparams", $sqlstring);
        }
    }

    if (strpos("  " . $sqlstring, " referrer ") != false) {
        $sqlstring = str_replace("referrer =", "r.referrer=", $sqlstring);
        $sqlstring = str_replace("referrer !=", "r.referrer!=", $sqlstring);
        $sqlstring = str_replace("referrer LIKE", "r.referrer LIKE", $sqlstring);
        $sqlstring = str_replace("referrer NOT LIKE", "r.referrer NOT LIKE", $sqlstring);
        $addtables .= ",$profile->tablename_referrers as r";
        $joincond .= " and a.referrer=r.id";
    }

    if (strpos("  " . $sqlstring, " refparams ") != false) {
        $sqlstring = str_replace("refparams =", "rp.params=", $sqlstring);
        $sqlstring = str_replace("refparams !=", "rp.params!=", $sqlstring);
        $sqlstring = str_replace("refparams LIKE", "rp.params LIKE", $sqlstring);
        $sqlstring = str_replace("refparams NOT LIKE", "rp.params NOT LIKE", $sqlstring);
        $addtables .= ",$profile->tablename_refparams as rp";
        $joincond .= " and a.refparams=rp.id";
    }

    if (strpos("  " . $sqlstring, " keywords ") != false) {
        $sqlstring = str_replace("keywords =", "k.keywords=", $sqlstring);
        $sqlstring = str_replace("keywords !=", "k.keywords!=", $sqlstring);
        $sqlstring = str_replace("keywords LIKE", "k.keywords LIKE", $sqlstring);
        $sqlstring = str_replace("keywords NOT LIKE", "k.keywords NOT LIKE", $sqlstring);
        $addtables .= ",$profile->tablename_keywords as k";
        $joincond .= " and a.keywords=k.id";
    }
    if (strpos("  " . $sqlstring, " ipnumber ") != false) {
        $sqlstring = str_replace("ipnumber =", "v.ipnumber=", $sqlstring);
        $sqlstring = str_replace("ipnumber !=", "v.ipnumber!=", $sqlstring);
        $sqlstring = str_replace("ipnumber LIKE", "v.ipnumber LIKE", $sqlstring);
        $sqlstring = str_replace("ipnumber NOT LIKE", "v.ipnumber NOT LIKE", $sqlstring);
        $addtables .= ",$profile->tablename_visitorids as v";
        $joincond .= " and a.visitorid=v.id";
    }

    /*if (strpos("  ".$sqlstring," useragent ")!=FALSE) {
        $sqlstring=str_replace("useragent =","CONCAT(ua.name, ' ', ua.version)=",$sqlstring);
        $sqlstring=str_replace("useragent !=","CONCAT(ua.name, ' ', ua.version)!=",$sqlstring);
        $sqlstring=str_replace("useragent LIKE","CONCAT(ua.name, ' ', ua.version) LIKE",$sqlstring);
        $sqlstring=str_replace("useragent NOT LIKE","CONCAT(ua.name, ' ', ua.version) NOT LIKE",$sqlstring);
        # Avoid it being joined twice if we also have is_mobile in the sqlstring
        if (strpos("  ".$sqlstring," is_mobile ")===FALSE) {
            $addtables.=",{$profile->tablename_useragents} as ua";
            $joincond.=" and a.useragentid=ua.id";
        }
    }*/

    if (strpos("  " . $sqlstring, " useragent ") != false) {
        $sqlstring = str_replace("useragent =", "ua.useragent=", $sqlstring);
        $sqlstring = str_replace("useragent !=", "ua.useragent!=", $sqlstring);
        $sqlstring = str_replace("useragent LIKE", "ua.useragent LIKE", $sqlstring);
        $sqlstring = str_replace("useragent NOT LIKE", "ua.useragent NOT LIKE", $sqlstring);
        # Avoid it being joined twice if we also have is_mobile in the sqlstring
        if (strpos("  " . $sqlstring, " is_mobile ") === false) {
            $addtables .= ",{$profile->tablename_useragents} as ua";
            $joincond .= " and a.useragentid=ua.id";
        }
    }
    if (strpos($sqlstring, "is_mobile ") !== false) {
        $sqlstring = str_replace("is_mobile =", "ua.is_mobile=", $sqlstring);
        $sqlstring = str_replace("is_mobile !=", "ua.is_mobile!=", $sqlstring);
        $sqlstring = str_replace("is_mobile LIKE", "ua.is_mobile LIKE", $sqlstring);
        $sqlstring = str_replace("is_mobile NOT LIKE", "ua.is_mobile NOT LIKE", $sqlstring);
        $addtables .= ",{$profile->tablename_useragents} as ua";
        $joincond .= " and a.useragentid=ua.id";
    }

    $sqlinfo["joincond"] = $joincond;
    $sqlinfo["addtables"] = $addtables;
    $sqlinfo["sqlstring"] = $sqlstring;

    return $sqlinfo;
}

function makePositive($sqlstring)
{
    $sqlstring = str_replace("!=", "=", $sqlstring);
    $sqlstring = str_replace("NOT LIKE", "LIKE", $sqlstring);
    return $sqlstring;
}

function hasNegativeCondition($sqlstring)
{
    if (strpos($sqlstring, "!=") !== false || strpos($sqlstring, "NOT LIKE") !== false) {
        return true;
    } else {
        return false;
    }
}

function getOperator($sqlstring)
{
    if (strpos($sqlstring, " AND ") !== false) {
        $operator = "AND";
    } else {
        $operator = "OR";
    }
    return $operator;
}

function arrayConditions($sqlstring)
{
    $operator = getOperator($sqlstring);
    $conditions = explode($operator, $sqlstring);
    return $conditions;
}

function getPositiveConditions($sqlstring)
{
    $newstr = "";
    $added = 0;
    $operator = getOperator($sqlstring);
    $conditions = arrayConditions($sqlstring);
    foreach ($conditions as $value) {
        if ($added != 0) {
            $op = " $operator ";
        } else {
            $op = "";
        }
        if (hasNegativeCondition($value) == false) {
            $newstr .= $op . $value;
            $added++;
        }
    }
    if ($newstr != "") {
        return $newstr;
    } else {
        return false;
    }
}

function insertSegmentVisitorids($sqlinfo, $temp_tablename, $crawl = "0")
{
    global $db, $profile, $from, $to;
    $starttime = getmicrotime();

    $lt = "";

    if (!empty($sqlinfo['addtables'])) {
        $lt = "," . str_replace(",", " READ,", substr($sqlinfo['addtables'], 1)) . "  READ";
    }

    $db->Execute("LOCK tables " . $temp_tablename . " WRITE, {$profile->tablename} as a READ $lt");
    $query = "INSERT INTO " . $temp_tablename . " SELECT distinct a.visitorid traffic_source_visitor_visitorid from " . $profile->tablename .
        " as a {$sqlinfo['addtables']} where timestamp >= " . $db->Quote($from) . " and timestamp <= " . $db->Quote(
            $to
        ) . " and a.crawl = " . $db->Quote($crawl) . " " .
        " {$sqlinfo['joincond']} and (" . $sqlinfo['sqlstring'] . ")";
    $took = getmicrotime() - $starttime;
    $db->Execute($query);
    $db->Execute("UNLOCK tables");
}

function updateSegmentTable($sqlinfo, $temp_tablename)
{
    global $db, $profile, $trafficsource, $from, $to;

    # Now check if the from-to range is unchanged, if it is, we have to refill the table
    if (($from . $to) != $profile->GetOtherSettings("SEGMENT_" . $trafficsource . "_Range", 0)) {
        $profile->SetOtherSettings("SEGMENT_" . $trafficsource . "_Range", ($from . $to));
        //first clear whatever is in the table
        $db->Execute("delete from " . $temp_tablename);
        insertSegmentVisitorids($sqlinfo, $temp_tablename);
    }
}

function makeNewVisitorsSegmentTable($temp_tablename)
{
    global $db, $profile, $from, $to;
    $db->Execute("delete from " . $temp_tablename);

    $db->Execute("LOCK tables {$temp_tablename} WRITE, {$profile->tablename_visitorids} as a READ");
    $query = "INSERT INTO {$temp_tablename} SELECT distinct a.id traffic_source_visitor_visitorid from " . $profile->tablename_visitorids .
        " as a where created >= " . $db->Quote($from) . " and created <= " . $db->Quote($to) . "";

    $db->Execute($query);
    $db->Execute("UNLOCK tables");
}

function makeReturnVisitorsSegmentTable($temp_tablename, $f = 0)
{
    global $db, $profile, $from;

    # If there is no from given in the function get the from of the total range
    if ($f === 0) {
        $f = $from;
    }

    # Date Range of visitors data filter filter is always max 30 days ??
    // $minimum = mktime(0,0,0, date('m',$f), date('d',$f) - 30,date('Y',$f) );

    $db->Execute("delete from $temp_tablename");

    $db->Execute("LOCK tables $temp_tablename WRITE, {$profile->tablename_visitorids} as a READ");
    $query = "INSERT INTO {$temp_tablename} SELECT distinct a.id traffic_source_visitor_visitorid from " . $profile->tablename_visitorids .
        " as a where created < " . $db->Quote($f) . "";
    $db->Execute($query);
    $db->Execute("UNLOCK tables");
}

function subsetDataToSourceID($report_query, $trafficsource = null, $f = 0)
{
    global $profile, $from, $to;
    global $db;
    if (!$trafficsource) {
        if (isset($_SESSION["trafficsource"])) {
            $trafficsource = $_SESSION["trafficsource"];
        }
    }
    if (isset($trafficsource) && is_numeric($trafficsource) && $trafficsource != 0) {
        $temp_tablename = "";
        $query = "";
        # Make a semi permanent table ...
        $temp_tablename = $profile->tablename . "_SEGMENT_" . $trafficsource;

        # Check if the table has been created
        if (!CheckIfTableExists($temp_tablename)) {
            # Create the semi temporary table of visitors based on the traffic source.
            $query = "CREATE OR REPLACE TABLE  " . $temp_tablename . " (traffic_source_visitor_visitorid int(11), KEY `visitorid` (`traffic_source_visitor_visitorid`)) ENGINE=MyISAM  CHARSET=utf8";
            $db->Execute($query);
        }
        # Get the primary query conditions
        $source = getTrafficSourceByID($trafficsource);

        //dump($source);

        $sqlstring = $source["sourcecondition"];
        # We need to rewrite the sqlstring to the new style tables first
        $sqlinfo = prepareSegmentQuery($sqlstring);

        # We need to decode the source condition an then prepare it along these rules:
        # 1. We ALWAYS make a positive visitorid list, even for negative conditions
        # 2. If there is a positive condition, we always join on visitorid = visitorid in the end
        # 3. If there is only one condition and it is negative, we join on visitorid != visitorid in the end
        # 4. If there are positive AND negative conditions, we make T1 (positive list), T2 (negative list) and then T3 (all t1 that not in t2)

        $sqlstring = $sqlinfo["sqlstring"];

        $conditions = arrayConditions($sqlstring);
        $num_conditions = count($conditions);

        if ($source["sourcename"] == "Return Visitors") { # Return visitors
            $sqlinfo["matchmode"] = "positive";
            makeReturnVisitorsSegmentTable($temp_tablename, $f);
        } else {
            if ($source["sourcename"] == "New Visitors") { # New visitors
                $sqlinfo["matchmode"] = "positive";
                makeNewVisitorsSegmentTable($temp_tablename);
            } else {
                if (hasNegativeCondition($sqlstring) == true && getPositiveConditions($sqlstring) == false) {
                    $sqlinfo["matchmode"] = "negative";
                    $sqlinfo["sqlstring"] = makePositive($sqlstring);
                    updateSegmentTable($sqlinfo, $temp_tablename);
                } else {
                    $sqlinfo["matchmode"] = "positive";

                    if (hasNegativeCondition($sqlstring) == false) {
                        # Just update the segment table
                        updateSegmentTable($sqlinfo, $temp_tablename);
                    } else {
                        # This means we have more than one condition and at least one is negative
                        if (($from . $to) != $profile->GetOtherSettings("SEGMENT_" . $trafficsource . "_Range", 0)) {
                            $profile->SetOtherSettings("SEGMENT_" . $trafficsource . "_Range", ($from . $to));

                            # First we take the positive stuff and put it in t1
                            $db->Execute(
                                "CREATE TEMPORARY TABLE if not exists t1 (traffic_source_visitor_visitorid int(11), KEY `visitorid` (`traffic_source_visitor_visitorid`))"
                            );
                            $sqlinfo["sqlstring"] = getPositiveConditions($sqlstring);
                            insertSegmentVisitorids($sqlinfo, "t1");

                            # Then we take the negative ones and put them in t2
                            $db->Execute(
                                "CREATE TEMPORARY TABLE if not exists t2 (traffic_source_visitor_visitorid int(11), KEY `visitorid` (`traffic_source_visitor_visitorid`))"
                            );
                            $sqlinfo["sqlstring"] = makePositive($sqlstring);
                            insertSegmentVisitorids($sqlinfo, "t2");

                            # Then we take everthing from t1 that is not found in t2 and we update the segment table manually
                            $t3 = "INSERT into $temp_tablename SELECT traffic_source_visitor_visitorid from t1 where traffic_source_visitor_visitorid NOT IN (select traffic_source_visitor_visitorid from t2)";
                            $db->Execute($t3);
                        }
                    }
                }
            }
        }

        # OK, we have some data, now let's fix up the query that was passed in so it *joins* with the new table.
        $aliasname = "FILTER_TABLE";
        if (strpos($report_query, "$profile->tablename as a") !== false || strpos(
                $report_query,
                $profile->tablename . "_temptable AS a"
            ) !== false) {
            $m_alias = "a.";
        } else {
            $m_alias = "";
        }

        # To prevent subqueries using IN from being editied, do this
        $rq = explode(" IN ", $report_query);
        if ($sqlinfo['matchmode'] == "positive") {
            $report_query = preg_replace(
                "/ from (.*) where (.*)/i",
                " FROM " . preg_quote(
                    $temp_tablename
                ) . " as " . $aliasname . ", $1 WHERE (" . $aliasname . ".traffic_source_visitor_visitorid = " . $m_alias . "visitorid) and $2",
                $rq[0]
            );
        } else {
            $report_query = preg_replace(
                "/ where (.*)/i",
                " WHERE " . $m_alias . "visitorid NOT IN (select traffic_source_visitor_visitorid from " . preg_quote(
                    $temp_tablename
                ) . ") and $1",
                $rq[0]
            );
        }
        # Stick the other IN clauses back on the query
        if (isset($rq[1])) {
            $report_query = $report_query . " IN " . $rq[1];
        }
        if (isset($rq[2])) {
            $report_query = $report_query . " IN " . $rq[2];
        }
        return $report_query;
    }
    return $report_query;
}

$trafficsources = null;

function LoadFieldSelect()
{
    global $conf, $profile, $db;

    $output = "<option></option>";
    $columns = $db->MetaColumns($profile->tablename);
    foreach ($columns as $column) {
        if ($column->name != "id" && $column->name != "timestamp" && $column->name != "status" && $column->name != "bytes" && $column->name != "crawl") {
            if ($column->name == "visitorid") {
                $output .= "<option value=\"ipnumber\">ipnumber</option>\n";
            } else {
                if ($column->name == "useragentid") {
                    $output .= "<option value=\"useragent\">useragent</option>\n";
                } else {
                    $output .= "<option value=\"" . $column->name . "\">" . $column->name . "</option>\n";
                }
            }
        }
    }

    # Add one more for the mobile field
    $output .= "<option value=\"is_mobile\">is Mobile</option>\n";

    return $output;
}

function LoadFieldSelectFull()
{
    global $conf, $profile, $db;

    $output = "<option></option>";

    $columns = $db->MetaColumns($profile->tablename);
    foreach ($columns as $column) {
        if ($column->name != "id" && $column->name != "timestamp" && $column->name != "sessionid") {
            if ($column->name == "visitorid") {
                $output .= "<option value=\"visitorid\">visitorid</option>\n";
                $output .= "<option value=\"ipnumber\">ipnumber</option>\n";
            } else {
                if ($column->name == "useragentid") {
                    $output .= "<option value=\"useragent\">useragent</option>\n";
                } else {
                    $output .= "<option value=\"" . $column->name . "\">" . $column->name . "</option>\n";
                }
            }
        }
    }

    # Add one more for the mobile field
    $output .= "<option value=\"is_mobile\">is Mobile</option>\n";
    return $output;
}

function SelectField($html, $field)
{
    # Remove any currently selected option
    $html = str_replace(" SELECTED", "", $html);

    # Now find the one we want and select it
    $field = trim($field);
    if ($field) {
        $html = str_replace("<option value=\"$field\">", "<option value=\"$field\" SELECTED>", $html);
    }
    return $html;
}

function SecurityCheck($input, $key)
{
    if (!is_array($input)) {
        if (strpos($input, ">") !== false) {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: $input (>): exiting (Invalid characters found)"
                )
            )
            );
        }
        if (strpos($input, "<") !== false) {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: $input (<): exiting (Invalid characters found)"
                )
            )
            );
        }
        if (strpos($input, "{") !== false && $key !== 'password') {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: $input ({): exiting (Invalid characters found)"
                )
            )
            );
        }
        if (strpos($input, "}") !== false && $key !== 'password') {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: $input (}): exiting (Invalid characters found)"
                )
            )
            );
        }
        if (strpos($input, "<script>") !== false) {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: JAVASCRIPT INJECTION!"
                )
            )
            );
        }
        if (strpos($input, "</script>") !== false) {
            die(
            json_encode(
                array(
                    "Status" => "Error",
                    "Callout" => true,
                    "Message" => "Security failure in $key: JAVASCRIPT INJECTION!"
                )
            )
            );
        }
    }
}

function get_month_lastday($month_num = false, $year = false)
{
    # Set the proper month (current if non passed)
    $month_num = ($month_num) ? $month_num : date('m');
    $year = ($year) ? $year : date('Y');

    # return the last day of the requested month
    $d = date(
        'd',
        strtotime(
            '-1 second',
            strtotime(
                '+1 month',
                strtotime($month_num . '/01/' . $year . ' 00:00:00')
            )
        )
    );
    return intval($d);
}

function DeleteRange($delprofile, $what)
{
    global $db, $from, $to;
    $m = "";
    /*
		what = 1: only delete detail data from main table
		what = 2: delete all
		what = 3: only delete from summary tables
    */
    if (($what == 1) || ($what == 2)) {
        $db->Execute(
            "delete from $delprofile->tablename where timestamp >=" . $db->Quote(
                $from
            ) . " and timestamp <=" . $db->Quote($to) . ""
        );
        $db->Execute(
            "delete from $delprofile->tablename_crawl where timestamp >=" . $db->Quote(
                $from
            ) . " and timestamp <=" . $db->Quote($to) . ""
        );

        $m = _DELETED_DETAIL_DATA_IN_DATE_RANGE . ". ";
    }

    if ($what == 2) {
        $m .= DeleteDataFiles($delprofile, $from, $to);
    }

    $db->Execute(
        "delete from $delprofile->tablename_conversions where timestamp >=" . $db->Quote(
            $from
        ) . " and timestamp <=" . $db->Quote($to) . ""
    );

    if (CheckIfTableExists($delprofile->tablename_screenres)) {
        $db->Execute(
            "delete from $delprofile->tablename_screenres where timestamp >=" . $db->Quote(
                $from
            ) . " and timestamp <=" . $db->Quote($to) . ""
        );
    }

    if (CheckIfTableExists($delprofile->tablename_colordepth)) {
        $db->Execute(
            "delete from $delprofile->tablename_colordepth where timestamp >=" . $db->Quote(
                $from
            ) . " and timestamp <=" . $db->Quote($to) . ""
        );
    }

    $delprofile->filehistory = "";
    $delprofile->Save();
    return $m;
}

function getField($table)
{
    # Returns the appropriate field to use with table
    switch ($table) {
        case "urls":
            $field = "url";
            break;
        case "urlparams":
            $field = "params";
            break;
        case "keyword":
            $field = "keywords";
            break;
        case "referrers":
            $field = "referrer";
            break;
        case "refparams":
            $field = "params";
            break;
        case "useragents":
            $field = "useragent";
            break;
    }
    if (isset($field)) {
        return $field;
    }
    return false;
}

function getTable($field)
{
    # Returns the appropriate table to use with the field
    switch ($field) {
        case "url":
            $table = "urls";
            break;
        case "params":
            $table = "urlparams";
            break;
        case "keywords":
            $table = "keyword";
            break;
        case "referrer":
            $table = "referrers";
            break;
        case "refparams":
            $table = "refparams";
            break;
        case "useragent":
            $table = "useragents";
            break;
    }
    if (isset($table)) {
        return $table;
    }
    return false;
}

function getID($item, $table, $profiletablename = "")
{
    /* returns the ID of the item in the table
    */
    global $db, $profile;

    if (empty($profiletablename)) {
        if (isset($profile->tablename)) {
            $profiletablename = $profile->tablename;
        } else {
            // this is no good
            return false;
        }
    }

    $field = getField($table);

    $query = "select id from " . $profiletablename . "_$table where `hash`=" . $db->Quote(md5($item));
    $result = $db->Execute($query);
    if ($data = $result->FetchRow()) {
        return $data['id'];
    } else {
        return false;
    }
}

function getVAL($id, $table, $profiletablename = "")
{
    /* returns the value of the item in the table
    */
    global $db, $profile;

    if (empty($profiletablename)) {
        if (isset($profile->tablename)) {
            $profiletablename = $profile->tablename;
        } else {
            // this is no good
            return false;
        }
    }

    $field = getField($table);

    $query = "select $field from " . $profiletablename . "_$table where `id`=" . $db->Quote($id);
    $result = $db->Execute($query);
    if ($data = $result->FetchRow()) {
        return $data[$field];
    } else {
        return false;
    }
}

# find or insert the item.
function InsertOrGetID($item, $table, $method = "")
{
    global $db, $profile, $timetracking;

    $starttime = getmicrotime();

    # get the field we need
    $field = getField($table);

    $item = substr($item, 0, 255);

    # Reject overly long 2 byte sequences, as well as characters above U+10000 and replace with ?
    $item = preg_replace(
        '/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]' .
        '|[\x00-\x7F][\x80-\xBF]+' .
        '|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*' .
        '|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})' .
        '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
        '?',
        $item
    );

    # Reject overly long 3 byte sequences and UTF-16 surrogates and replace with ?
    $item = preg_replace(
        '/\xE0[\x80-\x9F][\x80-\xBF]' .
        '|\xED[\xA0-\xBF][\x80-\xBF]/S',
        '?',
        $item
    );

    # Make the item safe for database insert
    $item = $db->quote($item);

    if ($method == "duplicate") {
        # This way is probably faster, but it's buggy on some mysql version AND we can't do this if we have merge tables
        $db->Execute(
            "INSERT INTO " . $profile->tablename . "_$table ($field, `hash`) VALUES ($item, MD5($item)) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)"
        );
        $id = $db->Insert_ID();
        $stoptime = getmicrotime();
        @$timetracking[$table] += $stoptime - $starttime;
        return $id;
    }

    $id = getID($item, $table);
    if ($id === false) {
        $db->Execute("Insert into " . $profile->tablename . "_$table ($field, `hash`) values ($item, MD5($item))");
        $id = $db->Insert_ID();
    }
    $stoptime = getmicrotime();
    @$timetracking[$table] += $stoptime - $starttime;
    return $id;
}

function echoDebug($string, $stay = false, $call = true)
{
    global $debug, $errorHandler;

    $extra_classes = "";
    if ($stay == true) {
        $extra_classes .= " error";
    }

    if (!empty($debug)) {
        ob_start();
        $errorHandler->showBacktrace();
        $callstack = ob_get_clean();
        echo "<div class=\"debug{$extra_classes}\">&nbsp; <div class='mysql_debug'>{$string}</div>";
        //echo "<div class=\"lala\">&nbsp; <div class='mysql_debug'>{$string}</div>";
        if ($call === true) {
            echo $callstack;
        }
        echo "</div>";
        // echo "<script type='text/javascript'>debugToConsole('');</script>";
    }
}

function echoWarning($string, $style = "margin-top:17px;")
{
    echo Warning($string, $style);
}

function Warning($string, $style = "")
{
    //return "<div class=\"warning ui-state-error ui-corner-all\" style=\"$style\">$string</div>";
    return "<div class=\"alert alert-danger\" style=\"$style\"><i class=\"fa fa-ban\"></i> $string</div>";
}

function echoSuccess($string, $style = "margin-top:17px;")
{
    echo Success($string, $style);
}

function Success($string, $style = "")
{
    //return "<div class=\"warning ui-state-error ui-corner-all\" style=\"$style\">$string</div>";
    return "<div class=\"alert alert-success\" style=\"$style\"><i class=\"fa fa-check\"></i> $string</div>";
}

function echoNotice($string, $style = "margin-top:17px;")
{
    echo Notice($string, $style);
}

function Notice($string, $style = "")
{
    //return "<div class=\"warning ui-state-highlight ui-corner-all\" style=\"$style\">$string</div>";
    return "<div class=\"alert alert-info\" style=\"$style\"><i class=\"fa fa-info\"></i> $string</div>";
}

function Button($url, $anchor, $style = "")
{
    return "<a class=\"btn btn-sm btn-default\" style=\"$style\" href=\"$url\">$anchor</a>";
}

/**
 * @desc This will create an array with target files.
 * If there are any entries with wildcards, we'll query
 * the database and add the variations
 */
function explodeTargets($targetfiles)
{
    global $profile, $db;

    $targets = explode(",", $targetfiles);
    $tarray = [];
    $i = 0;
    $w = 0;
    foreach ($targets as $thistarget) {
        $thistarget = trim($thistarget);
        if (strpos($thistarget, "*") !== false) {
            # we have a wildcard, lets add all the variations later
            $wildcard[$w] = $thistarget;
            $w++;
        } else {
            $tarray[$i] = $thistarget;
            $i++;
        }
    }
    if (isset($wildcard)) {
        foreach ($wildcard as $thistarget) {
            $t = str_replace("*", "%", $thistarget);
            $query = "select url from $profile->tablename_urls where url like " . $db->Quote($t) . " limit 10";
            $q = $db->Execute($query);
            while ($data = $q->FetchRow()) {
                $tarray[$i] = $data['url'];
                $i++;
            }
        }
    }
    return $tarray;
}

function PrettyDate($time)
{
    return date("D, d M Y / H:i", $time);
}

function deleteDataTable(&$profile)
{
    global $databasedriver, $db;

    $tables = array(
        $profile->tablename,
        $profile->tablename_conversions,
        $profile->tablename_urls,
        $profile->tablename_urlparams,
        $profile->tablename_referrers,
        $profile->tablename_refparams,
        $profile->tablename_keywords,
        $profile->tablename_visitorids,
        $profile->tablename_trackerlog,
        $profile->tablename_screenres,
        $profile->tablename_colordepth,
        $profile->tablename_useragents,
        $profile->tablename_crawl,
        $profile->tablename_merge,
        $profile->tablename_vlength,
        $profile->tablename_tlength,
        $profile->tablename . "_clength",
        $profile->tablename . "_funnels",
        $profile->tablename . "_splittests",
        $profile->tablename . "_splittests_results",
        $profile->tablename . "_surveyquestions",
        $profile->tablename . "_surveyresults",
        $profile->tablename . "_surveys",
        $profile->tablename . "log",
    );
    $segments = $db->Execute("select id from " . TBL_TRAFFIC_SOURCES . " where profileid = {$profile->profileid}");
    while ($row = $segments->FetchRow()) {
        $tables[] = $profile->tablename . "_SEGMENT_" . $row['id'];
    }

    foreach ($tables as $t) {
        $db->Execute("drop table IF EXISTS $t");
    }

    # Remove segments for this profile..
    $db->Execute("delete from " . TBL_TRAFFIC_SOURCES . " where profileid = {$profile->profileid}");

    # Remove goals from the table..
    @$db->Execute("delete from " . TBL_GOALS . " WHERE profileID = {$profile->profileid}");
}

function createMainProfileTable($tablename)
{
    global $databasedriver, $db, $logaEcommerce;

    $tabcreate = "CREATE OR REPLACE TABLE  $tablename (" .
        "timestamp int(11) NOT NULL default '0', " .
        "visitorid int(11) NOT NULL default '0', " .
        "url int(11),    " .
        "params int(11),    " .
        "status smallint(3) NOT NULL default 0,    " .
        "bytes int(20) NOT NULL default 0,    " .
        "referrer int(11),    " .
        "refparams int(11),    " .
        "useragentid int(11),    " .
        "keywords int(11),    " .
        "country char(3) default '',    " .
        "crawl int(1) NOT NULL default '0', " .
        "sessionid int(11) NOT NULL default '0', " .
        "key timestamp (timestamp), " .
        "key visitorid (visitorid) " .
        ") ENGINE=MyISAM  CHARSET=utf8";
    $db->Execute($tabcreate);

    # add ecommerce columns
    if (!empty($logaEcommerce)) {
        $logaEcommerce->AddColumns($tablename);
    }
}

/**
 * Create the table structure for the profile table.
 * @param SiteProfile The profile to update.
 */
function createDataTable(&$profile)
{
    global $databasedriver, $db, $logaEcommerce;

    # Check and see if we need to create the table.
    $tablename = $profile->tablename;


    createMainProfileTable($tablename);


    # create the tracker storage table
    if ($profile->trackermode == 1) {
        $db->Execute(
            "CREATE OR REPLACE TABLE  $profile->tablename_trackerlog (" .
            "id " . (($databasedriver != "sqlite") ? "int(11) NOT NULL auto_increment" : "integer primary key") . ", " .
            "logline TEXT default NULL" .
            (($databasedriver != "sqlite") ? ", PRIMARY KEY (id)" : "") .
            ") ENGINE=MyISAM  CHARSET=utf8"
        );
    }


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_conversions (
            timestamp int(11) NOT NULL default '0',
            visitorid varchar(32) NOT NULL default '0',
            url int(11) NOT NULL default '0'
        ) ENGINE=MyISAM  CHARSET=utf8"
    );
    if ($databasedriver == "mysql") {
        $db->Execute(
            "ALTER TABLE {$profile->tablename_conversions} ADD INDEX IF NOT EXISTS {$profile->tablename_conversions}_timestamp (timestamp)"
        );
    } else {
        $db->Execute(
            "CREATE INDEX {$profile->tablename_conversions}_timestamp on {$profile->tablename_conversions}(timestamp)"
        );
    }


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_urls (" .
        "id int(11) NOT NULL auto_increment, " .
        "url varchar(255) NOT NULL default '0'," .
        "title varchar(255) default ''," .
        "`hash` CHAR(32) default ''," .
        "PRIMARY KEY (id)," .
        "UNIQUE KEY (`hash`)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_urlparams (" .
        "id int(11) NOT NULL auto_increment, " .
        "params varchar(255) default '', " .
        "`hash` CHAR(32) default ''," .
        "PRIMARY KEY (id)," .
        "UNIQUE KEY (`hash`)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_referrers (" .
        "id int(11) NOT NULL auto_increment, " .
        "referrer varchar(255) NOT NULL default '0'," .
        "`hash` CHAR(32) default ''," .
        "`internal_referrer` INT NOT NULL DEFAULT 0," .
        "PRIMARY KEY (id)," .
        "UNIQUE KEY (`hash`)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_refparams (" .
        "id int(11) NOT NULL auto_increment, " .
        "params varchar(255) default ''," .
        "`hash` CHAR(32) default ''," .
        "PRIMARY KEY (id)," .
        "UNIQUE KEY (`hash`)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_keywords (" .
        "id int(11) NOT NULL auto_increment, " .
        "keywords varchar(255) default ''," .
        "`hash` CHAR(32) default ''," .
        "PRIMARY KEY (id)," .
        "UNIQUE KEY (`hash`)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    $db->Execute(
        "CREATE OR REPLACE TABLE  $profile->tablename_visitorids (" .
        "id int(11) NOT NULL auto_increment, " .
        "visitorid char(32) NOT NULL default '0'," .
        "ipnumber varchar(255) NOT NULL default '0', " .
        "authuser varchar(80), " .
        "created int(11) NOT NULL default '0', " .
        "customlabel varchar(80) NOT NULL default ''," .
        "crawl int(1) NOT NULL default 0 " .
        ", PRIMARY KEY (id)" .
        ", UNIQUE KEY (visitorid)" .
        ") ENGINE=MyISAM  CHARSET=utf8"
    );


    if ($profile->trackermode == 1) {
        $db->Execute(
            "CREATE OR REPLACE TABLE  $profile->tablename_screenres (" .
            "id " . (($databasedriver != "sqlite") ? "int(11) NOT NULL auto_increment" : "integer primary key") . ", " .
            "timestamp int(11) NOT NULL default '0'," .
            "screenres varchar(20) NOT NULL default ''," .
            "visits bigint(100) NOT NULL default '0'" .
            (($databasedriver != "sqlite") ? ", PRIMARY KEY (id)" : "") .
            ") ENGINE=MyISAM  CHARSET=utf8"
        );


        $db->Execute(
            "CREATE OR REPLACE TABLE  $profile->tablename_colordepth (" .
            "id " . (($databasedriver != "sqlite") ? "int(11) NOT NULL auto_increment" : "integer primary key") . ", " .
            "timestamp int(11) NOT NULL default '0'," .
            "colordepth varchar(20) NOT NULL default ''," .
            "visits bigint(100) NOT NULL default '0'" .
            (($databasedriver != "sqlite") ? ", PRIMARY KEY (id)" : "") .
            ") ENGINE=MyISAM  CHARSET=utf8"
        );
    }

    $db->Execute(
        "CREATE OR REPLACE TABLE  `{$profile->tablename_useragents}` (
			  `id` int(11) NOT NULL AUTO_INCREMENT,
			  `name` varchar(255) DEFAULT NULL,
			  `version` varchar(255) DEFAULT NULL,
			  `os` varchar(255) DEFAULT NULL,
			  `os_version` varchar(255) DEFAULT NULL,
			  `engine` varchar(255) DEFAULT NULL,
			  `useragent` text,
			  `is_bot` int(1) NOT NULL default '0',
			  `is_mobile` int(1) NOT NULL default '0',
			  `device` varchar(255) DEFAULT NULL,
			  `hash` CHAR(32) NOT NULL default '0',
			  PRIMARY KEY (`id`),
			  UNIQUE KEY `hash` (`hash`)
			) ENGINE=MyISAM  DEFAULT CHARSET=utf8;"
    );


    $db->Execute("CREATE OR REPLACE TABLE  `{$profile->tablename_crawl}` like {$profile->tablename}");


    if (!empty($logaEcommerce)) {
        $query = $logaEcommerce->MergeTable($profile->tablename_merge, $profile->tablename, $profile->tablename_crawl);
    } else {
        $query = "CREATE OR REPLACE TABLE  {$profile->tablename_merge} (" .
            "timestamp int(11) NOT NULL default '0',    " .
            "visitorid int(11) NOT NULL default '0', " .
            "url int(11),    " .
            "params int(11),    " .
            "status smallint(3) NOT NULL default 0,    " .
            "bytes int(20) NOT NULL default 0,    " .
            "referrer int(11),    " .
            "refparams int(11),    " .
            "useragentid int(11),    " .
            "keywords int(11),    " .
            "country char(3) default '',    " .
            "crawl int(1) NOT NULL default '0', " .
            "sessionid int(11) NOT NULL default '0', " .
            "KEY timestamp (timestamp)," .
            "KEY visitorid (visitorid)" .
            ") ENGINE=MERGE UNION=({$profile->tablename},{$profile->tablename_crawl}) CHARSET=utf8";
    }
    $db->Execute($query);


    $prequery = "CREATE OR REPLACE TABLE  " . $profile->tablename_vlength . " (length int(11), visitorid int(11), KEY vl (visitorid,length)) ENGINE=MyISAM  CHARSET=utf8";
    $db->Execute($prequery);


    $prequery = "CREATE OR REPLACE TABLE  " . $profile->tablename_tlength . " (length int(11), visitorid int(11), KEY vl (visitorid,length)) ENGINE=MyISAM  CHARSET=utf8";
    $db->Execute($prequery);


    $profile->structure_version = CURRENT_PROFILE_STRUCTURE_VERSION;
    $profile->Save();
}

function getAverage($data)
{
    if (!empty($data)) {
        return (array_sum($data) / count($data));
    } else {
        return false;
    }
}

function getStandardDev($data)
{
    if (!empty($data)) {
        $x_avg = getAverage($data);
        $n = count($data);
        foreach ($data as $k => $v) {
            $x_minus_avg[] = pow(($v - $x_avg), 2);
        }
        $sigma = array_sum($x_minus_avg);
        $lastpart = ($sigma / ($n - 1));

        $return = sqrt($lastpart);
        return $return;
    } else {
        return false;
    }
}

function getCorrelation($data)
{
    if (!empty($data)) {
        $i = 0;
        foreach ($data as $k => $v) {
            $days[] = $i++;
            $values[] = $v;
        }
        $n = count($data);
        if ($n == 1) {
            return false;
        }
        $day_avg = getAverage($days);
        $day_std = getStandardDev($days);
        $val_avg = getAverage($values);
        $val_std = getStandardDev($values);

        $x = 0;
        foreach ($data as $k => $v) {
            $x_part = ($days[$x] - $day_avg);
            $y_part = ($v - $val_avg);
            $e_part[] = ($x_part * $y_part); // stands for the mathematical E (sigma)
            $x++;
        }
        $e = array_sum($e_part); // mathematical E

        $lastpart = @($e / ($day_std * $val_std));
        $final = ($lastpart / ($n - 1));

        return $final;
    } else {
        return false;
    }
}

function getTrend($data, $keycol = "")
{
    $i = 0;
    $days = [];
    $values = [];
    foreach ($data as $k => $v) {
        $days[] = $i;
        if ($keycol != "") {
            $values[] = $v[$keycol];
        } else {
            $values[] = $v;
        }

        $i++;
    }

    if ($i == 1) {
        return false;
    }

    $day_std = getStandardDev($days);
    $val_std = getStandardDev($values);

    $r = getCorrelation($values);

    if ($day_std != 0) {
        $result = number_format((($val_std / $day_std) * $r), 2, ".", "");
    } else {
        $result = 0;
    }

    return $result;
}

function lgflush()
{
    @ob_flush();
    flush();
    @ob_end_flush();
    ob_start();
}

/**
 * @desc This function takes the data array that is used to create report tables,
 * grabs a single column from it and passes that back as a one-dimensional array
 */
function ColumnArray($data, $col)
{
    $a = [];
    foreach ($data as $row) {
        $a[] = $row[$col];
    }
    return $a;
}

/**
 * @desc This function returns the first timestamp saved in datafiles.
 * @returns timestamp
 */
function firstTimeDatafiles()
{
    global $profile;
    # Get the correct year folder.
    $dir = $profile->datamanagerDir . $profile->profilename . "/reports";
    $years = [];
    $list = glob($dir . '/*');
    if (!empty($list)) {
        foreach ($list as $file) {
            $parts = explode("/", $file);
            $years[] = end($parts);
        }
    }
    sort($years);

    if (empty($years)) {
        return 0;
    }

    # get the first timstamp from visitors per day report.
    $dir = $dir . "/" . $years[0] . "/_VISITORS_PER_DAY";
    $stamps = [];


    if (DATAFILE_METHOD == "ziparchive") {
        if (!file_exists($dir . ".zip")) {
            return 0;
        }
        $files = listzip("$dir.zip");
    } else {
        if (!file_exists($dir)) {
            return 0;
        }
        $files = glob($dir . '/*');
    }

    foreach ($files as $file) {
        $file = str_replace($dir, "", $file);
        $parts = explode(".", $file);
        if (strlen($parts[1]) > 6) {
            $d = substr($parts[1], 6, 7);
            $m = substr($parts[1], 4, -2);
            $y = substr($parts[1], 0, 4);
            $timestamp = mktime(0, 0, 0, $m, $d, $y);
            $stamps[] = $timestamp;
        }
    }
    sort($stamps);
    return (isset($stamps[0])) ? $stamps[0] : 0;
}

/**
 * @desc This function returns the first timestamp ever recorded in the software.
 * @returns timestamp
 */
function LogaholicFirstTimestamp()
{
    global $profile;
    $from_db = GetMaxDateRange($profile);
    $from_db = $from_db["from"];
    $from_datafiles = firstTimeDatafiles();


    if ($from_db < $from_datafiles || $from_datafiles == 0) {
        return $from_db;
    } else {
        return $from_datafiles;
    }
    return 0;
}

/**
 * @desc This function returns the maximum date range for a given profile
 * i.e. the oldest date in the database as 'from' and the most recent date as 'to'
 * @returns array containing from and to as keys
 */
function GetMaxDateRange($profile, $logtable = false)
{
    global $db;
    if ($logtable == true) {
        $log = "log";
    } else {
        $log = "";
    }
    $range = [];
    $q = "select timestamp from {$profile->tablename}$log order by timestamp limit 1";
    $r = $db->Execute($q);
    $data = $r->FetchRow();
    $range['from'] = $data['timestamp'] ?? '';

    $q = "select timestamp from {$profile->tablename}$log order by timestamp desc limit 1";
    $r = $db->Execute($q);
    $data = $r->FetchRow();
    $range['to'] = $data['timestamp'] ?? '';

    return $range;
}

/**
 * @desc This function will enable or disable the url sensitive import.
 */
function toggleUrlInsensitive()
{
    $sensitive = getGlobalSetting("ToggleUrlInsensitiveImport", 0);
    if ($sensitive == 1) {
        setGlobalSetting("ToggleUrlInsensitiveImport", 0);
        $sensitive = 0;
        return "Disabled Url insensitive import as default.";
    } else {
        if ($sensitive == 0) {
            setGlobalSetting("ToggleUrlInsensitiveImport", 1);
            $sensitive = 1;
            return "Enabled Url insensitive import as default.";
        }
    }
    return false;
}

/**
 * @desc This functions takes a path and makes sure we only use forward slashes and adds a slash at the end if it's not there
 */
function properSlash($path)
{
    $path = str_replace("\\", "/", $path);
    if (substr($path, -1) != "/") {
        $path .= "/";
    }
    return $path;
}

/**
 * @desc This function sorts any multidimensional array on the selected row
 */
function DataSort($data, $sort_row, $order = SORT_DESC)
{
    if (empty($data)) {
        // no data to sortdump($data);
        return $data;
    }

    foreach ($data as $key => $row) {
        $sortkey[$key] = $row[$sort_row];
    }

    if (is_array($sortkey)) {
        array_multisort($sortkey, $order, $data);
    }
    return $data;
}

/**
 * @desc Check if any maintenance is needed
 ** DEPRICATED FROM Logaholic 6
 */
function housekeeping()
{
    global $profile, $loginSystemExists, $db;

    // Does the current profile need to be updated?
    if (isset($profile)) {
        if ($profile->profileloaded) {
            // make sure the profile is of adequate version to be used.
            if ($profile->structure_version < CURRENT_PROFILE_STRUCTURE_VERSION) {
                //die('hoer');
                include_once "version_check.php";
                updateDataTableForProfile($profile);
                $profile->Load($profile->profilename); // Load the profile again to apply any changes
            }
        }
    }
}

/**
 * @desc SORT OUT THE REPORT CATEGORYS AND THE REPORTS INSIDE THE CATEGORY
 */
function sort_reports($reports)
{
    # first of all, we want to set an order for all known report categories
    $cat_order[] = "_KEY_METRIC";
    $cat_order[] = "_VISITOR_TRENDS";
    $cat_order[] = "_VISITOR_DETAILS";
    $cat_order[] = "_POPULAR_CONTENT";
    $cat_order[] = "_NAVIGATION";
    $cat_order[] = "_TRAFFIC_SOURCES";
    $cat_order[] = "_LOCATIONS";
    $cat_order[] = "_PERFORMANCE";
    $cat_order[] = "_ADVERTISING";
    $cat_order[] = "_TEST_CENTER";
    $cat_order[] = "_CLIENT_SYSTEM";
    $cat_order[] = "_TRAFFIC";
    $cat_order[] = "_PROBLEMS";
    $cat_order[] = "_SOCIAL_MEDIA";
    $cat_order[] = "_ECOMMERCE";
    $cat_order[] = "_TWITTER";
    $cat_order[] = "_FACEBOOK";
    $cat_order[] = "_OPENCART";
    $cat_order[] = "_ZENCART";
    $cat_order[] = "_INTERCOM";
    $cat_order[] = "_MAILCHIMP";
    $cat_order[] = "_TOOLS";
    $cat_order[] = "_REPORTS";
    $cat_order[] = "_FINANCIAL";

    # next, split the reports array into seperate arrays, one for each category
    $cat_reports = [];
    foreach ($reports as $key => $val) {
        $cat_reports[$val["Category"]][$key] = $val;
        // in case there are any categories we don't know about, make sure to add them to the end of the cat_order array
        if (!in_array($val["Category"], $cat_order)) {
            $cat_order[] = $val["Category"];
        }
    }

    # now, sort the reports inside each category by the order element
    foreach ($cat_reports as $cat => $report_array) {
        # since we can't be sure each report actually has an Order element, we have to verify them
        $report_array = verifyOrderReports($report_array);
        $new_reports[$cat] = DataSort($report_array, "Order", SORT_ASC);
    }

    # merge it all back together using the right category order
    $reports = [];
    foreach ($cat_order as $cat) {
        if (!empty($new_reports[$cat])) {
            $reports = array_merge($reports, $new_reports[$cat]);
        }
    }
    return $reports;
}

function verifyOrderReports($reports)
{
    # find the max value
    $max = multimax($reports, "Order");
    # now fill her up
    $verified = [];
    foreach ($reports as $key => $value) {
        if (!isset($value["Order"])) {
            $value["Order"] = $max++;
        }
        $verified[$key] = $value;
    }
    return $verified;
}

/**
 * @desc this function returns the max value from a multidemensional array, for the given key
 */
function multimax($array, $key)
{
    $max = 0;
    foreach ($array as $val) {
        if (isset($val[$key]) > $max) {
            $max = $val[$key];
        }
    }
    return $max;
}

function dump($var)
{
    echo "<pre>";
    print_r($var);
    echo "</pre>";
}

function SetupCustomDateFormat($timeformat)
{
    if (empty($timeformat)) {
        $timeformat = array(
            "format1" => "m",
            "seperator1" => "-",
            "format2" => "d",
            "seperator2" => "-",
            "format3" => "Y",
            "seperator3" => " ",
            "format4" => ""
        );
    }
    ?>
    <select class="format1" name="format1">
        <option value="d" <?php
        if ($timeformat["format1"] == "d") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (31)
        </option>
        <option value="D" <?php
        if ($timeformat["format1"] == "D") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (Mon)
        </option>
        <option value="m" <?php
        if ($timeformat["format1"] == "m") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (12)
        </option>
        <option value="M" <?php
        if ($timeformat["format1"] == "M") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (Dec)
        </option>
        <option value="Y" <?php
        if ($timeformat["format1"] == "Y") {
            echo 'selected="selected"';
        } ?>><?php
            echo _YEAR; ?></option>
        <option value="" <?php
        if ($timeformat["format1"] == "") {
            echo 'selected="selected"';
        } ?>><?php
            echo _NONE; ?></option>
    </select>
    <select class="seperator1" name="seperator1">
        <option value=" " <?php
        if ($timeformat["seperator1"] == " ") {
            echo 'selected="selected"';
        } ?>></option>
        <option value="-" <?php
        if ($timeformat["seperator1"] == "-") {
            echo 'selected="selected"';
        } ?>>-
        </option>
        <option value="/" <?php
        if ($timeformat["seperator1"] == "/") {
            echo 'selected="selected"';
        } ?>>/
        </option>
        <option value="," <?php
        if ($timeformat["seperator1"] == ",") {
            echo 'selected="selected"';
        } ?>>,
        </option>
    </select>
    <select class="format2" name="format2">
        <option value="d" <?php
        if ($timeformat["format2"] == "d") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (31)
        </option>
        <option value="D" <?php
        if ($timeformat["format2"] == "D") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (Mon)
        </option>
        <option value="m" <?php
        if ($timeformat["format2"] == "m") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (12)
        </option>
        <option value="M" <?php
        if ($timeformat["format2"] == "M") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (Dec)
        </option>
        <option value="Y" <?php
        if ($timeformat["format2"] == "Y") {
            echo 'selected="selected"';
        } ?>><?php
            echo _YEAR; ?></option>
        <option value="" <?php
        if ($timeformat["format2"] == "") {
            echo 'selected="selected"';
        } ?>><?php
            echo _NONE; ?></option>
    </select>
    <select class="seperator2" name="seperator2">
        <option value=" " <?php
        if ($timeformat["seperator2"] == " ") {
            echo 'selected="selected"';
        } ?>></option>
        <option value="-" <?php
        if ($timeformat["seperator2"] == "-") {
            echo 'selected="selected"';
        } ?>>-
        </option>
        <option value="/" <?php
        if ($timeformat["seperator2"] == "/") {
            echo 'selected="selected"';
        } ?>>/
        </option>
        <option value="," <?php
        if ($timeformat["seperator2"] == ",") {
            echo 'selected="selected"';
        } ?>>,
        </option>
    </select>
    <select class="format3" name="format3">
        <option value="d" <?php
        if ($timeformat["format3"] == "d") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (31)
        </option>
        <option value="D" <?php
        if ($timeformat["format3"] == "D") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (Mon)
        </option>
        <option value="m" <?php
        if ($timeformat["format3"] == "m") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (12)
        </option>
        <option value="M" <?php
        if ($timeformat["format3"] == "M") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (Dec)
        </option>
        <option value="Y" <?php
        if ($timeformat["format3"] == "Y") {
            echo 'selected="selected"';
        } ?>><?php
            echo _YEAR; ?></option>
        <option value="" <?php
        if ($timeformat["format3"] == "") {
            echo 'selected="selected"';
        } ?>><?php
            echo _NONE; ?></option>
    </select>
    <select class="seperator3" name="seperator3">
        <option value=" " <?php
        if ($timeformat["seperator3"] == " ") {
            echo 'selected="selected"';
        } ?>></option>
        <option value="-" <?php
        if ($timeformat["seperator3"] == "-") {
            echo 'selected="selected"';
        } ?>>-
        </option>
        <option value="/" <?php
        if ($timeformat["seperator3"] == "/") {
            echo 'selected="selected"';
        } ?>>/
        </option>
        <option value="," <?php
        if ($timeformat["seperator3"] == ",") {
            echo 'selected="selected"';
        } ?>>,
        </option>
    </select>
    <select class="format4" name="format4">
        <option value="d" <?php
        if ($timeformat["format4"] == "d") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (31)
        </option>
        <option value="D" <?php
        if ($timeformat["format4"] == "D") {
            echo 'selected="selected"';
        } ?>><?php
            echo _DAY; ?> (Mon)
        </option>
        <option value="m" <?php
        if ($timeformat["format4"] == "m") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (12)
        </option>
        <option value="M" <?php
        if ($timeformat["format4"] == "M") {
            echo 'selected="selected"';
        } ?>><?php
            echo _MONTH; ?> (Dec)
        </option>
        <option value="Y" <?php
        if ($timeformat["format4"] == "Y") {
            echo 'selected="selected"';
        } ?>><?php
            echo _YEAR; ?></option>
        <option value="" <?php
        if ($timeformat["format4"] == "") {
            echo 'selected="selected"';
        } ?>><?php
            echo _NONE; ?></option>
    </select>
    <?php
}

function GetCustomDateFormat($case = "PHP", $returnasarray = false)
{
    global $dateFormat, $profile;
    # returns a date string
    if (!isset($profile->profilename)) {
        $date = getGlobalSetting("profileDateFormat", $dateFormat);
        $date = json_decode($date, true);
    } else {
        $date = $profile->dateFormat;
    }

    $formats = array(
        "PHP" => array("d" => "d", "D" => "D", "m" => "m", "M" => "M", "Y" => "Y"),
        "JS" => array("d" => "DD", "D" => "DDD", "m" => "MM", "M" => "MMM", "Y" => "YYYY"),
        "D3" => array("d" => "%d", "D" => "%a", "m" => "%m", "M" => "%b", "Y" => "%Y")
    );
    $format = [];


    foreach ($date as $k => $v) {
        if (!empty($formats[$case][$v])) {
            $format[] = $formats[$case][$v];
        } else {
            $format[] = $v;
        }
    }

    if ($returnasarray) {
        return $format;
    } else {
        return trim(implode($format));
    }
}


# recursively remove a directory
function rrmdir($dir)
{
    if (!file_exists($dir)) {
        return;
    }
    $list = glob($dir . '/*');
    if (!empty($list)) {
        foreach ($list as $file) {
            if (is_dir($file)) {
                rrmdir($file);
            } else {
                unlink($file);
            }
        }
    }
    if (is_dir($dir)) {
        rmdir($dir);
    }
}

# Set chmod
function set_permissions($file)
{
    if (@_LOGAHOLIC_EDITION == 4 || LOGAHOLIC_BASE_EDITION == "cPanel Edition") {
        return true;
    }

    if (!file_exists($file)) {
        return false;
    }

    if (@chmod($file, 0777) === false) {
        //echoWarning($file);
        return false;
    }
    if (function_exists('posix_geteuid')) {
        clearstatcache();
        $u = posix_geteuid();
        if ($u == @fileowner($file) || $u == 0) {
            return true;
        }
    }
    return true;
}

function DeleteProfileFiles($profile)
{
    if (!empty($profile->profilename)) {
        rrmdir("{$profile->datamanagerDir}{$profile->profilename}");
        return "Succesfully deleted all the Profile files from the data directory. ";
    }
}

function DeleteDataFiles($profile, $from = '', $to = '')
{
    global $reports;

    $dir = "{$profile->datamanagerDir}{$profile->profilename}/reports";
    if (empty($from) && empty($to)) {
        rrmdir($dir);
        return "Succesfully deleted all the datafiles. ";
    }

    $files = [];
    $end_year = date("Y", $to);

    for ($start_year = date("Y", $from); $start_year <= $end_year; $start_year++) {
        if (DATAFILE_METHOD == "ziparchive") {
            foreach (glob("$dir/$start_year/*.zip") as $zfile) {
                $files = array_merge($files, listzip($zfile, "\/.*"));
            }
        } else {
            $files = glob("$dir/$start_year/*/*");
        }

        foreach ($files as $datafile) {
            $full_path = $datafile;
            $datafile = explode("/", $datafile);
            $datafile = end($datafile);

            $parts = explode(".", $datafile);
            $date = $parts[1];

            #check if this is a day or a month file.
            if (strlen($date) == 8) {
                #this is a day file.
                $stamp = mktime(
                    12,
                    0,
                    0,
                    substr($date, 4, -2),
                    substr($date, 6, 7),
                    $start_year
                ); // use mid day to avoid any possible timeszone crap
            } else {
                if (strlen($date) == 6) {
                    #this is a month file.
                    //$del[] = $full_path;
                    $stamp = mktime(0, 0, 0, substr($date, -2), 01, $start_year);
                    //we need to delete month files even if the delete range is only one day. If it affects the month, ditch it
                    if (date("mY", $from) == date("mY", $stamp)) {
                        $stamp = $from;
                    }
                    if (date("mY", $to) == date("mY", $stamp)) {
                        $stamp = $to;
                    }
                }
            }
            if (isset($stamp)) {
                if ($stamp >= $from && $stamp <= $to) {
                    if (DATAFILE_METHOD == "ziparchive") {
                        # remove file from zip.
                        $zip_file = "$dir/$start_year/{$parts[0]}.zip";
                        $zip = new ZipArchive;

                        if ($zip->open($zip_file) === true) {
                            @$zip->deleteName("/$datafile");
                            @$zip->close();
                        }
                    } else {
                        unlink($full_path);
                    }
                }
            }
        }
    }

    return "Succesfully deleted the datafiles.";
}

function Post($url, $data)
{
    # Create a stream
    $opts = array(
        'http' => array(
            'method' => "POST",
            'header' => 'Content-Type: application/x-www-form-urlencoded',
            'content' => http_build_query($data)
        )
    );

    $context = stream_context_create($opts);
    # Open the file using the HTTP headers set above
    $file = file_get_contents($url, false, $context);
    return $file;
}

# check if the keys are activated
function check_keys($table)
{
    global $db;
    $check = $db->Execute("SHOW KEYS FROM " . $table);
    while ($row = $check->fetchRow()) {
        if ($row["Comment"] == "disabled") {
            $db->Execute("ALTER TABLE {$table} ENABLE KEYS");
        }
    }
}

function CheckIfTableExists($table)
{
    global $db;
    $R = $db->getRow(
        "SELECT COUNT(*) FROM information_schema.TABLES  WHERE TABLE_SCHEMA ='" . $db->database . "' AND TABLE_NAME ='" . $table . "'"
    );
    if (0 !== $R[0]) {
        return true;
    } else {
        return false;
    }
}

function CheckIfIndexExists($table, $index)
{
    global $db;
    $check = $db->Execute("SHOW CREATE OR REPLACE TABLE  " . $table);
    $row = $check->fetchRow();
    $statement = $row["CREATE OR REPLACE TABLE "];
    $index = "KEY `" . $index;
    if (strpos($statement, $index) === false) {
        return false;
    } else {
        return true;
    }
}

# provides a generic access check for the system that can be used in any component or include to ensure any unauthorized access attempts are stopped right away
function AccessCheck()
{
    global $validUserRequired, $session, $profile, $conf, $editconf;

    # check if we are logged in
    if (LoggedIn() === false) {
        die("denied");
    }

    # if there is no validUserRequired, access control is not handled by Logaholic so we let them pass
    if ($validUserRequired) {
        # check if we are not an admin
        if (!$session->isAdmin()) {
            # if we have a profile, check if this user may access it (this check is also performed in siteprofile)
            # but we are going to check this here on multiple levels just in case

            if (isset($conf) && isset($editconf)) {
                # this situation should not occur to begin with
                die("denied");
            }

            if (isset($conf)) {
                $checkprofile = $conf;
            }

            if (isset($editconf)) {
                $checkprofile = $editconf;
            }

            if (isset($profile->profilename)) {
                # if the profileobject already exists somewhow, this is the one we will check
                $checkprofile = $profile->profilename;
            }

            if (isset($checkprofile)) {
                if ($session->canAddProfiles() && $checkprofile == "newcnf") {
                    # user is allowd to create a new profile, so let them pass
                } else {
                    if (!in_array($checkprofile, $session->user_profiles) && !$session->allProfiles) {
                        die("denied");
                    }
                }
            }
        }
    }
}

function LoggedIn()
{
    global $validUserRequired, $session;

    if (!$validUserRequired) {
        # we are always 'logged in' if we don't have to log in at all
        return true;
    }

    if (isset($session) && $session->logged_in) {
        return true;
    }

    return false;
}

# this function will sanitize any input in $_GET, $_POST and $_REQUEST
function SanitizeInput()
{
    $ignore_keys = array('subscriptions', 'reportsdata', 'panea', 'paneb');

    foreach ($_GET as $k => $v) {
        if (in_array($k, $ignore_keys)) {
            continue;
        }
        if (is_array($v)) {
            $_GET[$k] = filter_var_array($v, FILTER_SANITIZE_STRING);
        } else {
            $_GET[$k] = filter_var($v, FILTER_SANITIZE_STRING);
        }
    }
    foreach ($_POST as $k => $v) {
        if (in_array($k, $ignore_keys)) {
            continue;
        }
        if ($k !== 'saveDashboard') {
            if (is_array($v)) {
                $_POST[$k] = filter_var_array($v, FILTER_SANITIZE_STRING);
            } else {
                $_POST[$k] = filter_var($v, FILTER_SANITIZE_STRING);
            }
        } else {
            $_POST[$k] = strip_tags($v);
        }
    }
    foreach ($_REQUEST as $k => $v) {
        if (in_array($k, $ignore_keys)) {
            continue;
        }
        if ($k !== 'saveDashboard') {
            if (is_array($v)) {
                $_REQUEST[$k] = filter_var_array($v, FILTER_SANITIZE_STRING);
            } else {
                $_REQUEST[$k] = filter_var($v, FILTER_SANITIZE_STRING);
            }
        } else {
            $_REQUEST[$k] = strip_tags($v);
        }
    }
}


function ConvertDataFilesToZip($profile)
{
    $zip = new ZipArchive();
    $path = $profile->datamanagerDir . $profile->profilename . "/reports/";

    # Convert all years..
    $dirs = glob($path . "*/*", GLOB_ONLYDIR);
    foreach ($dirs as $dir) {
        $paths = explode("/", $dir);
        $year = $paths[(count($paths) - 2)];
        $report = end($paths);

        $ret = $zip->open($path . $year . "/$report.zip", ZipArchive::CREATE);
        if ($ret !== true) {
            echoWarning('Failed with code %d', $ret);
        } else {
            $options = array('add_path' => '/', 'remove_all_path' => true);
            $zip->addGlob("$path$year/$report/*", GLOB_BRACE, $options);
            $zip->close();
            set_permissions($path . $year . "/$report.zip");
        }
        rrmdir($dir);
    }
}

function listzip($zipfile, $pattern = "")
{
    //echo $zipfile;
    $res = [];
    if (!file_exists($zipfile)) {
        return $res;
    }
    $zip = new zipArchive;
    if ($zip->open($zipfile) == true) {
        $i = 0;
        while ($info = $zip->statIndex($i)) {
            if (preg_match("/$pattern/i", $info["name"])) {
                $res[] = $info["name"];
            }
            $i++;
        }
    }
    return $res;
}

/*
** Reset the data columns in the profiles table
*/
function ResetProfileSettings($profile)
{
    global $db;
    $profile->update_status = "ready";

    $profile->max_db_timestamp = 0;
    $profile->last_update_finished = 0;
    $profile->firstRequestTimeEver = 0;
    $profile->lastReportUpdate = 0;
    $profile->usage = "[]";

    $profile->sessioncounter = 0;
    $profile->filehistory = "";
    $profile->Save();
}

/*
** are we using subscriptions ?
*/
function CheckForSubscriptionsUsage()
{
    global $db;

    $r = $db->getRow(
        "SELECT COUNT(*) FROM information_schema.TABLES 
         WHERE TABLE_SCHEMA ='" . $db->database . "'
         AND TABLE_NAME ='" . TBL_SUBSCRIPTIONS . "'"
    );
    if ($r[0] !== false) {
        $s = $db->execute(
            "SELECT COUNT(*) FROM information_schema.TABLES 
         WHERE TABLE_SCHEMA ='" . $db->database . "'
         AND TABLE_NAME ='" . TBL_SUBSCRIPTIONS . "'"
        );
        $row = $s->fetchRow();
        if (empty($row)) {
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}

/*
**
*/
function NewSubscriptionLogEntry($message, $sub_name = 0, $price = 0, $username = "", $timestamp = null)
{
    global $db, $session, $validUserRequired;

    # Do we have a user?
    if (!$validUserRequired && empty($username)) {
        return false;
    }

    # Does this even exists?
    if (!CheckIfTableExists(TBL__SUBSCRIPTIONS_USERLOG)) {
        return false;
    }

    # if there is no timestamp given set it to current time
    if ($timestamp === null) {
        $timestamp = time();
    }

    # if there is no user_id given set it to current logged user
    if (empty($username)) {
        $username = $session->username;
    }

    $q = "INSERT INTO " . TBL__SUBSCRIPTIONS_USERLOG . " (`username`,`name`,`price`,`timestamp`,`message`) VALUES ( ?, ? , ? , ? , ? )";
    $db->Execute($q, array($username, $sub_name, $price, $timestamp, $message));
}

function CheckSubscriptionOption($key, $value = "")
{
    global $session;

    if (empty($session->subscription)) {
        return false; # If there is no subscription
    } else {
        if (empty($session->subscription[$key])) {
            return false; # If the option is not set
        } else {
            if ($value != "" && $session->subscription[$key] != $value) {
                return false; # If the options value is not equal to the one asked
            }
        }
    }

    # everything is ok ;)
    return true;
}

function LogaDate($format, $date, $type = "TIMESTAMP")
{
    global $lang, $profile;

    # No format given
    if (empty($format)) {
        return false;
    }

    # Are we on windows or Linux?
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        $sys = "w";
    } else {
        $sys = "l";
    }

    $set = array(
        "english" => array("w" => "eng", "l" => "en_US.UTF-8")
    ,
        "french" => array("w" => "fra", "l" => "fr_FR.UTF-8")
    ,
        "german" => array("w" => "deu", "l" => "de_DE.UTF-8")
    ,
        "dutch" => array("w" => "nld", "l" => "nl_NL.UTF-8")
    ,
        "italian" => array("w" => "ita", "l" => "it_IT.UTF-8")
    ,
        "spanish" => array("w" => "esp", "l" => "es_ES.UTF-8")
    ,
        "portuguese" => array("w" => "ptg", "l" => "pt_PT.UTF-8")
    );
    # First convert with english to timestamp
    setlocale(LC_TIME, $set["english"][$sys]);

    if ($type == "TIMESTAMP") {
        $time = $date;
    } else {
        $time = strtotime($date);
    }

    setlocale(LC_TIME, $set[$lang][$sys]);

    $new_format = "";
    foreach ($format as $k => $v) {
        # We have a format here
        if (strpos($k, "seperator") === false) {
            switch ($v) {
                case 'd':
                    $new_format .= "%d";
                    break;
                case 'D':
                    $new_format .= "%a";
                    break;
                case 'm':
                    $new_format .= "%m";
                    break;
                case 'M':
                    $new_format .= "%b";
                    break;
                case 'Y':
                    $new_format .= "%Y";
                    break;
                case 'F':
                    $new_format .= "%B";
                    break;
                case 'l':
                    $new_format .= "%A";
                    break;
                case 'H':
                    $new_format .= "%H";
                    break;
                case 'i':
                    $new_format .= "%i";
                    break;
                case 's':
                    $new_format .= "%s";
                    break;
            }
        } else {
            # Just a seperator
            $new_format .= $v;
        }
    }

    $new_date = strftime($new_format, $time);
    if ($sys == "w") {
        $new_date = utf8_encode($new_date);
    }

    setlocale(LC_TIME, $set["english"][$sys]);
    return trim($new_date);
}

function LogdateToStamp($format, $logtime, $tzone = "")
{
    $version = (int)str_replace(".", "", phpversion());
    $version = substr($version, 0, 3);

    if ($version >= 530) {
        if (empty($tzone)) {
            $date = DateTime::createFromFormat($format, $logtime);
        } else {
            $date = DateTime::createFromFormat($format, $logtime, $tzone);
        }
        if (!$date) {
            return false;
        } else {
            return $date->getTimestamp();
        }
    } else {
        if (empty($tzone)) {
            $logtime = str_replace("/", " ", substr($logtime, 0, 11)) . " " . substr($logtime, 12, 8);
        }
        return strtotime(trim($logtime));
    }
}

function IsValidFQDN($domain_name)
{
    return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domain_name) //valid chars check
        && preg_match("/^.{1,253}$/", $domain_name) //overall length check
        && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); //length of each label
}

function SwitchSystemUser($user = "root")
{
    $userinfo = posix_getpwuid(posix_getuid());
    if ($userinfo['name'] != $user) {
        $newuser = posix_getpwnam($user);
        if (posix_setgid($newuser['gid']) == true) {
            if (posix_setuid($newuser['uid']) == true) {
                # Ok
            }
        } else {
            # Failed
        }
    }
}

/**
 * @desc This function return the list of all the profiles of a user
 */
if (!function_exists('getProfileList')) { # it is possible it is predeclared in the API
    function getProfileList($username)
    {
        global $db;
        $query = @$db->Execute(
            "select profiles from `" . TBL_USERS . "` where username=" . $db->Quote($username)
        ) or Output("An error occurred:" . $db->ErrorMsg(), true);
        if ($query->NumRows() == 0) {
            // Output("An error occurred: User $username not found",true);
            return false;
        }
        $q = $query->FetchRow();
        return $q['profiles'];
    }
}

if (!function_exists('Output')) { # the API has it's own version
    function Output($str, $bool)
    {
        echo $str;
    }
}

/**
 * @desc This function saves the profilelist of a user
 */
if (!function_exists('saveProfileList')) { # it is possible it is predeclared in the API
    function saveProfileList($username, $profile_list)
    {
        global $db;

        $q = "UPDATE " . TBL_USERS . " SET profiles=" . $db->Quote($profile_list) . " WHERE username=" . $db->Quote(
                $username
            );
        @$db->Execute($q) or Output("An error occurred: " . $db->ErrorMsg(), true);
    }
}

/**
 * @desc This function returns the users that have access to a given profile
 */
if (!function_exists('GetUsersForProfile')) { # it is possible it is predeclared in the API
    function GetUsersForProfile($profilename)
    {
        global $db;
        $users = [];
        $q = $db->Execute(
            "select username from " . TBL_USERS . " where (profiles=" . $db->Quote(
                $profilename
            ) . " or profiles like " . $db->Quote("$profilename,%") . " or profiles like " . $db->Quote(
                "%,$profilename,%"
            ) . " or profiles like " . $db->Quote("%,$profilename") . ")"
        );
        while ($data = $q->FetchRow()) {
            if ($data['username']) {
                $users[] = $data['username'];
            }
        }
        return implode(",", $users);
    }
}

/**
 * @desc This function deletes the profile from all users
 */
if (!function_exists('DeleteProfileFromUsers')) { # it is possible it is predeclared in the API
    function DeleteProfileFromUsers($profilename)
    {
        $users = explode(",", GetUsersForProfile($profilename));

        foreach ($users as $user) {
            $plist = getProfileList($user);
            $plist_arr = explode(',', $plist);
            $plist_arr_keep = [];
            foreach ($plist_arr as $site) {
                $site = trim($site);
                if ($site && $site != $profilename) {
                    $plist_arr_keep[] = $site;
                }
            }
            $plist = (count($plist_arr_keep)) ? implode(',', $plist_arr_keep) : '';
            saveProfileList($user, $plist);
        }
    }
}

if (!function_exists('Output')) { # it is possible it is predeclared in the API
    function Output($str)
    {
        echo $str;
    }
}

function Stream($string)
{
    # Stream needs to do \n\n after echoing a data or it wont give output.. It's a must!
    echo "data: " . $string . "\n\n";
    //ob_flush();
    flush();
}

function CheckUserMetaData($userid, $userdata)
{
    global $db;
    $userdata = json_decode($userdata, true);

    $r = $db->Execute("SELECT metadata FROM " . TBL_USERS . " WHERE userid = ?", array($userid));
    $row = $r->fetchRow();
    $previous = json_decode($row['metadata'], true);
    if (!empty($previous)) {
        foreach ($previous as $k => $v) {
            if (!isset($userdata[$k])) {
                $userdata[$k] = $v;
            }
        }
    }

    return json_encode($userdata);
}

function print_gzipped_output()
{
    $HTTP_ACCEPT_ENCODING = @$_SERVER["HTTP_ACCEPT_ENCODING"];
    //exit("Hier".$HTTP_ACCEPT_ENCODING);
    if (headers_sent()) {
        $encoding = false;
    } else {
        if (strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false) {
            $encoding = 'x-gzip';
        } else {
            if (strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false) {
                $encoding = 'gzip';
            } else {
                $encoding = false;
            }
        }
    }

    if ($encoding) {
        $contents = ob_get_clean();
        $_temp1 = strlen($contents);
        if ($_temp1 < 2048)    // no need to waste resources in compressing very little data
        {
            print($contents);
        } else {
            header('Content-Encoding: ' . $encoding);
            print("\x1f\x8b\x08\x00\x00\x00\x00\x00");
            $contents = gzcompress($contents, 9);
            $contents = substr($contents, 0, $_temp1);
            print($contents);
        }
    } else {
        ob_end_flush();
    }
}

?>
