1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8class Tiki_PageCache 9{ 10 private $cacheData = []; 11 private $key; 12 private $meta = null; 13 private $headerLibCopy = null; 14 15 public static function create() 16 { 17 return new self; 18 } 19 20 function disableForRegistered() 21 { 22 global $user; 23 24 if ($user) { 25 $this->cacheData = null; 26 } 27 28 return $this; 29 } 30 31 function onlyForGet() 32 { 33 if ($_SERVER['REQUEST_METHOD'] != 'GET') { 34 $this->cacheData = null; 35 } 36 37 return $this; 38 } 39 40 function requiresPreference($preference) 41 { 42 global $prefs; 43 44 if ($prefs[$preference] != 'y') { 45 $this->cacheData = null; 46 } 47 48 return $this; 49 } 50 51 function addKeys($array, $keys) 52 { 53 if (is_array($this->cacheData)) { 54 foreach ($keys as $k) { 55 if (! isset($this->cacheData[$k])) { 56 $this->cacheData[$k] = isset($array[$k]) ? $array[$k] : null; 57 } 58 } 59 } 60 61 return $this; 62 } 63 64 function addArray($array) 65 { 66 if (is_array($this->cacheData)) { 67 $this->cacheData = array_merge($this->cacheData, $array); 68 } 69 70 return $this; 71 } 72 73 function addValue($key, $value) 74 { 75 if (is_array($this->cacheData)) { 76 $this->cacheData[$key] = $value; 77 } 78 79 return $this; 80 } 81 82 function checkMeta($role, $data) 83 { 84 $this->meta = array_merge([ 'role' => $role ], $data); 85 86 return $this; 87 } 88 89 function applyCache() 90 { 91 if (is_array($this->cacheData)) { 92 $memcachelib = TikiLib::lib("memcache"); 93 94 if (TikiLib::lib("memcache")->isEnabled()) { 95 $this->key = $memcachelib->buildKey($this->cacheData); 96 97 if ($this->meta) { 98 list($cachedOutput, $metaTime) = $memcachelib->getMulti( 99 [ 100 $this->key, 101 $this->meta, 102 ] 103 ); 104 105 if ($cachedOutput && $metaTime && $metaTime > $cachedOutput['timestamp']) { 106 $cachedOutput = null; 107 } 108 } else { 109 $cachedOutput = $memcachelib->get($this->key); 110 } 111 112 if ($cachedOutput && $cachedOutput['output']) { 113 $headerlib = TikiLib::lib('header'); 114 if (is_array($cachedOutput['jsfiles'])) { 115 foreach ($cachedOutput['jsfiles'] as $rank => $files) { 116 foreach ($files as $file) { 117 $skip_minify = isset($cachedOutput['skip_minify']) ? true : false; 118 $headerlib->add_jsfile_by_rank($file, $rank, $skip_minify); 119 } 120 } 121 } 122 if (is_array($cachedOutput['js'])) { 123 foreach ($cachedOutput['js'] as $rank => $js) { 124 foreach ($js as $j) { 125 $headerlib->add_js($j, $rank); 126 } 127 } 128 } 129 if (is_array($cachedOutput['jq_onready'])) { 130 foreach ($cachedOutput['jq_onready'] as $rank => $js) { 131 foreach ($js as $j) { 132 $headerlib->add_jq_onready($j, $rank); 133 } 134 } 135 } 136 if (is_array($cachedOutput['css'])) { 137 foreach ($cachedOutput['css'] as $rank => $css) { 138 foreach ($css as $c) { 139 $headerlib->add_css($c, $rank); 140 } 141 } 142 } 143 if (is_array($cachedOutput['cssfile'])) { 144 foreach ($cachedOutput['cssfile'] as $rank => $css) { 145 foreach ($css as $c) { 146 $headerlib->add_cssfile($c, $rank); 147 } 148 } 149 } 150 151 152 echo $cachedOutput['output']; 153 echo "\n<!-- memcache " . htmlspecialchars($this->key) . "-->"; 154 exit; 155 } 156 157 // save state of headerlib 158 $this->headerLibCopy = unserialize(serialize(TikiLib::lib('header'))); 159 160 // Start caching, automatically gather at destruction 161 ob_start(); 162 } 163 } 164 165 return $this; 166 } 167 168 function cleanUp() 169 { 170 if ($this->key) { 171 $cachedOutput = [ 172 'timestamp' => time(), 173 'output' => ob_get_contents() 174 ]; 175 176 if ($this->headerLibCopy) { 177 $headerlib = TikiLib::lib('header'); 178 $cachedOutput['jsfiles'] = array_diff($headerlib->jsfiles, $this->headerLibCopy->jsfiles); 179 $cachedOutput['skip_minify'] = array_diff($headerlib->skip_minify, $this->headerLibCopy->skip_minify); 180 $cachedOutput['jq_onready'] = array_diff($headerlib->jq_onready, $this->headerLibCopy->jq_onready); 181 $cachedOutput['js'] = array_diff($headerlib->js, $this->headerLibCopy->js); 182 $cachedOutput['css'] = array_diff($headerlib->css, $this->headerLibCopy->css); 183 $cachedOutput['cssfiles'] = array_diff($headerlib->cssfiles, $this->headerLibCopy->cssfiles); 184 } 185 186 if ($cachedOutput['output']) { 187 TikiLib::lib("memcache")->set($this->key, $cachedOutput); 188 } 189 190 ob_end_flush(); 191 } 192 193 $this->cacheData = []; 194 $this->key = null; 195 $this->meta = null; 196 } 197 198 function invalidate() 199 { 200 if ($this->meta) { 201 TikiLib::lib("memcache")->set($this->meta, time()); 202 } 203 } 204 205 function __destruct() 206 { 207 $this->cleanUp(); 208 } 209} 210