1 | <?php |
---|
2 | if (!defined('_ECRIRE_INC_VERSION')) { |
---|
3 | return; |
---|
4 | } |
---|
5 | include_spip('inc/cachelab_utils'); |
---|
6 | |
---|
7 | /** |
---|
8 | * Surcharge de la balise `#CACHE` definissant la durée de validité du cache du squelette |
---|
9 | * |
---|
10 | * Signature : `#CACHE{duree[,type]}` |
---|
11 | * |
---|
12 | * Le premier argument est la durée en seconde du cache. Le second |
---|
13 | * (par défaut `statique`) indique le type de cache : |
---|
14 | * |
---|
15 | * - `cache-client` autorise gestion du IF_MODIFIED_SINCE |
---|
16 | * - `statique` ne respecte pas l'invalidation par modif de la base |
---|
17 | * (mais s'invalide tout de même à l'expiration du delai) |
---|
18 | * - `calcul-methode` où la partie `methode` est variable et indique |
---|
19 | * la méthode de calcul dynamique de la durée cache à partir |
---|
20 | * de son contenu yc ses métadonnées et notamment l'env |
---|
21 | * Dans ce cas le 1er argument sert seulement pour compatibilité |
---|
22 | * si on désactive cachelab |
---|
23 | * |
---|
24 | * @balise |
---|
25 | * @see ecrire/public/cacher.php |
---|
26 | * @see memoization/public/cacher.php |
---|
27 | * @link http://www.spip.net/4330 |
---|
28 | * @examples |
---|
29 | * ``` |
---|
30 | * #CACHE{24*3600} |
---|
31 | * #CACHE{24*3600, cache-client} |
---|
32 | * #CACHE{0} pas de cache |
---|
33 | * ``` |
---|
34 | * + Extensions par cachelab : |
---|
35 | * ``` |
---|
36 | * #CACHE{3600,duree progressif} |
---|
37 | * #CACHE{session assert non} |
---|
38 | * #CACHE{24*3600, session} |
---|
39 | * #CACHE{log contexte} |
---|
40 | * #CACHE{log contexte/date_cration} |
---|
41 | * #CACHE{log,session anonyme} |
---|
42 | * ``` |
---|
43 | * @note |
---|
44 | * En absence de durée indiquée par cette balise, |
---|
45 | * la durée du cache est donnée |
---|
46 | * par la constante `_DUREE_CACHE_DEFAUT` |
---|
47 | * |
---|
48 | * @param Champ $p |
---|
49 | * Pile au niveau de la balise |
---|
50 | * @return Champ |
---|
51 | * Pile complétée par le code à générer |
---|
52 | **/ |
---|
53 | function balise_CACHE ($p) { |
---|
54 | if ($p->param) { |
---|
55 | $i = 0; |
---|
56 | |
---|
57 | $descr = $p->descr; |
---|
58 | $sourcefile = $descr['sourcefile']; |
---|
59 | $code = ''; |
---|
60 | |
---|
61 | $t = trim($p->param[0][1][0]->texte); |
---|
62 | if (preg_match(',^[0-9],', $t)) { |
---|
63 | ++$i; |
---|
64 | $duree = valeur_numerique($pd = $p->param[0][1][0]->texte); |
---|
65 | |
---|
66 | // noter la duree du cache dans un entete proprietaire |
---|
67 | $code = "'<'.'" . '?php header("X-Spip-Cache: ' |
---|
68 | . $duree |
---|
69 | . '"); ?' . "'.'>'"; |
---|
70 | |
---|
71 | // Remplir le header Cache-Control |
---|
72 | // cas #CACHE{0} |
---|
73 | if ($duree == 0) { |
---|
74 | $code .= ".'<'.'" |
---|
75 | . '?php header("Cache-Control: no-cache, must-revalidate"); ?' |
---|
76 | . "'.'><'.'" |
---|
77 | . '?php header("Pragma: no-cache"); ?' |
---|
78 | . "'.'>'"; |
---|
79 | } |
---|
80 | } |
---|
81 | |
---|
82 | // recuperer les parametres suivants |
---|
83 | // C'est analyse_resultat_skel qui transforme les headers du code en tableau $headers |
---|
84 | // S'il y a plusieurs fois la mm entete, seule la dernière valeur est retenue |
---|
85 | // |
---|
86 | while (isset($p->param[0][++$i])) { |
---|
87 | $pa = ($p->param[0][$i][0]->texte); |
---|
88 | |
---|
89 | if ($pa == 'cache-client' |
---|
90 | and $duree > 0 |
---|
91 | ) { |
---|
92 | $code .= ".'<'.'" . '?php header("Cache-Control: max-age=' |
---|
93 | . $duree |
---|
94 | . '"); ?' . "'.'>'"; |
---|
95 | // il semble logique, si on cache-client, de ne pas invalider |
---|
96 | $pa = 'statique'; |
---|
97 | } |
---|
98 | if ($pa == 'statique' |
---|
99 | and $duree > 0 |
---|
100 | ) { |
---|
101 | $code .= ".'<'.'" . '?php header("X-Spip-Statique: oui"); ?' . "'.'>'"; |
---|
102 | continue; |
---|
103 | } |
---|
104 | |
---|
105 | // il peut y avoir déjà eu, ou pas, du code |
---|
106 | $concat = (trim($code) ? '.' : ''); |
---|
107 | |
---|
108 | // ancienne syntaxe obsolète |
---|
109 | if (strpos($pa, 'duree-')===0) { |
---|
110 | $methode = substr($pa, 6); |
---|
111 | $ajout = "'<'.'" . '?php header("X-Spip-Methode-Duree-Cache: '.$methode.'"); ?' . "'.'>'"; |
---|
112 | $code .= $concat.$ajout; |
---|
113 | spip_log ("#CACHE($pa) sur $sourcefile avec méthode de calcul de la durée du cache : $methode", 'cachelab_OBSOLETE'); |
---|
114 | } |
---|
115 | |
---|
116 | if (strpos($pa, 'filtre-')===0) { |
---|
117 | $methode = substr($pa, 7); |
---|
118 | $ajout = "'<'.'" . '?php header("X-Spip-Filtre-Cache: '.$methode.'"); ?' . "'.'>'"; |
---|
119 | $code .= $concat.$ajout; |
---|
120 | spip_log ("#CACHE($pa) sur $sourcefile avec filtre sur le cache complet : $methode", 'cachelab_OBSOLETE'); |
---|
121 | } |
---|
122 | // fin des syntaxes obsolètes |
---|
123 | |
---|
124 | list ($func, $args) = split_first_arg ($pa); |
---|
125 | switch ($func) { |
---|
126 | // TODO : également traiter ici les morceaux du core traités plus haut |
---|
127 | case 'statique' : |
---|
128 | case 'duree' : |
---|
129 | $ajout = "'<'.'" . "?php header(\"X-Spip-Methode-Duree-Cache: $args\"); ?" . "'.'>'"; |
---|
130 | $code .= $concat.$ajout; |
---|
131 | spip_log ("#CACHE{$pa} sur $sourcefile avec méthode de calcul de la durée du cache : $args", 'cachelab'); |
---|
132 | break; |
---|
133 | |
---|
134 | case 'log' : |
---|
135 | case 'session' : |
---|
136 | case 'filtre' : |
---|
137 | $ajout = "'<'.'" . '?php header("X-Spip-Filtre-Cache: '.$pa.'"); ?' . "'.'>'"; |
---|
138 | $code .= $concat.$ajout; |
---|
139 | spip_log ("#CACHE{$pa} sur $sourcefile : filtre $func($args) sur le cache complet", 'cachelab'); |
---|
140 | break; |
---|
141 | default : |
---|
142 | break; |
---|
143 | } |
---|
144 | } |
---|
145 | } else { |
---|
146 | $code = "''"; |
---|
147 | } |
---|
148 | $p->code = $code; |
---|
149 | $p->interdire_scripts = false; |
---|
150 | |
---|
151 | return $p; |
---|
152 | } |
---|
153 | |
---|
154 | |
---|
155 | // |
---|
156 | // Calcul de durée de cache dynamique progressive |
---|
157 | // adapté pour un affichage approximatif et habituel |
---|
158 | // du type "il y a 20 secondes", "il y a 3 minutes", "ce matin", |
---|
159 | // "hier soir", "la semaine dernière" ou "il y a 3 mois" |
---|
160 | // |
---|
161 | // Renvoie une durée de cache trés courte pour les caches frais |
---|
162 | // et de plus en plus longue au fur et à mesure que le cache vieillit |
---|
163 | // Ainsi on peut écrire un filtre assurant un affichage approximatif |
---|
164 | // et permettre à la fois d'afficher "posté il y a 16 secondes", bien précis, |
---|
165 | // et "posté il y a 3 mois" ou "il y a 2 ans", bien suffisant en général. |
---|
166 | // |
---|
167 | // usage : #CACHE{3600, duree progapprox} ou #CACHE{3600, duree-progapprox date_naissance} |
---|
168 | // |
---|
169 | function cachelab_duree_progapprox($date_creation) { |
---|
170 | $dt_creation = new DateTime($date_creation); |
---|
171 | if (!$dt_creation) |
---|
172 | return _DUREE_CACHE_DEFAUT; |
---|
173 | |
---|
174 | $interval = $dt_creation->diff(new DateTime('NOW'),true); // valeur absolue |
---|
175 | if (!$interval) |
---|
176 | return _DUREE_CACHE_DEFAUT; |
---|
177 | if ($interval->y > 2) |
---|
178 | return 6*30*24*3600; // 6 mois si plus de 2 ans |
---|
179 | if ($interval->y) |
---|
180 | return 30*24*3600; // 1 mois si plus d'un an |
---|
181 | if ($interval->m) |
---|
182 | return 7*24*3600; // 1 semaine si plus d'un mois |
---|
183 | if ($interval->d > 7) |
---|
184 | return 24*3600; // 1 jour si plus d'une semaine |
---|
185 | if ($interval->d) |
---|
186 | return 6*3600; // 6h si plus d'un jour |
---|
187 | if ($interval->h > 6) |
---|
188 | return 3600; // 1h si plus de 6h |
---|
189 | if ($interval->h) |
---|
190 | return 30*60; // 1/2h si plus d'1h |
---|
191 | if ($interval->i > 10) |
---|
192 | return 10*60; // 10 minutes si plus de 10 minutes |
---|
193 | if ($interval->i) |
---|
194 | return 60; // chaque minute si plus d'une minute |
---|
195 | return 10; // 10secondes si moins d'une minute |
---|
196 | } |
---|
197 | |
---|
198 | // |
---|
199 | // Log tout ou un élément contenu par le tableau de cache |
---|
200 | // dans un fichier de log dont le nom reprend le chemin du squelette |
---|
201 | // (avec les / remplacés par des _) |
---|
202 | // |
---|
203 | // Exemples d'usages : |
---|
204 | // #CACHE{3600,log} : log tout le cache, méta et html |
---|
205 | // #CACHE{log lastmodified} : log l'entrée lastmodified du cache |
---|
206 | // #CACHE{log contexte} : log tout le tableau d'environnement |
---|
207 | // #CACHE{log contexte/date_creation} : log l'entrée 'date_creation' de l'environnement |
---|
208 | // |
---|
209 | function cachelab_filtre_log($cache, $arg) { |
---|
210 | if (!is_array($cache) or !isset($cache['source']) or !isset($cache['lastmodified']) or !isset($cache['invalideurs'])) { |
---|
211 | spip_log ("cachelab_duree_progapprox ne reçoit pas un cache mais".print_r($cache,1), "cachelab_assert"); |
---|
212 | return null; |
---|
213 | } |
---|
214 | $source_limace = slug_chemin($cache['source']); |
---|
215 | $arg=trim($arg); |
---|
216 | if ($arg) { |
---|
217 | if (strpos($arg, '/')) { #CACHE{log i/j} |
---|
218 | $ij=explode('/',$arg); |
---|
219 | $c = $cache[$i=trim(array_shift($ij))]; |
---|
220 | $c = $c[trim($j=array_shift($ij))]; |
---|
221 | } |
---|
222 | else { #CACHE{log i} |
---|
223 | $c = $cache[$arg]; |
---|
224 | } |
---|
225 | } |
---|
226 | else |
---|
227 | $c = $cache; #CACHE{log} |
---|
228 | spip_log ("cache[$arg] : ".print_r($c,1), "cachelab_".$source_limace); |
---|
229 | } |
---|
230 | |
---|
231 | |
---|
232 | // |
---|
233 | // Assertions sur le fait que le cache est sessionné ou non |
---|
234 | // et que l'internaute est identifié ou non |
---|
235 | // |
---|
236 | // usages : |
---|
237 | // 'assert' est utile pour vérifier que le sessionnement se passe bien comme prévu, et durablement, |
---|
238 | // et pour optimiser le découpage des noisettes et l'emploi de macrosession |
---|
239 | // On indique l'état théorique du sessionnement. |
---|
240 | // Les valeurs possibles sont : oui, oui_login, oui_anonyme, non, anonyme |
---|
241 | // Dans le cas où un assert n'est pas vérifié, un log est créé dans le fichier cachelab_assertsession |
---|
242 | // |
---|
243 | // #CACHE{3600, session assert non} s'assure que les emplois sont non-sessionnés |
---|
244 | // #CACHE{session assert oui} s'assure que tous les emplois sont sessionnés |
---|
245 | // #CACHE{session assert oui_login} s'assure que tous les emplois sont sessionnés avec un internaute identifié |
---|
246 | // #CACHE{session assert oui_anonyme} s'assure que tous les emplois sont sessionnés avec un internaute identifié (inutile ?) |
---|
247 | // #CACHE{session assert anonyme} s'assure que tous les emplois sans internaute identifié |
---|
248 | // |
---|
249 | // #CACHE{session log} loge l'état du sessionnement dans un cache dédié à ce squelette |
---|
250 | // #CACHE{session insert} insère à la fin du cache l'affichage de l'état du sessionnement |
---|
251 | // #CACHE{session echo} affiche l'état du sessionnement (comme var_mode=cache mais en permanence pour ce cache seulement) |
---|
252 | // |
---|
253 | function cachelab_filtre_session (&$cache, $totarg) { |
---|
254 | if (!is_array($cache) or !isset($cache['source']) or !isset($cache['lastmodified']) or !isset($cache['invalideurs'])) { |
---|
255 | spip_log ("cachelab_filtre_assertsession ne reçoit pas un cache mais".print_r($cache,1), "cachelab_assert"); |
---|
256 | return null; |
---|
257 | } |
---|
258 | $source = $cache['source']; |
---|
259 | $source_limace = slug_chemin($source); |
---|
260 | list($func, $what) = split_first_arg($totarg); |
---|
261 | |
---|
262 | $invalideurs = $cache['invalideurs']; |
---|
263 | |
---|
264 | $sess = cachelab_etat_sessionnement($invalideurs, 'avec_details'); |
---|
265 | |
---|
266 | switch ($func) { |
---|
267 | case 'assert' : |
---|
268 | switch($what) { |
---|
269 | case 'oui_login' : |
---|
270 | case 'oui_anonyme' : |
---|
271 | case 'non' : |
---|
272 | $ok = ($sess==$what); |
---|
273 | break; |
---|
274 | case 'anonyme' : |
---|
275 | $ok = empty($invalideurs['session']); // oui_anonyme ou non |
---|
276 | break; |
---|
277 | case 'oui' : |
---|
278 | $ok = isset($invalideurs['session']); // oui_anonyme ou oui_login |
---|
279 | break; |
---|
280 | default: |
---|
281 | spip_log ("Erreur de syntaxe : '$what' incorrect dans #CACHE{session $totarg}, il faut oui, oui_login, oui_anonyme, non ou anonyme", 'cachelab_erreur'); |
---|
282 | break 2; |
---|
283 | } |
---|
284 | if (!$ok) |
---|
285 | spip_log ("$source : session n'est pas '$what'. invalideurs=".print_r($invalideurs,1), "cachelab_assertsession"); |
---|
286 | break; |
---|
287 | case 'insert' : |
---|
288 | global $Memoization; |
---|
289 | if (!isset($Memoization)) { |
---|
290 | spip_log ("Erreur dans $source : #CACHE{session insert} nécessite que le plugin Memoization soit activé", 'cachelab_erreur'); |
---|
291 | echo "<div class='debug cachelab'><h6>Erreur dans $source : #CACHE{session insert} nécessite que le plugin Memoization soit activé</h6></div>"; |
---|
292 | break; |
---|
293 | } |
---|
294 | $cache['texte'] .= '<'."?php echo '<div class=\"debug cachelab\"><h6>$source sessionné : $sess</h6></div>' ?>"; |
---|
295 | $cache['process_ins'] = 'php'; |
---|
296 | break; |
---|
297 | case 'echo' : |
---|
298 | echo "<div class='debug cachelab'><h6>$source sessionné : $sess</h6></div>"; |
---|
299 | break; |
---|
300 | case 'log' : |
---|
301 | spip_log ('session : '.$sess, 'cachelab_session_'.$source_limace); |
---|
302 | break; |
---|
303 | default : |
---|
304 | spip_log ("Syntaxe incorrecte dans $source : $func inconnu dans #CACHE{session $totarg}", 'cachelab_erreur'); |
---|
305 | break; |
---|
306 | } |
---|
307 | } |
---|
308 | |
---|
309 | function cachelab_etat_sessionnement ($invalideurs, $detail=false) { |
---|
310 | if (!isset($invalideurs['session'])) |
---|
311 | return 'non'; |
---|
312 | if (!$detail) |
---|
313 | return 'oui'; |
---|
314 | elseif ($invalideurs['session']) |
---|
315 | return 'oui_login'; |
---|
316 | return 'oui_anonyme'; |
---|
317 | } |
---|
318 | |
---|
319 | |
---|