[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / public / compiler.php
index 362000a..a99fd95 100644 (file)
@@ -3,7 +3,7 @@
 /***************************************************************************\
  *  SPIP, Systeme de publication pour l'internet                           *
  *                                                                         *
- *  Copyright (c) 2001-2016                                                *
+ *  Copyright (c) 2001-2017                                                *
  *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
  *                                                                         *
  *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
 /**
  * Fichier principal du compilateur de squelettes
  *
- * @package SPIP\Compilateur\Compilation
-**/
+ * @package SPIP\Core\Compilateur\Compilation
+ **/
 
-if (!defined('_ECRIRE_INC_VERSION')) return;
+if (!defined('_ECRIRE_INC_VERSION')) {
+       return;
+}
 
 /** RepĂ©rer un code ne calculant rien, meme avec commentaire */
 define('CODE_MONOTONE', ",^(\n//[^\n]*\n)?\(?'([^'])*'\)?$,");
@@ -56,62 +58,91 @@ include_spip('public/jointures');
 // mais pas pour <INCLURE> dont le fond est defini explicitement.
 
 
-// http://doc.spip.org/@argumenter_inclure
-function argumenter_inclure($params, $rejet_filtres, $p, &$boucles, $id_boucle, $echap=true, $lang = '', $fond1=false){
+// http://code.spip.net/@argumenter_inclure
+function argumenter_inclure(
+       $params,
+       $rejet_filtres,
+       $p,
+       &$boucles,
+       $id_boucle,
+       $echap = true,
+       $lang = '',
+       $fond1 = false
+) {
        $l = array();
        $erreur_p_i_i = '';
-       if (!is_array($params)) return $l;
-       foreach($params as $k => $couple) {
-       // la liste d'arguments d'inclusion peut se terminer par un filtre
+       if (!is_array($params)) {
+               return $l;
+       }
+       foreach ($params as $k => $couple) {
+               // la liste d'arguments d'inclusion peut se terminer par un filtre
                $filtre = array_shift($couple);
-               if ($filtre) break;
-               foreach($couple as $n => $val) {
+               if ($filtre) {
+                       break;
+               }
+               foreach ($couple as $n => $val) {
                        $var = $val[0];
                        if ($var->type != 'texte') {
-                         if ($n OR $k OR $fond1) {
-                               $erreur_p_i_i = array('zbug_parametres_inclus_incorrects',
-                                        array('param' => $var->nom_champ));
-                               erreur_squelette($erreur_p_i_i, $p);
-                                 break;
-                         }
-                         else $l[1] = calculer_liste($val, $p->descr, $boucles, $id_boucle);
+                               if ($n or $k or $fond1) {
+                                       $erreur_p_i_i = array(
+                                               'zbug_parametres_inclus_incorrects',
+                                               array('param' => $var->nom_champ)
+                                       );
+                                       erreur_squelette($erreur_p_i_i, $p);
+                                       break;
+                               } else {
+                                       $l[1] = calculer_liste($val, $p->descr, $boucles, $id_boucle);
+                               }
                        } else {
-                               preg_match(",^([^=]*)(=?)(.*)$,m", $var->texte,$m);
+                               preg_match(",^([^=]*)(=?)(.*)$,m", $var->texte, $m);
+                               $m = array_pad($m, 3, null);
                                $var = $m[1];
                                $auto = false;;
                                if ($m[2]) {
-                                 $v = $m[3];
-                                 if (preg_match(',^[\'"](.*)[\'"]$,', $v, $m)) $v = $m[1];
-                                 $val[0] = new Texte;
-                                 $val[0]->texte = $v;
-                               } elseif ($k OR $n OR $fond1) {
-                                 $auto = true;
-                               } else $var = 1;
+                                       $v = $m[3];
+                                       if (preg_match(',^[\'"](.*)[\'"]$,', $v, $m)) {
+                                               $v = $m[1];
+                                       }
+                                       $val[0] = new Texte;
+                                       $val[0]->texte = $v;
+                               } elseif ($k or $n or $fond1) {
+                                       $auto = true;
+                               } else {
+                                       $var = 1;
+                               }
 
                                if ($var == 'lang') {
-                                 $lang = !$auto 
-                                   ? calculer_liste($val, $p->descr, $boucles, $id_boucle)
-                                   : '$GLOBALS["spip_lang"]';
+                                       $lang = !$auto
+                                               ? calculer_liste($val, $p->descr, $boucles, $id_boucle)
+                                               : '$GLOBALS["spip_lang"]';
                                } else {
-                                 $val = $auto
-                                   ? index_pile($id_boucle, $var, $boucles)
-                                   : calculer_liste($val, $p->descr, $boucles, $id_boucle);
-                                 if ($var !== 1)
-                                   $val = ($echap?"\'$var\' => ' . argumenter_squelette(":"'$var' => ")
-                                   . $val . ($echap? ") . '":" ");
-                                 else $val = $echap ? "'.$val.'" : $val;
-                                 $l[$var] = $val;
+                                       $val = $auto
+                                               ? index_pile($id_boucle, $var, $boucles)
+                                               : calculer_liste($val, $p->descr, $boucles, $id_boucle);
+                                       if ($var !== 1) {
+                                               $val = ($echap ? "\'$var\' => ' . argumenter_squelette(" : "'$var' => ")
+                                                       . $val . ($echap ? ") . '" : " ");
+                                       } else {
+                                               $val = $echap ? "'.$val.'" : $val;
+                                       }
+                                       $l[$var] = $val;
                                }
                        }
                }
        }
-       if ($erreur_p_i_i) return false;
+       if ($erreur_p_i_i) {
+               return false;
+       }
        // Cas particulier de la langue : si {lang=xx} est definie, on
        // la passe, sinon on passe la langue courante au moment du calcul
        // sauf si on n'en veut pas 
-       if ($lang === false) return $l;
-       if (!$lang) $lang = '$GLOBALS["spip_lang"]';
-       $l['lang'] = ($echap?"\'lang\' => ' . argumenter_squelette(":"'lang' => ")  . $lang . ($echap?") . '":" ");
+       if ($lang === false) {
+               return $l;
+       }
+       if (!$lang) {
+               $lang = '$GLOBALS["spip_lang"]';
+       }
+       $l['lang'] = ($echap ? "\'lang\' => ' . argumenter_squelette(" : "'lang' => ") . $lang . ($echap ? ") . '" : " ");
 
        return $l;
 }
@@ -134,7 +165,7 @@ define('CODE_RECUPERER_FOND', 'recuperer_fond(%s, %s, array(%s), %s)');
  *     Identifiant de la boucle contenant l'inclure
  * @return string
  *     Code PHP appelant l'inclusion
-**/
+ **/
 function calculer_inclure($p, &$boucles, $id_boucle) {
 
        $_contexte = argumenter_inclure($p->param, false, $p, $boucles, $id_boucle, true, '', true);
@@ -144,21 +175,26 @@ function calculer_inclure($p, &$boucles, $id_boucle) {
 
        } else {
                $code = calculer_liste($p->texte, $p->descr, $boucles, $id_boucle);
-               if ($code AND preg_match("/^'([^']*)'/s", $code, $r))
+               if ($code and preg_match("/^'([^']*)'/s", $code, $r)) {
                        $fichier = $r[1];
-               else $fichier = '';
+               } else {
+                       $fichier = '';
+               }
        }
-       if (!$code OR $code === '""') {
-               $erreur_p_i_i = array('zbug_parametres_inclus_incorrects',
-                                        array('param' => $code));
+       if (!$code or $code === '""') {
+               $erreur_p_i_i = array(
+                       'zbug_parametres_inclus_incorrects',
+                       array('param' => $code)
+               );
                erreur_squelette($erreur_p_i_i, $p);
+
                return false;
        }
        $compil = texte_script(memoriser_contexte_compil($p));
 
        if (is_array($_contexte)) {
                // Critere d'inclusion {env} (et {self} pour compatibilite ascendante)
-               if ($env = (isset($_contexte['env'])|| isset($_contexte['self']))) {
+               if ($env = (isset($_contexte['env']) || isset($_contexte['self']))) {
                        unset($_contexte['env']);
                }
 
@@ -167,17 +203,17 @@ function calculer_inclure($p, &$boucles, $id_boucle) {
                        $_contexte['doublons'] = "\\'doublons\\' => '.var_export(\$doublons,true).'";
                }
 
-               if ($ajax = isset($_contexte['ajax'])){
-                       $ajax = preg_replace(",=>(.*)$,ims",'=> ($v=(\\1))?$v:true',$_contexte['ajax']);
+               if ($ajax = isset($_contexte['ajax'])) {
+                       $ajax = preg_replace(",=>(.*)$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']);
                        unset($_contexte['ajax']);
                }
 
                $_contexte = join(",\n\t", $_contexte);
-       }
-       else
-               return false; // j'aurais voulu toucher le fond ...
-               
-       $contexte = 'array(' . $_contexte  .')';
+       } else {
+               return false;
+       } // j'aurais voulu toucher le fond ...
+
+       $contexte = 'array(' . $_contexte ')';
 
        if ($env) {
                $contexte = "array_merge('.var_export(\$Pile[0],1).',$contexte)";
@@ -186,15 +222,17 @@ function calculer_inclure($p, &$boucles, $id_boucle) {
        // s'il y a une extension .php, ce n'est pas un squelette
        if ($fichier and preg_match('/^.+[.]php$/s', $fichier)) {
                $code = sandbox_composer_inclure_php($fichier, $p, $contexte);
-       } else  {
+       } else {
                $_options[] = "\"compil\"=>array($compil)";
-               if ($ajax)
+               if ($ajax) {
                        $_options[] = $ajax;
-               $code = " ' . argumenter_squelette($code) . '"; 
-               $code = "echo " . sprintf(CODE_RECUPERER_FOND, $code, $contexte, implode(',',$_options), "_request(\"connect\")") . ';';
+               }
+               $code = " ' . argumenter_squelette($code) . '";
+               $code = "echo " . sprintf(CODE_RECUPERER_FOND, $code, $contexte, implode(',', $_options),
+                               "_request(\"connect\")") . ';';
        }
 
-       return  "\n'<'.'".      "?php ". $code . "\n?'." . "'>'";
+       return "\n'<'.'" . "?php " . $code . "\n?'." . "'>'";
 }
 
 
@@ -211,7 +249,7 @@ function calculer_inclure($p, &$boucles, $id_boucle) {
  * @param bool $ignore_previsu
  *     true pour ne tester que le cas publie et ignorer l'eventuel var_mode=preview de la page
  */
-function instituer_boucle(&$boucle, $echapper=true, $ignore_previsu=false){
+function instituer_boucle(&$boucle, $echapper = true, $ignore_previsu = false) {
        /*
        $show['statut'][] = array(
                'champ'=>'statut',  // champ de la table sur lequel porte le filtrage par le statut
@@ -238,13 +276,13 @@ function instituer_boucle(&$boucle, $echapper=true, $ignore_previsu=false){
 */
        $id_table = $boucle->id_table;
        $show = $boucle->show;
-       if (isset($show['statut']) AND $show['statut']){
-               foreach($show['statut'] as $k=>$s){
+       if (isset($show['statut']) and $show['statut']) {
+               foreach ($show['statut'] as $k => $s) {
                        // Restreindre aux elements publies si pas de {statut} ou autre dans les criteres
                        $filtrer = true;
                        if (isset($s['exception'])) {
-                               foreach(is_array($s['exception'])?$s['exception']:array($s['exception']) as $m) {
-                                       if (isset($boucle->modificateur[$m]) OR isset($boucle->modificateur['criteres'][$m])) {
+                               foreach (is_array($s['exception']) ? $s['exception'] : array($s['exception']) as $m) {
+                                       if (isset($boucle->modificateur[$m]) or isset($boucle->modificateur['criteres'][$m])) {
                                                $filtrer = false;
                                                break;
                                        }
@@ -252,51 +290,51 @@ function instituer_boucle(&$boucle, $echapper=true, $ignore_previsu=false){
                        }
 
                        if ($filtrer) {
-                               if (is_array($s['champ'])){
-                                       $statut = preg_replace(',\W,','',array_pop($s['champ'])); // securite
+                               if (is_array($s['champ'])) {
+                                       $statut = preg_replace(',\W,', '', array_pop($s['champ'])); // securite
                                        $jointures = array();
                                        // indiquer la description de chaque table dans le tableau de jointures,
                                        // ce qui permet d'eviter certains GROUP BY inutiles.
                                        $trouver_table = charger_fonction('trouver_table', 'base');
-                                       foreach($s['champ'] as $j) {
+                                       foreach ($s['champ'] as $j) {
                                                $id = reset($j);
                                                $def = $trouver_table($id);
-                                               $jointures[] = array('',array($id,$def),end($j));
+                                               $jointures[] = array('', array($id, $def), end($j));
                                        }
                                        $jointures[0][0] = $id_table;
-                                       if (!array_search($id, $boucle->from)){
+                                       if (!array_search($id, $boucle->from)) {
                                                include_spip('public/jointures');
                                                fabrique_jointures($boucle, $jointures, true, $boucle->show, $id_table, '', $echapper);
                                        }
                                        // trouver l'alias de la table d'arrivee qui porte le statut
                                        $id = array_search($id, $boucle->from);
-                               }
-                               else {
+                               } else {
                                        $id = $id_table;
-                                       $statut = preg_replace(',\W,','',$s['champ']); // securite
+                                       $statut = preg_replace(',\W,', '', $s['champ']); // securite
                                }
-                               $mstatut = $id .'.'.$statut;
+                               $mstatut = $id . '.' . $statut;
 
-                               $arg_ignore_previsu=($ignore_previsu?",true":'');
+                               $arg_ignore_previsu = ($ignore_previsu ? ",true" : '');
                                include_spip('public/quete');
-                               if (isset($s['post_date']) AND $s['post_date']
-                                       AND $GLOBALS['meta']["post_dates"] == 'non'){
-                                       $date = $id.'.'.preg_replace(',\W,','',$s['post_date']); // securite
+                               if (isset($s['post_date']) and $s['post_date']
+                                       and $GLOBALS['meta']["post_dates"] == 'non'
+                               ) {
+                                       $date = $id . '.' . preg_replace(',\W,', '', $s['post_date']); // securite
                                        array_unshift($boucle->where,
                                                $echapper ?
-                                                       "\nquete_condition_postdates('$date',"._q($boucle->sql_serveur)."$arg_ignore_previsu)"
-                                               :
-                                                       quete_condition_postdates($date,$boucle->sql_serveur,$ignore_previsu)
+                                                       "\nquete_condition_postdates('$date'," . _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
+                                                       :
+                                                       quete_condition_postdates($date, $boucle->sql_serveur, $ignore_previsu)
                                        );
                                }
                                array_unshift($boucle->where,
                                        $echapper ?
                                                "\nquete_condition_statut('$mstatut',"
-                                                       . _q($s['previsu']).","
-                                                       ._q($s['publie']).","
-                                                       ._q($boucle->sql_serveur)."$arg_ignore_previsu)"
-                                       :
-                                               quete_condition_statut($mstatut,$s['previsu'],$s['publie'],$boucle->sql_serveur,$ignore_previsu)
+                                               . _q($s['previsu']) . ","
+                                               . _q($s['publie']) . ","
+                                               . _q($boucle->sql_serveur) . "$arg_ignore_previsu)"
+                                               :
+                                               quete_condition_statut($mstatut, $s['previsu'], $s['publie'], $boucle->sql_serveur, $ignore_previsu)
                                );
                        }
                }
@@ -305,17 +343,17 @@ function instituer_boucle(&$boucle, $echapper=true, $ignore_previsu=false){
 
 /**
  * Produit le corps PHP d'une boucle Spip.
- * 
+ *
  * Ce corps remplit une variable $t0 retournĂ©e en valeur.
  * Ici on distingue boucles recursives et boucle Ă  requĂŞte SQL
  * et on insère le code d'envoi au debusqueur du resultat de la fonction.
  *
  * @param string $id_boucle
- *             Identifiant de la boucle
+ *    Identifiant de la boucle
  * @param array $boucles
- *             AST du squelette
+ *    AST du squelette
  * @return string
- *             Code PHP compilĂ© de la boucle
+ *    Code PHP compilĂ© de la boucle
  */
 function calculer_boucle($id_boucle, &$boucles) {
 
@@ -325,63 +363,66 @@ function calculer_boucle($id_boucle, &$boucles) {
 
        // en mode debug memoriser les premiers passages dans la boucle,
        // mais pas tous, sinon ca pete.
-       if  (_request('var_mode_affiche') != 'resultat') 
+       if (_request('var_mode_affiche') != 'resultat') {
                $trace = '';
-       else {
+       else {
                $trace = $boucles[$id_boucle]->descr['nom'] . $id_boucle;
                $trace = "if (count(@\$GLOBALS['debug_objets']['resultat']['$trace'])<3)
            \$GLOBALS['debug_objets']['resultat']['$trace'][] = \$t0;";
        }
+
        return ($boucles[$id_boucle]->type_requete == TYPE_RECURSIF)
-       ? calculer_boucle_rec($id_boucle, $boucles, $trace) 
-       : calculer_boucle_nonrec($id_boucle, $boucles, $trace);
+               ? calculer_boucle_rec($id_boucle, $boucles, $trace)
+               : calculer_boucle_nonrec($id_boucle, $boucles, $trace);
 }
 
 
 /**
- * Compilation d'une boucle recursive. 
+ * Compilation d'une boucle recursive.
  *
  * @internal
- *             Il suffit (ET IL FAUT) sauvegarder les valeurs des arguments passes par
- *             reference, car par definition un tel passage ne les sauvegarde pas
- * 
+ *    Il suffit (ET IL FAUT) sauvegarder les valeurs des arguments passes par
+ *    reference, car par definition un tel passage ne les sauvegarde pas
+ *
  * @param string $id_boucle
- *             Identifiant de la boucle
+ *    Identifiant de la boucle
  * @param array $boucles
- *             AST du squelette
+ *    AST du squelette
  * @param string $trace
- *             Code PHP (en mode debug uniquement) servant Ă  conserver une
- *             trace des premières valeurs de la boucle afin de pouvoir
- *             les afficher dans le dĂ©bugueur ultĂ©rieurement
+ *    Code PHP (en mode debug uniquement) servant Ă  conserver une
+ *    trace des premières valeurs de la boucle afin de pouvoir
+ *    les afficher dans le dĂ©bugueur ultĂ©rieurement
  * @return string
- *             Code PHP compilĂ© de la boucle rĂ©cursive
-**/
+ *    Code PHP compilĂ© de la boucle rĂ©cursive
+ **/
 function calculer_boucle_rec($id_boucle, &$boucles, $trace) {
        $nom = $boucles[$id_boucle]->param[0];
+
        return
-         // Numrows[$nom] peut ne pas ĂŞtre encore defini
-         "\n\t\$save_numrows = (isset(\$Numrows['$nom']) ? \$Numrows['$nom'] : array());"
-       . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ";"
-       . "\n\t\$Numrows['$nom'] = (\$save_numrows);"
-       . $trace
-       . "\n\treturn \$t0;";
+               // Numrows[$nom] peut ne pas ĂŞtre encore defini
+               "\n\t\$save_numrows = (isset(\$Numrows['$nom']) ? \$Numrows['$nom'] : array());"
+               . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ";"
+               . "\n\t\$Numrows['$nom'] = (\$save_numrows);"
+               . $trace
+               . "\n\treturn \$t0;";
 }
 
 /**
  * Compilation d'une boucle non recursive.
- * 
+ *
  * La constante donne le cadre systĂ©matique du code:
- * %s1: initialisation des arguments de calculer_select
- * %s2: appel de calculer_select en donnant un contexte pour les cas d'erreur
- * %s3: initialisation du sous-tableau Numrows[id_boucle]
- * %s4: sauvegarde de la langue et calcul des invariants de boucle sur elle
- * %s5: boucle while sql_fetch ou str_repeat si corps monotone
- * %s6: restauration de la langue
- * %s7: liberation de la ressource, en tenant compte du serveur SQL 
- * %s8: code de trace eventuel avant le retour
-**/
+ *
+ * - %s1: initialisation des arguments de calculer_select
+ * - %s2: appel de calculer_select en donnant un contexte pour les cas d'erreur
+ * - %s3: initialisation du sous-tableau Numrows[id_boucle]
+ * - %s4: sauvegarde de la langue et calcul des invariants de boucle sur elle
+ * - %s5: boucle while sql_fetch ou str_repeat si corps monotone
+ * - %s6: restauration de la langue
+ * - %s7: liberation de la ressource, en tenant compte du serveur SQL
+ * - %s8: code de trace eventuel avant le retour
+ **/
 define('CODE_CORPS_BOUCLE', '%s
-       if (defined("_BOUCLE_PROFILER")) $timer = time()+microtime();
+       if (defined("_BOUCLE_PROFILER")) $timer = time()+(float)microtime();
        $t0 = "";
        // REQUETE
        $iter = IterFactory::create(
@@ -396,50 +437,54 @@ define('CODE_CORPS_BOUCLE', '%s
        %s$iter->free();
        }%s
        if (defined("_BOUCLE_PROFILER")
-       AND 1000*($timer = (time()+microtime())-$timer) > _BOUCLE_PROFILER)
+       AND 1000*($timer = (time()+(float)microtime())-$timer) > _BOUCLE_PROFILER)
                spip_log(intval(1000*$timer)."ms %s","profiler"._LOG_AVERTISSEMENT);
        return $t0;'
 );
 
 /**
- * Compilation d'une boucle (non recursive). 
+ * Compilation d'une boucle (non recursive).
  *
  * @param string $id_boucle
- *             Identifiant de la boucle
+ *    Identifiant de la boucle
  * @param array $boucles
- *             AST du squelette
+ *    AST du squelette
  * @param string $trace
- *             Code PHP (en mode debug uniquement) servant Ă  conserver une
- *             trace des premières valeurs de la boucle afin de pouvoir
- *             les afficher dans le dĂ©bugueur ultĂ©rieurement
+ *    Code PHP (en mode debug uniquement) servant Ă  conserver une
+ *    trace des premières valeurs de la boucle afin de pouvoir
+ *    les afficher dans le dĂ©bugueur ultĂ©rieurement
  * @return string
- *             Code PHP compilĂ© de la boucle rĂ©cursive
-**/
+ *    Code PHP compilĂ© de la boucle rĂ©cursive
+ **/
 function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
 
        $boucle = &$boucles[$id_boucle];
        $return = $boucle->return;
        $type_boucle = $boucle->type_requete;
        $primary = $boucle->primary;
-       $constant = preg_match(CODE_MONOTONE, str_replace("\\'",'', $return));
-       $flag_cpt = $boucle->mode_partie ||$boucle->cptrows;
+       $constant = preg_match(CODE_MONOTONE, str_replace("\\'", '', $return));
+       $flag_cpt = $boucle->mode_partie || $boucle->cptrows;
        $corps = '';
 
        // faudrait expanser le foreach a la compil, car y en a souvent qu'un 
        // et puis faire un [] plutot qu'un "','."
-       if ($boucle->doublons)
+       if ($boucle->doublons) {
                $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
-               index_pile($id_boucle, $primary, $boucles)
-               . "; // doublons\n";
+                       index_pile($id_boucle, $primary, $boucles)
+                       . "; // doublons\n";
+       }
 
        // La boucle doit-elle selectionner la langue ?
        // - par defaut, les boucles suivantes le font
        //    (sauf si forcer_lang==true ou si le titre contient <multi>).
        // - a moins d'une demande explicite via {!lang_select}
        if (!$constant && $boucle->lang_select != 'non' &&
-           (($boucle->lang_select == 'oui')  ||
-                   in_array($type_boucle, array(
-                       'articles', 'rubriques', 'hierarchie', 'breves'
+               (($boucle->lang_select == 'oui') ||
+                       in_array($type_boucle, array(
+                               'articles',
+                               'rubriques',
+                               'hierarchie',
+                               'breves'
                        )))
        ) {
                // Memoriser la langue avant la boucle et la restituer apres
@@ -448,24 +493,27 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
                $fin_lang = "lang_select();\n\t";
                $fin_lang_select_public = "\n\t\tlang_select();";
 
-               $corps .= 
+               $corps .=
                        "\n\t\tlang_select_public("
                        . index_pile($id_boucle, 'lang', $boucles)
-                       . ", '".$boucle->lang_select."'"
+                       . ", '" . $boucle->lang_select . "'"
                        . (in_array($type_boucle, array(
-                               'articles', 'rubriques', 'hierarchie', 'breves'
-                               )) ? ', '.index_pile($id_boucle, 'titre', $boucles) : '')
+                               'articles',
+                               'rubriques',
+                               'hierarchie',
+                               'breves'
+                       )) ? ', ' . index_pile($id_boucle, 'titre', $boucles) : '')
                        . ');';
-       }
-       else {
+       } else {
                $init_lang = '';
                $fin_lang = '';
                $fin_lang_select_public = '';
                // sortir les appels au traducteur (invariants de boucle)
                if (strpos($return, '?php') === false
-               AND preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r)) {
+                       and preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r)
+               ) {
                        $i = 1;
-                       foreach($r[1] as $t) {
+                       foreach ($r[1] as $t) {
                                $init_lang .= "\n\t\$l$i = $t;";
                                $return = str_replace($t, "\$l$i", $return);
                                $i++;
@@ -474,79 +522,89 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
        }
 
        // gestion optimale des separateurs et des boucles constantes
-       if (count($boucle->separateur))
-         $code_sep = ("'" . str_replace("'","\'",join('',$boucle->separateur)) . "'");
+       if (count($boucle->separateur)) {
+               $code_sep = ("'" . str_replace("'", "\'", join('', $boucle->separateur)) . "'");
+       }
 
-       $corps .= 
-               ((!$boucle->separateur) ? 
+       $corps .=
+               ((!$boucle->separateur) ?
                        (($constant && !$corps && !$flag_cpt) ? $return :
-                        (($return==="''") ? '' :
-                         ("\n\t\t" . '$t0 .= ' . $return . ";"))) :
-                ("\n\t\t\$t1 " .
-                       ((strpos($return, '$t1.') === 0) ? 
-                        (".=" . substr($return,4)) :
-                        ('= ' . $return)) .
-                 ";\n\t\t" .
-                 '$t0 .= ((strlen($t1) && strlen($t0)) ? ' . $code_sep . " : '') . \$t1;"));
-     
+                               (($return === "''") ? '' :
+                                       ("\n\t\t" . '$t0 .= ' . $return . ";"))) :
+                       ("\n\t\t\$t1 " .
+                               ((strpos($return, '$t1.') === 0) ?
+                                       (".=" . substr($return, 4)) :
+                                       ('= ' . $return)) .
+                               ";\n\t\t" .
+                               '$t0 .= ((strlen($t1) && strlen($t0)) ? ' . $code_sep . " : '') . \$t1;"));
+
        // Calculer les invalideurs si c'est une boucle non constante et si on
        // souhaite invalider ces elements
-       if (!$constant AND $primary) {
+       if (!$constant and $primary) {
                include_spip('inc/invalideur');
-               if (function_exists($i = 'calcul_invalideurs'))
+               if (function_exists($i = 'calcul_invalideurs')) {
                        $corps = $i($corps, $primary, $boucles, $id_boucle);
+               }
        }
 
        // gerer le compteur de boucle 
        // avec ou sans son utilisation par les criteres {1/3} {1,4} {n-2,1}...
 
-       if ($boucle->partie OR $boucle->cptrows)
+       if ($boucle->partie or $boucle->cptrows) {
                $corps = "\n\t\t\$Numrows['$id_boucle']['compteur_boucle']++;"
-               . $boucle->partie 
-               . $corps;
+                       . $boucle->partie
+                       . $corps;
+       }
 
        // depiler la lang de la boucle si besoin
        $corps .= $fin_lang_select_public;
 
        // si le corps est une constante, ne pas appeler le serveur N fois!
 
-       if (preg_match(CODE_MONOTONE,str_replace("\\'",'',$corps), $r)) {
-               if (!isset($r[2]) OR (!$r[2])) {
-                       if (!$boucle->numrows)
+       if (preg_match(CODE_MONOTONE, str_replace("\\'", '', $corps), $r)) {
+               if (!isset($r[2]) or (!$r[2])) {
+                       if (!$boucle->numrows) {
                                return "\n\t\$t0 = '';";
-                       else
+                       } else {
                                $corps = "";
+                       }
                } else {
                        $boucle->numrows = true;
                        $corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);";
                }
-       } else $corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n       }"; 
+       } else {
+               $corps = "while (\$Pile[\$SP]=\$iter->fetch()) {\n$corps\n      }";
+       }
 
        $count = '';
        if (!$boucle->select) {
-               if (!$boucle->numrows OR $boucle->limit OR $boucle->mode_partie OR $boucle->group)
+               if (!$boucle->numrows or $boucle->limit or $boucle->mode_partie or $boucle->group) {
                        $count = '1';
-               else $count = 'count(*)';
-               $boucles[$id_boucle]->select[]= $count; 
+               } else {
+                       $count = 'count(*)';
+               }
+               $boucles[$id_boucle]->select[] = $count;
        }
 
-       if ($flag_cpt)
+       if ($flag_cpt) {
                $nums = "\n\t// COMPTEUR\n\t"
-               . "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t";
-       else $nums = '';
+                       . "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t";
+       } else {
+               $nums = '';
+       }
 
-       if ($boucle->numrows OR $boucle->mode_partie) {
+       if ($boucle->numrows or $boucle->mode_partie) {
                $nums .= "\$Numrows['$id_boucle']['total'] = @intval(\$iter->count());"
-               . $boucle->mode_partie
-               . "\n\t";
+                       . $boucle->mode_partie
+                       . "\n\t";
        }
 
        // Ne calculer la requete que maintenant
        // car ce qui precede appelle index_pile qui influe dessus
 
        $init = (($init = $boucles[$id_boucle]->doublons)
-                        ? ("\n\t$init = array();") : '')
-       . calculer_requete_sql($boucles[$id_boucle]);
+                       ? ("\n\t$init = array();") : '')
+               . calculer_requete_sql($boucles[$id_boucle]);
 
        $contexte = memoriser_contexte_compil($boucle);
 
@@ -560,7 +618,7 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
                $corps,
                $fin_lang,
                $trace,
-               'BOUCLE'.$id_boucle .' @ '.($boucle->descr['sourcefile'])
+               'BOUCLE' . $id_boucle . ' @ ' . ($boucle->descr['sourcefile'])
        );
 
 #      var_dump($a);exit;
@@ -572,47 +630,51 @@ function calculer_boucle_nonrec($id_boucle, &$boucles, $trace) {
  * Calcule le code PHP d'une boucle contenant les informations qui produiront une requĂŞte SQL
  *
  * Le code produit est un tableau associatif $command contenant les informations
- * pour que la boucle produise ensuite sa requĂŞte, tel que $command['from'] = 'spip_articles';
+ * pour que la boucle produise ensuite sa requĂŞte, tel que `$command['from'] = 'spip_articles';`
  *
  * @param Boucle $boucle
- *             AST de la boucle 
+ *     AST de la boucle
  * @return string
- *             Code PHP compilĂ© dĂ©finissant les informations de requĂŞte
-**/
-function calculer_requete_sql($boucle)
-{
+ *     Code PHP compilĂ© dĂ©finissant les informations de requĂŞte
+ **/
+function calculer_requete_sql($boucle) {
        $init = array();
-       $init[] = calculer_dec('table',  "'" . $boucle->id_table ."'");
-       $init[] = calculer_dec('id', "'" . $boucle->id_boucle ."'");
+       $init[] = calculer_dec('table', "'" . $boucle->id_table . "'");
+       $init[] = calculer_dec('id', "'" . $boucle->id_boucle . "'");
        # En absence de champ c'est un decompte :
-       $init[] = calculer_dec('from',  calculer_from($boucle));
+       $init[] = calculer_dec('from', calculer_from($boucle));
        $init[] = calculer_dec('type', calculer_from_type($boucle));
-       $init[] = calculer_dec('groupby', 'array(' . (($g=join("\",\n\t\t\"",$boucle->group))?'"'.$g.'"':'') . ")");
-       $init[] = calculer_dec('select', 'array("' . join("\",\n\t\t\"", $boucle->select).  "\")");
-       $init[] = calculer_dec('orderby', 'array(' . calculer_order($boucle) .  ")");
+       $init[] = calculer_dec('groupby',
+               'array(' . (($g = join("\",\n\t\t\"", $boucle->group)) ? '"' . $g . '"' : '') . ")");
+       $init[] = calculer_dec('select', 'array("' . join("\",\n\t\t\"", $boucle->select) . "\")");
+       $init[] = calculer_dec('orderby', 'array(' . calculer_order($boucle) . ")");
        $init[] = calculer_dec('where', calculer_dump_array($boucle->where));
        $init[] = calculer_dec('join', calculer_dump_join($boucle->join));
        $init[] = calculer_dec('limit',
-                       (strpos($boucle->limit, 'intval') === false ?
-                                 "'".$boucle->limit."'"
-                               :
-                                 $boucle->limit));
+               (strpos($boucle->limit, 'intval') === false ?
+                       "'" . $boucle->limit . "'"
+                       :
+                       $boucle->limit));
        $init[] = calculer_dec('having', calculer_dump_array($boucle->having));
        $s = $d = "";
-       foreach ($init as $i){
-               if (reset($i))
-                       $s .= "\n\t\t".end($i);
-               else
-                       $d .= "\n\t".end($i);
+       // l'index 0 de $i indique si l'affectation est statique (contenu)
+       // ou recalculĂ©e Ă  chaque passage (vide)
+       foreach ($init as $i) {
+               if (reset($i)) {
+                       $s .= "\n\t\t" . end($i);
+               } # statique
+               else {
+                       $d .= "\n\t" . end($i);
+               } # dynamique
        }
 
        return ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
-         . $boucle->in 
-         . $boucle->hash
-               . "\n\t".'if (!isset($command[\'table\'])) {'
-               . $s
-               . "\n\t}"
-               . $d;
+       . $boucle->in
+       . $boucle->hash
+       . "\n\t" . 'if (!isset($command[\'table\'])) {'
+       . $s
+       . "\n\t}"
+       . $d;
 }
 
 /**
@@ -622,52 +684,77 @@ function calculer_requete_sql($boucle)
  * de l'Ă©lĂ©ment dans une chaĂ®ne.
  *
  * @see reconstruire_contexte_compil()
- * 
+ *
  * @param Object $p
  *     Objet de l'AST dont on mĂ©morise le contexte
  * @return string
  *     Informations du contexte sĂ©parĂ©s par des virgules,
  *     qui peut ĂŞtre utilisĂ© pour la production d'un tableau array()
-**/
+ **/
 function memoriser_contexte_compil($p) {
        return join(',', array(
-               _q($p->descr['sourcefile']),
-               _q($p->descr['nom']),
-               @_q($p->id_boucle),
+               _q(isset($p->descr['sourcefile']) ? $p->descr['sourcefile'] : ''),
+               _q(isset($p->descr['nom']) ? $p->descr['nom'] : ''),
+               _q(isset($p->id_boucle) ? $p->id_boucle : null),
                intval($p->ligne),
-               '$GLOBALS[\'spip_lang\']'));
+               '$GLOBALS[\'spip_lang\']'
+       ));
 }
 
 /**
- * Reconstruit un contexte de compilation 
+ * Reconstruit un contexte de compilation
  *
  * Pour un tableau d'information de contexte donnĂ©,
  * retourne un objet Contexte (objet gĂ©nĂ©rique de l'AST)
  * avec ces informations
  *
  * @see memoriser_contexte_compil()
- * 
+ *
  * @param array $context_compil
  *     Tableau des informations du contexte
  * @return Contexte
  *     Objet Contexte
-**/
-function reconstruire_contexte_compil($context_compil)
-{
-       if (!is_array($context_compil)) return $context_compil;
+ **/
+function reconstruire_contexte_compil($context_compil) {
+       if (!is_array($context_compil)) {
+               return $context_compil;
+       }
        $p = new Contexte;
-       $p->descr = array('sourcefile' => $context_compil[0],
-                                 'nom' => $context_compil[1]);
+       $p->descr = array(
+               'sourcefile' => $context_compil[0],
+               'nom' => $context_compil[1]
+       );
        $p->id_boucle = $context_compil[2];
        $p->ligne = $context_compil[3];
        $p->lang = $context_compil[4];
+
        return $p;
 }
 
-// http://doc.spip.org/@calculer_dec
-function calculer_dec($nom, $val)
-{
-       $static = 'if (!isset($command[\''.$nom.'\'])) ';
+/**
+ * Calcule le code d'affectation d'une valeur Ă  une commande de boucle
+ *
+ * DĂ©crit le code qui complète le tableau $command qui servira entre autres
+ * Ă  l'itĂ©rateur. Pour un nom de commande donnĂ©e et un code PHP dĂ©crivant
+ * ou rĂ©cupĂ©rant une valeur, on retourne le code PHP qui fait l'affectation.
+ *
+ * L'index 0 du tableau retournĂ© indique, lorsqu'il n'est pas vide, que l'affectation
+ * de la variable pourra ĂŞtre statique (c'est Ă  dire qu'il ne dĂ©pend
+ * pas d'une quelconque variable PHP), et donc attribuĂ© une fois pour toutes
+ * quelque soit le nombre d'appels de la boucle.
+ *
+ * @param string $nom
+ *    Nom de la commande
+ * @param string $val
+ *    Code PHP dĂ©crivant la valeur Ă  affecter
+ * @return array
+ *
+ *    - index 0 : Code pour une affectation statique. Si non rempli, la propriĂ©tĂ© devra
+ *                ĂŞtre rĂ©-affectĂ©e Ă  chaque appel de la boucle.
+ *    - index 1 : Code de l'affectation
+ **/
+function calculer_dec($nom, $val) {
+       $static = 'if (!isset($command[\'' . $nom . '\'])) ';
        // si une variable apparait dans le calcul de la clause
        // il faut la re-evaluer a chaque passage
        if (
@@ -680,59 +767,100 @@ function calculer_dec($nom, $val)
                        AND $test = preg_replace(",'[^']*',UimsS","",$test) // supprimer les chaines qui peuvent contenir des fonctions SQL qui ne genent pas
                        AND preg_match(",\w+\s*\(,UimsS",$test,$regs) // tester la presence de fonctions restantes
                )*/
-       )
+       ) {
                $static = "";
+       }
 
-       return array($static,'$command[\''.$nom.'\'] = ' . $val . ';');
+       return array($static, '$command[\'' . $nom . '\'] = ' . $val . ';');
 }
 
-// http://doc.spip.org/@calculer_dump_array
-function calculer_dump_array($a)
-{
-  if (!is_array($a)) return $a ;
-  $res = "";
-  if ($a AND $a[0] == "'?'") 
-    return ("(" . calculer_dump_array($a[1]) .
-           " ? " . calculer_dump_array($a[2]) .
-           " : " . calculer_dump_array($a[3]) .
-           ")");
-  else {
-    foreach($a as $v) $res .= ", " . calculer_dump_array($v);
-    return "\n\t\t\tarray(" . substr($res,2) . ')';
-  }
+/**
+ * Calcule l'expression PHP dĂ©crivant un tableau complexe (ou une chaĂ®ne)
+ *
+ * Lorsqu'un tableau est transmis, reconstruit de quoi crĂ©er le tableau
+ * en code PHP (une sorte de var_export) en appelant pour chaque valeur
+ * cette fonction de manière rĂ©cursive.
+ *
+ * Si le premier index (0) du tableau est "'?'", retourne un code
+ * de test entre les 3 autres valeurs (v1 ? v2 : v3). Les valeurs
+ * pouvant ĂŞtre des tableaux aussi.
+ *
+ * @param mixed $a
+ *     Les donnĂ©es dont on veut construire un Ă©quivalent de var_export
+ * @return string
+ *     Expression PHP dĂ©crivant un texte ou un tableau
+ **/
+function calculer_dump_array($a) {
+       if (!is_array($a)) {
+               return $a;
+       }
+       $res = "";
+       if ($a and $a[0] == "'?'") {
+               return ("(" . calculer_dump_array($a[1]) .
+                       " ? " . calculer_dump_array($a[2]) .
+                       " : " . calculer_dump_array($a[3]) .
+                       ")");
+       } else {
+               foreach ($a as $v) {
+                       $res .= ", " . calculer_dump_array($v);
+               }
+
+               return "\n\t\t\tarray(" . substr($res, 2) . ')';
+       }
 }
 
-// http://doc.spip.org/@calculer_dump_join
-function calculer_dump_join($a)
-{
-  $res = "";
-  foreach($a as $k => $v) 
-               $res .= ", '$k' => array(".implode(',',$v).")";
-  return 'array(' . substr($res,2) . ')';
+// http://code.spip.net/@calculer_dump_join
+function calculer_dump_join($a) {
+       $res = "";
+       foreach ($a as $k => $v) {
+               $res .= ", '$k' => array(" . implode(',', $v) . ")";
+       }
+
+       return 'array(' . substr($res, 2) . ')';
 }
 
-// http://doc.spip.org/@calculer_from
-function calculer_from(&$boucle)
-{
-  $res = "";
-  foreach($boucle->from as $k => $v) $res .= ",'$k' => '$v'";
-  return 'array(' . substr($res,1) . ')';
+/**
+ * Calcule l'expression PHP dĂ©crivant les informations FROM d'une boucle
+ *
+ * @param Boucle $boucle
+ *     Description de la boucle
+ * @return string
+ *     Code PHP construisant un tableau des alias et noms des tables du FROM
+ **/
+function calculer_from(&$boucle) {
+       $res = "";
+       foreach ($boucle->from as $k => $v) {
+               $res .= ",'$k' => '$v'";
+       }
+
+       return 'array(' . substr($res, 1) . ')';
 }
 
-// http://doc.spip.org/@calculer_from_type
-function calculer_from_type(&$boucle)
-{
-  $res = "";
-  foreach($boucle->from_type as $k => $v) $res .= ",'$k' => '$v'";
-  return 'array(' . substr($res,1) . ')';
+/**
+ * Calcule l'expression PHP dĂ©crivant des informations de type de jointure
+ * pour un alias de table connu dans le FROM
+ *
+ * @param Boucle $boucle
+ *     Description de la boucle
+ * @return string
+ *     Code PHP construisant un tableau des alias et type de jointure du FROM
+ **/
+function calculer_from_type(&$boucle) {
+       $res = "";
+       foreach ($boucle->from_type as $k => $v) {
+               $res .= ",'$k' => '$v'";
+       }
+
+       return 'array(' . substr($res, 1) . ')';
 }
 
-// http://doc.spip.org/@calculer_order
-function calculer_order(&$boucle)
-{
+// http://code.spip.net/@calculer_order
+function calculer_order(&$boucle) {
        if (!$order = $boucle->order
-       AND !$order = $boucle->default_order)
+               and !$order = $boucle->default_order
+       ) {
                $order = array();
+       }
 
        /*if (isset($boucle->modificateur['collate'])){
                $col = "." . $boucle->modificateur['collate'];
@@ -740,6 +868,7 @@ function calculer_order(&$boucle)
                        if (strpos($order[$k],'COLLATE')===false)
                                $order[$k].= $col;
        }*/
+
        return join(', ', $order);
 }
 
@@ -748,47 +877,60 @@ function calculer_order(&$boucle)
 // Retourne une expression PHP,
 // (qui sera argument d'un Return ou la partie droite d'une affectation).
 
-// http://doc.spip.org/@calculer_liste
-function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') {
-       if (!$tableau) return "''";
-       if (!isset($descr['niv'])) $descr['niv'] = 0;
+// http://code.spip.net/@calculer_liste
+function calculer_liste($tableau, $descr, &$boucles, $id_boucle = '') {
+       if (!$tableau) {
+               return "''";
+       }
+       if (!isset($descr['niv'])) {
+               $descr['niv'] = 0;
+       }
        $codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
-       if ($codes === false) return false;
+       if ($codes === false) {
+               return false;
+       }
        $n = count($codes);
-       if (!$n) return "''";
+       if (!$n) {
+               return "''";
+       }
        $tab = str_repeat("\t", $descr['niv']);
        if (_request('var_mode_affiche') != 'validation') {
-               if ($n==1) 
+               if ($n == 1) {
                        return $codes[0];
-               else {
+               else {
                        $res = '';
-                       foreach($codes as $code) {
+                       foreach ($codes as $code) {
                                if (!preg_match("/^'[^']*'$/", $code)
-                               OR substr($res,-1,1)!=="'")
-                                 $res .=  " .\n$tab$code";
-                               else {
-                                 $res = substr($res,0,-1) . substr($code,1);
+                                       or substr($res, -1, 1) !== "'"
+                               ) {
+                                       $res .= " .\n$tab$code";
+                               } else {
+                                       $res = substr($res, 0, -1) . substr($code, 1);
                                }
                        }
-                       return '(' . substr($res,2+$descr['niv']) . ')';
+
+                       return '(' . substr($res, 2 + $descr['niv']) . ')';
                }
        } else {
-         $nom = $descr['nom'] . $id_boucle .  ($descr['niv']?$descr['niv']:'');
-         return "join('', array_map('array_shift', \$GLOBALS['debug_objets']['sequence']['$nom'] = array(" .  join(" ,\n$tab", $codes) . ")))";
+               $nom = $descr['nom'] . $id_boucle . ($descr['niv'] ? $descr['niv'] : '');
+
+               return "join('', array_map('array_shift', \$GLOBALS['debug_objets']['sequence']['$nom'] = array(" . join(" ,\n$tab",
+                       $codes) . ")))";
        }
 }
 
-define('_REGEXP_COND_VIDE_NONVIDE',"/^[(](.*)[?]\s*''\s*:\s*('[^']+')\s*[)]$/");
-define('_REGEXP_COND_NONVIDE_VIDE',"/^[(](.*)[?]\s*('[^']+')\s*:\s*''\s*[)]$/");
+define('_REGEXP_COND_VIDE_NONVIDE', "/^[(](.*)[?]\s*''\s*:\s*('[^']+')\s*[)]$/");
+define('_REGEXP_COND_NONVIDE_VIDE', "/^[(](.*)[?]\s*('[^']+')\s*:\s*''\s*[)]$/");
 define('_REGEXP_CONCAT_NON_VIDE', "/^(.*)[.]\s*'[^']+'\s*$/");
 
-// http://doc.spip.org/@compile_cas
+// http://code.spip.net/@compile_cas
 function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
 
-        $codes = array();
+       $codes = array();
        // cas de la boucle recursive
-       if (is_array($id_boucle)) 
-         $id_boucle = $id_boucle[0];
+       if (is_array($id_boucle)) {
+               $id_boucle = $id_boucle[0];
+       }
        $type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
        $tab = str_repeat("\t", ++$descr['niv']);
        $mode = _request('var_mode_affiche');
@@ -797,158 +939,169 @@ function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
        // par un caractere distinguant le cas, pour exploitation par debug.
        foreach ($tableau as $p) {
 
-               switch($p->type) {
-               // texte seul
-               case 'texte':
-                       $code = sandbox_composer_texte($p->texte, $p);
-                       $commentaire= strlen($p->texte) . " signes";
-                       $avant='';
-                       $apres='';
-                       $altern = "''";
-                       break;
-
-               case 'polyglotte':
-                       $code = "";
-                       foreach($p->traductions as $k => $v) {
-                         $code .= ",'" .
-                           str_replace(array("\\","'"),array("\\\\","\\'"), $k) .
-                           "' => '" .
-                           str_replace(array("\\","'"),array("\\\\","\\'"), $v) .
-                           "'";
-                       }
-                       $code = "choisir_traduction(array(" .
-                         substr($code,1) .
-                         "))";
-                       $commentaire= '&';
-                       $avant='';
-                       $apres='';
-                       $altern = "''";
-                       break;
-
-               // inclure
-               case 'include':
-                       $p->descr = $descr;
-                       $code = calculer_inclure($p, $boucles, $id_boucle);
-                       if ($code === false) {
-                               $err_e_c = true;
-                               $code = "''";
-                       } else {
-                               $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
-                               $avant='';
-                               $apres='';
+               switch ($p->type) {
+                       // texte seul
+                       case 'texte':
+                               $code = sandbox_composer_texte($p->texte, $p);
+                               $commentaire = strlen($p->texte) . " signes";
+                               $avant = '';
+                               $apres = '';
                                $altern = "''";
-                       }
-                       break;
-
-               // boucle
-               case TYPE_RECURSIF:
-                       $nom = $p->id_boucle;
-                       $newdescr = $descr;
-                       $newdescr['id_mere'] = $nom;
-                       $newdescr['niv']++;
-                       $avant = calculer_liste($p->avant,
-                               $newdescr, $boucles, $id_boucle);
-                       $apres = calculer_liste($p->apres,
-                               $newdescr, $boucles, $id_boucle);
-                       $newdescr['niv']--;
-                       $altern = calculer_liste($p->altern,
-                               $newdescr, $boucles, $id_boucle);
-                       if (($avant === false) OR ($apres === false) OR ($altern === false)) {
-                               $err_e_c = true;
-                               $code = "''";
-                       } else {
-                               $code = 'BOUCLE' .
-                                 str_replace("-","_", $nom) . $descr['nom'] .
-                                 '($Cache, $Pile, $doublons, $Numrows, $SP)';
-                               $commentaire= "?$nom";
-                               if (!$boucles[$nom]->milieu
-                               AND $boucles[$nom]->type_requete <> TYPE_RECURSIF) {
-                                       if ($altern != "''") $code .= "\n. $altern";
-                                       if ($avant<>"''" OR $apres<>"''")
-                                         spip_log("boucle $nom toujours vide, code superflu dans $id");
-                                       $avant = $apres = $altern = "''";
-                               } else if ($altern != "''") $altern = "($altern)";
-                       }
-                       break;
-
-               case 'idiome':
-                       $l = array();
-                       $code = '';
-                       foreach ($p->arg as $k => $v) {
-                               $_v = calculer_liste($v, $descr, $boucles, $id_boucle);
-                               if ($k) {
-                                       $l[] = _q($k) . ' => ' . $_v;
+                               break;
+
+                       case 'polyglotte':
+                               $code = "";
+                               foreach ($p->traductions as $k => $v) {
+                                       $code .= ",'" .
+                                               str_replace(array("\\", "'"), array("\\\\", "\\'"), $k) .
+                                               "' => '" .
+                                               str_replace(array("\\", "'"), array("\\\\", "\\'"), $v) .
+                                               "'";
+                               }
+                               $code = "choisir_traduction(array(" .
+                                       substr($code, 1) .
+                                       "))";
+                               $commentaire = '&';
+                               $avant = '';
+                               $apres = '';
+                               $altern = "''";
+                               break;
+
+                       // inclure
+                       case 'include':
+                               $p->descr = $descr;
+                               $code = calculer_inclure($p, $boucles, $id_boucle);
+                               if ($code === false) {
+                                       $err_e_c = true;
+                                       $code = "''";
                                } else {
-                                       $code = $_v;
+                                       $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
+                                       $avant = '';
+                                       $apres = '';
+                                       $altern = "''";
                                }
-                       }
-                       // Si le module n'est pas fourni, l'expliciter sauf si calculĂ©
-                       if ($p->module) {
-                               $m = $p->module .':'.$p->nom_champ;
-                       } elseif ($p->nom_champ) {
-                               $m = MODULES_IDIOMES .':'.$p->nom_champ;
-                       } else {
-                               $m = '';
-                       }
-                       $code = (!$code ? "'$m'" :
+                               break;
+
+                       // boucle
+                       case TYPE_RECURSIF:
+                               $nom = $p->id_boucle;
+                               $newdescr = $descr;
+                               $newdescr['id_mere'] = $nom;
+                               $newdescr['niv']++;
+                               $avant = calculer_liste($p->avant,
+                                       $newdescr, $boucles, $id_boucle);
+                               $apres = calculer_liste($p->apres,
+                                       $newdescr, $boucles, $id_boucle);
+                               $newdescr['niv']--;
+                               $altern = calculer_liste($p->altern,
+                                       $newdescr, $boucles, $id_boucle);
+                               if (($avant === false) or ($apres === false) or ($altern === false)) {
+                                       $err_e_c = true;
+                                       $code = "''";
+                               } else {
+                                       $code = 'BOUCLE' .
+                                               str_replace("-", "_", $nom) . $descr['nom'] .
+                                               '($Cache, $Pile, $doublons, $Numrows, $SP)';
+                                       $commentaire = "?$nom";
+                                       if (!$boucles[$nom]->milieu
+                                               and $boucles[$nom]->type_requete <> TYPE_RECURSIF
+                                       ) {
+                                               if ($altern != "''") {
+                                                       $code .= "\n. $altern";
+                                               }
+                                               if ($avant <> "''" or $apres <> "''") {
+                                                       spip_log("boucle $nom toujours vide, code superflu dans $descr[sourcefile]");
+                                               }
+                                               $avant = $apres = $altern = "''";
+                                       } else {
+                                               if ($altern != "''") {
+                                                       $altern = "($altern)";
+                                               }
+                                       }
+                               }
+                               break;
+
+                       case 'idiome':
+                               $l = array();
+                               $code = '';
+                               foreach ($p->arg as $k => $v) {
+                                       $_v = calculer_liste($v, $descr, $boucles, $id_boucle);
+                                       if ($k) {
+                                               $l[] = _q($k) . ' => ' . $_v;
+                                       } else {
+                                               $code = $_v;
+                                       }
+                               }
+                               // Si le module n'est pas fourni, l'expliciter sauf si calculĂ©
+                               if ($p->module) {
+                                       $m = $p->module . ':' . $p->nom_champ;
+                               } elseif ($p->nom_champ) {
+                                       $m = MODULES_IDIOMES . ':' . $p->nom_champ;
+                               } else {
+                                       $m = '';
+                               }
+
+                               $code = (!$code ? "'$m'" :
                                                ($m ? "'$m' . $code" :
                                                        ("(strpos(\$x=$code, ':') ? \$x : ('" . MODULES_IDIOMES . ":' . \$x))")))
                                        . (!$l ? '' : (", array(" . implode(",\n", $l) . ")"));
-                       $code = "_T($code)";
-                       if ($p->param) {
+                               $code = "_T($code)";
+                               if ($p->param) {
+                                       $p->id_boucle = $id_boucle;
+                                       $p->boucles = &$boucles;
+                                       $code = compose_filtres($p, $code);
+                               }
+                               $commentaire = ":";
+                               $avant = '';
+                               $apres = '';
+                               $altern = "''";
+                               break;
+
+                       case 'champ':
+
+                               // cette structure pourrait etre completee des le phrase' (a faire)
                                $p->id_boucle = $id_boucle;
                                $p->boucles = &$boucles;
-                               $code = compose_filtres($p, $code);
-                       }
-                       $commentaire = ":";
-                       $avant='';
-                       $apres='';
-                       $altern = "''";
-                       break;
-
-               case 'champ':
-
-                       // cette structure pourrait etre completee des le phrase' (a faire)
-                       $p->id_boucle = $id_boucle;
-                       $p->boucles = &$boucles;
-                       $p->descr = $descr;
-                       #$p->interdire_scripts = true;
-                       $p->type_requete = $type;
-
-                       $code = calculer_champ($p);
-                       $commentaire = '#' . $p->nom_champ . $p->etoile;
-                       $avant = calculer_liste($p->avant,
-                               $descr, $boucles, $id_boucle);
-                       $apres = calculer_liste($p->apres,
-                               $descr, $boucles, $id_boucle);
-                       $altern = "''";
-                       // Si la valeur est destinee a une comparaison a ''
-                       // forcer la conversion en une chaine par strval
-                       // si ca peut etre autre chose qu'une chaine
-                       if (($avant != "''" OR $apres != "''")
-                       AND $code[0]!= "'"
+                               $p->descr = $descr;
+                               #$p->interdire_scripts = true;
+                               $p->type_requete = $type;
+
+                               $code = calculer_champ($p);
+                               $commentaire = '#' . $p->nom_champ . $p->etoile;
+                               $avant = calculer_liste($p->avant,
+                                       $descr, $boucles, $id_boucle);
+                               $apres = calculer_liste($p->apres,
+                                       $descr, $boucles, $id_boucle);
+                               $altern = "''";
+                               // Si la valeur est destinee a une comparaison a ''
+                               // forcer la conversion en une chaine par strval
+                               // si ca peut etre autre chose qu'une chaine
+                               if (($avant != "''" or $apres != "''")
+                                       and $code[0] != "'"
 #                      AND (strpos($code,'interdire_scripts') !== 0)
-                       AND !preg_match(_REGEXP_COND_VIDE_NONVIDE, $code)
-                       AND !preg_match(_REGEXP_COND_NONVIDE_VIDE, $code)
-                       AND !preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) 
-                               $code = "strval($code)";
-                       break;
+                                       and !preg_match(_REGEXP_COND_VIDE_NONVIDE, $code)
+                                       and !preg_match(_REGEXP_COND_NONVIDE_VIDE, $code)
+                                       and !preg_match(_REGEXP_CONCAT_NON_VIDE, $code)
+                               ) {
+                                       $code = "strval($code)";
+                               }
+                               break;
 
-               default: 
-                 // Erreur de construction de l'arbre de syntaxe abstraite
-                       $code = "''";
-                       $p->descr = $descr;
-                       $err_e_c = _T('zbug_erreur_compilation');
-                       erreur_squelette($err_e_c, $p);
+                       default:
+                               // Erreur de construction de l'arbre de syntaxe abstraite
+                               $code = "''";
+                               $p->descr = $descr;
+                               $err_e_c = _T('zbug_erreur_compilation');
+                               erreur_squelette($err_e_c, $p);
                } // switch
 
                if ($code != "''") {
                        $code = compile_retour($code, $avant, $apres, $altern, $tab, $descr['niv']);
-                       $codes[]= (($mode == 'validation') ?
+                       $codes[] = (($mode == 'validation') ?
                                "array($code, '$commentaire', " . $p->ligne . ")"
                                : (($mode == 'code') ?
-                               "\n// $commentaire\n$code" :
-                               $code));
+                                       "\n// $commentaire\n$code" :
+                                       $code));
                }
        } // foreach
 
@@ -959,43 +1112,57 @@ function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
 // mais si EXP est de la forme (t ? 'C' : '') on produit (t ? (p . C . s) : a)
 // de meme si EXP est de la forme (t ? '' : 'C')
 
-// http://doc.spip.org/@compile_retour
-function compile_retour($code, $avant, $apres, $altern, $tab, $n)
-{
-       if ($avant == "''") $avant = '';
-       if ($apres == "''") $apres = '';
-       if (!$avant AND !$apres AND ($altern==="''")) return $code;
+// http://code.spip.net/@compile_retour
+function compile_retour($code, $avant, $apres, $altern, $tab, $n) {
+       if ($avant == "''") {
+               $avant = '';
+       }
+       if ($apres == "''") {
+               $apres = '';
+       }
+       if (!$avant and !$apres and ($altern === "''")) {
+               return $code;
+       }
 
        if (preg_match(_REGEXP_CONCAT_NON_VIDE, $code)) {
                $t = $code;
                $cond = '';
-       } elseif (preg_match(_REGEXP_COND_VIDE_NONVIDE,$code, $r)) {
-               $t = $r[2];
-               $cond =  '!' . $r[1];
-       } else if  (preg_match(_REGEXP_COND_NONVIDE_VIDE,$code, $r)) {
+       } elseif (preg_match(_REGEXP_COND_VIDE_NONVIDE, $code, $r)) {
                $t = $r[2];
-               $cond = $r[1];
+               $cond = '!' . $r[1];
        } else {
-               $t = '$t' . $n;
-               $cond = "($t = $code)!==''";
+               if (preg_match(_REGEXP_COND_NONVIDE_VIDE, $code, $r)) {
+                       $t = $r[2];
+                       $cond = $r[1];
+               } else {
+                       $t = '$t' . $n;
+                       $cond = "($t = $code)!==''";
+               }
        }
 
-       $res = (!$avant ? "" : "$avant . ") . 
+       $res = (!$avant ? "" : "$avant . ") .
                $t .
                (!$apres ? "" : " . $apres");
 
-       if ($res !== $t) $res = "($res)";
+       if ($res !== $t) {
+               $res = "($res)";
+       }
+
        return !$cond ? $res : "($cond ?\n\t$tab$res :\n\t$tab$altern)";
 }
 
 
-function compile_inclure_doublons($lexemes)
-{
-       foreach($lexemes as $v)
-         if($v->type === 'include' AND $v->param) 
-           foreach($v->param as $r) 
-             if (trim($r[0]) === 'doublons') 
-               return true;
+function compile_inclure_doublons($lexemes) {
+       foreach ($lexemes as $v) {
+               if ($v->type === 'include' and $v->param) {
+                       foreach ($v->param as $r) {
+                               if (trim($r[0]) === 'doublons') {
+                                       return true;
+                               }
+                       }
+               }
+       }
+
        return false;
 }
 
@@ -1014,8 +1181,8 @@ function compile_inclure_doublons($lexemes)
 // - 'entetes' => tableau des entetes http
 // En cas d'erreur, elle retournera un tableau des 2 premiers elements seulement
 
-// http://doc.spip.org/@public_compiler_dist
-function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect=''){
+// http://code.spip.net/@public_compiler_dist
+function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect = '') {
        // Pre-traitement : reperer le charset du squelette, et le convertir
        // Bonus : supprime le BOM
        include_spip('inc/charsets');
@@ -1023,14 +1190,18 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect='')
 
        // rendre inertes les echappements de #[](){}<>
        $i = 0;
-       while(false !== strpos($squelette, $inerte = '-INERTE'.$i)) $i++;
+       while (false !== strpos($squelette, $inerte = '-INERTE' . $i)) {
+               $i++;
+       }
        $squelette = preg_replace_callback(',\\\\([#[()\]{}<>]),',
                create_function('$a', "return '$inerte-'.ord(\$a[1]).'-';"), $squelette, -1, $esc);
 
-       $descr = array('nom' => $nom,
-                       'gram' => $gram,
-                       'sourcefile' => $sourcefile,
-                       'squelette' => $squelette);
+       $descr = array(
+               'nom' => $nom,
+               'gram' => $gram,
+               'sourcefile' => $sourcefile,
+               'squelette' => $squelette
+       );
 
        // Phraser le squelette, selon sa grammaire
 
@@ -1038,32 +1209,37 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect='')
        $f = charger_fonction('phraser_' . $gram, 'public');
 
        $squelette = $f($squelette, '', $boucles, $descr);
+
        $boucles = compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
 
        // restituer les echappements
-       if ($esc)
-               foreach($boucles as $i=>$boucle) {
+       if ($esc) {
+               foreach ($boucles as $i => $boucle) {
                        $boucles[$i]->return = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return chr($a[1]);'),
                                $boucle->return);
-                       $boucles[$i]->descr['squelette'] = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return "\\\\".chr($a[1]);'),
+                       $boucles[$i]->descr['squelette'] = preg_replace_callback(",$inerte-(\d+)-,",
+                               create_function('$a', 'return "\\\\".chr($a[1]);'),
                                $boucle->descr['squelette']);
                }
-       
-       $debug = ($boucles AND defined('_VAR_MODE') AND _VAR_MODE == 'debug');
+       }
+
+       $debug = ($boucles and defined('_VAR_MODE') and _VAR_MODE == 'debug');
        if ($debug) {
                include_spip('public/decompiler');
-               foreach($boucles as $id => $boucle) {
-                       if ($id)
-                         $decomp = "\n/* BOUCLE " .
-                           $boucle->type_requete .
-                           " " .
-                           str_replace('*/', '* /', public_decompiler($boucle, $gram, 0, 'criteres')) .
-                           " */\n";
-                       else $decomp = ("\n/*\n" . 
-                                str_replace('*/', '* /', public_decompiler($squelette, $gram)) 
-                                . "\n*/");
-                       $boucles[$id]->return = $decomp .$boucle->return; 
-                       $GLOBALS['debug_objets']['code'][$nom.$id] = $boucle->return;
+               foreach ($boucles as $id => $boucle) {
+                       if ($id) {
+                               $decomp = "\n/* BOUCLE " .
+                                       $boucle->type_requete .
+                                       " " .
+                                       str_replace('*/', '* /', public_decompiler($boucle, $gram, 0, 'criteres')) .
+                                       " */\n";
+                       } else {
+                               $decomp = ("\n/*\n" .
+                                       str_replace('*/', '* /', public_decompiler($squelette, $gram))
+                                       . "\n*/");
+                       }
+                       $boucles[$id]->return = $decomp . $boucle->return;
+                       $GLOBALS['debug_objets']['code'][$nom . $id] = $boucle->return;
                }
        }
 
@@ -1073,94 +1249,110 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect='')
 // Point d'entree pour arbre de syntaxe abstraite fourni en premier argument
 // Autres specifications comme ci-dessus
 
-function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect=''){
+function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = '') {
        static $trouver_table;
        spip_timer('calcul_skel');
 
-       if (defined('_VAR_MODE') AND _VAR_MODE == 'debug') {
+       if (defined('_VAR_MODE') and _VAR_MODE == 'debug') {
                $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette'];
                $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile;
 
-               if (!isset($GLOBALS['debug_objets']['principal']))
+               if (!isset($GLOBALS['debug_objets']['principal'])) {
                        $GLOBALS['debug_objets']['principal'] = $nom;
+               }
        }
        foreach ($boucles as $id => $boucle) {
-               $GLOBALS['debug_objets']['boucle'][$nom.$id] = $boucle;
+               $GLOBALS['debug_objets']['boucle'][$nom . $id] = $boucle;
        }
        $descr['documents'] = compile_inclure_doublons($squelette);
 
        // Demander la description des tables une fois pour toutes
-       // et reperer si les doublons sont demandes
-       // pour un inclure ou une boucle document
-       // c'est utile a la fonction champs_traitements
-       if (!$trouver_table)
+       if (!$trouver_table) {
                $trouver_table = charger_fonction('trouver_table', 'base');
+       }
 
-       foreach($boucles as $id => $boucle) {
-               if (!($type = $boucle->type_requete)) continue;
-               if (!$descr['documents'] AND (
-                       (($type == 'documents') AND $boucle->doublons) OR
-                               compile_inclure_doublons($boucle->avant) OR
-                               compile_inclure_doublons($boucle->apres) OR
-                               compile_inclure_doublons($boucle->milieu) OR
-                               compile_inclure_doublons($boucle->altern)))
-                       $descr['documents'] = true;  
+       // reperer si les doublons sont demandes
+       // pour un inclure ou une boucle document
+       // c'est utile a la fonction champs_traitements
+       foreach ($boucles as $id => $boucle) {
+               if (!($type = $boucle->type_requete)) {
+                       continue;
+               }
+               if (!$descr['documents'] and (
+                               (($type == 'documents') and $boucle->doublons) or
+                               compile_inclure_doublons($boucle->avant) or
+                               compile_inclure_doublons($boucle->apres) or
+                               compile_inclure_doublons($boucle->milieu) or
+                               compile_inclure_doublons($boucle->altern))
+               ) {
+                       $descr['documents'] = true;
+               }
                if ($type != TYPE_RECURSIF) {
-                       if (!$boucles[$id]->sql_serveur AND $connect)
+                       if (!$boucles[$id]->sql_serveur and $connect) {
                                $boucles[$id]->sql_serveur = $connect;
+                       }
 
                        // chercher dans les iterateurs du repertoire iterateur/
                        if ($g = charger_fonction(
-                       preg_replace('/\W/', '_', $boucle->type_requete), 'iterateur', true)) {
+                               preg_replace('/\W/', '_', $boucle->type_requete), 'iterateur', true)
+                       ) {
                                $boucles[$id] = $g($boucle);
 
-                       // sinon, en cas de requeteur d'un type predefini,
-                       // utiliser les informations donnees par le requeteur
-                       // cas "php:xx" et "data:xx".
-                       } else if ($boucle->sql_serveur AND $requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) {
-                               $requeteur($boucles, $boucle, $id);
-
-                       // utiliser la description des champs transmis
+                               // sinon, en cas de requeteur d'un type predefini,
+                               // utiliser les informations donnees par le requeteur
+                               // cas "php:xx" et "data:xx".
                        } else {
-                               $show = $trouver_table($type, $boucles[$id]->sql_serveur);
-                               // si la table n'existe pas avec le connecteur par defaut,
-                               // c'est peut etre une table qui necessite son connecteur dedie fourni
-                               // permet une ecriture allegee (GEO) -> (geo:GEO)
-                               if (!$show
-                               AND $show=$trouver_table($type, strtolower($type))) {
-                                       $boucles[$id]->sql_serveur = strtolower($type);
-                               }
-                               if ($show) {
-                                       $boucles[$id]->show = $show;
-                                       // recopie les infos les plus importantes
-                                       $boucles[$id]->primary = $show['key']["PRIMARY KEY"];
-                                       $boucles[$id]->id_table = $x = preg_replace(",^spip_,","",$show['id_table']);
-                                       $boucles[$id]->from[$x] = $nom_table = $show['table'];
-                                       $boucles[$id]->iterateur = 'SQL';
-
-                                       $boucles[$id]->descr = &$descr;
-                                       if ((!$boucles[$id]->jointures)
-                                           AND is_array($show['tables_jointures'])
-                                               AND count($x = $show['tables_jointures']))
-                                               $boucles[$id]->jointures = $x;
-                                       if ($boucles[$id]->jointures_explicites){
-                                               $jointures = preg_split("/\s+/",$boucles[$id]->jointures_explicites);
-                                               while ($j=array_pop($jointures))
-                                                       array_unshift($boucles[$id]->jointures,$j);
-                                       }
+                               if ($boucle->sql_serveur and $requeteur = charger_fonction($boucle->sql_serveur, 'requeteur', true)) {
+                                       $requeteur($boucles, $boucle, $id);
+
+                                       // utiliser la description des champs transmis
                                } else {
-                                       // Pas une erreur si la table est optionnelle
-                                       if ($boucles[$id]->table_optionnelle)
-                                               $boucles[$id]->type_requete = '';
-                                       else  {
-                                               $boucles[$id]->type_requete = false;
-                                               $boucle = $boucles[$id];
-                                               $x = (!$boucle->sql_serveur ? '' :
-                                                       ($boucle->sql_serveur . ":")) .
-                                                    $type;
-                                               $msg = array('zbug_table_inconnue',
-                                                            array('table' => $x));
-                                               erreur_squelette($msg, $boucle);
+                                       $show = $trouver_table($type, $boucles[$id]->sql_serveur);
+                                       // si la table n'existe pas avec le connecteur par defaut,
+                                       // c'est peut etre une table qui necessite son connecteur dedie fourni
+                                       // permet une ecriture allegee (GEO) -> (geo:GEO)
+                                       if (!$show
+                                               and $show = $trouver_table($type, strtolower($type))
+                                       ) {
+                                               $boucles[$id]->sql_serveur = strtolower($type);
+                                       }
+                                       if ($show) {
+                                               $boucles[$id]->show = $show;
+                                               // recopie les infos les plus importantes
+                                               $boucles[$id]->primary = isset($show['key']["PRIMARY KEY"]) ? $show['key']["PRIMARY KEY"] : '';
+                                               $boucles[$id]->id_table = $x = preg_replace(",^spip_,", "", $show['id_table']);
+                                               $boucles[$id]->from[$x] = $nom_table = $show['table'];
+                                               $boucles[$id]->iterateur = 'SQL';
+
+                                               $boucles[$id]->descr = &$descr;
+                                               if ((!$boucles[$id]->jointures)
+                                                       and is_array($show['tables_jointures'])
+                                                       and count($x = $show['tables_jointures'])
+                                               ) {
+                                                       $boucles[$id]->jointures = $x;
+                                               }
+                                               if ($boucles[$id]->jointures_explicites) {
+                                                       $jointures = preg_split("/\s+/", $boucles[$id]->jointures_explicites);
+                                                       while ($j = array_pop($jointures)) {
+                                                               array_unshift($boucles[$id]->jointures, $j);
+                                                       }
+                                               }
+                                       } else {
+                                               // Pas une erreur si la table est optionnelle
+                                               if ($boucles[$id]->table_optionnelle) {
+                                                       $boucles[$id]->type_requete = '';
+                                               } else {
+                                                       $boucles[$id]->type_requete = false;
+                                                       $boucle = $boucles[$id];
+                                                       $x = (!$boucle->sql_serveur ? '' :
+                                                                       ($boucle->sql_serveur . ":")) .
+                                                               $type;
+                                                       $msg = array(
+                                                               'zbug_table_inconnue',
+                                                               array('table' => $x)
+                                                       );
+                                                       erreur_squelette($msg, $boucle);
+                                               }
                                        }
                                }
                        }
@@ -1169,30 +1361,32 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
 
        // Commencer par reperer les boucles appelees explicitement 
        // car elles indexent les arguments de maniere derogatoire
-       foreach($boucles as $id => $boucle) {
-               if ($boucle->type_requete == TYPE_RECURSIF AND $boucle->param) {
+       foreach ($boucles as $id => $boucle) {
+               if ($boucle->type_requete == TYPE_RECURSIF and $boucle->param) {
                        $boucles[$id]->descr = &$descr;
                        $rec = &$boucles[$boucle->param[0]];
                        if (!$rec) {
-                               $msg = array('zbug_boucle_recursive_undef',
-                                       array('nom' => $boucle->param[0]));
+                               $msg = array(
+                                       'zbug_boucle_recursive_undef',
+                                       array('nom' => $boucle->param[0])
+                               );
                                erreur_squelette($msg, $boucle);
                                $boucles[$id]->type_requete = false;
                        } else {
                                $rec->externe = $id;
                                $descr['id_mere'] = $id;
                                $boucles[$id]->return =
-                                               calculer_liste(array($rec),
-                                                        $descr,
-                                                        $boucles,
-                                                        $boucle->param);
+                                       calculer_liste(array($rec),
+                                               $descr,
+                                               $boucles,
+                                               $boucle->param);
                        }
                }
        }
-       foreach($boucles as $id => $boucle) { 
+       foreach ($boucles as $id => $boucle) {
                $id = strval($id); // attention au type dans index_pile
                $type = $boucle->type_requete;
-               if ($type AND $type != TYPE_RECURSIF) {
+               if ($type and $type != TYPE_RECURSIF) {
                        $res = '';
                        if ($boucle->param) {
                                // retourne un tableau en cas d'erreur
@@ -1200,10 +1394,10 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
                        }
                        $descr['id_mere'] = $id;
                        $boucles[$id]->return =
-                         calculer_liste($boucle->milieu,
-                                        $descr,
-                                        $boucles,
-                                        $id);
+                               calculer_liste($boucle->milieu,
+                                       $descr,
+                                       $boucles,
+                                       $id);
                        // Si les criteres se sont mal compiles
                        // ne pas tenter d'assembler le code final
                        // (mais compiler le corps pour detection d'erreurs)
@@ -1218,14 +1412,16 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
        $corps = calculer_liste($squelette, $descr, $boucles);
 
 
-
        // Calcul du corps de toutes les fonctions PHP,
        // en particulier les requetes SQL et TOTAL_BOUCLE
        // de'terminables seulement maintenant
 
-       foreach($boucles as $id => $boucle) {
+       foreach ($boucles as $id => $boucle) {
                $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
-               if ($boucle->return === false) {$corps = false; continue;}
+               if ($boucle->return === false) {
+                       $corps = false;
+                       continue;
+               }
                // appeler la fonction de definition de la boucle
 
                if ($req = $boucle->type_requete) {
@@ -1234,15 +1430,15 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
                        $serveur = strtolower($boucle->sql_serveur);
                        if (
                                // fonction de boucle avec serveur & table
-                               (!$serveur OR
-                                ((!function_exists($f = "boucle_".$serveur."_".$table))
-                                 AND (!function_exists($f = $f."_dist"))
-                                )
+                               (!$serveur or
+                                       ((!function_exists($f = "boucle_" . $serveur . "_" . $table))
+                                               and (!function_exists($f = $f . "_dist"))
+                                       )
                                )
                                // fonction de boucle avec table
-                               AND (!function_exists($f = "boucle_".$table))
-                                       AND (!function_exists($f = $f."_dist"))
-                       ){
+                               and (!function_exists($f = "boucle_" . $table))
+                               and (!function_exists($f = $f . "_dist"))
+                       ) {
                                // fonction de boucle standard 
                                if (!function_exists($f = 'boucle_DEFAUT')) {
                                        $f = 'boucle_DEFAUT_dist';
@@ -1250,15 +1446,17 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
                        }
 
                        $req = "\n\n\tstatic \$command = array();\n\t" .
-                                       "static \$connect;\n\t" .
-                                       "\$command['connect'] = \$connect = " .
+                               "static \$connect;\n\t" .
+                               "\$command['connect'] = \$connect = " .
                                _q($boucle->sql_serveur) .
                                ";" .
                                $f($id, $boucles);
-               } else $req = ("\n\treturn '';");
+               } else {
+                       $req = ("\n\treturn '';");
+               }
 
-               $boucles[$id]->return = 
-                       "\n\nfunction BOUCLE" . strtr($id,"-","_") . $nom .
+               $boucles[$id]->return =
+                       "\n\nfunction BOUCLE" . strtr($id, "-", "_") . $nom .
                        '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
                        $req .
                        "\n}\n";
@@ -1266,25 +1464,27 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
 
        // Au final, si le corps ou un critere au moins s'est mal compile
        // retourner False, sinon inserer leur decompilation
-       if (is_bool($corps)) return false;
+       if (is_bool($corps)) {
+               return false;
+       }
 
-       $principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
+       $principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons = array(), $Numrows = array(), $SP = 0) {
 '
-       // reporter de maniere securisee les doublons inclus
-.'
+               // reporter de maniere securisee les doublons inclus
+               . '
        if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"]))
                $doublons = nettoyer_env_doublons($Pile[0]["doublons"]);
 
        $connect = ' .
-       _q($connect) . ';
+               _q($connect) . ';
        $page = ' .
-       // ATTENTION, le calcul de l'expression $corps affectera $Cache
-       // c'est pourquoi on l'affecte a la variable auxiliaire $page. 
-       // avant de referencer $Cache
-       $corps . ";
+               // ATTENTION, le calcul de l'expression $corps affectera $Cache
+               // c'est pourquoi on l'affecte a la variable auxiliaire $page.
+               // avant de referencer $Cache
+               $corps . ";
 
-       return analyse_resultat_skel(".var_export($nom,true)
-               .", \$Cache, \$page, ".var_export($sourcefile,true).");
+       return analyse_resultat_skel(" . var_export($nom, true)
+               . ", \$Cache, \$page, " . var_export($sourcefile, true) . ");
 }";
 
        $secondes = spip_timer('calcul_skel');
@@ -1297,21 +1497,22 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
        $code->descr = $descr;
        $code->return = '
 //
-// Fonction principale du squelette ' . 
-       $sourcefile . 
-       ($connect ? " pour $connect" : '') . 
-       (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
-       "\n//\n" .
-       $principal;
+// Fonction principale du squelette ' .
+               $sourcefile .
+               ($connect ? " pour $connect" : '') .
+               (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
+               "\n//\n" .
+               $principal;
 
        $boucles[''] = $code;
+
        return $boucles;
 }
 
 
 /**
  * Requeteur pour les boucles (php:nom_iterateur)
- * 
+ *
  * Analyse si le nom d'iterateur correspond bien a une classe PHP existante
  * et dans ce cas charge la boucle avec cet iterateur.
  * Affichera une erreur dans le cas contraire.
@@ -1319,8 +1520,8 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
  * @param $boucles Liste des boucles
  * @param $boucle  La boucle parcourue
  * @param $id      L'identifiant de la boucle parcourue
- * 
-**/
+ *
+ **/
 function requeteur_php_dist(&$boucles, &$boucle, &$id) {
        if (class_exists($boucle->type_requete)) {
                $g = charger_fonction('php', 'iterateur');
@@ -1328,8 +1529,10 @@ function requeteur_php_dist(&$boucles, &$boucle, &$id) {
        } else {
                $x = $boucle->type_requete;
                $boucle->type_requete = false;
-               $msg = array('zbug_iterateur_inconnu',
-                               array('iterateur' => $x));
+               $msg = array(
+                       'zbug_iterateur_inconnu',
+                       array('iterateur' => $x)
+               );
                erreur_squelette($msg, $boucle);
        }
 }
@@ -1338,7 +1541,7 @@ function requeteur_php_dist(&$boucles, &$boucle, &$id) {
 /**
  * Requeteur pour les boucles (data:type de donnee)
  * note: (DATA) tout court ne passe pas par ici.
- * 
+ *
  * Analyse si le type de donnee peut etre traite
  * et dans ce cas charge la boucle avec cet iterateur.
  * Affichera une erreur dans le cas contraire.
@@ -1346,26 +1549,26 @@ function requeteur_php_dist(&$boucles, &$boucle, &$id) {
  * @param $boucles Liste des boucles
  * @param $boucle  La boucle parcourue
  * @param $id      L'identifiant de la boucle parcourue
- * 
-**/
+ *
+ **/
 function requeteur_data_dist(&$boucles, &$boucle, &$id) {
        include_spip('iterateur/data');
-       if ($h = charger_fonction($boucle->type_requete . '_to_array' , 'inc', true)) {
+       if ($h = charger_fonction($boucle->type_requete . '_to_array', 'inc', true)) {
                $g = charger_fonction('data', 'iterateur');
                $boucles[$id] = $g($boucle);
                // from[0] stocke le type de data (rss, yql, ...)
                $boucles[$id]->from[] = $boucle->type_requete;
-               
+
        } else {
                $x = $boucle->type_requete;
                $boucle->type_requete = false;
-               $msg = array('zbug_requeteur_inconnu',
-                               array(
+               $msg = array(
+                       'zbug_requeteur_inconnu',
+                       array(
                                'requeteur' => 'data',
                                'type' => $x
-               ));
+                       )
+               );
                erreur_squelette($msg, $boucle);
        }
 }
-
-?>