Initial commit

This commit is contained in:
2020-11-02 15:46:52 +01:00
commit 17f974127c
13788 changed files with 1921656 additions and 0 deletions

View File

@@ -0,0 +1,611 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class Analyse{
public $contenu;
public $tokens;
public $pile_nom_boucle;
public $pile_boucle_courante;
private $in_comment = false;
private static $no_debug;
public static $debug_text;
function __construct($allow_debug)
{
self::$no_debug = ! ($allow_debug && (DEBUG_PARSER || DEBUG_EVAL));
$this->tokens = array();
$this->pile_nom_boucles = array();
$this->pile_boucle_courante = array();
self::$debug_text = false;
}
function terminer()
{
if (! self::$no_debug)
{
self::$debug_text = '
<div style="border: 1px solid black; margin: 5px; background-color: white; color: black; text-align: left; font-size: 11px;">
<div style="border-bottom: 1px solid black; margin: 0; padding: 5px; background-color: #f0f0f0; font-weight: bold;">Information de debug du parser</div>
<pre style="margin: 0; padding: 5px; height: 200px; overflow: scroll;">'
. self::$debug_text
.'</pre></div>'
;
}
}
static function strlen_cmp($a, $b)
{
$la = strlen($a);
$lb = strlen($b);
if ($la == $lb) return 0;
return ($la > $lb) ? -1 : 1;
}
public static function echo_debug()
{
if (self::$no_debug) return;
$text = '';
$numargs = func_num_args();
for($idx = 0; $idx < $numargs; $idx++)
{
$arg = func_get_arg($idx);
$text .= is_scalar($arg) ? $arg : print_r($arg, true);
}
self::$debug_text .= '<pre>[DEBUG] ' . htmlspecialchars($text)."</pre>\n";
}
function parse_string(&$filecontents)
{
$this->tokens = preg_split("/( |\t|\n|\r|<|>|\\#|\")/", $filecontents, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
// Comme on fait un next() dans parse content, insérer une valeur non significative en début de tableau
array_unshift($this->tokens, '');
// if (DEBUG_PARSER) {Analyse::echo_debug("Tokens: ", $this->tokens); }
return $this->parse_content();
}
function parse_string_with_cache(&$filecontents, $cache_dir)
{
if (! is_dir($cache_dir))
{
if (mkdir($cache_dir, 0777, true) === false)
{
die('Impossible de créer le répertoire '.$cache_dir.'. Vérifiez les droits d\'accès');
}
}
$this->cleanup_cache($cache_dir);
$cache_file = $cache_dir . hash('md5', $filecontents) . '.cache';
if (file_exists($cache_file))
{
// Mettre à jour la date du fichier: les fichiers les plus souvent accédés restent plus longtemps dans le cache.
@touch($cache_file);
return unserialize(file_get_contents($cache_file));
}
else
{
$data = $this->parse_string($filecontents);
file_put_contents($cache_file, serialize($data));
return $data;
}
}
public static function cleanup_cache($cache_dir, $force = 0)
{
// Doit-on purger le cache ?
$last_check = intval(Variable::lire(Parseur::PREFIXE.'_cache_check_time'));
$check_period = intval(3600 * Variable::lire(Parseur::PREFIXE.'_cache_check_period'));
if ($force == 0 && time() - $last_check < $check_period) return;
Variable::ecrire(Parseur::PREFIXE.'_cache_check_time', time());
$cache_file_lifetime = 3600 * Variable::lire(Parseur::PREFIXE.'_cache_file_lifetime');
if ($dh = @opendir($cache_dir))
{
while ($file = readdir($dh))
{
if (strstr($file, '.cache') !== false)
{
$path = $cache_dir . $file;
$filemtime = @filemtime($path);
if (! $filemtime || (time() - $filemtime) >= $cache_file_lifetime )
{
@unlink($path);
}
}
}
@closedir($dh);
}
}
function parse_args()
{
$args = '';
$in_quote = false;
while (1)
{
$tok = next($this->tokens);
//if (DEBUG_PARSER) { Analyse::echo_debug("Parse args: tok='$tok', in_quote=$in_quote"); }
if ($tok == '#')
{
$token = next($this->tokens);
if (preg_match('/([A-Z0-9_]+)/', $token, $varname) > 0)
{
$tok = '#'.$varname[1];
//if (DEBUG_PARSER) { Analyse::echo_debug("new arg var: '$tok'"); }
}
$this->add_var($tok);
// Il faut placer dans les args la valeur originale (sinon bug. Ex: #PROMO[X][Y])
$tok = '#'.$token;
}
else if ($tok == '"')
{
$in_quote = ! $in_quote;
}
else if ($tok == '>')
{
if (! $in_quote) break;
}
else if ($tok === FALSE)
{
break;
}
$args .= $tok;
}
return $args;
}
function add_var($token)
{
// Ne pas prendre en compte les filtres et les get/set
if (strstr($token, 'FILTRE_') !== FALSE
||
strstr($token, 'GET{') !== FALSE
||
strstr($token, 'SET{') !== FALSE) return;
//if (DEBUG_PARSER) { Analyse::echo_debug("Variable: $token");}
$count = count($this->pile_boucle_courante);
// Pas de boucle ouverte
if ($count == 0) return;
//$boucle_courante = end($this->pile_boucle_courante);
$boucle_courante = $this->pile_boucle_courante[$count-1];
//if (DEBUG_PARSER) { Analyse::echo_debug("boucle courante: ", $boucle_courante); }
// La boucle n'est pas une boucle simple -> on ne stocke pas les variables
if ($boucle_courante->type() != PexToken::TYPE_BOUCLE_SIMPLE) return;
if (preg_match('/([A-Z0-9_]+)/', $token, $varname) > 0)
{
if (! in_array($varname[1], $boucle_courante->variables))
{
$boucle_courante->variables[] = $varname[1];
//if (DEBUG_PARSER) { Analyse::echo_debug("Variables de $boucle_courante->nom", $boucle_courante->variables);}
}
}
}
function controle_fermeture_boucle($nom_boucle)
{
$nom_pile = array_pop($this->pile_nom_boucles);
//if (DEBUG_PARSER) Analyse::echo_debug("Pile boucles: required: '$nom_boucle', popped: '/$nom_pile', ", $this->pile_nom_boucles);
if ($nom_boucle != '/' . $nom_pile)
{
if ($nom_pile == '')
{
die("Erreur de syntaxe: $nom_boucle: balise de fin sans balise de début.");
}
else
{
die("Erreur de syntaxe: $nom_boucle trouvé, /$nom_pile attendu.");
}
}
}
function process_token(&$atoken)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("enter process_token ", $atoken);}
$token_type = PexToken::TXT;
if ($atoken == '<')
{
$no_match = false;
$token = next($this->tokens);
if (DEBUG_PARSER) { Analyse::echo_debug("Next PexToken:[$token]");}
// Optimisation (gain: ~= 0,1 sec. sur index standard)
if ($token[0] != 'T' && strpos($token, '/T') !== 0 && strpos($token, '//T') !== 0 && $token[0] != 'R' && strpos($token, '/R') !== 0)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("N'est pas une boucle thelia");}
$no_match = true;
}
else
{
// Get token type
if (strpos($token, 'THELIA_') === 0)
$token_type = PexToken::OBS;
else if (strpos($token, '/THELIA_') === 0)
$token_type = PexToken::FBS;
else if (strpos($token, 'TEST_') === 0)
$token_type = PexToken::OBT;
else if (strpos($token, '/TEST_') === 0)
$token_type = PexToken::EBT;
else if (strpos($token, '//TEST_') === 0)
$token_type = PexToken::FBT;
else if (strpos($token, 'T_') === 0)
$token_type = PexToken::OBC;
else if (strpos($token, '/T_') === 0)
$token_type = PexToken::EBC;
else if (strpos($token, '//T_') === 0)
$token_type = PexToken::FBC;
else if (strpos($token, 'REM') === 0)
$token_type = PexToken::OCM;
else if (strpos($token, '/REM') === 0)
$token_type = PexToken::FCM;
else if (strpos($token, 'REPETER') === 0)
$token_type = PexToken::OBR;
else if (strpos($token, '/REPETER') === 0)
$token_type = PexToken::FBR;
else if (strpos($token, 'T:') === 0)
$token_type = PexToken::OBCV;
else if (strpos($token, '/T:') === 0)
$token_type = PexToken::EBCV;
else if (strpos($token, '//T:') === 0)
$token_type = PexToken::FBCV;
else
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Token type texte");}
$no_match = true;
}
}
if ($no_match)
{
prev($this->tokens);
$token = $atoken;
}
}
// Variables
else if ($atoken == '#')
{
// Traiter les cas similaires à ##REF
$tmp = next($this->tokens);
if ($tmp == '#')
{
$token = '#';
prev($this->tokens);
}
else
{
$token = '#' . $tmp;
$this->add_var($token);
}
}
else
{
$token = $atoken;
}
//if (DEBUG_PARSER) { Analyse::echo_debug( "Token:[$token], type $token_type"); }
// Dans un commentaire, on attend la fin sans rien analyser
if ($this->in_comment && $token_type !== PexToken::FCM)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("ignore: $token_type:", $token); }
return 'vide';
}
// BOUCLE SIMPLE et boucle REPETER
if ($token_type === PexToken::OBS || $token_type === PexToken::OBR)
{
if ($token_type === PexToken::OBS)
$boucle = new BoucleSimple(substr($token, 7));
else
$boucle = new BoucleRepeter(substr($token, 8));
array_push($this->pile_nom_boucles, $token);
// Parse args se fait avant le push, car les variables dans les args doivent être valuées
// par la boucle enclosante.
$boucle->set_args($this->parse_args());
array_push($this->pile_boucle_courante, $boucle);
//if (DEBUG_PARSER) { Analyse::echo_debug("Push boucle courante $boucle->nom\n", $this->pile_boucle_courante); }
$boucle->ajouter($this->parse_content());
// Skip remaining > TODO check >
$this->skipto('>');
return $boucle;
}
else if ($token_type === PexToken::FBS || $token_type === PexToken::FBR)
{
$this->controle_fermeture_boucle($token);
array_pop($this->pile_boucle_courante);
//if (DEBUG_PARSER) { Analyse::echo_debug("Pop boucle courante $token\n", $this->pile_boucle_courante); }
return 'stop';
}
// BOUCLE CONDITIONNELLE
else if ($token_type === PexToken::OBC)
{
$boucle = new BoucleConditionnelle(substr($token, 2));
$this->skipto('>');
array_push($this->pile_nom_boucles, $token);
//if (DEBUG_PARSER) { Analyse::echo_debug("Push boucle conditionnelle $token\n", $this->pile_boucle_courante); }
// Si
$boucle->ajouter($this->parse_content());
$this->skipto('>');
array_push($this->pile_nom_boucles, '/'.$token);
//if ( const ) { Analyse::echo_debug("Push SI boucle conditionnelle $token\n", $this->pile_boucle_courante); }
// Sinon
$boucle->ajouter($this->parse_content());
$this->skipto('>');
return $boucle;
}
else if ($token_type === PexToken::EBC)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture SI: $token\n", $this->pile_boucle_courante); }
$this->controle_fermeture_boucle($token);
return 'stop';
}
else if ($token_type === PexToken::FBC)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture ELSE: $token\n", $this->pile_boucle_courante);}
$this->controle_fermeture_boucle($token);
return 'stop';
}
// BOUCLE CONDITIONNELLE sur vaeriable
else if ($token_type === PexToken::OBCV)
{
$var = substr($token, 2);
// Ajouter la variable à la boucle enclosante
$this->add_var($var);
$boucle = new BoucleConditionnelleVariable($var);
$this->skipto('>');
array_push($this->pile_nom_boucles, $token);
//if (DEBUG_PARSER) { Analyse::echo_debug("Push boucle conditionnelle $token\n", $this->pile_boucle_courante); }
// Si
$boucle->ajouter($this->parse_content());
$this->skipto('>');
array_push($this->pile_nom_boucles, '/'.$token);
//if ( const ) { Analyse::echo_debug("Push SI boucle conditionnelle $token\n", $this->pile_boucle_courante); }
// Sinon
$boucle->ajouter($this->parse_content());
$this->skipto('>');
return $boucle;
}
else if ($token_type === PexToken::EBCV)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture SI: $token\n", $this->pile_boucle_courante); }
$this->controle_fermeture_boucle($token);
return 'stop';
}
else if ($token_type === PexToken::FBCV)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture ELSE: $token\n", $this->pile_boucle_courante);}
$this->controle_fermeture_boucle($token);
return 'stop';
}
// Boucle <TEST_xxx>
else if ($token_type === PexToken::OBT)
{
$boucle = new BoucleTest(substr($token, 5));
// Parse args se fait avant le push, car les variables dans les args doivent être valuées
// par la boucle enclosante.
$boucle->set_args($this->parse_args());
array_push($this->pile_nom_boucles, $token);
//if (DEBUG_PARSER) { Analyse::echo_debug("Push boucle Test $boucle->nom\n", $this->pile_boucle_courante);}
// Si
$boucle->ajouter($this->parse_content());
$this->skipto('>');
array_push($this->pile_nom_boucles, '/' . $token);
// Sinon
$boucle->ajouter($this->parse_content());
$this->skipto('>');
return $boucle;
}
else if ($token_type === PexToken::EBT)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture TEST SI: $token\n", $this->pile_boucle_courante);}
$this->controle_fermeture_boucle($token);
return 'stop';
}
else if ($token_type === PexToken::FBT)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture TEST ELSE: $token\n", $this->pile_boucle_courante); }
$this->controle_fermeture_boucle($token);
return 'stop';
}
else if ($token_type === PexToken::OCM)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Ouverture commentaire: $token\n", $this->pile_boucle_courante); }
$this->in_comment = true;
return 'vide';
}
else if ($token_type === PexToken::FCM)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Controle fermeture TEST ELSE: $token\n", $this->pile_boucle_courante); }
$this->in_comment = false;
$this->skipto('>');
return 'vide';
}
else if ($token !== '')
{
return new PexTexte($token);
}
else
{
return 'vide';
}
}
function skipto($val)
{
$ret = false;
while ( ( ($tok = next($this->tokens)) !== false) && $tok != $val )
{
//if (DEBUG_PARSER) { Analyse::echo_debug("skipping $tok"); }
$ret = $tok;
}
}
function parse_content()
{
$contenu = new ContenuElement();
$i = false;
while (true)
{
$token = next($this->tokens);
// Done !
if ($token === FALSE)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("No more tokens.");}
// Si on est encore dans un commentaire, failed !
if ($this->in_comment)
{
die('Erreur de syntaxe: un commentaire n\'a pas été fermé.');
}
// S'il reste des choses dans la pile des noms, des boucles n'ont pas été fermées correctement.
if (count($this->pile_nom_boucles) > 0)
{
die('Erreur de syntaxe: une ou plusieurs boucles n\'ont pas été fermées: '.implode(', ', $this->pile_nom_boucles));
}
break;
}
$res = $this->process_token($token);
if ($res == 'vide')
continue;
else if ($res == 'stop')
break;
else
$contenu->ajouter($res);
}
return $contenu;
}
}
?>

