<?php
if (file_exists(__DIR__ .'/config/config.php')){
    require_once __DIR__ .'/config/config.php';
}
require_once __DIR__ .'/lib/dbwrapper.php';

session_start();

function dbconn(){
    //return dbw_connect('mysqli','localhost','proyecto','root','mysql');
    if (!defined('SGBD')){
		die('You can\'t establish a connection without a config file.');
	}
	if (SGBD == 'sqlite3'){
        return dbw_connect('sqlite3',__DIR__ .'/'.DBSERVER);
    }else if (SGBD == 'mysqli'){
        return dbw_connect('mysqli',DBSERVER,DBDATABASE,DBUSER,DBPASS);
    }
}

function showUptime($str) {
    $num   = floatval($str);
    $secs  = $num % 60;
    $num   = (int)($num / 60);
    $mins  = $num % 60;
    $num   = (int)($num / 60);
    $hours = $num % 24;
    $num   = (int)($num / 24);
    $days  = $num;

    return $days . " días, " . sprintf('%02d', $hours) . ":" . sprintf('%02d', $mins) . ":" . sprintf('%02d', $secs);
}

/** Transform bytes to an human readable text **/
function bytesToHuman($int,$round = 2, $onlynumber = 0,$returnin = NULL){
    if (!is_numeric($int)){
        return NULL;
    }
    $ret = ($int / 1024/1024);
    if ($onlynumber){
        if ($returnin == 'GB'){
            return round($ret / 1024,$round); //Return in GB
        }else{
            return round($ret,$round); //Return in MB, ever, and without text, for charts
        }
        
    }else{
        if ($ret > 1024*10){ //Long number
            return round(($ret / 1024),$round).'GB';
        }else{
            return round($ret,$round).'MB';
        }
    }

}


function percent($parc,$total){
	if ($total){
        return round(($parc/$total)*100,2);
	}else{
		return 'DIV BY ZERO';
	}
}

/** Know at what groups belong a Server **/
function arrayGroupsOfServ($ID_SERV) {
	$db_conn = dbconn();
	$list = dbw_query($db_conn,"SELECT * FROM S_INGROUP WHERE ID_SERV='$ID_SERV'");
	
	$ret = NULL; //Empty var
	while ($line = dbw_fetch_array($db_conn,$list)){
		$ID_G = $line['ID_G'];
        $namegrp = dbw_query_fetch_array($db_conn,"SELECT `Name` FROM GROUPS WHERE ID_G='$ID_G'")[0];
        $ret[] = array('ID_G' => $ID_G,'Name' => $namegrp);
    }
	return $ret;
}

/** Return last hdd status as string **/
function getFastHddStats($ID_SERV){
    $db_conn = dbconn();
    $sql = dbw_query($db_conn,"SELECT * FROM S_HDDSTAT WHERE ID_SERV='$ID_SERV' AND `Timestamp` = (SELECT MAX(`Timestamp`) FROM S_HDDSTAT WHERE ID_SERV='$ID_SERV')");
    $ret = NULL; //Empty var

    while ($line = dbw_fetch_array($db_conn,$sql)){
        $line['Usedspace'] = $line['Space']-$line['Freespace'];
        $ret .= $line['HDD']. ' - ' . percent($line['Usedspace'],$line['Space']).'% ocupado ('.bytesToHuman($line['Usedspace']).'/'.bytesToHuman($line['Space']).')<br>';
    }
    return $ret;  //HDD1 - % ocupado (NUsedGb/NTotalGb)<br>Other..
}


/** This function returns, from a ID_SERV and a time, an array of every HDD and free space **/
function getHistoricHddStats($ID_SERV,$backto = (24*3600)){ //Backto one day by default
    $db_conn = dbconn();

    $timeini = time() - $backto;
    $lines = dbw_query($db_conn,"SELECT * FROM S_HDDSTAT WHERE ID_SERV='$ID_SERV' AND `Timestamp` > '$timeini' ORDER BY `Timestamp` DESC");

    $ret = array();

    $between = (time() - $timeini) / 100; //Tiempo entre el actual y desde el que empieza, partido de 100, para que el máximo sean 100 tramos.


    while ($line = dbw_fetch_array($db_conn,$lines)){
        if (!isset($lasttimestamp[$line['HDD']]) || abs($lasttimestamp[$line['HDD']] - $line['Timestamp']) > $between ){ //Calcula que exista, y que el tiempo sea mayor que el tramo dicho
            $ret[$line['HDD']][] = array('Timestamp' => $line['Timestamp'],'HumanTimestamp' => timestampToHuman($line['Timestamp']), 'Space' => bytesToHuman($line['Space'],2,1,'GB') , 'Freespace' =>bytesToHuman($line['Freespace'],2,1,'GB'));
            $lasttimestamp[$line['HDD']] = $line['Timestamp'];
        }
        
    }

    foreach ($ret as $key => $value){ //Order timestamps ASC
        $ret[$key] = array_reverse($ret[$key]);

    }
    return $ret; //Array ret[HDD1][0](Timestamp,HumanTimestamp,Space,Freespace)-[1](Timestamp,HumanTimestamp,Space,Freespace)-....

}

