3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
6 * Copyright (c) 2001-2007 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
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 \***************************************************************************/
14 if (!defined("_ECRIRE_INC_VERSION")) return;
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;
23 if ($forcer_lang AND ($forcer_lang!=='non') AND !count($_POST)) {
24 include_spip('inc/lang');
27 if (isset($_GET['lang'])) {
28 include_spip('inc/lang');
29 lang_select($_GET['lang']);
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());
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']);
47 // refus du debug si l'admin n'est pas connecte
48 if ($var_mode=='debug') {
49 if ($auteur_session['statut'] == '0minirezo')
52 include_spip('inc/headers');
53 redirige_par_entete(generer_url_public('login',
55 parametre_url(self(), 'var_mode', 'debug', '&')
60 return assembler_page ($fond);
64 // http://doc.spip.org/@is_preview
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'));
75 // calcule la page et les entetes
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;
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);
87 if (!$chemin_cache ||
!$lastmodified) $lastmodified = time();
89 // demande de previsualisation ?
90 // -> inc-calcul n'enregistrera pas les fichiers caches
91 // -> inc-boucles acceptera les objets non 'publie'
93 $var_mode = 'recalcul';
95 spip_log('preview !');
96 } else $var_preview = false
;
98 $headers_only = ($_SERVER['REQUEST_METHOD'] == 'HEAD');
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'])
106 AND isset($page['entetes'])
107 AND strstr($page['entetes']['Cache-Control'],'max-age=')
108 AND !strstr($_SERVER['SERVER_SOFTWARE'],'IIS/')
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
;
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)
123 $page['entetes']["Connection"] = "close";
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;
133 $parametrer = charger_fonction('parametrer', 'public');
134 $page = $parametrer($fond, '', $chemin_cache);
136 $cacher(NULL
, $use_cache, $chemin_cache, $page, $lastmodified);
139 if ($chemin_cache) $page['cache'] = $chemin_cache;
141 auto_content_type($page);
143 $flag_preserver |
= headers_sent();
145 // Definir les entetes si ce n'est fait
146 if (!$flag_preserver) {
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();
153 // pas de cache client en mode 'observation'
155 $page['entetes']["Cache-Control"]= "no-cache,must-revalidate";
156 $page['entetes']["Pragma"] = "no-cache";
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)
166 AND !isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
167 $page['entetes']["Last-Modified"]=gmdate("D, d M Y H:i:s", $lastmodified)." GMT";
173 // 2 fonctions pour compatibilite arriere. Sont probablement superflues
176 // http://doc.spip.org/@auto_content_type
177 function auto_content_type($page)
179 global $flag_preserver;
180 if (!isset($flag_preserver))
182 $flag_preserver = preg_match("/header\s*\(\s*.content\-type:/isx",$page['texte']) ||
(isset($page['entetes']['Content-Type']));
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");
193 // http://doc.spip.org/@inclure_page
194 function inclure_page($fond, $contexte_inclus) {
195 global $lastmodified;
197 // Si un fragment est demande et deja obtenu, inutile de continuer a inclure
198 if (defined('_STOP_INCLURE')) {
201 'process_ins' => 'html'
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'];
209 if ($contexte_inclus['lang'] != $GLOBALS['meta']['langue_site']) {
210 lang_select($contexte_inclus['lang']);
211 $lang_select = true
; // pour lang_dselect en sortie
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);
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'];
226 // Si use_cache vaut 0, la page a ete tiree du cache et se trouve dans $page
228 $lastmodified = max($lastmodified, $lastinclude);
230 // sinon on la calcule
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
237 AND $page['entetes']['X-Spip-Cache'] > 0)
238 $cacher($contexte_inclus, $use_cache, $chemin_cache, $page,
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
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
256 if (is_array($texte)) {
258 list($fond, $delainc, $contexte_inclus) = $texte;
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;
266 // Faire remonter les entetes
267 if (is_array($page['entetes'])) {
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']);
279 if ($page['process_ins'] == 'html') {
280 $texte = $page['texte'];
283 eval('?' . '>' . $page['texte']);
284 $texte = ob_get_contents();
289 if ($GLOBALS['var_mode'] == 'debug')
290 $GLOBALS['debug_objets']['resultat'][$ligne] = $texte;
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']);
309 // Valider/indenter a la demande.
310 // http://doc.spip.org/@f_tidy
311 function f_tidy ($texte) {
314 if ($xhtml # tidy demande
315 AND $GLOBALS['html'] # verifie que la page avait l'entete text/html
317 AND (_request('var_fragment') === NULL
)
318 AND !headers_sent()) {
319 # Compatibilite ascendante
320 if (!is_string($xhtml)) $xhtml ='tidy';
322 if ($f = charger_fonction($xhtml, 'inc'))
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
337 ($pos = stripos($texte, '</head>'))
338 ||
($pos = stripos($texte, '<body>'))
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);
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);
360 // http://doc.spip.org/@message_erreur_404
361 function message_erreur_404 ($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';
374 $contexte_inclus = array(
375 'erreur' => _T($erreur),
376 'lang' => $GLOBALS['spip_lang']
378 $page = inclure_page('404', $contexte_inclus);
379 $page['status'] = 404;
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()) {
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;
394 if (($fond=='')&&isset($contexte['fond']))
395 $fond = $contexte['fond'];
397 $contexte['fond'] = $fond; // necessaire pour calculer correctement le cache
399 $page = inclure_page($fond, $contexte);
400 if ($GLOBALS['flag_ob'] AND ($page['process_ins'] != 'html')) {
402 eval('?' . '>' . $page['texte']);
403 $page['texte'] = ob_get_contents();
407 unset($GLOBALS['_INC_PUBLIC']);
408 return trim($page['texte']);
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) {
417 foreach ($args as $var=>$val) {
418 if (is_int($var)){ // argument pas formate
419 if (in_array($val, array('left', 'right', 'center'))) {
421 $contexte[$var] = $val;
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);
429 $contexte[$var] = $val;
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) {
439 if (++
$compteur>10) return ''; # ne pas boucler indefiniment
441 $type = strtolower($type);
443 $fond = 'modeles/'.$type;
445 $params = array_filter(explode('|', $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);
455 if (preg_match(',^[a-z0-9_]+$,', $soustype)) {
456 $fond = 'modeles/'.$type.'_'.$soustype;
457 if (!find_in_path($fond.'.html')) {
458 $fond = 'modeles/'.$type;
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')) {
468 $lien = calculer_url("$type$id", '', 'tout');
469 if (strpos($lien[1],'spip_url') !== false
)
472 return '<a href="'.$lien[0].'" class="spip_modele'
473 . ($class ?
" $class" : '')
474 . '">'.sinon($lien[2], _T('ecrire:info_sans_titre'))."</a>";
480 'lang' => $GLOBALS['spip_lang'],
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
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
488 $contexte[id_table_objet($type)] = $contexte['id'] = $id;
491 $contexte['class'] = $class;
493 // Si un lien a ete passe en parametre, ex: [<modele1>->url]
495 # un eventuel guillemet (") sera reechappe par #ENV
496 $contexte['lien'] = str_replace(""",'"', $lien[0]);
497 $contexte['lien_class'] = $lien[1];
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));
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;
514 // Appliquer le modele avec le contexte
515 $retour = trim(recuperer_fond($fond, $contexte));
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;
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')).' ',
531 $retour = inserer_attribut($retour, 'class',
532 trim(str_replace(' spip_lien_ok ', ' ', " $classes ")));
534 $retour = "<a href='".$lien[0]."' class='".$lien[1]."'>".$retour."</a>";