source: spip-zone/_plugins_/cachelab/trunk/public/cachelab_balises.php @ 112625

Last change on this file since 112625 was 112625, checked in by jluc@…, 2 years ago

#CACHE et var_cache n'ont pas besoin de mémoization - sf exception

File size: 10.8 KB
Line 
1<?php
2if (!defined('_ECRIRE_INC_VERSION')) {
3        return;
4}
5include_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 **/
53function 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//
169function 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//
209function 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//
253function 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
309function 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       
Note: See TracBrowser for help on using the repository browser.