From f4cca4fdd4233ceb27ec979cf72bb52521b4f80b Mon Sep 17 00:00:00 2001 From: "Committo,Ergo:sum" <esj@rezo.net> Date: Sun, 29 Jan 2006 14:06:25 +0000 Subject: [PATCH] Faciliter l'envoi d'en-tetes http dans les squelettes, afin de remplacer les variables PHP $flag_preserver et $flag_dynamique par des entitees independantes du langage d'execution. Pour cela: - introduction d'une balise #HTTP{e1, ... en} utilisable en debut de squelette, et dont les arguments sont des chaines, entourees de guillemets ou d'apostrophes, conforme au protocole HTTP1/1 : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4 - cette balise est compilee en une sequence <?php header(e1); .... ;header(en) ?> - Spip repere une telle sequence initiale (c'est donc valable aussi pour un code php ecrit directement sous-reserve que la syntaxe soit exactement la meme) et en fait une meta-donnee pour chaque page produite par l'execution du squelette, afin de disposer facilement des en-tetes au moment de l'envoi; - Spip repere dans ces meta-donnees la presence de la directive Content-Type. Si elle est absente, elle est automatiquement rajoutee avec comme habituellement la valeur: Content-Type: text/html; charset=#CHARSET Spip n'enverra les boutons d'administration et de previsualisation et n'inserera leur CSS associee que si cette directive a pour valeur text/html ou que le mode debug est actif. Cette assertion simple reflete l'usage de la variable $flag_preserver qui n'a ainsi plus de raison d'etre. - Spip repere aussi dans ces meta-donnees la presence d'une directive "Cache-control", auquel cas il n'enverra aucune autre directive concernant le cache du client. Ainsi, le positionnement a "vrai" de la variable $flag_dynamique, jamais documentee, est equivalent a #HTTP{'Pragma: no-cache', 'Cache-Control: no-cache; must-revalidate'} --- dist/backend.html | 5 +- dist/distrib.html | 2 +- dist/forum.html | 2 + dist/ical.html | 2 +- dist/login.html | 2 + dist/sommaire.html | 1 + ecrire/inc_utils.php | 6 +- forum.php3 | 3 +- inc-balises.php3 | 19 +++++- inc-cache.php3 | 2 + inc-calcul.php3 | 23 ++++++- inc-compilo.php3 | 18 ++---- inc-public-global.php3 | 142 +++++++++++++++++++++++------------------ inc-public.php3 | 26 ++++++-- spip_login.php3 | 2 - 15 files changed, 155 insertions(+), 100 deletions(-) diff --git a/dist/backend.html b/dist/backend.html index e58ce44989..6b2da0098f 100644 --- a/dist/backend.html +++ b/dist/backend.html @@ -1,7 +1,4 @@ -<?php - @header('Content-type: text/xml[; charset=(#CHARSET)]'); - echo '<'.'?xml version="1.0"[ encoding="(#CHARSET)"]?'.">\n"; -?> +<?php @header("Content-type: text/xml[; charset=(#CHARSET)]"); echo '<'.'?xml version="1.0"[ encoding="(#CHARSET)"]?'.">\n"; ?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" diff --git a/dist/distrib.html b/dist/distrib.html index 5499a27482..08a0efb588 100644 --- a/dist/distrib.html +++ b/dist/distrib.html @@ -1,4 +1,4 @@ -<?php header("Content-Type: text/javascript") ?> +#HTTP**{"Content-Type: text/javascript"} document.write('<table border="0" bgcolor="#000000" cellspacing="0" cellpadding="0"><tr><td>'); document.write('<table border="0" bgcolor="#ffffff" cellspacing="1" cellpadding="2"><tr><td bgcolor="#d0d0d0" align="center">'); document.write('<a href="#URL_SITE_SPIP/"><b>[(#NOM_SITE_SPIP|addslashes)]</b></a> </td></tr><tr><td><ul><small>'); diff --git a/dist/forum.html b/dist/forum.html index 0c134e9aa6..11f9ecf21d 100644 --- a/dist/forum.html +++ b/dist/forum.html @@ -1,3 +1,5 @@ +#HTTP**{"Cache-Control: no-store, no-cache, must-revalidate", + "Pragma: no-cache"} <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html dir="#LANG_DIR" lang="#LANG"> <head> diff --git a/dist/ical.html b/dist/ical.html index 8654d3199c..0b6a0f89a9 100644 --- a/dist/ical.html +++ b/dist/ical.html @@ -1,4 +1,4 @@ -<?php header ("Content-type: text/calendar") ?> +#HTTP**{"Content-type: text/calendar"} BEGIN:VCALENDAR CALSCALE:GREGORIAN X-WR-CALNAME;VALUE=TEXT:[(#NOM_SITE_SPIP|filtrer_ical)] diff --git a/dist/login.html b/dist/login.html index 1ce3fac59e..cd52e77c14 100644 --- a/dist/login.html +++ b/dist/login.html @@ -1,3 +1,5 @@ +#HTTP**{"Cache-Control: no-store, no-cache, must-revalidate", + "Pragma: no-cache"} <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html dir="#LANG_DIR" lang="#LANG"> <head> diff --git a/dist/sommaire.html b/dist/sommaire.html index 9e06b88bab..91f1453ebe 100644 --- a/dist/sommaire.html +++ b/dist/sommaire.html @@ -6,6 +6,7 @@ <!-- Ceci est la feuille de style par defaut pour les types internes a SPIP --> <link rel="stylesheet" href="spip_style.css" type="text/css" /> +<link rel="stylesheet" href="spip_admin.css" type="text/css" /> <!-- Les feuilles de style specifiques aux presents squelettes --> <link rel="stylesheet" href="#DOSSIER_SQUELETTE/typographie.css" type="text/css" /> diff --git a/ecrire/inc_utils.php b/ecrire/inc_utils.php index cb27fa47dd..4e7b5abf2c 100644 --- a/ecrire/inc_utils.php +++ b/ecrire/inc_utils.php @@ -528,11 +528,11 @@ function http_last_modified($lastmodified, $expire = 0) { } // envoyer le navigateur sur une nouvelle adresse +// en evitant les attaques par la redirection (souvent indique par 1 $_GET) function redirige_par_entete($url, $fin="") { # spip_log("redirige $url$fin"); - include_ecrire('inc_headers'); - spip_header("Location: $url$fin"); + header("Location: " . strtr("$url$fin", "\n\r", " ")); echo '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> @@ -542,7 +542,7 @@ function redirige_par_entete($url, $fin="") { <h1>302 Found</h1> <a href="' .quote_amp("$url$fin") -.'">Click here</a>.<p> +.'">Click here</a>. </body></html>'; exit; diff --git a/forum.php3 b/forum.php3 index 861d351d1b..48b94cb353 100644 --- a/forum.php3 +++ b/forum.php3 @@ -12,8 +12,7 @@ $delais = 3600; // 2. faire des forums uniquement pour affecter des mots-cles // $afficher_texte = "non"; -// En cas de forums sur abonnement, on a un panneau de login -$flag_dynamique = true; +// forum sur abonnement => login; ne pas oublier le header "no-cache" include ("inc-public.php3"); diff --git a/inc-balises.php3 b/inc-balises.php3 index a5b032d075..9af6d7d92c 100644 --- a/inc-balises.php3 +++ b/inc-balises.php3 @@ -598,9 +598,9 @@ function balise_EXTRA_dist ($p) { $p->code = $_extra; // Gerer la notation [(#EXTRA|isbn)] - if ($p->params) { + if ($p->param) { include_ecrire("inc_extra"); - list ($key, $champ_extra) = each($p->params); // le premier filtre + list ($key, $champ_extra) = each($p->param); // le premier filtre $type_extra = $p->type_requete; $champ = $champ_extra[1]; @@ -609,7 +609,7 @@ function balise_EXTRA_dist ($p) { // on aura le type_extra du sous-objet (!) if (extra_champ_valide($type_extra, $champ)) { - array_shift($p->params); + array_shift($p->param); # A quoi ca sert ? # $p->code = "extra($p->code, '".addslashes($champ)."')"; @@ -766,4 +766,17 @@ function balise_REM_dist($p) { return $p; } +// +// #HTTP +// pour les entetes. A n'utiliser qu'en debut de squelette +// +function balise_HTTP_dist($p) { + $a = $p->param[0]; + array_shift($a); + $code = ""; + foreach($a as $v) $code .= 'header("' . $v[0]->texte . '");'; + $p->code="('<'.'?php $code ?' . '>')"; + return $p; +} + ?> diff --git a/inc-cache.php3 b/inc-cache.php3 index 909594919b..9774fd98c4 100644 --- a/inc-cache.php3 +++ b/inc-cache.php3 @@ -210,6 +210,8 @@ function creer_cache(&$page, $chemin_cache, $duree) { // Enregistrer le fichier cache qui contient // 1) la carte d'identite de la page (ses "globals", genre id_article=7) // 2) son contenu + $page['signal']['process_ins'] = $page['process_ins']; + $page['signal']['entetes'] = $page['entetes']; $r = ecrire_fichier($chemin_cache, "<!-- " . str_replace("\n", " ", serialize($page['signal'])) diff --git a/inc-calcul.php3 b/inc-calcul.php3 index eab33923d8..1b51c938cc 100644 --- a/inc-calcul.php3 +++ b/inc-calcul.php3 @@ -207,7 +207,7 @@ function calculer_contexte() { function calculer_page_globale($cache, $fond) { - global $lastmodified, $_SERVER, $contexte; + global $_SERVER, $contexte; $contexte = calculer_contexte(); @@ -253,8 +253,25 @@ function calculer_page_globale($cache, $fond) { } $page['signal'] = $signal; - $page['signal']['process_ins'] = $page['process_ins']; - $lastmodified = time(); return $page; } + +function analyse_resultat_skel($nom, $Cache, $corps) +{ + $headers = array(); + while (preg_match('/^(<[?]php\s+)@?header\s*\(\s*.([^:]*):\s*([^)]*)[^)]\s*\)\s*[;]?/ims',$corps, $r)) + { + $corps = $r[1] . substr($corps,strlen($r[0])); + $j=str_replace(' - ','-',ucwords(str_replace('-',' - ',$r[2]))); + $headers[$j] = $r[3]; + } + if (preg_match('/^<[?]php\s+[?]>\s*/', $corps, $r)) + $corps = substr($corps,strlen($r[0])); + return array('texte' => $corps, + 'squelette' => $nom, + 'process_ins' => ((strpos($corps,'<'.'?')=== false) ? 'html' : 'php'), + 'invalideurs' => $Cache, + 'entetes' => $headers); +} + ?> diff --git a/inc-compilo.php3 b/inc-compilo.php3 index 188e9db5ed..5a13048ea5 100644 --- a/inc-compilo.php3 +++ b/inc-compilo.php3 @@ -39,9 +39,6 @@ include_local("inc-compilo-api"); # definition des tables include_ecrire('inc_serialbase'); -// outils pour debugguer le compilateur -#include_local("inc-compilo-debug"); # desactive - // // Calculer un <INCLURE()> // @@ -385,7 +382,7 @@ function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') { join(" ,\n$tab", $codes) . "))"; } -function compile_cas($tableau, $descr, &$boucles, $id_boucle='') { +function compile_cas($tableau, $descr, &$boucles, $id_boucle) { $codes = array(); // cas de la boucle recursive if (is_array($id_boucle)) @@ -558,11 +555,12 @@ function code_boucle(&$boucles, $id, $nom) // Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment: // - 1er: element 'cache' => nom (du fichier ou` mettre la page) // - 2e: element 0 contenant un environnement ('id_article => $id_article, etc) -// Elle retourne alors un tableau de 4 e'le'ments: +// Elle retourne alors un tableau de 5 e'le'ments: // - 'texte' => page HTML, application du squelette a` l'environnement; // - 'squelette' => le nom du squelette // - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique // - 'invalideurs' => de'pendances de cette page, pour invalider son cache. +// - 'entetes' => tableau des entetes http // (voir son utilisation, optionnelle, dans invalideur.php) // En cas d'erreur, elle retourne un tableau des 2 premiers elements seulement @@ -690,14 +688,8 @@ function calculer_squelette($squelette, $nom, $gram, $sourcefile) { // Fonction principale du squelette $sourcefile // function $nom (\$Cache, \$Pile, \$doublons=array(), \$Numrows='', \$SP=0) { -\$t0 = $corps; - - return array( - 'texte' => \$t0, - 'squelette' => '$nom', - 'process_ins' => ((strpos(\$t0,'<'.'?')=== false) ? 'html' : 'php'), - 'invalideurs' => \$Cache - ); + + return analyse_resultat_skel('$nom', \$Cache, $corps); } ?".">"; diff --git a/inc-public-global.php3 b/inc-public-global.php3 index 04cdfd6fc6..59710dbca2 100644 --- a/inc-public-global.php3 +++ b/inc-public-global.php3 @@ -70,6 +70,7 @@ function calcule_header_et_page ($fond) { function obtenir_page_ancienne ($chemin_cache, $fond, $inclusion=false) { + global $lastmodified ; // // Lire le fichier cache // @@ -114,14 +115,18 @@ function is_preview() // calculer la page principale et envoyer les entetes // function afficher_page_globale ($fond) { - global $flag_dynamique, $flag_ob, $flag_preserver, - $lastmodified, $recherche, $use_cache, $var_mode, $var_preview; - global $_GET, $_POST, $_COOKIE, $_SERVER; + global $flag_dynamique, $flag_ob, $flag_preserver,$lastmodified, + $use_cache, $var_mode, $var_preview; + global $_COOKIE, $_SERVER; include_local("inc-cache"); // Peut-on utiliser un fichier cache ? $chemin_cache = determiner_cache($use_cache, NULL, $fond); + if ($chemin_cache) + $lastmodified = @filemtime($chemin_cache); + else + $lastmodified = time(); // demande de previsualisation ? // -> inc-calcul n'enregistrera pas les fichiers caches @@ -130,92 +135,109 @@ function afficher_page_globale ($fond) { $var_mode = 'recalcul'; $var_preview = true; spip_log('preview !'); - } else - $var_preview = false; + } else $var_preview = false; + + + $headers_only = ($_SERVER['REQUEST_METHOD'] == 'HEAD'); + + // une perennite valide a meme reponse qu'une requete HEAD - // Repondre gentiment aux requetes sympas - // (ici on ne tient pas compte d'une obsolence du cache ou des - // eventuels fichiers inclus modifies depuis la date - // HTTP_IF_MODIFIED_SINCE du client) if ($GLOBALS['HTTP_IF_MODIFIED_SINCE'] AND !$var_mode AND $chemin_cache AND !$flag_dynamique) { - $lastmodified = @filemtime($chemin_cache); - $headers_only = http_last_modified($lastmodified); + if (!preg_match(',IIS/,', $_SERVER['SERVER_SOFTWARE'])) { + $since = preg_replace('/;.*/', '', + $GLOBALS['HTTP_IF_MODIFIED_SINCE']); + $since = str_replace('GMT', '', $since); + if (trim($since) == http_gmoddate($lastmodified)) { + $status = 304; + $headers_only = true; + } + } } - $headers_only |= ($_SERVER['REQUEST_METHOD'] == 'HEAD'); + + // si le last-modified (mis + bas) est suffisant, ne meme pas mettre + // de content-type (pour contrer le bouton admin de inc-public) if ($headers_only) { - if ($chemin_cache) - $t = @filemtime($chemin_cache); - else - $t = time(); - @header('Last-Modified: '.http_gmoddate($t).' GMT'); - @header('Connection: close'); - // Pas de bouton admin pour un HEAD - $flag_preserver = true; - } - else { - // Obtenir la page + $page['entetes']["Connection"] = "close"; + } else { if (!$use_cache) $page = obtenir_page_ancienne ($chemin_cache, $fond, false); else { include_local('inc-calcul'); $page = calculer_page_globale ($chemin_cache, $fond); - if ($chemin_cache) creer_cache($page, $chemin_cache, $use_cache); } - } - if ($chemin_cache) $page['cache'] = $chemin_cache; + if ($chemin_cache) $page['cache'] = $chemin_cache; - if ($page['process_ins'] == 'php') { - if (!isset($flag_preserver)) - $flag_preserver = preg_match("/header\s*\(\s*.content\-type:/isx",$page['texte']); + // compatibilite. devrait pouvoir sauter + if ($page['process_ins'] == 'php') { + auto_content_type($page['texte']); + auto_expire($page['texte']); + } - $expire = preg_match("/header\s*\(\s*.Expire:([\s\d])*.\s*\)/is",$php, $r); - if (!isset($flag_dynamique)) - $flag_dynamique = $expire && (intval($r[1]) === 0); - } + $flag_preserver |= (headers_sent()); - if ($var_preview AND !$flag_preserver) { - include_ecrire('inc_minipres'); - $page['texte'] .= afficher_bouton_preview(); - } - // - // Envoyer les entetes appropries - // a condition d'etre sur de pouvoir le faire - // - if (!headers_sent() AND !$flag_preserver) { + // Definir les entetes si ce n'est fait - // Content-type: par defaut html+charset (poss surcharge par la suite) - header("Content-Type: text/html; charset=".$GLOBALS['meta']['charset']); + if (!$flag_preserver) { - if ($flag_ob) { - // Si la page est vide, produire l'erreur 404 - if (trim($page['texte']) === '' - AND $var_mode != 'debug') { - $page = message_erreur_404(); - } - // Interdire au client de cacher un login, un admin ou un recalcul - else if ($flag_dynamique OR $var_mode - OR $_COOKIE['spip_admin']) { - header("Cache-Control: no-cache,must-revalidate"); - header("Pragma: no-cache"); + if (!isset($page['entetes']['Content-Type'])) { + $page['entetes']['Content-Type'] = + "text/html; charset=" + . $GLOBALS['meta']['charset']; } - // Pour les autres donner l'heure de modif - else if ($lastmodified) { - header("Last-Modified: ".http_gmoddate($lastmodified)." GMT"); + if ($flag_ob) { + // Si la page est vide, produire l'erreur 404 + if (trim($page['texte']) === '' + AND $var_mode != 'debug') { + $page = message_erreur_404(); + $status = 404; + $flag_dynamique = true; + } + // pas de mise en cache pour les observateurs (et si pas deja indique) + if ($flag_dynamique + OR $_COOKIE['spip_admin'] + OR $var_mode) { + $page['entetes']["Cache-Control"]= "no-cache,must-revalidate"; + $page['entetes']["Pragma"] = "no-cache"; + } } } } + // toujours utile + $page['entetes']["Last-Modified"]=http_gmoddate($lastmodified)." GMT"; + $page['status'] = $status; + return $page; } +// +// 2 fonctions pour compatibilite arriere. Sont probablement superflues +// + +function auto_content_type($code) +{ + global $flag_preserver; + if (!isset($flag_preserver)) + $flag_preserver = preg_match("/header\s*\(\s*.content\-type:/isx",$code); +} + +function auto_expire($code) +{ + global $flag_dynamique; + if (!isset($flag_dynamique)) { + if (preg_match("/header\s*\(\s*.Expire:([\s\d])*.\s*\)/is",$code, $r)) + $flag_dynamique = (intval($r[1]) === 0); + } +} function inclure_page($fond, $contexte_inclus, $cache_incluant='') { + global $lastmodified; // Peut-on utiliser un fichier cache ? $chemin_cache = determiner_cache($use_cache, $contexte_inclus, $fond); @@ -242,7 +264,6 @@ function inclure_page($fond, $contexte_inclus, $cache_incluant='') { else { include_local('inc-calcul'); $page = cherche_page($chemin_cache, $contexte_inclus, $fond, false); - $page['signal']['process_ins'] = $page['process_ins']; $lastmodified = time(); if ($chemin_cache) creer_cache($page, $chemin_cache, $use_cache); } @@ -319,9 +340,6 @@ function message_erreur_404 ($erreur= "") { else if (isset($GLOBALS['id_syndic'])) $erreur = 'public:aucun_site'; } - include_ecrire('inc_headers'); - http_status(404); - return array('texte' => '<'.'?php $contexte_inclus = array("fond" => 404, "erreur" => _T("' . $erreur . '")); diff --git a/inc-public.php3 b/inc-public.php3 index 940d1c7d74..bd78c4f538 100644 --- a/inc-public.php3 +++ b/inc-public.php3 @@ -29,15 +29,29 @@ if (defined("_INC_PUBLIC")) { } include_local('inc-public-global'); - // Calculer la page en envoyant seulement les en-tetes, pas la page $tableau_des_erreurs = array(); $page = calcule_header_et_page ($fond); + if ($page['status']) { + include_ecrire('inc_headers'); + http_status($page['status']); + } + + foreach($page['entetes'] as $k => $v) + { header("$k: $v");} + + $html= preg_match(',^\s*text/html,',$page['entetes']['Content-Type']); + + if ($var_preview AND $html) { + include_ecrire('inc_minipres'); + $page['texte'] .= afficher_bouton_preview(); + } + // est-on admin ? - if ($affiche_boutons_admin = ( - (!$flag_preserver AND $GLOBALS['_COOKIE']['spip_admin']) - OR $var_mode == 'debug')) - include_local(find_in_path('inc-formulaire_admin'. _EXTENSION_PHP)); + if ($affiche_boutons_admin = ($_COOKIE['spip_admin'] + AND ($html OR ($var_mode == 'debug')))) + + include_local(find_in_path('inc-formulaire_admin'. _EXTENSION_PHP)); // Execution de la page calculee // 1. Cas d'une page contenant uniquement du HTML : @@ -94,7 +108,7 @@ if (defined("_INC_PUBLIC")) { } // Valider/indenter a la demande. garder la compatibilite tidy - if (trim($page) AND $xhtml AND !$flag_preserver AND !headers_sent()) { + if (trim($page) AND $xhtml AND $html AND !headers_sent()) { $f = include_fonction(($xhtml === true) ? 'tidy' : $xhtml); $page = $f($page); } diff --git a/spip_login.php3 b/spip_login.php3 index 43b850d2d3..2ac94163cb 100644 --- a/spip_login.php3 +++ b/spip_login.php3 @@ -12,8 +12,6 @@ $fond = "login"; $delais = 3600; -$flag_dynamique = true; -$flag_preserver = true; $forcer_lang = true; // Compatibilite anciennes versions de SPIP : si un 'var_url' (cible du login) -- GitLab