squellete2
[aidenligne_francais_universite.git] / ecrire / public / assembler.php
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 if (!defined("_ECRIRE_INC_VERSION")) return;
15
16 // fonction principale declenchant tout le service
17 // elle-meme ne fait que traiter les cas particuliers, puis passe la main.
18 // http://doc.spip.org/@public_assembler_dist
19 function public_assembler_dist($fond) {
20 global $auteur_session, $forcer_lang, $ignore_auth_http, $var_mode;
21
22 // multilinguisme
23 if ($forcer_lang AND ($forcer_lang!=='non') AND !count($_POST)) {
24 include_spip('inc/lang');
25 verifier_lang_url();
26 }
27 if (isset($_GET['lang'])) {
28 include_spip('inc/lang');
29 lang_select($_GET['lang']);
30 }
31
32 // Si envoi pour un forum, enregistrer puis rediriger
33 if (isset($_POST['confirmer_forum'])
34 OR (isset($_POST['ajouter_mot']) AND $GLOBALS['afficher_texte']=='non')) {
35 include_spip('inc/headers');
36 $forum_insert = charger_fonction('forum_insert', 'inc');
37 redirige_par_entete($forum_insert());
38 }
39
40 // si signature de petition, l'enregistrer avant d'afficher la page
41 // afin que celle-ci contienne la signature
42 if (isset($_GET['var_confirm'])) {
43 include_spip('balise/formulaire_signature');
44 reponse_confirmation($_GET['var_confirm']);
45 }
46
47 // refus du debug si l'admin n'est pas connecte
48 if ($var_mode=='debug') {
49 if ($auteur_session['statut'] == '0minirezo')
50 spip_log('debug !');
51 else {
52 include_spip('inc/headers');
53 redirige_par_entete(generer_url_public('login',
54 'url='.rawurlencode(
55 parametre_url(self(), 'var_mode', 'debug', '&')
56 ), true));
57 }
58 }
59
60 return assembler_page ($fond);
61 }
62
63
64 // http://doc.spip.org/@is_preview
65 function is_preview()
66 {
67 global $var_mode;
68 if ($var_mode !== 'preview') return false;
69 $statut = $GLOBALS['auteur_session']['statut'];
70 return ($statut=='0minirezo' OR
71 ($GLOBALS['meta']['preview']=='1comite' AND $statut=='1comite'));
72 }
73
74 //
75 // calcule la page et les entetes
76 //
77 // http://doc.spip.org/@assembler_page
78 function assembler_page ($fond) {
79 global $flag_ob, $flag_preserver,$lastmodified,
80 $use_cache, $var_mode, $var_preview;
81
82 // Cette fonction est utilisee deux fois
83 $cacher = charger_fonction('cacher', 'public');
84 // Garnir ces quatre parametres avec les infos sur le cache
85 $cacher(NULL, $use_cache, $chemin_cache, $page, $lastmodified);
86
87 if (!$chemin_cache || !$lastmodified) $lastmodified = time();
88
89 // demande de previsualisation ?
90 // -> inc-calcul n'enregistrera pas les fichiers caches
91 // -> inc-boucles acceptera les objets non 'publie'
92 if (is_preview()) {
93 $var_mode = 'recalcul';
94 $var_preview = true;
95 spip_log('preview !');
96 } else $var_preview = false;
97
98 $headers_only = ($_SERVER['REQUEST_METHOD'] == 'HEAD');
99
100 // Pour les pages non-dynamiques (indiquees par #CACHE{duree,cache-client})
101 // une perennite valide a meme reponse qu'une requete HEAD (par defaut les
102 // pages sont dynamiques)
103 if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
104 AND !$var_mode
105 AND $chemin_cache
106 AND isset($page['entetes'])
107 AND strstr($page['entetes']['Cache-Control'],'max-age=')
108 AND !strstr($_SERVER['SERVER_SOFTWARE'],'IIS/')
109 ) {
110 $since = preg_replace('/;.*/', '',
111 $_SERVER['HTTP_IF_MODIFIED_SINCE']);
112 $since = str_replace('GMT', '', $since);
113 if (trim($since) == gmdate("D, d M Y H:i:s", $lastmodified)) {
114 $page['status'] = 304;
115 $headers_only = true;
116 }
117 }
118
119 // Si requete HEAD ou Last-modified compatible, ignorer le texte
120 // et pas de content-type (pour contrer le bouton admin de inc-public)
121
122 if ($headers_only) {
123 $page['entetes']["Connection"] = "close";
124 $page['texte'] = "";
125 } else {
126 if (!$use_cache) {
127 if (isset($page['contexte'])){
128 // Remplir les globals pour les boutons d'admin
129 foreach ($page['contexte'] as $var=>$val)
130 $GLOBALS[$var] = $val;
131 }
132 } else {
133 $parametrer = charger_fonction('parametrer', 'public');
134 $page = $parametrer($fond, '', $chemin_cache);
135 if ($chemin_cache)
136 $cacher(NULL, $use_cache, $chemin_cache, $page, $lastmodified);
137 }
138
139 if ($chemin_cache) $page['cache'] = $chemin_cache;
140
141 auto_content_type($page);
142
143 $flag_preserver |= headers_sent();
144
145 // Definir les entetes si ce n'est fait
146 if (!$flag_preserver) {
147 if ($flag_ob) {
148 // Si la page est vide, produire l'erreur 404
149 if (trim($page['texte']) === ''
150 AND $var_mode != 'debug') {
151 $page = message_erreur_404();
152 }
153 // pas de cache client en mode 'observation'
154 if ($var_mode) {
155 $page['entetes']["Cache-Control"]= "no-cache,must-revalidate";
156 $page['entetes']["Pragma"] = "no-cache";
157 }
158 }
159 }
160 }
161
162 // Entete Last-Modified:
163 // eviter d'etre incoherent en envoyant un lastmodified identique
164 // a celui qu'on a refuse d'honorer plus haut (cf. #655)
165 if ($lastmodified
166 AND !isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
167 $page['entetes']["Last-Modified"]=gmdate("D, d M Y H:i:s", $lastmodified)." GMT";
168
169 return $page;
170 }
171
172 //
173 // 2 fonctions pour compatibilite arriere. Sont probablement superflues
174 //
175
176 // http://doc.spip.org/@auto_content_type
177 function auto_content_type($page)
178 {
179 global $flag_preserver;
180 if (!isset($flag_preserver))
181 {
182 $flag_preserver = preg_match("/header\s*\(\s*.content\-type:/isx",$page['texte']) || (isset($page['entetes']['Content-Type']));
183 }
184 }
185
186 // http://doc.spip.org/@stop_inclure
187 function stop_inclure($fragment) {
188 if ($fragment == _request('var_fragment')) {
189 define('_STOP_INCLURE', 1);
190 #spip_log("fin du fragment $fragment, on arrete d'inclure");
191 }
192 }
193 // http://doc.spip.org/@inclure_page
194 function inclure_page($fond, $contexte_inclus) {
195 global $lastmodified;
196
197 // Si un fragment est demande et deja obtenu, inutile de continuer a inclure
198 if (defined('_STOP_INCLURE')) {
199 return array(
200 'texte' => '',
201 'process_ins' => 'html'
202 );
203 }
204
205 // Si on a inclus sans fixer le critere de lang, on prend la langue courante
206 if (!isset($contexte_inclus['lang']))
207 $contexte_inclus['lang'] = $GLOBALS['spip_lang'];
208
209 if ($contexte_inclus['lang'] != $GLOBALS['meta']['langue_site']) {
210 lang_select($contexte_inclus['lang']);
211 $lang_select = true; // pour lang_dselect en sortie
212 }
213
214 $cacher = charger_fonction('cacher', 'public');
215 // Garnir ces quatre parametres avec les infos sur le cache :
216 // emplacement, validite, et, s'il est valide, contenu & age
217 $cacher($contexte_inclus, $use_cache, $chemin_cache, $page, $lastinclude);
218
219 // Une fois le chemin-cache decide, on ajoute la date (et date_redac)
220 // dans le contexte inclus, pour que les criteres {age} etc fonctionnent
221 if (!isset($contexte_inclus['date']))
222 $contexte_inclus['date'] = date('Y-m-d H:i:s');
223 if (!isset($contexte_inclus['date_redac']))
224 $contexte_inclus['date_redac'] = $contexte_inclus['date'];
225
226 // Si use_cache vaut 0, la page a ete tiree du cache et se trouve dans $page
227 if (!$use_cache) {
228 $lastmodified = max($lastmodified, $lastinclude);
229 }
230 // sinon on la calcule
231 else {
232 $parametrer = charger_fonction('parametrer', 'public');
233 $page = $parametrer($fond, $contexte_inclus, $chemin_cache);
234 $lastmodified = time();
235 // et on l'enregistre sur le disque
236 if ($chemin_cache
237 AND $page['entetes']['X-Spip-Cache'] > 0)
238 $cacher($contexte_inclus, $use_cache, $chemin_cache, $page,
239 $lastmodified);
240 }
241 if($lang_select)
242 lang_dselect();
243
244 return $page;
245 }
246
247
248 # Attention, un appel explicite a cette fonction suppose certains include
249 # (voir l'exemple de spip_inscription et spip_pass)
250 # $echo = faut-il faire echo ou return
251
252 // http://doc.spip.org/@inclure_balise_dynamique
253 function inclure_balise_dynamique($texte, $echo=true, $ligne=0) {
254 global $contexte_inclus; # provisoire : c'est pour le debuggueur
255
256 if (is_array($texte)) {
257
258 list($fond, $delainc, $contexte_inclus) = $texte;
259
260 // delais a l'ancienne, c'est pratiquement mort
261 $d = isset($GLOBALS['delais']) ? $GLOBALS['delais'] : NULL;
262 $GLOBALS['delais'] = $delainc;
263 $page = inclure_page($fond, $contexte_inclus);
264 $GLOBALS['delais'] = $d;
265
266 // Faire remonter les entetes
267 if (is_array($page['entetes'])) {
268 // mais pas toutes
269 unset($page['entetes']['X-Spip-Cache']);
270 unset($page['entetes']['Content-Type']);
271 if (is_array($GLOBALS['page'])) {
272 if (!is_array($GLOBALS['page']['entetes']))
273 $GLOBALS['page']['entetes'] = array();
274 $GLOBALS['page']['entetes'] =
275 array_merge($GLOBALS['page']['entetes'],$page['entetes']);
276 }
277 }
278
279 if ($page['process_ins'] == 'html') {
280 $texte = $page['texte'];
281 } else {
282 ob_start();
283 eval('?' . '>' . $page['texte']);
284 $texte = ob_get_contents();
285 ob_end_clean();
286 }
287 }
288
289 if ($GLOBALS['var_mode'] == 'debug')
290 $GLOBALS['debug_objets']['resultat'][$ligne] = $texte;
291
292 if ($echo)
293 echo $texte;
294 else
295 return $texte;
296
297 }
298
299 // Traiter var_recherche pour surligner les mots
300 // http://doc.spip.org/@f_surligne
301 function f_surligne ($texte) {
302 if (isset($_GET['var_recherche'])) {
303 include_spip('inc/surligne');
304 $texte = surligner_mots($texte, $_GET['var_recherche']);
305 }
306 return $texte;
307 }
308
309 // Valider/indenter a la demande.
310 // http://doc.spip.org/@f_tidy
311 function f_tidy ($texte) {
312 global $xhtml;
313
314 if ($xhtml # tidy demande
315 AND $GLOBALS['html'] # verifie que la page avait l'entete text/html
316 AND strlen($texte)
317 AND (_request('var_fragment') === NULL)
318 AND !headers_sent()) {
319 # Compatibilite ascendante
320 if (!is_string($xhtml)) $xhtml ='tidy';
321
322 if ($f = charger_fonction($xhtml, 'inc'))
323 $texte = $f($texte);
324 }
325
326 return $texte;
327 }
328
329 // Offre #INSERT_HEAD sur tous les squelettes (bourrin)
330 // a activer dans mes_options via :
331 // $spip_pipeline['affichage_final'] .= '|f_insert_head';
332 // http://doc.spip.org/@f_insert_head
333 function f_insert_head($texte) {
334 if (!$GLOBALS['html']) return $texte;
335 include_spip('public/admin'); // pour strripos
336
337 ($pos = stripos($texte, '</head>'))
338 || ($pos = stripos($texte, '<body>'))
339 || ($pos = 0);
340
341 if (false === strpos(substr($texte, 0,$pos), '<!-- insert_head -->')) {
342 $insert = "\n".pipeline('insert_head','<!-- f_insert_head -->')."\n";
343 $texte = substr_replace($texte, $insert, $pos, 0);
344 }
345
346 return $texte;
347 }
348
349 // Inserer au besoin les boutons admins
350 // http://doc.spip.org/@f_admin
351 function f_admin ($texte) {
352 if ($GLOBALS['affiche_boutons_admin']) {
353 include_spip('public/admin');
354 $texte = affiche_boutons_admin($texte);
355 }
356
357 return $texte;
358 }
359
360 // http://doc.spip.org/@message_erreur_404
361 function message_erreur_404 ($erreur= "") {
362 if (!$erreur) {
363 if (isset($GLOBALS['id_article']))
364 $erreur = 'public:aucun_article';
365 else if (isset($GLOBALS['id_rubrique']))
366 $erreur = 'public:aucune_rubrique';
367 else if (isset($GLOBALS['id_breve']))
368 $erreur = 'public:aucune_breve';
369 else if (isset($GLOBALS['id_auteur']))
370 $erreur = 'public:aucun_auteur';
371 else if (isset($GLOBALS['id_syndic']))
372 $erreur = 'public:aucun_site';
373 }
374 $contexte_inclus = array(
375 'erreur' => _T($erreur),
376 'lang' => $GLOBALS['spip_lang']
377 );
378 $page = inclure_page('404', $contexte_inclus);
379 $page['status'] = 404;
380 return $page;
381 }
382
383 // fonction permettant de recuperer le resultat du calcul d'un squelette
384 // pour une inclusion dans un flux
385 // http://doc.spip.org/@recuperer_fond
386 function recuperer_fond($fond, $contexte=array()) {
387
388 $clear = false;
389 // on est peut etre dans l'espace prive au moment de l'appel
390 if (!isset($GLOBALS['_INC_PUBLIC'])) {
391 $GLOBALS['_INC_PUBLIC'] = 1;
392 $clear = true;
393 }
394 if (($fond=='')&&isset($contexte['fond']))
395 $fond = $contexte['fond'];
396
397 $contexte['fond'] = $fond; // necessaire pour calculer correctement le cache
398
399 $page = inclure_page($fond, $contexte);
400 if ($GLOBALS['flag_ob'] AND ($page['process_ins'] != 'html')) {
401 ob_start();
402 eval('?' . '>' . $page['texte']);
403 $page['texte'] = ob_get_contents();
404 ob_end_clean();
405 }
406 if ($clear)
407 unset($GLOBALS['_INC_PUBLIC']);
408 return trim($page['texte']);
409 }
410
411 // temporairement ici : a mettre dans le futur inc/modeles
412 // creer_contexte_de_modele('left', 'autostart=true', ...) renvoie un array()
413 // http://doc.spip.org/@creer_contexte_de_modele
414 function creer_contexte_de_modele($args) {
415 $contexte = array();
416 $params = array();
417 foreach ($args as $var=>$val) {
418 if (is_int($var)){ // argument pas formate
419 if (in_array($val, array('left', 'right', 'center'))) {
420 $var = 'align';
421 $contexte[$var] = $val;
422 } else {
423 $args = explode('=', $val);
424 if (count($args)>=2) // Flashvars=arg1=machin&arg2=truc genere plus de deux args
425 $contexte[$args[0]] = substr($val,strlen($args[0])+1);
426 }
427 }
428 else
429 $contexte[$var] = $val;
430 }
431
432 return $contexte;
433 }
434
435 // Calcule le modele et retourne la mini-page ainsi calculee
436 // http://doc.spip.org/@inclure_modele
437 function inclure_modele($type, $id, $params, $lien) {
438 static $compteur;
439 if (++$compteur>10) return ''; # ne pas boucler indefiniment
440
441 $type = strtolower($type);
442
443 $fond = 'modeles/'.$type;
444
445 $params = array_filter(explode('|', $params));
446 if ($params) {
447 list(,$soustype) = each($params);
448 $soustype = strtolower($soustype);
449 if (in_array($soustype,
450 array('left', 'right', 'center'))) {
451 list(,$soustype) = each($params);
452 $soustype = strtolower($soustype);
453 }
454
455 if (preg_match(',^[a-z0-9_]+$,', $soustype)) {
456 $fond = 'modeles/'.$type.'_'.$soustype;
457 if (!find_in_path($fond.'.html')) {
458 $fond = 'modeles/'.$type;
459 $class = $soustype;
460 }
461 }
462 }
463
464 // en cas d'echec : si l'objet demande a une url, on cree un petit encadre
465 // avec un lien vers l'objet ; sinon on passe la main au suivant
466 if (!find_in_path($fond.'.html')) {
467 if (!$lien)
468 $lien = calculer_url("$type$id", '', 'tout');
469 if (strpos($lien[1],'spip_url') !== false)
470 return false;
471 else
472 return '<a href="'.$lien[0].'" class="spip_modele'
473 . ($class ? " $class" : '')
474 . '">'.sinon($lien[2], _T('ecrire:info_sans_titre'))."</a>";
475 }
476
477
478 // Creer le contexte
479 $contexte = array(
480 'lang' => $GLOBALS['spip_lang'],
481 'fond' => $fond,
482 'dir_racine' => _DIR_RACINE # eviter de mixer un cache racine et un cache ecrire (meme si pour l'instant les modeles ne sont pas caches, le resultat etant different il faut que le contexte en tienne compte
483 );
484 // Fixer l'identifiant qu'on passe dans #ENV ;
485 // pour le modele <site1> on veut id_syndic => 1
486 // par souci de systematisme on ajoute aussi
487 // id => 1.
488 $contexte[id_table_objet($type)] = $contexte['id'] = $id;
489
490 if ($class)
491 $contexte['class'] = $class;
492
493 // Si un lien a ete passe en parametre, ex: [<modele1>->url]
494 if ($lien) {
495 # un eventuel guillemet (") sera reechappe par #ENV
496 $contexte['lien'] = str_replace("&quot;",'"', $lien[0]);
497 $contexte['lien_class'] = $lien[1];
498 }
499
500 // Traiter les parametres
501 // par exemple : <img1|center>, <emb12|autostart=true> ou <doc1|lang=en>
502 $contexte = array_merge($contexte,
503 creer_contexte_de_modele($params));
504
505 // On cree un marqueur de notes unique lie a ce modele
506 // et on enregistre l'etat courant des globales de notes...
507 $enregistre_marqueur_notes = $GLOBALS['marqueur_notes'];
508 $enregistre_les_notes = $GLOBALS['les_notes'];
509 $enregistre_compt_note = $GLOBALS['compt_note'];
510 $GLOBALS['marqueur_notes'] = substr(md5(serialize($contexte)),0,8);
511 $GLOBALS['les_notes'] = '';
512 $GLOBALS['compt_note'] = 0;
513
514 // Appliquer le modele avec le contexte
515 $retour = trim(recuperer_fond($fond, $contexte));
516
517 // On restitue les globales de notes telles qu'elles etaient avant l'appel
518 // du modele. Si le modele n'a pas affiche ses notes, tant pis (elles *doivent*
519 // etre dans le cache du modele, autrement elles ne seraient pas prises en
520 // compte a chaque calcul d'un texte contenant un modele, mais seulement
521 // quand le modele serait calcule, et on aurait des resultats incoherents)
522 $GLOBALS['les_notes'] = $enregistre_les_notes;
523 $GLOBALS['marqueur_notes'] = $enregistre_marqueur_notes;
524 $GLOBALS['compt_note'] = $enregistre_compt_note;
525
526 // Regarder si le modele tient compte des liens (il *doit* alors indiquer
527 // spip_lien_ok dans les classes de son conteneur de premier niveau ;
528 // sinon, s'il y a un lien, on l'ajoute classiquement
529 if (strstr(' ' . ($classes = extraire_attribut($retour, 'class')).' ',
530 'spip_lien_ok')) {
531 $retour = inserer_attribut($retour, 'class',
532 trim(str_replace(' spip_lien_ok ', ' ', " $classes ")));
533 } else if ($lien)
534 $retour = "<a href='".$lien[0]."' class='".$lien[1]."'>".$retour."</a>";
535
536 $compteur--;
537 return $retour;
538 }
539
540 ?>