<?php

declare(strict_types=1);

/**
 * 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-2026 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         https://gnu.org/licenses/gpl.html
 * @license_terms   please see LICENSE and COPYING files in your package
 *
 */


/**
 *    Class to handle values out the $_POST or $_GET
 */
 
class LEPTON_request
{
    use LEPTON_singleton;

    const USE_POST    = "post";
    const USE_GET     = "get";
    const USE_REQUEST = "request";
    const USE_SESSION = "session";
    const USE_SERVER  = "server";

    const ALLOWED_INSIDE = [
        self::USE_POST,
        self::USE_GET,
        self::USE_REQUEST,
        self::USE_SESSION,
        self::USE_SERVER
    ];

    public static $instance;

    /**
     *  Public var to handle the way the class should look for the value;
     *  supported types are 'post', 'get' or 'request'
     *
     *  @type       string
     *  @default    "post"
     *
     */
    protected string $strict_looking_inside = "post";
    
    /**
     *  By default we are not collecting any errors
     *
     *  @since      0.1.0
     *  @type       bool
     *  @default    false
     *
     */
    public bool $error_mode = false;

    /**
     *  The name of the log file of the request errors.
     *
     *  @type string
     *  @access public
     */
    public string $logFileName = "LEPTON_request.log";

    /**
     *  The default path for the (error-) log file.
     *
     *  @type string
     *  @access public
     */
    public string $logFilePath = "/temp/secure/";

    /**
     *  Public var that holds the errors in an array.
     *
     *  @since      0.1.0
     *  @type       array
     *  @default    empty array
     *
     */
    public array $errors = [];

    public function setStrictLookInside(string $sNewValue = ''): bool
    {
        if ($sNewValue === '')
        {
            return false;
        }
        
        $sNewValueLower = strtolower($sNewValue);
        
        if (in_array($sNewValueLower, self::ALLOWED_INSIDE))
        {
            $this->strict_looking_inside = $sNewValueLower;
            return true;
        } else {
            return false;
        }
    }
    
    /**
     *  Testing a list of values against the $_POST array and returns a linear list of the results.
     *
     *  @param  array   An array with an assoc. subarray for the 'keys' to test for.
     *
     *  @code{.php}
     *  // a simple list of values to test agains $_POST
     *  $aLookUp = [
     *       'page_id'      => ['type' => 'integer+', 'default' => null],
     *       'section_id'   => ['type' => 'integer+', 'default' => null],
     *       'hello_text'   => ['type' => 'string', 'default' => ''],
     *       'content'      => ['type' => 'string_chars', 'default' => ""],
     *       'text'         => ['type' => 'string_clean', 'default' => ""],
     *       'input'        => ['type' => 'string_allowed', 'default' => "", 'range' =>['h1','h2','h3'] ]
     *   ];
     *
     *  @endcode
     *
     *  @return array   The results as an assoc. array.
     *
     */
    public function testPostValues(array &$aValueList ): array
    {
        $this->strict_looking_inside = "post";
        
        $aReturnList = [];
        foreach($aValueList as $term => $options)
        {
            $aReturnList[ $term ] = $this->get_request( 
                $term, 
                $options['default'], 
                $options['type'], 
                (isset($options['range']) ? $options['range'] : "" )
            );
        }
        
        return $aReturnList;
    }
        
    /**
     *  Testing a list of values against the $_GET array and returns a linear list of the results.
     *  This method is similar to ::testPostValues
     *
     *  @param  array   An array with an assoc. subarray for the 'keys' to test for.
     *
     *  @code{.php}
     *  // a simple list of values to test agains $_GET
     *  $aLookUp = array(
     *       'page_id'      => array('type' => 'integer+', 'default' => null),
     *       'section_id'   => array('type' => 'integer+', 'default' => null),
     *       'hello_text'   => array('type' => 'string', 'default' => ''),
     *       'content'      => array('type' => 'string_chars', 'default' => ""),
     *       'text'         => array('type' => 'string_clean', 'default' => ""),
     *       'input'        => array('type' => 'string_allowed', 'default' => "", 'range' => array('h1','h2','h3') )
     *   );
     *
     *  @endcode
     *
     *  @return array   The results as an assoc. array.
     *
     */
    public function testGetValues(array &$aValueList): array
    {
        $this->strict_looking_inside = "get";
        
        $aReturnList = [];
        foreach($aValueList as $term => $options)
        {
            $aReturnList[ $term ] = $this->get_request(
                $term,
                $options['default'],
                $options['type'],
                (isset($options['range']) ? $options['range'] : "" )
            );
        }
        
        return $aReturnList;
    }

