Exemplo n.º 1
0
function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect = '')
{
    static $trouver_table;
    spip_timer('calcul_skel');
    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'])) {
            $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 != TYPE_RECURSIF) {
            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)) {
                $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
                } 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 = 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);
                        }
                    }
                }
            }
        }
    }
    // 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) {
            $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 != TYPE_RECURSIF) {
            $res = '';
            if ($boucle->param) {
                // retourne un tableau en cas d'erreur
                $res = 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($res)) {
                $boucles[$id]->type_requete = false;
            }
        }
    }
    // idem pour la racine
    $descr['id_mere'] = '';
    $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) {
        $boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
        if ($boucle->return === false) {
            $corps = false;
            continue;
        }
        // appeler la fonction de definition de la boucle
        if ($req = $boucle->type_requete) {
            // boucle personnalisée ?
            $table = strtoupper($boucle->type_requete);
            $serveur = strtolower($boucle->sql_serveur);
            if ((!$serveur or !function_exists($f = "boucle_" . $serveur . "_" . $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';
                }
            }
            $req = "\n\n\tstatic \$command = array();\n\t" . "static \$connect;\n\t" . "\$command['connect'] = \$connect = " . _q($boucle->sql_serveur) . ";" . $f($id, $boucles);
        } else {
            $req = "\n\treturn '';";
        }
        $boucles[$id]->return = "\n\nfunction BOUCLE" . strtr($id, "-", "_") . $nom . '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' . $req . "\n}\n";
    }
    // 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;
    }
    $principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
' . '
	if (isset($Pile[0]["doublons"]) AND is_array($Pile[0]["doublons"]))
		$doublons = nettoyer_env_doublons($Pile[0]["doublons"]);

	$connect = ' . _q($connect) . ';
	$page = ' . $corps . ";\n\n\treturn analyse_resultat_skel(" . var_export($nom, true) . ", \$Cache, \$page, " . var_export($sourcefile, true) . ");\n}";
    $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, pour retourner un resultat 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//\n" . $principal;
    $boucles[''] = $code;
    return $boucles;
}
Exemplo n.º 2
0
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;
}