function decompiler_idiome($struct, $fmt = '', $prof = 0) { $args = array(); foreach ($struct->arg as $k => $v) { $args[$k] = public_decompiler($v, $fmt, $prof); } $filtres = decompiler_liste($struct->param, $fmt, $prof); $f = 'format_idiome_' . $fmt; return $f($struct->nom_champ, $struct->module, $args, $filtres, $prof); }
function debusquer_source($objet, $affiche) { $quoi = $GLOBALS['debug_objets'][$affiche][$objet]; if (!empty($GLOBALS['debug_objets']['boucle'][$objet]->id_boucle)) { $nom = $GLOBALS['debug_objets']['boucle'][$objet]->id_boucle; } else { $nom = $GLOBALS['debug_objets']['sourcefile'][$objet]; } $res2 = ""; if ($affiche == 'resultat') { $legend = $nom; $req = $GLOBALS['debug_objets']['requete'][$objet]; if (function_exists('_mysql_traite_query')) { $c = strtolower(_request('connect')); $c = $GLOBALS['connexions'][$c ? $c : 0]['prefixe']; $req = _mysql_traite_query($req, '', $c); } // permettre le copier/coller facile // $res = ancre_texte($req, array(), true); $res = "<div id='T" . md5($req) . "'>\n<pre>\n" . $req . "</pre>\n</div>\n"; // formatage et affichage des resultats bruts de la requete $ress_req = spip_query($req); $brut_sql = ''; $num = 1; // eviter l'affichage de milliers de lignes // personnalisation possible dans mes_options $max_aff = defined('_MAX_DEBUG_AFF') ? _MAX_DEBUG_AFF : 50; while ($retours_sql = sql_fetch($ress_req)) { if ($num <= $max_aff) { $brut_sql .= "<h3>" . ($num == 1 ? $num . " sur " . sql_count($ress_req) : $num) . "</h3>"; $brut_sql .= "<p>"; foreach ($retours_sql as $key => $val) { $brut_sql .= "<strong>" . $key . "</strong> => " . spip_htmlspecialchars(couper($val, 150)) . "<br />\n"; } $brut_sql .= "</p>"; } $num++; } $res2 = interdire_scripts($brut_sql); foreach ($quoi as $view) { // ne pas afficher les $contexte_inclus $view = preg_replace(",<\\?php.+\\?[>],Uims", "", $view); if ($view) { $res2 .= "\n<br /><fieldset>" . interdire_scripts($view) . "</fieldset>"; } } } elseif ($affiche == 'code') { $legend = $nom; $res = ancre_texte("<" . "?php\n" . $quoi . "\n?" . ">"); } elseif ($affiche == 'boucle') { $legend = _T('zbug_boucle') . ' ' . $nom; // Le compilateur prefixe le nom des boucles par l'extension du fichier source. $gram = preg_match('/^([^_]+)_/', $objet, $r) ? $r[1] : ''; $res = ancre_texte(public_decompiler($quoi, $gram, 0, 'boucle')); } elseif ($affiche == 'squelette') { $legend = $GLOBALS['debug_objets']['sourcefile'][$objet]; $res = ancre_texte($GLOBALS['debug_objets']['squelette'][$objet]); } return array($legend, $res, $res2); }
function decompiler_liste($sources, $fmt='', $prof=0) { if (!is_array($sources)) return ''; $f = 'format_liste_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES); $res = ''; foreach($sources as $arg) { if (!is_array($arg)) { continue; // ne devrait pas arriver. } else {$r = array_shift($arg);} $args = array(); foreach($arg as $v) { // cas des arguments entoures de ' ou " if ((count($v) == 1) AND $v[0]->type=='texte' AND (strlen($v[0]->apres) == 1) AND $v[0]->apres == $v[0]->avant) $args[]= $v[0]->avant . $v[0]->texte . $v[0]->apres; else $args[]= public_decompiler($v, $fmt, 0-$prof); } if (($r!=='') OR $args) $res .= $f($r, $args, $prof); } return $res; }
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'); $squelette = transcoder_page($squelette); // rendre inertes les echappements de #[](){}<> $i = 0; 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); // Phraser le squelette, selon sa grammaire $boucles = array(); $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) { $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]);'), $boucle->descr['squelette']); } } $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; } } return $boucles; }
function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = ''){ global $tables_jointures; static $trouver_table; spip_timer('calcul_skel'); if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'){ $GLOBALS['debug_objets']['squelette'][$nom] = $descr['squelette']; $GLOBALS['debug_objets']['sourcefile'][$nom] = $sourcefile; if (!isset($GLOBALS['debug_objets']['principal'])) $GLOBALS['debug_objets']['principal'] = $nom; } foreach ($boucles as $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) $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; if ($type!='boucle'){ if (!$boucles[$id]->sql_serveur AND $connect) $boucles[$id]->sql_serveur = $connect; $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 = $show['id_table']; $boucles[$id]->from[$x] = $nom_table = $show['table']; $boucles[$id]->descr = &$descr; if ((!$boucles[$id]->jointures) AND (isset($tables_jointures[$nom_table])) AND is_array($x = $tables_jointures[$nom_table]) ) $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); } } } } // Commencer par reperer les boucles appelees explicitement // car elles indexent les arguments de maniere derogatoire foreach ($boucles as $id => $boucle){ if ($boucle->type_requete=='boucle' 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])); 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); } } } foreach ($boucles as $id => $boucle){ $id = strval($id); // attention au type dans index_pile $type = $boucle->type_requete; if ($type AND $type!='boucle'){ $crit = !$boucle->param ? true : calculer_criteres($id, $boucles); $descr['id_mere'] = $id; $boucles[$id]->return = 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) if (is_array($crit)) $boucles[$id]->type_requete = false; } } // idem pour la racine $descr['id_mere'] = ''; $corps = calculer_liste($squelette, $descr, $boucles); $debug = (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug'); if ($debug){ include_spip('public/decompiler'); include_spip('public/format_' . _EXTENSION_SQUELETTES); } // 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){ $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle); if ($boucle->return===false) continue; // appeler la fonction de definition de la boucle if ($req = $boucle->type_requete){ $f = 'boucle_' . strtoupper($req); // si pas de definition perso, definition spip if (!function_exists($f)) $f = $f . '_dist'; // laquelle a une definition par defaut if (!function_exists($f)) $f = 'boucle_DEFAUT'; if (!function_exists($f)) $f = 'boucle_DEFAUT_dist'; $req = "\n\n\tstatic \$connect = " . _q($boucle->sql_serveur) . ";" . $f($id, $boucles); } else $req = ("\n\treturn '';"); $boucles[$id]->return = "function BOUCLE" . strtr($id, "-", "_") . $nom . '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' . $req . "\n}\n\n"; if ($debug) $GLOBALS['debug_objets']['code'][$nom . $id] = $boucles[$id]->return; } // 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; foreach ($boucles as $id => $boucle){ if ($boucle->return===false) return false; $boucle->return = "\n\n/* BOUCLE " . $boucle->type_requete . " " . (!$debug ? '' : str_replace('*/', '* /', decompiler_criteres($boucle->param, $boucle->criteres))) . " */\n\n " . $boucle->return; } $secondes = spip_timer('calcul_skel'); spip_log("COMPIL ($secondes) [$sourcefile] $nom.php"); // $connect n'est pas sûr : on nettoie $connect = preg_replace(',[^\w],', '', $connect); // Assimiler la fct principale a une boucle anonyme, c'est plus simple $code = new Boucle; $code->descr = $descr; $code->return = ' // // Fonction principale du squelette ' . $sourcefile . ($connect ? " pour $connect" : '') . (!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") . "\n//" . (!$debug ? '' : ("\n/*\n" . str_replace('*/', '* /', public_decompiler($squelette)) . "\n*/")) . " function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) { ' // 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) . '; $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 . "; return analyse_resultat_skel(" . var_export($nom, true) . ", \$Cache, \$page, " . var_export($sourcefile, true) . "); }"; $boucles[''] = $code; return $boucles; }