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

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

nouveaux arguments de #CACHE{filtre-assertsession ...} : echo et debug. Il est probable qu'on proposera +tard d'autres syntaxes plus sympa

File size: 8.7 KB
Line 
1<?php
2
3/**
4 * Surcharge de la balise `#CACHE` definissant la durée de validité du cache du squelette
5 *
6 * Signature : `#CACHE{duree[,type]}`
7 *
8 * Le premier argument est la durée en seconde du cache. Le second
9 * (par défaut `statique`) indique le type de cache :
10 *
11 * - `cache-client` autorise gestion du IF_MODIFIED_SINCE
12 * - `statique` ne respecte pas l'invalidation par modif de la base
13 *   (mais s'invalide tout de même à l'expiration du delai)
14 * - `calcul-methode` où la partie `methode` est variable et indique
15 *    la méthode de calcul dynamique de la durée cache à partir
16 *    de son contenu yc ses métadonnées et notamment l'env
17 *    Dans ce cas le 1er argument sert seulement pour compatibilité
18 *    si on désactive cachelab
19 *
20 * @balise
21 * @see ecrire/public/cacher.php
22 * @see memoization/public/cacher.php
23 * @link http://www.spip.net/4330
24 * @example
25 *     ```
26 *     #CACHE{24*3600}
27 *     #CACHE{24*3600, cache-client}
28 *     #CACHE{0} pas de cache
29 *     #CACHE{3600,calcul-progressif}
30 *     ```
31 * @note
32 *   En absence de cette balise la durée du cache est donnée
33 *   par la constante `_DUREE_CACHE_DEFAUT`
34 *
35 * @param Champ $p
36 *     Pile au niveau de la balise
37 * @return Champ
38 *     Pile complétée par le code à générer
39 **/
40function balise_CACHE ($p) {
41        if ($p->param) {
42                $i = 0;
43
44                $descr = $p->descr;
45                $sourcefile = $descr['sourcefile'];
46
47                $t = trim($p->param[0][1][0]->texte);
48                if (preg_match(',^[0-9],', $t)) {
49                        ++$i;
50                        $duree = valeur_numerique($pd = $p->param[0][1][0]->texte);
51
52                        // noter la duree du cache dans un entete proprietaire
53                        $code = "'<'.'" . '?php header("X-Spip-Cache: '
54                                . $duree
55                                . '"); ?' . "'.'>'";
56
57                        // Remplir le header Cache-Control
58                        // cas #CACHE{0}
59                        if ($duree == 0) {
60                                $code .= ".'<'.'"
61                                        . '?php header("Cache-Control: no-cache, must-revalidate"); ?'
62                                        . "'.'><'.'"
63                                        . '?php header("Pragma: no-cache"); ?'
64                                        . "'.'>'";
65                        }
66                }
67
68                // recuperer les parametres suivants
69                // C'est analyse_resultat_skel qui transforme les headers du code en tableau $headers
70                // S'il y a plusieurs fois la mm entete, seule la dernière valeur est retenue
71                //
72                while (isset($p->param[0][++$i])) {
73                        $pa = ($p->param[0][$i][0]->texte);
74
75                        if ($pa == 'cache-client'
76                                and $duree > 0
77                        ) {
78                                $code .= ".'<'.'" . '?php header("Cache-Control: max-age='
79                                        . $duree
80                                        . '"); ?' . "'.'>'";
81                                // il semble logique, si on cache-client, de ne pas invalider
82                                $pa = 'statique';
83                        }
84
85                        if ($pa == 'statique'
86                                and $duree > 0
87                        ) {
88                                $code .= ".'<'.'" . '?php header("X-Spip-Statique: oui"); ?' . "'.'>'";
89                        }
90
91                        $concat = (trim($code) ? '.' : '');
92
93                        if (strpos($pa, 'duree-')===0) {
94                                $methode = substr($pa, 6);
95                                $ajout = "'<'.'" . '?php header("X-Spip-Methode-Duree-Cache: '.$methode.'"); ?' . "'.'>'";
96                                $code .= $concat.$ajout;
97                                spip_log ("#CACHE $sourcefile avec méthode de calcul de la durée du cache : $methode", 'cachelab');
98                        }
99
100                        if (strpos($pa, 'filtre-')===0) {
101                                $methode = substr($pa, 7); 
102                                $ajout = "'<'.'" . '?php header("X-Spip-Filtre-Cache: '.$methode.'"); ?' . "'.'>'";
103                                $code .= $concat.$ajout; 
104                                spip_log ("#CACHE $sourcefile avec filtre sur le cache complet : $methode", 'cachelab');
105                        }
106                }
107        } else {
108                $code = "''";
109        }
110        $p->code = $code;
111        $p->interdire_scripts = false;
112
113        return $p;
114}
115
116
117//
118// Calcul de durée de cache dynamique progressive
119// adapté pour un affichage approximatif et habituel
120// du type "il y a 20 secondes", "il y a 3 minutes", "ce matin",
121// "hier soir", "la semaine dernière" ou "il y a 3 mois"
122//
123// Renvoie une durée de cache trés courte pour les caches frais
124// et de plus en plus longue au fur et à mesure que le cache vieillit
125// Ainsi on peut écrire un filtre assurant un affichage approximatif
126// et permettre à la fois d'afficher "posté il y a 16 secondes", bien précis,
127// et "posté il y a 3 mois" ou "il y a 2 ans", bien suffisant en général.
128//
129// usage : #CACHE{3600, duree-progapprox} ou #CACHE{3600, duree-progapprox date_naissance}
130//
131function cachelab_duree_progapprox($date_creation) {
132        $dt_creation = new DateTime($date_creation);
133        if (!$dt_creation)
134                return _DUREE_CACHE_DEFAUT;
135
136        $interval = $dt_creation->diff(new DateTime('NOW'),true); // valeur absolue
137        if (!$interval)
138                return _DUREE_CACHE_DEFAUT;
139        if ($interval->y > 2)
140                return 6*30*24*3600; // 6 mois si plus de 2 ans
141        if ($interval->y)
142                return 30*24*3600;      // 1 mois si plus d'un an
143        if ($interval->m)
144                return 7*24*3600;       // 1 semaine si plus d'un mois
145        if ($interval->d > 7)
146                return 24*3600;         // 1 jour si plus d'une semaine
147        if ($interval->d)
148                return 6*3600;          // 6h si plus d'un jour
149        if ($interval->h > 6)
150                return 3600;            // 1h si plus de 6h
151        if ($interval->h)
152                return 30*60;           // 1/2h si plus d'1h
153        if ($interval->i > 10)
154                return 10*60;           // 10 minutes si plus de 10 minutes
155        if ($interval->i)
156                return 60;                      // chaque minute si plus d'une minute
157        return 10;                              // 10secondes si moins d'une minute
158}
159
160//
161// Log tout ou un élément contenu par le tableau de cache
162// dans un fichier de log dont le nom reprend le chemin du squelette
163// (avec les / remplacés par des _)
164//
165// Exemples d'usages :
166//      #CACHE{3600, filtre-log} : log tout le cache, méta et html
167//      #CACHE{filtre-log lastmodified}  : log l'entrée lastmodified du cache
168//      #CACHE{filtre-log contexte} : log tout le tableau d'environnement
169//  #CACHE{filtre-log contexte/date_creation} : log l'entrée 'date_creation' de l'environnement
170//
171function cachelab_filtre_log($cache, $arg) {
172        if (!is_array($cache) or !isset($cache['source']) or !isset($cache['lastmodified']) or !isset($cache['invalideurs'])) {
173                spip_log ("cachelab_duree_progapprox ne reçoit pas un cache mais".print_r($cache,1), "cachelab_assert");
174                return null;
175        }
176        $source = $cache['source']; 
177        $source_file = str_replace(array('/','.'), '_', $source);
178        $arg=trim($arg);
179        if ($arg) {
180                if (strpos($arg, '/')) {
181                        $ij=explode('/',$arg);
182                        $c = $cache[$i=trim(array_shift($ij))];
183                        $c = $c[trim($j=array_shift($ij))];
184                }
185                else {
186                        $c = $cache[$arg];
187                }
188        }
189        else
190                $c = $cache;
191        spip_log ("cache[$arg] : ".print_r($c,1), "cachelab_".$source_file);
192}
193
194//
195// Assertions sur le fait que le cache est sessionné ou non
196// et que l'internaute est identifié ou non
197//
198// Arguments possibles : oui, non, login, anonyme, log
199// usages :
200// #CACHE{3600, filtre-assertsession non} s'assure que les emplois sont non-sessionnés
201// #CACHE{filtre-assertsession oui} s'assure que tous les emplois sont sessionnés
202// #CACHE{filtre-assertsession login} s'assure que tous les emplois sont sessionnés avec un internaute identifié
203// #CACHE{filtre-assertsession anonyme} s'assure que tous les emplois sans internaute identifié
204// Dans le cas où un assert n'est pas vérifié, un log est créé dans le fichier cachelab_assertsession
205//
206// Une dernière valeur de l'argument n'induit pas une assertion mais un log :
207// #CACHE{filtre-assertsession log} crée un log avec l'état de la session pour chaque instance du cache
208//
209// Utile pour optimiser avec plugin macrosession et vérifier que ça se passe bien, et durablement, comme prévu
210//
211function cachelab_filtre_assertsession (&$cache, $arg) {
212        if (!is_array($cache) or !isset($cache['source']) or !isset($cache['lastmodified']) or !isset($cache['invalideurs'])) {
213                spip_log ("cachelab_filtre_assertsession ne reçoit pas un cache mais".print_r($cache,1), "cachelab_assert");
214                return null;
215        }
216        $source = $cache['source']; 
217        $source_file = str_replace(array('/','.'), '_', $source);
218        $arg=trim($arg);
219       
220        $invalideurs = $cache['invalideurs'];
221
222        // on teste l'invalideur session
223        // On pourrait aussi tester par le nom du cache avec '/_([0-9a-f]{8}|)$/i' ?
224
225        switch ($arg) {
226        case 'login' :
227                $ok = !empty($invalideurs['session']); // def et non vide
228                break;
229        case 'anonyme' :
230                $ok = empty($invalideurs['session']);   // undef ou vide
231                break;
232        case 'oui' :
233                $ok = isset($invalideurs['session']);   // défini, mais peut être vide
234                break;
235        case 'non' :
236                $ok = !isset($invalideurs['session']);  // non défini
237                break;
238        case 'debug' :
239        case 'echo' :
240        case 'log' :
241                if (!isset($invalideurs['session']))
242                        $log = 'non';
243                elseif ($invalideurs['session'])
244                        $log = 'oui_login';
245                else
246                        $log = 'oui_anonyme';
247                $ok = true;
248                switch ($arg) {
249                case 'log' :
250                        spip_log ("session ? $log", "cachelab_".$source_file);
251                        break;
252                case 'echo' :
253                        echo "<div class='debug cachelab'>$source_file sessionné ? $log</div>";
254                        break;
255                case 'debug' :
256                        $cache['texte'] .= '<'."?php echo '<div class=\"debug cachelab\" style=\"background-color:yellow\">$source_file sessionné ? $log</div>' ?>";
257                        $cache['process_ins'] = 'php';
258                        break;
259                };
260        default:
261                $ok = false;
262                $arg .= " : valeur incorrecte";
263                break;
264        }
265        if (!$ok)
266                spip_log ("$source : assertsession n'est pas '$arg'. invalideurs=".print_r($invalideurs,1), "cachelab_assertsession");
267}
Note: See TracBrowser for help on using the repository browser.