source: spip-zone/_plugins_/cache/trunk/inc/cache.php @ 118461

Last change on this file since 118461 was 118461, checked in by eric@…, 11 months ago

Micro amélioration d'un test sur l'identifiant du cache.

  • Property svn:eol-style set to native
File size: 18.0 KB
Line 
1<?php
2/**
3 * Ce fichier contient les fonctions d'API du plugin Cache Factory.
4 *
5 * @package SPIP\CACHE\API
6 */
7if (!defined('_ECRIRE_INC_VERSION')) {
8        return;
9}
10
11
12/**
13 * Ecrit un contenu donné dans un cache spécifié par son identifiant relatif ou par son chemin complet.
14 *
15 * @api
16 *
17 * @uses configuration_cache_lire()
18 * @uses cache_cache_composer()
19 * @uses sous_repertoire()
20 * @uses ecrire_fichier()
21 * @uses ecrire_fichier_securise()
22 *
23 * @param string       $plugin
24 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
25 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
26 * @param array|string $cache
27 *        Identifiant du cache sous la forme d'une chaine (le chemin du fichier) ou d'un tableau fournissant
28 *        les composants canoniques du nom.
29 * @param array|string $contenu
30 *        Contenu sous forme de tableau à sérialiser ou sous la forme d'une chaine.
31 *
32 * @return bool
33 *         True si l'écriture s'est bien passée, false sinon.
34 */
35function cache_ecrire($plugin, $cache, $contenu) {
36
37        // Initialisation du retour de la fonction
38        $cache_ecrit = false;
39       
40        // Lecture de la configuration des caches du plugin.
41        $configuration = configuration_cache_lire($plugin);
42
43        // Le cache peut-être fourni soit sous la forme d'un chemin complet soit sous la forme d'un
44        // tableau permettant de calculer le chemin complet. On prend en compte ces deux cas.
45        $fichier_cache = '';
46        if (is_array($cache)) {
47                // Vérification de la conformité entre la configuration et le sous-dossier du cache.
48                if (!$configuration['sous_dossier']
49                or ($configuration['sous_dossier'] and !empty($cache['sous_dossier']))) {
50                        // Détermination du chemin du cache si pas d'erreur sur le sous-dossier :
51                        // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
52                        //   de la configuration du nom pour le plugin.
53                        include_spip('cache/cache');
54                        $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
55                }
56        } elseif (is_string($cache)) {
57                // Le chemin complet du fichier cache est fourni. Aucune vérification ne peut être faite
58                // il faut donc que l'appelant ait utilisé l'API pour calculer le fichier au préalable.
59                $fichier_cache = $cache;
60        }
61       
62        if ($fichier_cache) {
63                // On crée les répertoires si besoin
64                include_spip('inc/flock');
65                $dir_cache = sous_repertoire(
66                        constant($configuration['racine']),
67                        rtrim($configuration['dossier_plugin'], '/')
68                );
69                if ($configuration['sous_dossier']) {
70                        sous_repertoire($dir_cache, rtrim($cache['sous_dossier'], '/'));
71                }
72
73                // Suivant que la configuration demande une sérialisation ou pas, on vérife le format du contenu
74                // de façon à toujours écrire une chaine.
75                $contenu_cache = '';
76                if ($configuration['serialisation']) {
77                        if (!is_array($contenu)) {
78                                $contenu = $contenu ? array($contenu) : array();
79                        }
80                        $contenu_cache = serialize($contenu);
81                } else {
82                        if (is_string($contenu)) {
83                                $contenu_cache = $contenu;
84                        }
85                }
86
87                // Ecriture du fichier cache sécurisé ou pas suivant la configuration.
88                $ecrire = 'ecrire_fichier';
89                if ($configuration['securisation']) {
90                        $ecrire = 'ecrire_fichier_securise';
91                }
92                $cache_ecrit = $ecrire($fichier_cache, $contenu_cache);
93        }
94       
95        return $cache_ecrit;
96}
97
98
99/**
100 * Lit le cache spécifié par son identifiant relatif ou son chemin complet et renvoie le contenu sous forme
101 * de tableau ou de chaine suivant l’attribut de sérialisation.
102 * En cas d’erreur, la fonction renvoie false.
103 *
104 * @api
105 *
106 * @uses configuration_cache_lire()
107 * @uses cache_cache_composer()
108 * @uses lire_fichier()
109 * @uses lire_fichier_securise()
110 *
111 * @param string       $plugin
112 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
113 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
114 * @param array|string $cache
115 *        Identifiant du cache sous la forme d'une chaine (le chemin du fichier) ou d'un tableau fournissant
116 *        les composants canoniques du nom.
117 *
118 * @return array|string|bool
119 *        Contenu du fichier sous la forme d'un tableau, d'une chaine ou false si une erreur s'est produite.
120 */
121function cache_lire($plugin, $cache) {
122
123        // Initialisation du contenu du cache
124        $cache_lu = false;
125
126        // Lecture de la configuration des caches du plugin.
127        $configuration = configuration_cache_lire($plugin);
128
129        // Le cache peut-être fourni soit sous la forme d'un chemin complet soit sous la forme d'un
130        // tableau permettant de calculer le chemin complet. On prend en compte ces deux cas.
131        $fichier_cache = '';
132        include_spip('cache/cache');
133        if (is_array($cache)) {
134                // Détermination du chemin du cache :
135                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
136                //   de la configuration du nom pour le plugin.
137                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
138        } elseif (is_string($cache)) {
139                // Le chemin complet du fichier cache est fourni. Aucune vérification ne peut être faite
140                // il faut donc que l'appelant ait utilisé l'API pour calculer le fichier au préalable.
141                $fichier_cache = $cache;
142        }
143
144        // Détermination du nom du cache en fonction du plugin appelant et du type
145        if ($fichier_cache) {
146                // Lecture du fichier cache sécurisé ou pas suivant la configuration.
147                include_spip('inc/flock');
148                $lire = 'lire_fichier';
149                if ($configuration['securisation']) {
150                        $lire = 'lire_fichier_securise';
151                }
152                $contenu_cache = '';
153                $lecture_ok = $lire($fichier_cache, $contenu_cache);
154               
155                if ($lecture_ok) {
156                        if ($configuration['serialisation']) {
157                                $cache_lu = unserialize($contenu_cache);
158                        } else {
159                                $cache_lu = $contenu_cache;
160                                if ($configuration['decodage']) {
161                                        $cache_lu = cache_cache_decoder($plugin, $cache_lu, $configuration);
162                                }
163                        }
164                }
165        }
166
167        return $cache_lu;
168}
169
170
171/**
172 * Teste l'existence d'un cache sur le disque spécifié par son identifiant relatif ou par son chemin complet et,
173 * si il existe, teste si la date d'expiration du fichier n'est pas dépassée. Si le fichier existe et n'est pas périmé,
174 * la fonction renvoie le chemin complet, sinon elle renvoie une chaine vide.
175 *
176 * @api
177 *
178 * @uses configuration_cache_lire()
179 * @uses cache_cache_composer()
180 *
181 * @param string       $plugin
182 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
183 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
184 * @param array|string $cache
185 *        Identifiant du cache sous la forme d'une chaine (le chemin du fichier) ou d'un tableau fournissant
186 *        les composants canoniques du nom.
187 *
188 * @return string
189 *         Le chemin complet du fichier si valide, la chaine vide sinon.
190 */
191function cache_est_valide($plugin, $cache) {
192
193        // Lecture de la configuration des caches du plugin.
194        $configuration = configuration_cache_lire($plugin);
195
196        // Le cache peut-être fourni soit sous la forme d'un chemin complet soit sous la forme d'un
197        // tableau permettant de calculer le chemin complet. On prend en compte ces deux cas.
198        $fichier_cache = '';
199        if (is_array($cache)) {
200                // Détermination du chemin du cache :
201                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
202                //   de la configuration du nom pour le plugin.
203                include_spip('cache/cache');
204                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
205        } elseif (is_string($cache)) {
206                // Le chemin complet du fichier cache est fourni. Aucune vérification ne peut être faite
207                // il faut donc que l'appelant ait utilisé l'API cache_existe() pour calculer le fichier au préalable.
208                $fichier_cache = $cache;
209        }
210
211        if ($fichier_cache) {
212                // Vérifier en premier lieu l'existence du fichier.
213                if (!file_exists($fichier_cache)) {
214                        $fichier_cache = '';
215                } else {
216                        // Vérifier la péremption ou pas du fichier.
217                        // -- un délai de conservation est configuré pour les caches du plugin utilisateur mais il possible
218                        //    de préciser un délai spécifique à un cache donné (index 'conservation' dans l'id du cache).
219                        // -- si le délai est à 0 cela correspond à un cache dont la durée de vie est infinie.
220                        $conservation = is_array($cache) and isset($cache['conservation'])
221                                ? $cache['conservation']
222                                : $configuration['conservation'];
223                        if (($conservation > 0)
224                        and (!filemtime($fichier_cache) or (time() - filemtime($fichier_cache) > $conservation))) {
225                                $fichier_cache = '';
226                        }
227                }
228        }
229
230        return $fichier_cache;
231}
232
233
234/**
235 * Renvoie le chemin complet du cache sans tester son existence.
236 * Cette fonction est une encapsulation du service cache_cache_composer().
237 *
238 * @api
239 *
240 * @uses configuration_cache_lire()
241 * @uses cache_cache_composer()
242 *
243 * @param string $plugin
244 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
245 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
246 * @param array  $cache
247 *        Identifiant du cache sous la forme d'un tableau fournissant les composants canoniques du nom.
248 *
249 * @return string
250 */
251function cache_nommer($plugin, $cache) {
252
253        // Lecture de la configuration des caches du plugin.
254        $configuration = configuration_cache_lire($plugin);
255
256        // Le cache est toujours fourni sous la forme d'un tableau permettant de calculer le chemin complet.
257        $fichier_cache = '';
258        if (is_array($cache)) {
259                // Détermination du chemin du cache :
260                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
261                //   de la configuration du nom pour le plugin.
262                include_spip('cache/cache');
263                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
264        }
265
266        return $fichier_cache;
267}
268
269
270/**
271 * Supprime le cache spécifié par son identifiant relatif ou par son chemin complet.
272 *
273 * @api
274 *
275 * @uses configuration_cache_lire()
276 * @uses cache_cache_composer()
277 * @uses supprimer_fichier()
278 *
279 * @param string       $plugin
280 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
281 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
282 * @param array|string $cache
283 *        Identifiant du cache sous la forme d'une chaine (le chemin du fichier) ou d'un tableau fournissant
284 *        les composants canoniques du nom.
285 *
286 * @return bool
287 *         True si la suppression s'est bien passée, false sinon.
288 */
289function cache_supprimer($plugin, $cache) {
290
291        // Initialisation du contenu du cache
292        $cache_supprime = false;
293
294        // Lecture de la configuration des caches du plugin.
295        $configuration = configuration_cache_lire($plugin);
296
297        // Le cache peut-être fourni soit sous la forme d'un chemin complet soit sous la forme d'un
298        // tableau permettant de calculer le chemin complet. On prend en compte ces deux cas.
299        $fichier_cache = '';
300        if (is_array($cache)) {
301                // Détermination du chemin du cache :
302                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
303                //   de la configuration du nom pour le plugin.
304                include_spip('cache/cache');
305                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
306        } elseif (is_string($cache)) {
307                // Le chemin complet du fichier cache est fourni. Aucune vérification ne peut être faite
308                // il faut donc que l'appelant ait utilisé l'API cache_existe() pour calculer le fichier au préalable.
309                $fichier_cache = $cache;
310        }
311
312        // Détermination du nom du cache en fonction du plugin appelant et du type
313        if ($fichier_cache) {
314                // Lecture du fichier cache sécurisé ou pas suivant la configuration.
315                include_spip('inc/flock');
316                $cache_supprime = supprimer_fichier($fichier_cache);
317        }
318
319        return $cache_supprime;
320}
321
322
323/**
324 * Retourne la description des caches d'un plugin utilisateur filtrée sur un ensemble de critères. La description
325 * de base fournie par Cache Factory contient les éléments de l’identifiant relatif mais peut-être remplacée ou
326 * complétée par le plugin appelant au travers de services propres.
327 * Les filtres concernent uniquement les éléments de l’identifiant relatif.
328 *
329 * @api
330 *
331 * @uses configuration_cache_lire()
332 * @uses cache_cache_decomposer()
333 * @uses cache_cache_completer()
334 *
335 * @param string       $plugin
336 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
337 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
338 * @param array $filtres
339 *        Tableau associatif `[champ] = valeur` ou `[champ] = !valeur` de critères de filtres sur les composants
340 *        de caches. Les opérateurs égalité et inégalité sont possibles.
341 *
342 * @return array
343 *        Tableau des descriptions des fichiers cache créés par le plugin indexé par le chemin complet de
344 *        chaque fichier cache.
345 */
346function cache_repertorier($plugin, $filtres = array()) {
347
348        // Initialisation de la liste des caches
349        $caches = array();
350
351        // Lecture de la configuration des caches du plugin.
352        $configuration = configuration_cache_lire($plugin);
353
354        // Rechercher les caches du plugin sans appliquer de filtre si ce n'est sur le sous-dossier éventuellement.
355        // Les autres filtres seront appliqués sur les fichiers récupérés.
356        $pattern_fichier = constant($configuration['racine']) . $configuration['dossier_plugin'];
357        if ($configuration['sous_dossier']) {
358                if (array_key_exists('sous_dossier', $filtres)) {
359                        $pattern_fichier .= rtrim($filtres['sous_dossier'], '/') . '/';
360                } else {
361                        $pattern_fichier .= '*/';
362                }
363        }
364
365        // On complète le pattern avec une recherche d'un nom quelconque mais avec l'extension configurée.
366        $pattern_fichier .= '*' . $configuration['extension'];
367
368        // On recherche les fichiers correspondant au pattern.
369        $fichiers_cache = glob($pattern_fichier);
370
371        if ($fichiers_cache) {
372                foreach ($fichiers_cache as $_fichier_cache) {
373                        // On décompose le chemin de chaque cache afin de renvoyer l'identifiant canonique du cache.
374                        include_spip('cache/cache');
375                        $cache = cache_cache_decomposer($plugin, $_fichier_cache, $configuration);
376
377                        // Maintenant que les composants sont déterminés on applique les filtres pour savoir si on
378                        // complète et stocke le cache.
379                        $cache_conforme = true;
380                        foreach ($filtres as $_critere => $_valeur) {
381                                $operateur_egalite = true;
382                                $valeur = $_valeur;
383                                if (substr($_valeur, 0, 1) == '!') {
384                                        $operateur_egalite = false;
385                                        $valeur = ltrim($_valeur, '!');
386                                }
387                                if (isset($cache[$_critere])
388                                and (($operateur_egalite and ($cache[$_critere] != $valeur))
389                                        or (!$operateur_egalite and ($cache[$_critere] == $valeur)))) {
390                                        $cache_conforme = false;
391                                        break;
392                                }
393                        }
394
395                        if ($cache_conforme) {
396                                // On permet au plugin de completer la description canonique
397                                $cache = cache_cache_completer($plugin, $cache, $_fichier_cache, $configuration);
398
399                                // On stocke la description du fichier cache dans le tableau de sortie.
400                                $caches[$_fichier_cache] = $cache;
401                        }
402                }
403        }
404
405        return $caches;
406}
407
408
409/**
410 * Supprime, pour un plugin donné, les caches désignés par leur chemin complet.
411 *
412 * @api
413 *
414 * @uses supprimer_fichier()
415 *
416 * @param string $plugin
417 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
418 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
419 * @param array  $caches
420 *        Liste des fichiers caches désignés par leur chemin complet.
421 *
422 * @return bool
423 *         True si la suppression s'est bien passée, false sinon.
424 */
425function cache_vider($plugin, $caches) {
426
427        // Initialisation du retour
428        $cache_vide = false;
429
430        if ($caches) {
431                $fichiers_cache = is_string($caches) ? array($caches) : $caches;
432                include_spip('inc/flock');
433                foreach ($fichiers_cache as $_fichier) {
434                        supprimer_fichier($_fichier);
435                }
436                $cache_vide = true;
437        }
438       
439        return $cache_vide;
440}
441
442
443/**
444 * Lit la configuration standard des caches d'un plugin utilisateur ou de tous les plugins utilisateur
445 * ayant enregistrés une configuration.
446 *
447 * @api
448 *
449 * @uses lire_config()
450 * @uses cache_cache_configurer()
451 *
452 * @param string $plugin
453 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
454 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
455 *        Si vide, toutes les configurations sont fournies.
456 *
457 * @return array
458 *        Tableau de configuration des caches d'un plugin utilisateur ou tableau vide si aucune configuration n'est encore
459 *        enregistrée.
460 */
461function configuration_cache_lire($plugin = '') {
462
463        static $configuration = array();
464
465        // Retourner la configuration du plugin ou de tous les plugins utilisateur.
466        include_spip('inc/config');
467        if ($plugin) {
468                // Lecture de la configuration des caches du plugin. Si celle-ci n'existe pas encore elle est créée.
469                if (empty($configuration[$plugin]) and (!$configuration[$plugin] = lire_config("cache/${plugin}", array()))) {
470                        include_spip('cache/cache');
471                        $configuration[$plugin] = cache_cache_configurer($plugin);
472                }
473                $configuration_lue = $configuration[$plugin];
474        } else {
475                $configuration_lue = lire_config('cache', array());
476        }
477
478        return $configuration_lue;
479}
480
481
482/**
483 * Efface la configuration standard des caches d'un plugin utilisateur ou de tous les plugins utilisateur
484 * ayant enregistrés une configuration.
485 *
486 * @api
487 *
488 * @uses lire_config()
489 * @uses effacer_config()
490 *
491 * @param string $plugin
492 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
493 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
494 *        Si vide, toutes les configurations sont effacées.
495 *
496 * @return bool
497 *         True si la suppression s'est bien passée, false sinon.
498 */
499function configuration_cache_effacer($plugin = '') {
500
501        // Initialisation de la configuration à retourner
502        include_spip('inc/config');
503        $configuration_effacee = true;
504
505        if ($plugin) {
506                // Récupération de la meta du plugin Cache
507                $configuration_plugin = lire_config("cache/${plugin}", array());
508                if ($configuration_plugin) {
509                        effacer_config("cache/${plugin}");
510                } else {
511                        $configuration_effacee = false;
512                }
513        } else {
514                effacer_config('cache');
515        }
516
517        return $configuration_effacee;
518}
Note: See TracBrowser for help on using the repository browser.