/** Sents a command by SSH to server and returns result **/
function commandbyssh($host,$port,$user,$pass,$cmd){
	if ((int)$port == 0){
		$port = 22;
	}
    require_once __DIR__ .'/lib/phpseclib-2.0/phpseclib/bootstrap.php';
    $ssh = new phpseclib\Net\SSH2($host,$port);
    if (!$ssh->login($user, $pass)) {
		if (DEBUG) {echo "ERROR AL CONECTAR|".$user;}
       return NULL;

    }else{
        return $ssh->exec($cmd);
    }
}

//This function is an alias to Twig render, with "standard args" added
function renderPage($page,$array = array()){
    require 'lib/loadTwig.php';
    global $namepage; //Todo edit this.
    if (isset($_SESSION['user'])){$allarray['user'] = $_SESSION['user'];}
    $allarray['namepage'] = $namepage;
    if (isset($_SESSION['MSG'])){$allarray['msg'] = $_SESSION['MSG'];$_SESSION['MSG'] = NULL;} //Var for showing messages
    if (isset($_SESSION['MSG_E'])){$allarray['msg_e'] = $_SESSION['MSG_E'];$_SESSION['MSG_E'] = NULL;} //Var for showing messages
    if (isset($_SESSION['MSG_I'])){$allarray['msg_i'] = $_SESSION['MSG_I'];$_SESSION['MSG_I'] = NULL;} //Var for showing messages
    $allarray['POST'] = $_POST; //For forms
    foreach ($array as $key => $value) {
		$allarray[$key] = $value;
    }
    
	if (defined('SGBD')){	
		$allarray['alerts'] = getAlerts();
    }

    $allarray['sys']['intervalts'] = (30*60);
	echo $twig->render($page, $allarray);
}

function ping($ip, $timeout = 2,$rTimes = 2) {

    /* ICMP ping packet with a pre-calculated checksum */
	$retry = 0;
	while ($retry < $rTimes){ //Retry rTimes times if fail
		//Create ICMP socket and see if works
		$package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost";
        $socket  = socket_create(AF_INET, SOCK_RAW, 1);
        if ($socket == FALSE){ //If not works, please don't continue.
            break;
        }
		socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
		socket_connect($socket, $ip, null);

		$ts = microtime(true);
		socket_send($socket, $package, strLen($package), 0);
		if (socket_read($socket, 255))
				$result = microtime(true) - $ts;
		else    $result = -1; // Never returns, host off or didn't answer
		socket_close($socket);

		if ($result != -1){
			return round($result,3);
		}else{
			$retry++;
		}
    }
    return -1; //If in rTimes doesn't connect, return error
}

function encodePassword($str,$IV){
    //$IV = randomString(16); //For secure encoding
    return base64_encode(openssl_encrypt($str, 'aes-256-ctr', ENCPASSWD, false, $IV));
}

function decodePassword($str,$IV){
    //$IV = randomString(16); //For secure encoding
    return openssl_decrypt(base64_decode($str), 'aes-256-ctr', ENCPASSWD, false, $IV);
}

