diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 321efffb22539eaa18b82094138f9c8e5b5a8a9d..5410e761e7fa009bf8d9383f64d07da4c36b4c93 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -1389,6 +1389,28 @@ function lang_select ($lang=NULL) {
 	changer_langue($lang);
 	return $lang;
 }
+
+
+// Renvoie une chaine qui decrit la session courante pour savoir si on peut
+// utiliser un cache enregistre pour cette session.
+// Par convention cette chaine ne doit pas contenir de caracteres [^0-9A-Za-z]
+// Attention on ne peut *pas* inferer id_auteur a partir de la session, qui
+// pourrait etre une chaine arbitraire -- ce n'est pas le cas pour l'instant
+// http://doc.spip.org/@spip_session
+function spip_session() {
+	static $session;
+	if (!isset($session)) {
+		$session = $GLOBALS['auteur_session']
+			? 'session'
+				.$GLOBALS['auteur_session']['id_auteur']
+				.'_'
+				.$_COOKIE['spip_session']
+			: '';
+	}
+	#spip_log('session: '.$session);
+	return $session;
+}
+
 //
 // Aide, aussi depuis l'espace prive a present.
 //  Surchargeable mais pas d'ereur fatale si indisponible.
diff --git a/ecrire/public/balises.php b/ecrire/public/balises.php
index c2b44d5d4c5c596b44b4608b3f71f4a9bc9b5612..8660652853be296fc9728ea7f97057d3640e967b 100644
--- a/ecrire/public/balises.php
+++ b/ecrire/public/balises.php
@@ -998,6 +998,8 @@ function balise_CHEMIN_dist($p) {
 //
 // La syntaxe #ENV{toto, rempl} renverra 'rempl' si $toto est vide
 //
+// Si le tableau est vide on renvoie '' (utile pour #SESSION)
+//
 // http://doc.spip.org/@balise_ENV_dist
 function balise_ENV_dist($p, $src = NULL) {
 	// le tableau de base de la balise (cf #META ci-dessous)
@@ -1009,13 +1011,15 @@ function balise_ENV_dist($p, $src = NULL) {
 	if (!$_nom) {
 		// cas de #ENV sans argument : on retourne le serialize() du tableau
 		// une belle fonction [(#ENV|affiche_env)] serait pratique
-		$p->code = 'serialize('.$src.')';
+		$p->code = "($src ? serialize($src) : '')";
 	} else {
 		// admet deux arguments : nom de variable, valeur par defaut si vide
-		$p->code = $src."[$_nom]";
+		$p->code = 'is_array('.$src.') ? '.$src.'['.$_nom.'] : ""';
 		if ($_sinon)
 			$p->code = 'sinon('. 
 				$p->code.",$_sinon)";
+		else
+			$p->code = '('.$p->code.')';
 	}
 	#$p->interdire_scripts = true;
 
@@ -1039,6 +1043,23 @@ function balise_CONFIG_dist($p) {
 		return balise_ENV_dist($p, '$GLOBALS["meta"]');
 }
 
+//
+// #SESSION
+// Cette balise est un tableau des donnees du visiteur (nom, email etc)
+// Si elle est invoquee, elle leve un drapeau dans le fichier cache, qui
+// permet a public/cacher d'invalider le cache si le visiteur suivant n'a
+// pas la meme session
+function balise_SESSION_dist($p) {
+	$p->descr['session'] = true;
+
+	$f = function_exists('balise_ENV')
+		? 'balise_ENV'
+		: 'balise_ENV_dist';
+
+	$p = $f($p, '$GLOBALS["auteur_session"]');
+	return $p;
+}
+
 
 //
 // #EVAL{...}
diff --git a/ecrire/public/cacher.php b/ecrire/public/cacher.php
index 3987807fa0a4484eba342cb8e06bd1837f62cfea..57bdf404a22496f0f06f742f028ef3f367573205 100644
--- a/ecrire/public/cacher.php
+++ b/ecrire/public/cacher.php
@@ -99,6 +99,15 @@ function cache_valide(&$page, $date) {
 		return 1;
 	}
 
+	// Si la page a un invalideur de session 'zz', on ignore le cache
+	// si le visiteur n'a pas la meme session 'zz'
+	if (isset($page['invalideurs'])
+	AND isset($page['invalideurs']['session'])
+	AND $page['invalideurs']['session'] != spip_session()) {
+		#spip_log('Session: \''.$page['invalideurs']['session'] . '\' != \''.spip_session().'\'');
+		return 1;
+	}
+
 	// Sinon comparer l'age du fichier a sa duree de cache
 	$duree = intval($page['entetes']['X-Spip-Cache']);
 	if ($duree == 0)  #CACHE{0}
diff --git a/ecrire/public/references.php b/ecrire/public/references.php
index abae7b36700fa6509b3673afe30afad342ccf1ad..df8fde1a025bea1dbdf01ad31ea053156e76f603 100644
--- a/ecrire/public/references.php
+++ b/ecrire/public/references.php
@@ -439,6 +439,12 @@ function applique_filtres($p) {
 	if ($p->param)
 		$code = compose_filtres($p, $code);
 
+	// S'il y a un lien avec la session, ajouter un code qui levera
+	// un drapeau dans la structure d'invalidation $Cache
+	if ($p->descr['session'])
+		$code = "$code
+		. (!\$Cache['session']=true) // invalideur session\n		";
+
 	// ramasser les images intermediaires inutiles et graver l'image finale
 	if ($p->ramasser_miettes)
 		$code = "filtrer('image_graver',$code)";