source: spip-zone/_plugins_/memoization/public/cacher.php @ 65792

Last change on this file since 65792 was 65792, checked in by cedric@…, 8 years ago

Complement a r64364 pour etre strictement equivalent a avant (ne pas bugguer sur le cas $cfgpages? = null; par exemple)
Au passage on decouvre cette option qui permet donc de spécifier une méthode de memoization spécifique au cache SPIP

File size: 12.0 KB
Line 
1<?php
2
3/***************************************************************************\
4 *  SPIP, Systeme de publication pour l'internet                           *
5 *                                                                         *
6 *  Copyright (c) 2001-2010                                                *
7 *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
8 *                                                                         *
9 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
10 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
11\***************************************************************************/
12
13if (!defined("_ECRIRE_INC_VERSION")) return;
14
15/* compat SPIP 1.9 */
16if(!function_exists('test_espace_prive')) {
17        function test_espace_prive() {
18                return !!_DIR_RACINE;
19        }
20}
21
22
23// http://doc.spip.org/@generer_nom_fichier_cache
24function generer_nom_fichier_cache($contexte, $page) {
25        // l'indicateur sert a savoir un peu de quoi il s'agit
26        // quand on regarde dans le cache ; on le met a la fin
27        // du nom pour que ca "melange" mieux sous memcache
28        $indicateur = is_array($page)
29                ? $page['contexte_implicite']['cache'] # SPIP 2.1
30                : strval($page); # SPIP 2.0 ou autre
31
32        return
33                md5(var_export(array($contexte, $page),true))
34                . '-'.$indicateur;
35}
36
37// Parano : on signe le cache, afin d'interdire un hack d'injection
38// dans notre memcache
39function cache_signature(&$page) {
40        if (!isset($GLOBALS['meta']['cache_signature'])){
41                include_spip('inc/acces');
42                include_spip('auth/sha256.inc');
43                ecrire_meta('cache_signature', _nano_sha256($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SERVER_SIGNATURE"] . creer_uniqid()), 'non');
44        }
45        return crc32($GLOBALS['meta']['cache_signature'].$page['texte']);
46}
47
48/**
49 * gestion des delais d'expiration du cache...
50 * $page passee par reference pour accelerer
51 *
52 * La fonction retourne
53 * 1 si il faut mettre le cache a jour
54 * 0 si le cache est valide
55 * -1 si il faut calculer sans stocker en cache
56 *
57 * @param array $page
58 * @param int $date
59 * @return -1/0/1
60 */
61/// http://doc.spip.org/@cache_valide
62function cache_valide(&$page, $date) {
63        $now = $_SERVER['REQUEST_TIME'];
64
65        if (defined('_VAR_NOCACHE') AND _VAR_NOCACHE) return -1;
66        if (isset($GLOBALS['meta']['cache_inhib']) AND $_SERVER['REQUEST_TIME'] AND $_SERVER['REQUEST_TIME']<$GLOBALS['meta']['cache_inhib']) return -1;
67        if (isset($GLOBALS['var_nocache']) AND $GLOBALS['var_nocache']) return -1;
68        if (defined('_NO_CACHE')) return (_NO_CACHE==0 AND !isset($page['texte']))?1:_NO_CACHE;
69        if (!$page OR !isset($page['texte']) OR !isset($page['entetes']['X-Spip-Cache'])) return 1;
70
71        // controle de la signature
72        if ($page['sig'] !== cache_signature($page))
73                return 1;
74
75        // #CACHE{n,statique} => on n'invalide pas avec derniere_modif
76        // cf. ecrire/public/balises.php, balise_CACHE_dist()
77        if (!isset($page['entetes']['X-Spip-Statique']) OR $page['entetes']['X-Spip-Statique'] !== 'oui') {
78
79                // Cache invalide par la meta 'derniere_modif'
80                // sauf pour les bots, qui utilisent toujours le cache
81                if (!_IS_BOT
82                AND $GLOBALS['derniere_modif_invalide']
83                AND $date < $GLOBALS['meta']['derniere_modif'])
84                        return 1;
85
86                // Apparition d'un nouvel article post-date ?
87                if ($GLOBALS['meta']['post_dates'] == 'non'
88                AND isset($GLOBALS['meta']['date_prochain_postdate'])
89                AND $now > $GLOBALS['meta']['date_prochain_postdate']) {
90                        spip_log('Un article post-date invalide le cache');
91                        include_spip('inc/rubriques');
92                        ecrire_meta('derniere_modif', $now);
93                        calculer_prochain_postdate();
94                        return 1;
95                }
96
97        }
98
99        // Sinon comparer l'age du fichier a sa duree de cache
100        $duree = intval($page['entetes']['X-Spip-Cache']);
101        $cache_mark = (isset($GLOBALS['meta']['cache_mark'])?$GLOBALS['meta']['cache_mark']:0);
102        if ($duree == 0)  #CACHE{0}
103                return -1;
104        else if ($date + $duree < $now 
105                # le cache est anterieur a la derniere purge : l'ignorer
106          OR $date<$cache_mark)
107                return 1;
108        else
109                return 0;
110}
111
112// Creer le fichier cache
113# Passage par reference de $page par souci d'economie
114// http://doc.spip.org/@creer_cache
115function creer_cache(&$page, &$chemin_cache, &$memo) {
116
117        // Ne rien faire si on est en preview, debug, ou si une erreur
118        // grave s'est presentee (compilation du squelette, MySQL, etc)
119        // le cas var_nocache ne devrait jamais arriver ici (securite)
120        // le cas spip_interdire_cache correspond a une ereur SQL grave non anticipable
121        if ((defined('_VAR_NOCACHE') AND _VAR_NOCACHE)
122                OR (isset($GLOBALS['var_nocache']) AND $GLOBALS['var_nocache']) // compat SPIP 2.x
123                OR defined('spip_interdire_cache'))
124                return;
125
126        // Si la page c1234 a un invalideur de session 'zz', sauver dans
127        // 'tmp/cache/MD5(chemin_cache)_zz'
128        if (isset($page['invalideurs'])
129        AND isset($page['invalideurs']['session'])) {
130                // on verifie que le contenu du chemin cache indique seulement
131                // "cache sessionne" ; sa date indique la date de validite
132                // des caches sessionnes
133                if (!is_array($tmp = $memo->get($chemin_cache))) {
134                        spip_log('Creation cache sessionne '.$memo->methode.' '.$chemin_cache);
135                        $tmp = array(
136                                'invalideurs' => array('session' => ''),
137                                'lastmodified' => $_SERVER['REQUEST_TIME']
138                        );
139                        $memo->set($chemin_cache, $tmp);
140                }
141                $chemin_cache .= '_'.$page['invalideurs']['session'];
142        }
143
144        // ajouter la date de production dans le cache lui meme
145        // (qui contient deja sa duree de validite)
146        $page['lastmodified'] = $_SERVER['REQUEST_TIME'];
147
148        // signer le contenu
149        $page['sig']= cache_signature($page);
150
151        // compresser si elle est > 16 ko
152        if (strlen($page['texte']) > 16384
153        AND function_exists('gzcompress')) {
154                $page['texte'] = gzcompress($z = $page['texte']);
155                $page['gz'] = true;
156        }
157
158        // memoizer...
159        // on ajoute une heure histoire de pouvoir tourner
160        // sur le cache quand la base de donnees est plantee (a tester)
161        $ok = $memo->set($chemin_cache, $page, 3600+$page['entetes']['X-Spip-Cache']);
162
163        // retablir le texte pour l'afficher
164        if (isset($z)) {
165                $page['texte'] = $z;
166                unset($page['gz']);
167        }
168
169        spip_log("Creation du cache $chemin_cache ". $memo->methode ." pour "
170                . $page['entetes']['X-Spip-Cache']." secondes". ($ok?'':' (erreur!)'));
171
172        // Inserer ses invalideurs
173        /* compat SPIP 1.9 : ne pas appeler les invalideurs du tout */
174        if (!(isset($GLOBALS['spip_version']) AND $GLOBALS['spip_version']<2)) {
175                include_spip('inc/invalideur');
176                maj_invalideurs($chemin_cache, $page);
177        }
178}
179
180
181// purger un petit cache (tidy ou recherche) qui ne doit pas contenir de
182// vieux fichiers ; (cette fonction ne sert que dans des plugins obsoletes)
183// http://doc.spip.org/@nettoyer_petit_cache
184function nettoyer_petit_cache($prefix, $duree = 300) {
185        // determiner le repertoire a purger : 'tmp/CACHE/rech/'
186        $dircache = sous_repertoire(_DIR_CACHE,$prefix);
187        if (spip_touch($dircache.'purger_'.$prefix, $duree, true)) {
188                foreach (preg_files($dircache,'[.]txt$') as $f) {
189                        if ($_SERVER['REQUEST_TIME'] - (@file_exists($f)?@filemtime($f):0) > $duree)
190                                spip_unlink($f);
191                }
192        }
193}
194
195
196// Interface du gestionnaire de cache
197// Si son 3e argument est non vide, elle passe la main a creer_cache
198// Sinon, elle recoit un contexte (ou le construit a partir de REQUEST_URI)
199// et affecte les 4 autres parametres recus par reference:
200// - use_cache qui vaut
201//     -1 s'il faut calculer la page sans la mettre en cache
202//      0 si on peut utiliser un cache existant
203//      1 s'il faut calculer la page et la mettre en cache
204// - chemin_cache qui est le chemin d'acces au fichier ou vide si pas cachable
205// - page qui est le tableau decrivant la page, si le cache la contenait
206// - lastmodified qui vaut la date de derniere modif du fichier.
207// Elle retourne '' si tout va bien
208// un message d'erreur si le calcul de la page est totalement impossible
209
210// http://doc.spip.org/@public_cacher_dist
211function public_cacher($contexte, &$use_cache, &$chemin_cache, &$page, &$lastmodified) {
212        $chemin_cache_session = false;
213       
214        /* compat SPIP 1.9 */
215        if (is_null($contexte) AND function_exists('nettoyer_uri'))
216                $contexte = array('uri' => nettoyer_uri());
217
218        static $memo;
219        if (!isset($memo)) {
220                include_spip('inc/memoization');
221                $cfg = @unserialize($GLOBALS['meta']['memoization']);
222                $memo = new MCache((isset($cfg['pages']) AND $cfg['pages'])? $cfg['pages'] : $cfg['methode']);
223        }
224
225        /* compat SPIP 1.9 */
226        if (is_array($page) AND !isset($page['entetes']['X-Spip-Cache']))
227                $page['duree'] = $page['entetes']['X-Spip-Cache'] = isset($GLOBALS['delais']) ? $GLOBALS['delais'] : null;
228
229        // Second appel, destine a l'enregistrement du cache sur le disque
230        if (isset($chemin_cache)) return creer_cache($page, $chemin_cache, $memo);
231
232        // Toute la suite correspond au premier appel
233        $contexte_implicite = $page['contexte_implicite'];
234
235        // Cas ignorant le cache car completement dynamique
236        if ($_SERVER['REQUEST_METHOD'] == 'POST'
237        OR (substr($contexte_implicite['cache'],0,8)=='modeles/') 
238        OR (_request('connect'))
239// Mode auteur authentifie appelant de ecrire/ : il ne faut rien lire du cache
240// et n'y ecrire que la compilation des squelettes (pas les pages produites)
241// car les references aux repertoires ne sont pas relatifs a l'espace public
242        OR test_espace_prive()) {
243                $use_cache = -1;
244                $lastmodified = 0;
245                $chemin_cache = "";
246                $page = array();
247                return;
248        }
249
250        // Controler l'existence d'un cache nous correspondant
251        $chemin_cache = generer_nom_fichier_cache($contexte, $page);
252        $lastmodified = 0;
253
254        // charger le cache s'il existe
255        if (!is_array($page = $memo->get($chemin_cache)))
256                $page = array();
257
258        // s'il est sessionne, charger celui correspondant a notre session
259        if (isset($page['invalideurs'])
260        AND isset($page['invalideurs']['session'])) {
261                $chemin_cache_session = $chemin_cache . '_' . spip_session();
262                if (is_array($page_session = $memo->get($chemin_cache_session))
263                AND $page_session['lastmodified'] >= $page['lastmodified'])
264                        $page = $page_session;
265                else
266                        $page = array();
267        }
268
269        // dezip si on l'a zipe
270        if (isset($page['gz'])) {
271                $page['texte'] = gzuncompress($page['texte']);
272                unset($page['gz']);
273        }
274
275        // HEAD : cas sans jamais de calcul pour raisons de performance
276        if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
277                $use_cache = 0;
278                $page = array('contexte_implicite'=>$contexte_implicite);
279                return;
280        }
281
282        // Si un calcul, recalcul [ou preview, mais c'est recalcul] est demande,
283        // on supprime le cache
284        if (((isset($GLOBALS['var_mode']) && $GLOBALS['var_mode']) OR (defined('_VAR_MODE') && _VAR_MODE)) &&
285                (isset($_COOKIE['spip_session'])
286                || isset($_COOKIE['spip_admin'])
287                || @file_exists(_ACCESS_FILE_NAME))
288        ) {
289                $page = array('contexte_implicite'=>$contexte_implicite); // ignorer le cache deja lu
290                include_spip('inc/invalideur');
291                if (function_exists('retire_caches')) retire_caches($chemin_cache); # API invalideur inutile
292                $memo->del($chemin_cache);
293                if ($chemin_cache_session)
294                        $memo->del($chemin_cache_session);
295        }
296
297        // $delais par defaut (pour toutes les pages sans #CACHE{})
298        if (!isset($GLOBALS['delais'])) {
299                define('_DUREE_CACHE_DEFAUT', 24*3600);
300                $GLOBALS['delais'] = _DUREE_CACHE_DEFAUT;
301        }
302
303        // determiner la validite de la page
304        if ($page) {
305                $use_cache = cache_valide($page, isset($page['lastmodified']) ? $page['lastmodified']:null);
306                // le contexte implicite n'est pas stocke dans le cache, mais il y a equivalence
307                // par le nom du cache. On le reinjecte donc ici pour utilisation eventuelle au calcul
308                $page['contexte_implicite'] = $contexte_implicite;
309                if (!$use_cache)
310                        return;
311        } else {
312                $page = array('contexte_implicite'=>$contexte_implicite);
313                $use_cache = cache_valide($page,0); // fichier cache absent : provoque le calcul
314        }
315
316        // Si pas valide mais pas de connexion a la base, le garder quand meme
317        if (!spip_connect()) {
318                if (isset($page['texte'])) {
319                        $use_cache = 0;
320                }
321                else {
322                        spip_log("Erreur base de donnees, impossible utiliser "._MEMOIZE." $chemin_cache");
323                        include_spip('inc/minipres');
324                        return minipres(_T('info_travaux_titre'),  _T('titre_probleme_technique'));
325                }
326        }
327
328        if ($use_cache < 0) $chemin_cache = '';
329        return;
330}
331
332// Faut-il decompresser ce cache ?
333// (passage par reference pour alleger)
334// http://doc.spip.org/@gunzip_page
335function gunzip_page(&$page) {
336        if ($page['gz']) {
337                $page['texte'] = gzuncompress($page['texte']);
338                $page['gz'] = false; // ne pas gzuncompress deux fois une meme page
339        }
340}
341
342?>
Note: See TracBrowser for help on using the repository browser.