    /**
     * Same as above but not force to an entry like e.g. $_GET or $_POST
     *
     * @param  array   An array with an assoc. subarray for the 'keys' to test for.
     * @return array   The results as an assoc. array.
     *
     */
    public function testValues(array &$aValueList): array
    {
        $aReturnList = [];
        foreach($aValueList as $term => $options)
        {
            $aReturnList[ $term ] = $this->get_request(
                $term,
                $options['default'],
                $options['type'],
                (isset($options['range']) ? $options['range'] : "" )
            );
        }
        
        return $aReturnList;
    }


    /**
     *
     *  Public function that looks for a value in the $_POST or $_GET super-variables.
     *  If it is found and the type match it is returned. If not, the given default
     *  value is returned. There are also optional settings for the situation, the
     *  value has to be in a given range, and/or the string has to be a given size.
     *
     * @param string  name    Name of the value/key
     * @param mixed   default (optional) The default of this value
     * @param string  type    (optional) The type of the value, see list below
     * @param array   range   (optional) The settings for testing if the value is inside a range.
     *
     * @retuns mixed   the value
     *
     *  NOTICE: the range-settings have no effekt if the default-value is set to null.
     *
     *
     *  Supported types are (quick-, short-, long-notation)
     *
     *  integer     Any integer
     *  integer+    Any positive integer +0
     *  integer-    Any negative integer +0
     *
     *  string      Any string
     *  string_clean    Any string - HTML tags will be removed!
     *  string_chars    Any String - but tags are converted via htmlspecialchars!
     *  string_allowed  Any String - HTML tags are removed, exept the given one in "range"!
     *
     *  email   Any mail adress
     *  array   Any array (e.g. from a multible select)
     *
     *  Range got following keys/options
     *
     *      min     the minmium, as for integers the lowest number, as for strings the min. number of chars.
     *              default: 0;
     *
     *      max     the maximum, as for integers the heights number, as for strings the max. number of chars.
     *              default: 255;
     *
     *      use     what kind of use if the value is not inside the range, supported types are
     *              - default   use the given default value (integer, string, null)
     *              - min       however (value is less or more out of the range) use the min-value.
     *              - max       however (value is less or more out of the range) use the max-value.
     *              - near      if the value is less, use the min-value, if it is more, use the max-value.
     *              - fill      only for strings.
     *              - cut       only for strings.
     *                          default: 'default'
     *
     *      char    default: ' 'if #fill is used and the number of chars is less than the min-value,
     *              the string is 'filled' up with this char.
     *              default: ' ' (space|blank)
     *
     *  If one of the keys/options is missing, the default-settings are used.
     *  NOTICE: the range-settings have no effekt if the default-value is set to null.
     *
     * @throws Exception
     */

    public function get_request(string $aName="", string|int|array|float|bool|null $aDefault=null, string $type="", string|array $range="")
    {
        
        if ($aName == "")
        {
            return null;
        }

        if (false === $this->strict_looking_inside)
        {

            if (strtoupper($_SERVER['REQUEST_METHOD']) == "POST")
            {
                $return_value = (true === array_key_exists ($aName , $_POST) ) ? $_POST[$aName] : $aDefault;
            } 
            else 
            {
                $return_value = (true === array_key_exists ($aName , $_GET) ) ? $_GET[$aName] : $aDefault;
            }
        } 
        else 
        {
            switch ($this->strict_looking_inside) 
            {
                case self::USE_POST:
                    $return_value = $_POST[$aName] ?? $aDefault;
                    break;
                    
                case self::USE_GET:
                    $return_value = $_GET[$aName] ?? $aDefault;
                    break;
                    
                case self::USE_REQUEST:
                    $return_value = $_REQUEST[$aName] ?? $aDefault;
                    break;
                 
                case self::USE_SESSION:
                    $return_value = $_SESSION[$aName] ?? $aDefault;
                    break;
                    
                case self::USE_SERVER:
                    $return_value = $_SERVER[$aName] ?? $aDefault;
                    break;
                       
                default:
                    $return_value = null;
                    break;
            }
        }
        
        if (!empty($type)) 
        {
            // $this->testType($aName, $type, gettype($return_value));
            
            if (is_array($return_value) && ($type != "array"))
            {
                foreach ($return_value as $key => &$tempValue)
                {
                    $tempValue = $this->filterValue($tempValue, $type, $aDefault, $range);
                }
            }
            else
            {
                $return_value = $this->filterValue($return_value, $type, $aDefault, $range);
            }
        }
        return $return_value;     
    }

