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

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

#CACHE : syntaxe plus sympa pour les durées dynamiques et pour les filtres sur le cache. 'session' et 'log' sont implémentés comme filtres prédéfinis.

File size: 9.9 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 = $cache['source']; 
215        $source_file = str_replace(array('/','.'), '_', $source);
216        $arg=trim($arg);
217        if ($arg) {
218                if (strpos($arg, '/')) {
219                        $ij=explode('/',$arg);
220                        $c = $cache[$i=trim(array_shift($ij))];
221                        $c = $c[trim($j=array_shift($ij))];
222                }
223                else {
224                        $c = $cache[$arg];
225                }
226        }
227        else
228                $c = $cache;
229        spip_log ("cache[$arg] : ".print_r($c,1), "cachelab_".$source_file);
230}
231
232
233//
234// Assertions sur le fait que le cache est sessionné ou non
235// et que l'internaute est identifié ou non
236//
237// Arguments possibles : oui, non, login, anonyme, log
238// usages :
239// #CACHE{3600, session assert non} s'assure que les emplois sont non-sessionnés
240// #CACHE{session assert oui} s'assure que tous les emplois sont sessionnés
241// #CACHE{session assert login} s'assure que tous les emplois sont sessionnés avec un internaute identifié
242// #CACHE{session assert anonyme} s'assure que tous les emplois sans internaute identifié
243// Dans le cas où un assert n'est pas vérifié, un log est créé dans le fichier cachelab_assertsession
244//
245// Utile pour vérifier que le sessionnement se passe bien, et durablement, comme prévu
246// et optimiser avec un bon découpage des noisettes et avec macrosession
247//
248function cachelab_filtre_session (&$cache, $totarg) {
249        if (!is_array($cache) or !isset($cache['source']) or !isset($cache['lastmodified']) or !isset($cache['invalideurs'])) {
250                spip_log ("cachelab_filtre_assertsession ne reçoit pas un cache mais".print_r($cache,1), "cachelab_assert");
251                return null;
252        }
253        $source = $cache['source']; 
254        $source_file = str_replace(array('/','.'), '_', $source);
255        list($func, $what) = split_first_arg($totarg);
256       
257        $invalideurs = $cache['invalideurs'];
258
259        if (!isset($invalideurs['session']))
260                $sess = 'non';
261        elseif ($invalideurs['session'])
262                $sess = 'oui_login';
263        else
264                $sess = 'oui_anonyme';
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, login, 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 'debug' : // debug est OBSOLETE
288                spip_log ("#CACHE{session debug}", "cachelab_OBSOLETE");
289                // nobreak;
290        case 'insert' :
291                $cache['texte'] .= '<'."?php echo '<div class=\"debug cachelab\">$source_file sessionné : $sess</div>' ?>";
292                $cache['process_ins'] = 'php';
293                break;
294        case 'echo' :
295                echo "<div class='debug cachelab'>$source_file sessionné : $log</div>";
296                break;
297        case 'log' :
298                spip_log ("session : $sess", "cachelab_".$source_file);
299                break;
300        default : 
301                spip_log ("Syntaxe incorrecte dans $source_file : $func inconnu dans #CACHE{session $totarg}", 'cachelab_erreur');
302                break;
303        }
304}
Note: See TracBrowser for help on using the repository browser.