Custom error: [2] Cannot modify header information - headers already sent by (output started at /home/garcialo/www/Pdo_sql_model.php:1634)
Error on line 612 in /home/garcialo/Router/Router.php

Code:
<?php

namespace Router;

use Exceptions\RouteNotFoundException;
use Exceptions\ClassNotFoundException;
use Exceptions\MethodNotFoundException;
use Class\Pdo_sql_model;

include '../public/config.php';
require_once '../public/getdatafct.php';
require_once '../public/api/getrecord.php';

class Router
{
private bool $booPremierPassage=true;
    private string $strCurrentUser = '';
    private string $strCurrentUserId = '1';

    private string $uri = '';
    private string $initialuri = '';
    private string $site = 'tbl_';
    private string $tblconfig;
    private string $tbllanguages;
    private string $tblroutes;
    private string $tblpages;
    private string $tblblock;
    private string $tblblockcontent;
    private string $tbltemplates;
    private string $tblpagesectionblocks;
    private string $tblmenus;
    private string $tblmenuitems;
    private string $tblvocabulary;

    /// Variable containing the validation file's filename
    public string $api_validity_file='';

    /// Variable containing the validation code that will be used in the call_api function.
    public string $api_validity_code='';

    /// Parameters from the current route.
    public array $params;

    /// Array containt the Parameters from the current route.
    public ?array $tabparams=null;

    /// Variable containing the class of the parameters (or null if no parameter in the route).
    public ?stdClass $parametres=null;

    /// Variable containing the path of the current route.
    public $strPath;

    private ?int $intDefaultLanguage=null;
    private array $routes;
    private array $tabvar;
    private string $BR = "<br>\n";
    //private string $BR = "<br>";
    private string $strLangue;

    private $javascript_langues = '';
    private $javascript_json = '';
    private $javascript_json_javascript = '';
    private $intDataDiv = 0;
    private $strLanguage;
    private ?int $idLanguage=null;
    private int $intPage;
    private $strTitle;
    private $intRoute;
    private string $strHomeTitle;
    private $booDebug = __DEBUGMODE__;
    private string $url;

    private int $nremplacements=0;
    private Pdo_sql_model $db;
    private bool $booEditableVocabulary = false;
    private bool $booEditableBlocks = false;
    private bool $booEditableVocabulary_admin = false;
    private bool $booEditableBlocks_admin = false;
    //private bool $booEditableSecurity = false;
    
    private function inittables($uri)
    {
/*
        if (! isset ($_SERVER['SERVER_NAME'])) { // Utile pour pouvoir tester le moteur en ligne de commande.
            // Voir si la première partie du path est /admin/
            $arr = explode('/',$uri,3);
            if ($arr [1] == 'admin') {
                $this->site = 'admin_';
                if (sizeof ($arr) == 3) {
                    $uri = $arr [2];
                } else {
                    $uri = '';
                }
            }
        } else if ($_SERVER['SERVER_NAME'] == 'admin.meinguet.net') {
            $this->site = 'admin_';
        } else if ($_SERVER['SERVER_NAME'] == 'admingarcia.meinguet.net') {
            $this->site = 'admin_';
        } else if ($_SERVER['SERVER_NAME'] == 'garcia.meinguet.net') {
*/
            // Voir si la première partie du path est /admin/
            $arr = explode('/',$uri,3);
            if ($arr [1] == 'admin') {
                $this->site = 'admin_';
                if (sizeof ($arr) == 3) {
                    $uri = $arr [2];
                } else {
                    $uri = '';
                }
            }
/*
        } else {
            $arr = explode('/',$uri,3);
            if ($arr [1] == 'admin') {
                $this->site = 'admin_';
                if (sizeof ($arr) == 3) {
                    $uri = $arr [2];
                } else {
                    $uri = '';
                }
            }
        }
*/

//$this->display("uri=$uri");
//$this->display("site=" . $this->site);

        $this->tblconfig = $this->site . "config";
        $this->tbllanguages = $this->site . "languages";
        $this->tblroutes = $this->site . "routes";
        $this->tblpages = $this->site . "pages";
        $this->tblblock = $this->site . "block";
        $this->tblblockcontent = $this->site . "block_content";
        $this->tbltemplates = $this->site . "templates";
        $this->tblpagesectionblocks = $this->site . "page_section_blocks";
        $this->tblmenus = $this->site . "menus";
        $this->tblmenuitems = $this->site . "menu_items";
        $this->tblvocabulary = $this->site . "vocabulary";

        return ($uri);
    }
    
    /// Function to add a message for the tdb (tableau de bord).
    public function tdbAddMessage ($strMessage,$event = 'message')
    {
        /*
        $filename = __SITEPATH__ . 'public/api/queues/messages/' . date("Y-m-d_H-i-s");
        $orig = $filename;
        $i = 2;
        while (file_exists ($filename)) {
            $filename = $orig . '_' . $i++;
        }

        file_put_contents ($filename,"retry: 2000\nevent:$event\ndata: $strMessage\n\n");
         */
    }

    public function myErrorHandler($errno, $errstr, $errfile, $errline) {
        echo "<b>Custom error:</b> [$errno] $errstr<br>Error on line $errline in $errfile<br>";
        $this->tdbAddMessage (
            "Custom error: [$errno] $errstr<br>Error on line $errline in $errfile",
            'erreur');
        
        //$code = file_get_contents ($errfile);
        //echo '<b><pre>Code:<br>' . htmlspecialchars($code) . '</pre></b>';
        $tab = file($errfile);
        echo '<br>Code:<br>';
        for ($i=0; $i<sizeof($tab); $i++) {
            if ($i+1 == $errline) {
                echo '<font color=red>' . str_replace("\t","&nbsp;&nbsp;&nbsp;&nbsp;",htmlspecialchars($tab[$i])) . '</font><br>';
            } else {
                echo str_replace("\t","&nbsp;&nbsp;&nbsp;&nbsp;",htmlspecialchars($tab[$i])) . '<br>';
            }
        }
        echo '</pre>';
        die ();
/*
            $arrPath = explode ('/',$errfile);
            $lastdir = $arrPath[sizeof($arrPath)-2];
            if ($lastdir == 'Customer') {
                echo "<br><h1><b>Dans /Customer => éditer la source</b></h1>";
            }
*/
    }

    public function __construct ()
    {
        $this->routes = [];

        $old_error_handler = set_error_handler(array($this,'myErrorHandler'));

        try {
            $this->db = new Pdo_sql_model(__DATABASE__,true);
        }
        catch (Exception $e) {
            echo "Error opening database " . __DATABASE__ . " : " . $e->message();
            throw new RouteNotFoundException ();
        }

        if(isset($_COOKIE['username'])) {
            $this->strCurrentUser = $_COOKIE['username'];
        }
//$this->display("username=" . $this->strCurrentUser);

        if ($this->strCurrentUser != "") {
            $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','tbl_vocabulary') AS PERMS");
            if ($result->success) {
                $pos = strpos($result->data[0]['PERMS'], 'W');
                if ($pos !== false) {
                    $this->booEditableVocabulary = true;
                }
            }
            $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','tbl_block') AS PERMS");
            if ($result->success) {
                $pos = strpos($result->data[0]['PERMS'], 'W');
                if ($pos !== false) {
                    $this->booEditableBlocks = true;
                }
            }

            $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','admin_vocabulary') AS PERMS");
            if ($result->success) {
                $pos = strpos($result->data[0]['PERMS'], 'W');
                if ($pos !== false) {
                    $this->booEditableVocabulary_admin = true;
                }
            }
            $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','admin_block') AS PERMS");
            if ($result->success) {
                $pos = strpos($result->data[0]['PERMS'], 'W');
                if ($pos !== false) {
                    $this->booEditableBlocks_admin = true;
                }
            }
        }
    }

    public function __destruct() {
        $this->db->close();
    }

    public function display (string $str)
    {
        if (__DEBUGMODE__) {
            echo $str . $this->BR;
            /*
            if ($this->initialuri != '/admin/tdb') {
                $this->tdbAddMessage ($str,'display');
            }
             */
        }
    }

    private function SQLLike (string $str, ?string $pattern, ?string $varPath=null) : bool
    {
        global $params;
        global $strLangue;
//        global $variables;

        if (is_null ($pattern)) {
            return (false);
        }

//$this->display ("SQLLike str=$str pattern=$pattern varPath=$varPath");
        if ($strLangue != '') {
            $pattern = $strLangue . '/' . $pattern;
            $varPath = $strLangue . '/' . $varPath;
//$this->display ("LANGUE => SQLLike str=$str pattern=$pattern varPath=$varPath");
        }

        $routefound = true;
        $pos = strpos($pattern,'%');
        if ($pos == FALSE) {
            return ($str == $pattern);
        }

        // On enlève les / devant et derrière
        if (substr ($pattern,0,1) == '/') {
            $pattern = substr($pattern,1);
        }
        if (substr ($pattern,-1) == '/') {
            $pattern = substr ($pattern,0,strlen($pattern)-1);
        }
        if (substr ($str,0,1) == '/') {
            $pattern = substr($str,1);
        }
        if (substr ($str,-1) == '/') {
            $str = substr ($str,0,strlen($str)-1);
        }

        // On compte les /, si pas le même nombre => mauvaise route
        $slash_pattern = explode('/',$pattern);
        $slash_str = explode('/',$str);
        if (sizeof ($slash_pattern) != sizeof ($slash_str)) {
            return (false);
        }

        $params = [];

        while ($routefound) {
            $p = substr ($pattern,0,1);
            $s = substr ($str,0,1);
            if ($p != '%' && $p != $s) {
                //$this->display ("% et p=$p != s=$s => stop");
                $routefound = false;
                break;
            }
            if ($p == '%') {
                //$this->display ("------------------");
                //$this->display ("% => p=$p s=$s");
                //$this->display ("% => pattern=$pattern str=$str");
                
                $pattern = substr($pattern,1);
                if (substr ($pattern,0,1) == '/') {
                    $pattern = substr($pattern,1);
                }
                //$this->display ("% => pattern=$pattern str=$str varPath=$varPath") ;
                
                if (! is_null($varPath)) {
                    if (substr ($varPath,0,1) == '/') {
                        $varPath= substr($varPath,1);
                    }

                    $pos = strpos($varPath,'/');
                    if ($pos == FALSE) {
                        $variable = $varPath;
                    } else {
                        $variable = substr ($varPath,0,$pos);
                        $varPath = substr ($varPath,$pos+1);
                    }
//$this->display("varPath pas null => variable=$variable");
                }

                $pos = strpos($str,'/');
                if ($pos == FALSE) {
                    $param = $str;
                } else {
                    $param = substr ($str,0,$pos);
                    $str = substr ($str,$pos+1);
                }
//$this->display ("% => param=$param");
//$this->display ("% => pattern=$pattern str=$str");
                //$params[] = $param;
                if (! is_null($varPath)) {
                    $nomvar = "";
                    foreach ($this->tabparams['parametres'] as $key => $nom) {
//$this->display ("key=$key nom=$nom");
                        if (($nom == '%') && ($nomvar == "")) {
                            $nomvar = $key;
                        }
                    }

                    $this->tabparams['parametres'] [$variable] = $param;
//$this->display ("Ajout de $param dans le paramètre $variable");
                    $params[$variable] = $param;
                }
            } else {
                $pattern = substr($pattern,1);
                $str = substr($str,1);
                if (! is_null($varPath)) {
                    $varPath = substr ($varPath,1);
                }
            }
            if (($str == "") || ($pattern == "")) {
                break;
            }
        }

        if (sizeof ($this->tabparams['parametres']) > 0) {
            extract ($this->tabparams,EXTR_OVERWRITE); // Crée une variable (object) avec le contenu d'un tableau.
        }

        return ($routefound);
    }

    public function addRoute($uri, callable|array $action, ?string $varNames = null) : void
    {
        $this->routes[$uri] = $action;

        if (! is_null ($varNames)) {
            $this->tabvar[$uri] = $varNames;
        } else {
            $this->tabvar[$uri] = null;
        }
    }