View File

@@ -0,0 +1,136 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class BoucleConditionnelle extends PexElement{
public $nom;
public $contenu;
public $valeur;
function __construct($nom)
{
$this->nom = $nom;
$this->contenu = array();
}
function type()
{
return PexToken::TYPE_BOUCLE_COND;
}
function evaluer(&$substitutions = array())
{
// Evaluer la boucle. Le scope des variables positionnes par cette boucle
// n'est pas propage au contenu des boucles imbriquées
if (DEBUG_EVAL) { Analyse::echo_debug("Eval boucle conditionnelle $this->nom"); }
$si = $this->contenu[0]->evaluer($substitutions);
if (DEBUG_EVAL) { Analyse::echo_debug("Eval boucle conditionnelle $this->nom: ", $si); }
// Trouver la boucle concernée, ou la première boucle si aucun nom de boucle ne matche
$premiere_boucle = false;
$boucle_test = false;
$nb_boucles = 0;
foreach($this->contenu[0]->elements as &$element)
{
if (DEBUG_EVAL) { Analyse::echo_debug("checking element nom='$element->nom', type=".$element->type(),':', $element); }
if ($element->type() == PexToken::TYPE_BOUCLE_SIMPLE)
{
$nb_boucles++;
if ($premiere_boucle === false) $premiere_boucle = &$element;
if ($element->nom == $this->nom)
{
if (DEBUG_EVAL) { Analyse::echo_debug("Boucle 'si' trouve pour $this->nom"); }
$boucle_test = &$element;
break;
}
}
}
// Par defaut, la boucle est vide.
$est_vide = true;
// Aucune boucle trouvée ? On evalue le texte de la condition 'si'
if ($nb_boucles == 0)
{
$est_vide = trim($si) != '';
}
// Une boucle ? On regarde si elle est vide
else if ($boucle_test === false)
{
if ($premiere_boucle === false)
{
die ("Boucle conditionnelle T_$this->nom: boucle THELIA_$this->nom non trouvée.");
}
else
{
$est_vide = $premiere_boucle->est_vide;
}
}
else
{
$est_vide = $boucle_test->est_vide;
}
if (DEBUG_EVAL) { Analyse::echo_debug("boucle $this->nom ", $est_vide ? " Vide" : " Non vide"); }
if ($est_vide)
{
if (DEBUG_EVAL) { Analyse::echo_debug("Eval expression 'vide'"); }
return $this->contenu[1]->evaluer($substitutions);
}
else
{
if (DEBUG_EVAL) { Analyse::echo_debug("Retourne expression 'non vide'"); }
return $si;
}
}
function ajouter($data)
{
if (DEBUG_EVAL) { Analyse::echo_debug("BoucleConditionnelle ajout:", $data); }
$this->contenu[] = $data;
}
function imprimer()
{
Analyse::echo_debug("[SI $this->nom]");
if ($this->contenu[0]) $this->contenu[0]->imprimer();
Analyse::echo_debug("[SINON $this->nom]");
if ($this->contenu[1]) $this->contenu[1]->imprimer();
Analyse::echo_debug("[FINSI $this->nom]");
}
}
?>

