squellete2
[aidenligne_francais_universite.git] / ecrire / public / compiler.php
CommitLineData
c495c100
P
1<?php
2
3/***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2007 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11\***************************************************************************/
12
13
14//
15// Fichier principal du compilateur de squelettes
16//
17
18if (!defined("_ECRIRE_INC_VERSION")) return;
19
20// reperer un code ne calculant rien, meme avec commentaire
21define('CODE_MONOTONE', ",^(\n//[^\n]*\n)?\(?'([^'])*'\)?$,");
22
23// Definition de la structure $p, et fonctions de recherche et de reservation
24// dans l'arborescence des boucles
25include_spip('public/references');
26
27// definition des boucles
28include_spip('public/boucles');
29
30// definition des criteres
31include_spip('public/criteres');
32
33// definition des balises
34include_spip('public/balises');
35
36// definition de l'API
37include_spip('public/interfaces');
38
39# definition des tables
40include_spip('base/serial');
41
42// http://doc.spip.org/@argumenter_inclure
43function argumenter_inclure($struct, $descr, &$boucles, $id_boucle, $echap=true){
44 $l = array();
45 $lang = '';
46 foreach($struct->param as $val) {
47 $var = array_shift($val);
48 if ($var == 'lang')
49 $lang = $val;
50 else
51 $l[$var] = ($echap?"\'$var\' => ' . argumenter_squelette(":"'$var' => ") .
52 ($val
53 ? calculer_liste($val[0], $descr, $boucles, $id_boucle)
54 : index_pile($id_boucle, $var, $boucles)
55 ) . ($echap?") . '":" ");
56 }
57 // Cas particulier de la langue : si {lang=xx} est definie, on
58 // la passe, sinon on passe la langue courante au moment du calcul
59 $l['lang'] = ($echap?"\'lang\' => ' . argumenter_squelette(":"'lang' => ") .
60 ($lang
61 ? calculer_liste($lang[0], $descr, $boucles, $id_boucle)
62 : '$GLOBALS["spip_lang"]'
63 ) . ($echap?") . '":" ");
64 return $l;
65}
66
67//
68// Calculer un <INCLURE()>
69//
70// http://doc.spip.org/@calculer_inclure
71function calculer_inclure($struct, $descr, &$boucles, $id_boucle) {
72
73 # Si pas raccourci <INCLURE{fond=xxx}>
74 # chercher le fichier, eventuellement en changeant.php3 => .php
75 # et en gardant la compatibilite <INCLURE(page.php3)>
76 if ($fichier = $struct->texte) {
77 if (preg_match(',^(.*[.]php)3?$,', $fichier, $r)) {
78 $fichier = $r[1];
79 }
80 if ($fichier == 'page.php') {
81 $fichier = '';
82 } else {
83 if (!$path = find_in_path($fichier))
84 $path = find_in_path($fichier.'3');
85 if (!$path) {
86 spip_log("ERREUR: <INCLURE($fichier)> impossible");
87 erreur_squelette(_T('zbug_info_erreur_squelette'),
88 "&lt;INCLURE($fichier)&gt; - "
89 ._T('fichier_introuvable', array('fichier' => $fichier)));
90 return "'<!-- Erreur INCLURE(".texte_script($fichier).") -->'";
91 }
92 }
93 }
94
95 return "\n'<".
96 "?php\n\t\$contexte_inclus = array(" .
97 join(",\n\t", argumenter_inclure($struct, $descr, $boucles, $id_boucle)) .
98 ");" .
99 "\n\tinclude(" .
100 ($fichier ? "\\'$path\\'" : ('_DIR_RESTREINT . "public.php"')).
101 ");" .
102 "\n?'." . "'>'";
103 }
104
105//
106// calculer_boucle() produit le corps PHP d'une boucle Spip.
107// ce corps remplit une variable $t0 retournee en valeur.
108// Ici on distingue boucles recursives et boucle a requete SQL
109// et on insere le code d'envoi au debusqueur du resultat de la fonction.
110
111// http://doc.spip.org/@calculer_boucle
112function calculer_boucle($id_boucle, &$boucles) {
113
114 if ($boucles[$id_boucle]->type_requete == 'boucle') {
115 $corps = calculer_boucle_rec($id_boucle, $boucles);
116 $req = "";
117 } else {
118 $corps = calculer_boucle_nonrec($id_boucle, $boucles);
119 // attention, ne calculer la requete que maintenant
120 // car la fonction precedente appelle index_pile qui influe dessus
121 $req = (($init = $boucles[$id_boucle]->doublons) ?
122 ("\n\t$init = array();") : '') .
123 calculer_requete_sql($boucles[$id_boucle]);
124 }
125 $notrace = isset($GLOBALS['var_mode_affiche']) ? ($GLOBALS['var_mode_affiche'] != 'resultat') : true;
126 return $req . $corps
127 . ($notrace ? "" : "
128 boucle_debug_resultat('$id_boucle', 'resultat', \$t0);")
129 . "\n return \$t0;";
130}
131
132// compil d'une boucle recursive.
133// il suffit (ET IL FAUT) sauvegarder les valeurs des arguments passes par
134// reference, car par definition un tel passage ne les sauvegarde pas
135
136// http://doc.spip.org/@calculer_boucle_rec
137function calculer_boucle_rec($id_boucle, &$boucles) {
138 $nom = $boucles[$id_boucle]->param[0];
139 return "\n\t\$save_numrows = (\$Numrows['$nom']);"
140 . "\n\t\$t0 = " . $boucles[$id_boucle]->return . ";"
141 . "\n\t\$Numrows['$nom'] = (\$save_numrows);";
142}
143
144// compil d'une boucle non recursive.
145// c'est un "while (fetch_sql)" dans le cas général,
146// qu'on essaye d'optimiser un max.
147
148// http://doc.spip.org/@calculer_boucle_nonrec
149function calculer_boucle_nonrec($id_boucle, &$boucles) {
150
151 $boucle = &$boucles[$id_boucle];
152 $return = $boucle->return;
153 $type_boucle = $boucle->type_requete;
154 $primary = $boucle->primary;
155 $constant = preg_match(CODE_MONOTONE,$return);
156
157 // Cas {1/3} {1,4} {n-2,1}...
158
159 $flag_cpt = $boucle->mode_partie ||$boucle->cptrows;
160
161 //
162 // Creer le debut du corps de la boucle :
163 //
164 $corps = !$flag_cpt ? '' : "\n \$Numrows['$id_boucle']['compteur_boucle']++;";
165
166 if ($boucle->mode_partie)
167 $corps .= "
168 if (\$Numrows['$id_boucle']['compteur_boucle']-1 >= \$debut_boucle) {
169 if (\$Numrows['$id_boucle']['compteur_boucle']-1 > \$fin_boucle) break;\n";
170
171 // Calculer les invalideurs si c'est une boucle non constante et si on
172 // souhaite invalider ces elements
173 if (!$constant AND $primary) {
174 include_spip('inc/invalideur');
175 if (function_exists($i = 'calcul_invalideurs'))
176 $corps = $i($corps, $primary, $boucles, $id_boucle);
177 }
178
179 // faudrait expanser le foreach a la compil, car y en a souvent qu'un
180 // et puis faire un [] plutot qu'un "','."
181 if ($boucle->doublons)
182 $corps .= "\n\t\t\tforeach(" . $boucle->doublons . ' as $k) $doublons[$k] .= "," . ' .
183 index_pile($id_boucle, $primary, $boucles)
184 . "; // doublons\n";
185
186
187 if (count($boucle->separateur))
188 $code_sep = ("'" . str_replace("'","\'",join('',$boucle->separateur)) . "'");
189
190 // La boucle doit-elle selectionner la langue ?
191 // -. par defaut, les boucles suivantes le font
192 // "peut-etre", c'est-a-dire si forcer_lang == false.
193 // - . a moins d'une demande explicite
194 if (!$constant && $boucle->lang_select != 'non' &&
195 (($boucle->lang_select == 'oui') ||
196 (
197 $type_boucle == 'articles'
198 OR $type_boucle == 'rubriques'
199 OR $type_boucle == 'hierarchie'
200 OR $type_boucle == 'breves'
201 )))
202 {
203 $corps .=
204 (($boucle->lang_select != 'oui') ?
205 "\t\tif (!\$GLOBALS['forcer_lang'])\n\t " : '')
206 . "\t\t\$GLOBALS['spip_lang'] = (\$x = "
207 . index_pile($id_boucle, 'lang', $boucles)
208 . ') ? $x : $old_lang;';
209 // Memoriser la langue avant la boucle pour la restituer apres
210 $init = "\n \$old_lang = \$GLOBALS['spip_lang'];";
211 $fin = "\n \$GLOBALS['spip_lang'] = \$old_lang;";
212
213 }
214 else {
215 $init = '';
216 $fin = '';
217 }
218
219 // gestion optimale des separateurs et des boucles constantes
220 $corps .=
221 ((!$boucle->separateur) ?
222 (($constant && !$corps) ? $return :
223 ("\n\t\t" . '$t0 .= ' . $return . ";")) :
224 ("\n\t\t\$t1 " .
225 ((strpos($return, '$t1.') === 0) ?
226 (".=" . substr($return,4)) :
227 ('= ' . $return)) .
228 ";\n\t\t" .
229 '$t0 .= (($t1 && $t0) ? ' . $code_sep . " : '') . \$t1;"));
230
231 // Fin de parties
232 if ($boucle->mode_partie) $corps .= "\n }\n";
233
234
235 // si le corps est une constante, ne pas appeler le serveur N fois!
236 if (preg_match(CODE_MONOTONE,$corps, $r)) {
237 if (!$r[2]) {
238 if (!$boucle->numrows)
239 return 'return "";';
240 else
241 $corps = "";
242 } else {
243 $boucle->numrows = true;
244 $corps = "\n ".'for($x=$Numrows["'.$id_boucle.'"]["total"];$x>0;$x--)
245 $t0 .= ' . $corps .';';
246 }
247 } else {
248
249 $corps = $init . '
250
251 // RESULTATS
252 while ($Pile[$SP] = @spip_abstract_fetch($result,"' .
253 $boucle->sql_serveur .
254 '")) {' .
255 "\n$corps\n }\n" .
256 $fin ;
257 }
258
259 return ($boucle->mode_partie ?
260 calculer_parties($boucles, $id_boucle) :
261 (!$boucle->numrows ? '' :
262 ( "\n \$Numrows['" .
263 $id_boucle .
264 "']['total'] = @spip_abstract_count(\$result,'" .
265 $boucle->sql_serveur .
266 "');"))) .
267 (!$flag_cpt ? "" :
268 "\n \$Numrows['$id_boucle']['compteur_boucle'] = 0;")
269 . '
270 $t0 = "";
271 $SP++;'
272 .
273 $corps .
274 "\n @spip_abstract_free(\$result,'" .
275 $boucle->sql_serveur . "');";
276}
277
278
279// http://doc.spip.org/@calculer_requete_sql
280function calculer_requete_sql(&$boucle)
281{
282 if (!$order = $boucle->order
283 AND !$order = $boucle->default_order)
284 $order = array();
285
286 return ($boucle->hierarchie ? "\n\t$boucle->hierarchie" : '')
287 . $boucle->in
288 . $boucle->hash .
289 "\n\n // REQUETE
290 \$result = spip_optim_select(\n\t\tarray(\"" .
291 # En absence de champ c'est un decompte :
292 # prendre une constante pour avoir qqch
293 (!$boucle->select ? 1 :
294 join("\",\n\t\t\"", $boucle->select)) .
295 '"), # SELECT
296 ' . calculer_from($boucle) .
297 ', # FROM
298 ' . calculer_dump_array($boucle->where) .
299 ', # WHERE
300 ' . calculer_dump_join($boucle->join)
301 . ', # WHERE pour jointure
302 ' . (!$boucle->group ? "''" :
303 ('"' . join(", ", $boucle->group)) . '"') .
304 ', # GROUP
305 array(' .
306 join(', ', $order) .
307 "), # ORDER
308 " . (strpos($boucle->limit, 'intval') === false ?
309 "'".$boucle->limit."'" :
310 $boucle->limit). ", # LIMIT
311 '".$boucle->sous_requete. "', # sous
312 " . calculer_dump_array($boucle->having) . ", # HAVING
313 '".$boucle->id_table."', # table
314 '".$boucle->id_boucle."', # boucle
315 '".$boucle->sql_serveur."'); # serveur";
316}
317
318
319// http://doc.spip.org/@calculer_dump_array
320function calculer_dump_array($a)
321{
322 if (!is_array($a)) return $a ;
323 $res = "";
324 if ($a AND $a[0] == "'?'")
325 return ("(" . calculer_dump_array($a[1]) .
326 " ? " . calculer_dump_array($a[2]) .
327 " : " . calculer_dump_array($a[3]) .
328 ")");
329 else {
330 foreach($a as $k => $v) $res .= ", " . calculer_dump_array($v);
331 return "\n\t\t\tarray(" . substr($res,2) . ')';
332 }
333}
334
335// http://doc.spip.org/@calculer_dump_join
336function calculer_dump_join($a)
337{
338 $res = "";
339 foreach($a as $k => $v) $res .= ", $k => array('$v[0]', '$v[1]')";
340 return 'array(' . substr($res,2) . ')';
341}
342
343// http://doc.spip.org/@calculer_from
344function calculer_from(&$boucle)
345{
346 $res = "";
347 foreach($boucle->from as $k => $v) $res .= ",'$k' => '$v'";
348 return 'array(' . substr($res,1) . ')';
349}
350
351//
352// fonction traitant les criteres {1,n} (analyses dans inc-criteres)
353//
354## a deplacer dans inc-criteres ??
355// http://doc.spip.org/@calculer_parties
356function calculer_parties($boucles, $id_boucle) {
357
358 $boucle = &$boucles[$id_boucle];
359 $partie = $boucle->partie;
360 $mode_partie = $boucle->mode_partie;
361 $total_parties = $boucle->total_parties;
362
363 // Notes :
364 // $debut_boucle et $fin_boucle sont les indices SQL du premier
365 // et du dernier demandes dans la boucle : 0 pour le premier,
366 // n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
367
368 // nombre total avant partition
369 $retour = "\n\n // Partition\n " .
370 '$nombre_boucle = @spip_abstract_count($result,"' .
371 $boucle->sql_serveur .
372 '");';
373
374 preg_match(",([+-/p])([+-/])?,", $mode_partie, $regs);
375 list(,$op1,$op2) = $regs;
376
377 // {1/3}
378 if ($op1 == '/') {
379 $pmoins1 = is_numeric($partie) ? ($partie-1) : "($partie-1)";
380 $totpos = is_numeric($total_parties) ? ($total_parties) :
381 "($total_parties ? $total_parties : 1)";
382 $retour .= "\n "
383 .'$debut_boucle = ceil(($nombre_boucle * '
384 . $pmoins1 . ')/' . $totpos . ");";
385 $fin = 'ceil (($nombre_boucle * '
386 . $partie . ')/' . $totpos . ") - 1";
387 }
388
389 // {1,x}
390 elseif ($op1 == '+') {
391 $retour .= "\n "
392 . '$debut_boucle = ' . $partie . ';';
393 }
394 // {n-1,x}
395 elseif ($op1 == '-') {
396 $retour .= "\n "
397 . '$debut_boucle = $nombre_boucle - ' . $partie . ';';
398 }
399 // {pagination}
400 elseif ($op1 == 'p') {
401 $retour .= "\n "
402 . '$debut_boucle = ' . $partie . ';';
403 }
404
405 // {x,1}
406 if ($op2 == '+') {
407 $fin = '$debut_boucle'
408 . (is_numeric($total_parties) ?
409 (($total_parties==1) ? "" :(' + ' . ($total_parties-1))):
410 ('+' . $total_parties . ' - 1'));
411 }
412 // {x,n-1}
413 elseif ($op2 == '-') {
414 $fin = '$debut_boucle + $nombre_boucle - '
415 . (is_numeric($total_parties) ? ($total_parties+1) :
416 ($total_parties . ' - 1'));
417 }
418
419 // Rabattre $fin_boucle sur le maximum
420 $retour .= "\n "
421 .'$fin_boucle = min(' . $fin . ', $nombre_boucle - 1);';
422
423 // calcul du total boucle final
424 $retour .= "\n "
425 .'$Numrows[\''.$id_boucle.'\']["grand_total"] = $nombre_boucle;'
426 . "\n "
427 .'$Numrows[\''.$id_boucle.'\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);';
428
429 return $retour;
430}
431
432// Production du code PHP a partir de la sequence livree par le phraseur
433// $boucles est passe par reference pour affectation par index_pile.
434// Retourne une expression PHP,
435// (qui sera argument d'un Return ou la partie droite d'une affectation).
436
437// http://doc.spip.org/@calculer_liste
438function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') {
439 if (!$tableau) return "''";
440 if (!isset($descr['niv'])) $descr['niv'] = 0;
441 $codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
442 $n = count($codes);
443 if (!$n) return "''";
444 $tab = str_repeat("\t", $descr['niv']);
445 if (!isset($GLOBALS['var_mode_affiche'])
446 OR $GLOBALS['var_mode_affiche'] != 'validation')
447 return
448 (($n==1) ? $codes[0] :
449 "(" . join (" .\n$tab", $codes) . ")");
450 else return "@debug_sequence('$id_boucle', '" .
451 ($descr['nom']) .
452 "', " .
453 $descr['niv'] .
454 ", array(" .
455 join(" ,\n$tab", $codes) . "))";
456}
457
458// http://doc.spip.org/@compile_cas
459function compile_cas($tableau, $descr, &$boucles, $id_boucle) {
460 $codes = array();
461 // cas de la boucle recursive
462 if (is_array($id_boucle))
463 $id_boucle = $id_boucle[0];
464 $type = !$id_boucle ? '' : $boucles[$id_boucle]->type_requete;
465 $tab = str_repeat("\t", ++$descr['niv']);
466 $mode = isset($GLOBALS['var_mode_affiche']) ? $GLOBALS['var_mode_affiche'] : '';
467 // chaque commentaire introduit dans le code doit commencer
468 // par un caractere distinguant le cas, pour exploitation par debug.
469 foreach ($tableau as $p) {
470
471 switch($p->type) {
472 // texte seul
473 case 'texte':
474 $code = "'".str_replace(array("\\","'"),array("\\\\","\\'"), $p->texte)."'";
475
476 $commentaire= strlen($p->texte) . " signes";
477 $avant='';
478 $apres='';
479 $altern = "''";
480 break;
481
482 case 'polyglotte':
483 $code = "";
484 foreach($p->traductions as $k => $v) {
485 $code .= ",'" .
486 str_replace(array("\\","'"),array("\\\\","\\'"), $k) .
487 "' => '" .
488 str_replace(array("\\","'"),array("\\\\","\\'"), $v) .
489 "'";
490 }
491 $code = "multi_trad(array(" .
492 substr($code,1) .
493 "))";
494 $commentaire= '&';
495 $avant='';
496 $apres='';
497 $altern = "''";
498 break;
499
500 // inclure
501 case 'include':
502 $code = calculer_inclure($p, $descr, $boucles, $id_boucle);
503
504 $commentaire = '<INCLURE ' . addslashes(str_replace("\n", ' ', $code)) . '>';
505 $avant='';
506 $apres='';
507 $altern = "''";
508 break;
509
510 // boucle
511 case 'boucle':
512 $nom = $p->id_boucle;
513 $newdescr = $descr;
514 $newdescr['id_mere'] = $nom;
515 $newdescr['niv']++;
516 $code = 'BOUCLE' .
517 str_replace("-","_", $nom) . $descr['nom'] .
518 '($Cache, $Pile, $doublons, $Numrows, $SP)';
519 $commentaire= "?$nom";
520 $avant = calculer_liste($p->avant,
521 $newdescr, $boucles, $id_boucle);
522 $apres = calculer_liste($p->apres,
523 $newdescr, $boucles, $id_boucle);
524 $newdescr['niv']--;
525 $altern = calculer_liste($p->altern,
526 $newdescr, $boucles, $id_boucle);
527 break;
528
529 case 'idiome':
530 $code = "_T('" . $p->module . ":" .$p->nom_champ . "')";
531 if ($p->param) {
532 $p->id_boucle = $id_boucle;
533 $p->boucles = &$boucles;
534 $code = compose_filtres($p, $code);
535 }
536 $commentaire = ":";
537 $avant='';
538 $apres='';
539 $altern = "''";
540 break;
541
542 case 'champ':
543
544 // cette structure pourrait etre completee des le phrase' (a faire)
545 $p->id_boucle = $id_boucle;
546 $p->boucles = &$boucles;
547 $p->descr = $descr;
548 #$p->interdire_scripts = true;
549 $p->type_requete = $type;
550
551 $code = calculer_champ($p);
552 $commentaire = '#' . $p->nom_champ . $p->etoile;
553 $avant = calculer_liste($p->avant,
554 $descr, $boucles, $id_boucle);
555 $apres = calculer_liste($p->apres,
556 $descr, $boucles, $id_boucle);
557 $altern = "''";
558 break;
559
560 default:
561 erreur_squelette(_T('zbug_info_erreur_squelette'));
562 } // switch
563
564 if ($code != "''") {
565 if ($avant == "''")
566 $avant = '';
567 if ($apres == "''")
568 $apres = '';
569 if ($avant||$apres||($altern!="''")) {
570 $t = '$t' . $descr['niv'];
571 $res = (!$avant ? "" : "$avant . ") .
572 $t .
573 (!$apres ? "" : " . $apres");
574 $code = "((strval($t = $code)!='')"
575 ." ?\n\t$tab($res) :\n\t$tab($altern))";
576 }
577
578 // gestion d'une boucle-fragment (ahah)
579 if (isset($p->modificateur['fragment'])) {
580 static $nombre_fragments = array();
581 $fragment = $p->modificateur['fragment'];
582 $fragment .= $nombre_fragments[$p->modificateur['fragment']]++;
583 $code = "\n((\$f = ($code))?
584 '<div id=\"$fragment\" class=\"fragment\">'.\$f.'<!-- /$fragment --></div><"."?php stop_inclure(\"$fragment\"); ?".">':'')\n";
585 }
586
587 }
588 if ($code != "''")
589 $codes[]= (($mode == 'validation') ?
590 "array(" . $p->ligne . ", '$commentaire', $code)"
591 : (($mode == 'code') ?
592 "\n// $commentaire\n$code" :
593 $code));
594 } // foreach
595 return $codes;
596}
597
598// affichage du code produit
599
600// http://doc.spip.org/@code_boucle
601function code_boucle(&$boucles, $id, $nom)
602{
603 $boucle = &$boucles[$id];
604
605 // Indiquer la boucle en commentaire
606 $pretty = '';
607
608 if ($boucle->type_requete != 'boucle')
609 {
610 // Resynthetiser les criteres
611 foreach ($boucle->param as $param) {
612 $s = "";
613 $sep = "";
614 foreach ($param as $t) {
615 if (is_array($t)) { // toujours vrai normalement
616 $s .= $sep;
617 $c = $t[0];
618 if ($c->apres)
619 $s .= ($c->apres . $c->texte . $c->apres);
620 else {
621 // faudrait decompiler aussi les balises...
622 foreach ($t as $c)
623 $s .= ($c->type == 'texte') ? $c->texte : '#...';
624 }
625 $sep = ", ";
626 }
627 }
628 $pretty .= ' {' . $s . '}';
629 }
630 }
631
632 $pretty = "BOUCLE$id(".strtoupper($boucle->type_requete) . ")" .
633 strtr($pretty,"\r\n", " ");
634
635 return $pretty;
636}
637
638
639// Prend en argument le texte d'un squelette (et son fichier d'origine)
640// sa grammaire et un nom.
641// Retourne une fonction PHP/SQL portant ce nom et calculant une page.
642// Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
643// - 1er: element 'cache' => nom (du fichier ou` mettre la page)
644// - 2e: element 0 contenant un environnement ('id_article => $id_article, etc)
645// Elle retourne alors un tableau de 5 e'le'ments:
646// - 'texte' => page HTML, application du squelette a` l'environnement;
647// - 'squelette' => le nom du squelette
648// - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
649// - 'invalideurs' => de'pendances de cette page, pour invalider son cache.
650// - 'entetes' => tableau des entetes http
651// En cas d'erreur, elle retourne un tableau des 2 premiers elements seulement
652
653// http://doc.spip.org/@public_compiler_dist
654function public_compiler_dist($squelette, $nom, $gram, $sourcefile) {
655 global $table_des_tables, $tables_des_serveurs_sql, $tables_principales,
656 $tables_jointures;
657
658 // Pre-traitement : reperer le charset du squelette, et le convertir
659 // Bonus : supprime le BOM
660 include_spip('inc/charsets');
661 $squelette = transcoder_page($squelette);
662
663 // Hacke un eventuel tag xml "<?xml" pour qu'il ne soit pas traite comme php
664 $squelette = str_replace('<'.'?xml', "#HTTP_HEADER{X-Xml-Hack: ok}<\1?xml", $squelette);
665
666 // Phraser le squelette, selon sa grammaire
667 // pour le moment: "html" seul connu (HTML+balises BOUCLE)
668 $boucles = array();
669 spip_timer('calcul_skel');
670
671 $f = charger_fonction('phraser_'.$gram, 'public');
672
673 $racine = $f($squelette, '',$boucles, $nom);
674
675 // tableau des informations sur le squelette
676 $descr = array('nom' => $nom, 'sourcefile' => $sourcefile);
677
678 // une boucle documents est conditionnee par tout le reste!
679 foreach($boucles as $id => $boucle) {
680 $type = $boucle->type_requete;
681 if ($type != 'boucle') {
682 $boucles[$id]->descr = &$descr;
683 if ($x = $table_des_tables[$type]) {
684 $boucles[$id]->id_table = $x;
685 $boucles[$id]->primary = $tables_principales["spip_$x"]['key']["PRIMARY KEY"];
686 if ((!$boucles[$id]->jointures)
687 AND (is_array($x = $tables_jointures['spip_' . $x])))
688 $boucles[$id]->jointures = $x;
689 } else {
690 // table non Spip.
691 $boucles[$id]->id_table = $type;
692 $serveur = $boucle->sql_serveur;
693 $x = $tables_des_serveurs_sql[$serveur ? $serveur : 'localhost'][$type]['key'];
694 $boucles[$id]->primary = ($x["PRIMARY KEY"] ? $x["PRIMARY KEY"] : $x["KEY"]);
695 }
696 }
697 if (($boucle->type_requete == 'documents') && $boucle->doublons)
698 { $descr['documents'] = true; }
699 }
700 // Commencer par reperer les boucles appelees explicitement
701 // car elles indexent les arguments de maniere derogatoire
702 foreach($boucles as $id => $boucle) {
703 if ($boucle->type_requete == 'boucle') {
704 $boucles[$id]->descr = &$descr;
705 $rec = &$boucles[$boucle->param[0]];
706 if (!$rec) {
707 return array(_T('zbug_info_erreur_squelette'),
708 ($boucle->param[0]
709 . ' '. _T('zbug_boucle_recursive_undef')));
710 } else {
711 $rec->externe = $id;
712 $descr['id_mere'] = $id;
713 $boucles[$id]->return =
714 calculer_liste(array($rec),
715 $descr,
716 $boucles,
717 $boucle->param);
718 }
719 }
720 }
721 foreach($boucles as $id => $boucle) {
722 $type = $boucle->type_requete;
723 if ($type != 'boucle') {
724 if ($boucle->param) {
725 $res = calculer_criteres($id, $boucles);
726 if (is_array($res)) return $res; # erreur
727 }
728 $descr['id_mere'] = $id;
729 $boucles[$id]->return =
730 calculer_liste($boucle->milieu,
731 $descr,
732 $boucles,
733 $id);
734 }
735 }
736
737 // idem pour la racine
738 $descr['id_mere'] = '';
739 $corps = calculer_liste($racine, $descr, $boucles);
740
741 // Calcul du corps de toutes les fonctions PHP,
742 // en particulier les requetes SQL et TOTAL_BOUCLE
743 // de'terminables seulement maintenant
744
745 foreach($boucles as $id => $boucle) {
746 // appeler la fonction de definition de la boucle
747 $f = 'boucle_'.strtoupper($boucle->type_requete);
748 // si pas de definition perso, definition spip
749 if (!function_exists($f)) $f = $f.'_dist';
750 // laquelle a une definition par defaut
751 if (!function_exists($f)) $f = 'boucle_DEFAUT';
752 if (!function_exists($f)) $f = 'boucle_DEFAUT_dist';
753 $boucles[$id]->return =
754 "function BOUCLE" . strtr($id,"-","_") . $nom .
755 '(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
756 $f($id, $boucles) .
757 "\n}\n\n";
758 if ($GLOBALS['var_mode'] == 'debug')
759 boucle_debug_compile ($id, $nom, $boucles[$id]->return);
760
761 }
762
763 $code = "";
764 foreach($boucles as $id => $boucle) {
765 $code .= "\n//\n// <BOUCLE " .
766# code_boucle($boucles, $id, $nom). # pas au point
767 $boucle->type_requete .
768 ">\n//\n" .
769 $boucle->return;
770 }
771
772 $secondes = spip_timer('calcul_skel');
773 spip_log("COMPIL ($secondes) ["
774 .preg_replace(',\.html$,', '', $sourcefile)
775 ."] $nom.php");
776
777 $code = "<"."?php
778/*
779 * Squelette : $sourcefile
780 * Date : ".gmdate("D, d M Y H:i:s", @filemtime($sourcefile))." GMT
781 * Compile : ".gmdate("D, d M Y H:i:s", time())." GMT ($secondes)
782 * " . (!$boucles ? "Pas de boucle" :
783 ("Boucles : " . join (', ', array_keys($boucles)))) ."
784 */ " .
785 $code . '
786
787//
788// Fonction principale du squelette ' . $sourcefile ."
789//
790function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
791 $page = ' .
792 // ATTENTION, le calcul du l'expression $corps affectera $Cache
793 // c'est pourquoi on l'affecte a cette variable auxiliaire
794 // avant de referencer $Cache
795 $corps . ";
796
797 return analyse_resultat_skel('$nom', \$Cache, \$page);
798}
799
800?".">";
801
802 if ($GLOBALS['var_mode'] == 'debug')
803 squelette_debug_compile($nom, $sourcefile, $code, $squelette);
804 return $code;
805
806}
807
808?>