/** This function returns all data from server in array, do not overuse this function **/
function serverData($ID_SERV){
    $db_conn = dbconn();

    //For HDD Stats
    if (isset($_GET['backto']) && (int)$_GET['backto'])   {
        $backto = (int)$_GET['backto'] * 24*3600;
    }else if (isset($_POST['backto']) && (int)$_POST['backto'])   {
        $backto = (int)$_POST['backto'] * 24*3600;
    }else{
        $backto = 24*3600; //Un día
    }

    $serv = dbw_query_fetch_array($db_conn,"SELECT * FROM SERVERS WHERE ID_SERV='$ID_SERV'");

    if (!$serv){ //No server with this ID? Return null
        return NULL;
    }

    $servEnabled = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM S_SERVICES WHERE ID_SERV='$serv[ID_SERV]' AND `Enabled`=1")[0];
    $servDisabled = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM S_SERVICES WHERE ID_SERV='$serv[ID_SERV]' AND `Enabled`=0")[0];
    
    if ($servEnabled){
        $servActive = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM S_SERVICES WHERE `Status`=1 AND ID_SERV='$serv[ID_SERV]' AND `Enabled`=1")[0];
        $servInactive = $servEnabled - $servActive;
    }else{
        $servActive = 0;
        $servEnabled = 0;
    }

    $sql = dbw_query($db_conn,"SELECT * FROM S_INGROUP WHERE ID_SERV='$ID_SERV'");
    $listidg = array();
    while ($line = dbw_fetch_array($db_conn,$sql)){
        $listidg[$line['ID_G']] = array(
            'ID_G' => $line['ID_G'],
            'Name' => nameFromID_G($line['ID_G'])
        );
    }
    $ping = dbw_query_fetch_array($db_conn,"SELECT `Value` FROM S_HISTPING WHERE ID_SERV='$serv[ID_SERV]' ORDER BY `Timestamp` DESC LIMIT 1");
    if ($ping != NULL){
        $ping = $ping[0];
    }else{
        $ping = "";
    }

    list($serv['Freeram'],$serv['Detram']) = dbw_query_fetch_array($db_conn,"SELECT `Freeram`,`Detram` FROM S_HISTRAM WHERE ID_SERV='$ID_SERV' ORDER BY `Timestamp` DESC LIMIT 1");
    return array(
        'ID_SERV'   => $serv['ID_SERV'],
        'Name'      => trim($serv['Name']),
        'Description' => trim($serv['Description']),
        'IP'        => trim($serv['IP']),
        'SO'        => trim($serv['SO']),
        'Version'   => $serv['Version'],
        'InGroups'  => $listidg,
        'Online'    => $serv['Online'],
        'Enabled'   => $serv['Enabled'],
        'Ping'      => $ping,
        'BadCreds'  => $serv['BadCreds'],
        'Uptime'    => showUptime($serv['Uptime']),
        'Freeram'   => bytesToHuman($serv['Freeram']),
		'Detram'   => bytesToHuman($serv['Detram']),
		'Usedram'   => bytesToHuman($serv['Detram']-$serv['Freeram']),
        'HDDFastStats' => getFastHddStats($serv['ID_SERV']),
        'HDDData'   => getHistoricHddStats($serv['ID_SERV'],$backto),
        'STotal'    => ($servEnabled + $servDisabled),
        'SEnabled'  => $servEnabled,
        'SDisabled' => $servDisabled,
        'SActive'   => $servActive,
        'SInactive' => ($servEnabled - $servActive),
		'LastCheck' => $serv['LastCheck'],
        'AlertHDD' => hasalert($ID_SERV,'HDD')
    );
}

function getPerm($perm){
    if ($_SESSION['user'][$perm] ||$_SESSION['user']['PE_admin']){ //Admin has all rights
        return true;
    }else{
        return false;
    }
}

function showdeb($str){
    if (DEBUG){
        //echo "<p>Debug: ".$str."</p>";
        sendmsg('info','Debug: '.var_dump($str));
    }
    
}


function cleanData($str,$raw = 0){
    if (!is_array($str)){
        return htmlentities(trim($str),ENT_QUOTES);
    }else{
        return $str; //Arrays not clean yet
    }
    
}


function nameFromID_G($ID_G){
    $ID_G = (int)$ID_G;
    return dbw_query_fetch_array(dbconn(),"SELECT `Name` FROM GROUPS WHERE ID_G='$ID_G'")[0];
}

//Send msg to twig template to see it. Its an array
function sendmsg($type,$str){
    switch ($type){
        case 'ok':
            $_SESSION['MSG'][] = $str;
        break;
        case 'error':
            $_SESSION['MSG_E'][] = $str;
        break;
        case 'info':
            $_SESSION['MSG_I'][] = $str;
        break;
        case 'debug':
            $_SESSION['MSG_I'][] = 'Debug: '.$str;
        break;
    }
}