View File

@@ -0,0 +1,64 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : thelia@openstudio.fr */
/* web : http://www.openstudio.fr */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* Ê Êalong with this program. ÊIf not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class BoucleConditionnelleVariable extends PexElement{
public $nom;
public $contenu;
function __construct($nom)
{
$this->nom = $nom;
$this->contenu = array();
}
function type()
{
return PexToken::TYPE_BOUCLE_COND_VARIABLE;
}
function evaluer(&$substitutions = array())
{
$idx = isset($substitutions['#'.$this->nom]) && $substitutions['#'.$this->nom] != '' ? 0 : 1;
return $this->contenu[$idx]->evaluer($substitutions);
}
function ajouter($data)
{
if (DEBUG_EVAL) { Analyse::echo_debug("BoucleConditionnelleVariable ajout:", $data); }
$this->contenu[] = $data;
}
function imprimer()
{
Analyse::echo_debug("[SI $this->nom]");
if ($this->contenu[0]) $this->contenu[0]->imprimer();
Analyse::echo_debug("[SINON $this->nom]");
if ($this->contenu[1]) $this->contenu[1]->imprimer();
Analyse::echo_debug("[FINSI $this->nom]");
}
}
?>

View File

@@ -0,0 +1,88 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class BoucleRepeter extends PexElement{
public $nom;
public $contenu;
public $args;
function __construct($nom)
{
$this->nom = $nom;
}
function type()
{
return PexToken::TYPE_BOUCLE_REPETER;
}
function set_args($args)
{
$this->args = $args;
}
function ajouter($data)
{
$this->contenu = $data;
}
function evaluer(&$substitutions = array())
{
if (DEBUG_EVAL) { Analyse::echo_debug("Evaluation boucle repeter $this->nom. RAW args: $this->args"); }
$args = $this->replace($substitutions, $this->args);
$debut = lireTag($args, "debut");
$fin = lireTag($args, "fin");
$increment = lireTag($args, "increment");
if ($debut == '') $debut = 1;
if ($increment == '') $increment = 1;
$val = '';
if ($increment == 0) die("L'increment de la boucle REPETER_".$this->nom." doit être different de 0");
for($idx = $debut, $count = 1; $idx <= $fin; $idx += $increment, $count++)
{
$substitutions['#INDEX'] = $idx;
$substitutions['#__COMPTEUR__'] = $count;
$val .= $this->contenu->evaluer($substitutions);
}
return $val;
}
function imprimer()
{
Analyse::echo_debug("[DEBUT REPETER $this->nom, args: ", $this->args, "]");
$this->contenu->imprimer();
Analyse::echo_debug("[FIN REPETER $this->nom]");
}
}
?>