    static public function add_slash(string &$sText="" ): void 
    {
        if (substr($sText, 0,1) != "/")
        {
            $sText = "/".$sText;
        }
        
        if (substr($sText, -1) != "/")
        {
            $sText .= "/";
        }
    }
    
    private function check_range(string $type, int|string|array|float &$value, int|string|array|float|null &$default, string|array|float|int &$range)
    {

        if (is_null($value))
        {
            return true;
        }

        if (!array_key_exists('use', $range))
        {
            $range['use'] = 'default';
        }

        if (!array_key_exists('min', $range))
        {
            switch (strtolower($type))
            {
                case 'date':
                    $range['min'] = '2000-01-01';
                    break;

                case 'datetime':
                case 'timestamp':
                    $range['min'] = '2000-01-01 00:00:00';
                    break;

                case 'time':
                    $range['min'] = "00:00";
                    break;
                    
                default:
                    $range['min'] = 0;
                    break;
            }
        }

        if (!array_key_exists('max', $range))
        {
            switch (strtolower($type))
            {
                case 'date':
                    $range['max'] = '2048-01-01';
                    break;

                case 'datetime':
                case 'timestamp':
                    $range['max'] = '2048-12-31 23:59:59';
                    break;

                case 'time':
                    $range['max'] = "23:59";
                    break;
                    
                default:
                    $range['max'] = 255;
                    break;
            }
        }

        if (!array_key_exists('char', $range))
        {
            $range['char'] = " ";
        }

        switch (strtolower($type) )
        {
            case 'integer':
            case 'integer+':
            case 'integer-':
            case 'integer_eval':
            case 'float':
            case 'number':
                if (($value < $range['min']) || ($value > $range['max']))
                {
                    switch (strtolower($range['use']))
                    {
                        case 'default':
                            $value = $default;
                            break;
                            
                        case 'min':
                            $value = $range['min'];
                            break;
                            
                        case 'max':
                            $value = $range['max'];
                            break;
                            
                        case 'near':
                            if ($value <= $range['min'])
                            {
                                $value = $range['min'];
                            }

                            if ($value >= $range['max'])
                            {
                                $value = $range['max'];
                            }
                            break;

                        default:
                            // nothing
                            break;
                    }
                }
                break;

            case 'string':
                $nc = strlen($value);

                if (($nc < $range['min']) || ($nc > $range['max']))
                {

                    switch(strtolower($range['use']))
                    {
                        case 'default':
                            $value = $default;
                            break;

                        case 'fill':
                            for ($i=$nc; $i<=$range['min'];$i++)
                            {
                                $value .= $range['char'];
                            }
                            break;

                        case 'cut':
                            $value = substr(
                                $value,
                                0,
                                ( isset($range['max'])
                                    ? intval($range['max'])
                                    : $nc 
                                )
                            );
                            break;

                        default:
                            // nothing - keep value as it is
                            break;
                    }
                }
                break;

            case 'date':
            case 'datetime':
            case 'timestamp':
                $iValue = strtotime($value);
                $iMin = strtotime($range['min']);
                $iMax = strtotime($range['max']);
                if (($iValue < $iMin) || ($iValue > $iMax))
                {
                    switch(strtolower($range['use']))
                    {
                        case 'default':
                            $value = $default;
                            break;

                        case 'min':
                            $value = $range['min'];
                            break;

                        case 'max':
                            $value = $range['max'];
                            break;

                        case 'near':
                            $value = ($iValue < $iMin)
                                ? $range['min']
                                : $range['max']
                                ;

                        default:
                            // nothing - keep value as it is
                            break;
                    }
                }
                break;

            case 'time':
                $aValue = explode(":", $value);
                $iValue = mktime(intval($aValue[0]),intval($aValue[1]), 0, 1, 1, 1970);
                
                $aMin = explode(":", $range['min']);
                $iMin = mktime(intval($aMin[0]),intval($aMin[1]), 0, 1, 1, 1970);

                $aMax = explode(":", $range['max']);
                $iMax = mktime(intval($aMax[0]),intval($aMax[1]), 0, 1, 1, 1970);
                
                if (($iValue < $iMin) || ($iValue > $iMax))
                {
                    switch(strtolower($range['use']))
                    {
                        case 'default':
                            $value = $default;
                            break;

                        case 'min':
                            $value = $range['min'];
                            break;

                        case 'max':
                            $value = $range['max'];
                            break;

                        case 'near':
                            $value = ($iValue < $iMin)
                                ? $range['min']
                                : $range['max']
                                ;

                        default:
                            // nothing - keep value as it is
                            break;
                    }
                }
                
                break;
                
            default:
                // nothing
                break;
        }
        return true;
    }