function RandomString($length)
{
        //https://phpes.wordpress.com/2007/06/12/generador-de-una-cadena-aleatoria/
    $source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
    if($length>0){
        $rstr = "";
        $source = str_split($source,1);
        for($i=1; $i<=$length; $i++){
            mt_srand((double)microtime() * 1000000);
            $num = mt_rand(1,count($source));
            $rstr .= $source[$num-1];
        }

    }
    return $rstr;
}

function removeEmptyLines($arr){
	for ($x = 0;$x < count($arr);$x++){
		if (strlen($arr[$x]) == 0 ||!$arr[$x]){
			array_splice($arr,$x,1);
		}
	}
	return $arr;
}

function enviarcorreo($ID_SERV,$type,$msg){
    $db_conn = dbconn();
    dbw_query($db_conn,"INSERT INTO MAIL (ID_SERV,`Type`,Msg) VALUES ('$ID_SERV','$type','$msg')");
    $lastid = dbw_last_id($db_conn);
    $mails = listaMails();
	if ($mails != NULL){
		foreach($mails as $mail){
			mail ($mail,'Incidencias',$type.' \n'.$msg);
		}
		//Add to sent
		dbw_query($db_conn,"UPDATE MAIL SET `Sent`=1 WHERE ID_M='$lastid'");
	}
    //dbw_query($db_conn,"DELETE FROM MAIL WHERE `Sent`=1"); //Delete sent messages

}

function listaMails(){
    $db_conn = dbconn();
    $query = dbw_query($db_conn,"SELECT Email FROM USERS WHERE SendMail = '1'");
    while ($line = dbw_fetch_array($db_conn,$query)){
        $mail[] = $line['Email'];
    }
    if (!isset($mail)){
        return NULL;
    }else{
        return $mail;
    }

}


function gestionAlerta($server,$type,$nameParam,$status){
    $db_conn = dbconn();
    $ID_SERV = (int)$server['ID_SERV'];
    switch ($type) {
        case 'PING':
            $hasalert = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type` = 'PING'")[0];
            if ($hasalert == 0 && $status == 0){ //Apagado
                enviarcorreo($ID_SERV,$type,'El servidor '.$server['Name'].' está apagado / no responde a Ping');
                newAlert($ID_SERV,$type,'','El servidor '.$server['Name'].' está apagado / no responde a Ping');
                
            }else if ($hasalert && $status == 1){ //Todo bien
                enviarcorreo($ID_SERV,$type,'El servidor '.$server['Name'].' vuelve a estar disponible / responde al Ping');
                deleteAlert($ID_SERV,$type);
            }
        break;
        case 'SERVICE':
            $service = $nameParam;
            $hasalert = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type`='SERVICE' AND `Param`='$service'")[0];
            if ($hasalert == 0 && $status == 0){ //Se ha caido
            enviarcorreo($ID_SERV,$type.'.'.$service,'El servicio '.$service.' del servidor '.$server['Name'] .' ('.$server['IP'].') no responde');
            newAlert($ID_SERV,$type,$service,'El servicio '.$service.' del servidor '.$server['Name'] .' ('.$server['IP'].') no responde');
            }else if ($hasalert && $status == 1){ //Volvió
                enviarcorreo($ID_SERV,$type.'.'.$service,'El servicio '.$service.' del servidor '.$server['Name'] .' ('.$server['IP'].') ya responde');
                deleteAlert($ID_SERV,$type,$service);
            }
        break;
        case 'HDD':
            $disk = $nameParam;
            $hasalert = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type` = 'HDD' AND `Param`='$disk'")[0];
            if ($hasalert == 0 && $status == 0){ //Espacio bajo
                enviarcorreo($ID_SERV,$type.'.'.$disk,'El disco duro '.$disk.' del servidor '.$server['Name'] .' tiene poco espacio disponible');
                newAlert($ID_SERV,$type,$disk,'El disco duro '.$disk.' del servidor '.$server['Name'] .' tiene poco espacio disponible');
            }else if ($hasalert && $status == 1){ //Todo bien
                enviarcorreo($ID_SERV,$type.'.'.$disk,'El disco duro '.$disk.' del servidor '.$server['Name'] .' ya tiene más espacio disponible');
                deleteAlert($ID_SERV,$type,$disk);
            }
        break;
        case 'RAM':
            $percent = $nameParam;
            $hasalert = dbw_query_fetch_array($db_conn,"SELECT COUNT(*) FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type` = 'RAM'")[0];
            if ($hasalert == 0 && $status == 0){ //RAM bajo
                enviarcorreo($ID_SERV,$type,'El servidor '.$server['Name'] .' tiene poca RAM disponible ('.$percent.')');
                newAlert($ID_SERV,$type,$disk,'El servidor '.$server['Name'] .' tiene poca RAM disponible ('.$percent.')');
            }else if ($hasalert && $status == 1){ //Todo bien
                enviarcorreo($ID_SERV,$type,'El servidor '.$server['Name'] .' ya tiene más RAM disponible');
                deleteAlert($ID_SERV,$type);
            }
        break;
    }
    
}