View File

@@ -0,0 +1,357 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class BoucleSimple extends PexElement{
public $nom;
public $args;
public $contenu;
public $est_vide;
public $variables;
private $compteur = 1;
function __construct($nom)
{
$this->nom = $nom;
$this->modules = null;
$this->est_vide = true;
$this->variables = array();
}
function type()
{
return PexToken::TYPE_BOUCLE_SIMPLE;
}
function set_args($args)
{
$this->args = $args;
$type_boucle = ucfirst(strtolower(lireTag($args, 'type')));
if (DEBUG_EVAL) { Analyse::echo_debug($this->nom, ": $type_boucle"); }
}
function ajouter($data)
{
$this->contenu = $data;
}
// Evaluer la boucle en utilisant la fonction classique
function evaluer_boucle_classique($type_boucle, $args)
{
$var_template = '';
$this->compteur = 1;
// HACK: Si la liste des variables contient une variable conditionelle, assurer le traitement
// de ces variables. Voir aussi la methode replace() de la classe PexElement
foreach(Parseur::$VARIABLES_CONDITIONNELLES as $varcond)
{
if (in_array($varcond, $this->variables))
{
if ($var_template != '') $var_template .= PexToken::COUPLE_SEP;
$var_template .= '__VARCOND__'.$varcond.'__' . PexToken::ASSIGN_SEP . '#' . $varcond . '[1][0]';
}
}
usort($this->variables, array("Analyse", "strlen_cmp"));
foreach($this->variables as $var)
{
if ($var_template != '') $var_template .= PexToken::COUPLE_SEP;
$var_template .= $var . PexToken::ASSIGN_SEP . '#' . $var;
}
// PexToken::START_MARK permet de déterminer si la boucle modifie ou remplace le texte
// indiqué dans la boucle (plugin notation et commentaires)
$var_template = PexToken::START_MARK . $var_template . PexToken::ITER_SEP;
if (DEBUG_EVAL) { Analyse::echo_debug("appel boucle exec $type_boucle, args='$args', var_template='$var_template'");}
// Appel du boucle_exec() de base de Thélia
$valued_text = $this->boucle_exec(strtoupper($type_boucle), $args, $var_template);
if (DEBUG_EVAL) { Analyse::echo_debug("$this->nom: valued template='$valued_text'"); }
if (trim($valued_text) != '')
{
$boucle_subst = new EvalBoucle();
// Parse $texte to extract substitutions
$rows = explode(PexToken::ITER_SEP, $valued_text);
// Compter le nombre de resultats
$nbres = count($rows);
foreach($rows as $row) if ($row == '') $nbres--;
foreach($rows as $row)
{
if ($row == '') continue;
$iteration = new IterationBoucle();
if (DEBUG_EVAL) { Analyse::echo_debug("row: '$row'"); }
if ($row[0] != PexToken::START_MARK)
{
$start_pos = strpos($row, PexToken::START_MARK);
if (DEBUG_EVAL) { Analyse::echo_debug("Start mark at pos '$start_pos'"); }
if ($start_pos === false)
{
if (DEBUG_EVAL) { Analyse::echo_debug("Texte remplacé par '$row'"); }
$iteration->remplacement = $row;
$boucle_subst->ajoutIteration($iteration);
// On n'examine pas la suite
continue;
}
else
{
if (DEBUG_EVAL) { Analyse::echo_debug("Texte modifié. prefixe: ".substr($row, 0, $start_pos)); }
// Retenir le prefixe, qui sera ajouté lors des substitutions
$iteration->prefixe = substr($row, 0, $start_pos);
// Continuer , et examiner le reste.
$row = substr($row, $start_pos + 1);
}
}
else
{
// Enlever la marque de début
$row = substr($row, 1);
// S'il ne reste plus rien, on ne va pas plus loin, ça ne sert à rien.
// if ($row == '') continue;
}
$vars = explode(PexToken::COUPLE_SEP, $row);
$line_vars = array();
foreach($vars as $varval)
{
if (DEBUG_EVAL) { Analyse::echo_debug("varval: '$varval'"); }
list($var, $value) = explode(PexToken::ASSIGN_SEP, $varval);
if (DEBUG_EVAL) { Analyse::echo_debug("$var=$value"); }
$iteration->ajoutVarVal($var, $value);
}
// Ajouter le compteur
$iteration->ajoutVarVal('__COMPTEUR__', $this->compteur++);
// Ajouter le nombre de resultats total
$iteration->ajoutVarVal('__NOMBRE__', $nbres);
$boucle_subst->ajoutIteration($iteration);
}
}
else
{
// la boucle est vide
$boucle_subst = false;
}
if (DEBUG_EVAL) { Analyse::echo_debug("type_boucle=$type_boucle: boucle_subst: ",$boucle_subst, $boucle_subst === false ? 'FALSE' : ''); }
return $boucle_subst;
}
function evaluer(&$substitutions = array())
{
if (DEBUG_EVAL) { Analyse::echo_debug("Eval boucle simple $this->nom"); }
// Bug signalé par tetedelard
// Réinitialiser l'état (la boucle peut-être placée dans une boucle qui implique des iterations,
// et influe sur les paramètres de cette boucle, et donc sur ses résultats.
$this->est_vide = true;
$val = '';
// Effectuer les substitutions dans les arguments de la boucle a exécuter
// avec les valeurs de la présente boucle.
$args = $this->replace($substitutions, $this->args);
/*
if (DEBUG_EVAL) {
Analyse::echo_debug("Eval boucle simple $this->nom, args=$this->args, subst_args=$args, Substitutions: \n",
$substitutions,
'variables:,
$this->variables);
}
*/
$type_boucle = ucfirst(strtolower(lireTag($args, 'type')));
$boucle_subst = $this->evaluer_boucle_classique($type_boucle, $args);
if (DEBUG_EVAL) { Analyse::echo_debug("Eval boucle simple $this->nom, subst: ",$boucle_subst === false ? 'FALSE' : $boucle_subst, " est vide: ",$this->est_vide === false ? 'FALSE' : "TRUE"); }
if ($boucle_subst !== false)
{
if (DEBUG_EVAL) { Analyse::echo_debug("Boucle simple $this->nom n'est plus vide."); }
// Si boucle_subst es définie, alors la boucle n'est pas vide.
$this->est_vide = false;
// Evaluer la présente boucle.
foreach($boucle_subst->iterations as $iteration)
{
if (DEBUG_EVAL) { Analyse::echo_debug("eval: type=".$this->contenu->type()."\nsubst: ", $iteration, "\ncontenu: "); $this->contenu->imprimer();}
if ($iteration->prefixe !== false)
{
// La boucle a place quelque chose avant le texte.
// On l'ajoute nous aussi.
$val .= $iteration->prefixe;
if (DEBUG_EVAL) { Analyse::echo_debug("eval: prefixe=$iteration->prefixe"); }
}
if ($iteration->remplacement !== false)
{
// La boucle a remplacé le texte qu'on lui a passé par un autre
// -> on retourne simplement ce texte, sans faire d'autres évaluations
$val .= $iteration->remplacement;
if (DEBUG_EVAL) { Analyse::echo_debug("eval: remplacement=$iteration->remplacement"); }
}
else
{
if (DEBUG_EVAL) { Analyse::echo_debug("eval: evaluation contenu"); }
$val .= $this->contenu->evaluer($iteration->varval);
}
}
// Si la boucle n'est pas vide, mais n'a retourné aucune itération,
// il faut tout de même évaluer son contenu.
// FIXME: retiré, car on ajoute toujours une iteration par tour de boucle
// cf. ajoutIteration()
// if (count($boucle_subst->iterations) == 0) $val .= $this->contenu->evaluer();
}
if (DEBUG_EVAL) { Analyse::echo_debug("boucle=$type_boucle vide:", $this->est_vide ? "Oui" : "Non"); }
return $val;
}
function boucle_exec($type_boucle, $args, $texte, $nom_boucle = ""){
global $page;
$variables="";
$res = "";
$exec_boucle = 1;
//$param = array(&$type_boucle, &$args, &$texte, &$nom_boucle, &$exec_boucle);
//ActionsModules::instance()->appel_module( "avantboucle", $param);
if($exec_boucle)
switch($type_boucle){
case 'RUBRIQUE' : $res .= boucleRubrique($texte, $args); break;
case 'DOSSIER' : $res .= boucleDossier($texte, $args); break;
case 'CONTENU' : $res .= boucleContenu($texte, $args); break;
case 'CONTENUASSOC' : $res .= boucleContenuassoc($texte, $args); break;
case 'PRODUIT' : $res .= boucleProduit($texte, $args); break;
case 'PAGE' : $res .= bouclePage($texte, $args); break;
case 'PANIER' : $res .= bouclePanier($texte, $args); break;
case 'QUANTITE' : $res .= boucleQuantite($texte, $args); break;
case 'CHEMIN' : $res .= boucleChemin($texte, $args); break;
case 'CHEMINDOS' : $res .= boucleChemindos($texte, $args); break;
case 'PAIEMENT' : $res .= bouclePaiement($texte, $args); break;
case 'ADRESSE' : $res .= boucleAdresse($texte, $args); break;
case 'VENTEADR' : $res .= boucleVenteadr($texte, $args); break;
case 'COMMANDE' : $res .= boucleCommande($texte, $args); break;
case 'VENTEPROD' : $res .= boucleVenteprod($texte, $args); break;
case 'IMAGE' : $res .= boucleImage($texte, $args); break;
case 'DOCUMENT' : $res .= boucleDocument($texte, $args); break;
case 'ACCESSOIRE' : $res .= boucleAccessoire($texte, $args); break;
case 'TRANSPORT' : $res .= boucleTransport($texte, $args); break;
case 'PAYS' : $res .= bouclePays($texte, $args); break;
case 'CARACTERISTIQUE' : $res .= boucleCaracteristique($texte, $args); break;
case 'CARACDISP' : $res .= boucleCaracdisp($texte, $args); break;
case 'CARACVAL' : $res .= boucleCaracval($texte, $args); break;
case 'DEVISE' : $res .= boucleDevise($texte, $args); break;
case 'CLIENT' : $res .= boucleClient($texte, $args); break;
case 'DECLINAISON' : $res .= boucleDeclinaison($texte, $args); break;
case 'DECLIDISP' : $res .= boucleDeclidisp($texte, $args); break;
case 'DECVAL' : $res .= boucleDecval($texte, $args); break;
case 'RSS' : $res .= boucleRSS($texte, $args); break;
case 'STOCK' : $res .= boucleStock($texte, $args); break;
case 'PAGERUBRIQUE' : $res .= bouclePagerubrique($texte, $args); break;
case 'RAISON' : $res .= boucleRaison($texte, $args); break;
case 'TVA' : $res .= boucleTva($texte, $args); break;
case 'LANGUE' : $res .= boucleLangue($texte, $args); break;
case 'REPRISEPAIEMENT' : $res .= boucleReprisePaiement($texte, $args); break;
default: $res.= $this->moduleBoucle($type_boucle, $texte, $args); break;
}
else
$res = $texte;
//$param = array(&$type_boucle, &$args, &$res, &$nom_boucle);
//ActionsModules::instance()->appel_module( "apresboucle", $param);
return $res;
}
function moduleBoucle($type_boucle, $texte, $args){
try {
$modules = new Modules();
if ($modules->charger(strtolower($type_boucle)) && $modules->actif) {
$instance = ActionsModules::instance()->instancier($modules->nom);
if (method_exists($instance, 'boucle'))
return $instance->boucle($texte, $args);
}
} catch (Exception $ex) {}
return '';
}
function imprimer()
{
Analyse::echo_debug("[DEBUT $this->nom, args: ", $this->args, "]");
$this->contenu->imprimer();
Analyse::echo_debug("[FIN $this->nom]");
}
}
?>

