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

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

Ajout d'une option pour décoder le contenu d'un fichier cache lors de la lecture, si la configuration le demande.

  • 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 = isset($cache['conservation']) ? $cache['conservation'] : $configuration['conservation'];
221                        if (($conservation > 0)
222                        and (!filemtime($fichier_cache) or (time() - filemtime($fichier_cache) > $conservation))) {
223                                $fichier_cache = '';
224                        }
225                }
226        }
227
228        return $fichier_cache;
229}
230
231
232/**
233 * Renvoie le chemin complet du cache sans tester son existence.
234 * Cette fonction est une encapsulation du service cache_cache_composer().
235 *
236 * @api
237 *
238 * @uses configuration_cache_lire()
239 * @uses cache_cache_composer()
240 *
241 * @param string $plugin
242 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
243 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
244 * @param array  $cache
245 *        Identifiant du cache sous la forme d'un tableau fournissant les composants canoniques du nom.
246 *
247 * @return string
248 */
249function cache_nommer($plugin, $cache) {
250
251        // Lecture de la configuration des caches du plugin.
252        $configuration = configuration_cache_lire($plugin);
253
254        // Le cache est toujours fourni sous la forme d'un tableau permettant de calculer le chemin complet.
255        $fichier_cache = '';
256        if (is_array($cache)) {
257                // Détermination du chemin du cache :
258                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
259                //   de la configuration du nom pour le plugin.
260                include_spip('cache/cache');
261                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
262        }
263
264        return $fichier_cache;
265}
266
267
268/**
269 * Supprime le cache spécifié par son identifiant relatif ou par son chemin complet.
270 *
271 * @api
272 *
273 * @uses configuration_cache_lire()
274 * @uses cache_cache_composer()
275 * @uses supprimer_fichier()
276 *
277 * @param string       $plugin
278 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
279 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
280 * @param array|string $cache
281 *        Identifiant du cache sous la forme d'une chaine (le chemin du fichier) ou d'un tableau fournissant
282 *        les composants canoniques du nom.
283 *
284 * @return bool
285 *         True si la suppression s'est bien passée, false sinon.
286 */
287function cache_supprimer($plugin, $cache) {
288
289        // Initialisation du contenu du cache
290        $cache_supprime = false;
291
292        // Lecture de la configuration des caches du plugin.
293        $configuration = configuration_cache_lire($plugin);
294
295        // Le cache peut-être fourni soit sous la forme d'un chemin complet soit sous la forme d'un
296        // tableau permettant de calculer le chemin complet. On prend en compte ces deux cas.
297        $fichier_cache = '';
298        if (is_array($cache)) {
299                // Détermination du chemin du cache :
300                // - le nom sans extension est construit à partir des éléments fournis sur le conteneur et
301                //   de la configuration du nom pour le plugin.
302                include_spip('cache/cache');
303                $fichier_cache = cache_cache_composer($plugin, $cache, $configuration);
304        } elseif (is_string($cache)) {
305                // Le chemin complet du fichier cache est fourni. Aucune vérification ne peut être faite
306                // il faut donc que l'appelant ait utilisé l'API cache_existe() pour calculer le fichier au préalable.
307                $fichier_cache = $cache;
308        }
309
310        // Détermination du nom du cache en fonction du plugin appelant et du type
311        if ($fichier_cache) {
312                // Lecture du fichier cache sécurisé ou pas suivant la configuration.
313                include_spip('inc/flock');
314                $cache_supprime = supprimer_fichier($fichier_cache);
315        }
316
317        return $cache_supprime;
318}
319
320
321/**
322 * Retourne la description des caches d'un plugin utilisateur filtrée sur un ensemble de critères. La description
323 * de base fournie par Cache Factory contient les éléments de l’identifiant relatif mais peut-être remplacée ou
324 * complétée par le plugin appelant au travers de services propres.
325 * Les filtres concernent uniquement les éléments de l’identifiant relatif.
326 *
327 * @api
328 *
329 * @uses configuration_cache_lire()
330 * @uses cache_cache_decomposer()
331 * @uses cache_cache_completer()
332 *
333 * @param string       $plugin
334 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
335 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
336 * @param array $filtres
337 *        Tableau associatif `[champ] = valeur` ou `[champ] = !valeur` de critères de filtres sur les composants
338 *        de caches. Les opérateurs égalité et inégalité sont possibles.
339 *
340 * @return array
341 *        Tableau des descriptions des fichiers cache créés par le plugin indexé par le chemin complet de
342 *        chaque fichier cache.
343 */
344function cache_repertorier($plugin, $filtres = array()) {
345
346        // Initialisation de la liste des caches
347        $caches = array();
348
349        // Lecture de la configuration des caches du plugin.
350        $configuration = configuration_cache_lire($plugin);
351
352        // Rechercher les caches du plugin sans appliquer de filtre si ce n'est sur le sous-dossier éventuellement.
353        // Les autres filtres seront appliqués sur les fichiers récupérés.
354        $pattern_fichier = constant($configuration['racine']) . $configuration['dossier_plugin'];
355        if ($configuration['sous_dossier']) {
356                if (array_key_exists('sous_dossier', $filtres)) {
357                        $pattern_fichier .= rtrim($filtres['sous_dossier'], '/') . '/';
358                } else {
359                        $pattern_fichier .= '*/';
360                }
361        }
362
363        // On complète le pattern avec une recherche d'un nom quelconque mais avec l'extension configurée.
364        $pattern_fichier .= '*' . $configuration['extension'];
365
366        // On recherche les fichiers correspondant au pattern.
367        $fichiers_cache = glob($pattern_fichier);
368
369        if ($fichiers_cache) {
370                foreach ($fichiers_cache as $_fichier_cache) {
371                        // On décompose le chemin de chaque cache afin de renvoyer l'identifiant canonique du cache.
372                        include_spip('cache/cache');
373                        $cache = cache_cache_decomposer($plugin, $_fichier_cache, $configuration);
374
375                        // Maintenant que les composants sont déterminés on applique les filtres pour savoir si on
376                        // complète et stocke le cache.
377                        $cache_conforme = true;
378                        foreach ($filtres as $_critere => $_valeur) {
379                                $operateur_egalite = true;
380                                $valeur = $_valeur;
381                                if (substr($_valeur, 0, 1) == '!') {
382                                        $operateur_egalite = false;
383                                        $valeur = ltrim($_valeur, '!');
384                                }
385                                if (isset($cache[$_critere])
386                                and (($operateur_egalite and ($cache[$_critere] != $valeur))
387                                        or (!$operateur_egalite and ($cache[$_critere] == $valeur)))) {
388                                        $cache_conforme = false;
389                                        break;
390                                }
391                        }
392
393                        if ($cache_conforme) {
394                                // On permet au plugin de completer la description canonique
395                                $cache = cache_cache_completer($plugin, $cache, $_fichier_cache, $configuration);
396
397                                // On stocke la description du fichier cache dans le tableau de sortie.
398                                $caches[$_fichier_cache] = $cache;
399                        }
400                }
401        }
402
403        return $caches;
404}
405
406
407/**
408 * Supprime, pour un plugin donné, les caches désignés par leur chemin complet.
409 *
410 * @api
411 *
412 * @uses supprimer_fichier()
413 *
414 * @param string $plugin
415 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
416 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
417 * @param array  $caches
418 *        Liste des fichiers caches désignés par leur chemin complet.
419 *
420 * @return bool
421 *         True si la suppression s'est bien passée, false sinon.
422 */
423function cache_vider($plugin, $caches) {
424
425        // Initialisation du retour
426        $cache_vide = false;
427
428        if ($caches) {
429                $fichiers_cache = is_string($caches) ? array($caches) : $caches;
430                include_spip('inc/flock');
431                foreach ($fichiers_cache as $_fichier) {
432                        supprimer_fichier($_fichier);
433                }
434                $cache_vide = true;
435        }
436       
437        return $cache_vide;
438}
439
440
441/**
442 * Lit la configuration standard des caches d'un plugin utilisateur ou de tous les plugins utilisateur
443 * ayant enregistrés une configuration.
444 *
445 * @api
446 *
447 * @uses lire_config()
448 * @uses cache_cache_configurer()
449 *
450 * @param string $plugin
451 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
452 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
453 *        Si vide, toutes les configurations sont fournies.
454 *
455 * @return array
456 *        Tableau de configuration des caches d'un plugin utilisateur ou tableau vide si aucune configuration n'est encore
457 *        enregistrée.
458 */
459function configuration_cache_lire($plugin = '') {
460
461        static $configuration = array();
462
463        // Retourner la configuration du plugin ou de tous les plugins utilisateur.
464        include_spip('inc/config');
465        if ($plugin) {
466                // Lecture de la configuration des caches du plugin. Si celle-ci n'existe pas encore elle est créée.
467                if (empty($configuration[$plugin]) and (!$configuration[$plugin] = lire_config("cache/${plugin}", array()))) {
468                        include_spip('cache/cache');
469                        $configuration[$plugin] = cache_cache_configurer($plugin);
470                }
471                $configuration_lue = $configuration[$plugin];
472        } else {
473                $configuration_lue = lire_config('cache', array());
474        }
475
476        return $configuration_lue;
477}
478
479
480/**
481 * Efface la configuration standard des caches d'un plugin utilisateur ou de tous les plugins utilisateur
482 * ayant enregistrés une configuration.
483 *
484 * @api
485 *
486 * @uses lire_config()
487 * @uses effacer_config()
488 *
489 * @param string $plugin
490 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier
491 *        ou un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
492 *        Si vide, toutes les configurations sont effacées.
493 *
494 * @return bool
495 *         True si la suppression s'est bien passée, false sinon.
496 */
497function configuration_cache_effacer($plugin = '') {
498
499        // Initialisation de la configuration à retourner
500        include_spip('inc/config');
501        $configuration_effacee = true;
502
503        if ($plugin) {
504                // Récupération de la meta du plugin Cache
505                $configuration_plugin = lire_config("cache/${plugin}", array());
506                if ($configuration_plugin) {
507                        effacer_config("cache/${plugin}");
508                } else {
509                        $configuration_effacee = false;
510                }
511        } else {
512                effacer_config('cache');
513        }
514
515        return $configuration_effacee;
516}
Note: See TracBrowser for help on using the repository browser.