function newAlert($ID_SERV,$type,$param,$msg){
    $time = time();
    dbw_query(dbconn(),"INSERT INTO P_ALERTS (ID_SERV,`Type`,`Param`,`Timestamp`,`Msg`) VALUES ('$ID_SERV','$type','$param','$time','$msg')");
}
function deleteAlert($ID_SERV,$type,$param = NULL){
    if ($param == NULL){
        dbw_query(dbconn(),"DELETE FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type`='$type'");
    }else{
        dbw_query(dbconn(),"DELETE FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type`='$type' AND `Param`='$param'");
    }
    
}


function getAlerts(){
    $db_conn = dbconn();
    $query = dbw_query($db_conn,"SELECT * FROM P_ALERTS ORDER BY `Timestamp` DESC");
    while ($line = dbw_fetch_array($db_conn,$query)){
        //$type = strtolower(explode('.',$line['Type'])[0]);
        $servName = dbw_query_fetch_array($db_conn,"SELECT `Name` FROM SERVERS WHERE ID_SERV='$line[ID_SERV]'")[0];
        $alert[] = array(
            'ID_SERV' => $line['ID_SERV'],
            'Type' => $line['Type'],
            'Param' => $line['Param'],
            'Timestamp' => timestampToHuman($line['Timestamp']),
            'Text' => $line['Msg'],
            'ServName' => $servName
        );
    }
    if (!isset($alert)) return NULL;
    return $alert;
}

function timestampToHuman($timestamp){
    return date('d-m-y H:i',$timestamp);
}

function percalertfor($str){
    $value = dbw_query_fetch_array(dbconn(),"SELECT `Value` FROM SYS WHERE `Option`='${str}ALERT'")[0];
    if (!$value){
        return NULL;
    }else{
        return $value;
    }
}

//Return 1 is alert is going, 0 if not alerts of this type
function hasalert($ID_SERV,$type){
    if (dbw_query_fetch_array(dbconn(),"SELECT COUNT(*) FROM P_ALERTS WHERE ID_SERV='$ID_SERV' AND `Type`='$type'")[0]){
        return 1;
    }else{
        return 0;
    }
}

function getsysopt($opt){
    $value = dbw_query_fetch_array(dbconn(),"SELECT `Value` FROM SYS WHERE `Option`='${opt}'")[0];
    if (!$value){
        return NULL;
    }else{
        return $value;
    }
}


function toggle_server_svc($ID_SERV,$servicename){

    $server = serverData($ID_SERV); //Load server data
       
    list($name,$status) = dbw_query_fetch_array($db_conn,"SELECT `Name`,`Status` FROM S_SERVICES WHERE ID_SERV='$ID_SERV' AND `Name`='$servicename'");

    if ($status == 0){ //Estaba parado, arrancar
        switch ($server['SO']){
            case 'LINUX_SYSTEMD':
                commandbyssh($server['IP'],$server['SSHPort'],$server['User'],$server['Password'],'systemctl restart '.$servicename.'>/dev/null');

            break;
            case 'LINUX_SERVICE':
                commandbyssh($server['IP'],$server['SSHPort'],$server['User'],$server['Password'],'service '.$servicename.' start;');

            break;
        }
    }else{ //Esta arrancado, parar
        switch ($so){
            case 'LINUX_SYSTEMD':
                commandbyssh($server['IP'],$server['SSHPort'],$server['User'],$server['Password'],'systemctl stop '.$servicename.'>/dev/null');

            break;
            case 'LINUX_SERVICE':
                commandbyssh($server['IP'],$server['SSHPort'],$server['User'],$server['Password'],'service '.$servicename.' stop;');

            break;
        }    
    }



}
?>