    public function ValidationParametres ($uri,$chemintrouve,$regles) : string
    {
//$this->display("<br><br><br><br><br><br>ValidationParametres ($uri,$chemintrouve,$regles");
        $msg = '';

        // Pas de règle de validation
        if ($regles == '') {
            return ('');
        }

        // Pas de paramètre dans l'URL
        if (strpos ($chemintrouve,'%') === FALSE) {
            return ('');
        }

        if ((substr ($uri,0,6) == '/admin') && (strlen ($uri) > 6)) {
            $uri = substr ($uri,6);
    
        }
        if ((substr ($uri,0,1) == '/') && (strlen ($uri) > 1)) {
            $uri = substr ($uri,1);
        }
    

//$this->display("uri=$uri");
$taburi=explode('/',$uri);
$tabValidation=explode('/',$regles);
$tabUri=explode('/',$chemintrouve);

/*
print_r($taburi);
print_r($tabValidation);
print_r($tabUri);
*/

$tabValidationRules = array();
$tabValidationParams = array();
$j=0;
for ($i=0; $i<sizeof($tabUri); $i++) {
    if ($tabUri[$i] == '%') {
        if ($i < sizeof($tabValidation)) {
            $tabValidationRules[$j] = $tabValidation[$i];
        } else {
            $tabValidationRules[$j] = '';
        }
        $tabValidationParams[$j++] = $taburi[$i];
    }
}
/*
print_r($tabValidationParams);
)print_r($tabValidationRules);
*/

        $ok = true;

        for ($i=0; $i<sizeof($tabValidationRules); $i++) {
            $rule = $tabValidationRules[$i];
            $param = $tabValidationParams[$i];
            //$this->display ("tester si " . $param . ' est validé par la règle ' . $rule);
            $ipos = strpos ($rule,"|");

            if ($ipos === FALSE) {
                if ($rule == 'integer' || $rule == 'int') {
                    if (! filter_var($param, FILTER_VALIDATE_INT)) {
                        $ok = false;
                        $msg .= $param . " n'est pas un nombre entier<br>";
                    }
                } else if ($rule == 'float') {
                    if (! filter_var($param, FILTER_VALIDATE_FLOAT)) {
                        $ok = false;
                        $msg .= $param . " n'est pas un nombre float<br>";
                    }
                } else if ($rule == 'email') {
                    if (! filter_var($param, FILTER_VALIDATE_EMAIL)) {
                        $ok = false;
                        $msg .= $param . " n'est pas une adresse e-mail valable<br>";
                    }
                } else if ($rule == 'boolean') {
                    if (! filter_var($param, FILTER_VALIDATE_BOOLEAN)) {
                        $ok = false;
                        $msg .= $param . " n'est pas un booléen<br>";
                    }
                } else if ($rule == 'url') {
                    if (! filter_var($param, FILTER_VALIDATE_URL)) {
                        $ok = false;
                        $msg .= $param . " n'est pas une URL valable<br>";
                    }
                } else if ($rule == 'domain') {
                    if (! filter_var($param, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
                        $ok = false;
                        $msg .= $param . " n'est pas un domaine valable<br>";
                    }
                } else if ($rule == 'ip') {
                    if (! filter_var($param, FILTER_VALIDATE_IP)) {
                        $ok = false;
                        $msg .= $param . " n'est pas une adresse IP valable<br>";
                    }
                }
            } else {
                // Il s'agit d'une liste de valeurs
                $tabvalues = explode ('|',$rule);
                $subok = false;
                foreach ($tabvalues as $key => $valeur) {
                    if ($tabValidationParams[$i] == $valeur) {
                        $subok = true;
                        break;
                    }
                }
                if (! $subok) {
                    $msg .= $param . " n'est pas dans les valeurs " . $rule . '<br>';
                    $ok = false;
                }
            }
        }

        return ($msg);
    }

    private string $breadcrumb='';
    private function setBreadCrumb (string $uri, $booPretty=false)
    {
        $tab = explode ('/',$uri);
        $uri = __HOMESITE__ . '/' . $uri;

        $this->breadcrumb = '<script type="application/ld+json">';
        $schema ['@context'] = 'https://schema.org';
        $schema ['@type'] = 'BreadcrumbList';

        $elem ['@type'] = 'ListItem';
        for ($i = 0; $i < sizeof ($tab); $i++) {
            $elem ['position'] = $i+1;
            $elem ['name'] = '';
            $elem ['item'] = $tab[$i];
            $schema ['itemListElement'][] = $elem;
        }
        if ($booPretty) {
            $this->breadcrumb .= json_encode ($schema,JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        } else {
            $this->breadcrumb .= json_encode ($schema);
        }
        $this->breadcrumb .= "\n</script>\n";
        $this->setSchemaWebPage ($uri,$booPretty);
    }

    private string $schemaWebPage='schemaWebPage';
    public function setSchemaWebPage ($uri,$booPretty=false)
{
     $schema ['@context'] = 'http://schema.org';
     $schema ['@type'] = 'WebPage';
     $schema ['name'] = '';
     $schema ['description'] = 'description';
     $schema ['url'] = $uri;

    $schema ['publisher']['@type'] = 'Organization';
     $schema ['publisher']['name'] = 'MPC Consult SRL';
     /*
    $schema ['publisher']['logo']['@type'] = self::$publisher_logo_type;
     $schema ['publisher']['logo']['url'] = self::$publisher_logo_url;

    if (! is_null (self::$publisher_logo_width)) {
     $schema ['publisher']['logo']['width'] = self::$publisher_logo_width;
     }
    if (! is_null (self::$publisher_logo_height)) {
         $schema ['publisher']['logo']['height'] = self::$publisher_logo_height;
     }
     */

    $this->schemaWebPage = "<script type=\"application/ld+json\">\n";
    if ($booPretty) {
         $this->schemaWebPage .= json_encode ($schema,JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    } else {
         $this->schemaWebPage .= json_encode ($schema);
     }
    $this->schemaWebPage .= "\n</script>";
    
    }

    public function resolve (string $uri) : mixed
    {
        global $params;
        global $strLangue;

        if ($uri != '/admin/tdb') {
            $this->tdbAddMessage ("resolve $uri");
        }
        $this->initialuri = $uri;

        $uri = $this->inittables($uri);
        $this->uri = $uri;
        $tblroutes = $this->tblroutes;
        $tblblock = $this->tblblock;
        $tblblockcontent = $this->tblblockcontent;
        $tblconfig = $this->tblconfig;
        $tbllanguages = $this->tbllanguages;
        $tblpages = $this->tblpages;
        $tbltemplates = $this->tbltemplates;
        $tblpagesectionblocks = $this->tblpagesectionblocks;

$this->url = $uri;
//$this->display ("resolve de $uri");

        $pos = strpos($uri,'?');
        if ($pos != FALSE) {
            $uri = substr ($uri,0,$pos);
        }

        $params = [];
        if (substr ($uri,-1) == '/') {
            $uri = substr ($uri,0,strlen($uri)-1);
        }
        if (substr ($uri,0,1) == '/') {
            $uri = substr ($uri,1,strlen($uri)-1);
        }

        //$bd = new Pdo_sql_model(__DATABASE__,true);
        if (($uri == '') || ($uri == 'fr') || ($uri == 'nl')) {
            $result = $this->db->select ("SELECT strHomeRoute, intDefaultLanguage FROM $tblconfig WHERE idConfig=1");

            if ((! $result->success) || ($result->numrows < 1)) {
                return ("Error when selecting HomeRoute");
            } else {
                $this->intDefaultLanguage = $result->data[0]['intDefaultLanguage'];
                if ($this->site == 'admin_') {
                    header ("Location: /admin/" . $result->data[0]['strHomeRoute']);
                } else {
                    header ("Location: /" . $result->data[0]['strHomeRoute']);
                }
                exit (0);
            }
        }

        $result = $this->db->select ("SELECT strHomeRoute, intDefaultLanguage FROM $tblconfig WHERE idConfig=1");
        $this->intDefaultLanguage = $result->data[0]['intDefaultLanguage'];

        $action=null;
        $chemintrouve="";

        $this->tabparams = [];
        $this->tabparams['parametres'] = array();

        //$this->display ('test des routes ajoutées par addRoute');
        foreach ($this->routes as $key => $route) {
            $indexkey = $key;

            $var = $this->tabvar [$indexkey];
            if (is_null ($var)) {
                $var = '';
            }
            if (substr ($var,-1) == '/') {
                $var = substr ($var,0,strlen($var)-1);
            }
            if (substr ($var,0,1) == '/') {
                $var = substr ($var,1);
            }
            if (substr ($key,0,1) == '/') {
                $key = substr ($key,1,strlen($key)-1);
            }

            // Prendre toutes les variables attendues d'après $var
            $this->tabparams = [];
            $this->tabparams['parametres'] = array();
            $taburi = explode('/',$key);
            $tabparams = explode('/',$var);
            for ($i=0; $i < sizeof($taburi) && $i < sizeof($tabparams); $i++) {
                if ($tabparams[$i] != "") {
                    $elem = $taburi[$i];
                    $this->tabparams['parametres'][$tabparams[$i]] = $elem;
                }
            }

            $str = $uri;
            $pattern = $key;

            //$this->display ("uri=$uri pattern=$pattern var=$var");
            if (is_null($indexkey)) {
                if ($this->SQLLike ($str, $pattern)) {
                    //                echo "Route trouvée : $key" . $this->BR;
                    $action = $route;
                    $chemintrouve = $key;
                    //$this->display ("break 1");
                    break;
                }
            } else if (is_null ($var)) {
                if ($this->SQLLike ($str, $pattern)) {
                    //$this->display ("break 2");
                    $action = $route;
                    $chemintrouve = $key;
                    break;
                }
            } else if ($this->SQLLike ($str, $pattern, $var)) {
                $action = $route;
                $chemintrouve = $key;
                //$this->display ("break 3");
                break;
            }
        }
        //$this->display ("chemintrouve=$chemintrouve action=$action");

        $path = explode('?',$uri);
        //$action = $this->routes[$path[0]] ?? null;

        if (is_callable($action)) {
            //$this->display ("is_callable");
/*
            for ($i = 1; $i<sizeof($path); $i++) {
                echo "paramètre $i = " . $path[$i] . "<br>";
            }
//echo "chemintrouve=$chemintrouve <br>";
            $pos = strpos($chemintrouve,'%');
            $params = array();
            while ($pos != FALSE) {
                $chemintrouve = substr ($chemintrouve,$pos);
//echo "uri=$uri <br>";
                $uri = substr ($uri,$pos);
                $pos = strpos($chemintrouve,'%');
//echo "chemintrouve=$chemintrouve <br>";
//echo "uri=$uri <br>";
                $posslash = strpos($uri,'/');
                if ($posslash != FALSE) {
                    $params[] = substr($uri,0,$posslash);
                } else {
                    $params[] = $uri;
                }
            }

//echo "nparams=" . sizeof($params) . "<br>";
//echo "params[0]=" . $params[0] . "<br>";
*/

            //$this->display ("*****");
            //$this->display ("sizeof(params) = " . sizeof($params));
            //$this->display ("*****");
            //        for ($i=0; $i<sizeof($params); $i++) {
            //echo "params[$i] = " . $params[$i] . $this->BR;
            //}
            switch (sizeof($params)) {
            case 0:
                return ($action());
            case 1:
                return ($action($params[0]));
            case 2:
                return ($action($params[0],$params[1]));
            case 3:
                return ($action($params[0],$params[1],$params[2]));
            case 4:
                return ($action($params[0],$params[1],$params[2],$params[3]));
            case 5:
                return ($action($params[0],$params[1],$params[2],$params[3],$params[4]));
            case 6:
                return ($action($params[0],$params[1],$params[2],$params[3],$params[4],$params[5]));
            }
        } else {
            //$this->display ('Pas callable');
        }

        if (is_array($action)) {
            [$classe, $methode] = $action;
            if (! class_exists ($classe)) {
                throw new ClassNotFoundException ($classe);
            }
            if (! method_exists ($classe,$methode)) {
                throw new MethodNotFoundException ($classe,$methode);
            }

            $class = new $classe();
            return call_user_func_array([$class,$methode],[]);
        } else {
            //$this->display ('Pas array');
        }

        /*
        try {
            $bd = new Pdo_sql_model(__DATABASE__,true);
        }
        catch (Exception $e) {
            echo "Error opening database " . __DATABASE__ . " : " . $e->message();
            throw new RouteNotFoundException ();
        }
         */

        // Parcourir les routes dans tbl_routes, pour la langue courante.
         /*
        $pos = strpos($uri,'/');
        if ($pos !== FALSE) {
            $strLangue = substr ($uri,0,$pos);
            $uri = substr ($uri,$pos+1);
        } else {
//$this->display ("strLangue=$strLangue");
        }
         */

//$this->display ("uri=$uri");
        $strLangue = "";
        $sqlCmd = "SELECT strLanguage FROM $tbllanguages";
        $result = $this->db->select ($sqlCmd);
        if ($result->success) {
            if ($result->numrows > 0) {
                foreach ($result->data as $key => $row) {
                    //$this->display ("row['strLanguage'] = " . $row['strLanguage']);
                    $len = strlen ($row['strLanguage']);
                    $pos = strpos($uri,'/');
                    if ($pos == FALSE) {
                        break; // Pas de langue dans l'URL
                    }
                    if ($pos == $len) {
                        if (substr ($uri,0,$pos) == $row['strLanguage']) {
                            $strLangue = $row['strLanguage'];
                            break;
                        }
                    }
                }
            } else {
                //$this->display ("pas de langue dans $tbllanguages");
            }
        } else {
            //$this->display ('! success');
        }
        //$this->display ("strLangue=$strLangue");

        if ($strLangue != '') {
            $sqlCmd = "SELECT idLanguage FROM $tbllanguages WHERE strLanguage='$strLangue'";
            //$this->display ("sqlCmd=$sqlCmd" . $this->BR);
            $result = $this->db->select ($sqlCmd);

            if ($result->success) {
                if ($result->numrows > 0) {
                    $this->idLanguage = $result->data[0]['idLanguage'];
                } else {
                    return ("Language $strLangue not found");
                }
            } else {
                return ("Error when searching for language $strLangue");
            }
        } else {
            $this->idLanguage = 0;
        }
//$this->display("idLanguage=" . $this->idLanguage);
//        if ($this->idLanguage == 0) {
            //$sqlCmd = "SELECT idRoute, strPath, strVar, strValidation, intPage, strTitle, strDescription, strAuthor FROM $tblroutes LEFT JOIN $tblpages ON $tblpages.idPage = $tblroutes.intPage WHERE intLanguage IS NULL";
        //} else {
            $sqlCmd = "SELECT idRoute, strPath, strVar, strValidation, intPage, strTitle, strDescription, strAuthor FROM $tblroutes LEFT JOIN $tblpages ON $tblpages.idPage = $tblroutes.intPage WHERE intLanguage=$this->idLanguage";
        //}
//$this->display($sqlCmd);
        $result = $this->db->select ($sqlCmd);
        if ($result->success) {
            $trouve = false;
            if ($result->numrows > 0) {
                foreach ($result->data as $key => $route) {
                    if ($route['strVar'] == '') {
                        if ($this->SQLLike ($uri, $route['strPath'])) {
                            $trouve = true;
                            $chemintrouve = $route['strPath'];
                            break;
                        }
                    } else if ($this->SQLLike ($uri, $route['strPath'], $route['strVar'])) {
                        $trouve = true;
                        $chemintrouve = $route['strPath'];
                        break;
                    }
                }
            }
            if ($trouve) {
                $this->setBreadCrumb($uri,true);
                return ($this->AfficherPage ($route['idRoute'],$route['intPage'],$route['strPath'],$route['strTitle'],$route['strDescription'],$route['strAuthor'],$this->idLanguage));
            } else {
                $sqlCmd = "SELECT idRoute, strPath, strVar, strValidation, intPage, strTitle, strDescription, strAuthor FROM $tblroutes LEFT JOIN $tblpages ON $tblpages.idPage = $tblroutes.intPage WHERE intLanguage IS NULL";
                $result = $this->db->select ($sqlCmd);
                //$this->display ("sqlCmd=$sqlCmd");
                if ($result->success) {
                    if ($result->numrows > 0) {
                        $trouve = false;
                        foreach ($result->data as $key => $route) {
                            //$this->display("route = " . $route['strPath']);
                            if ($route['strVar'] == '') {
                                if ($this->SQLLike ($uri, $route['strPath'])) {
                                    $trouve = true;
                                    $chemintrouve = $route['strPath'];
                                    break;
                                }
                            } else if ($this->SQLLike ($uri, $route['strPath'], $route['strVar'])) {
                                $trouve = true;
                                $chemintrouve = $route['strPath'];
                                break;
                            }
                        }
                    }
                    if ($trouve) {
                        //$bd->close ();
                        $ok = true;

                        $erreurs = $this->ValidationParametres ($this->initialuri,$chemintrouve,$route['strValidation']);

                        if ($erreurs == '') {
                            $this->setBreadCrumb($uri,true);
                            return ($this->AfficherPage ($route['idRoute'],$route['intPage'],$route['strPath'],$route['strTitle'],$route['strDescription'],$route['strAuthor'],$this->idLanguage));
                        } else {
                            return ($this->Erreur404($uri,$strLangue));
                            /*
                            if ($this->booDebug) {
                                return ("<br><font color=red>Tous les paramètres ne sont pas valides:<br></font> $erreurs");
                            } else {
                                return ('<br><font color=red>Tous les paramètres ne sont pas valides.<br>');
                            }
                             */
                        }
                    } else {
                        $sqlCmd = "SELECT idRoute, strPath, strVar, intPage, strLanguage, intGroup FROM $tblroutes LEFT JOIN $tbllanguages ON $tbllanguages.idLanguage=$tblroutes.intLanguage WHERE intLanguage IS NOT NULL AND intLanguage <> $this->idLanguage";
                        $result = $this->db->select ($sqlCmd);
                        //$this->display ("sqlCmd=$sqlCmd");
                        if ($result->success) {
                            if ($result->numrows > 0) {
                                $trouve = false;
                                foreach ($result->data as $key => $route) {
                                    if ($route['strVar'] == '') {
                                        //$this->display ("comparaison de $uri et " . $route['strPath']);
                                        if ($this->SQLLike ($uri, $route['strPath'])) {
                                            $trouve = true;
                                            $intGroup = $route['intGroup'];
                                            $chemintrouve = $route['strPath'];
                                            break;
                                        } else if ($this->SQLLike ($uri, $route['strPath'], $route['strVar'])) {
                                            $trouve = true;
                                            $intGroup = $route['intGroup'];
                                            $chemintrouve = $route['strPath'];
                                            break;
                                        }
                                    }
                                }
                            }
                            if ($trouve) {
                                //$this->display ("intGroup=$intGroup");
                                $sqlCmd = "SELECT * FROM $tblroutes LEFT JOIN $tbllanguages ON $tbllanguages.idLanguage=$tblroutes.intLanguage WHERE intGroup=$intGroup AND intLanguage=$this->idLanguage";
                                //$this->display ("sqlCmd=$sqlCmd");
                                $result = $this->db->select ($sqlCmd);
                                if ($result->success && ($result->numrows == 1)) {
                                    $route = $result->data[0];
                                    header ("Location: /" . $route['strLanguage'] . '/' . $route['strPath']);
                                    //$this->display ("On essaie d'aller vers /" . $route['strLanguage'] . '/' . $route['strPath']);
                                } else {
                                    header ("Location: /" . $route['strLanguage'] . '/' . $route['strPath']);
                                    //$this->display ("On essaie d'aller vers /" . $route['strLanguage'] . '/' . $route['strPath']);
                                }
                                //$bd->close ();
                            } else {
                                //throw new RouteNotFoundException ();
                                if (substr ($uri,0,6) == '@file/') {
                                    $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','Gestion de l''admin') AS PERMS");
                                    if ($result->success) {
                                        $pos = strpos($result->data[0]['PERMS'], 'X');
                                        if ($pos === false) {
                                            return ("Unauthorized access");
                                        }
                                    }

                                    if (file_exists (substr ($uri,5))) {
                                        return (file_get_contents (substr ($uri,5)));
                                    } else {
                                        return ("0) We’re sorry!<br>The page (<b>" . $uri . "</b>) you’re looking for may have been moved or deleted.<br>Start a new search on <a href='http://" . __HOMESITE__ . "'>" . __HOMESITE__ . "</a><br>");
                                    }
                                }

                                if (substr ($uri,0,6) == '@code/') {
                                    $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','Gestion de l''admin') AS PERMS");
                                    if ($result->success) {
                                        $pos = strpos($result->data[0]['PERMS'], 'X');
                                        if ($pos === false) {
                                            return ("Unauthorized access");
                                        }
                                    }

                                    //return ("Présenter le contenu du fichier : " . substr($uri,5));
                                    if (file_exists (substr ($uri,5))) {
                                        $html = "<script>\n";
                                        $html .= "function update_file()\n";
                                        $html .= "{\n";
                                        $html .= " const url = '/api/save_file.php';\n";
                                        $html .= " const formdata = new FormData();\n";

                                        $html .= "         let el = document.getElementById('texte');\n";
                                        $html .= " formdata.append('filename','" . substr ($uri,5) . "');\n";
                                        $html .= " formdata.append('content',el.value);\n";

                                        $html .= " const requestOptions = {\n";
                                        $html .= " method: 'POST',\n";
                                        $html .= " body: formdata,\n";
                                        $html .= " redirect: 'follow'\n";
                                        $html .= " };\n";

                                        $html .= " fetch(url,requestOptions)\n";
                                        $html .= " .then((response) => response.json())\n";
                                        $html .= " .then((data) => {\n";
                                        $html .= " if (data.code != 'OK') {\n";
                                        $html .= " alert (data.message);\n";
                                        $html .= " } else {\n";
                                        $html .= " history.back();\n";
                                        $html .= " return (true);\n";
                                        $html .= " }\n";
                                        $html .= " });\n";

                                        $html .= " return (false);\n";
                                        $html .= "}\n";
                                        $html .= "</script>\n";

                                        $html .= '<textarea style="height:95%; width:100%" id="texte">';
                                        $html .= file_get_contents (substr ($uri,5));
                                        $html .= "</textarea><br><button type='button' onclick=\"update_file()\">Sauver</button> <button type='button' onclick='history.back()'>Abandonner</button>";
                                        return ($html);
                                    }
                                    return ("0) We’re sorry!<br>The page (<b>" . $uri . "</b>) you’re looking for may have been moved or deleted.<br>Start a new search on <a href='/'>" . __HOMESITE__ . "</a><br>");
                                }

                                if (substr ($uri,0,9) == '@newcode/') {
                                    if (! file_exists (substr ($uri,8))) {
                                        $html = "<script>\n";
                                        $html .= "function update_file()\n";
                                        $html .= "{\n";
                                        $html .= " const url = '/api/save_file.php';\n";
                                        $html .= " const formdata = new FormData();\n";

                                        $html .= "    let el = document.getElementById('texte');\n";
                                        $html .= " formdata.append('filename','" . substr ($uri,8) . "');\n";
                                        $html .= " formdata.append('content',el.value);\n";

                                        $html .= " const requestOptions = {\n";
                                        $html .= " method: 'POST',\n";
                                        $html .= " body: formdata,\n";
                                        $html .= " redirect: 'follow'\n";
                                        $html .= " };\n";

                                        $html .= " fetch(url,requestOptions)\n";
                                        $html .= " .then((response) => response.json())\n";
                                        $html .= " .then((data) => {\n";
                                        $html .= " if (data.code != 'OK') {\n";
                                        $html .= " alert (data.message);\n";
                                        $html .= " } else {\n";
                                        $html .= " history.back();\n";
                                        $html .= " return (true);\n";
                                        $html .= " }\n";
                                        $html .= " });\n";

                                        $html .= " return (false);\n";
                                        $html .= "}\n";
                                        $html .= "</script>\n";

                                        $html .= '<textarea style="height:95%; width:100%" id="texte">';
                                        $html .= "</textarea><br><button type='button' onclick=\"update_file()\">Sauver</button> <button type='button' onclick='history.back()'>Abandonner</button>";
                                        return ($html);
                                    } else {
                                        return ("File already exists");
                                    }
                                }
                                return ($this->Erreur404($uri,$strLangue));
                            }
                        }
                    }
                }
                //throw new RouteNotFoundException ();
                return ("2) We’re sorry!<br>The page you’re looking for may have been moved or deleted.<br>Start a new search on <a href='/'>" . __HOMESITE__ . "</a>");
                //throw new RouteNotFoundException ();
            }
        }
        //else $this->display("not success");
//$this->display ("sqlCmd=$sqlCmd");
        return ("Pas de route sans langue");
    }

    function Erreur404($uri,$strLangue) : mixed
    {
        if ($uri != '404') {
            if ($strLangue != '') {
                return ($this->resolve("/$strLangue/404"));
            } else {
                return ($this->resolve('/404'));
            }
        }

        return ("1) We’re sorry!<br>The page (" . $uri . ") you’re looking for may have been moved or deleted.<br>Start a new search on <a href='/'>" . __HOMESITE__ . "</a><br>");
    }

    function fctHTML($numero)
    {
        $code = "let elem=document.getElementById('idEditeur" . $numero . "');";
        //    $code .= "elem.setAttribute('contenteditable','false');";
        $code .= "if (elem == null) { alert ('idEditeur" . $numero . " pas trouvé') } else {";
        $code .= " innerhtml = elem.innerHTML;";
        $code .= " if (innerhtml.substring (0,5) == '<xmp>') {";
        $code .= " innerhtml = innerhtml.replaceAll ('<xmp>','');";
        $code .= " innerhtml = innerhtml.replaceAll ('</xmp>','');";
        $code .= " elem.innerHTML = innerhtml;";
        $code .= " } else {";
        $code .= " elem.innerHTML = '<xmp>' + elem.innerHTML + '</xmp>';";
        $code .= " }";
        $code .= "}";
        $code .= "";

        return $code;
    }

    function ExecCommand ($btn,$commande,$numero)
    {
        $code = "onclick=\"";
        //$code .= "const el = document.getElementById('idEditeur');";
        //$code .= "const selection = window.getSelection();";
        //$code .= "const range = document.createRange();";
        //$code .= "selection.removeAllRanges();";
        //$code .= "range.selectNodeContents(el);";
        //$code .= "btn = document.getElementById('" . $btn . "'); if (btn == null) console.log('btn pas trouvé') else if (! btn.hasAttribute ('disabled')) document.execCommand('" . $commande . "',false);";
        //$code .= "if (! document.getElementById('" . $btn . $numero . "').hasAttribute ('disabled')) {document.execCommand('" . $commande . "',false);}SetFocus()";
        $code .= "ActionBoutonEditeur(" . $numero . ",'" . $btn . $numero . "','" . $commande . "')";
        //$code .= "range.collapse(false);";
        //$code .= "selection.addRange(range);";
        //$code .= "el.focus();";
        //$code .= "el.setSelectionRange(2, 5);";
        $code .= "\"";

        return ($code);
    }

    function HtmlEditorButton ($numero)
    {
        $buttons = "<div id='EditorButtons" . $numero . "' style='display: none'>";
        $buttons .= "<button tabindex='-1' id='btnBold" . $numero . "' type='button' title='Mettre en gras (CtrlB)' " . $this->ExecCommand ('btnBold','bold',$numero) . "><i class='bi bi-type-bold'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnItalic" . $numero . "' type='button' title='Mettre en italique (CtrlI)' " . $this->ExecCommand ('btnItalic','italic',$numero) . "><i class='bi bi-type-italic'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnUnderline" . $numero . "' type='button' title='Souligner (CtrlU)' " . $this->ExecCommand ('btnUnderline','underline',$numero) . "><i class='bi bi-type-underline'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnStrikeThrough" . $numero . "' type='button' title='Barrer' " . $this->ExecCommand ('btnStrikeThrough','strikeThrough',$numero) . "><i class='bi bi-type-strikethrough'></i></button>";
        $buttons .= "<button tabindex='-1' type='button' title='Titre de niveau 1' onclick=\"document.execCommand('formatBlock', false, 'H1')\"><i class='bi bi-type-h1'></i></button>";
        $buttons .= "<button tabindex='-1' type='button' title='Titre de niveau 2' onclick=\"document.execCommand('formatBlock', false, 'H2')\"><i class='bi bi-type-h2'></i></button>";
        $buttons .= "<button tabindex='-1' type='button' title='Titre de niveau 3' onclick=\"document.execCommand('formatBlock', false, 'H3')\"><i class='bi bi-type-h3'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnInsertHR" . $numero . "' type='button' title='Tracer une ligne horizontale' " . $this->ExecCommand ('btnInsertHR','insertHorizontalRule',$numero) . "><i class='bi bi-hr'></i></button>";
        $buttons .= "<button tabindex='-1' type='button' title='D&eacute;buter un paragraphe' onclick=\"document.execCommand('formatBlock', false, 'P')\"><i class='bi bi-paragraph'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnUndo" . $numero . "' type='button' title='D&eacute;faire (CtrlZ)' " . $this->ExecCommand ('btnUndo','undo',$numero) . "><i class='bi bi-arrow-counterclockwise'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnRedo" . $numero . "' type='button' title='Refaire' " . $this->ExecCommand ('btnRedo','redo',$numero) . "><i class='bi bi-arrow-clockwise'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnIndent" . $numero . "' type='button' title='Indenter' " . $this->ExecCommand ('btnIndent','indent',$numero) . "><i class='bi bi-indent'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnOutdent" . $numero . "' type='button' title='Enlever indentation' " . $this->ExecCommand ('btnOutdent','outdent',$numero) . "><i class='bi bi-unindent'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnSubscript" . $numero . "' type='button' title='Mettre en indice' " . $this->ExecCommand ('btnSubscript','subscript',$numero) . "><i class='bi bi-subscript'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnSuperscript" . $numero . "' type='button' title='Mettre en exposant' " . $this->ExecCommand ('btnSuperscript','superscript',$numero) . "><i class='bi bi-superscript'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnJustifyCenter" . $numero . "' type='button' title='Centrer' " . $this->ExecCommand ('btnJustifyCenter','justifyCenter',$numero) . "><i class='bi bi-justify'></i> </button>";
        $buttons .= "<button tabindex='-1' id='btnJustifyLeft" . $numero . "' type='button' title='Cadrer &agrave; gauche' " . $this->ExecCommand ('btnJustifyLeft','justifyLeft',$numero) . "><i class='bi bi-justify-left'></i> </button>";
        $buttons .= "<button tabindex='-1' id='btnJustifyRight" . $numero . "' type='button' title='Cadrer &agrave; droite' " . $this->ExecCommand ('btnJustifyRight','justifyRight',$numero) . "><i class='bi bi-justify-right'></i> </button>";
        $buttons .= "<button tabindex='-1' id='btnInsertOL" . $numero . "' type='button' title='Liste num&eacute;rot&eacute;e' " . $this->ExecCommand ('btnInsertOL','insertOrderedList',$numero) . "><i class='bi bi-list-ol'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnInsertUL" . $numero . "' type='button' title='Liste non num&eacute;rot&eacute;e' " . $this->ExecCommand ('btnInsertUL','insertUnorderedList',$numero) . "><i class='bi bi-list-ul'></i></button>";
        $buttons .= "<button tabindex='-1' type='button' title='Basculer entre contenu HTML et visuel' onclick=\"fctHTML(" . $numero . ")\"><i class='bi bi-filetype-html'></i></button>";
        $buttons .= "<button tabindex='-1' id='btnRemoveFormat" . $numero . "' type='button' title='Enlever le formatage' " . $this->ExecCommand ('btnRemoveFormat','removeformat',$numero) . ">Unformat</i></button>";

        $buttons .= "<select tabindex='-1' onchange='fontEditor(this[this.selectedIndex].value)'>";
        $buttons .= "<option value=''>Select font</option>";
        $buttons .= "<option value='Arial'>Arial</option>";
        $buttons .= "<option value='Calibri'>Calibri</option>";
        $buttons .= "<option value='Comic Sans MS'>Comic Sans MS</option>";
        $buttons .= "</select>";

        $buttons .= "</div>";

        return ($buttons);
    }

    /*
    function fctUserCanUpdate()
    {
        if ($this->strCurrentUser == "") {
            return (false);
        } else {
            //$db = new Pdo_sql_model(__DATABASE__,false);
            $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "','tbl_vocabulary') AS PERMS");
            if (! $result->success) {
                return (false);
            }
            //$db->close();
            $pos = strpos($result->data[0]['PERMS'], 'W');
            if ($pos === false) {
                return (false);
            }
            return (true);
        }
    }
     */

    function replace_combo($html)
    {
        //return ($this->keep_combo ($html));
        //$this->display("replace_combo()");
        // Exemple : <combo table="tbl_block" column="intContentType"></combo>
/*
        $dom = new DOMDocument();

        // Le @ placé devant permet de ne pas avoir d'avertissement pour combo
        @$dom->loadHTML($html);

        foreach ($dom->getElementsByTagName("combo") as $a) {
            echo $a->getAttribute("type") . "\n";
        }
*/
        $table = $column = $value = "";

        $array_attributes = $this->get_tag_attributes("COMBO",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("table",$array_attributes)) {
            $table = $array_attributes['table'];
        }
        if (array_key_exists("column",$array_attributes)) {
            $column = $array_attributes['column'];
        }
        if (array_key_exists("value",$array_attributes)) {
            $value = $array_attributes['value'];
        }
        if (array_key_exists("class",$array_attributes)) {
            $classe = $array_attributes['class'];
        } else {
            $classe = "form-control";
        }
        if (array_key_exists('validation',$array_attributes)) {
            $validation = $array_attributes['validation'];
        } else {
            $validation = '';
        }
        if (array_key_exists('onblur',$array_attributes)) {
            $onblur = $array_attributes['onblur'];
        } else {
            $onblur = '';
        }
        if (array_key_exists('onfocus',$array_attributes)) {
            $onfocus = $array_attributes['onfocus'];
        } else {
            $onfocus = '';
        }
        if (array_key_exists('onchange',$array_attributes)) {
            $onchange = $array_attributes['onchange'];
        } else {
            $onchange = '';
        }
        //$this->display ("getSelectOptions ($table,$column,'Veuillez sélectionner' ,$value, $classe)");
        $result = $array_attributes ['beforeTag'] . $this->db->getSelectOptions ($table,$column,"Veuillez s&eacute;lectionner",$value,$classe,$validation,$onblur,$onfocus,$onchange) . $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function replace_mustache($html)
    {
        $tablename = $criteria = $orderby = $linkedto = $linkedfrom = $query = '';
        $columns = '*';

        $array_attributes = $this->get_tag_attributes("MUSTACHE",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("tablename",$array_attributes)) {
            $tablename = $this->replace_parameters ($array_attributes['tablename']);
        }
        if (array_key_exists("criteria",$array_attributes)) {
            $criteria = $this->replace_parameters ($array_attributes['criteria']);
        }
        if (array_key_exists("orderby",$array_attributes)) {
            $orderby = $array_attributes['orderby'];
        }
        if (array_key_exists("query",$array_attributes)) {
            $query = $array_attributes['query'];
        }
        if (array_key_exists("linkedto",$array_attributes)) {
            $linkedto = $array_attributes['linkedto'];
        }
        if (array_key_exists("linkedfrom",$array_attributes)) {
            $linkedfrom = $array_attributes['linkedfrom'];
        }
        if (array_key_exists("columns",$array_attributes)) {
            $columns = $array_attributes['columns'];
        }

        $render = 'render';
        if ($tablename != '') {
            if (array_key_exists("innerHtml",$array_attributes)) {
                $data = getrecords ($tablename, $criteria, $orderby, $query, $linkedto, $linkedfrom, $columns);
                $met = new \Customer\Model ();
                $render = $met->render ($data,$array_attributes['innerHtml']);
            }
        }

        $result = $array_attributes ['beforeTag'] . $render . $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function replace_include($html)
    {
        $tablename = $criteria = $orderby = "";
        $linkedto = $linkedfrom = '';

        $array_attributes = $this->get_tag_attributes("INCLUDE",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("filename",$array_attributes)) {
            $filename = $this->replace_parameters ($array_attributes['filename']);
        }

        $content = '';
        if ($filename != '') {
            if (file_exists ($filename)) {
                $content = file_get_contents ($filename);
                /*
            if (array_key_exists("innerHtml",$array_attributes)) {
                $content = $met->render ($data,$array_attributes['innerHtml']);
            }
                 */
            }
            $content = str_replace("\n",'',$content);
        }

        $result = $array_attributes ['beforeTag'] . $content . $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function replace_formmpc($html)
    {
        global $params;

        $table = $column = $value = "";

        $array_attributes = $this->get_tag_attributes("FORMMPC",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("mode",$array_attributes)) {
            $mode = $array_attributes['mode'];
        } else {
            $mode = 'add';
        }
        if (array_key_exists("id",$array_attributes)) {
            $id = $array_attributes['id'];
            $result = $this->db->select ("SELECT * FROM admin_forms WHERE idForm=$id");
        }
        if (array_key_exists("name",$array_attributes)) {
            $name = $array_attributes['name'];
            $result = $this->db->select ("SELECT * FROM admin_forms WHERE strName='$name'");
            if ($result->numrows != 1) {
                return ($array_attributes ['beforeTag'] . "form name $name not found" . $array_attributes['afterTag']);
            }
            $id = $formid = $result->data[0]['idForm'];
        }

        if ($result->success && $result->numrows > 0) {
            $strUpdateButton = $this->replace_parameters ($result->data[0]['strUpdateButton']);
$ysnUpdateButtonOnlyOnce = $this->replace_parameters ($result->data[0]['ysnUpdateButtonOnlyOnce']);
            $strUpdateClass = $this->replace_parameters ($result->data[0]['strUpdateClass']);
            $strUpdateApi = $this->replace_parameters ($result->data[0]['strUpdateApi']);
            $strCreateButton = $this->replace_parameters ($result->data[0]['strCreateButton']);
$ysnCreateButtonOnlyOnce = $this->replace_parameters ($result->data[0]['ysnCreateButtonOnlyOnce']);
            $strCreateClass = $this->replace_parameters ($result->data[0]['strCreateClass']);
            $strCreateApi = $this->replace_parameters ($result->data[0]['strCreateApi']);
            $strPostVariables = $this->replace_parameters ($result->data[0]['strPostVariables']);
            $strValidationFunction = $this->replace_parameters ($result->data[0]['strValidationFunction']);

            $formcontent = "<div class='container-fluid column-gap-1 mx-3 p-3 my-3 me-3 mr-3' style='background-color: lightblue'>\n";
            $formcontent .= "<form id='$id' class='form-horizontal' novalidate>\n";
            $result = $this->db->select ("SELECT *, IFNULL (intMaxLength,0) AS MaxLength FROM admin_form_items WHERE intForm=$id ORDER BY intLine,intColumn");
            $intLine = -1;
            $booPremierChamp = true;

            $strValidationLine = "<div class='form-group row'>\n";
            $formcontent .= "<div class='form-group row'>\n";

            foreach ($result->data as $key => $row) {
                if ($row['intLine'] != $intLine) {
                    if ($intLine != -1) {
                        $strValidationLine .= '</div>';
                        $formcontent .= $strValidationLine;
                        $strValidationLine = "<div class='form-group row'>\n";
                        $formcontent .= "</div>\n";
                        $formcontent .= "<div class='form-group row'>\n";
                    }
                    $intLine = $row['intLine'];
                //$formcontent .= "</div>\n";
                }
                //$formcontent .= '<div class="col-sm">';
                
                $formcontent .= '<label id="lbl_' . $row['strFieldName'] . '" for="' . $row['strFieldName'] . '" class="col-form-label ' . $row['strLabelClass'] . '"';
                if ($row['strLabelStyle'] != '') {
                    $formcontent .= ' style="' . $row['strLabelStyle'] . '"';
                }
                $formcontent .= '>' . $row['strLabel'];
                $strValidationLine .= "<label class='col-form-label " . $row['strLabelClass'] . "'></label>";

                $strValidation = $row['strValidation'];
                if (is_null ($strValidation)) {
                    $strValidation = '';
                }
                $rules = explode (',',$strValidation);

                for ($i=0; $i<sizeof($rules); $i++) {
                    if ($rules[$i] == 'required') {
                        $formcontent .= '<span class="required-asterisk"> * </span>';
                        break;
                    }
                }

                $formcontent .= "</label>\n";

                /*
                if (! is_null ($row['intInputColumns'])) {
                    $formcontent .= '<div class="col-sm-' . $row['intInputColumns'] . '">';
                } else {
                    $formcontent .= '<div class="col">';
                }
                 */
$formcontent .= '<div class="col">';

                $colonne = $this->db->getcoldef ($this->replace_parameters ($row['strDBTable']),
                                 $this->replace_parameters ($row['strDBColumn']));

                if ((! is_null ($colonne)) && $colonne['format'] == 'combo') {
                    $formcontent .= "<combo table='" . $this->replace_parameters ($row['strDBTable']) . "' column='" . $this->replace_parameters ($row['strDBColumn']) . "'";
                    $formcontent .= " value='@" . $row['strFieldName'] . "@'";
                    $formcontent .= " onfocus=\"evaluate_buttons('$id','$strValidationFunction')\"";
                    $formcontent .= " onchange=\"evaluate_buttons('$id','$strValidationFunction')\"";
                    if ($strValidation != '') {
                        $formcontent .= " validation='$strValidation' onblur=\"validate_field($id,'" . $row['strFieldName'] . "',true)\" ";
                    }
                    $formcontent .= " class='form-control col-sm-4'></combo>";
                } else {
                //$formcontent .= '</div>';
                    $formcontent .= '<input id="' . $row['strFieldName'] . '" class="';
                    if ((is_null ($row['strInputClass']) || $row['strInputClass']) == '') {
                        $formcontent .= 'form-control"';
                    } else {
                        //if ($colonne['coltype'] == 'bit(1)' || $colonne['format'] == 'checkbox') {
                        //    $formcontent .= 'custom-checkbox"';
                        //} else {
                            $formcontent .= $row['strInputClass'] . '"';
                        //}
                    }
                if (intval ($row['MaxLength']) > 0) {
                    $formcontent .= " maxlength='" . $row['MaxLength'] . "'";
                } else if (! (is_null($row['strDBTable']) || is_null ($row['strDBColumn']))) {
                    $length = $this->db->getcollength ($row['strDBTable'],$row['strDBColumn']);
                    if ($length > 0) {
                        $formcontent .= " maxlength='$length'";
                    }
                }
                $placeholder = $this->db->getplaceholder ($row['strDBTable'],$row['strDBColumn']);
                if ($placeholder != '') {
                    $formcontent .= " placeholder='$placeholder'";
                }

                if ($row['strInputStyle'] != '') {
                    $formcontent .= ' style="' . $row['strInputStyle'] . '"';
                }

                if ((! is_null ($colonne)) && ($colonne['coltype'] == 'bit(1)' || $colonne['format'] == 'checkbox')) {
                    if ($mode == 'update') {
                        $formcontent .= " type='checkbox' @" . $row['strFieldName'] . '@';
                    } else {
                        $formcontent .= " type='checkbox'";
                    }
                } else if ((! is_null ($colonne)) && $colonne['coltype'] == 'date') {
                    if ($mode == 'update') {
                        $formcontent .= " type='date' value='@" . $row['strFieldName'] . "@'";
                    } else {
                        $formcontent .= " type='date'";
                    }
                } else {
                    if ($mode == 'update') {
                        $formcontent .= ' value="@' . $row['strDBColumn'] . '@"';
                    }
                }

                //if ($booPremierChamp) {
                    $formcontent .= " onfocus=\"evaluate_buttons('$id','$strValidationFunction')\"";
                    //$booPremierChamp = false;
                //}

                $formcontent .= " onkeyup=\"evaluate_buttons('$id','$strValidationFunction')\"";
                if ($strValidation != '') {
                    $formcontent .= " onblur=\"validate_field($id,'" . $row['strFieldName'] . "',true)\" ";
                }

                $formcontent .= " validation='$strValidation' />";
                }
                $formcontent .= "</div>\n";

                // Champ pour afficher les erreurs lors de la validation.
//                $formcontent .= '<div class="form-group row">';
                $strValidationLine .= '<div id="valid_' . $row['strFieldName'] . '" class="col" style="display: none"></div>';
                //$formcontent .= '<div id="valid_' . $row['strFieldName'] . '" class="col" style="display: none"></div>';
            }
            $formcontent .= $strValidationLine . '</div>';
            $formcontent .= "</div>\n";

            // Ajout des variables que l'on aurait definies dans strPostVariables (forms).
            if ($strPostVariables != '') {
                $tabPostVariables = explode (',',$strPostVariables);
                foreach ($tabPostVariables as $key => $valeur) {
                    $tabValeur = explode ('=',$valeur);
                    $formcontent .= "<input id='" . $tabValeur[0] . "' value='" . $tabValeur[1] . "' style='display: none' /><br>";
                }
            }

            //$formcontent .= "</div>\n";
            if ($strUpdateButton != '') {
                $formcontent .= '<div class="form-group row">';
                $formcontent .= '<div class="col">';
                if ($ysnUpdateButtonOnlyOnce == 1) {
                    $onlyonce = 'onlyonce first';
                } else {
                    $onlyonce = '';
                }
                $formcontent .= "<button type='button' id='btnUpdate' onfocus=\"evaluate_buttons($formid,'$strValidationFunction')\" disabled $onlyonce onclick='call_api (\"" . $strUpdateApi . "\",$id,\"@VALIDITY_FILE@\",\"@VALIDITY_CODE@\")'";
                if ($strUpdateClass != '') {
                    $formcontent .= " class='$strUpdateClass'";
                }
                $formcontent .= ">" . $strUpdateButton . '</button>';
                $formcontent .= "</div>\n";
            }
            if ($strCreateButton != '') {
                if ($strUpdateButton == '') {
                    $formcontent .= '<div class="form-group row">';
                }
                $formcontent .= '<div class="col">';
                if ($ysnCreateButtonOnlyOnce == 1) {
                    $onlyonce = 'onlyonce first';
                } else {
                    $onlyonce = '';
                }
                $formcontent .= "<button type='button' id='btnCreate' disabled $onlyonce onclick='call_api (\"" . $strCreateApi . "\",$id,\"@VALIDITY_FILE@\",\"@VALIDITY_CODE@\")'";
                if ($strCreateClass != '') {
                    $formcontent .= " class='$strCreateClass'";
                }
                $formcontent .= ">" . $strCreateButton . '</button>';
                $formcontent .= "</div>\n";
            }
            $formcontent .= "</div>\n";
            $formcontent .= "</form>\n";
            $formcontent .= "</div>\n"; // container
    $formcontent .= '<div id="message_api" style="color: red"></div>';

            if ($this->api_validity_file != '' && $this->api_validity_code != '') {
                $formcontent = str_replace ('@VALIDITY_FILE@',$this->api_validity_file,$formcontent);
                $formcontent = str_replace ('@VALIDITY_CODE@',$this->api_validity_code,$formcontent);
            }
            $html = $array_attributes ['beforeTag'] . $formcontent . $array_attributes['afterTag'];
        } else {
            $html = $array_attributes ['beforeTag'] . "form id $id not found" . $array_attributes['afterTag'];
        }

        $this->nremplacements++;

        return ($html);
    }

    function keep_combo($html)
    {
        //$this->display("keep_combo()");
        $array_attributes = $this->get_tag_attributes("COMBO",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;combo";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/combo&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function keep_formmpc($html)
    {
        //$this->display("keep_formmpc()");
        $array_attributes = $this->get_tag_attributes("FORMMPC",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;combo";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/formmpc&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function keep_mustache($html)
    {
        $array_attributes = $this->get_tag_attributes("MUSTACHE",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;combo";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/mustache&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function keep_include($html)
    {
        $array_attributes = $this->get_tag_attributes("INCLUDE",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;combo";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/include&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    public function get_tag_attributes ($tag,?string $text) : array
    {
        $attributes = array();

        if (is_null ($text)) {
            $text = '';
        }

        $uppertext = strtoupper($text);
        $uppertag = strtoupper($tag);

        if ($uppertag == 'RESTRICT') {
            $booDisplay = false;
        } else {
            $booDisplay = false;
        }
        //$this->display("get_tag_attributes($tag,\"" . htmlspecialchars (substr($text,0,100)) . "\"");

        $i = strpos ($uppertext,"<$uppertag ");
        if ($booDisplay) $this->display ("recherche de <$uppertag ");
        if ($booDisplay) $this->display ("i=$i");
        if ($i === FALSE) { // TAG without attributes
            if ($booDisplay) $this->display("on essaie le TAG sans attribut");
            $i = strpos ($uppertext,"<$uppertag");
            if ($i === FALSE) {
                if ($booDisplay) $this->display("i est toujours FALSE");
            }
        }

        $attributes['found'] = false;
        if ($i !== FALSE) {
            $j = strpos ($uppertext,"</$uppertag>");
            if ($booDisplay) $this->display("i=$i j=$j");
            if ($j === FALSE) {
                if ($booDisplay) $this->display("pas de tag de fin");
                return $attributes;
            }

            $attributes['found'] = true;
            $attributes['beforeTag'] = substr ($text,0,$i);
            //$this->display("beforeTag=" . htmlspecialchars ($attributes['beforeTag']));
            $attributes['afterTag'] = substr ($text,$j+strlen($tag)+3);
            if ($booDisplay) $this->display("afterTag = " . $attributes['afterTag']);

            $jj = strpos (substr($uppertext,$i) ,">") + $i; // Fin de la balise ouverture
            if ($booDisplay) $this->display("jj=$jj");

            $attributes['innerHtml'] = substr ($text,$jj+1,$j-$jj-1);
            if ($booDisplay) $this->display("innerHtml=" . $attributes['innerHtml']);

            $balise = trim (substr ($text,$i+strlen($tag)+2,$jj-$i-strlen($tag)-2));
            //$this->display("content=" . htmlspecialchars($content));
            if ($booDisplay) $this->display("balise=" . htmlspecialchars($balise));
            $pos_egal = strpos ($balise,'=');
            while ($pos_egal !== FALSE) {
                $avant = trim (substr($balise,0,$pos_egal));

                $apres = trim (substr($balise,$pos_egal+1));
                $valeur = "";
                if (strlen ($apres) > 0) {
                    $separateur = substr ($apres,0,1);
                    $apres = substr ($apres,1);
                    $posfin = strpos ($apres,$separateur);
                    $valeur = substr ($apres,0,$posfin);
                    $balise = trim (substr ($apres,$posfin+1));
                }
                $attributes[strtolower($avant)] = $valeur;
                if ($booDisplay) $this->display ("Nouvel attribut : " . strtolower($avant));
                $pos_egal = strpos ($balise,'=');
            }
        } else {
            //$attributes['beforeTag'] = htmlspecialchars($text);
            //$attributes['afterTag'] = $attributes['innerHtml'] = "";
            $attributes['found'] = false;
        }
        //print_r($attributes);
        //$this->display("");

        if ($booDisplay) $this->display("FIN DE get_tag_attributes($tag,\"" . htmlspecialchars (substr($text,0,100)) . "\"");
        return ($attributes);
    }

    public function get_tag_attributes_html ($tag,$text) : array
    {
        $attributes = array();

        $uppertext = strtoupper($text);
        $uppertag = strtoupper($tag);

        if ($uppertag == 'RESTRICT') {
            $booDisplay = false;
        } else {
            $booDisplay = false;
        }

        $i = strpos ($uppertext,"&lt;$uppertag ");
        if ($i === FALSE) { // TAG without attributes
            $i = strpos ($uppertext,"&lt;$uppertag");
            if ($i === FALSE) {
            }
        }

        $attributes['found'] = false;
        if ($i !== FALSE) {
            $j = strpos ($uppertext,"&lt;/$uppertag&gt;");
            if ($j === FALSE) {
                return $attributes;
            }

            $attributes['found'] = true;
            $attributes['beforeTag'] = substr ($text,0,$i);
            $attributes['afterTag'] = substr ($text,$j+strlen($tag)+6);

            $jj = strpos (substr($uppertext,$i) ,"&gt;") + $i; // Fin de la balise ouverture

            $attributes['innerHtml'] = substr ($text,$jj+1,$j-$jj-1);

            $balise = trim (substr ($text,$i+strlen($tag)+2,$jj-$i-strlen($tag)-2));
            $pos_egal = strpos ($balise,'=');
            while ($pos_egal !== FALSE) {
                $avant = trim (substr($balise,0,$pos_egal));

                $apres = trim (substr($balise,$pos_egal+1));
                $valeur = "";
                if (strlen ($apres) > 0) {
                    $separateur = substr ($apres,0,1);
                    $apres = substr ($apres,1);
                    $posfin = strpos ($apres,$separateur);
                    $valeur = substr ($apres,0,$posfin);
                    $balise = trim (substr ($apres,$posfin+1));
                }
                $attributes[strtolower($avant)] = $valeur;
                $pos_egal = strpos ($balise,'=');
            }
        } else {
            $attributes['found'] = false;
        }

        return ($attributes);
    }

    public function replace_parameters ($html)
    {
        if (is_null ($html)) {
            return '';
        }

        if (strlen($html) < 30) {
            /*
$dbt=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,2);
$caller = isset($dbt[1]['function']) ? $dbt[1]['function'] : null;
             */
        }

        $i = strpos ($html,'[%');
        if ($i === FALSE) {
            return ($html);
        }

        if (is_null ($this->tabparams)) {
            return ($html);
        }
        if (is_null ($this->tabparams['parametres'])) {
            return ($html);
        }

        while ($i !== FALSE) {
            $j = strpos ($html,'%]',$i+1);
            if ($j === FALSE) {
                return ($html);
            }

            $beforeTag = substr ($html,0,$i);
            $afterTag = substr ($html,$j+2);

            $strParamName = substr ($html,$i+2,$j-$i-2);
            $strParamName = trim ($strParamName);

            if (is_null ($this->tabparams['parametres'])) {
                $strValeur = "tabparams est null";
            } else {
                if (key_exists ($strParamName,$this->tabparams['parametres'])) {
                    $strValeur = $this->tabparams['parametres'][$strParamName];
                } else {
                    $strValeur = "param $strParamName not found";
                }
            }
            $this->nremplacements++;

            $html = $beforeTag . $strValeur . $afterTag;
            $i = strpos ($html,'[%');
        }

        return ($html);
    }

    function replace_special_tags ($html)
    {
        $strContent = $html;

        do {
            $this->nremplacements=0;
            $strContent = $this->replace_restrict($strContent);
            $strContent = $this->replace_include($strContent);
            $strContent = $this->replace_parameters($strContent);
            if ($this->site != 'admin_') {
                $strContent = $this->replace_mustache($strContent);
            }
            $strContent = $this->replace_combo($strContent);
            if ($this->site != 'admin_') {
                $strContent = $this->replace_block($strContent);
            }
            $strContent = $this->replace_vocabulary($strContent);
            $strContent = $this->replace_menu($strContent);
            $strContent = $this->replace_formmpc($strContent);
        } while ($this->nremplacements > 0);

        return ($strContent);
    }

    function keep_special_tags ($html)
    {
        do {
            $this->nremplacements=0;
            $html = $this->keep_include($html);
            $html = $this->keep_mustache($html);
            $html = $this->keep_combo($html);
            $html = $this->keep_block($html);
            $html = $this->keep_vocabulary($html);
            $html = $this->keep_menu($html);
            $html = $this->keep_formmpc($html);
            $html = $this->keep_restrict($html);
            $html = $this->keep_icon($html);
        } while ($this->nremplacements > 0);

        return ($html);
    }

    function replace_block($html)
    {
        //return ($this->keep_block($html));
        // Exemple : <block id="12" name="nom"></block>

        $id = $name = "";

        $array_attributes = $this->get_tag_attributes("BLOCK",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("id",$array_attributes)) {
            $id = $array_attributes['id'];
        }
        if (array_key_exists("name",$array_attributes)) {
            $name = $array_attributes['name'];
        }

        $contenu_block = "";
        if ($id != "") {
            if ($this->idLanguage > 0) {
                $sqlCmd = "SELECT idBlock, idBlockContent, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, BC.strContent AS BCstrContent, B.booEditable AS BbooEditable, BC.booEditable AS BCbooEditable, " .
                    "strTablename, strScripts, strScriptsAfterContent FROM " . $this->site . 'block B ' .
                    'LEFT JOIN ' . $this->site . "block_content BC ON BC.intBlock=B.idBlock AND BC.intLanguage=$this->idLanguage " .
                    "WHERE idBlock=$id";
            } else {
                $sqlCmd = "SELECT idBlock, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, '' AS BCstrContent, B.booEditable AS BbooEditable, 0 AS BCbooEditable, " .
                    "strTablename, strScripts, strScriptsAfterContent FROM " . $this->site . 'block B ' .
                    "WHERE idBlock=$id";
            }

            $block = $this->db->select ($sqlCmd);
            if ($block->success && $block->numrows == 1) {
                $contenu_block = $this->ManageBlock ($block->data[0]);
                $this->nremplacements++;
            } else {
                $contenu_block = "<br><font color='red'>Block with id=$id not found<br>$sqlCmd</font><br>";
                //$contenu_block .= "<br>" . $block->status['errormessage'] . "<br>";
            }
        } else if ($name != "") {
            if ($this->idLanguage > 0) {
                $sqlCmd = "SELECT idBlock, idBlockContent, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, BC.strContent AS BCstrContent, B.booEditable AS BbooEditable, BC.booEditable AS BCbooEditable, " .
                    "strTablename, strScripts, strScriptsAfterContent FROM tbl_block B " .
                    "LEFT JOIN tbl_block_content BC ON BC.intBlock=B.idBlock AND BC.intLanguage=$this->idLanguage " .
                    "WHERE B.strName='$name'";
            } else {
                $sqlCmd = "SELECT idBlock, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, '' AS BCstrContent, B.booEditable AS BbooEditable, BC.booEditable AS BCbooEditable, " .
                    "strTablename, strScripts, strScriptsAfterContent FROM tbl_block B " .
                    "WHERE B.strName='$name'";
            }
            $block = $this->db->select ($sqlCmd);
            if ($block->success && $block->numrows == 1) {
                $contenu_block = $this->ManageBlock ($block->data[0]);
            } else {
                $contenu_block = "Block with name='$name' not found";
            }
            $this->nremplacements++;
        }
        $result = $array_attributes['beforeTag'] . $contenu_block . $array_attributes['afterTag'];

        return ($result);
    }

    function keep_block ($html)
    {
        $array_attributes = $this->get_tag_attributes("BLOCK",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;block";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/block&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function replace_vocabulary($html) : string
    {
        // Exemple : <block id="12" name="nom"></block>

        $tagarray = [];
        $tagarray[0] = 'VOCABULARY';
        $tagarray[1] = 'VOCA';
        /*
        $this->tabparams['parametres'] = array();
         */

/*
        if ($this->site == 'admin_') {
            return ($html);
        }
*/

        for ($itag = 0; $itag < sizeof ($tagarray); $itag++) {
            $tag = $tagarray[$itag];
            $found = false;

            $array_attributes = $this->get_tag_attributes($tag,$html);
            if(! $array_attributes['found']) {
            }

            $replaced = "";
            while ($array_attributes['found']) {
                $found = true;

                if (array_key_exists("innerHtml",$array_attributes)) {
                    $voca = $array_attributes['innerHtml'];

                    if ($this->idLanguage > 0) {
                        $sqlCmd = "SELECT strValue,booEditable FROM " . $this->site . "vocabulary WHERE strName='$voca' AND intLanguage=" . $this->idLanguage;
                    } else {
                        $sqlCmd = "SELECT strValue,booEditable FROM " . $this->site . "vocabulary WHERE strName='$voca' AND intLanguage=1";
                    }
                    $res = $this->db->first($sqlCmd);
                    if (! $res->success) {
                        $replaced = "";
                    } else if ($res->numrows == 1) {
                        if (($this->booEditableVocabulary || ($this->site == 'admin_' && $this->booEditableVocabulary_admin)) && $res->data['booEditable'] == 1) {
                            $replaced = "<span oncontextmenu=\"return mnuCMS(this,'editvocabulary','$voca',0)\">" . $res->data['strValue'] . '</span>';
                        } else {
                            $replaced = $res->data['strValue'];
                        }
                    } else {
                        //$this->display ("Error finding vocabulary $voca [" . $res->error . "]");
                        if ($this->booEditableVocabulary || ($this->site == 'admin_' && $this->booEditableVocabulary_admin)) {
                            $replaced = "<span oncontextmenu=\"return mnuCMS(this,'editvocabulary','$voca',0)\"><s><b>$voca</b></s></span>";
                        } else {
                            $replaced = "<s>$voca</s>";
                        }
                    }
                } else {
                    $replaced = "pas de innerHtml";
                    //$this->display ("pas de innerHtml");
                }
                $this->nremplacements++;
                $html = $array_attributes['beforeTag'] . $replaced . $array_attributes['afterTag'];

                $array_attributes = $this->get_tag_attributes($tag,$html);
            }
        }

        return ($html);
    }

    function replace_vocabulary_html($html) : string
    {

        $tagarray = [];
        $tagarray[0] = 'VOCABULARY';
        $tagarray[1] = 'VOCA';

        $bd = null;

        for ($itag = 0; $itag < sizeof ($tagarray); $itag++) {
            $tag = $tagarray[$itag];
            $found = false;

            $array_attributes = $this->get_tag_attributes_html($tag,$html);
            if(! $array_attributes['found']) {
            }

            $replaced = "";
            while ($array_attributes['found']) {
                $found = true;

                if (array_key_exists("innerHtml",$array_attributes)) {
                    $voca = $array_attributes['innerHtml'];

                    $sqlCmd = "SELECT strValue FROM " . $this->site . "vocabulary WHERE strName='$voca' AND intLanguage=" . $this->idLanguage;
                    $res = $this->db->first($sqlCmd);
                    if (! $res->success) {
                        $replaced = "";
                    } else if ($res->numrows == 1) {
                        $replaced = $res->data['strValue'];
                    }
                } else {
                    $replaced = "pas de innerHtml";
                }
                $this->nremplacements++;
                $html = $array_attributes['beforeTag'] . $replaced . $array_attributes['afterTag'];

                $array_attributes = $this->get_tag_attributes($tag,$html);
            }
        }

        return ($html);
    }

    function keep_vocabulary($html)
    {
        $tagarray = [];
        $tagarray[0] = 'VOCA';
        $tagarray[1] = 'VOCABULARY';

        for ($itag = 0; $itag < sizeof ($tagarray); $itag++) {
            $tag = $tagarray[$itag];
            $lowertag = strtolower ($tag);
            $array_attributes = $this->get_tag_attributes($tag,$html);
            if ($array_attributes['found']) {
                $this->nremplacements++;

                $result = $array_attributes ['beforeTag'];
                $result .= "&lt;$lowertag&gt;";
                $result .= $array_attributes['innerHtml'];
                $result .= "&lt;/$lowertag&gt;";
                $result .= $array_attributes['afterTag'];
                return ($result);
            }
        }

        return ($html);
    }

    function GenererChangerLangue ()
    {
        $tbllanguages = $this->tbllanguages;
        //$bd = new Pdo_sql_model(__DATABASE__,true);

        $menu = "\n/* GenererChangerLangue */\nfunction changer_langue (langue)\n";
        $menu .= "{\n";

        $sqlCmd = "SELECT strLanguage FROM $tbllanguages";
        $langues = $this->db->select ($sqlCmd);

        if ($langues->success && $langues->numrows > 0) {
            $numligne=1;
            foreach ($langues->data as $key => $rowlangues) {
                if ($numligne == 1) {
                    $menu .= "\tif (langue == '" . $rowlangues['strLanguage'] . "') {\n";
                    $menu .= "\t\tdocument.location.href = route_" . $rowlangues['strLanguage'] . ";\n";
                } else {
                    $menu .= "\t} else if (langue == '" . $rowlangues['strLanguage'] . "') {\n";
                    $menu .= "\t\tdocument.location.href = route_" . $rowlangues['strLanguage'] . ";\n";
                }
                $numligne++;
            }
            $menu .= "\t}\n";
        }
        $menu .= "}\n";

        return ($menu);
    }

    function replace_menu($html)
    {
        //$this->display("replace_menu()");
        //return ($this->keep_menu ($html));
        // Exemple : <menu id="12" name="nom"></menu>

        $tblmenuitems = $this->tblmenuitems;
        $tbllanguages = $this->tbllanguages;
        $tblroutes = $this->tblroutes;
        $strHomeTitle = $this->strHomeTitle;

        $id = $name = "";

        $array_attributes = $this->get_tag_attributes("MENU",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if (array_key_exists("id",$array_attributes)) {
            $id = $array_attributes['id'];
        }
        if (array_key_exists("name",$array_attributes)) {
            $name = $array_attributes['name'];
        }

        //$bd = new Pdo_sql_model(__DATABASE__,true);
        $error = "";
        if ($id != "") {
            $sqlCmd = "SELECT idMenu, strName FROM $this->tblmenus WHERE idMenu=$id";
            $block = $this->db->select ($sqlCmd);
            if ($block->success && $block->numrows == 1) {
                $name = $block->data[0]['strName'];
            } else {
                $error = "Menu with id=$id not found";
                $error .= "<br>" . $block->status['errormessage'] . "<br>";
                $error .= "<br>$sqlCmd<br>";
            }
        } else if ($name != "") {
            $sqlCmd = "SELECT idMenu,strName FROM $this->tblmenus WHERE strName='$name'";
            $block = $this->db->select ($sqlCmd);
            if ($block->success && $block->numrows == 1) {
                $id = $block->data[0]['idMenu'];
            } else {
                $error = "Menu with name=$name not found";
            }
        } else {
            return ($array_attributes['beforeTag'] . "<br><font color='red'>MENU NOT FOUND</font><br>" . $array_attributes['afterTag']);
        }

        $this->nremplacements++;

        $sqlCmd = "SELECT * FROM $tblmenuitems LEFT JOIN $tblroutes ON $tblroutes.idRoute=$tblmenuitems.intLinkRoute WHERE intMenu=$id ORDER BY intOrdre";

        $menuitems = $this->db->select ($sqlCmd);
        if ($menuitems->success && $menuitems->numrows > 0) {
            $menu = "";
/*
            $menu = "<SCRIPT>\nfunction changer_langue (langue)\n";
            $menu .= "{\n";

            $sqlCmd = "SELECT strLanguage FROM $tbllanguages";
            $langues = $bd->select ($sqlCmd);

            if ($langues->success && $langues->numrows > 0) {
                $numligne=1;
                foreach ($langues->data as $key => $rowlangues) {
                    if ($numligne == 1) {
                        $menu .= "\tif (langue == '" . $rowlangues['strLanguage'] . "') {\n";
                        $menu .= "\t\tdocument.location.href = route_" . $rowlangues['strLanguage'] . ";\n";
                    } else {
                        $menu .= "\telse if (langue == '" . $rowlangues['strLanguage'] . "') {\n";
                        $menu .= "\t\tdocument.location.href = route_" . $rowlangues['strLanguage'] . ";\n";
                    }
                    $numligne++;
                }
                $menu .= "\t}\n";
            }

            $menu .= "}\n</SCRIPT>\n";
*/

            $menu .= "<nav class='navbar navbar-expand-sm bg-dark navbar-dark fixed-top me-auto'>";
            $menu .= "<div class='container-fluid'>";
            $menu .= "<div class='onlysmartphone'>";
            $menu .= "<button id='hamburger' class='navbar-toggler' type='button' data-bs-toggle='collapse' data-bs-target='#navbarCollapse'>";
            $menu .= "<span class='fa fa-bars' style='text-align: right;'></span>";
            $menu .= "</button>";
            $menu .= "</div>";

            $menu .= "<div class='collapse navbar-collapse' id='navbarCollapse'>";
            $menu .= "<div class='navbar-nav ms-auto py-0'>";
            $menu .= "<ul class='navbar-nav'>";

            if ($strHomeTitle != "") {
                $menu .= "<a class='navbar-brand' href='/nl/onthaal'>$strHomeTitle</a>";
            }

            foreach ($menuitems->data as $key => $row) {
                $menu .= "<li class='nav-item'><a class='nav-link active' href='" .    $row['strPath'] . "'>";
//$this->display ('strItem=' . $row['strItem'] . ' intPermission=' . $row['intPermission']);
                if (! is_null ($row['intPermission'])) {
                    $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "'," . $row['intPermission']. ") AS PERMS");
                    if ($result->success) {
                        $pos = strpos($result->data[0]['PERMS'], $row['strPermission']);
                        if ($pos !== false) {
                            $menu .= $row['strItem'];
                        } else {
                            $menu .= "not allowed: " . $row['strItem'];
                        }
                    }
                } else {
                    $menu .= $row['strItem'];
                }
                $menu .= "</a></li>";
            }
            $menu .= "</ul></div></div>";
            $menu .= "<div id='idLanguage' style='color: red'>";
            if ($this->idLanguage == 1) {
                $menu .= "<button type='button' onclick='changer_langue (\"nl\")'>NL</button>";
            } else {
                $menu .= "<button type='button' onclick='changer_langue (\"fr\")'>FR</button>";
            }
            $menu .= "</div></div>";
            $menu .= "</nav><br><br>";
        } else {
            $menu = "Pas de ligne trouvée pour le menu $name";
        }

        //$bd->close ();

        return ($array_attributes['beforeTag'] . $menu . $array_attributes['afterTag']);
    }

    function keep_menu($html)
    {
        $array_attributes = $this->get_tag_attributes("MENU",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;menu";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;&lt;/menu&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function replace_restrict($html)
    {
        //return ($this->keep_restrict($html));
        // Exemple : <restrict idpermission='12' type='R' user='nom'></restrict> => Je dois $etre connecté come user 'nom' et avoir la permission R(Read) sur 12.

        $idPermission = $permission = $idUser = $user = $idgroup = $group = "";
        $booAuthorized = true;

        $array_attributes = $this->get_tag_attributes("RESTRICT",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        if ($this->strCurrentUser == '') {
            $this->nremplacements++;
            return ($array_attributes['beforeTag'] . $array_attributes['afterTag']);
        }

        $this->nremplacements++;
        $contenu = $array_attributes['innerHtml'];

        if (array_key_exists("idpermission",$array_attributes)) {
            $idPermission= $array_attributes['idpermission'];
        }
        if (array_key_exists("permissionid",$array_attributes)) {
            $idPermission= $array_attributes['permissionid'];
        }

        if (array_key_exists("permission",$array_attributes)) {
            $permission= $array_attributes['permission'];
        }

        if ($permission != "") {
            $sqlCommand = "SELECT * FROM " . __SECUREPREFIX__ . "permissions WHERE strName='" . str_replace ("'","''",$permission) . "'";
            $result = $this->db->select($sqlCommand);

            if (! $result->success) {
                $this->nremplacements++;
                return ($array_attributes['beforeTag'] . "Unknow permission name: $permission<br>SQL : $sqlCommand<br>" . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                $this->nremplacements++;
                return ($array_attributes['beforeTag'] . "Unknow permission name: $permission<br>SQL : $sqlCommand<br>" . $array_attributes['afterTag']);
            }

            if ($idPermission != "") {
                if ($result->data[0]['idPermission'] != $idPermission) {
                    $this->nremplacements++;
                    //$bd->close ();
                    return ($array_attributes['beforeTag'] . "idPermission ($idPermission) does not correspond to name: $permission" . $array_attributes['afterTag']);
                }
            } else {
                $idPermission = $result->data[0]['idPermission'];
            }
        }
        if ($idPermission != "") {
            $result = $this->db->select("SELECT * FROM " . __SECUREPREFIX__ . "permissions WHERE idPermission=$idPermission");

            if (! $result->success) {
                $this->nremplacements++;
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "Unknow idPermission : $idPermission" . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                $this->nremplacements++;
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "Unknow idPermission : $idPermission" . $array_attributes['afterTag']);
            }

            $sqlCommand = "SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "',$idPermission) AS PERMS";
            $result = $this->db->select($sqlCommand);
            if (! $result->success) {
                $this->nremplacements++;
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "Call to function fctUserPermissionsOn failed.<br>SQL : $sqlCommand<br>Error : " . $result->status['errormessage'] . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                $this->nremplacements++;
                // Permission not granted to current user.
                //$bd->close ();
                return ($array_attributes['beforeTag'] . $array_attributes['afterTag']);
            } else {
                if (array_key_exists("type",$array_attributes)) {
                    // Voir si l'utilisateur courant a la permission 'type'.
                    $type = strtoupper ($array_attributes['type']);
                    $strPermissions = strtoupper ($result->data[0]['PERMS']);

                    $chars = str_split($type);
                    foreach ($chars as $char) {
                        if (strpos ($strPermissions,$char) === FALSE) {
                            // The current user does not have the permission type required by the tag TYPE.
                            //$bd->close ();
                            return ($array_attributes['beforeTag'] . "<br>User does not have the permission $char<br>type=$type PERMS=$strPermissions<br>" . $array_attributes['afterTag']);
                        }
                    }
                }
            }
        }

        if (array_key_exists("user",$array_attributes)) {
            $user = $array_attributes['user'];
            if ($user != $this->strCurrentUser) {
                // The current user does not correspond to the user in the tag RESTRICT.
                //$bd->close ();
                return ($array_attributes['beforeTag'] . $array_attributes['afterTag']);
            }
        }

        if (array_key_exists("iduser",$array_attributes)) {
            $iduser = $array_attributes['iduser'];
            $result = $this->db->select("SELECT strUserName FROM " . __SECUREPREFIX__ . "users WHERE idUser=$iduser");
            if (! $result->success) {
                $this->nremplacements++;
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "Unknow idUser : $iduser" . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                $this->nremplacements++;
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "Unknow idUser : $iduser" . $array_attributes['afterTag']);
            }
            if ($result->data[0]['strUserName'] != $this->strCurrentUser) {
                // The current user does not correspond to the idUser in the tag RESTRICT.
                //$bd->close ();
                return ($array_attributes['beforeTag'] . $array_attributes['afterTag']);
            }
        }

        if (array_key_exists("group",$array_attributes)) {
            $group = $array_attributes['group'];
            $result = $this->db->first ("SELECT * FROM " . __SECUREPREFIX__ . "groups WHERE strName='" . str_replace ("'","''",$group) . "'");

            if (! $result->success) {
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "<br>group not found : $group<br>" . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "<br>group not found : $group<br>" . $array_attributes['afterTag']);
            } else {
                $idgroup = $result->data['idGroup'];
            }
        }

        if (array_key_exists("idgroup",$array_attributes)) {
            if (($idgroup != "" ) && ($idgroup != $array_attributes['idgroup'])) {
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "idgroup ($idgroup) does not correspond to name: $group" . $array_attributes['afterTag']);
            }
            $idgroup = $array_attributes['idgroup'];
            $result = $this->db->first ("SELECT * FROM " . __SECUREPREFIX__ . "users_in_groups WHERE intUser=$this->strCurrentUserId AND intGroup=$idgroup");

            if (! $result->success) {
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "User not in idgroup $idgroup " . $array_attributes['afterTag']);
            } else if ($result->numrows != 1) {
                //$bd->close ();
                return ($array_attributes['beforeTag'] . "User not in idgroup $idgroup " . $array_attributes['afterTag']);
            }

            //$bd->close ();
        }

        //$bd->close ();

        if (! $booAuthorized) {
            return ($array_attributes['beforeTag'] . $array_attributes['afterTag']);
        }

        return ($array_attributes['beforeTag'] . $contenu . $array_attributes['afterTag']);
    }

    function keep_restrict ($html)
    {
        $array_attributes = $this->get_tag_attributes("RESTRICT",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;restrict";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;" . $array_attributes ['innerHtml'] . "&lt;/restrict&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    function keep_icon ($html)
    {
        $array_attributes = $this->get_tag_attributes("I",$html);

        if (! $array_attributes['found']) {
            return ($html);
        }

        $result = $array_attributes ['beforeTag'];
        $result .= "&lt;i";
        foreach ($array_attributes as $key => $valeur) {
            if ($key != 'beforeTag' && $key != 'afterTag' && $key != 'found' && $key != 'innerHtml') {
                $result .= " $key='$valeur'";
            }
        }
        $result .= "&gt;" . $array_attributes ['innerHtml'] . "&lt;/i&gt;";

        $result .= $array_attributes['afterTag'];
        $this->nremplacements++;

        return ($result);
    }

    private function ManageBlock ($row)
    {
        global $params;

        $strScripts = $this->replace_parameters ($row['strScripts']);
        $strScriptsAfterContent = $this->replace_parameters ($row['strScriptsAfterContent']);

        $this->api_validity_file = $this->api_validity_code = '';

        if ($this->booDebug == 1) {
            $strContent = "\n<!-- Block id=" . $row['idBlock'] . " -->\n";
            /*
            if ($strScripts != '') {
                $strContent = "\n<!-- Scripts=$strScripts -->\n";
            }
            */
        } else {
            $strContent = "";
        }

        //$booEditable = $this->fctUserCanUpdate();
        $booEditable = ($this->site == 'tbl_' && $this->booEditableBlocks) || ($this->site == 'admin_' && $this->booEditableBlocks_admin);
        $strTemplateMustache = $this->replace_parameters ($row['strTemplateMustache']);
//$this->display ('ManageBlock idBlock=' . $row['idBlock'] . ' intContentType=' . $row['intContentType']);
$strContent .= "\n<!-- ManageBlock idBlock='" . $row['idBlock'] . ' intContentType=' . $row['intContentType'] . ' -->';
        if ($row['intContentType'] == 2) { // php
            $classe = $this->replace_parameters ($row['strClass']);
//$this->display ('ManageBlock idBlock=' . $row['idBlock'] . ' intContentType=' . $row['intContentType']);
            $methode = $this->replace_parameters ($row['strMethod']);
//$this->display("ContentType=2 $classe:$methode");

            if ($classe != '') {
                if (! class_exists ($classe)) {
                    throw new ClassNotFoundException ($classe);
                }
                if (! method_exists ($classe,$methode)) {
                    throw new MethodNotFoundException ($classe,$methode);
                }
                $strContent .= "\n<!-- Start class $classe -->\n";

//$this->display("Appel de $classe:$methode");
                $class = new $classe();
                if ($class instanceof \Customer\Model) {
                    $class->idBlock = $row['idBlock'];
                    $class->strName = $row['strName'];
                    $class->intContentType = $row['intContentType'];
                    $class->strScripts = $strScripts;
                    $class->strScriptsAfterContent = $strScriptsAfterContent;
                    $class->strTemplateMustache = $strTemplateMustache;
                    $class->strContent = $this->replace_parameters ($row['BstrContent']);
                    $class->strTablename = $this->replace_parameters ($row['strTablename']);
                    $class->strParams = $this->replace_parameters ($row['strParams']);

                    $class->strLanguage = $this->strLanguage;
                    $class->idLanguage = $this->idLanguage;
                    $class->intLanguage = $this->idLanguage;
                    $class->intPage = $this->intPage;
                    $class->strPath = $this->strPath;
                    $class->strTitle = $this->strTitle;
                    $class->idRoute = $this->intRoute;
                    $class->params = $params;
                    $class->routes_languages = $this->javascript_json;
                    $class->router = $this;
                }

                $strContent .= call_user_func_array([$class,$methode],[]);
                if ($class instanceof \Customer\Model) {
                    $strContent = $class->AfterRender ($strContent);
                    $strScripts = $class->strScripts;
                    $strScriptsAfterContent = $class->strScriptsAfterContent;
                }
                if ($booEditable && $row['BbooEditable'] == 1) {
                    $strContent = "<span oncontextmenu=\"return mnuCMS(this,'editmodule','$this->tblblock'," . $row['idBlock'] . ")\">$strContent</span>";
                }
                $strContent .= "\n<!-- After $classe -->\n";
            }
        } else if ($row['intContentType'] == 3) {
            $this->intDataDiv++;
            $strTablename = $this->replace_parameters ($row['strTablename']);
            $strContent .= "\n<!-- ContentType=3 load content of table $strTablename -->\n";
            $sqlCommand = "SELECT * FROM $strTablename";
            //$bd = new Pdo_sql_model(__DATABASE__,true);
            $result = $this->db->selectobj ($sqlCommand);
            if (! $result->success) {
                $strContent .= "La requête a échou� ($sqlCommand)�";
            } else if ($result->numrows < 1) {
                $strContent .= 'La table est vide';
            } else {
                $strContent .= 'La table contient ' . $result->numrows . ' enregistrement(s)';
                $data = json_encode ($result->dataobj);
                if ($strTemplateMustache == '') {
                    $strTemplateMustache = $result->dataobj->templatemustache;
                    if ($row['ysnSaveGeneratedTemplate'] == 1) {
                        $sqlCommand = "UPDATE $tblblock SET strTemplateMustache=? " .
                        "WHERE idBlock=" . $row['idBlock'];
                        $this->db->update ($sqlCommand,str_replace ("'","''",$strTemplateMustache));
                    }
                }
                $met = new \Customer\Model ();
                $strTemplateMustache = str_replace ('@TABLEID@','table_id' . $this->intDataDiv,$strTemplateMustache);
                $render = $met->render ($data,$strTemplateMustache);
                $strContent .= $render;
            }
        } else if ($row['intContentType'] == 4) { // Table with update
            $strTablename = $this->replace_parameters ($row['strTablename']);
//$this->display("type 4 : update table $strTablename");
            $strContent .= "\n<!-- ContentType=4 load content of table $strTablename for UPDATE -->\n";

            if ($booEditable && $row['BbooEditable'] == 1) {
                $strContent = "<span oncontextmenu=\"return mnuCMS(this,'edittable','admin'," . $row['idBlock'] . ")\">";
            }
$strContent .= "<div id='data' class='container-fluid' style='padding-left: 60px;'>";

$browse = $this->db->gettablebrowse ($strTablename);
            //$str = fctgetdata (1,__DATABASE__,$strTablename,"SELECT $browse FROM $strTablename LIMIT 100");
            $str = fctgetdata (1,__DATABASE__,$strTablename,"SELECT $browse FROM $strTablename",$this);

            $strContent .= $str;
$strContent .= "</div><script>MontrerSearch();</script>";

            $this->intDataDiv++;
            /*
            $sqlCommand = "SELECT * FROM $strTablename";
            $result = $bd->select ($sqlCommand,false);
            if (! $result->success) {
                $strContent .= 'La requête a échoué';
            } else if ($result->numrows < 1) {
                $strContent .= 'La table est vide';
            } else {
                $strContent .= 'La table contient ' . $result->numrows . ' enregistrement(s)';
                $strTemplateMustache = $result->dataobj->templatemustacheupdate;
                $data = json_encode ($result->dataobj);
                if ($strTemplateMustache == '') {
                    $strContent .= $data;
                    $strTemplateMustache = $result->dataobj->templatemustache;
                    if ($row['ysnSaveGeneratedTemplate'] == 1) {
                        $sqlCommand = "UPDATE $tblblock SET strTemplateMustache=? " .
                        "WHERE idBlock=" . $row['idBlock'];
                        $bd->update ($sqlCommand,str_replace ("'","''",$strTemplateMustache));
                    }
                }
                $met = new \Customer\Model ();
                $strTemplateMustache = str_replace ('@TABLEID@','table_id' . $this->intDataDiv,$strTemplateMustache);
                $render = $met->render ($data,$strTemplateMustache);
                $strContent .= $render;
            }
             */
        } else if ($row['intContentType'] == 5) {
            $strContent .= "\n<!-- ContentType=5 load content from file -->\n";

            $strParams = $this->replace_parameters ($row['strParams']);

            if ($booEditable && $row['BbooEditable'] == 1) {
                $strContent .= "<span oncontextmenu=\"return mnuCMS(this,'editfile','" . str_replace ('/',__DIRSEP__,$strParams) . "','')\">";
            }
            if (file_exists ($strParams)) {
                $html = file_get_contents ($strParams);
                $strContent .= $html;
            } else {
                $strContent .= "Le fichier " . $strParams . " n'existe pas";
            }

            if ($booEditable && $row['BbooEditable'] == 1) {
                $strContent .= "</span>";
            }
            return ($strContent);
        } else if ($row['intContentType'] == 6) { // Edit record
//$this->display("type 6 : edit record $strTablename");
            $strContent .= "\n<!-- ContentType=6 Edit record -->\n";
            $strContent .= '<script>' . $this->replace_parameters ($row['strScripts']) . '</script>';
            $strParams = $this->replace_parameters ($row['strParams']);
            $strTablename = $this->replace_parameters ($row['strTablename']);

            $data = getrecords ($strTablename, $strParams, '', '', '', '', '');
//echo "\ndata=$data\n";
            $met = new \Customer\Model ();
            $render = $met->render ($data,$strTemplateMustache);
            $strContent .= $render;

            return ($strContent);
        } else {
            $strContent .= "\n<!-- ContentType=else -->\n";
            if ($row['BCstrContent'] != '') {
                if ($booEditable && $row['BCbooEditable'] == 1) {
                    $strContent .= "<span oncontextmenu=\"return mnuCMS(this,'editcontent','$this->tblblockcontent'," . $row['idBlockContent'] . ")\">";
                }
                $strContent .= $this->replace_parameters ($row['BCstrContent']);
                if ($booEditable && $row['BCbooEditable'] == 1) {
                    $strContent .= "</span>";
                }
                $strContent .= "\n<!-- Load strContent from $this->tblblockcontent -->\n";
            } else {
                if ($booEditable && $row['BbooEditable'] == 1) {
                    $strContent .= "<span oncontextmenu=\"return mnuCMS(this,'editcontent','" . $this->tblblock . "'," . $row['idBlock'] . ")\">";
                }
                $strContent .= $row['BstrContent'];
                if ($booEditable && $row['BbooEditable'] == 1) {
                    $strContent .= "</span>";
                }
                $strContent .= "\n<!-- Load strContent from $this->tblblock -->\n";
                /*
                if (! is_null ($row['strScriptsAfterContent']) && $row['strScriptsAfterContent'] != '') {
                    $strContent .= "\n<script>" . $row['strScriptsAfterContent'] . "\n</script>\n";
                }
                 */
            }
            if ($booEditable && $row['BbooEditable'] == 1) {
                $strContent .= "</span>\n";
            }

/*
            if (! is_null ($row['strScripts'])) {
                $strContent = '<script>' . $row['strScripts'] . "</script>$strContent";
            }
*/
        }

        if (($strScripts != '') || ($this->javascript_langues != '')) {
            //$strContent = "\n<SCRIPT>\n" . $this->javascript_langues. "\n" . $this->javascript_json_javascript . "\n\n$strScripts</SCRIPT>\n" . $strContent;
            $strContent = "\n<SCRIPT>\n// javascript_langues puis javascript_json_javascript\n" . $this->javascript_langues. "\n" . $this->javascript_json_javascript . "\n\n$strScripts\n</script>\n$strContent\n";
            $this->javascript_langues = '';
        }
        if ($strScriptsAfterContent != '') {
            $strContent .= "\n<script>\n" . $strScriptsAfterContent . "\n</script>\n";
        }

        if ($this->booDebug == 1) {
            $strContent .= "\n<!-- End of Block id=" . $row['idBlock'] . " -->\n";
        }

//$this->display ('** End of block *** idBlock=' . $row['idBlock'] . ' intContentType=' . $row['intContentType']);

        do {
            $this->nremplacements=0;
            $strContent = $this->replace_special_tags ($strContent);
        } while ($this->nremplacements > 0);

        return ($strContent);
    }

    private function getVocabulary ($intLanguage, $strCode)
    {
        $tblvoca = $this->tblvocabulary;
        if ($intLanguage != 0) {
            $result = $this->db->select ("SELECT strValue FROM $tblvoca WHERE intLanguage=$intLanguage AND strName='$strCode'");
        } else {
            $result = $this->db->select ("SELECT strValue FROM $tblvoca WHERE intLanguage=1 AND strName='$strCode'");
        }
        if (! $result->success) {
            return ($strCode);
        }
        if ($result->numrows < 1) {
            return ($strCode);
        }
        return ($result->data[0]['strValue']);
    }

    private function AfficherPage ($intRoute,$intPage,$strPath,$strTitle,$strDescription,$strAuthor,$idLanguage)
    {
        global $params;

        $tblroutes = $this->tblroutes;

        if (__USECACHE__) {
            $result = $this->db->select ("SELECT booCache FROM $tblroutes WHERE idRoute=$intRoute");
            if ($result->success && $result->numrows == 1) {
                if ($result->data[0]['booCache'] == 1) {
                    $filename = $this->url . ".html";
                    $filename = __PATHCACHE__ . str_replace ("/","_",$filename);
                    if (file_exists ($filename)) {
                        $html = file_get_contents ($filename);
                        return $html;
                    }
                    $booCache = true;
                }
            } else {
                $booCache = false;
            }
        } else {
            $booCache = false;
        }

if ($idLanguage == 0 && $this->intDefaultLanguage != null) {
    $idLanguage = $this->intDefaultLanguage;
    //$this->display("On passe &agrave; la langue par défaut");
}

$this->intRoute = $intRoute;
$this->intPage = $intPage;
$this->strPath = $strPath;
$this->strTitle = $strTitle;
$this->idLanguage = $idLanguage;
//$this->display ("AfficherPage : idLanguage=$idLanguage");
//
        $js_params = "let route_language=$this->idLanguage;\n";
        foreach ($this->tabparams['parametres'] as $key => $row) {
            $js_params .= "let param_$key='$row';\n";
        }

        // Messages utilises par validate_field().
        $js_params .= "let msg_validation_required='" . $this->getVocabulary ($idLanguage,'msg_validation_required') . "';\n";
        $js_params .= "let msg_validation_email='" . $this->getVocabulary ($idLanguage,'msg_validation_email') . "';\n";
        $js_params .= "let msg_validation_integer='" . $this->getVocabulary ($idLanguage,'msg_validation_integer') . "';\n";
        $js_params .= "let msg_validation_float='" . $this->getVocabulary ($idLanguage,'msg_validation_float') . "';\n";
        $js_params .= "let msg_validation_date='" . $this->getVocabulary ($idLanguage,'msg_validation_date') . "';\n";

//        $this->inittables($this->uri);
        $tblblock = $this->tblblock;
        $tblblockcontent = $this->tblblockcontent;
        $tblconfig = $this->tblconfig;
        $tbllanguages = $this->tbllanguages;
        $tbltemplates = $this->tbltemplates;
        $tblpagesectionblocks = $this->tblpagesectionblocks;
        $tblmenus = $this->tblmenus;
        $tblmenuitems = $this->tblmenuitems;
        $tblpages = $this->tblpages;

        $this->intDataDiv = 0;

//$this->display ("AfficherPage intRoute=$intRoute intPage=$intPage strPath=$strPath strTitle=$strTitle idLanguage=$idLanguage");
        try {
            $result = $this->db->select ("SELECT strLanguage FROM $tbllanguages WHERE idLanguage=$idLanguage");
            if (! $result->success) {
                return ("Impossible de lire dans $tbllanguages");
            } else if ($result->numrows == 1) {
                $this->strLanguage = $result->data[0]['strLanguage'];
            } else {
                $this->strLanguage = "";
            }
            $result = $this->db->select ("SELECT IFNULL(strHeader,'') AS strHeader,IFNULL(strFooter,'') AS strFooter,booDebug,IFNULL(strHomeTitle,'') AS strHomeTitle FROM $tblconfig WHERE idConfig=1");
            if (! $result->success) {
                return ("Impossible de lire strHeader et strFooter");
            }
            if ($this->site == "admin_" && $this->strCurrentUser == '') {
                return (str_replace ('@HEADTITLE@','Admin - Log in',$result->data[0]['strHeader']));
            }

            $this->strHomeTitle = $result->data[0]['strHomeTitle'];
            if ($this->strHomeTitle == null) {
                $this->strHomeTitle = "";
            }

            $this->booDebug = $result->data[0]['booDebug'];
            if ($this->booDebug == 1) {
                $strFooter = "<!-- Footer from $tblconfig -->\n" . $result->data[0]['strFooter'] . "\n<!-- End Footer from $tblconfig-->\n";
                $html = "<!-- AffichePage intRoute=$intRoute intPage=$intPage strPath=$strPath strTitle=$strTitle idLanguage=$idLanguage -->\n" ;
                $html .= "<!-- Header from $tblconfig -->\n" . $result->data[0]['strHeader'] . "\n<!-- End Header from $tblconfig-->\n";
            } else {
                $strFooter = $result->data[0]['strFooter'];
                $html = $this->replace_special_tags ($result->data[0]['strHeader']);
            }
            $strFooter = $this->replace_special_tags ($strFooter);

            if (! is_null($html)) {
                if (! is_null ($strTitle)) {
                    $html = str_replace('@HEADTITLE@',$strTitle,$html);
                } else {
                    $html = str_replace('@HEADTITLE@','',$html);
                }
                if (! is_null ($strDescription)) {
                    $html = str_replace('@HEADDESCRIPTION@',$strDescription,$html);
                } else {
                    $html = str_replace('@HEADDESCRIPTION@','',$html);
                }
                if (! is_null ($strAuthor)) {
                    $html = str_replace('@HEADAUTHOR@',$strAuthor,$html);
                } else {
                    $html = str_replace('@HEADAUTHOR@','',$html);
                }
            }

            $result = $this->db->select ("SELECT * FROM $tblroutes WHERE idRoute=$intRoute");
            $this->javascript_langues = "";
            
            $this->javascript_json_javascript = $this->GenererChangerLangue() . "\nroutes_languages='";

            $this->javascript_json = "{\"routes\":[";
            if (($result->success) && ($result->numrows == 1)) {
                $intGroup = $result->data[0]['intGroup'];
                $sqlCmd = "SELECT * FROM $tblroutes LEFT JOIN $tbllanguages ON $tbllanguages.idLanguage=$tblroutes.intLanguage WHERE intGroup=$intGroup";
                $result = $this->db->select ($sqlCmd);
                if (($result->success) && ($result->numrows > 0)) {
                    foreach ($result->data as $key => $row) {
//$this->display ('route ' . $row['strLanguage'] . ' ' . $row['strLabel'] . ' ' . $row['strPath']);
                        $this->javascript_langues .= "\nvar route_" . $row['strLanguage'] . '="/' . $row['strLanguage'] . '/' . $row['strPath'] . "\";";
                        $this->javascript_json .= ' {"idLanguage": "' . $row['idLanguage'] . '", ' .
                                 '"strLanguage": "' . $row['strLanguage'] . '", ' .
                                 '"strLabel": "' . $row['strLabel'] . '", ' .
                                 '"strPath": "/' . $row['strLanguage'] . '/' . $row['strPath'] . '"},';
                    }
                    $this->javascript_json = substr ($this->javascript_json,0,strlen($this->javascript_json)-1);
                }
            }
            $this->javascript_json .= "]}";
            $this->javascript_json_javascript .= $this->javascript_json . "';";

            $result = $this->db->select ("SELECT strContent, intTemplate, intMenu, booEditable FROM $tblpages WHERE idPage=$intPage");
            if (! $result->success) {
                $html .= "Impossible de lire la page";
                return ($html);
            } else {
                $intTemplate = $result->data[0]['intTemplate'];
                $intMenu = $result->data[0]['intMenu'];
            }

            $html .= $this->breadcrumb;
            $html .= $this->schemaWebPage;

            if ($this->booDebug == 1) {
                $html .= "<!-- intMenu=$intMenu -->\n" ;
            }

            $menu = "";
            if (! is_null ($intMenu)) {
//$this->display("menu $intMenu");
                $sqlCmd = "SELECT * FROM $tblmenuitems LEFT JOIN $tblroutes ON $tblroutes.idRoute=$tblmenuitems.intLinkRoute LEFT JOIN $tbllanguages ON $tbllanguages.idLanguage=$tblroutes.intLanguage WHERE intMenu=$intMenu ORDER BY intOrdre";

                $menuitems = $this->db->select ($sqlCmd);
                if ($menuitems->success && $menuitems->numrows > 0) {
                    $menu = "<nav class='navbar navbar-expand-sm bg-dark navbar-dark fixed-top me-auto'>";
                    $menu .= "<div class='container-fluid'>";
                    $menu .= "<div class='onlysmartphone'>";
                    $menu .= "<button id='hamburger' class='navbar-toggler' type='button' data-bs-toggle='collapse' data-bs-target='#navbarCollapse'>";
                    $menu .= "<span class='fa fa-bars' style='text-align: right;'></span>";
                    $menu .= "</button>";
                    $menu .= "</div>";

                    $menu .= "<div class='collapse navbar-collapse' id='navbarCollapse'>";
                    $menu .= "<div class='navbar-nav ms-auto py-0'>";
//                     $menu .= "<ul class='navbar-nav'><a class='navbar-brand' href='/nl/onthaal'>MPC Consult SRL</a>";

                    foreach ($menuitems->data as $key => $row) {
                        $menu .= "<li class='nav-item'><a class='nav-link active' href='" .
                             $row['strPath'] . "'>";
                            if (! is_null ($row['intPermission'])) {
                                $result = $this->db->select ("SELECT fctUserPermissionsOn('" . $this->strCurrentUser . "'," . $row['intPermission']. ") AS PERMS");
                                if ($result->success) {
                                    $pos = strpos($result->data[0]['PERMS'], $row['strPermission']);
                                    if ($pos !== false) {
                                        $menu .= $row['strItem'];
                                    } else {
                                        $menu .= "not allowed: " . $row['strItem'];
                                    }
                                }
                            } else {
                                $menu .= "OK: " . $row['strItem'];
                            }
                             $menu .= "</a></li>";
                    }
                    $menu .= "</ul></div></div></nav>";
                }
                if ($this->booDebug == 1) {
                    $html .= "<!-- fin de l'insertion du menu -->\n" ;
                }
            } else if ($this->booDebug == 1) {
//$this->display('pas de menu');
                $html .= "<!-- Pas de menu -->\n";
            }

            if (is_null ($intTemplate)) {
                if ($this->booDebug == 1) {
                    $html .= "\n<!-- Begin of strContent from page $intPage -->\n";
                }
                if ($this->booEditableBlocks && $result->data[0]['booEditable'] == 1) {
                    $html .= "<span oncontextmenu=\"return mnuCMS(this,'editcontent','$this->tblpages'," . $intPage . ")\">";
                }
                $html .= $result->data[0]['strContent'];
                if ($this->booEditableBlocks && $result->data[0]['booEditable'] == 1) {
////                    $html .= '</span>';
                }
                if ($this->booDebug == 1) {
                    $html .= "\n<!-- End of strContent from page $intPage -->\n";
                }

                if ($js_params != '') {
                    $html .= "<script>\n$js_params\n</script>\n";
                }

                $html .= $strFooter;

                do {
                    $this->nremplacements=0;
                    $html = $this->replace_special_tags ($html);
                } while ($this->nremplacements > 0);

                return ($html);
            }

//$this->display("lecture du template $intTemplate");
            $template = $this->db->select ("SELECT * FROM $tbltemplates WHERE idTemplate=$intTemplate");
            if (! $template->success) {
                $html .= "Impossible de lire le template $intTemplate <br><br>";
                return ($html);
            }

            if ($this->booDebug == 1) {
                $html .= "<!-- Template " . $template->data[0]['strName'] . " -->\n" ;
//$this->display("template " . $template->data[0]['strName']);
            }
            $strTemplateName = $template->data[0]['strName'];
            $intNSections = $template->data[0]['intNSections'];
            $strDefinition = $template->data[0]['strDefinition'];

            if ($intNSections < 1) {
                $html .= $result->data[0]['strContent'];
                $html .= $strFooter;

                do {
                    $this->nremplacements=0;
                    $html = $this->replace_special_tags ($html);
                } while ($this->nremplacements > 0);

                if ($booCache) { // Sauvetage de la cache
                    $filename = $this->url . ".html";
                    $filename = __PATHCACHE__ . str_replace ("/","_",$filename);
                    $html .= "<!-- Save cache in $filename -->\n";
                    file_put_contents ($filename,$html);    
                } else {
                    $html .= "<!-- Do not save cache -->\n";
                }
                return ($html);
            }

$html .= $menu;

/*
            $js_params = "let route_language=$this->idLanguage;\n";
            foreach ($this->tabparams['parametres'] as $key => $row) {
                $js_params .= "let param_$key='$row';\n";
            }
*/
            if ($js_params != '') {
                $strContent = "<script>\n$js_params\n</script>\n";
            } else {
                $strContent = '';
            }

            $blocks_found = false;
            for ($i=1; $i<=$intNSections; $i++) {
                if ($this->idLanguage > 0) {
                $sqlcmd = "SELECT idBlock, idBlockContent, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, BC.strContent AS BCstrContent, B.booEditable AS BbooEditable, BC.booEditable AS BCbooEditable," .
                    "strTablename, strScripts, strParams, strScriptsAfterContent FROM $tblpagesectionblocks LEFT JOIN $tblblock B ON B.idBlock=$tblpagesectionblocks.intBlock " .
                    "LEFT JOIN $tblblockcontent BC ON BC.intBlock=$tblpagesectionblocks.intBlock AND BC.intLanguage=$this->idLanguage " .
                    "WHERE intPage=$intPage AND intSection=$i ORDER BY intOrdre";
                } else {
                $sqlcmd = "SELECT idBlock, B.strName AS strName, intContentType, strParams, ysnSaveGeneratedTemplate, strClass, strMethod, intContentType, " .
                    "strTemplateMustache, B.strContent AS BstrContent, '' AS BCstrContent, B.booEditable AS BbooEditable, 0 AS BCbooEditable," .
                    "strTablename, strScripts, strParams, strScriptsAfterContent FROM $tblpagesectionblocks LEFT JOIN $tblblock B ON B.idBlock=$tblpagesectionblocks.intBlock " .
                    "WHERE intPage=$intPage AND intSection=$i ORDER BY intOrdre";
                }
//$this->display ($sqlcmd);
                $blocks = $this->db->select ($sqlcmd);
                if ($blocks->success && ($blocks->numrows >= 1)) {
                    $blocks_found = true;
                    foreach ($blocks->data as $key => $row) {
                        $strContent .= $this->ManageBlock ($row);
                    }
                } else {
//                    $this->display ("pas de block pour la section $i");
                }
                $strDefinition = str_replace("<SECTION $i>",$strContent,$strDefinition);
                $strContent = '';
            }
            if (! $blocks_found ) {
                //$this->display ('Pas de block pour la page => on prend le contenu de pages->strContent');

                if ($this->booEditableBlocks && $result->data[0]['booEditable'] == 1) {
                    $html .= "<span oncontextmenu=\"return mnuCMS(this,'editcontent','$this->tblpages'," . $intPage . ")\">";
                }
                $result = $this->db->select ("SELECT strContent,booEditable FROM $tblpages WHERE idPage=$intPage");
                if ($result->success && $result->numrows > 0) {
                    $strContent = $result->data[0]['strContent'];
                }
                $html .= $strContent;
                if ($this->booEditableBlocks && $result->data[0]['booEditable'] == 1) {
                    $html .= '</span>';
                }
            } else {
                $html .= $strDefinition;
            }

            $html .= $strFooter;


            do {
                $this->nremplacements=0;
                $html = $this->replace_special_tags ($html);
            } while ($this->nremplacements > 0);

            if ($this->booDebug == 1) {
                $html .= "<!-- End of AffichePage intRoute=$intRoute intPage=$intPage strPath=$strPath strTitle=$strTitle idLanguage=$idLanguage -->\n" ;
            }

            // Remplacement des variables utilisables dans les pages ou les scripts des clients
            //$html = str_replace("@username@",$strCurrentUser,$html);

            if ($booCache) { // Sauvetage de la cache
                $filename = $this->url . ".html";
                $filename = __PATHCACHE__ . str_replace ("/","_",$filename);
                $html .= "<!-- Save cache in $filename -->\n";
                file_put_contents ($filename,$html);    
            } else {
                $html .= "<!-- Do not save cache -->\n";
            }

            return ($html);
        }
        catch (Exception $e) {
            return "Error opening database " . __DATABASE__ . " : " . $e->message();
        }
    }
}