PageRenderTime 52ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/_plugins_/memoization/public/cacher.php

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