    static public function getRequest(string $sField = "")
    {
        $sReturnValue = filter_input(
            INPUT_GET,
            $sField,
            FILTER_VALIDATE_REGEXP,
            [ "options"     => [
                "regexp"    => "~^[a-z0-9-_]{2,}$~i",
                "default"   => null
            ]]
        );

        if (null !== $sReturnValue)
        {
            return $sReturnValue;
        } 
        else 
        {
             return filter_input(
                INPUT_POST,
                $sField,
                FILTER_VALIDATE_REGEXP,
                [ "options"   => [
                      "regexp"    => "~^[a-z0-9-_]{2,}$~i",
                      "default"   => null
                    ]
                ]
            );
        }
    }

    static public function getPageID()
    {
        if (defined("PAGE_ID"))
        {
            return PAGE_ID;
        }
        
        $sField="page_id" ;
         
        $sReturnValue = filter_input(
            INPUT_GET,
            $sField,
            FILTER_VALIDATE_REGEXP,
            [ "options"     => [
                    "regexp"    => "~^[1-9-]?[0-9]*$~",
                    "default"   => null
                ]
            ]
        );

        if (null !== $sReturnValue)
        {
            return $sReturnValue;
        } 
        else 
        {
            return filter_input(
                INPUT_POST,
                $sField,
                FILTER_VALIDATE_REGEXP,
                [ "options"     => [
                        "regexp"    => "~^[1-9-]?[0-9]*$~",
                        "default"   => null
                    ]
                ]
            );
        }
    }

    /**
     * LEPTOPN VII.1
     *
     * @param string|int|array|float|null  $return_value
     * @param string $type
     * @param string|int|array|float|null  $aDefault
     * @param string|array $range
     *
     */
    public function filterValue(
        string|int|array|float|bool|null $return_value,
        string $type,
        string|int|array|float|bool|null $aDefault=null,
        string|array $range=""
    ): string|int|array|float|bool|null
    {
        switch (strtolower($type)) 
        {
            //  [1] Integers
            //  [1.1]
            case 'number':
            case 'integer':
                $return_value = intval($return_value);
                if (!is_int($return_value)) {
                    $return_value = $aDefault;
                } else {
                    if (true === is_array($range))
                    {
                        $this->check_range($type, $return_value, $aDefault, $range);
                    }
                }
                break;
        
            //  [1.2] Only positive integers (without 0)
            case 'integer+':
                $return_value = intval($return_value);
                if (!is_int($return_value))
                {
                    $return_value = $aDefault;
                }
            
                if ($return_value <= 0)
                {
                    $return_value = $aDefault;
                }
            
                if (true === is_array($range) )
                {
                    $this->check_range($type, $return_value, $aDefault, $range);
                }
                break;
            
            //  [1.3] Only negative integers (without 0)
            case 'integer-':
                $return_value = intval($return_value);
                if (!is_int($return_value))
                {
                    $return_value = $aDefault;
                }
            
                if ( $return_value >= 0)
                {
                    $return_value = $aDefault;
                }
            
                if ( true === is_array($range) )
                {
                    $this->check_range($type, $return_value, $aDefault, $range);
                }
                break;
    
            /*  [1.4] decimal
             *      Keep in mind that we only replace the "," (Comma) with "." (decimal-dot)!  
             *      to save a valid value in the database.
             *
             *  e.g. "Win 1.234.300 Euro" will become "1234300"
             *       "1.300.000,34" will become "1300000.34"
             *       "1.300.000.27" will become "1300000.27"
             *       "-23,99" will become "-23.99"
             */ 
            case 'float':
            case 'double':
            case 'decimal': // -12.350,78 
                //  1.4.1 remove all NONE numbers (but keep '.', ',' and '-')                
                $sPattern = "/[^0-9-,\.]/i";
                $return_value = preg_replace (
                    $sPattern, 
                    "",
                    (string)$return_value
                );
            
                //  [1.4.2] replace existing "," with "."
                $return_value = str_replace(",", ".", $return_value);
            
                //  [1.4.3] force to keep at last ONE dot (.)
                $aTemp = explode(".", $return_value);
            
                //  [1.4.3.1] more than one dot found!
                if(count($aTemp) > 2)
                {
                    $sPrefix = array_pop($aTemp);
                    $return_value = implode("", $aTemp).".".$sPrefix;    
                }
            
                //  [1.4.4] the range
                if ( true === is_array($range) )
                {
                    $this->check_range($type, $return_value, $aDefault, $range);
                }
                break;

            //  [1.5] Evaluate an expression. E.g. "3 * 5" results in 15
            case 'integer_eval':
                $return_value = intval(eval("return ".$return_value.";"));

                if (true === is_array($range))
                {
                    $this->check_range($type, $return_value, $aDefault, $range);
                }
                break;

            //  [2] Strings
            //  [2.1]
            case 'string':
                //    keep in mind that pdo add slashes automatically    via prepare and execute
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
            
                if (true === is_array($range))
                {
                    $this->check_range($type, $return_value, $aDefault, $range);
                }
                break;
        
            //  2.2 string without any html tags
            case 'string_clean':      
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                else
                {
                    $return_value = htmlspecialchars(strip_tags($return_value));
                }
                break;

            //  [2.3] string with all html-tags converted to htmlspecialchars
            case 'string_chars':
            
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                else
                {
                    $return_value = lib_lepton::getToolInstance("htmlpurifier")->purify($return_value);
                    $return_value = htmlspecialchars($return_value);
                }
                break;
        
            //  [2.4] string without tags but allowed html-tags
            case 'string_allowed':
        
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                else
                {
                    $return_value = strip_tags($return_value, $range);                    
                }
                break;

            //  [2.5] string only with some chars, see LEPTON_core->string_secure
            case 'string_secure':
                if (false === LEPTON_handle::checkStringSecure($return_value))
                {
                    $return_value = $aDefault;
                }
                break;
                        
            //  [4.1] E-Mail
            case 'email':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                elseif (false === LEPTON_handle::checkEmailChars($return_value))
                {
                    $return_value = $aDefault;
                }
                break;
            
            //  [4.2] username
            case 'username':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                elseif (false === LEPTON_handle::checkUsernameChars($return_value))
                {
                    $return_value = $aDefault;
                }
                break;

            //  [4.3] password      // just to check password chars, NO testing if password is valid
            case 'password':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                }
                elseif (false === LEPTON_handle::checkPasswordChars($return_value))
                {
                    $return_value = $aDefault;
                }
                break;

            //  [5] Date(-s)
            //  [5.1]
            case 'date':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    $format = 'Y-m-d';
                    $d = DateTime::createFromFormat($format, $return_value);
                    $result = $d && $d->format($format) == $return_value;
                    if ($result === false) {
                        $return_value = $aDefault;
                    } else {
                        if (true === is_array($range) )
                        {
                            $this->check_range($type, $return_value, $aDefault, $range);
                        }
                    }
                }
                break;
        
            //  [5.2]
            case 'datetime':
            case 'timestamp':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    $format = 'Y-m-d H:i:s';
                    $d = DateTime::createFromFormat($format, $return_value);
                    $result = $d && $d->format($format) == $return_value;
                    if ($result === false) {
                        $return_value = $aDefault;
                    } else {
                        if (true === is_array($range) )
                        {
                            $this->check_range($type, $return_value, $aDefault, $range);
                        }
                    }
                }
                break;
            
            //  [5.3]
            case 'datetime_local':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    $format = 'Y-m-d\TH:i:s';
                    $d = DateTime::createFromFormat($format, $return_value);
                    $result = $d && $d->format($format) == $return_value;
                    if ($result === false) {
                        $return_value = $aDefault;
                    }
                }
                break;

            //  [5.4]
            case 'month':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    $format = 'Y-m';
                    $d = DateTime::createFromFormat($format, $return_value);
                    $result = $d && $d->format($format) == $return_value;
                    if ($result === false) {
                        $return_value = $aDefault;
                    }
                }
                break;

            //  [5.5]
            case 'time':        // hour 00:00
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    $format = 'H:i';
                    $d = DateTime::createFromFormat($format, $return_value);
                    $result = $d && $d->format($format) == $return_value;
                    if ($result === false) {
                        $return_value = $aDefault;
                    } else {
                        if (true === is_array($range) )
                        {
                            $this->check_range($type, $return_value, $aDefault, $range);
                        }
                    }
                }
                break;

            //  [5.6]
            case 'week':
                if (!is_string($return_value))
                {
                    $return_value = $aDefault;
                } else {
                    // $format = 'Y-W[0-9]{2}';
                    $result = preg_match("/^[1-9][0-9]{3}[-][W][0-9]{2}$/", $return_value);
                    if ($result != 1) {
                        $return_value = $aDefault;
                    }
                }
                break;

            //  [6] Arrays -- Keep in mind that this one could be problematic for recursive requests!
            case 'array':
                if (!is_array($return_value))
                {
                    $return_value = $aDefault;
                }
                break;

            //  [7] RegExp
            case 'regexp':
                if ((true === is_array($range)) && (isset($range['pattern'])))
                {
                    $test = preg_match($range['pattern'], $return_value);
                    if ($test !== 1)
                    {
                        $return_value = $range['default'] ?? $aDefault;
                    }
                }
                break;

            //  [8] Boolean
            case 'bool':
                $return_value = filter_var(
                        $return_value,
                        FILTER_VALIDATE_BOOLEAN,
                        ['flags' => FILTER_NULL_ON_FAILURE]
                        ) ?? $aDefault;
                break;

            //  [9]
            default:
                // nothing above match.
                break;
        }

        return $return_value;
    }
    
    /**
     *  Convert a given formatted string to an array
     *  @param string $input        A formated string.
     *  @param string $delimiter    The item-delimiter. Default is ";".
     *  @param string $subdelimiter The subdelimiter. Default is ":".
     *
     *  @use
     *      $_POST['save_'] = "job: part; id: 11; test: this is a quick check";
     *
     *      LEPTON_request::getStringToArray($_POST["save_"], ";", ":");
     *
     *      results in
     *          [job] => part
     *          [id] => 11
     *          [test] => this is a quick check
     */
    static public function getStringToArray(string $input, string $delimiter=";", string $subdelimiter = ":"): array
    {
        $aTemp = explode($delimiter, $input);
        $aReturn = [];
        foreach ($aTemp as $term)
        {
            if (!empty($term))
            {
                $aTerm = explode($subdelimiter, $term);
                $aReturn[trim($aTerm[0])] = trim($aTerm[1] ?? "");
            }
        }
        return $aReturn;
    }

    protected function testType(string $name, string $expected, string $getTypeResult): void
    {
        if (true === $this->error_mode)
        {
            $types = [
                'string' => ['string', 'str'],
                'integer' => ['integer', 'integer+', 'integer-', 'int', 'int+', 'int-']
            ];
            
            if (isset($types[$getTypeResult]) && (in_array($expected, $types[$getTypeResult])))
            {
            
            }
            else
            {
                $strTemp = "Type does not match! '%s' is not %s. [%s].";
                $this->writeInfoToLogfile(
                    sprintf(
                        $strTemp,
                        $name,
                        $expected,
                        $getTypeResult
                    )
                );
            }
        }
    }
     
    protected function writeInfoToLogfile(string $sMessage=""): void
    {
        $sOutputStrg = "[".date("Y-m-d H:i:s")."] ".$sMessage."\n";
        $sFullPath = dirname(__DIR__, 2).$this->logFilePath.$this->logFileName;
        file_put_contents($sFullPath, $sOutputStrg, FILE_APPEND);
    }

}