View File

@@ -0,0 +1,148 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class BoucleTest extends PexElement{
public $nom;
public $contenu;
public $args;
function __construct($nom)
{
$this->nom = $nom;
$this->contenu = array();
}
function type()
{
return PexToken::TYPE_BOUCLE_TEST;
}
function set_args($args)
{
$this->args = $args;
}
function ajouter($data)
{
$this->contenu[] = $data;
}
function evaluer(&$substitutions = array())
{
if (DEBUG_EVAL) { Analyse::echo_debug("Evaluation boucle test $this->nom. RAW args: $this->args"); }
$args = $this->replace($substitutions, $this->args);
$var = lireTag($args, "variable");
if ($var == '') $var = lireTag($args, "var");
$test = lireTag($args, "test");
$val = lireTag($args, "valeur");
if ($val == '') $val = lireTag($args, "val");
if (DEBUG_EVAL) { Analyse::echo_debug("Boucle test: args='$args', var='$var', test='$test', val='$val'"); }
$vrai = false;
switch(strtolower($test))
{
case "vide" :
$vrai = trim($var) == '';
break;
case "nonvide" :
$vrai = trim($var) != '';
break;
case "egal" :
$vrai = ($var == $val);
break;
case "different" :
$vrai = ($var != $val);
break;
case "superieur" :
$vrai = ($var > $val);
break;
case "superieurouegal" :
$vrai = ($var >= $val);
break;
case "inferieur" :
$vrai = ($var < $val);
break;
case "inferieurouegal" :
$vrai = ($var <= $val);
break;
case "dansliste" :
$sep = lireTag($args, "separateur");
if (empty($sep)) $sep = ",";
$vrai = in_array($var, explode($sep, $val));
break;
case "contient" :
$vrai = strstr($var, $val) !== false;
break;
// Contribution de asturyan
case "modulo" :
$val = explode(",", $val);
$vrai = ($var % $val[0] == $val[1]);
break;
default:
die("L'argument 'test' de la boucle $this->nom est manquant ou inconnu: '$test'");
break;
}
if ($vrai)
{
return $this->contenu[0]->evaluer($substitutions);
}
else
{
return $this->contenu[1]->evaluer($substitutions);
}
}
function imprimer()
{
Analyse::echo_debug("[TEST_VRAI $this->nom $args]");
if ($this->contenu[0]) $this->contenu[0]->imprimer();
Analyse::echo_debug("[TEST_FAUX $this->nom]");
if ($this->contenu[1]) $this->contenu[1]->imprimer();
Analyse::echo_debug("[TEST_FIN $this->nom]");
}
}
?>

View File

@@ -0,0 +1,98 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class ContenuElement extends PexElement{
public $elements;
public $idx;
public $last_type;
function __construct()
{
$this->elements = array();
$this->idx = 0;
$this->last_type = -1;
}
function type()
{
return PexToken::TYPE_CONTENU;
}
function ajouter($element)
{
// Merge subsequent text elements
//if (DEBUG_PARSER) { Analyse::echo_debug("Contenu ajouter: idx=".$this->idx.", last_type=".$this->last_type.", element type=".$element->type());}
if ($this->idx > 0
&&
$this->last_type == PexToken::TYPE_TEXTE
&&
$element->type() == PexToken::TYPE_TEXTE)
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Contenu append: "); $element->imprimer();}
$this->elements[$this->idx-1]->ajouter($element->texte);
}
else
{
//if (DEBUG_PARSER) { Analyse::echo_debug("Contenu ajout:"); $element->imprimer(); }
$this->elements[] = $element;
$this->last_type = $element->type();
//if (DEBUG_PARSER) { Analyse::echo_debug("Après ajout: last_type=".$this->last_type); }
$this->idx++;
}
}
function evaluer(&$substitutions = array())
{
if (DEBUG_EVAL) { Analyse::echo_debug("Eval contenu $this->idx"); }
$val = '';
foreach($this->elements as $element)
{
if (DEBUG_EVAL) { Analyse::echo_debug("CONT:eval ". $element->type()); $element->imprimer();}
$val .= $element->evaluer($substitutions);
}
return $val;
}
function imprimer()
{
foreach($this->elements as $element)
{
$element->imprimer();
}
}
}
?>

View File

@@ -0,0 +1,44 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
// Stocke les infos sur une boucle pendant son évaluation
class EvalBoucle{
public $iterations;
public function __construct()
{
$this->iterations = array();
}
public function ajoutIteration($iteration)
{
/*
Retiré: if ($iteration->estValuee())
On ajoute une iteration par tour de boucle, comme le fait le parser de base.
*/
$this->iterations[] = $iteration;
}
}
?>

View File

@@ -0,0 +1,47 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
// Définit les données resultant d'une iteration de boucle
class IterationBoucle{
public $remplacement;
public $prefixe;
public $varval;
public function __construct(){
$this->remplacement = false;
$this->prefixe = false;
$this->varval = array();
}
public function ajoutVarVal($var, $value){
if (trim($var) != '') $this->varval['#'.$var] = $value;
}
public function estValuee(){
return count($this->varval) > 0 || $this->remplacement !== false || $this->prefixe !== false;
}
}
?>

View File

@@ -0,0 +1,63 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
// Classe de base des éléments de template
abstract class PexElement{
public abstract function imprimer();
public abstract function evaluer(&$substitutions = array());
public abstract function ajouter($data);
public abstract function type();
public function replace($substitutions, $texte){
if (trim($texte) == '' /* || count($substitutions) == 0 */) return $texte;
$val = &$texte;
// Cas spécial des variables conditionnelles
foreach(Parseur::$VARIABLES_CONDITIONNELLES as $varcond)
{
if (isset($substitutions['#__VARCOND__'.$varcond.'__']))
{
$num_exp = $substitutions['#__VARCOND__'.$varcond.'__'] == '1' ? '1' : '2';
$val = preg_replace('/#'.$varcond.'\[([^]]*)\]\[([^]]*)\]/', "\\$num_exp", $texte);
}
}
$subs = str_replace(array_keys($substitutions), array_values($substitutions), $val);
// Traiter les variables de template s'il y en a
if (strpos($subs, '#SET') !== false || strpos($subs, '#GET') !== false || strpos($subs, '#ENV') !== false || strpos($subs, '#SESSION') !== false)
{
include_once(__DIR__.'/VariablesTemplate.class.php');
$subs = VariablesTemplate::analyser($subs);
}
return $subs;
}
}
?>

View File

@@ -0,0 +1,57 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
class PexTexte extends PexElement{
public $texte;
function __construct(&$texte)
{
$this->texte = $texte;
}
function type()
{
return PexToken::TYPE_TEXTE;
}
function ajouter($texte)
{
$this->texte .= $texte;
}
function evaluer(&$substitutions = array())
{
if (DEBUG_EVAL) { Analyse::echo_debug("Eval texte '$this->texte'"); }
return $this->replace($substitutions, $this->texte);
}
function imprimer()
{
Analyse::echo_debug($this->texte);
}
}
?>

View File

@@ -0,0 +1,63 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
require_once __DIR__ . "/../../fonctions/autoload.php";
// Tokens and separators
// ---------------------
interface PexToken{
// Token types
const OBS = 1;
const FBS = 2;
const OBC = 3;
const EBC = 4;
const FBC = 5;
const TXT = 7;
const OBT = 8;
const EBT = 9;
const FBT = 10;
const OCM = 11;
const FCM = 12;
const OBR = 13;
const FBR = 14;
const OBCV = 15;
const EBCV = 16;
const FBCV = 17;
// Element types
const TYPE_BOUCLE_SIMPLE = 1;
const TYPE_BOUCLE_COND = 2;
const TYPE_BOUCLE_TEST = 21;
const TYPE_TEXTE = 3;
const TYPE_CONTENU = 4;
const TYPE_BOUCLE_REPETER = 5;
const TYPE_BOUCLE_COND_VARIABLE = 6;
// Separateurs
const ITER_SEP = "\x01";
const COUPLE_SEP = "\x02";
const ASSIGN_SEP = "\x03";
const START_MARK = "\x04";
}
?>

View File

@@ -0,0 +1,297 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) 2005-2013 OpenStudio */
/* email : info@thelia.fr */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
// ------------------------------------------------------------------
// Traitement de variables de template, avec la syntaxe:
// #SET{var, valeur}, #GET{var [, defaut]} et #ENV{var [, defaut]}
// ------------------------------------------------------------------
require_once __DIR__ . "/../../fonctions/autoload.php";
class VariablesTemplate
{
private static $instance = null;
private static $symboles = array();
private static $modules = false;
// Trouver tous les plugins avec une fonction post() et #FILTRE dans leur code
private function trouver_modules_filtre()
{
if (self::$modules !== false) return;
self::$modules = array();
// Trouver tous les modules ayant '#FILTRE' dans leur code (hack pour la perf)
$liste = ActionsModules::instance()->lister(false, true);
foreach($liste as $module) {
try {
$class_name = ucfirst($module->nom);
$class_file = ActionsModules::instance()->lire_chemin_module . "/" . $class_name. ".class.php";
if (file_exists($class_file))
{
$code = file_get_contents($class_file);
if (strpos($code, '#FILTRE') !== false)
{
$instance = ActionsModules::instance()->instancier($module->nom);
if (method_exists($instance, 'post'))
{
self::$modules[] = $clazz;
}
}
}
} catch (Exception $e) {}
}
}
public static function analyser($texte)
{
if (self::$instance == null) self::$instance = new VariablesTemplate();
return self::$instance->demarrer($texte);
}
private function syntax_error($text)
{
die("Erreur de syntaxe: $text");
}
// Appliquer les filtres de base et les filtres utilisateur
private function appliquer_filtres($texte)
{
global $res;
if (strpos($texte, '#FILTRE') !== false)
{
$this->trouver_modules_filtre();
$tmp_res = $res;
// Filtres standard
// $res = filtres($texte);
Filtres::exec($texte);
$res = $texte;
// Filtres utilisateur
foreach(self::$modules as $module)
{
$module->post();
}
$res = $tmp_res;
}
return $texte;
}
// Récupérer une valeur de variable, avec filtrage éventuel, et valeur par defaut
// si la variable ne peut être valuée.
private function filtrer_var($type, $var, $defaut = '')
{
if ($type == 'ENV' && isset($_REQUEST[$var]))
{
$var = is_array($_REQUEST[$var]) ? implode(',', $_REQUEST[$var]) : $_REQUEST[$var];
return strip_tags($var);
}
else if ($type == 'GET' && isset(self::$symboles[$var]) && self::$symboles[$var] != '')
{
return self::$symboles[$var];
}
else if ($type == 'SESSION' && isset($_SESSION["thelia_$var"]) && $_SESSION["thelia_$var"] != '')
{
return $_SESSION["thelia_$var"];
}
return $defaut;
}
private function analyser_nom_var()
{
$var = trim(next($this->tokens));
if (! preg_match('/^[\w\:]+$/', $var)) $this->syntax_error("Nom de variable invalide: '$var'");
return $var;
}
private function analyser_set($directive)
{
//Parser::echo_debug("get_set()");
$tok = next($this->tokens);
if ($tok == '{')
{
$var = $this->analyser_nom_var();
if (next($this->tokens) == ',')
{
// Lire jusqu'<27> la fermeture
$val = $this->analyser_contenu('}');
if (current($this->tokens) == '}')
{
$val = $this->appliquer_filtres(trim($val));
if ($directive == 'SET')
{
// Evaluer les filtres THELIA sur la valeur
self::$symboles[$var] = $val;
}
else if ($directive == 'SESSION_SET')
{
$_SESSION["thelia_$var"] = $val;
}
// Parser::echo_debug("FIN $directive $var = $val");
return '';
}
else
{
$this->syntax_error("$directive $var: } attendu, $tok trouv<75>.");
}
}
else if (current($this->tokens) == '}')
{
if ($directive == 'SET')
{
unset(self::$symboles[$var]);
}
else if ($directive == 'SESSION_SET')
{
unset($_SESSION["thelia_$var"]);
}
return '';
}
else
{
$this->syntax_error("$directive $var: ',' attendu $tok trouv<75>.");
}
}
else
{
return $tok;
}
}
private function analyser_get($type)
{
//Parser::echo_debug( "analyser_get()");
// Lire jusqu'<27> la fermeture
if (($tok = next($this->tokens)) == '{')
{
$var = $this->analyser_nom_var();
if (($tok = next($this->tokens)) == ',')
{
// Une valeur par defaut - appliquer les filtres Thelia à cette valeur
$defaut = $this->appliquer_filtres(trim($this->analyser_contenu('}')));
return $this->filtrer_var($type, $var, $defaut);
}
else if ($tok == '}')
{
// Pas de valeur par defaut
return $this->filtrer_var($type, $var);
}
else
{
$this->syntax_error("$type $var: ',' ou '}' attendu, $tok trouv<75>.");
}
}
else
{
return $tok;
}
}
private function analyser_contenu($stopchar = '')
{
// Parser::echo_debug( "analyser_contenu($stopchar)");
$content = '';
while (($tok = next($this->tokens)) !== false)
{
if ($tok == '#')
{
$tok = next($this->tokens);
if ($tok == 'SET' || $tok == 'SESSION_SET')
{
$this->analyser_set($tok);
}
else if ($tok == 'GET' || $tok == 'ENV' || $tok == 'SESSION')
{
$content .= $this->analyser_get($tok);
}
else
{
$content .= '#'.$tok;
}
}
else if ($stopchar != '' && $tok == $stopchar)
{
break;
}
else
{
$content .= $tok;
}
}
// Parser::echo_debug( "parsing done.");
return $content;
}
private function demarrer($chaine)
{
$this->tokens = preg_split('/(\#|\{|\}|,)/', $chaine, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
// Comme on fait un next() dans parse content, insérer une valeur non significative en début de tableau
array_unshift($this->tokens, '');
//Parser::echo_debug("Tokens:", $this->tokens);
$content = $this->analyser_contenu();
//Parser::echo_debug("Content:", $content);
return $content;
}
}
?>