source: spip-zone/_plugins_/cachelab/trunk/inc/cachelab.php @ 112671

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

nouvelles actions get_html et get + petit ménage

File size: 10.0 KB
Line 
1<?php
2if (!defined('_ECRIRE_INC_VERSION')) {
3        return;
4}
5include_spip('public/cachelab_utils');
6
7//
8// Applique une action sur un cache donné
9//
10// Nécessite Mémoization (toutes méthodes OK).
11//
12// Renvoie un booléen indiquant si l'action a pu être appliquée ou non
13//
14function cachelab_applique ($action, $cle, $data=null, $options='', &$return=null) {
15global $Memoization;
16        if (!isset($Memoization) or !$Memoization) {
17                spip_log("cachelab_applique ($action, $cle...) : Memoization n'est pas activé", 'cachelab_erreur');
18                return false;
19        }
20
21static $len_prefix;
22        if (!$len_prefix)
23                $len_prefix = strlen(_CACHE_NAMESPACE);
24        $joliecle = substr($cle, $len_prefix);
25
26        switch ($action) {
27        case 'del' :
28                $del = $Memoization->del($joliecle);
29                if (!$del) {
30                        spip_log ("Échec 'del' $joliecle", 'cachelab');
31                        return false;
32                };
33                break;
34
35        // gérés par cachelab_cibler
36        case 'pass' :   // passe
37        case 'list' :   // renvoie les clés
38        case 'clean' :  // nettoie
39                break;
40               
41        case 'list_html' :      // renvoie les contenus indexés par les clés sans préfixes
42                                                // attention ça peut grossir !
43                if (!is_array($return))
44                        $return = array();
45                $return[$joliecle] = $data['texte'];
46                break;
47
48        case 'get' :    // renvoie le 1er cache ciblé
49                if (!$data)
50                        $data = $Memoization->get($joliecle);
51                $return = $data;
52                break;
53
54        case 'get_html' :       // renvoie le contenu du 1er cache
55                if (!$data)
56                        $data = $Memoization->get($joliecle);
57                $return = $data['texte'];
58                break;
59
60        default :
61                $f = 'cachelab_applique_'.$action;
62                if (function_exists($f))
63                        return $f($action, $cle, $data, $options, $return);
64                else {
65                        spip_log ("L'action $action n'est pas définie pour cachelab_applique", 'cachelab_erreur');
66                        return false;
67                };
68        }
69        return true;
70}
71
72function cachelab_filtre($action, $conditions=array(), $options=array()) {
73        spip_log ("cachelab_filtre obsolète avec $action, ".print_r($conditions, 1), "OBSOLETE_cachelab");
74        return cachelab_cibler ($action, $conditions, $options);
75}
76
77//
78// cachelab_cibler :
79//      applique une action donnée à tous les caches vérifiant certaines conditions
80//
81// uses apcu_cache_info()
82//      et donc nécessite que Memoization soit activé avec APC ou APCu
83//
84// renvoie :
85//      le résultat si c'est une action 'get' ou 'get_...'
86//      la liste des stats sinon, avec éventuellement la liste des résultats s'ils sont demandés (pour 'list_html'...)
87//
88function cachelab_cibler ($action, $conditions=array(), $options=array()) {
89global $Memoization;
90        if (!isset($Memoization) or !$Memoization or !in_array($Memoization->methode(), array('apc', 'apcu'))) {
91                spip_log("cachelab_cibler($action...) : le plugin Mémoization doit être activé avec APC ou APCu", 'cachelab_erreur');
92                die ("cachelab_cibler($action...) : le plugin Mémoization doit être activé avec APC ou APCu");
93        }
94        $return = null;
95
96        // filtrage
97        $session = (isset($conditions['session']) ? $conditions['session'] : null);
98        if ($session=='courante')
99                $session = spip_session();
100
101        $chemin = (isset($conditions['chemin']) ? $conditions['chemin'] : null);
102        $chemins = explode('|', $chemin); // sert seulement pour methode_chemin == strpos
103
104        $cle_objet = (isset($conditions['cle_objet']) ? $conditions['cle_objet'] : null);
105        $id_objet = (isset($conditions['id_objet']) ? $conditions['id_objet'] : null);
106        if ($cle_objet and !$id_objet) {
107                spip_log("cachelab_cibler : $cle_objet inconnu\n".print_r(debug_backtrace(),1), "cachelab_erreur");
108                $cle_objet=null;
109        }
110
111        if (isset($conditions['more']))                 // obsolète (todo : fix vieux codes appelant)
112                $conditions['plus'] = $conditions['more'];
113        // pour 'contexte' on simule un 'plus' pour donner un exemple d'extension
114        if (isset($conditions['contexte']) and $conditions['contexte'] and !isset($conditions['plus']))
115                $conditions['plus'] = 'contexte';
116        if ($plus = (isset($conditions['plus']) ? (string)$conditions['plus'] : '')) {
117                $plusfunc='cachelab_ciblercache_'.$plus;
118                // Signature nécessaire : $plusfunc ($action, $conditions, $options, &$stats)
119                if (!function_exists($plusfunc)) {
120                        spip_log ("La fonction '$plusfunc' n'est pas définie", 'cachelab_erreur');
121                        return;
122                }
123        }
124
125        // options
126        // explode+strpos par défaut pour les chemins
127        $methode_chemin = (isset ($options['methode_chemin']) ? $options['methode_chemin'] : 'strpos');
128        $partie_chemin = (isset ($options['partie_chemin']) ? $options['partie_chemin'] : 'tout');
129        // clean par défaut
130        $do_clean = (isset ($options['clean']) ? $options['clean'] : (!defined('CACHELAB_CLEAN') or CACHELAB_CLEAN)); 
131        // pas de listes par défaut
132        $do_lists = ($action == 'list') or (isset ($options['list']) and $options['list']);
133        // pas de chrono par défaut sauf si CACHELAB_CHRONO
134        $do_chrono = (isset ($options['chrono']) ? $options['chrono'] : (defined('CACHELAB_CHRONO') and CACHELAB_CHRONO)); 
135        if ($do_chrono) {
136                include_spip ('lib/microtime.inc');
137                microtime_do ('begin');
138        }
139
140        // retours
141        $stats=array();
142        $stats['nb_alien']=$stats['nb_candidats']=$stats['nb_clean']=$stats['nb_no_data']=$stats['nb_not_array']=$stats['nb_cible']=0;
143        $stats['l_no_data'] = $stats['l_not_array'] = $stats['l_cible'] = array();
144
145        // On y va
146        $cache = apcu_cache_info();
147        $meta_derniere_modif = lire_meta('derniere_modif');
148        $len_prefix = strlen(_CACHE_NAMESPACE);
149
150        foreach($cache['cache_list'] as $i => $d) {
151                // on "continue=passe au suivant" dés qu'on sait que le cache n'est pas cible
152
153                $cle = $d['info'];
154                $data=null;
155
156                // on saute les caches d'autres origines
157                // (et les caches d'un autre _CACHE_NAMESPACE pour ce même site)
158                if (strpos ($cle, _CACHE_NAMESPACE) !== 0) {
159                        $stats['nb_alien']++;
160                        continue;
161                }
162
163                // on ne veut examiner que les caches de squelettes SPIP
164                if (substr($cle, $len_prefix-1, 7) != ':cache:')
165                        continue;
166
167                // effacer ou sauter les caches invalidés par une invalidation totale
168                // ou que apcu ne suit plus
169                if ($meta_derniere_modif > $d['creation_time']
170                        or !apcu_exists($cle)) {
171                        if ($do_clean) {
172                                $del=$Memoization->del(substr($cle,$len_prefix));
173                                if (!$del)
174                                        spip_log ("Echec du clean du cache $cle (création : {$d['creation_time']}, invalidation : $meta_derniere_modif)", "cachelab_erreur");
175                                $stats['nb_clean']++;
176                        };
177                        continue;
178                }
179
180                // caches SPIP véritablement candidats
181                $stats['nb_candidats']++;
182
183                // 1er filtrage : par la session
184                if ($session) {
185                        if (substr ($cle, -9) != "_$session")
186                                continue;
187                }
188
189                // 2eme filtrage : par le chemin
190                if ($chemin) {
191                        switch ($partie_chemin) {
192                        case 'tout' :
193                        case 'chemin' :
194                                $partie_cle = $cle;
195                                break;
196                        case 'fichier' :
197                                $parties = explode('/', $cle);
198                                $partie_cle = array_pop($parties);
199                                break;
200                        case 'dossier' :
201                                $parties = explode('/', $cle);
202                                $parties = array_pop($parties);
203                                $partie_cle = array_pop($parties);
204                                break;
205                        default :
206                                spip_log ("Option partie_chemin incorrecte : '$partie_chemin'", 'cachelab_erreur');
207                                return;
208                        }
209                        // mémo php : « continue resumes execution just before the closing curly bracket ( } ), and break resumes execution just after the closing curly bracket. »
210                        switch ($methode_chemin) {
211                        case 'strpos' :
212                                foreach ($chemins as $unchemin)
213                                        if ($unchemin and (strpos ($partie_cle, $unchemin) !== false))
214                                                break 2;        // trouvé : sort du foreach et du switch et poursuit le test des autres conditions
215                                continue 2;      // échec : passe à la $cle suivante
216                        case 'regexp' :
217                                if ($chemin and ($danslechemin = preg_match(",$chemin,i", $partie_cle)))
218                                        break;  // trouvé : poursuit le test des autres conditions
219                                continue 2;     // échec : passe à la clé suivante
220                        default :
221                                spip_log ("Méthode '$methode_chemin' pas prévue pour le filtrage par le chemin", 'cachelab_erreur');
222                                return;
223                        };
224                }
225
226                // pour les filtres suivants on a besoin du contenu du cache
227                if ($cle_objet or $plusfunc) {
228                        global $Memoization;
229                        $data = $Memoization->get(substr($cle, $len_prefix));
230                        if (!$data) {
231                                $stats['nb_no_data']++;
232                                continue;
233                        }
234                        if (!is_array($data)) {
235                                spip_log ("clé=$cle : data n'est pas un tableau : ".print_r($data,1), 'cachelab');
236                                $stats['nb_not_array']++;
237                                if ($do_lists)
238                                        $stats['l_not_array'][] = $cle;
239                                continue;
240                        };
241                };
242
243                // 3eme filtre : par une valeur dans l'environnement
244                if ($cle_objet
245                        and (!isset ($data['contexte'][$cle_objet])
246                                or ($data['contexte'][$cle_objet]!=$id_objet)))
247                        continue;
248
249                // 4eme filtre : par une extension
250                if ($plusfunc
251                        and !$plusfunc ($action, $conditions, $options, $cle, $data, $stats))
252                        continue;
253
254                // restent les cibles
255                $stats['nb_cible']++;
256                if ($do_lists) 
257                        $stats['l_cible'][] = $cle;
258
259                cachelab_applique ($action, $cle, $data, $options, $return);
260
261                if ($return 
262                        and (($action=='get') 
263                                or (substr($action,0,4)=='get_')))
264                        return $return;
265        }
266
267        if ($do_chrono) {
268                $stats['chrono'] = microtime_do ('end', 'ms');
269                spip_log ("cachelab_cibler ($action, session=$session, objet $cle_objet=$id_objet, chemin=$chemin) : {$stats['nb_cible']} caches ciblés (sur {$stats['nb_candidats']}) en {$stats['chrono']} ms", 'cachelab');
270        }
271
272        if ($return)
273                $stats['retour'] = $return;
274        return $stats;
275}
276
277function controler_invalideur($action, $objets_invalidants=array()) {
278static $prev_derniere_modif_invalide;
279        switch($action) {
280        case 'stop' :
281                $objets_invalidants = array();
282                // nobreak;
283        case 'select' :
284                $prev_derniere_modif_invalide = $GLOBALS['derniere_modif_invalide'];
285                if (is_array($objets_invalidants))
286                        $GLOBALS['derniere_modif_invalide'] = $objets_invalidants;
287                break;
288        case 'go' :
289                $GLOBALS['derniere_modif_invalide'] = $prev_derniere_modif_invalide;
290                break;
291        }
292}
293
294//
295// Exemple d'extension utilisable avec 'plus'=>'contexte'
296// Filtrer non sur une seule valeur de l'environnement comme avec 'cle_objet'
297// mais sur un ensemble de valeurs spécifié par $conditions['contexte']
298// qui est un tableau de (clé, valeur)
299// Toutes les valeurs doivent être vérifiées dans l'environnement.
300//
301function cachelab_ciblercache_contexte($action, $conditions, $options, $cle, &$data, &$stats) {
302        if (!isset ($data['contexte'])
303                or !isset($conditions['contexte'])
304                or !is_array($conditions['contexte']))
305                return false;
306        $diff = array_diff_assoc($conditions['contexte'], $data['contexte']);
307        return empty($diff);
308}
Note: See TracBrowser for help on using the repository browser.