/** * Composer le code d'inclusion PHP * * @param string $fichier * @param Object $p * @return string */ function sandbox_composer_inclure_php($fichier, &$p) { $compil = texte_script(memoriser_contexte_compil($p)); // si inexistant, on essaiera a l'execution if ($path = find_in_path($fichier)) { $path = "\"{$path}\""; } else { $path = "find_in_path(\"{$fichier}\")"; } return sprintf(CODE_INCLURE_SCRIPT, $path, $fichier, $compil); }
/** * Compilation d'une boucle (non recursive). * * @param string $id_boucle * Identifiant de la boucle * @param array $boucles * 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 * @return string * 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; $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) { $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' . 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')))) { // Memoriser la langue avant la boucle et la restituer apres // afin que le corps de boucle affecte la globale directement $init_lang = "lang_select(\$GLOBALS['spip_lang']);\n\t"; $fin_lang = "lang_select();\n\t"; $fin_lang_select_public = "\n\t\tlang_select();"; $corps .= "\n\t\tlang_select_public(" . index_pile($id_boucle, 'lang', $boucles) . ", '" . $boucle->lang_select . "'" . (in_array($type_boucle, array('articles', 'rubriques', 'hierarchie', 'breves')) ? ', ' . index_pile($id_boucle, 'titre', $boucles) : '') . ');'; } 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)) { $i = 1; foreach ($r[1] as $t) { $init_lang .= "\n\t\$l{$i} = {$t};"; $return = str_replace($t, "\$l{$i}", $return); $i++; } } } // gestion optimale des separateurs et des boucles constantes if (count($boucle->separateur)) { $code_sep = "'" . str_replace("'", "\\'", join('', $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;"; // Calculer les invalideurs si c'est une boucle non constante et si on // souhaite invalider ces elements if (!$constant and $primary) { include_spip('inc/invalideur'); 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) { $corps = "\n\t\t\$Numrows['{$id_boucle}']['compteur_boucle']++;" . $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) { return "\n\t\$t0 = '';"; } 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\t}"; } $count = ''; if (!$boucle->select) { if (!$boucle->numrows or $boucle->limit or $boucle->mode_partie or $boucle->group) { $count = '1'; } else { $count = 'count(*)'; } $boucles[$id_boucle]->select[] = $count; } if ($flag_cpt) { $nums = "\n\t// COMPTEUR\n\t" . "\$Numrows['{$id_boucle}']['compteur_boucle'] = 0;\n\t"; } else { $nums = ''; } if ($boucle->numrows or $boucle->mode_partie) { $nums .= "\$Numrows['{$id_boucle}']['total'] = @intval(\$iter->count());" . $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]); $contexte = memoriser_contexte_compil($boucle); $a = sprintf(CODE_CORPS_BOUCLE, $init, $boucle->iterateur, "\$command", $contexte, $nums, $init_lang, $corps, $fin_lang, $trace, 'BOUCLE' . $id_boucle . ' @ ' . $boucle->descr['sourcefile']); # var_dump($a);exit; return $a; }
/** * Compile la balise `#MODELE` qui inclut un résultat de squelette de modèle * * `#MODELE{nom}` insère le résultat d’un squelette contenu dans le * répertoire `modeles/`. L’identifiant de la boucle parente est transmis * par défaut avec le paramètre `id` à cette inclusion. * * Des arguments supplémentaires peuvent être transmis : * `[(#MODELE{nom, argument=xx, argument})]` * * @balise * @see balise_INCLURE_dist() * @example * ``` * #MODELE{article_traductions} * ``` * * @param Champ $p * Pile au niveau de la balise * @return Champ * Pile complétée par le code à générer **/ function balise_MODELE_dist($p) { $_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false); // erreur de syntaxe = fond absent // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP if (!$_contexte) { $contexte = array(); } if (!isset($_contexte[1])) { $msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE')); erreur_squelette($msg, $p); } else { $nom = $_contexte[1]; unset($_contexte[1]); if (preg_match("/^\\s*'[^']*'/s", $nom)) { $nom = "'modeles/" . substr($nom, 1); } else { $nom = "'modeles/' . {$nom}"; } $flag_env = false; if (isset($_contexte['env'])) { $flag_env = true; unset($_contexte['env']); } // Incoherence dans la syntaxe du contexte. A revoir. // Reserver la cle primaire de la boucle courante si elle existe if (isset($p->boucles[$p->id_boucle]->primary)) { $primary = $p->boucles[$p->id_boucle]->primary; if (!strpos($primary, ',')) { $id = champ_sql($primary, $p); $_contexte[] = "'{$primary}'=>" . $id; $_contexte[] = "'id'=>" . $id; } } $_contexte[] = "'recurs'=>(++\$recurs)"; $connect = ''; if (isset($p->boucles[$p->id_boucle])) { $connect = $p->boucles[$p->id_boucle]->sql_serveur; } $_options = memoriser_contexte_compil($p); $_options = "'compil'=>array({$_options}), 'trim'=>true"; if (isset($_contexte['ajax'])) { $_options .= ", " . preg_replace(",=>(.*)\$,ims", '=> ($v=(\\1))?$v:true', $_contexte['ajax']); unset($_contexte['ajax']); } $_l = 'array(' . join(",\n\t", $_contexte) . ')'; if ($flag_env) { $_l = "array_merge(\$Pile[0],{$_l})"; } $page = sprintf(CODE_RECUPERER_FOND, $nom, $_l, $_options, _q($connect)); $p->code = "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t{$page})\n"; $p->interdire_scripts = false; // securite assuree par le squelette } return $p; }
function calculer_balise_dynamique($p, $nom, $l, $supp=array()) { if (!balise_distante_interdite($p)) { $p->code = "''"; return $p; } // compatibilite: depuis qu'on accepte #BALISE{ses_args} sans [(...)] autour // il faut recracher {...} quand ce n'est finalement pas des args if ($p->fonctions AND (!$p->fonctions[0][0]) AND $p->fonctions[0][1]) { $p->fonctions = null; } if ($p->param AND ($c = $p->param[0])) { // liste d'arguments commence toujours par la chaine vide array_shift($c); // construire la liste d'arguments comme pour un filtre $param = compose_filtres_args($p, $c, ','); } else $param = ""; $collecte = collecter_balise_dynamique($l, $p, $nom); $p->code = sprintf(CODE_EXECUTER_BALISE, $nom, join(',', $collecte), ($collecte ? $param : substr($param,1)), # virer la virgule memoriser_contexte_compil($p), (!$supp ? '' : (', ' . join(',', $supp)))); $p->interdire_scripts = false; return $p; }
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; $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) $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' . 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' ))) ){ // Memoriser la langue avant la boucle et la restituer apres // afin que le corps de boucle affecte la globale directement $init_lang = "lang_select(\$GLOBALS['spip_lang']);\n\t"; $fin_lang = "lang_select();\n\t"; $corps .= "\n\t\tlang_select_public(" . index_pile($id_boucle, 'lang', $boucles) . ", '" . $boucle->lang_select . "'" . (in_array($type_boucle, array( 'articles', 'rubriques', 'hierarchie', 'breves' )) ? ', ' . index_pile($id_boucle, 'titre', $boucles) : '') . ');'; } else { $init_lang = ''; $fin_lang = ''; // sortir les appels au traducteur (invariants de boucle) if (strpos($return, '?php')===false AND preg_match_all("/\W(_T[(]'[^']*'[)])/", $return, $r) ){ $i = 1; foreach ($r[1] as $t){ $init_lang .= "\n\t\$l$i = $t;"; $return = str_replace($t, "\$l$i", $return); $i++; } } } // gestion optimale des separateurs et des boucles constantes if (count($boucle->separateur)) $code_sep = ("'" . str_replace("'", "\'", join('', $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 .= (($t1 && $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){ include_spip('inc/invalideur'); 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) $corps = "\n\t\t\$Numrows['$id_boucle']['compteur_boucle']++;" . $boucle->partie . $corps; $serveur = !$boucle->sql_serveur ? '' : (', ' . _q($boucle->sql_serveur)); // 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) return "\n\t\$t0 = '';"; else $corps = ""; } else { $boucle->numrows = true; $corps = "\n\t\$t0 = str_repeat($corps, \$Numrows['$id_boucle']['total']);"; } } else $corps = "while (\$Pile[\$SP] = @sql_fetch(\$result$serveur)) {\n$corps\n }"; $count = ''; if (!$boucle->select){ if (!$boucle->numrows OR $boucle->limit OR $boucle_mode_partie OR $boucle->group) $count = '1'; else $count = 'count(*)'; $boucles[$id_boucle]->select[] = $count; } if ($flag_cpt) $nums = "\n\t// COMPTEUR\n\t" . "\$Numrows['$id_boucle']['compteur_boucle'] = 0;\n\t"; else $nums = ''; if ($boucle->numrows OR $boucle->mode_partie){ if ($count=='count(*)') $count = "(\$cc=sql_fetch(\$result$serveur))?array_shift(\$cc):0"; else $count = "sql_count(\$result$serveur)"; $nums .= "\$Numrows['$id_boucle']['total'] = @intval($count);" . $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]); $contexte = memoriser_contexte_compil($boucle); return sprintf(CODE_CORPS_BOUCLE, $init, $contexte, $nums, $init_lang, $corps, $fin_lang, $serveur, $trace); }
function balise_MODELE_dist($p) { $_contexte = argumenter_inclure($p->param, true, $p, $p->boucles, $p->id_boucle, false); // erreur de syntaxe = fond absent // (2 messages d'erreur SPIP pour le prix d'un, mais pas d'erreur PHP if (!$_contexte) $contexte = array(); if (!isset($_contexte[1])) { $msg = array('zbug_balise_sans_argument', array('balise' => ' MODELE')); erreur_squelette($msg, $p); } else { $nom = $_contexte[1]; unset($_contexte[1]); if (preg_match("/^\s*'[^']*'/s", $nom)) $nom = "'modeles/" . substr($nom,1); else $nom = "'modeles/' . $nom"; // Incoherence dans la syntaxe du contexte. A revoir. // Reserver la cle primaire de la boucle courante si elle existe if (isset($p->boucles[$p->id_boucle]->primary)) { $primary = $p->boucles[$p->id_boucle]->primary; if (!strpos($primary,',')) { $id = champ_sql($primary, $p); $_contexte[] = "'$primary'=>".$id; $_contexte[] = "'id'=>".$id; } } $_contexte[] = "'recurs'=>(++\$recurs)"; $connect = ''; if (isset($p->boucles[$p->id_boucle])) $connect = $p->boucles[$p->id_boucle]->sql_serveur; $_options = memoriser_contexte_compil($p); $_options = "'compil'=>array($_options), 'trim'=>true" . (isset($_contexte['ajax'])?", 'ajax'=>true":''); $page = sprintf(CODE_RECUPERER_FOND, $nom, 'array(' . join(',', $_contexte) .')', $_options, _q($connect)); $p->code = "\n\t(((\$recurs=(isset(\$Pile[0]['recurs'])?\$Pile[0]['recurs']:0))>=5)? '' :\n\t$page)\n"; $p->interdire_scripts = false; // securite assuree par le squelette } return $p; }