1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
19:
20: App::uses('AppHelper', 'View/Helper');
21:
22: 23: 24: 25: 26: 27: 28: 29: 30:
31: class CacheHelper extends AppHelper {
32:
33: 34: 35: 36: 37: 38:
39: protected $_replace = array();
40:
41: 42: 43: 44: 45: 46:
47: protected $_match = array();
48:
49: 50: 51: 52: 53:
54: protected $_counter = 0;
55:
56: 57: 58: 59: 60:
61: protected function _enabled() {
62: return (($this->_View->cacheAction != false)) && (Configure::read('Cache.check') === true);
63: }
64:
65: 66: 67: 68: 69: 70:
71: public function afterRenderFile($viewFile, $output) {
72: if ($this->_enabled()) {
73: return $this->_parseContent($viewFile, $output);
74: }
75: }
76:
77: 78: 79: 80: 81: 82:
83: public function afterLayout($layoutFile) {
84: if ($this->_enabled()) {
85: $this->_View->output = $this->cache($layoutFile, $this->_View->output);
86: }
87: $this->_View->output = preg_replace('/<!--\/?nocache-->/', '', $this->_View->output);
88: }
89:
90: 91: 92: 93: 94: 95: 96: 97: 98:
99: protected function _parseContent($file, $out) {
100: $out = preg_replace_callback('/<!--nocache-->/', array($this, '_replaceSection'), $out);
101: $this->_parseFile($file, $out);
102: return $out;
103: }
104:
105: 106: 107: 108: 109: 110: 111: 112:
113: public function cache($file, $out) {
114: $cacheTime = 0;
115: $useCallbacks = false;
116: $cacheAction = $this->_View->cacheAction;
117:
118: if (is_array($cacheAction)) {
119: $keys = array_keys($cacheAction);
120: $index = null;
121:
122: foreach ($keys as $action) {
123: if ($action == $this->request->params['action']) {
124: $index = $action;
125: break;
126: }
127: }
128:
129: if (!isset($index) && $this->request->params['action'] == 'index') {
130: $index = 'index';
131: }
132:
133: $options = $cacheAction;
134: if (isset($cacheAction[$index])) {
135: if (is_array($cacheAction[$index])) {
136: $options = array_merge(array('duration' => 0, 'callbacks' => false), $cacheAction[$index]);
137: } else {
138: $cacheTime = $cacheAction[$index];
139: }
140: }
141: if (isset($options['duration'])) {
142: $cacheTime = $options['duration'];
143: }
144: if (isset($options['callbacks'])) {
145: $useCallbacks = $options['callbacks'];
146: }
147: } else {
148: $cacheTime = $cacheAction;
149: }
150:
151: if ($cacheTime != '' && $cacheTime > 0) {
152: $cached = $this->_parseOutput($out);
153: $this->_writeFile($cached, $cacheTime, $useCallbacks);
154: $out = $this->_stripTags($out);
155: }
156: return $out;
157: }
158:
159: 160: 161: 162: 163: 164: 165:
166: protected function _parseFile($file, $cache) {
167: if (is_file($file)) {
168: $file = file_get_contents($file);
169: } elseif ($file = fileExistsInPath($file)) {
170: $file = file_get_contents($file);
171: }
172: preg_match_all('/(<!--nocache:\d{3}-->(?<=<!--nocache:\d{3}-->)[\\s\\S]*?(?=<!--\/nocache-->)<!--\/nocache-->)/i', $cache, $outputResult, PREG_PATTERN_ORDER);
173: preg_match_all('/(?<=<!--nocache-->)([\\s\\S]*?)(?=<!--\/nocache-->)/i', $file, $fileResult, PREG_PATTERN_ORDER);
174: $fileResult = $fileResult[0];
175: $outputResult = $outputResult[0];
176:
177: if (!empty($this->_replace)) {
178: foreach ($outputResult as $i => $element) {
179: $index = array_search($element, $this->_match);
180: if ($index !== false) {
181: unset($outputResult[$i]);
182: }
183: }
184: $outputResult = array_values($outputResult);
185: }
186:
187: if (!empty($fileResult)) {
188: $i = 0;
189: foreach ($fileResult as $cacheBlock) {
190: if (isset($outputResult[$i])) {
191: $this->_replace[] = $cacheBlock;
192: $this->_match[] = $outputResult[$i];
193: }
194: $i++;
195: }
196: }
197: }
198:
199: 200: 201: 202: 203: 204:
205: protected function _replaceSection() {
206: $this->_counter += 1;
207: return sprintf('<!--nocache:%03d-->', $this->_counter);
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217:
218: protected function _stripTags($content) {
219: return preg_replace('#<!--/?nocache(\:\d{3})?-->#', '', $content);
220: }
221:
222: 223: 224: 225: 226: 227:
228: protected function _parseOutput($cache) {
229: $count = 0;
230: if (!empty($this->_match)) {
231: foreach ($this->_match as $found) {
232: $original = $cache;
233: $length = strlen($found);
234: $position = 0;
235:
236: for ($i = 1; $i <= 1; $i++) {
237: $position = strpos($cache, $found, $position);
238:
239: if ($position !== false) {
240: $cache = substr($original, 0, $position);
241: $cache .= $this->_replace[$count];
242: $cache .= substr($original, $position + $length);
243: } else {
244: break;
245: }
246: }
247: $count++;
248: }
249: return $cache;
250: }
251: return $cache;
252: }
253:
254: 255: 256: 257: 258: 259: 260: 261:
262: protected function _writeFile($content, $timestamp, $useCallbacks = false) {
263: $now = time();
264:
265: if (is_numeric($timestamp)) {
266: $cacheTime = $now + $timestamp;
267: } else {
268: $cacheTime = strtotime($timestamp, $now);
269: }
270: $path = $this->request->here();
271: if ($path == '/') {
272: $path = 'home';
273: }
274: $cache = strtolower(Inflector::slug($path));
275:
276: if (empty($cache)) {
277: return;
278: }
279: $cache = $cache . '.php';
280: $file = '<!--cachetime:' . $cacheTime . '--><?php';
281:
282: if (empty($this->_View->plugin)) {
283: $file .= "
284: App::uses('{$this->_View->name}Controller', 'Controller');
285: ";
286: } else {
287: $file .= "
288: App::uses('{$this->_View->plugin}AppController', '{$this->_View->plugin}.Controller');
289: App::uses('{$this->_View->name}Controller', '{$this->_View->plugin}.Controller');
290: ";
291: }
292:
293: $file .= '
294: $request = unserialize(base64_decode(\'' . base64_encode(serialize($this->request)) . '\'));
295: $response = new CakeResponse(array("charset" => Configure::read("App.encoding")));
296: $controller = new ' . $this->_View->name . 'Controller($request, $response);
297: $controller->plugin = $this->plugin = \'' . $this->_View->plugin . '\';
298: $controller->helpers = $this->helpers = unserialize(base64_decode(\'' . base64_encode(serialize($this->_View->helpers)) . '\'));
299: $controller->layout = $this->layout = \'' . $this->_View->layout . '\';
300: $controller->theme = $this->theme = \'' . $this->_View->theme . '\';
301: $controller->viewVars = unserialize(base64_decode(\'' . base64_encode(serialize($this->_View->viewVars)) . '\'));
302: Router::setRequestInfo($controller->request);
303: $this->request = $request;';
304:
305: if ($useCallbacks == true) {
306: $file .= '
307: $controller->constructClasses();
308: $controller->startupProcess();';
309: }
310:
311: $file .= '
312: $this->viewVars = $controller->viewVars;
313: $this->loadHelpers();
314: extract($this->viewVars, EXTR_SKIP);
315: ?>';
316: $content = preg_replace("/(<\\?xml)/", "<?php echo '$1';?>", $content);
317: $file .= $content;
318: return cache('views' . DS . $cache, $file, $timestamp);
319: }
320:
321: }
322: