<?php
/**
 * This file is part of an ADDON for use with LEPTON Core.
 * This ADDON is released under the GNU GPL.
 * Additional license terms can be seen in the info.php of this module.
 *
 * @module          Droplets
 * @author          LEPTON Project
 * @copyright       2010-2026 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         https://gnu.org/licenses/gpl.html
 * @license_terms   please see info.php of this module
 *
 */

// include secure.php to protect this file and the whole CMS!
if(!defined("SEC_FILE")){define("SEC_FILE",'/framework/secure.php' );}
if (defined('LEPTON_PATH')) {	
	include LEPTON_PATH.SEC_FILE;
} else {
	$oneback = "../";
	$root = $oneback;
	$level = 1;
	while (($level < 10) && (!file_exists($root.SEC_FILE))) {
		$root .= $oneback;
		$level += 1;
	}
	if (file_exists($root.SEC_FILE)) { 
		include $root.SEC_FILE;   
	} else {
		trigger_error(sprintf("[ <b>%s</b> ] Can't include secure.php!", $_SERVER['SCRIPT_NAME']), E_USER_ERROR);
	}
}
// end include secure file

/**
 * @param $_x_codedata
 * @param $_x_varlist
 * @param $oLEPTON_page_data
 * @return mixed
 */
function do_eval($_x_codedata, $_x_varlist, &$oLEPTON_page_data)
{
    extract($_x_varlist, EXTR_SKIP);
    return (eval($_x_codedata));
}

function processDroplets(string &$oLEPTON_page_data ): bool
{
    // collect all droplets from document
    $droplet_tags = [];
    $droplet_replacements = [];

    if (preg_match_all('/\[\[(.*?)\]\]/', $oLEPTON_page_data, $found_droplets))
    {
        foreach ($found_droplets[1] as $droplet)
        {
            if (array_key_exists('[[' . $droplet . ']]', $droplet_tags) === false)
            {
                // go in if same droplet with same arguments is not processed already
                $varlist = [];
                // split each droplet command into droplet_name and request_string
                $tmp            = preg_split( '/\?/', $droplet, 2 );
                $droplet_name   = $tmp[ 0 ];
                $request_string = (isset($tmp[1]) ? $tmp[1] : '');
                if ( $request_string != '' )
                {
                    // make sure we can parse the arguments correctly
                    $request_string = html_entity_decode( $request_string , ENT_COMPAT, ini_get("default_charset")); // , DEFAULT_CHARSET );
                    // create array of arguments from query_string
                    $argv = preg_split( '/&(?!amp;)/', $request_string );
                    foreach ($argv as $argument)
                    {
                        // split argument in pair of varname, value
                        list($variable, $value) = explode('=', $argument, 2);
                        if (!empty($value))
                        {
                            // encode the value again and push the var to the varlist
                            $varlist[$variable] = html_entity_decode($value, ENT_COMPAT, ini_get("default_charset"));
                        }
                    }
                }
                else
                {
                    // no arguments given, so
                    $droplet_name = $droplet;
                }
                // request the droplet code from database
                $sql      = 'SELECT `code` FROM `' . TABLE_PREFIX . 'mod_droplets` WHERE `name` LIKE "' . $droplet_name . '" AND `active` = 1';
                $codedata = LEPTON_database::getInstance()->get_one( $sql );
                if (!is_null($codedata))
                {
                    $newvalue = do_eval($codedata, $varlist, $oLEPTON_page_data);
                    // check returnvalue (must be a string of 1 char at least or (bool)true
                    if ($newvalue == '' && $newvalue !== true)
                    {
                        if (DEBUG === true)
                        {
                            $newvalue = '<span class="mod_droplets_err">Error in: ' . $droplet . ', no valid returnvalue.</span>';
                        }
                        else
                        {
                            $newvalue = true;
                        }
                    }
                    if ($newvalue === true)
                    {
                        $newvalue = "";
                    }
                    // remove any defined CSS section from code. For valid XHTML a CSS-section is allowed inside <head>...</head> only!
                    $newvalue = preg_replace('/<style.*>.*<\/style>/siU', '', $newvalue);
                    // push droplet-tag and it's replacement into Search/Replace array after executing only
                }
                else
                {
                    // just remove droplet placeholder if no code was found
                    if (DEBUG === true)
                    {
                        $newvalue = '<span class="mod_droplets_err">No such droplet: ' . $droplet . '</span>';
                    }
                    else
                    {
                        $newvalue = "**No such droplet: ".$droplet."**";
                    }
                }
                $droplet_tags[]         = '[[' . $droplet . ']]';
                $droplet_replacements[] = $newvalue;
            }
        }   // End foreach( $found_droplets[1] as $droplet )
        // replace each Droplet-Tag with corresponding $newvalue
        $oLEPTON_page_data = str_replace($droplet_tags, $droplet_replacements, $oLEPTON_page_data);
    }
    // returns TRUE if droplets found in content, FALSE if not
    return (!empty($droplet_tags));
}

/**
 * @notice  Since L* 7.3 the function is nullable.
 *
 * @param   string|null  $oLEPTON_page_data HTML source of the generated page. Call by reference!
 * @param   int     $max_loops The maximum iteration?
 *
 * @return  void    As the HTML source is passed by reference.
 *
 */
function evalDroplets(string|null &$oLEPTON_page_data, int $max_loops = 3): void
{
    if (!is_null($oLEPTON_page_data))
    {
        $max_loops = ((int)$max_loops === 0 ? 3 : (int)$max_loops);
        while ((processDroplets($oLEPTON_page_data) === true) && ($max_loops > 0))
	    { 
		    $max_loops--;
	    }
	}
}
