<?php
	// ----------------
	// GESTIONE ERRORI
	// ----------------
	if( TRUE )
	{
		error_reporting(E_ALL);
		ini_set('display_errors', 'On');
		ini_set('display_startup_errors', 1);
	}
	/// -----------------------------------------------------------
	/// VERSIONE NUOVA PER SISTEMI NON DO0 - AGGIORNAMENTO PER PHP8
	/// -----------------------------------------------------------
	// 1 dec 2022 - inserisco 2 nuove variabili calcolate automaticamente per
	//	gestire correttamente i cookies: $gbl_mainDomain e $gbl_subDomain.
	// _<MAIN-DOMAIN-NAME>
	// dalla revisione 7 Luglio 2022, non è più utilizzato
	// questo la rende standard anche per do0 praticamente
	// $gbl_url contiene sempre il sottodominio
	// $gbl_myFullUrl invece è la variabile utilizzata per 
	// gestire i token (deve corrispondere a me stesso)
	//2 REVISIONE * 16 NOVEMBRE 2022 *, MODIFICO NUOVAMENTE LA GESTIONE DEI TOKEN
	//2 IL PUNTO E' CHE IN FIREFOX SI CREANO 2 CLASSI DI TOKEN, UNO CON LEADING DOT (.CRC2.AWGP.IT)
	//2 PROVO AD ELIMINARE IL PROBLEMA TOGLIENDO IL SOTTODOMINIO REVISIONE * 16 NOVEMBRE 2022 *
	//2 faccio in modo che $gbl_myFullUrl contenga solo il dominio principale
	// ------------------
	
	
	// ATTENZIONE: qualsiasi tabella DEVE avere il campo ID!!!
	
	/* ------------------------------------------------------------------------------ */
	/* 				ATTENZIONE!!!					  */
	/* per questa funzione bisogna usare la "togliVirgolette" per il valore del campo */
	/* 				ATTENZIONE!!!					  */
	/* ------------------------------------------------------------------------------ */
	function dbQuery($q) // tutta la query incluso select
	{
		global $db_sql;
		global $db_sql_result;
	
		if( !isset( $db_sql) || ($db_sql == NULL))
			return -10001;
		
		if( $q == "" )
			return -10002;
	
		@mysqli_query($db_sql, $q);
	
		return mysqli_affected_rows ( $db_sql );
	}
	
	
	function dbQueryResult($q) // tutta la query incluso select
	{
		global $db_sql;
		global $db_sql_result;
	
		if( !isset( $db_sql) || ($db_sql == NULL))
			return -10001;
		
		if( $q == "" )
			return -10002;
	
		return mysqli_query($db_sql, $q);
	}
	
	function dataItaliana2( $tempo, $mode=0)
	{
	/*
	$tempo è quello che ritorna time(); // dataora unixtime
	mode 0 = Martedì 14 Aprile
	mode 1 = Martedì 14 Aprile 2010
	mode 12 = data ora tipo: 12:31 12/14/2013
	*/
	
	if( $tempo < 0) $tempo = 0;
	
	    
	// carico tutti i nomi dei mesi nell'array $mese
	$mese = array ("","Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre");
	$meseCorto = array ("","Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic");
	
	// carico tutti i giorni della settimana nell'array $giorno
	$giorno = array ("Domenica", "Luned&igrave;", "Marted&igrave;", "Mercoled&igrave;", "Gioved&igrave;", "Venerd&igrave;","Sabato");
	
	$laData = getdate($tempo);
	
	$g = $laData['mday'];
	$m = $laData['mon'];
	$a = $laData['year'];
	
	$wd = $laData['wday'];
	
	
	switch( $mode)
	{
	   case 0:
	           $dataItaliana = $giorno[$wd] ." " . $g ." " . $mese[$m];
	   break;
	
	   case 1:
	           $dataItaliana = $giorno[$wd] ." " . $g ." " . $mese[$m] . " " . $a;
	   break;
	   case 12:
	           $dataItaliana = $g ." " . $meseCorto[$m] . " " . $a . " - " . sprintf("%02d:%02d", $laData['hours'], $laData['minutes']);
	   break;
	   case 13:
	           $dataItaliana = sprintf("%02d/%02d/%04d", $g, $m, $a );
	   break;
	   case 14:
	           $dataItaliana = sprintf("%02d/%02d/%04d", $m, $g, $a );
	   break;
	   case 15:
	           $dataItaliana = sprintf("%02d/%02d/%04d-%02d:%02d:%02d", $g, $m, $a, $laData['hours'], $laData['minutes'], $laData['seconds'] );
	   break;
	   case 16: // data ora e stop 10:00
	           $dataItaliana = sprintf("%02d:%02d", $laData['hours'], $laData['minutes']);
	   break;
	   case 17:
	           $dataItaliana = sprintf("%02d/%02d/%04d %02d:%02d:%02d", $g, $m, $a, $laData['hours'], $laData['minutes'], $laData['seconds'] );
	   break;
	
	}
	
	return $dataItaliana;
	}
	
	
	
	
	// funzione che ritorna i nomi dei menu' selezionati
	//
	/*
			admin
				Dashboard: main, fa fa-home, alias1, alias2, alias3, alias4, alias5, alias6
				Tabella Utenti: showUserTable, fa fa-user
					Funzione 1: funzione1, fa fa-home
					Funzione 3: funzione3, fa fa-home
						Funzione 2: funzione2, fa fa-home
		
	se ho selezionato funzione2, mi ritorna un array che contiene: [0]=showUserTable, [1]=funzione3
	*/
	
	
	function getExpandedList( $tree, $selected )
	{
		$branch = array();
	
		if( !is_array( $tree ))
			return $branch;
	
		$selected = trim( $selected );
	
		foreach( $tree as $nom=>$leaf )
		{
			if( !is_array( $leaf ))
				continue;
	
			$branch = getBranch( $leaf, $branch, $selected );
	
			if( count( $branch)) // se non trova l'elemento, branch è vuoto
				return $branch;
		}
	
		return $branch;
	
	}
	
	function getBranch( $leaf, $branch, $selected )
	{
		if( !is_array( $leaf ))
			return $branch;
	
		foreach( $leaf as $name=>$element )
		{
			//0 revisione 20 maggio 2022 -> ---------------------------------------------------------------------------------------------------
			if( $name == "0" || $name == "2" || $name == "3" || $name == "4" || $name == "5" || $name == "6" || $name == "7" ) // nome funzione
			//0 -------------------------------------------------------------------------------------------------------------------------------
			{
				if( is_array( $element) || $element == $selected )
					return $branch;
	
				$branch[] = $element;
				continue;
			}
	
			if( !is_array( $element))
				continue;
	
			$temp = getBranch( $element, $branch, $selected );
			
			if( count( $temp))
				return $temp;
		}
	
		$nothing = array(); // non era il ramo contenente l'elemento selezionato
		return $nothing;
	}
	
	
	
	function getFreshToken($useridx, $databaseName="", $durata=86400)
	{
		//0 ------------------------------------------------------------
		//0 rev.211012 modifica delle funzioni per la gestione dei token
		// -------------------------------
		// Nota: IDX attualmente è l'email
		$password = "ambarabaciccicocco_zompalla$01";
		$tmp = (time()+$durata);
		if( $databaseName == "" )
			$token = $tmp . "|" . $useridx;
		else
			$token = $tmp . "|" . $useridx . "|" . $databaseName;
	
		$token = _encrypta( $token, $password);
		return bin2hex($token);
	}
	
	function checkToken($token,$databaseName="")
	{
		$token = hex2bin( $token);
		$password = "ambarabaciccicocco_zompalla$01";
		$stringa = _decrypta( $token, $password);
		$block = explode("|",$stringa);
	
		if( $databaseName != "" )
		{
			if( !isset($block[2]))
				return NULL;
			if( $block[2] != $databaseName)
				return NULL;
		}
	
		if( count( $block) < 2 )
			return NULL;
	
		if( $block[0] < time())
			return NULL;
	
		return $block[1];
	}
	
	
	
	$kT="1029384756qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM";
	function bin2pck($v0){ global $kT;
		$rV = "";
		while($v0>0) {
			$rV .= $kT[($v0%62)];
			$v0 = intVal($v0/62);
			}
		return $rV;
		}
	
	function pck2bin($s0){ global $kT;
		if(($l=strlen($s0))<=0) return 0; $v=strpos($kT,$s0[0]); 
		for($x=1;$x<$l;$x++)
		   $v = $v + ((pow(62,$x))*strpos($kT,$s0[$x]));
		return $v;
		}
	
	
	class UnsafeCrypto
	{
	    const METHOD = 'aes-256-ctr';
	
	    /**
	     * Encrypts (but does not authenticate) a message
	     * 
	     * @param string $message - plaintext message
	     * @param string $key - encryption key (raw binary expected)
	     * @param boolean $encode - set to TRUE to return a base64-encoded 
	     * @return string (raw binary)
	     */
	    public static function encrypt($message, $key, $encode = false)
	    {
	        $nonceSize = openssl_cipher_iv_length(self::METHOD);
	        $nonce = openssl_random_pseudo_bytes($nonceSize);
	
	        $ciphertext = openssl_encrypt(
	            $message,
	            self::METHOD,
	            $key,
	            OPENSSL_RAW_DATA,
	            $nonce
	        );
	
	        // Now let's pack the IV and the ciphertext together
	        // Naively, we can just concatenate
	        if ($encode) {
	            return base64_encode($nonce.$ciphertext);
	        }
	        return $nonce.$ciphertext;
	    }
	
	    /**
	     * Decrypts (but does not verify) a message
	     * 
	     * @param string $message - ciphertext message
	     * @param string $key - encryption key (raw binary expected)
	     * @param boolean $encoded - are we expecting an encoded string?
	     * @return string
	     */
	    public static function decrypt($message, $key, $encoded = false)
	    {
	        if ($encoded) {
	            $message = base64_decode($message, true);
	            if ($message === false) {
	                throw new Exception('Encryption failure');
	            }
	        }
	
	        $nonceSize = openssl_cipher_iv_length(self::METHOD);
	        $nonce = mb_substr($message, 0, $nonceSize, '8bit');
	        $ciphertext = mb_substr($message, $nonceSize, null, '8bit');
	
	        $plaintext = openssl_decrypt(
	            $ciphertext,
	            self::METHOD,
	            $key,
	            OPENSSL_RAW_DATA,
	            $nonce
	        );
	
	        return $plaintext;
	    }
	}
	
	
	class SaferCrypto extends UnsafeCrypto
	{
	    const HASH_ALGO = 'sha256';
	
	    /**
	     * Encrypts then MACs a message
	     * 
	     * @param string $message - plaintext message
	     * @param string $key - encryption key (raw binary expected)
	     * @param boolean $encode - set to TRUE to return a base64-encoded string
	     * @return string (raw binary)
	     */
	    public static function encrypt($message, $key, $encode = false)
	    {
	        list($encKey, $authKey) = self::splitKeys($key);
	
	        // Pass to UnsafeCrypto::encrypt
	        $ciphertext = parent::encrypt($message, $encKey);
	
	        // Calculate a MAC of the IV and ciphertext
	        $mac = hash_hmac(self::HASH_ALGO, $ciphertext, $authKey, true);
	
	        if ($encode) {
	            return base64_encode($mac.$ciphertext);
	        }
	        // Prepend MAC to the ciphertext and return to caller
	        return $mac.$ciphertext;
	    }
	
	    /**
	     * Decrypts a message (after verifying integrity)
	     * 
	     * @param string $message - ciphertext message
	     * @param string $key - encryption key (raw binary expected)
	     * @param boolean $encoded - are we expecting an encoded string?
	     * @return string (raw binary)
	     */
	    public static function decrypt($message, $key, $encoded = false)
	    {
	        list($encKey, $authKey) = self::splitKeys($key);
	        if ($encoded) {
	            $message = base64_decode($message, true);
	            if ($message === false) {
	                throw new Exception('Encryption failure');
	            }
	        }
	
	        // Hash Size -- in case HASH_ALGO is changed
	        $hs = mb_strlen(hash(self::HASH_ALGO, '', true), '8bit');
	        $mac = mb_substr($message, 0, $hs, '8bit');
	
	        $ciphertext = mb_substr($message, $hs, null, '8bit');
	
	        $calculated = hash_hmac(
	            self::HASH_ALGO,
	            $ciphertext,
	            $authKey,
	            true
	        );
	
	        if (!self::hashEquals($mac, $calculated)) {
	            throw new Exception('Encryption failure');
	        }
	
	        // Pass to UnsafeCrypto::decrypt
	        $plaintext = parent::decrypt($ciphertext, $encKey);
	
	        return $plaintext;
	    }
	
	    /**
	     * Splits a key into two separate keys; one for encryption
	     * and the other for authenticaiton
	     * 
	     * @param string $masterKey (raw binary)
	     * @return array (two raw binary strings)
	     */
	    protected static function splitKeys($masterKey)
	    {
	        // You really want to implement HKDF here instead!
	        return [
	            hash_hmac(self::HASH_ALGO, 'ENCRYPTION', $masterKey, true),
	            hash_hmac(self::HASH_ALGO, 'AUTHENTICATION', $masterKey, true)
	        ];
	    }
	
	    /**
	     * Compare two strings without leaking timing information
	     * 
	     * @param string $a
	     * @param string $b
	     * @ref https://paragonie.com/b/WS1DLx6BnpsdaVQW
	     * @return boolean
	     */
	    protected static function hashEquals($a, $b)
	    {
	        if (function_exists('hash_equals')) {
	            return hash_equals($a, $b);
	        }
	        $nonce = openssl_random_pseudo_bytes(32);
	        return hash_hmac(self::HASH_ALGO, $a, $nonce) === hash_hmac(self::HASH_ALGO, $b, $nonce);
	    }
	}
	
	function _encrypta( $message, $key )
	{
		try 
		{
			return SaferCrypto::encrypt($message, $key);
		} 
		catch (Exception $ex) 
		{
		}
		return "***";
	}
	
	function _decrypta( $encrypted, $key )
	{
		try 
		{
			return SaferCrypto::decrypt($encrypted, $key);
		} 
		catch (Exception $ex) 
		{
		}
		return "***";
	}
	
	//// SCRAMBLE
	function scramble( $something, $code )
	{
	        $len = strlen( $something );
	        if( $len <= 0 )
	                return "";
	        $lenC = strlen( $code );
	        if( $lenC <= 0 )
	                return "";
	        // -------------------------------
	        // scambio terminali
	        $temp2 = $something[0];
	        $something[0] = $something[$len-1];
	        $something[$len-1] = $temp2;
	        // -------------------------------
	        for( $i=1; $i<($len-2); $i+=2)
	        {
	                $temp2 = $something[$i+1];
	                $something[$i+1] = $something[$i];
	                $something[$i] = $temp2;
	        }
	
	        // -------------------------------
	        // offuscamento
	        for( $i=0; $i<$len; $i++)
	        {
	                $index = $i % $lenC;
	                $a = ord($something[$i]);
	                $b = ord($code[$index]);
	                $c = $a ^ $b;
	                $something[$i] = chr($c);
	        }
	        return $something;
	}
	
	//// DESCRAMBLE
	function descramble( $something, $code )
	{
	        $len = strlen( $something );
	        if( $len <= 0 )
	                return "";
	        $lenC = strlen( $code );
	        if( $lenC <= 0 )
	                return "";
	        // -------------------------------
	        // deoffuscamento
	        for( $i=0; $i<$len; $i++)
	        {
	                $index = $i % $lenC;
	                $a = ord($something[$i]);
	                $b = ord($code[$index]);
	                $c = $a ^ $b;
	                $something[$i] = chr($c);
	        }
	        // -------------------------------
	        // scambio terminali
	        $temp2 = $something[0];
	        $something[0] = $something[$len-1];
	        $something[$len-1] = $temp2;
	        // -------------------------------
	        for( $i=1; $i<($len-2); $i+=2)
	        {
	                $temp2 = $something[$i+1];
	                $something[$i+1] = $something[$i];
	                $something[$i] = $temp2;
	        }
	
	        return $something;
	}
	
	
	
	
	
	
	
	
	
	
	function sanitize($var, $type, $sql=NULL)
	{
	        switch($type) {
	                case 'html':
	                        $safe = htmlspecialchars($var);
	                        break;
	                case 'sql':
	                        $safe = mysqli_real_escape_string($sql,$var);
	                        break;
	                case 'file':
	                        $safe = preg_replace('/(\/|-|_)/','',$var);
	                        break;
	                case 'shell':
	                        $safe = escapeshellcmd($var);
	                        break;
	                default:
	                        $safe = htmlspecialchars($var);
	        }
	        return $safe;
	}
	
	
	//// ----------------------------------------------------
	//// PER LA .1 -> LA FUNZIONE NON GESTISCE LE VIRGOLETTE
	//// È FATTO APPOSTA PER LE SITUAZIONI IN CUI SO CHE NON
	//// SERVE
	//// ----------------------------------------------------
	function db_sql_insert_2( $nomeTabella, $record) // record singolo
	{
		global $db_sql;
	
		if( !isset( $db_sql) || ($db_sql == NULL))
			return -1;
	
		if( !isset( $record) || !is_array($record))
			return -2;
	
		if($nomeTabella == "") return -26;
		
		//// a scanso di equivoci, id è sempre e solo in lettura
		if( isset( $record['id']))
			unset( $record['id']);
	
		$q = "INSERT INTO " . trim($nomeTabella) . " (";
	
		$t = 0;
		foreach($record as $chiave=>$valore) 
		{
			if( $chiave == "")
				return -4;
	
			if($t++)
				$q .= "," . $chiave;
			else
				$q .= $chiave;
		}
	
		$q .= ") VALUES ('";
	
		$t = 0;
		foreach($record as $valore) {
			if($t++)
				$q .= "','" . $valore;
			else
				$q .= $valore;
		}
	
		$q .= "')";
	
		if (!mysqli_query($db_sql, $q))
			return -30;
		
		return mysqli_insert_id($db_sql);
	}
	//// ----------------------------------------------------
	//// PER LA .1 -> LA FUNZIONE NON GESTISCE LE VIRGOLETTE
	//// È FATTO APPOSTA PER LE SITUAZIONI IN CUI SO CHE NON
	//// SERVE
	//// ----------------------------------------------------
	function db_sql_update_2( $nomeTabella, $record, $campo, $valoreComp) // where $campo == $valoreComp
	{
		global $db_sql;
	
		if( !isset( $db_sql) || ($db_sql == NULL)) return -1;
	
		if( !isset( $record) || !is_array($record)) return -2;
	
		if($campo == "") return -23;
	
		if($nomeTabella == "") return -26;
	
		// a scanso di equivoci, id solo in lettura
		if( isset( $record['id']))
			unset( $record['id']);
		
		$q = "UPDATE " . trim($nomeTabella) . " SET ";
	
		$t = 0;
		foreach($record as $chiave=>$valore) {
			if($t++)
				$q .= "," . $chiave . "='" . $valore . "' ";
			else
				$q .= $chiave . "='" . $valore . "' ";
		}
	
		$q .= " WHERE " . $campo . "='" . $valoreComp . "'";
	
		if (!mysqli_query($db_sql, $q))
	        	return -33;
	
		return 0;
	}
	
	
	
	
	function contains( $s, $w )
	{
		if( !isset( $s) || $s == "" || $s == null )
			return false;
	
		if( is_array($s))
			return false;
		if (strpos($s, $w) !== false) 
	    	return true;
	
		return false;
	}
	
	
	function startsWith ($string, $startString)
	{
	    $len = strlen($startString);
	    return (substr($string, 0, $len) === $startString);
	}
	
	
	function endsWith($string, $endString)
	{
	    $len = strlen($endString);
	    if ($len == 0) {
	        return true;
	    }
	    return (substr($string, -$len) === $endString);
	}
	
	
	
	
	
	///	------------------------------------------------------------------
	/// Error Handler
	///	------------------------------------------------------------------
	$gbl_prevRow = "";
	$gbl_currentRow = "";
	function exceptions_error_handler($severity, $message, $filename, $lineno)
	{
		if (error_reporting() == 0) 
			return;
	
		global $gbl_currentRow, $gbl_prevRow;
		echo "Current Row:[" . $gbl_currentRow ."]\n";
		echo "\n*********************************************************************************************************************\n";
		echo "\nPrev Row:[" . $gbl_prevRow ."]\n";
	
		if (error_reporting() & $severity) 
			throw new ErrorException($message, 0, $severity, $filename, $lineno);
	}
	///	------------------------------------------------------------------
	/// Esegue e sostituisce tutte le variabili che trova {{=what.whatelse.whatagain=}}
	///	------------------------------------------------------------------
	
	function please_execTuttVariab( &$_t, $valore)
	{
		global $gbl_currentRow, $gbl_prevRow;
	
		if( strpos( $valore, "=}}") === false)
			return $valore;
	
		$pezzoni = explode( "=}}", $valore);
	
		foreach( $pezzoni as $tocco)
		{
			$aPos = strpos( $tocco, "{{=");
			if( $aPos !== false)
			{
				$tentative = trim(substr( $tocco, $aPos+3)); // filtra "{" e "{" e "="
				if( $tentative !== false)
				{
					$stringNames = explode( ".", $tentative); // tutti i nomi in array, dal padre al figlio: padre.figlio.nipote
					$varName = NULL;
	
					if( !is_array($stringNames))
						continue;
	
					foreach( $stringNames as $singleName)
					{
						if( !contains( $singleName, "\n") && !contains( $singleName, "\r") &&
						    !contains( $singleName, "'") && !contains( $singleName, '"') && !contains( $singleName, "\t") )
							$varName .= "['" . $singleName . "']";
						else
						{
							$varName = NULL;
							break;
						}
					}
	
					if( !is_null($varName) && !($varName == ""))
					{
						$varValue = eval('if( isset( $_t'."$varName)) return " . '($_t'."$varName); else return NULL;");
						
						if( !contains( $varValue, "{{=") && !contains( $varValue, "[[-") &&
						    !contains( $varValue, "<!xxx--") && !contains( $varValue, "{--") )
						{
							try {
								$gbl_prevRow = $gbl_currentRow;
								$gbl_currentRow = $varValue;
								$varValue = eval($varValue);
							} catch (ParseError $e) {
								echo $e . "\n";
							    echo "<<<\n" . $varValue . "\n>>>";
								exit();
							}
							$varValue = isset($varValue) && $varValue != null ? $varValue : "";
							$valore = str_replace( "{{=" . $tentative . "=}}", $varValue, $valore); 
						}
					}
				}
			}
		}
		return $valore;
	}
	
	
	
	
	function please_execTuttVariab2( &$_t, $valore)
	{
		global $gbl_currentRow, $gbl_prevRow;
	
		if( strpos( $valore, "--}") === false)
			return $valore;
	
		$pezzoni = explode( "--}", $valore);
	
		foreach( $pezzoni as $tocco)
		{
			$aPos = strpos( $tocco, "{!--");
			if( $aPos !== false)
			{
				$tentative = trim(substr( $tocco, $aPos+4)); // filtra "{" e "{" e "="
				if( $tentative !== false)
				{
					$stringNames = explode( ".", $tentative); // tutti i nomi in array, dal padre al figlio: padre.figlio.nipote
					$varName = NULL;
	
					if( !is_array($stringNames))
						continue;
	
					foreach( $stringNames as $singleName)
					{
						if( !contains( $singleName, "\n") && !contains( $singleName, "\r") &&
						    !contains( $singleName, "'") && !contains( $singleName, '"') && !contains( $singleName, "\t") )
							$varName .= "['" . $singleName . "']";
						else
						{
							$varName = NULL;
							break;
						}
					}
	
					if( !is_null($varName) && !($varName == ""))
					{
						$varValue = eval('if( isset( $_t'."$varName)) return " . '($_t'."$varName); else return NULL;");
						if( !contains( $varValue, "{{=") && !contains( $varValue, "[[-") &&
						    !contains( $varValue, "<!xxx--") && !contains( $varValue, "{--") )
						{
							try {
								$gbl_prevRow = $gbl_currentRow;
								$gbl_currentRow = $varValue;
								$varValue = eval($varValue);
							} catch (ParseError $e) {
								echo $e . "\n";
							    echo "<<<\n" . $varValue . "\n>>>";
								exit();
							}
							$varValue = isset($varValue) && $varValue != null ? $varValue : "";
							$valore = str_replace( "{!--" . $tentative . "--}", $varValue, $valore); 
						}
					}
				}
			}
		}
		return $valore;
	}
	
	
	
	
	
	function please_sostTuttVariab( &$_t, $valore)
	{
		if( strpos( $valore, "-]]") === false)
			return $valore;
	
		$pezzoni = explode( "-]]", $valore);
	
		foreach( $pezzoni as $tocco)
		{
			$aPos = strpos( $tocco, "[[-");
			if( $aPos !== false)
			{
				$tentative = trim(substr( $tocco, $aPos+3)); // filtra "<" e "!" e "-" e "-"
				if( $tentative !== false)
				{
					$stringNames = explode( ".", $tentative); // tutti i nomi in array, dal padre al figlio: padre.figlio.nipote
					$varName = NULL;
	
					if( !is_array($stringNames))
						continue;
	
					foreach( $stringNames as $singleName)
					{
						if( !contains( $singleName, "\n") && !contains( $singleName, "\r") &&
						    !contains( $singleName, "'") && !contains( $singleName, '"') && !contains( $singleName, "\t") )
							$varName .= "['" . $singleName . "']";
						else
						{
							$varName = NULL;
							break;
						}
					}
	
					if( !is_null($varName) && !($varName == ""))
					{
						$varValue = eval('if( isset( $_t'."$varName)) return " . '($_t'."$varName); else return '';");
						if( !contains( $varValue, "{{=") && !contains( $varValue, "[[-") &&
						    !contains( $varValue, "<!xxx--") && !contains( $varValue, "{--") )
						{
							$varValue = isset($varValue) && $varValue != null ? $varValue : "";
							$valore = str_replace( "[[-" . $tentative . "-]]", $varValue, $valore); 
						}
					}
				}
			}
		}
		return $valore;
	}
	
	
	
	
	
	
	
	
	
	function please_sostTuttVariab2( &$_t, $valore)
	{
		if( strpos( $valore, "-->") === false)
			return $valore;
	
		$pezzoni = explode( "-->", $valore);
	
		foreach( $pezzoni as $tocco)
		{
			$aPos = strpos( $tocco, "<!--");
			if( $aPos !== false)
			{
				$tentative = trim(substr( $tocco, $aPos+4)); // filtra "<" e "!" e "-" e "-"
				if( $tentative !== false)
				{
					$stringNames = explode( ".", $tentative); // tutti i nomi in array, dal padre al figlio: padre.figlio.nipote
					$varName = NULL;
	
					if( !is_array($stringNames))
						continue;
	
					foreach( $stringNames as $singleName)
					{
						if( !contains( $singleName, "\n") && !contains( $singleName, "\r") &&
						    !contains( $singleName, "'") && !contains( $singleName, '"') && !contains( $singleName, "\t") )
							$varName .= "['" . $singleName . "']";
						else
						{
							$varName = NULL;
							break;
						}
					}
	
					if( !is_null($varName) && !($varName == ""))
					{
						$varValue = eval('if( isset( $_t'."$varName)) return " . '($_t'."$varName); else return '';");
						if( !contains( $varValue, "{{=") && !contains( $varValue, "[[-") &&
						    !contains( $varValue, "<!xxx--") && !contains( $varValue, "{--") && 
						    !is_array($tentative) && !is_array($varValue) && !is_array($valore) )
						{
							$varValue = isset($varValue) && $varValue != null ? $varValue : "";
							$valore = str_replace( "<!--" . $tentative . "-->", $varValue, $valore); 
						}
					}
				}
			}
		}
		return $valore;
	}
	
	
	
	
	
	
	
	
	function _parser( $_t )
	{
		global $gbl_currentRow, $gbl_prevRow;
	
		if( !isset($_t) || !is_array( $_t))
			return NULL;
	
		set_error_handler('exceptions_error_handler');
	
		$index = 0;
		$somethingDone = true;
		while( $somethingDone )
		{
			$somethingDone = false;
			$temp = $_t;
			foreach( $temp as $key => $value)
			{
				$doneSomething = false;
				$_t[ $key] = replaceExec( $_t, $value, $doneSomething );
				if( $doneSomething )
					$somethingDone = true;
			}
		}
	
		$documento = "";
		foreach( $_t as $key => $branch)
		{
			if( $key[0] == "_" )
			{
				try {
					$gbl_prevRow = $gbl_currentRow;
					$gbl_currentRow = $branch;
					$documento .= eval( $branch);
				} catch (ParseError $e) {
				    echo $e . "\n";
				    echo "<<<\n" . $branch . "\n>>>";
					exit();
				}
			}
		}
		return $documento;
	}
	
	function replaceExec( $_t, $value, &$doneSomething )
	{
		$doneSomething = false;
		$returnWhat = "";
		if( is_array( $value))
		{
			$returnWhat = array();
			foreach( $value as $gkey => $gvalue)
			{
				if( is_array($gvalue))
				{
					$somethingDone = false;
					$returnWhat[$gkey] = replaceExec( $_t, $gvalue, $somethingDone );
					if( $somethingDone )
						$doneSomething = true;
				}
				else
				{
					$prev = $gvalue;
					$returnWhat[$gkey] = please_sostTuttVariab($_t, $gvalue);
					if( $returnWhat[$gkey] != $prev )
						$doneSomething = true;
	
					$prev = $returnWhat[$gkey];
					$returnWhat[$gkey] = please_sostTuttVariab2($_t, $returnWhat[$gkey]);
					if( $returnWhat[$gkey] != $prev )
						$doneSomething = true;
	
					$prev = $returnWhat[$gkey];
					$returnWhat[$gkey] = please_execTuttVariab($_t, $returnWhat[$gkey]);
					if( $returnWhat[$gkey] != $prev )
						$doneSomething = true;
	
					$prev = $returnWhat[$gkey];
					$returnWhat[$gkey] = please_execTuttVariab2($_t, $returnWhat[$gkey]);
					if( $returnWhat[$gkey] != $prev )
						$doneSomething = true;
				}
			}
		}
		else
		{
			$prev = $value;
			$returnWhat = please_sostTuttVariab($_t, $value);
			if( $returnWhat != $prev )
				$doneSomething = true;
	
			$prev = $returnWhat;
			$returnWhat = please_sostTuttVariab2($_t, $returnWhat);
			if( $returnWhat != $prev )
				$doneSomething = true;
	
			$prev = $returnWhat;
			$returnWhat = please_execTuttVariab($_t, $returnWhat);
			if( $returnWhat != $prev )
				$doneSomething = true;
	
			$prev = $returnWhat;
			$returnWhat = please_execTuttVariab2($_t, $returnWhat);
			if( $returnWhat != $prev )
				$doneSomething = true;
		} 
		return $returnWhat;
	}
	
	
	
	
	function readSimpleTreeFile( $filename )
	{
		if( !isset( $filename) || $filename == "")
			return NULL;
	
		if( !file_exists( $filename))
			return NULL;
	
		$handle = fopen( $filename, "r");
	
		if (!$handle) return NULL;
	
	
	
		$level = 0;
		$numLine = 0;
	
		$retArray = readSimpleTreeNode( $handle, $level, $numLine, NULL );
	
	
	
	    fclose($handle);
	
	    return $retArray;
	
	} 
	
	
	
	function readSimpleTreeNode( $handle, $level, &$numLine, $theTree) 
	{
		if( !$handle || ($level<0) ) return NULL;
		$retArray = array();
	
		while ( true ) 
		{
			$positionWas = ftell( $handle);
			$line = fgets($handle);	$numLine++;
	
			if( $line === false) {
				if((count($retArray, true) == 1) && (reset( $retArray) == "") )
					return $potentialFather;
				break;	
			}
	
			$tLine = trim($line);
			$tLen = strlen($tLine);
	
	///		if( ($tLine == "") || ( ($tLen>2) && ($tLine[0] == "/") && ($tLine[1] == "/") && ($tLine[2] == "/") ) ) mod .rev.20mar2021
			if( ($tLine == "") || ( ($tLen>=2) && ($tLine[0] == "/") && ($tLine[1] == "/"))) 
				continue; // riga vuota o commento
	
			$numTabs = HELP_contaTabs( $line); 
			$line = trim($line);
	
			if( $numTabs == $level ) 
			{
				if( $line == "<[" ) 
				{ 
					echo "Attenzione, alla linea " . $numLine . " il blocco '<[' non è indentato correttamente, va spostato a destra di un TAB."; 
					exit();
				}
	
				if( !$level && (trim(strtok($line, " ")) == "include") ) // gestione nuovo handle ad un nuovo livello
				{
					$fNam = trim(strtok(" "));
					$uNom = str_replace('/',"_",$fNam); // se va in direttori diversi, tolgo lo slash e diventa underscore
					$retArray[$uNom] = readSimpleTreeFile($fNam . ".php"); // sempre php!!!
					continue;
				}
	
				if( $line != "di tipo")
				{
					if( !isset( $retArray[$line]))
					{
						if( fromStringToArray( $line, $flashArray, $flashNome ))
						{
							$retArray[ $flashNome] = $flashArray;
							$line = $flashNome; // correggiamo il potentialFather, altrimenti nel caso misto crea un nuovo elemento con un nome nuovo
						}
						else
							$retArray[$line] = "";
					}
				}
	
				$potentialFather = $line;
				continue;
			}
	
	
			if( $numTabs == ($level+1)) // child found
			{ 
				if( $line == "<[" )
					$retArray[$potentialFather] = readSimpleTreeBlock( $handle, $numTabs, $numLine);
				else 
				{
					$classe = NULL;
					if( $potentialFather == "di tipo") 
					{
						if( is_array($theTree))
						{
							// $aTemp = array_merge( $theTree, $retArray);
							$aTemp = array_replace_recursive( $theTree, $retArray);
							$classe = HELP_getClasses( $line, $aTemp);				
						}
						else
							$classe = HELP_getClasses( $line, $retArray);				
					}
				
					if( !$classe )
					{
						fseek( $handle, $positionWas); $numLine--; // linea da rileggere
						$ritemp = readSimpleTreeNode( $handle, $numTabs, $numLine, $retArray);
	
						if( is_array( $ritemp) && is_array($retArray[$potentialFather]))
							$retArray[$potentialFather] = array_replace_recursive( $retArray[$potentialFather], $ritemp);
						else
							$retArray[$potentialFather] = $ritemp;
						unset($ritemp);
					} 
					else
						$retArray = array_replace_recursive( $classe, $retArray);
				}
			}
	
			if( $numTabs < $level )
			{
				fseek( $handle, $positionWas); $numLine--; // linea da rileggere
				if((count($retArray, true) == 1) && (reset( $retArray) == "") )
					return $potentialFather;
				else
					break; // livello superiore
			}
	
			if( $numTabs > ($level+1))
				echo "\n\rAttenzione: alla linea " . $numLine . " il livello è scollegato, verificare.";
		}
	
		return $retArray;
	}
	
	
	
	
	
	function readSimpleTreeBlock( $handle, $level, &$numLine) 
	{
		if( !$handle || ($level<0) ) return NULL;
		$retString = "";
	
		while ( true ) 
		{	$line = fgets($handle);	$numLine++;
			if( $line === false) 
			{	echo "Fine del file non attesa alla linea " . $numLine . ".";
				break; // no more lines to read
			}
			if( trim($line) == "<[" ) // prima linea
				continue;
	
			$tLine = trim($line);
			$tLen = strlen($tLine);
			if( ($tLine == "") || ( ($tLen>2) && ($tLine[0] == "/") && ($tLine[1] == "/") && ($tLine[2] == "/") ) ) 
				continue;
	
			if( trim($line) == "]>" ) // ultima linea
				break;
	
			$line = HELP_stripTabs($line, $level);
	
			$retString .= $line; // devo aggiungere cr+lf? vedremo
	
		}
	
		return $retString;
	}
	
	
	
	
	function HELP_contaTabs( $linea )
	{
		$len = strlen( $linea);
	
		for( $t=0; $t<$len; $t++)
			if( $linea[$t] != "\t" )
				break;
	
		return $t;
	}
	
	
	function HELP_stripTabs( $linea, $livello )
	{
		$len = strlen( $linea);
	
		for( $t=0; $t<$livello; $t++)
		{
			if( $linea[0] != "\t" )
				break;
			else
				$linea = substr($linea, 1);
	
		}
		return $linea;
	}
	
	function HELP_getClasses( $classNames, $theTree )
	{
		$nome = strtok( $classNames, ","); // per quando poi ci saranno più nomi
	
		// nomi delle classi separati dalla virgola, indirizzo della classe specifica separato dal punto, quindi il nome della classe può contenere spazi
	
		$retClass = array();
		do
		{
			$nomi = explode("/", $nome); 
			$varName = "";
			foreach( $nomi as $singolo)
			{
				$singolo = trim($singolo);
				$varName .= "['" . $singolo . "']";
			}
	
			$varValue = eval('if( isset( $theTree'."$varName)) return " . '($theTree'."$varName); else return array();");
			if( is_array( $varValue))
				$retClass = array_replace_recursive( $retClass, $varValue);
			else
			{
				echo "dbg: tipo non definito:[" . $classNames . "]";
				exit();
			}
		}
	
		while( $nome = strtok(","));
		return $retClass;
	}
	
	function array_merge_recursive_distinct ( array &$array1, array &$array2 )
	{
	  $merged = $array1;
	
	  foreach ( $array2 as $key => &$value )
	  {
	    if ( is_array ( $value ) && isset ( $merged [$key] ) && is_array ( $merged [$key] ) )
	    {
	      $merged [$key] = array_merge_recursive_distinct ( $merged [$key], $value );
	    }
	    else
	    {
	      $merged [$key] = $value;
	    }
	  }
	
	  return $merged;
	}
	
	
	
	/*
		prende una stringa nel formato: galla: pluto, paperino, 1, 10, 13, "tanto, va la gatta, al lardo"
		e diventa un array come segue:
		array['galla'][0] = "pluto";
		array['galla'][1] = "paperino";
		array['galla'][2] = "1";
		array['galla'][3] = "10";
		array['galla'][4] = "13";
		array['galla'][5] = "tanto, va la gatta, al lardo";
	
		se il nome è nullo, es: :prova,pluto,paperino -> viene messo [0]:
			array[0][0] = prova;
			array[0][1] = pluto;
			array[0][2] = paperino;
	
		se non ci sono parametri, viene ritornata esattamente la stringa in ingresso.
		es: nome che voglio
		ret value: "nome che voglio"
		es: nome che voglio:
		ret value: array['nome che voglio'][0] = "";
	
		i campi vengono tutti trimmati, tranne quando sono all'interno delle virgolette così:
		nome : alfa , be m ta
	
		array[nome][0] = "alfa";
		array[nome][0] = "be m ta";
	
		se il nome o il parametro contiene una virgoletta a buzzo, cancello tutto quello che viene prima e dopo:
	
		il "nome" è mio: "parametro" a buzzo
		array[nome][0] = "parametro";
	*/
	function fromStringToArray( $s, &$retArray, &$retNome )
	{
		$s = trim( $s );
		if( $s == "" ) return false;
		
		$ret = array();
		$status = "leggo nome";
		$len = strlen( $s);
		$i = 0; $p = 0;
		$nome = "";
		while( $i<$len )
		{
			if( $status == "leggo nome" ){
				
							if( $s[$i]=="'" )
							{
								$status = "leggo nome: in virgoletta";
								$nome = ""; // se c'era qualcosa prima: cancellato( es: dsfgdsf"sdfg" diventa solo <sdfg>)
								$i++;
								continue;				
							}
							if( $s[$i]=='"' )
							{
								$status = "leggo nome: in virgolette";
								$nome = ""; // se c'era qualcosa prima: cancellato( es: dsfgdsf"sdfg" diventa solo <sdfg>)
								$i++;
								continue;
							}
							if( $s[$i]==':' )
							{
								$nome = trim( $nome); // non era dentro virgolette di sicuro
								if( $nome == "" )
									$nome = "0";
								$status = "leggo parametro";
								$parametro = "";
								$i++;
								continue;
							}
							$nome .= $s[ $i];
							$i++;
							continue;
				
				
			}
			if( $status == "leggo nome: in virgoletta" ){
				
							if( $s[$i]=="'" )
							{
								$status = "aspetto due punti";
								$i++;
								continue;				
							}
							$nome .= $s[$i];
							$i++;
							continue;
				
			}
			if( $status == "leggo nome: in virgolette" ){
				
							if( $s[$i]=='"' )
							{
								$status = "aspetto due punti";
								$i++;
								continue;				
							}
							$nome .= $s[$i];
							$i++;
							continue;
				
			}
			if( $status == "aspetto due punti" ){
				
							// tutto quello che segue la chiusura delle virgolette singole o doppie viene scartato
							if( $s[$i]==':' )
							{
								/// ----------------------------------------------------
								/// se era nelle virgolette, il $nome non viene trimmato
								/// ----------------------------------------------------
								if( $nome == "" )
									$nome = "0";
								$status = "leggo parametro";
								$parametro = "";
								$i++;
								continue;
							}
							$i++;
							continue;
				
			}
			if( $status == "leggo parametro" ){
				
							if( $s[$i]=="'" )
							{
								$status = "leggo parametro: in virgoletta";
								$parametro = ""; // cominciano le virgolette, cancello quello che c'era prima
								$i++;
								continue;				
							}
							if( $s[$i]=='"' )
							{
								$status = "leggo parametro: in virgolette";
								$parametro = ""; // cominciano le virgolette, cancello quello che c'era prima
								$i++;
								continue;
							}
							if( $s[$i]==',' )
							{
								$parametro = trim( $parametro); // trimmato perché NON era dentro le virgolette
								$ret[$p] = $parametro; // potrebbe anche essere nullo
								$parametro = "";
								$p++;
								$i++;
								continue;
							}
							$parametro .= $s[$i];
							$i++;
							continue;
				
			}
			if( $status == "leggo parametro: in virgoletta" ){
				
							if( $s[$i]=="'" )
							{
								$status = "aspetto virgola";
								$i++;
								continue;				
							}
							$parametro .= $s[$i];
							$i++;
							continue;
				
			}
			if( $status == "leggo parametro: in virgolette" ){
				
							if( $s[$i]=='"' )
							{
								$status = "aspetto virgola";
								$i++;
								continue;				
							}
							$parametro .= $s[$i];
							$i++;
							continue;
				
			}
			if( $status == "aspetto virgola" ){
				
							// tutto quello che segue la chiusura delle virgolette singole o doppie viene scartato
							if( $s[$i]==',' )
							{
								// era dentro le virgolette, non viene trimmato
								$ret[$p] = $parametro; // potrebbe anche essere nullo
								$parametro = "";
								$p++;
								$i++;
								$status = "leggo parametro";
								continue;
							}
							$i++;
							continue;
				
			}
		}
		
			if( $status == "leggo nome" ){
				return false;
			}
			if( $status == "leggo nome: in virgoletta" ){
				return false;
			}
			if( $status == "leggo nome: in virgolette" ){
				return false;
			}
			if( $status == "aspetto due punti" ){
				return false;
			}
			if( $status == "leggo parametro: in virgoletta" ){
				return false;
			}
			if( $status == "leggo parametro: in virgolette" ){
				return false;
			}
		
			/// ----------------------------------------------
			/// SOLO IN QUESTI 2 STATI LA LETTURA DELLA RIGA
			/// TERMINA CORRETTAMENTE. TUTTI GLI ALTRI INDICA
			/// UNA FORMATTAZIONE ERRATA.
			/// ----------------------------------------------
			if( $status == "leggo parametro" )
			{
				$parametro = trim( $parametro); // trimmato perché NON era dentro le virgolette
				$ret[$p] = $parametro; // potrebbe anche essere nullo
				$retNome = $nome;
				$retArray = $ret;
				return true; 
			}
			if( $status == "aspetto virgola" )
			{
				// era dentro le virgolette, non viene trimmato
				$ret[$p] = $parametro; // potrebbe anche essere nullo
				$retNome = $nome;
				$retArray = $ret;
				return true; 
			}
		
		
		return false;
	}
	
	
	
	
	//1 ATTENZIONE: qualsiasi tabella DEVE avere il campo ID!!!
	
	/*								
	*/
	/// function sanificator(stringa) as string
	
	if (function_exists('mb_ereg_replace'))
	{
	    function sanificator(string $string)
	    {
			$string = mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]', '\\\0', $string);
			return preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $string);
	    }
	} 
	else 
	{
	    function sanificator(string $string)
	    {
			$string = preg_replace('~[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]~u', '\\\$0', $string);
			return preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $string);
	    }
	}
	
	function _s( $s )
	{
		return sanificator( $s );
	}
	
	
	
	/* ------------------------------------------------------------------------------	*/
	/* 				ATTENZIONE!!!					  										*/
	/* per questa funzione bisogna usare la addslashes() per il valore del campo		*/
	/* 				ATTENZIONE!!!					  										*/
	/* ------------------------------------------------------------------------------ 	*/
	function _dbGet($q=NULL) // tutta la query incluso select
	{
		global $db_sql;
		global $db_sql_result;
	
		if( !isset( $db_sql) || ($db_sql == NULL))
			return NULL;
	
		$tb_record = array();
	
		if( $q ) 
		{
			if( $db_sql_result)
				mysqli_free_result($db_sql_result);
	
			$db_sql_result = @mysqli_query($db_sql, $q);
		}
	
		if( $db_sql_result == null )
			return NULL;
	
		$aRecord = @mysqli_fetch_assoc($db_sql_result);
	
		if( !$aRecord )
		{
			if( $db_sql_result)	
				mysqli_free_result($db_sql_result);
	
			$db_sql_result = NULL;
		}
	
		if( isset( $aRecord ))
			return $aRecord;
	
		return NULL;
	}
	
	function _dbInsert( $nomeTabella, $record) // record singolo
	{
		global $db_sql;
	
		if( !isset( $db_sql) || ($db_sql == NULL))
			return -1;
	
		if( !isset( $record) || !is_array($record))
			return -2;
	
		if($nomeTabella == "") return -26;
		
		//
		// a scanso di equivoci, id è sempre e solo in lettura
		//
		if( isset( $record['id']))
			unset( $record['id']);
	
		$q = "INSERT INTO " . trim($nomeTabella) . " (";
	
	
		$t = 0;
		foreach($record as $chiave=>$valore) 
		{
			if( $chiave == "")
				return -4;
	
			if($t++)
				$q .= "," . $chiave;
			else
				$q .= $chiave;
		}
	
	
		$q .= ") VALUES ('";
	
		$t = 0;
		foreach($record as $valore) {
	
			if($t++)
				$q .= "','" . sanificator($valore);
			else
				$q .= sanificator($valore);
		}
	
		$q .= "');";
	
	
	   if (!mysqli_query($db_sql, $q))
	      return -30;
	
	   return mysqli_insert_id($db_sql);
	}
	
	function _dbUpdate( $nomeTabella, $record, $campo, $valoreComp) // where $campo == $valoreComp
	{
		global $db_sql;
	
		if( !isset( $db_sql) || ($db_sql == NULL)) return -1;
	
		if( !isset( $record) || !is_array($record)) return -2;
	
		if($campo == "") return -23;
	
		if($nomeTabella == "") return -26;
	
		// a scanso di equivoci, id solo in lettura
		if( isset( $record['id']))
			unset( $record['id']);
		
		$q = "UPDATE " . trim($nomeTabella) . " SET ";
	
		$t = 0;
		foreach($record as $chiave=>$valore) {
			if($t++)
				$q .= "," . $chiave . "='" . sanificator($valore) . "' ";
			else
				$q .= $chiave . "='" . sanificator($valore) . "' ";
		}
	
		$q .= " WHERE " . $campo . "='" . sanificator($valoreComp) . "';";
	
		if (!mysqli_query($db_sql, $q))
	        	return -33;
	
		return 0;
	}
	
	
	/**
	Validate an email address.
	Provide email address (raw input)
	Returns true if the email address has the email 
	address format and the domain exists.
	*/
	function validEmail($email)
	{
	   $isValid = true;
	   $atIndex = strrpos($email, "@");
	   if (is_bool($atIndex) && !$atIndex)
	   {
	      $isValid = false;
	   }
	   else
	   {
	      $domain = substr($email, $atIndex+1);
	      $local = substr($email, 0, $atIndex);
	      $localLen = strlen($local);
	      $domainLen = strlen($domain);
	      if ($localLen < 1 || $localLen > 64)
	      {
	         // local part length exceeded
	         $isValid = false;
	      }
	      else if ($domainLen < 1 || $domainLen > 255)
	      {
	         // domain part length exceeded
	         $isValid = false;
	      }
	      else if ($local[0] == '.' || $local[$localLen-1] == '.')
	      {
	         // local part starts or ends with '.'
	         $isValid = false;
	      }
	      else if (preg_match('/\\.\\./', $local))
	      {
	         // local part has two consecutive dots
	         $isValid = false;
	      }
	      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
	      {
	         // character not valid in domain part
	         $isValid = false;
	      }
	      else if (preg_match('/\\.\\./', $domain))
	      {
	         // domain part has two consecutive dots
	         $isValid = false;
	      }
	      else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/',str_replace("\\\\","",$local)))
	      {
	         // character not valid in local part unless 
	         // local part is quoted
	         if (!preg_match('/^"(\\\\"|[^"])+"$/',
	             str_replace("\\\\","",$local)))
	         {
	            $isValid = false;
	         }
	      }
	      if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")))
	      {
	         // domain not found in DNS
	         $isValid = false;
	      }
	   }
	   return $isValid;
	}
	
	
	// -------------------------------------------------------
	// serve per risolvere il problema del blocco in caso
	// di separatore ""
	function _explode( $separator, $stringa, $parameters=NULL)
	{
		if( $separator == "" )
		{
			$ret = array();
			$ret[] = "";
			return $ret;
		}
		try
		{
			if( $parameters === NULL )
				return @explode( $separator, $stringa);
			else
				return @explode( $separator, $stringa, $parameters);
	 	}
		catch (Exception $e)
		{
			$ret = array();
			$ret[] = "";
			return $ret;
		}
	}
	// -------------------------------------------------------
	
	
	
	
	/// ---------------------------------------------------------------
	/// CLASSE DATABASE è in /var/www/html/libs
	/// ---------------------------------------------------------------
	require("sia/_libs/dbClass.inc.php");
	require("sia/project/project.inc.php");
	//1 ELIMINATO:
	//1 _[ELIMINATO da versione DO0]
	//1 ---------------------------------------------------------------	
	$gbl_struct = array(); /// metto la struttura della tabella in esame, campi: nome, tipo, lunghezza->direttamente dal DATABASE
	$gbl_tableName = "";
	$gbl_masterFunction = "";
	$gbl_nomeCampoTitolo = "";
	$gbl_nomeTipo = "ADMIN STANDALONE";
	$gbl_session = array(); // tb_parametro (parametri di sessione)
	$gbl_idSessione = 0; // GESTITO SE POSSO ACCEDERE AL DATABASE
	/// ---------------------------------------------------------------	
	unset( $dbcore );
	$gbl_userData = array();
	$gbl_query = ""; // query forzata (se necessaria) per le pagine interne
	$gbl_stack = array();
	$gbl_father = 0;
	$gbl_anyFilterOn = false; /// server per attivare il pulsante "filtro" rosso, nel caso ci sia qualche filtro attivo
	// ----------------------------------------------------------------
	// AGGIUNTO NELLA VERSIONE STANDALONE
	$xurl = $_SERVER['HTTP_HOST'];
	$xurl = strtolower( $xurl);
	$gbl_myFullUrl = trim( $xurl);
	$tmpArray = explode(".",$gbl_myFullUrl);
	$gbl_mainDomain = count($tmpArray) > 2 ? trim($tmpArray[1]) . "." . trim($tmpArray[2]) : $gbl_myFullUrl;
	$gbl_subDomain = count($tmpArray) > 2 ? trim($tmpArray[0]) : "www";
	$gbl_changePasswordDisabled = TRUE;
	// -----------------------------------------------------------------
	// FACCIO IL CAMBIO DI DIRETTORIO. SE NON VA A BUON FINE
	// SEMPLICEMENTE SIAMO GIA' NEL DIRETTORIO CORRETTO
	// -----------------------------------------------------------------
	//1 ELIMINATO
	//1 	@chdir ( $tip['sub_dir'] );
	// -----------------------------------------------------------------
	// A QUESTO PUNTO, ABBIAMO SPOSTATO IL DIRETTORIO DI DEFAULT 
	// NEL SOTTODIRETTORIO SPECIFICO 
	// -----------------------------------------------------------------
	/// require("_libs/funzioni.inc.php");
	$theEncoding = "UTF-8"; // oppure: "iso-8859-1"
	// -----------------------------------------------------------------
	// VECCHIE VARIABILI, INCLUSE PER PORTABILITA'
	// -----------------------------------------------------------------
	$aCapo = chr(13) . chr(10);
	$APICE = "<<<14_41>>>";
	$VIRGOLETTE = "<<<24_42>>>";
	// ----------------
	// CODIFICA INTERNA
	// ----------------
	mb_internal_encoding($theEncoding);
	mb_http_output($theEncoding);
	/// mb_http_input($theEncoding);
	mb_http_input();
	mb_language('uni');
	mb_regex_encoding($theEncoding);
	ob_start('mb_output_handler');
	
	
	// conserva il risultato delle query
	$db_sql_result = NULL;
	$db_finfo = NULL;
	$db_sql = @mysqli_connect($db_sql_host, $db_sql_user, $db_sql_password, $db_sql_name);
	if ($db_sql == FALSE)
	{
	///	echo "<br>:" . $db_sql_host;
	///	echo "<br>:" . $db_sql_user;
	///	echo "<br>:" . $db_sql_password;
	///	echo "<br>:" . $db_sql_name;
	///	exit();
	///   LA NUOVA REVISIONE FUNZIONA ANCHE SENZA DB
	///   echo "sys error 0129 std";
	///   exit();
	}
	else
	{
		if( isset($_COOKIE['tkS_' . $gbl_subDomain]))
		{
			$tempToken = $_COOKIE['tkS_' . $gbl_subDomain];
			$tempToken = sanitize( $tempToken, "sql", $db_sql);
			$arec = _dbGet("SELECT * FROM tb_sessione WHERE unicode='{$tempToken}';");
			if( isset($arec['id']))
				$gbl_idSessione = $arec['id'];
		}
	}
	@mysqli_set_charset($db_sql, "utf8");
	
	
	
	//0 -----------------------------------------------------------------------------------------------------
	$frm = $_REQUEST['frm'] ?? "main";
	$fx = $_REQUEST['fx'] ?? $frm;
	$gbl_id_oggetto = $_REQUEST['e'] ?? 0; // nessun oggetto oppure il vecchio "e"
	$gbl_tbx = $_REQUEST['tbx'] ?? ""; // parametro opzionale: tabella cui e si riferisce
	$gbl_get = array();
	//0 -----------------------------------------------------------------------------------------------------
	
	if( function_exists("getSeoNameInfo"))
	{
		if( !isset($_REQUEST['frm']) &&
		 !isset($_REQUEST['fx']) )
		{
			$uri = $_SERVER['REQUEST_URI'] ?? "";
			if( trim($uri) != "" )
			{
				$where = getSeoNameInfo( strtolower(trim($uri)));
				$frm = $where['frm'] ?? "main";
				$fx = $where['fx'] ?? "main";
				$gbl_id_oggetto = $where['e'] ?? 0;
				$gbl_tbx = $where['tbx'] ?? 0;
				$gbl_get = $where['get'] ?? array();
			}
		}
	}
	
	//0 -----------------------------------------------------------------------------------------------------
	$frm .= ".php"; // protezione sorgenti, unica modifica al file EXTREEME IV, non può essere usato senza questo accorgimento
	
	$theForm = readSimpleTreeFile( $frm);
	
	
	
	require_once(__DIR__ . "/plugin/vendor/autoload.php");
	if (file_exists(__DIR__ . "/config.php")) {
	    require_once(__DIR__ . "/config.php");
	}
	
	// PER TEST
	$base = 'https://servizi.cslab.info'; /// METADATA XML: OrganizationURL
	$estensioneAggregato = "odgtaa";
	$organizationName = "Ordine Dei Geologi del Trentino Alto Adige"; // Ordine Dei Geologi del Trentino Alto Adige";
	$organizationAcronym = "Ordine Dei Geologi del Trentino Alto Adige";
	$organizationEmail = "info@geologitrentinoaltoadige.it";
	/// ------------------------------------------------------------------
	/// DATI PER Saml.php (SEZIONE AGGREGATOR)
	/// IT03783330131
	/// 03783330131
	/// Creative Software Lab S.r.l.
	/// assistenza@cslab.info
	/// +390395969170
	/// ------------------------------------------------------------------
	/// DATI PER Saml.php (SEZIONE AGGREGATED)
	/// odgtaa // odgtaa
	/// Ordine Dei Geologi del Trentino Alto Adige // Ordine Dei Geologi del Trentino Alto Adige
	// PER ATTIVAZIONE ***************************************************
	/// $base = 'https://acn3.inpt.it'; /// METADATA XML: OrganizationURL*
	/// $estensioneAggregato = "odgtaa";
	/// $organizationName = "Ordine Dei Geologi del Trentino Alto Adige";
	// *******************************************************************
	/// CONFIGURAZIONE HTML
	//2 LA PAGINA DI LOGIN E' IN views/smart-button.php
	//2 -----------------------------------------------
	$c_page_title = "SIA CSLAB S.r.l.";
	$c_page_keywords = "sia, sistema, informativo, aziendale, spid, login";
	$c_page_description = "accesso al sistema informativo CSLAB tramite SPID";
	$c_titolo = "Ordine Dei Geologi del Trentino Alto Adige";
	$c_sottoTitolo = "Area Riservata";
	$c_main_icon = "ogtaa/ogtaa.png";
	$c_eventualeErrore = "";
	$c_home_page_address = "https://servizi.cslab.info"; // dovrebbe essere la pagina esterna principale tipo cslab.info oppure architettitrento.it
	
	$settings = [
	    'sp_entityid' => $base . "/pub-ag-full/" . $estensioneAggregato,
	    'sp_key_file' => './certificate/sp.key',
	    'sp_cert_file' => './certificate/sp.crt',
	    'sp_assertionconsumerservice' => [
	        $base . '/acs'
	    ],
	    'sp_singlelogoutservice' => [
	        [$base . '/slo', "POST"],
	        [$base . '/slo', "REDIRECT"]
	    ],
	    'sp_org_name' => $organizationName,
	    'sp_org_display_name' => $organizationAcronym,
		 /// _[SEZIONE PER LA CREAZIONE IN AUTOMATICO DEL CERTIFICATO DI TEST]
	    'idp_metadata_folder' => './idp_metadata/',
	    'sp_attributeconsumingservice' => [
	        ["name", "familyName", "fiscalNumber", "email"],
	        ["name", "familyName", "fiscalNumber", "email", "spidCode"]
	    ]
	];
	
	$sp = new Italia\Spid\Sp($settings);
	$request_uri = explode('?', $_SERVER['REQUEST_URI'], 2);
	// ---------------------------------------------------------------------------------
	// lavoriamo in un sottodirettorio e quindi gli possiamo togliere la parte iniziale:
	/// $remaining_part = str_replace("/".$estensioneAggregato,"",$request_uri[0]);
	// ---------------------------------------------------------------------------------
	switch ($request_uri[0]) {
	    // Home page
	    case '/':
			//2 ---------------------------------------------------------------------------
			//2 SE NON SONO AUTENTICATO, QUALSIASI SIA LA SITUAZIONE, VADO NELLA PAGINA
			//2 DELLA LOGIN.
			//2 ---------------------------------------------------------------------------
			if ( ! $sp->isAuthenticated())
			{
				setcookie("tk_" . $gbl_subDomain, "", time() -3600, "/", "$gbl_mainDomain", true, true);
				setcookie("tkS_" . $gbl_subDomain, "", time() -3600, "/", "$gbl_mainDomain", true, true);
				session_unset();
				/// {CANCELLO TUTTI I DATI DELLA SESSIONE}
				
				/// -----------------------------------------------------------------------------
				/// A PRESCINDERE, CANCELLO TUTTI I PARAMETRI DI SESSIONE SE LA SESSIONE STESSA
				/// E' SCADUTA. SCELGO COME MOMENTO I LOGIN DEI CLIENTI.
				/// TUTTI I LOGIN CAUSANO LA CANCELLAZIONE DELLE VECCHIE SESSIONI SCADUTE
				/// LE SESSIONI DURANO 30 GIORNI E VENGONO RIUTILIZZATE QUINDI NON SI CORRE IL
				/// RISCHIO CHE UNA SESSIONE SIA CANCELLATA PER ERRORE (AD OGNI CHIAMATA DI INDEX
				/// IL TEMPO DI SESSIONE VIENE RIPRISTINATO (A 30 GG).
				/// -----------------------------------------------------------------------------
				dbQuery("DELETE FROM tb_parametro WHERE tb_sessione='$gbl_idSessione';");
				dbQuery("DELETE FROM tb_sessione WHERE id='$gbl_idSessione';");
				
				
				
				
				require './views/smart-button.php';
				exit();
			}
			//2 ---------------------------------------------------------------------------
			break;
		 case '/totalRecall':
			session_unset();
			break;
	    // Login page
	    case '/login':
	        require './views/login.php';
				exit();
	        break;
	    // Login POST page
	    case '/login-post':
	        require './views/login_post.php';
				exit();
	        break;
	    // Login Smart Button page
	    case '/smart-button':
	        require './views/smart-button.php';
				exit();
	        break;
	    // Metadata page
	    case '/metadata':
	        require './views/metadata.php';
				exit();
	        break;
	    // Acs page
	    case '/acs':
			
			try
			{
				if ($sp->isAuthenticated())
				{
					$spidData = $sp->getAttributes() ?? NULL;
					if( $spidData == NULL )
					{
						session_unset();
						header("Location: info.php?i=1");
						exit();
					}
					
						//2 ----------------------------------------------------------------------
						//2 ENTRATA CON SPID, NON POSSIAMO ENTRARE CON EMAIL PER ORA
						//2 ----------------------------------------------------------------------
						//2 QUI SIAMO AUTENTICATI SICURAMENTE. (PUNTO)
						//2 ----------------------------------------------------------------------
						//2 VERIFICA DEL CODICE FISCALE: E' IL MIO CODICE DI IDENTIFICAZIONE
						$cf = $spidData['fiscalNumber'] ?? "";
						$cf = trim( $cf );
						if( $cf == "" )
						{
							session_unset();
							header("Location: info.php?i=3");
							exit();
						}
						$name = $spidData['name'] ?? "";
						$surname = $spidData['familyName'] ?? "";
						$email = $spidData['email'] ?? "";
						//2 ----------------------------------------------------------------------
						//2 UNUSED
						$spidCode = $spidData['spidCode'] ?? "";
						//2 ----------------------------------------------------------------------
						$name = addslashes($name);
						$surname = addslashes($surname);
						$email = addslashes($email);
						$cf = addslashes($cf);
						//2 ----------------------------------------------------------------------
						//2 UNUSED
						$spidCode = addslashes( $spidCode );
						//2 ----------------------------------------------------------------------
						//2 CARICO I DATI DELL'UTENTE TRAMITE CODICE FISCALE
						$uRec = _dbGet("SELECT * FROM tb_utente WHERE cf='" . $cf . "';");
						if( $uRec == NULL )
						{
							$u = array();
							$u['nome'] = $name . " " . $surname;
							$u['email'] = $email;
							$u['cf'] = $cf;
							$u['tbs_qualifica'] = 1; // USER
							$u['tb_role'] = 3; // USER
							$u['dt_registrazione'] = time();
							$loUserId = db_sql_insert_2("tb_utente", $u);
							// ASSERT: DEVE FARE LA INSERT
							if( $loUserId <= 0 )
							{
								session_unset();
								header("Location: info.php?i=50");
								exit();
							}
							
								//1 --------------------------------------
								//1 NOME UTENTE DIVENTA loUserId
								$token = getFreshToken( $loUserId, $db_sql_name);
								//1 --------------------------------------
								setcookie("tk_" . $gbl_subDomain, $token, [
							    'expires' => time() + 86400,
							    'path' => '/',
							    'domain' => $gbl_mainDomain,
							    'secure' => true,
							    'httponly' => true,
							    'samesite' => 'None',] );
							
							
							
							
							
							header("Location: /");
							exit();
						}
						$loUserId = $uRec['id'];
						
							//1 --------------------------------------
							//1 NOME UTENTE DIVENTA loUserId
							$token = getFreshToken( $loUserId, $db_sql_name);
							//1 --------------------------------------
							setcookie("tk_" . $gbl_subDomain, $token, [
						    'expires' => time() + 86400,
						    'path' => '/',
						    'domain' => $gbl_mainDomain,
						    'secure' => true,
						    'httponly' => true,
						    'samesite' => 'None',] );
						
						
						
						
						
					
						if( isset($_SERVER['REMOTE_ADDR']))
							$ip = $_SERVER['REMOTE_ADDR'];
						else
							$ip = "1.1.1.1";
					
						
						// $rUser
						$log = array();
						$log['data'] = date("Y-m-d H:i:s", time());  
						$log['tb_utente'] = $uRec['id'];
						$log['testo'] = addslashes("L'utente ha fatto un nuovo accesso");
						db_sql_insert_2( "tb_user_log", $log);
						
						
						
						/// ----------------------------------------------
						/// CANCELLO I DATI DI SESSIONE DI TUTTO IL MONDO!
						
						/// -----------------------------------------------------------------------------
						/// A PRESCINDERE, CANCELLO TUTTI I PARAMETRI DI SESSIONE SE LA SESSIONE STESSA
						/// E' SCADUTA. SCELGO COME MOMENTO I LOGIN DEI CLIENTI.
						/// TUTTI I LOGIN CAUSANO LA CANCELLAZIONE DELLE VECCHIE SESSIONI SCADUTE
						/// LE SESSIONI DURANO 30 GIORNI E VENGONO RIUTILIZZATE QUINDI NON SI CORRE IL
						/// RISCHIO CHE UNA SESSIONE SIA CANCELLATA PER ERRORE (AD OGNI CHIAMATA DI INDEX
						/// IL TEMPO DI SESSIONE VIENE RIPRISTINATO (A 30 GG).
						/// -----------------------------------------------------------------------------
						$tempo = time();
						$expired = array();
						/// -----------------------------------------------------------------------------
						/// TUTTE LE SESSIONI SCADUTE *** ANCHE QUELLE DI ALTRI UTENTI ***
						$rec = _dbGet("SELECT * FROM tb_sessione WHERE expires < '{$tempo}';");
						while( $rec != NULL)
						{
							$expired[] =  $rec['id'];
							$rec = _dbGet();
						}
						
						foreach( $expired as $idSessione)
							dbQuery("DELETE FROM tb_parametro WHERE tb_sessione='{$idSessione}';");
						
						dbQuery("DELETE FROM tb_sessione WHERE expires < '{$tempo}';");
						
						
						
						
						/// ----------------------------------------------
						/// CREO IL RECORD DI SESSIONE SE NON PRESENTE
						$gbl_userId = $uRec['id'];
						
						$tempo = time();
						
						$unicode = bin2pck("" . time() . $gbl_userId);
						if( isset( $_COOKIE["tkS_" . $gbl_subDomain]))
							$unicode = sanitize($_COOKIE["tkS_" . $gbl_subDomain], "sql", $db_sql);
						
						$rec = _dbGet("SELECT * FROM tb_sessione WHERE unicode='{$unicode}' AND tb_utente='$gbl_userId';"); // "expires" sarà OK, tutti quelli vecchi li ho appena cancellati
						if( $rec == NULL )
						{
							// ---------------------------------------------------------------------
							//  PER QUALCHE RAGIONE HO IL TOKEN MA NON C'E' IL RECORD DI SESSIONE.
							//2 NON POSSO CANCELLARE EVENTUALI RECORD SPURI RESIDUALI TB_PARAMETRO
							// ---------------------------------------------------------------------
							$r = array();
							$r['unicode'] = $unicode; // NON SERVE SANIFICARE
							$r['tb_utente'] = $gbl_userId;
							$r['expires'] = time() + 2592000;
							db_sql_insert_2("tb_sessione", $r);
							setcookie("tkS_" . $gbl_subDomain, $unicode, [
								'expires' => time() + 86400,
								'path' => '/',
								'domain' => $gbl_mainDomain,
								'secure' => true,
								'httponly' => true,
								'samesite' => 'None'] );
						}
						
						
						//1 --------------------------------------------------------------------------------
						//1 NON DEVO VERIFICARE SE E' IL MOMENTO DI CAMBIARE PASSWORD: SONO ENTRATO CON SPID
						//1 --------------------------------------------------------------------------------
					
			
					header("Location: index.php");
					exit();
				}
				else /// SI FA DOPO
				{
					$theThing = $_SESSION ?? "";
					if( $theThing != "" )
						$theThing = json_encode( $theThing );
					else
					{
						
						if ( isset($_POST['SAMLResponse']) || isset($_GET['SAMLResponse']))
						{
						    $theThing = isset($_GET['SAMLResponse']) ? gzinflate(base64_decode($_GET['SAMLResponse'])) : base64_decode($_POST['SAMLResponse']);
						}
						
						
					}
					$theName = "ACS: not authenticated";
					
					//1 usato per ora solo in index.php (errore 78)
					
						$recordo = array();
						$recordo['nome'] = $theName;
						$recordo['valore'] = $theThing;
						$recordo['data'] = date('Y-m-d H:i:s');
						_dbInsert("tb_x_cose", $recordo);
					
					//1 usato per ora solo in index.php (errore 78)
					
					session_unset();
					header("Location: info.php?i=2");
					exit();
				/// INGRESSO CON EMAIL->
				/// _[PART ACS: GESTIONE LOGIN CASO NON AUTENTICATO]
				}
			}
			catch (Exception $e) 
			{
				$v = hash('crc32b', $e->getMessage());
			
				$theThing = $e->getMessage();
				$theName = "ACS: accesso SPID";
				
				//1 usato per ora solo in index.php (errore 78)
				
					$recordo = array();
					$recordo['nome'] = $theName;
					$recordo['valore'] = $theThing;
					$recordo['data'] = date('Y-m-d H:i:s');
					_dbInsert("tb_x_cose", $recordo);
				
				//1 usato per ora solo in index.php (errore 78)
				
			
				if( contains( $e->getMessage(), "StatusCode is not Success" ))
				{
					header("Location: info.php?i=7&d={$v}");
					exit();
				}
				else
				{
					header("Location: info.php?i=78&d={$v}");
					exit();
				}
			}
			
			
			
			
	        /// require './views/acs.php';
			exit();
			break;
	    // Logout page
	    case '/logout':
				require './views/logout.php';
				exit();
	        break;
	    // Logout POST page
	    case '/logout-post':
	        require './views/logout_post.php';
				exit();
	        break;
	    // Slo page
	    case '/slo':
			try
			{
				if ($sp->isAuthenticated())
					header("Location: info.php?i=6");
				else
					header("Location: index.php?fx=cmdLogout");
			}
			catch (Exception $e) 
			{
				header("Location: info.php?i=8");
				exit();
			}
			
			
			
			
			
			
	        /// require './views/slo.php';
				exit();
	        break;
	    // Everything else
	    /* default:
	        echo "404 not found";
	 		exit();
	        break; */
	}
	
	// echo $gbl_subDomain;
	// exit();
	//echo $_SERVER['REQUEST_URI'];
	//exit();
	
	/// _[EX LOGOUT]
	
	/// _[EX LOGIN]
	
	/// _[EX TRIAGE]
	
	
	
	
	if( isset( $_REQUEST['debug']))
	{
		var_dump($theForm[$fx]);
		exit(0);
	}
	
	if( $theForm == NULL) 
	{
		header("Location: info.php?i=40");
		exit(0);
	}
	
	if( !isset($theForm[$fx]) || !is_array($theForm[$fx]))
	{
		header("Location: info.php?i=41");
		exit(0);
	}
	
	$oDire = $theForm[$fx];
	$gbl_userId = 0; // nessuno
	$gbl_fx = $fx;
	//// --------------------------------------------------------------------------------------
	//// LA VERIFICA DELLO USERTOKEN VIENE FATTA SOLO SE LA PAGINA PREVEDE LA VERIFICA DELLE
	//// QUALIFICHE.
	//// --------------------------------------------------------------------------------------
	if( isset( $oDire['permessi']) && ($oDire['permessi'] != "") && (trim($oDire['permessi']) != "ANY") && !is_array($oDire['permessi'])) 
	{
		//// --------------------------------------------------------------------------------------
		//// VERIFICHIAMO CHE IL TOKEN SIA VALIDO, ALTRIMENTI ANDIAMO ALLA LOGIN
		//// --------------------------------------------------------------------------------------
		$loUserId = isset($_COOKIE["tk_" . $gbl_subDomain]) ? checkToken( $_COOKIE["tk_" . $gbl_subDomain], $db_sql_name): "";
		if( !$loUserId)
		{
			setcookie("tk_" . $gbl_subDomain, "", time() -3600, "/", NULL, true, true);
			session_unset();
			//0 LOGIN PAGE
			header("Location: info.php?i=4");
			exit(0);
		}
		//0 -----------------------------------------------------------------------------------
		//0 CONSERVIAMO LA GESTIONE DI ID COME EMAIL. revisione 13 ottobre 2021
		//0 SEMPLIFICHIAMO LA GESTIONE DEL TOKEN PER CONTENERE UNICAMENTE L'ID (EMAIL) UTENTE
		//0 TUTTI GLI ALTRI DATI ANDRANNO A FINIRE DENTRO $gbl_userData
		//0 -----------------------------------------------------------------------------------
		
		// --------------------------
		// userEmail arriva dal token,
		// quindi è sicuro.
		// $gbl_userData = array(); (già fatto prima)
		/// ------------------------------------------------------------------------------------
		/// LA FUNZIONE VIENE CHIAMATA DOPO AVER CARICATO I DATI DATABASE
		$urec = _dbGet("SELECT id,email,tbs_qualifica,tb_role,nome FROM tb_utente WHERE id='{$loUserId}';");
		// --------------------------
		if( $urec == NULL)
		{
			//0 LOGIN PAGE
			header("Location: info.php?i=4");
			exit(0);
		}
		$gbl_userData['id'] = isset( $urec['id']) ? $urec['id'] : 0;
		$gbl_userData['email'] = isset( $urec['email']) ? $urec['email'] : "";
		$gbl_userData['nome'] = isset( $urec['nome']) ? $urec['nome'] : "";
		// --------------------------------------------------------------------------------------
		// CALCOLIAMO LE QUALIFICHE
		// --------------------------------------------------------------------------------------
		if( !isset( $urec['tbs_qualifica']))
		{
			//0 LOGIN PAGE
			header("Location: info.php?i=4");
			exit(0);
		}
		$quals = explode(",", $urec['tbs_qualifica']);
		$query = "";
		if( is_array( $quals))
		{
			foreach( $quals as $qua )
			{
				if( $query == "" )
					$query = " id='{$qua}'";
				else
					$query .= " OR id='{$qua}'";
			}
		}
		$quals = "";
		if( $query != "" )
		{
			$query = "SELECT id,nome FROM tbs_qualifica WHERE " . $query . ";";
			$rec = _dbGet($query);
			while( isset($rec['nome']))
			{
				if( $quals == "" )
					$quals = $rec['nome'];
				else
					$quals .= "," . $rec['nome'];
				$rec = _dbGet();
			}
		}
		$gbl_userData['qualifiche'] = $quals;
		// --------------------------------------------------------------------------------------
		// CALCOLIAMO IL RUOLO
		// --------------------------------------------------------------------------------------
		if( !isset( $urec['tb_role']))
		{
			//0 LOGIN PAGE
			header("Location: info.php?i=4");
			exit(0);
		}
		$rec = _dbGet("SELECT id,titolo FROM tb_role WHERE id='" . intval($urec['tb_role']) . "';");
		$gbl_userData['ruolo'] = isset($rec['titolo']) ? $rec['titolo'] : "";
		/// ------------------------------------------------------------------------------------
		if( $gbl_userData['ruolo'] == "" )
		{
			//0 LOGIN PAGE
			header("Location: info.php?i=4");
			exit(0);
		}
		
		
		
		
		//  -----------------------------------------------------------------------------------
		//  LA STRUTTURA $GBL_USERDATA A QUESTO PUNTO E' VERIFICATA, SIAMO SICURI CHE I DATI 
		//  SONO CONGRUENTI
		//  -----------------------------------------------------------------------------------
		$gbl_userId = $gbl_userData['id'];
		$ricPermessi = $oDire['permessi'];
		$permessi = $gbl_userData['qualifiche'];
		$permessiAr = explode(",", $permessi);
		$ricPermessiAr = explode(",", $ricPermessi);
	
		foreach( $ricPermessiAr as $permesso)
		{
			if( !in_array( $permesso, $permessiAr)) 
			{
				header("Location: info.php?i=4");
				exit(0);
			}
		}
		//// ---------------------------------------------------------------------------------
		$aFreshToken = getFreshToken( $loUserId, $db_sql_name);
		setcookie( "tk_" . $gbl_subDomain, $aFreshToken, [
	    'expires' => time() + 86400,
	    'path' => '/',
	    'domain' => $gbl_mainDomain,
	    'secure' => true,
	    'httponly' => true,
	    'samesite' => 'None',] );
		/// LA GESTIONE E' UNICAMENTE SE SEI GIA' LOGGATO
		
		$tempo = time();
		
		$unicode = bin2pck("" . time() . $gbl_userId);
		if( isset( $_COOKIE["tkS_" . $gbl_subDomain]))
			$unicode = sanitize($_COOKIE["tkS_" . $gbl_subDomain], "sql", $db_sql);
		
		$rec = _dbGet("SELECT * FROM tb_sessione WHERE unicode='{$unicode}' AND tb_utente='$gbl_userId';"); // "expires" sarà OK, tutti quelli vecchi li ho appena cancellati
		if( $rec == NULL )
		{
			// ---------------------------------------------------------------------
			//  PER QUALCHE RAGIONE HO IL TOKEN MA NON C'E' IL RECORD DI SESSIONE.
			//2 NON POSSO CANCELLARE EVENTUALI RECORD SPURI RESIDUALI TB_PARAMETRO
			// ---------------------------------------------------------------------
			$r = array();
			$r['unicode'] = $unicode; // NON SERVE SANIFICARE
			$r['tb_utente'] = $gbl_userId;
			$r['expires'] = time() + 2592000;
			$gbl_idSessione = db_sql_insert_2("tb_sessione", $r);
		}
		else
		{
			$rec['expires'] = time() + 2592000;
			db_sql_update_2("tb_sessione", $rec, "id", $rec['id']);
		}
		
		setcookie("tkS_" . $gbl_subDomain, $unicode, [
			'expires' => time() + 86400,
			'path' => '/',
			'domain' => $gbl_mainDomain,
			'secure' => true,
			'httponly' => true,
			'samesite' => 'None'] );
		
	}
	
	/// header('Content-Type: text/html; charset=utf-8');
	echo _parser( $theForm[$fx] );
	
	
	@mysqli_close($db_sql); 
	exit();
?>

