<?php

/**
 * This file is part of LEPTON Core, released under the GNU GPL
 * Please see LICENSE and COPYING files in your package for details, specially for terms and warranties.
 * 
 * NOTICE:LEPTON CMS Package has several different licenses.
 * Please see the individual license in the header of each single file or info.php of modules and templates.
 *
 * @author          LEPTON Project
 * @copyright       2010-2021 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         http://www.gnu.org/licenses/gpl.html
 * @license_terms   please see LICENSE and COPYING files in your package
 *
 */

/**
 *  Extended methods for LEPTON_database
 *
 */
trait LEPTON_secure_database
{
    
    static private  $db_key = 0;
    
    static private  $default_openssl_method = 0;
    
    static private  $default_openssl_iv = 0;
    
    static private  $default_openssl_ivlen = 0;
    
    static private  $default_openssl_options = 0;
    
    /**
     *  To encrypt any string.
     *  @param  string  $sSource    Any string
     *  @return string  The crypted string.
     */
    protected function cryptString( $sSource="" )
    {
        if( 0 === self::$default_openssl_method )
        {
            echo LEPTON_tools::display("UNABLE to crypt source! Keep source untouched.", "pre", "ui message red");
            return $sSource;
        }
        return openssl_encrypt(
            $sSource,
            self::$default_openssl_method,
            self::$db_key,
            self::$default_openssl_options,
            self::$default_openssl_iv
        );
    }

    /**
     *  To decrypt any string.
     *  @param  string  $sSource    Any crypted string.
     *  @return string  The crypted string.
     */    
    protected function decryptString( $sSource )
    {
        if( 0 === self::$default_openssl_method )
        {
            return $sSource;
        }
        return openssl_decrypt(
            $sSource,
            self::$default_openssl_method,
            self::$db_key,
            self::$default_openssl_options,
            self::$default_openssl_iv
        );
    }

    /** *********************
     *  [1] Interface functions
     *
     */
    
    /**
     *  Set the method
     *  @param  string $sMethodName A valid Method
     *  @return nothing
     */
    public function setOpenSSLMethod($sMethodName)
    {
        $this->default_openssl_method = $sMethodName;
    }

    /**
     *  Set the iv
     *  @param  string $sNewIV A valid iv (16 byptes!)
     *  @return nothing
     */    
    public function setOpenSSLIv( $sNewIV )
    {
        $this->default_openssl_iv = $sNewIV;
    }
    
    /**
     *  Handle static calls
     *
     *  @example
     *          // crypt
     *          LEPTON_database::cryptString( "aladin" );
     *      or
     *          // decrypt
     *          LEPTON_database::decryptstring( $sAnyCrypedString );
     *      or
     *          // ERROR! unknown/undeclared method
     *          LEPTON_database::super(); // THIS WILL THROW AN ERROR MESSAGE! 
     */
    public static function __callStatic($method, $args) {
        switch( strtolower( $method ))
        {
            case 'cryptstring':
                return self::$instance->cryptString( $args[0] );
                break;
                
            case 'decryptstring':
                return self::$instance->decryptString( $args[0] );
                break;
                
            default:
                echo LEPTON_tools::display("Static call to unknown method!", "pre", "ui message red");
                return NULL;
                break;
        }
    }
    
    /** *********************
     *  [2] New class methods
     *
     */
     
    /**
     *	Execute a SQL query and return the first row of the result array
     *
     *	@param	string	Any SQL-Query or statement
     *
     *	@return	mixed 	Value of the table-field or NULL for error
     */
    public function secure_get_one($SQL)
    {
        $result = $this->get_one($SQL);
        return ($result === NULL)
            ? NULL
            : $this->decryptString( $result )
            ;
    }

    /**
     *	Public "shortcut" for executeing a single mySql-query without passing values.
     *
     *
     *	@param	string	$aQuery     A valid mySQL query.
     *	@param	bool	$bFetch     Fetch the result - default is false.
     *	@param	array	$aStorage   A storage array for the fetched results. Pass by reference!
     *	@param	bool	$bFetchAll  Try to get all entries. Default is true.
     *  @param	string	$aListOfFields  A linear array with the fieldnames to de-crypt.
	 *
	 *	@return	bool	False if fails, otherwise true.
	 *
	 * @example
     *	$results_array = array();       
     *  $this->db_handle->execute_query( 
	 * 			"SELECT * from ".TABLE_PREFIX."pages WHERE page_id = '".$page_id."' ",
	 *			true, 
	 *			$results_array, 
	 *			false,
	 *          array('modify_by') 
	 *	);
     *   	 
     *
     */
    public function secure_execute_query( $aQuery="", $bFetch=false, &$aStorage=array(), $bFetchAll=true, $aListOfFields=array() ) {
		
		if(!is_array( $aListOfFields ))
		{
		    LEPTON_tools::display("REQUIRED list of fieldnames must be an array!", "div", "ui message red");
		    return false;
		}
		
		$result = $this->execute_query(
		    $aQuery,
		    $bFetch,
		    $aStorage,
		    $bFetchAll
		);
		
		if(false === $result)
		{
		    LEPTON_tools::display( $this->get_error(), "div", "ui message red");
		    return false;
		}
		
		if( true === $bFetchAll )
		{
		    foreach( $aStorage as &$ref)
		    {
		        foreach($aListOfFields as $sFieldname)
		        {
		            if(isset($ref[ $sFieldname ]))
		            {
		                $ref[ $sFieldname ] = $this->decryptString( $ref[ $sFieldname ] );
		                
		            }
		        }
		    }
		} else {
            foreach($aListOfFields as $sFieldname)
		    { 
		        if(isset($aStorage[ $sFieldname ]))
		        {
		            $aStorage[ $sFieldname ] = $this->decryptString( $aStorage[ $sFieldname ] );
		        }
		    }
		}
		
		return true;
    }

    /**
     *	Public function to build and execute a mySQL query direct.
     *	Use this function/method for update and insert values only.
     *	As for a simple select you can use "prepare_and_execute" above.
     *
     *	@param	string	$type           A "job"-type: this time only "update" and "insert" are supported.
     *	@param	string	$table_name     A valid tablename (incl. table-prefix).
     *	@param	array	$table_values   An array within the table-field-names and values. Pass by reference!
     *	@param	string	$condition      An optional condition for "update" - this time a simple string.
     *  @param	string	$aListOfFields  A linear array with the fieldnames to crypt.
     *  @param  string  $key            An optional "no update" key field to be excluded on update while "insert_on_duplicate_key_update" - a simple string containing 1 key field.
     *
     *	@return	bool	False if fails, otherwise true.
     *
     */
    public function secure_build_and_execute( $type, $table_name, $table_values, $condition="", $aListOfFields=array(), $key="" ) {
    	
        if(!is_array( $aListOfFields ))
		{
		    LEPTON_tools::display("REQUIRED list of fieldnames must be an array!", "div", "ui message red");
		    return false;
		}
		
    	foreach( $aListOfFields as $sName)
    	{
    	    if(isset($table_values[ $sName ]))
    	    {
    	        $table_values[ $sName ] = $this->cryptString( $table_values[ $sName ] );
    	    }
    	}
    	
    	return $this->build_and_execute(
    	    $type,
    	    $table_name,
    	    $table_values,
    	    $condition,
    	    $key
    	); 
    }
}

?>